Skip to content

Commit c3bcad8

Browse files
committed
Do not check for ambiguous implicits in viewExists
Previously `viewExists(X, Y)` failed if there were ambiguous implicit conversions from X to Y. This is too fragile, as demonstrated by test case run/array-addition.scala. Here, the `genericArrayOps` implicit was not inserted because its result type `Array[?T]` was deemed to be incompatible with `? { +: : ? }`. It was incompatible because there were multiple implicits that added :+ to arrays of various element types. But once `genericArrayOps` gets applied, the type parameter `?T` of the array result is fixed, and the ambuity goes away. The scenario shows that we should not test for ambiguous implicits in viewExists. Such a test is fragile because it depends on the progress of type inference when the test is made. It's preferable to just test for any implicit conversion to exist and to check for ambiguities later, when the implicit conversion is actually applied. This has also the potential of speeding up implicit search in situations where `viewExists` is called often (e.g. when coupled with overloading resolution).
1 parent 204158d commit c3bcad8

File tree

4 files changed

+14
-3
lines changed

4 files changed

+14
-3
lines changed

src/dotty/tools/dotc/typer/Implicits.scala

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -384,7 +384,9 @@ trait Implicits { self: Typer =>
384384
&& (ctx.mode is Mode.ImplicitsEnabled)
385385
&& from.isInstanceOf[ValueType]
386386
&& ( from.isValueSubType(to)
387-
|| inferView(dummyTreeOfType(from), to)(ctx.fresh.setExploreTyperState).isInstanceOf[SearchSuccess]
387+
|| inferView(dummyTreeOfType(from), to)
388+
(ctx.fresh.addMode(Mode.ImplicitExploration).setExploreTyperState)
389+
.isInstanceOf[SearchSuccess]
388390
)
389391
)
390392

@@ -515,8 +517,11 @@ trait Implicits { self: Typer =>
515517
case fail: SearchFailure =>
516518
rankImplicits(pending1, acc)
517519
case best: SearchSuccess =>
518-
val newPending = pending1 filter (isAsGood(_, best.ref)(nestedContext.setExploreTyperState))
519-
rankImplicits(newPending, best :: acc)
520+
if (ctx.mode.is(Mode.ImplicitExploration)) best :: Nil
521+
else {
522+
val newPending = pending1 filter (isAsGood(_, best.ref)(nestedContext.setExploreTyperState))
523+
rankImplicits(newPending, best :: acc)
524+
}
520525
}
521526
case nil => acc
522527
}

src/dotty/tools/dotc/typer/Mode.scala

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,5 +73,11 @@ object Mode {
7373
*/
7474
val ImplicitShadowing = newMode(11, "ImplicitShadowing")
7575

76+
/** We are currently in a `viewExists` check. In that case, ambiguous
77+
* implicits checks are disabled and we succeed with teh first implicit
78+
* found.
79+
*/
80+
val ImplicitExploration = newMode(12, "ImplicitExploration")
81+
7682
val PatternOrType = Pattern | Type
7783
}

0 commit comments

Comments
 (0)