Skip to content

Commit 923d5c8

Browse files
committed
Change implicit resolution rule wrt implicit parameters
The method with fewer parameters wins now over methods with more parameters. The reason for the change is i3430.scala, with Nil.sum Here, orderings for any type are eligible implied instances for `sum`'s implicit `Ordering` parameter. If we prioritize arguments with implicit parameters, we have to try all tuple orderings which themselves take as many implicit parameters as the tuple has elements. This leads to an infinite recursion with very broad fanout, so the observed effect is that the compiler hangs. By prioritizing shorter implicit parameter lists, we avoid this problem.
1 parent b537220 commit 923d5c8

File tree

5 files changed

+20
-40
lines changed

5 files changed

+20
-40
lines changed

compiler/src/dotty/tools/dotc/typer/Applications.scala

+2-2
Original file line numberDiff line numberDiff line change
@@ -1411,10 +1411,10 @@ trait Applications extends Compatibility { self: Typer with Dynamic =>
14111411
val strippedType2 = stripImplicit(fullType2, +1)
14121412

14131413
val result = compareWithTypes(strippedType1, strippedType2)
1414-
if (result != 0 || !ctx.typerState.test(implicit ctx => strippedType1 =:= strippedType2))
1414+
if (result != 0)
14151415
result
14161416
else if (implicitBalance != 0)
1417-
-implicitBalance.signum
1417+
implicitBalance.signum
14181418
else if ((strippedType1 `ne` fullType1) || (strippedType2 `ne` fullType2))
14191419
compareWithTypes(fullType1, fullType2)
14201420
else

docs/docs/reference/changed-features/implicit-resolution.md

+1-3
Original file line numberDiff line numberDiff line change
@@ -114,10 +114,8 @@ affect implicits on the language level.
114114
An alternative A is _more specific_ than an alternative B if
115115

116116
- the relative weight of A over B is greater than the relative weight of B over A, or
117-
- the relative weights are the same, and the returned types of A and B are
118-
unifiable, and A takes more inferable parameters than B, or
117+
- the relative weights are the same, and A takes fewer inferable parameters than B, or
119118
- the relative weights and the number of inferable parameters are the same, and
120-
the returned types of A and B are unifiable, and
121119
A is more specific than B if all inferable parameters in either alternative are
122120
replaced by regular parameters.
123121

tests/run/implicit-specifity.scala

+14-2
Original file line numberDiff line numberDiff line change
@@ -12,19 +12,31 @@ object Generic {
1212
implied showGen[T] given Generic for Show[T] = new Show[T](2)
1313
}
1414

15+
class Generic2
16+
object Generic2 {
17+
opaque type HiPriority = AnyRef
18+
implied showGen[T] for (Show[T] & HiPriority) = new Show[T](2).asInstanceOf
19+
}
20+
21+
class SubGen extends Generic
22+
object SubGen {
23+
implied for SubGen
24+
}
1525
object Contextual {
1626
trait Context
1727
implied ctx for Context
1828
implied showGen[T] given Generic for Show[T] = new Show[T](2)
1929
implied showGen[T] given Generic, Context for Show[T] = new Show[T](3)
30+
implied showGen[T] given SubGen for Show[T] = new Show[T](4)
2031
}
2132

2233
object Test extends App {
2334
assert(Show[Int] == 0)
2435
assert(Show[String] == 1)
25-
assert(Show[Generic] == 2) // showGen beats fallback due to longer argument list
36+
assert(Show[Generic] == 1) // showGen loses against fallback due to longer argument list
37+
assert(Show[Generic2] == 2) // ... but the opaque type intersection trick works.
2638

2739
{ import implied Contextual._
28-
assert(Show[Generic] == 3)
40+
assert(Show[Generic] == 4) // shorter, more specific implicit parameter list wins
2941
}
3042
}

tests/run/implied-specifity.scala

-30
This file was deleted.

tests/run/overloading-specifity.scala

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
// Shows that now implicit parameters act as a tie-breaker.
2-
// The alternative with more implicit parameters wins.
2+
// The alternative with fewer implicit parameters wins.
33
case class Show[T](val i: Int)
44

55
class Generic
@@ -21,7 +21,7 @@ object Test extends App {
2121
def foo[T]: Show[T] = new Show[T](2)
2222
}
2323

24-
assert(a.foo[Int].i == 2)
25-
assert(b.foo[Int].i == 1)
24+
assert(a.foo[Int].i == 1)
25+
assert(b.foo[Int].i == 2)
2626

2727
}

0 commit comments

Comments
 (0)