You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Consider the following program:
```scala
class A
class B extends A
class C extends A
given A = A()
given B = B()
given C = C()
def f(using a: A, b: B, c: C) =
println(a.getClass)
println(b.getClass)
println(c.getClass)
@main def Test = f
```
With the current rules, this would fail with an ambiguity error between B and C when
trying to synthesize the A parameter. This is a problem without an easy remedy.
We can fix this problem by flipping the priority for implicit arguments. Instead of
requiring an argument to be most _specific_, we now require it to be most _general_
while still conforming to the formal parameter.
There are three justifications for this change, which at first glance seems quite drastic:
- It gives us a natural way to deal with inheritance triangles like the one in the code above.
Such triangles are quite common.
- Intuitively, we want to get the closest possible match between required formal parameter type and
synthetisized argument. The "most general" rule provides that.
- We already do a crucial part of this. Namely, with current rules we interpolate all
type variables in an implicit argument downwards, no matter what their variance is.
This makes no sense in theory, but solves hairy problems with contravariant typeclasses
like `Comparable`. Instead of this hack, we now do something more principled, by
flipping the direction everywhere, preferring general over specific, instead of just
flipping contravariant type parameters.
The behavior is dependent on the Scala version
- Old behavior: up to 3.4
- New behavior: from 3.5, 3.5-migration warns on behavior change
The CB builds under the new rules. One fix was needed for a shapeless 3 deriving test.
There was a typo: mkInstances instead of mkProductInstances, which previously got healed
by accident because of the most specific rule.
Also: Don't flip contravariant type arguments for overloading resolution
Flipping contravariant type arguments was needed for implicit search
where it will be replaced by a more general scheme. But it makes no
sense for overloading resolution. For overloading resolution, we want
to pick the most specific alternative, analogous to us picking the
most specific instantiation when we force a fully defined type.
Also: Disable implicit search everywhere for disambiaguation
Previously, one disambiguation step missed that, whereas implicits were
turned off everywhere else.
Copy file name to clipboardExpand all lines: docs/_docs/reference/changed-features/implicit-resolution.md
+16-1
Original file line number
Diff line number
Diff line change
@@ -165,7 +165,22 @@ Condition (*) is new. It is necessary to ensure that the defined relation is tra
165
165
166
166
[//]: # todo: expand with precise rules
167
167
168
-
**9.** The following change is currently enabled in `-source future`:
168
+
169
+
**9.** Given disambiguation has changed. When comparing two givens that both match an expected type, we used to pick the most specific one, in alignment with
170
+
overloading resolution. From Scala 3.5 on, we pick the most general one instead. Compiling with Scala 3.5-migration will print a warning in all cases where the preference has changed. Example:
171
+
```scala
172
+
classA
173
+
classBextendsA
174
+
classCextendsA
175
+
176
+
givenA=A()
177
+
givenB=B()
178
+
givenC=C()
179
+
180
+
summon[A] // was ambiguous, will now return `given_A`
181
+
```
182
+
183
+
**10.** The following change is currently enabled in `-source future`:
169
184
170
185
Implicit resolution now avoids generating recursive givens that can lead to an infinite loop at runtime. Here is an example:
0 commit comments