Skip to content

Commit 4eeffb0

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 2f7404e commit 4eeffb0

File tree

4 files changed

+12
-3
lines changed

4 files changed

+12
-3
lines changed

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

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -395,7 +395,7 @@ trait Implicits { self: Typer =>
395395
case _ =>
396396
return false
397397
}
398-
inferView(dummyTreeOfType(from), to)(ctx.fresh.setExploreTyperState).isInstanceOf[SearchSuccess]
398+
inferView(dummyTreeOfType(from), to)(ctx.fresh.addMode(Mode.ImplicitExploration).setExploreTyperState).isInstanceOf[SearchSuccess]
399399
}
400400
)
401401

@@ -526,8 +526,11 @@ trait Implicits { self: Typer =>
526526
case fail: SearchFailure =>
527527
rankImplicits(pending1, acc)
528528
case best: SearchSuccess =>
529-
val newPending = pending1 filter (isAsGood(_, best.ref)(nestedContext.setExploreTyperState))
530-
rankImplicits(newPending, best :: acc)
529+
if (ctx.mode.is(Mode.ImplicitExploration)) best :: Nil
530+
else {
531+
val newPending = pending1 filter (isAsGood(_, best.ref)(nestedContext.setExploreTyperState))
532+
rankImplicits(newPending, best :: acc)
533+
}
531534
}
532535
case nil => acc
533536
}

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)