Skip to content

Commit 0e4d51a

Browse files
committed
Do not visit args recursively in issueErrors
Instead, fix the display of nested `AmbiguousImplicits` errors.
1 parent 0890e7a commit 0e4d51a

16 files changed

+128
-47
lines changed

compiler/src/dotty/tools/dotc/reporting/messages.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2980,7 +2980,7 @@ class MissingImplicitArgument(
29802980
* def foo(implicit foo: Foo): Any = ???
29812981
*/
29822982
arg.tpe match
2983-
case ambi: AmbiguousImplicits =>
2983+
case ambi: AmbiguousImplicits if !ambi.nested =>
29842984
(ambi.alt1, ambi.alt2) match
29852985
case (alt @ AmbiguousImplicitMsg(msg), _) =>
29862986
userDefinedAmbiguousImplicitMsg(alt, msg)

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -537,7 +537,7 @@ object Implicits:
537537
end TooUnspecific
538538

539539
/** An ambiguous implicits failure */
540-
class AmbiguousImplicits(val alt1: SearchSuccess, val alt2: SearchSuccess, val expectedType: Type, val argument: Tree) extends SearchFailureType:
540+
class AmbiguousImplicits(val alt1: SearchSuccess, val alt2: SearchSuccess, val expectedType: Type, val argument: Tree, val nested: Boolean = false) extends SearchFailureType:
541541

542542
def msg(using Context): Message =
543543
var str1 = err.refStr(alt1.ref)

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

Lines changed: 26 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -3872,38 +3872,36 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
38723872
end implicitArgs
38733873

38743874
/** Reports errors for arguments of `appTree` that have a
3875-
* `SearchFailureType`, recursively traversing arguments that are
3876-
* themselves applications. `mt` must be the type of `appTree.fun`.
3875+
* `SearchFailureType`.
38773876
*/
3878-
def reportErrors(appTree: Apply, mt: MethodType): Unit =
3879-
val Apply(fun, args) = appTree
3880-
for (paramName, formal, arg) <- mt.paramNames.lazyZip(mt.paramInfos).lazyZip(args) do
3877+
def issueErrors(fun: Tree, args: List[Tree]): Tree =
3878+
def firstFailure = args.tpes.find(_.isInstanceOf[SearchFailureType]).getOrElse(NoType)
3879+
val errorType =
3880+
firstFailure match
3881+
case tp: AmbiguousImplicits =>
3882+
AmbiguousImplicits(tp.alt1, tp.alt2, tp.expectedType, tp.argument, nested = true)
3883+
case tp =>
3884+
tp
3885+
val res = untpd.Apply(fun, args).withType(errorType)
3886+
3887+
wtp.paramNames.lazyZip(wtp.paramInfos).lazyZip(args).foreach { (paramName, formal, arg) =>
38813888
arg.tpe match
38823889
case failure: SearchFailureType =>
3883-
arg match
3884-
case childAppTree: Apply =>
3885-
childAppTree.fun.tpe.widen match
3886-
case childMt: MethodType => reportErrors(childAppTree, childMt)
3887-
case _ => ()
3888-
case _ => ()
3889-
38903890
val methodStr = err.refStr(methPart(fun).tpe)
38913891
val paramStr = implicitParamString(paramName, methodStr, fun)
3892-
val paramSymWithMethodCallTree =
3893-
fun.symbol.paramSymss.flatten
3894-
.find(_.name == paramName)
3895-
.map((_, appTree))
3896-
val message = missingArgMsg(arg, formal, paramStr, paramSymWithMethodCallTree)
3897-
// Note: if the same error type appears on several trees, we
3898-
// might report it several times, but this is not a problem
3899-
// because only the first one will be displayed. We traverse in
3900-
// post-order, so that the most detailed message gets displayed.
3901-
report.error(message, fun.srcPos.endPos)
3902-
case _ => ()
3892+
val paramSym = fun.symbol.paramSymss.flatten.find(_.name == paramName)
3893+
val paramSymWithMethodCallTree = paramSym.map((_, res))
3894+
report.error(
3895+
missingArgMsg(arg, formal, paramStr, paramSymWithMethodCallTree),
3896+
tree.srcPos.endPos
3897+
)
3898+
case _ =>
3899+
}
3900+
3901+
res
39033902

39043903
val args = implicitArgs(wtp.paramInfos, 0, pt)
3905-
val firstFailure = args.tpes.find(_.isInstanceOf[SearchFailureType])
3906-
if (firstFailure.isDefined) {
3904+
if (args.tpes.exists(_.isInstanceOf[SearchFailureType])) {
39073905
// If there are several arguments, some arguments might already
39083906
// have influenced the context, binding variables, but later ones
39093907
// might fail. In that case the constraint and instantiated variables
@@ -3934,14 +3932,9 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
39343932
// node, we can report the errors for each argument nicely.
39353933
// Otherwise, we don't report anything here.
39363934
retyped match
3937-
case retyped: Apply if retyped.tpe.isError => reportErrors(retyped, wtp)
3938-
case _ => ()
3939-
3940-
retyped
3941-
else
3942-
val res = untpd.Apply(tree, args).withType(firstFailure.get)
3943-
reportErrors(res, wtp)
3944-
res
3935+
case Apply(tree, args) if retyped.tpe.isError => issueErrors(tree, args)
3936+
case _ => retyped
3937+
else issueErrors(tree, args)
39453938
}
39463939
else tree match {
39473940
case tree: Block =>

tests/neg/19414-desugared.check

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,14 @@
11
-- [E172] Type Error: tests/neg/19414-desugared.scala:22:34 ------------------------------------------------------------
22
22 | summon[BodySerializer[JsObject]] // error: Ambiguous given instances
33
| ^
4-
|Ambiguous given instances: both given instance given_Writer_JsValue and given instance given_Writer_JsObject match type Writer[B] of parameter writer of given instance given_BodySerializer_B
4+
|No given instance of type BodySerializer[JsObject] was found for parameter x of method summon in object Predef.
5+
|I found:
6+
|
7+
| given_BodySerializer_B[B](
8+
| writer =
9+
| /* ambiguous: both given instance given_Writer_JsValue and given instance given_Writer_JsObject match type Writer[B] */
10+
| summon[Writer[B]]
11+
| ,
12+
| this.given_BodySerializer_B$default$2[B])
13+
|
14+
|But both given instance given_Writer_JsValue and given instance given_Writer_JsObject match type Writer[B].

tests/neg/19414.check

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,14 @@
11
-- [E172] Type Error: tests/neg/19414.scala:15:34 ----------------------------------------------------------------------
22
15 | summon[BodySerializer[JsObject]] // error: Ambiguous given instances
33
| ^
4-
|Ambiguous given instances: both given instance given_Writer_JsValue and given instance given_Writer_JsObject match type Writer[B] of a context parameter of given instance given_BodySerializer_B
4+
|No given instance of type BodySerializer[JsObject] was found for parameter x of method summon in object Predef.
5+
|I found:
6+
|
7+
| given_BodySerializer_B[B](
8+
| evidence$1 =
9+
| /* ambiguous: both given instance given_Writer_JsValue and given instance given_Writer_JsObject match type Writer[B] */
10+
| summon[Writer[B]]
11+
| ,
12+
| this.given_BodySerializer_B$default$2[B])
13+
|
14+
|But both given instance given_Writer_JsValue and given instance given_Writer_JsObject match type Writer[B].

tests/neg/given-ambiguous-1.check

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
-- [E172] Type Error: tests/neg/given-ambiguous-1.scala:12:23 ----------------------------------------------------------
2+
12 |def f: Unit = summon[B] // error: Ambiguous given instances
3+
| ^
4+
| No given instance of type B was found for parameter x of method summon in object Predef.
5+
| I found:
6+
|
7+
| given_B(/* ambiguous: both given instance a1 and given instance a2 match type A */summon[A])
8+
|
9+
| But both given instance a1 and given instance a2 match type A.

tests/neg/given-ambiguous-1.scala

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
class A
2+
class B
3+
given a1: A = ???
4+
given a2: A = ???
5+
given (using a: A): B = ???
6+
7+
// In this case, the ambiguous given instance is not directly the argument of
8+
// `summon`; it is the argument of `given_B` which is needed for the argument of
9+
// `summon`. This is a nested ambiguous implicit, thus we report an error in
10+
// the style "I found ... but". See `given-ambiguous-2` for a direct ambiguous
11+
// implicit error.
12+
def f: Unit = summon[B] // error: Ambiguous given instances

tests/neg/given-ambiguous-2.check

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
-- [E172] Type Error: tests/neg/given-ambiguous-2.scala:10:15 ----------------------------------------------------------
2+
10 |def f: Unit = g // error: Ambiguous given instances
3+
| ^
4+
| Ambiguous given instances: both given instance a1 and given instance a2 match type A of parameter a of method g

tests/neg/given-ambiguous-2.scala

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
class A
2+
class B
3+
given a1: A = ???
4+
given a2: A = ???
5+
def g(using a: A): B = ???
6+
7+
// In this case, the ambiguous given instance is directly the argument of
8+
// `summon`. This is a direct ambiguous implicit, thus we report the error
9+
// directly. See `given-ambiguous-1` for a nested ambiguous implicit error.
10+
def f: Unit = g // error: Ambiguous given instances
Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
11
-- [E172] Type Error: tests/neg/given-ambiguous-default-1.scala:18:23 --------------------------------------------------
22
18 |def f: Unit = summon[B] // error: Ambiguous given instances
33
| ^
4-
|Ambiguous given instances: both given instance a1 and given instance a2 match type A of parameter a of given instance given_B
4+
| No given instance of type B was found for parameter x of method summon in object Predef.
5+
| I found:
6+
|
7+
| given_B(a = /* ambiguous: both given instance a1 and given instance a2 match type A */summon[A])
8+
|
9+
| But both given instance a1 and given instance a2 match type A.
Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
11
-- [E172] Type Error: tests/neg/given-ambiguous-default-2.scala:18:23 --------------------------------------------------
22
18 |def f: Unit = summon[C] // error: Ambiguous given instances
33
| ^
4-
|Ambiguous given instances: both given instance a1 and given instance a2 match type A of parameter a of given instance given_C
4+
|No given instance of type C was found for parameter x of method summon in object Predef.
5+
|I found:
6+
|
7+
| given_C(a = /* ambiguous: both given instance a1 and given instance a2 match type A */summon[A], this.given_C$default$2)
8+
|
9+
|But both given instance a1 and given instance a2 match type A.

tests/neg/i8827a.check

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,12 @@
11
-- [E172] Type Error: tests/neg/i8827a.scala:16:26 ---------------------------------------------------------------------
22
16 | summon[Order[List[Foo]]] // error
33
| ^
4-
| No given instance of type pkg.Order[pkg.Foo] was found for parameter orderA of method orderList in object Order
4+
| No given instance of type pkg.Order[List[pkg.Foo]] was found for parameter x of method summon in object Predef.
5+
| I found:
6+
|
7+
| pkg.Order.orderList[pkg.Foo](/* missing */summon[pkg.Order[pkg.Foo]])
8+
|
9+
| But no implicit values were found that match type pkg.Order[pkg.Foo].
510
|
611
| The following import might fix the problem:
712
|

tests/neg/i8827b.check

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,12 @@
11
-- [E172] Type Error: tests/neg/i8827b.scala:16:28 ---------------------------------------------------------------------
22
16 | summon[Order[Option[Foo]]] // error
33
| ^
4-
|No given instance of type pkg.Order[pkg.Foo] was found for parameter orderA of given instance given_Order_Option in object Order
4+
|No given instance of type pkg.Order[Option[pkg.Foo]] was found for parameter x of method summon in object Predef.
5+
|I found:
6+
|
7+
| pkg.Order.given_Order_Option[pkg.Foo](/* missing */summon[pkg.Order[pkg.Foo]])
8+
|
9+
|But no implicit values were found that match type pkg.Order[pkg.Foo].
510
|
611
|The following import might fix the problem:
712
|

tests/neg/i9568.check

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,13 @@
44
| No given instance of type => Monad[F] was found for parameter ev of method blaMonad in object Test.
55
| I found:
66
|
7-
| Test.blaMonad[F², S]
7+
| Test.blaMonad[F², S](Test.blaMonad[F³, S²])
88
|
9-
| But method blaMonad in object Test does not match type => Monad[F]
9+
| But method blaMonad in object Test does not match type => Monad[F²]
1010
|
1111
| where: F is a type variable with constraint <: [_] =>> Any
1212
| F² is a type variable with constraint <: [_] =>> Any
13+
| F³ is a type variable with constraint <: [_] =>> Any
14+
| S is a type variable
15+
| S² is a type variable
1316
| .

tests/neg/implicitSearch.check

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,12 @@
11
-- [E172] Type Error: tests/neg/implicitSearch.scala:13:12 -------------------------------------------------------------
22
13 | sort(xs) // error (with a partially constructed implicit argument shown)
33
| ^
4-
| No given instance of type Test.Ord[T] was found for parameter o of method listOrd in object Test
4+
| No given instance of type Test.Ord[List[List[T]]] was found for parameter o of method sort in object Test.
5+
| I found:
6+
|
7+
| Test.listOrd[List[T]](Test.listOrd[T](/* missing */summon[Test.Ord[T]]))
8+
|
9+
| But no implicit values were found that match type Test.Ord[T].
510
-- [E172] Type Error: tests/neg/implicitSearch.scala:15:38 -------------------------------------------------------------
611
15 | listOrd(listOrd(implicitly[Ord[T]] /*not found*/)) // error
712
| ^

tests/neg/missing-implicit3.check

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,14 @@
11
-- [E172] Type Error: tests/neg/missing-implicit3.scala:13:36 ----------------------------------------------------------
22
13 |val sortedFoos = sort(List(new Foo)) // error
33
| ^
4-
|No given instance of type ord.Foo => Comparable[? >: ord.Foo] was found for parameter x$1 of given instance ordered in object Ord
4+
| No given instance of type ord.Ord[ord.Foo] was found for a context parameter of method sort in package ord.
5+
| I found:
56
|
6-
|The following import might make progress towards fixing the problem:
7+
| ord.Ord.ordered[ord.Foo](/* missing */summon[ord.Foo => Comparable[? >: ord.Foo]])
78
|
8-
| import scala.math.Ordered.orderingToOrdered
9+
| But no implicit values were found that match type ord.Foo => Comparable[? >: ord.Foo].
10+
|
11+
| The following import might make progress towards fixing the problem:
12+
|
13+
| import scala.math.Ordered.orderingToOrdered
914
|

0 commit comments

Comments
 (0)