Skip to content

Commit db5956b

Browse files
committed
Refine checking for underspecified implicit queries
- Use the wildcard approximation instead of the original type since that one determined what is eligible, and the goal is to refuse the search if everything is eligible. - Also refuse underspecified implicit parameters, not just conversions. - Treat wildcard types as underspecified. Two tests had to be reclassified. But the original tests were not meant to compile anyway. They were bout misleading error messages (no longer the case) and crashers.
1 parent 807743a commit db5956b

File tree

7 files changed

+86
-64
lines changed

7 files changed

+86
-64
lines changed

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

+38-30
Original file line numberDiff line numberDiff line change
@@ -795,16 +795,8 @@ trait Implicits:
795795
*/
796796
def inferView(from: Tree, to: Type)(using Context): SearchResult = {
797797
record("inferView")
798-
val wfromtp = from.tpe.widen
799-
if to.isAny
800-
|| to.isAnyRef
801-
|| to.isRef(defn.UnitClass)
802-
|| wfromtp.isRef(defn.NothingClass)
803-
|| wfromtp.isRef(defn.NullClass)
804-
|| !ctx.mode.is(Mode.ImplicitsEnabled)
805-
|| from.isInstanceOf[Super]
806-
|| (wfromtp eq NoPrefix)
807-
then NoMatchingImplicitsFailure
798+
if !ctx.mode.is(Mode.ImplicitsEnabled) || from.isInstanceOf[Super] then
799+
NoMatchingImplicitsFailure
808800
else {
809801
def adjust(to: Type) = to.stripTypeVar.widenExpr match {
810802
case SelectionProto(name, memberProto, compat, true) =>
@@ -1434,27 +1426,43 @@ trait Implicits:
14341426
rank(sort(eligible), NoMatchingImplicitsFailure, Nil)
14351427
end searchImplicit
14361428

1429+
def isUnderSpecifiedArgument(tp: Type): Boolean =
1430+
tp.isRef(defn.NothingClass) || tp.isRef(defn.NullClass) || (tp eq NoPrefix)
1431+
1432+
private def isUnderspecified(tp: Type): Boolean = tp.stripTypeVar match
1433+
case tp: WildcardType =>
1434+
!tp.optBounds.exists || isUnderspecified(tp.optBounds.hiBound)
1435+
case tp: ViewProto =>
1436+
isUnderspecified(tp.resType)
1437+
|| tp.resType.isRef(defn.UnitClass)
1438+
|| isUnderSpecifiedArgument(tp.argType.widen)
1439+
case _ =>
1440+
tp.isAny || tp.isAnyRef
1441+
14371442
private def searchImplicit(contextual: Boolean): SearchResult =
1438-
val eligible =
1439-
if contextual then ctx.implicits.eligible(wildProto)
1440-
else implicitScope(wildProto).eligible
1441-
searchImplicit(eligible, contextual) match
1442-
case result: SearchSuccess =>
1443-
result
1444-
case failure: SearchFailure =>
1445-
failure.reason match
1446-
case _: AmbiguousImplicits => failure
1447-
case reason =>
1448-
if contextual then
1449-
searchImplicit(contextual = false).recoverWith {
1450-
failure2 => failure2.reason match
1451-
case _: AmbiguousImplicits => failure2
1452-
case _ =>
1453-
reason match
1454-
case (_: DivergingImplicit) => failure
1455-
case _ => List(failure, failure2).maxBy(_.tree.treeSize)
1456-
}
1457-
else failure
1443+
if isUnderspecified(wildProto) then
1444+
NoMatchingImplicitsFailure
1445+
else
1446+
val eligible =
1447+
if contextual then ctx.implicits.eligible(wildProto)
1448+
else implicitScope(wildProto).eligible
1449+
searchImplicit(eligible, contextual) match
1450+
case result: SearchSuccess =>
1451+
result
1452+
case failure: SearchFailure =>
1453+
failure.reason match
1454+
case _: AmbiguousImplicits => failure
1455+
case reason =>
1456+
if contextual then
1457+
searchImplicit(contextual = false).recoverWith {
1458+
failure2 => failure2.reason match
1459+
case _: AmbiguousImplicits => failure2
1460+
case _ =>
1461+
reason match
1462+
case (_: DivergingImplicit) => failure
1463+
case _ => List(failure, failure2).maxBy(_.tree.treeSize)
1464+
}
1465+
else failure
14581466
end searchImplicit
14591467

14601468
/** Find a unique best implicit reference */

compiler/test/dotty/tools/dotc/CompilationTests.scala

-1
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,6 @@ class CompilationTests {
183183
compileFile("tests/neg-custom-args/feature-shadowing.scala", defaultOptions.and("-Xfatal-warnings", "-feature")),
184184
compileDir("tests/neg-custom-args/hidden-type-errors", defaultOptions.and("-explain")),
185185
compileFile("tests/neg-custom-args/i13026.scala", defaultOptions.and("-print-lines")),
186-
compileFile("tests/neg-custom-args/i13838.scala", defaultOptions.and("-Ximplicit-search-limit", "1000")),
187186
).checkExpectedErrors()
188187
}
189188

tests/neg-custom-args/i13838.check

-32
This file was deleted.
File renamed without changes.
File renamed without changes.

tests/neg/i13838a.scala

+47
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
object TooSlow {
2+
trait EqSyntax {
3+
implicit def catsSyntaxEq[A: Eq](a: A): EqOps[A] = ???
4+
}
5+
6+
final class EqOps[A]
7+
8+
object eq extends EqSyntax
9+
10+
import eq._
11+
12+
sealed abstract class Foo[A]
13+
object Foo {
14+
implicit def eqFoo[A: Eq]: Eq[Foo[A]] = ???
15+
}
16+
17+
type FooT[F[_], A] = F[Foo[A]]
18+
object FooT {
19+
def liftF[F[_], A](fa: F[A]): F[Foo[A]] =
20+
map(fa)(???) // error
21+
22+
def map[F[_], A, B](ffa: F[Foo[A]])(f: A => B): F[Foo[B]] =
23+
???
24+
}
25+
26+
trait Order[A] extends Eq[A]
27+
28+
trait Eq[A]
29+
30+
object Eq {
31+
implicit def catsKernelOrderForTuple14[A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13](implicit A0: Order[A0], A1: Order[A1], A2: Order[A2], A3: Order[A3], A4: Order[A4], A5: Order[A5], A6: Order[A6], A7: Order[A7], A8: Order[A8], A9: Order[A9], A10: Order[A10], A11: Order[A11], A12: Order[A12], A13: Order[A13]): Order[(A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13)] = ???
32+
implicit def catsKernelOrderForTuple13[A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12](implicit A0: Order[A0], A1: Order[A1], A2: Order[A2], A3: Order[A3], A4: Order[A4], A5: Order[A5], A6: Order[A6], A7: Order[A7], A8: Order[A8], A9: Order[A9], A10: Order[A10], A11: Order[A11], A12: Order[A12]): Order[(A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12)] = ???
33+
implicit def catsKernelOrderForTuple12[A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11](implicit A0: Order[A0], A1: Order[A1], A2: Order[A2], A3: Order[A3], A4: Order[A4], A5: Order[A5], A6: Order[A6], A7: Order[A7], A8: Order[A8], A9: Order[A9], A10: Order[A10], A11: Order[A11]): Order[(A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11)] = ???
34+
implicit def catsKernelOrderForTuple11[A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10](implicit A0: Order[A0], A1: Order[A1], A2: Order[A2], A3: Order[A3], A4: Order[A4], A5: Order[A5], A6: Order[A6], A7: Order[A7], A8: Order[A8], A9: Order[A9], A10: Order[A10]): Order[(A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10)] = ???
35+
implicit def catsKernelOrderForTuple10[A0, A1, A2, A3, A4, A5, A6, A7, A8, A9](implicit A0: Order[A0], A1: Order[A1], A2: Order[A2], A3: Order[A3], A4: Order[A4], A5: Order[A5], A6: Order[A6], A7: Order[A7], A8: Order[A8], A9: Order[A9]): Order[(A0, A1, A2, A3, A4, A5, A6, A7, A8, A9)] = ???
36+
implicit def catsKernelOrderForTuple9[A0, A1, A2, A3, A4, A5, A6, A7, A8](implicit A0: Order[A0], A1: Order[A1], A2: Order[A2], A3: Order[A3], A4: Order[A4], A5: Order[A5], A6: Order[A6], A7: Order[A7], A8: Order[A8]): Order[(A0, A1, A2, A3, A4, A5, A6, A7, A8)] = ???
37+
implicit def catsKernelOrderForTuple8[A0, A1, A2, A3, A4, A5, A6, A7](implicit A0: Order[A0], A1: Order[A1], A2: Order[A2], A3: Order[A3], A4: Order[A4], A5: Order[A5], A6: Order[A6], A7: Order[A7]): Order[(A0, A1, A2, A3, A4, A5, A6, A7)] = ???
38+
implicit def catsKernelOrderForTuple7[A0, A1, A2, A3, A4, A5, A6](implicit A0: Order[A0], A1: Order[A1], A2: Order[A2], A3: Order[A3], A4: Order[A4], A5: Order[A5], A6: Order[A6]): Order[(A0, A1, A2, A3, A4, A5, A6)] = ???
39+
implicit def catsKernelOrderForTuple6[A0, A1, A2, A3, A4, A5](implicit A0: Order[A0], A1: Order[A1], A2: Order[A2], A3: Order[A3], A4: Order[A4], A5: Order[A5]): Order[(A0, A1, A2, A3, A4, A5)] = ???
40+
implicit def catsKernelOrderForTuple5[A0, A1, A2, A3, A4](implicit A0: Order[A0], A1: Order[A1], A2: Order[A2], A3: Order[A3], A4: Order[A4]): Order[(A0, A1, A2, A3, A4)] = ???
41+
implicit def catsKernelOrderForTuple4[A0, A1, A2, A3](implicit A0: Order[A0], A1: Order[A1], A2: Order[A2], A3: Order[A3]): Order[(A0, A1, A2, A3)] = ???
42+
implicit def catsKernelOrderForTuple3[A0, A1, A2](implicit A0: Order[A0], A1: Order[A1], A2: Order[A2]): Order[(A0, A1, A2)] = ???
43+
implicit def catsKernelOrderForTuple2[A0, A1](implicit A0: Order[A0], A1: Order[A1]): Order[(A0, A1)] = ???
44+
implicit def catsKernelOrderForTuple1[A0](implicit A0: Order[A0]): Order[Tuple1[A0]] = ???
45+
}
46+
47+
}
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
trait F[x]
22
implicit def foo[f[_], y, x <: f[y]](implicit ev: F[y]): F[x] = ???
3-
val test = implicitly
3+
val test = implicitly // error

0 commit comments

Comments
 (0)