Skip to content

Commit 292865a

Browse files
committed
issueErrors also when typing with default params fails
1 parent 41fb24d commit 292865a

11 files changed

+132
-13
lines changed

compiler/src/dotty/tools/dotc/core/Types.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5719,7 +5719,7 @@ object Types extends TypeUtils {
57195719
def explanation(using Context): String = msg.message
57205720
}
57215721

5722-
/** Note: Make sure an errors is reported before construtcing this
5722+
/** Note: Make sure an errors is reported before constructing this
57235723
* as the type of a tree.
57245724
*/
57255725
object ErrorType:

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2916,7 +2916,7 @@ class MissingImplicitArgument(
29162916
i"""$headline.
29172917
|I found:
29182918
|
2919-
| ${original.show.replace("\n", "\n ")}
2919+
| ${original.showIndented(4)}
29202920
|
29212921
|But ${tpe.explanation}."""
29222922
case _ => headline

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

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3849,11 +3849,12 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
38493849
end implicitArgs
38503850

38513851
val args = implicitArgs(wtp.paramInfos, 0, pt)
3852-
val firstNonAmbiguous = args.tpes.find(tp => tp.isError && !tp.isInstanceOf[AmbiguousImplicits])
3853-
def firstError = args.tpes.find(_.isError)
3854-
val propFail = firstNonAmbiguous.orElse(firstError).getOrElse(NoType)
38553852

3856-
def issueErrors(): Tree = {
3853+
def issueErrors(failingArgs: List[Tree]): Tree = {
3854+
val firstNonAmbiguous = failingArgs.tpes.find(tp => tp.isError && !tp.isInstanceOf[AmbiguousImplicits])
3855+
def firstError = failingArgs.tpes.find(_.isError)
3856+
val propFail = firstNonAmbiguous.orElse(firstError).getOrElse(NoType)
3857+
38573858
def paramSymWithMethodTree(paramName: TermName) =
38583859
if tree.symbol.exists then
38593860
tree.symbol.paramSymss.flatten
@@ -3864,7 +3865,7 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
38643865
else
38653866
None
38663867

3867-
wtp.paramNames.lazyZip(wtp.paramInfos).lazyZip(args).foreach { (paramName, formal, arg) =>
3868+
wtp.paramNames.lazyZip(wtp.paramInfos).lazyZip(failingArgs).foreach { (paramName, formal, arg) =>
38683869
arg.tpe match {
38693870
case failure: SearchFailureType =>
38703871
report.error(
@@ -3874,10 +3875,10 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
38743875
case _ =>
38753876
}
38763877
}
3877-
untpd.Apply(tree, args).withType(propFail)
3878+
untpd.Apply(tree, failingArgs).withType(propFail)
38783879
}
38793880

3880-
if (propFail.exists) {
3881+
if (args.tpes.exists(_.isError)) {
38813882
// If there are several arguments, some arguments might already
38823883
// have influenced the context, binding variables, but later ones
38833884
// might fail. In that case the constraint and instantiated variables
@@ -3887,18 +3888,21 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
38873888
// If method has default params and there are no "Ambiguous implicits"
38883889
// error, fall back to regular application where all inferred
38893890
// implicits are passed as named args.
3890-
if hasDefaultParams && !propFail.isInstanceOf[AmbiguousImplicits] then
3891+
if hasDefaultParams then
38913892
val namedArgs = wtp.paramNames.lazyZip(args).flatMap { (pname, arg) =>
3892-
if (arg.tpe.isError) Nil else untpd.NamedArg(pname, untpd.TypedSplice(arg)) :: Nil
3893+
if arg.tpe.isInstanceOf[NoMatchingImplicits] then Nil
3894+
else untpd.NamedArg(pname, untpd.TypedSplice(arg)) :: Nil
38933895
}
38943896
val app = cpy.Apply(tree)(untpd.TypedSplice(tree), namedArgs)
38953897
val needsUsing = wtp.isContextualMethod || wtp.match
38963898
case MethodType(ContextBoundParamName(_) :: _) => sourceVersion.isAtLeast(`3.4`)
38973899
case _ => false
38983900
if needsUsing then app.setApplyKind(ApplyKind.Using)
38993901
typr.println(i"try with default implicit args $app")
3900-
typed(app, pt, locked)
3901-
else issueErrors()
3902+
val tpdApply @ Apply(_, args1) = typed(app, pt, locked): @unchecked
3903+
println("tpdApply.tpe " + tpdApply.tpe)
3904+
if tpdApply.tpe.isError then issueErrors(args1) else tpdApply
3905+
else issueErrors(args)
39023906
}
39033907
else tree match {
39043908
case tree: Block =>

tests/neg/19414-desugared.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/19414-desugared.scala:34:34 ------------------------------------------------------------
2+
34 | summon[BodySerializer[JsObject]] // error: Ambiguous given instances
3+
| ^
4+
|Ambiguous given instances: both given instance given_Writer_JsValue and given instance given_Writer_JsObject match type Writer[B] of parameter x of method summon in object Predef

tests/neg/19414-desugared.scala

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
/** This test checks that provided given instances take precedence over default
2+
* given arguments, even when there are multiple default arguments.
3+
*
4+
* Before the fix for issue #19414, this code would fail with a "No given
5+
* instance of type BodySerializer[JsObject]".
6+
*
7+
* See also:
8+
* - tests/neg/19414.scala
9+
* - tests/neg/given-ambiguous-default-1.scala
10+
* - tests/neg/given-ambiguous-default-2.scala
11+
*/
12+
13+
trait JsValue
14+
trait JsObject extends JsValue
15+
16+
trait Writer[T]
17+
trait BodySerializer[-B]
18+
19+
class Printer
20+
21+
given Writer[JsValue] = ???
22+
given Writer[JsObject] = ???
23+
24+
// This is not an exact desugaring of the original code: currently the compiler
25+
// actually changes the modifier of the parameter list from `using` to
26+
// `implicit` when desugaring the context-bound `B: Writer` to `implicit writer:
27+
// Writer[B]`, but we can't write in user code as this is not valid syntax.
28+
given [B](using
29+
writer: Writer[B],
30+
printer: Printer = new Printer
31+
): BodySerializer[B] = ???
32+
33+
def f: Unit =
34+
summon[BodySerializer[JsObject]] // error: Ambiguous given instances

tests/neg/19414.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/19414.scala:27:34 ----------------------------------------------------------------------
2+
27 | summon[BodySerializer[JsObject]] // error: Ambiguous given instances
3+
| ^
4+
|Ambiguous given instances: both given instance given_Writer_JsValue and given instance given_Writer_JsObject match type Writer[B] of parameter x of method summon in object Predef

tests/neg/19414.scala

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
/** This test checks that provided given instances take precedence over default
2+
* given arguments, even when there are multiple default arguments.
3+
*
4+
* Before the fix for issue #19414, this code would fail with a "No given
5+
* instance of type BodySerializer[JsObject]".
6+
*
7+
* See also:
8+
* - tests/neg/19414-desugared.scala
9+
* - tests/neg/given-ambiguous-default-1.scala
10+
* - tests/neg/given-ambiguous-default-2.scala
11+
*/
12+
13+
trait JsValue
14+
trait JsObject extends JsValue
15+
16+
trait Writer[T]
17+
trait BodySerializer[-B]
18+
19+
class Printer
20+
21+
given Writer[JsValue] = ???
22+
given Writer[JsObject] = ???
23+
24+
given [B: Writer](using printer: Printer = new Printer): BodySerializer[B] = ???
25+
26+
def f: Unit =
27+
summon[BodySerializer[JsObject]] // error: Ambiguous given instances
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-default-1.scala:19:23 --------------------------------------------------
2+
19 |def f: Unit = summon[B] // error: Ambiguous given instances
3+
| ^
4+
|Ambiguous given instances: both given instance a1 and given instance a2 match type A of parameter x of method summon in object Predef
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
/** This test checks that provided given instances take precedence over default
2+
* given arguments.
3+
*
4+
* In the following code, the compiler must report an "Ambiguous implicits"
5+
* error for the parameter `a`, and must not use its default value.
6+
*
7+
* See also:
8+
* - tests/neg/19414.scala
9+
* - tests/neg/19414-desugared.scala
10+
* - tests/neg/given-ambiguous-default-2.scala
11+
*/
12+
13+
class A
14+
class B
15+
given a1: A = ???
16+
given a2: A = ???
17+
given (using a: A = A()): B = ???
18+
19+
def f: Unit = summon[B] // error: Ambiguous given instances
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-default-2.scala:19:23 --------------------------------------------------
2+
19 |def f: Unit = summon[C] // error: Ambiguous given instances
3+
| ^
4+
|Ambiguous given instances: both given instance a1 and given instance a2 match type A of parameter x of method summon in object Predef
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
/** This test checks that provided given instances take precedence over default
2+
* given arguments, even when there are multiple default arguments.
3+
*
4+
* Before the fix for issue #19414, this code would compile without errors.
5+
*
6+
* See also:
7+
* - tests/neg/given-ambiguous-default-1.scala
8+
* - tests/neg/19414.scala
9+
* - tests/neg/19414-desugared.scala
10+
*/
11+
12+
class A
13+
class B
14+
class C
15+
given a1: A = ???
16+
given a2: A = ???
17+
given (using a: A = A(), b: B = B()): C = ???
18+
19+
def f: Unit = summon[C] // error: Ambiguous given instances

0 commit comments

Comments
 (0)