@@ -3707,7 +3707,6 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
3707
3707
3708
3708
private def adapt1 (tree : Tree , pt : Type , locked : TypeVars )(using Context ): Tree = {
3709
3709
assert(pt.exists && ! pt.isInstanceOf [ExprType ] || ctx.reporter.errorsReported, i " tree: $tree, pt: $pt" )
3710
- def methodStr = err.refStr(methPart(tree).tpe)
3711
3710
3712
3711
def readapt (tree : Tree )(using Context ) = adapt(tree, pt, locked)
3713
3712
def readaptSimplified (tree : Tree )(using Context ) = readapt(simplify(tree, pt, locked))
@@ -3872,49 +3871,38 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
3872
3871
arg :: inferArgsAfter(arg)
3873
3872
end implicitArgs
3874
3873
3875
- val args = implicitArgs(wtp.paramInfos, 0 , pt)
3876
-
3877
- def propagatedFailure (args : List [Tree ]): Type = args match {
3878
- case arg :: args1 =>
3879
- arg.tpe match {
3880
- case ambi : AmbiguousImplicits =>
3881
- propagatedFailure(args1) match {
3882
- case NoType | (_ : AmbiguousImplicits ) => ambi
3883
- case failed => failed
3884
- }
3885
- case failed : SearchFailureType => failed
3886
- case _ => propagatedFailure(args1)
3887
- }
3888
- case Nil => NoType
3889
- }
3890
-
3891
- val propFail = propagatedFailure(args)
3892
-
3893
- def issueErrors (): Tree = {
3894
- def paramSymWithMethodTree (paramName : TermName ) =
3895
- if tree.symbol.exists then
3896
- tree.symbol.paramSymss.flatten
3897
- .map(sym => sym.name -> sym)
3898
- .toMap
3899
- .get(paramName)
3900
- .map((_, tree))
3901
- else
3902
- None
3903
-
3904
- wtp.paramNames.lazyZip(wtp.paramInfos).lazyZip(args).foreach { (paramName, formal, arg) =>
3905
- arg.tpe match {
3874
+ /** 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`.
3877
+ */
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
3881
+ arg.tpe match
3906
3882
case failure : SearchFailureType =>
3907
- report.error(
3908
- missingArgMsg(arg, formal, implicitParamString(paramName, methodStr, tree), paramSymWithMethodTree(paramName)),
3909
- tree.srcPos.endPos
3910
- )
3911
- case _ =>
3912
- }
3913
- }
3914
- untpd.Apply (tree, args).withType(propFail)
3915
- }
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
+
3890
+ val methodStr = err.refStr(methPart(fun).tpe)
3891
+ 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 _ => ()
3916
3903
3917
- if (propFail.exists) {
3904
+ val args = implicitArgs(wtp.paramInfos, 0 , pt)
3905
+ if (args.tpes.exists(_.isInstanceOf [SearchFailureType ])) {
3918
3906
// If there are several arguments, some arguments might already
3919
3907
// have influenced the context, binding variables, but later ones
3920
3908
// might fail. In that case the constraint and instantiated variables
@@ -3923,18 +3911,39 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
3923
3911
3924
3912
// If method has default params, fall back to regular application
3925
3913
// where all inferred implicits are passed as named args.
3926
- if hasDefaultParams && ! propFail.isInstanceOf [AmbiguousImplicits ] then
3927
- val namedArgs = wtp.paramNames.lazyZip(args).flatMap { (pname, arg) =>
3928
- if (arg.tpe.isError) Nil else untpd.NamedArg (pname, untpd.TypedSplice (arg)) :: Nil
3929
- }
3914
+ if hasDefaultParams then
3915
+ // Only keep the arguments that don't have an error type, or that
3916
+ // have an `AmbiguousImplicits` error type. The later ensures that a
3917
+ // default argument can't override an ambiguous implicit. See tests
3918
+ // `given-ambiguous-default*` and `19414*`.
3919
+ val namedArgs =
3920
+ wtp.paramNames.lazyZip(args)
3921
+ .filter((_, arg) => ! arg.tpe.isError || arg.tpe.isInstanceOf [AmbiguousImplicits ])
3922
+ .map((pname, arg) => untpd.NamedArg (pname, untpd.TypedSplice (arg)))
3923
+
3930
3924
val app = cpy.Apply (tree)(untpd.TypedSplice (tree), namedArgs)
3931
3925
val needsUsing = wtp.isContextualMethod || wtp.match
3932
3926
case MethodType (ContextBoundParamName (_) :: _) => sourceVersion.isAtLeast(`3.4`)
3933
3927
case _ => false
3934
3928
if needsUsing then app.setApplyKind(ApplyKind .Using )
3935
3929
typr.println(i " try with default implicit args $app" )
3936
- typed(app, pt, locked)
3937
- else issueErrors()
3930
+ val retyped = typed(app, pt, locked)
3931
+
3932
+ // If the retyped tree still has an error type and is an `Apply`
3933
+ // node, we can report the errors for each argument nicely.
3934
+ // Otherwise, we don't report anything here.
3935
+ retyped match
3936
+ case retyped : Apply if retyped.tpe.isError => reportErrors(retyped, wtp)
3937
+ case _ => ()
3938
+
3939
+ retyped
3940
+ else
3941
+ val firstNonAmbiguous = args.tpes.find(tp => tp.isError && ! tp.isInstanceOf [AmbiguousImplicits ])
3942
+ def firstError = args.tpes.find(_.isError)
3943
+ val errorType = firstNonAmbiguous.orElse(firstError).getOrElse(NoType )
3944
+ val res = untpd.Apply (tree, args).withType(errorType)
3945
+ reportErrors(res, wtp)
3946
+ res
3938
3947
}
3939
3948
else tree match {
3940
3949
case tree : Block =>
0 commit comments