More powerful implicit resolution in case matches #17827
Replies: 0 comments 8 replies
-
On a related note: I am a little confused about the behavior of the auto-generated object Test {
trait Foo[Self]
class ExplicitClass(val a: String)
object ExplicitClass {
def unapply(i: ExplicitClass): Option[String] = Some(i.a)
}
given Foo[ExplicitClass] with {}
case class CaseClass(val b: Int)
given Foo[CaseClass] with {}
object Foo {
class Type private (t: Any)
object Type {
def apply[T: Foo](t: T) = new Type(t)
def unapply[T: Foo](t: Type): Option[T] = ???
}
}
val x = Foo.Type(ExplicitClass("x"))
val matched: Option[CaseClass] = Foo.Type.unapply(x)
val compiles = Foo.Type.unapply(x).flatMap(ExplicitClass.unapply _)
val doesntCompile = Foo.Type.unapply(x).flatMap(CaseClass.unapply _) // ambiguous implicits
} Looking at what I think is the code for for the auto-generated unapply, I see that the return type of the generated method is not an Option anymore in Scala 3. I'm surprised that it affects compilation here though. I'm not clear if this counts as a bug or not. |
Beta Was this translation helpful? Give feedback.
-
@adampauls https://docs.scala-lang.org/scala3/reference/changed-features/pattern-matching.html note that normal usage of case classes for pattern cases is constructor pattern, not extractor pattern. |
Beta Was this translation helpful? Give feedback.
-
@som-snytt thanks, I'm familiar with the new pattern matching facilities (though I don't understand all the implications). I don't understand why it would affect implicit resolution as it does in my second example. I think the only thing that should matter is the input to To double check: "constructor pattern" is what's called Product Match in the page you linked correct? |
Beta Was this translation helpful? Give feedback.
-
My eyes are tired at the moment, but I see what you mean now that I've read it through. Since And for the first example, the test pattern should type check because the res expression does.
Just from the form of the pattern, it can't know if it's a constructor or an extractor or which flavor of extraction. An Option result must be type R with single match ( If it were a Product match, On terminology, constructor pattern |
Beta Was this translation helpful? Give feedback.
-
Not following what you mean here. Why should
Again, sorry, not following what you mean. At some point, the compiler must resolve whether to call Is the issue that implicit resolution happens before the compiler resolves the compiler to one of the pattern matching options? That seems unlikely to me, but I'm out of my depth here. |
Beta Was this translation helpful? Give feedback.
-
The shape of the extraction is known from For But I won't speculate. Not only am I out of my depth, I just read that nytimes piece about great white sharks: who knows what may be down there. |
Beta Was this translation helpful? Give feedback.
-
Oh, derp, of course flatMap doesn't compile if there is no Option. Now I see what you mean by I might want a better error message. In any case, I think the extra power in pattern matching is theoretically achievable but possibly very hard to implement. Could you by chance point me to the part of the code that performs type inference on pattern matches (or that compiles it to non-pattern matching code before type inference) so I could see for myself? I see this, but I'm not sure where implicit resolution happens or if the that link is the whole story |
Beta Was this translation helpful? Give feedback.
-
It looks like the limiting code is here. This code doesn't even look at |
Beta Was this translation helpful? Give feedback.
-
Consider the following code (compiled with 3.1.0-RC2):
In the above,
Foo.Type.unapply
takes an implicit type parameter that only shows up on the output. When directly invokingunapply
in a context where the expected type constrains the output type, everything works. However, in a case match where the output type ofunapply
is effectively constrained by a nested matcher, implicit resolution still fails.I'm not sure if there is a good reason for this. In cases where the nested
unapply
and/or type ascription unambiguously specifies a type constraint, I think implicit resolution could be successful.Of course there are ambiguous cases -- for example, if we have
case Foo.Type(SomeAmbiguousUnapply(_)) => ???
where
SomeAmbiguousUnapply
has bothunapply(Impl1)
andunapply(Impl2)
, there is insufficient information to constrain the implicit search and it's reasonable to fail in that case.Beta Was this translation helpful? Give feedback.
All reactions