diff options
author | Martin Odersky <odersky@gmail.com> | 2015-06-18 15:15:42 +0200 |
---|---|---|
committer | Martin Odersky <odersky@gmail.com> | 2015-06-22 11:42:05 +0200 |
commit | c3bcad807db47ee4ab27ac4a725ba5f402667b4d (patch) | |
tree | 2d80305765fd763574b36c47d6a413179eee3860 /src | |
parent | 204158d4141254d1148534e14d3d26b361b7bc12 (diff) | |
download | dotty-c3bcad807db47ee4ab27ac4a725ba5f402667b4d.tar.gz dotty-c3bcad807db47ee4ab27ac4a725ba5f402667b4d.tar.bz2 dotty-c3bcad807db47ee4ab27ac4a725ba5f402667b4d.zip |
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).
Diffstat (limited to 'src')
-rw-r--r-- | src/dotty/tools/dotc/typer/Implicits.scala | 11 | ||||
-rw-r--r-- | src/dotty/tools/dotc/typer/Mode.scala | 6 |
2 files changed, 14 insertions, 3 deletions
diff --git a/src/dotty/tools/dotc/typer/Implicits.scala b/src/dotty/tools/dotc/typer/Implicits.scala index be76553be..a3ddca5d9 100644 --- a/src/dotty/tools/dotc/typer/Implicits.scala +++ b/src/dotty/tools/dotc/typer/Implicits.scala @@ -384,7 +384,9 @@ trait Implicits { self: Typer => && (ctx.mode is Mode.ImplicitsEnabled) && from.isInstanceOf[ValueType] && ( from.isValueSubType(to) - || inferView(dummyTreeOfType(from), to)(ctx.fresh.setExploreTyperState).isInstanceOf[SearchSuccess] + || inferView(dummyTreeOfType(from), to) + (ctx.fresh.addMode(Mode.ImplicitExploration).setExploreTyperState) + .isInstanceOf[SearchSuccess] ) ) @@ -515,8 +517,11 @@ trait Implicits { self: Typer => case fail: SearchFailure => rankImplicits(pending1, acc) case best: SearchSuccess => - val newPending = pending1 filter (isAsGood(_, best.ref)(nestedContext.setExploreTyperState)) - rankImplicits(newPending, best :: acc) + if (ctx.mode.is(Mode.ImplicitExploration)) best :: Nil + else { + val newPending = pending1 filter (isAsGood(_, best.ref)(nestedContext.setExploreTyperState)) + rankImplicits(newPending, best :: acc) + } } case nil => acc } diff --git a/src/dotty/tools/dotc/typer/Mode.scala b/src/dotty/tools/dotc/typer/Mode.scala index e84ef2784..31766adc6 100644 --- a/src/dotty/tools/dotc/typer/Mode.scala +++ b/src/dotty/tools/dotc/typer/Mode.scala @@ -73,5 +73,11 @@ object Mode { */ val ImplicitShadowing = newMode(11, "ImplicitShadowing") + /** We are currently in a `viewExists` check. In that case, ambiguous + * implicits checks are disabled and we succeed with teh first implicit + * found. + */ + val ImplicitExploration = newMode(12, "ImplicitExploration") + val PatternOrType = Pattern | Type } |