@@ -36,7 +36,6 @@ import util.{Property, SimpleIdentityMap, SrcPos}
3636import Applications .{tupleComponentTypes , wrapDefs , defaultArgument }
3737
3838import collection .mutable
39- import annotation .tailrec
4039import Implicits .*
4140import util .Stats .record
4241import config .Printers .{gadts , typr }
@@ -52,7 +51,8 @@ import config.Config
5251import config .MigrationVersion
5352import transform .CheckUnused .OriginalName
5453
55- import scala .annotation .constructorOnly
54+ import scala .annotation .{unchecked as _ , * }
55+ import dotty .tools .dotc .util .chaining .*
5656
5757object Typer {
5858
@@ -4197,6 +4197,12 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
41974197
41984198 def addImplicitArgs (using Context ) =
41994199 def hasDefaultParams = methPart(tree).symbol.hasDefaultParams
4200+ def findDefaultArgument (argIndex : Int ): Tree =
4201+ def appPart (t : Tree ): Tree = t match
4202+ case Block (_, expr) => appPart(expr)
4203+ case Inlined (_, _, expr) => appPart(expr)
4204+ case t => t
4205+ defaultArgument(appPart(tree), n = argIndex, testOnly = false )
42004206 def implicitArgs (formals : List [Type ], argIndex : Int , pt : Type ): List [Tree ] = formals match
42014207 case Nil => Nil
42024208 case formal :: formals1 =>
@@ -4218,13 +4224,8 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
42184224 then implicitArgs(formals, argIndex, pt1)
42194225 else arg :: implicitArgs(formals1, argIndex + 1 , pt1)
42204226 case failed : SearchFailureType =>
4221- lazy val defaultArg =
4222- def appPart (t : Tree ): Tree = t match
4223- case Block (stats, expr) => appPart(expr)
4224- case Inlined (_, _, expr) => appPart(expr)
4225- case _ => t
4226- defaultArgument(appPart(tree), argIndex, testOnly = false )
4227- .showing(i " default argument: for $formal, $tree, $argIndex = $result" , typr)
4227+ lazy val defaultArg = findDefaultArgument(argIndex)
4228+ .showing(i " default argument: for $formal, $tree, $argIndex = $result" , typr)
42284229 if ! hasDefaultParams || defaultArg.isEmpty then
42294230 // no need to search further, the adapt fails in any case
42304231 // the reason why we continue inferring arguments in case of an AmbiguousImplicits
@@ -4246,44 +4247,44 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
42464247 arg :: inferArgsAfter(arg)
42474248 end implicitArgs
42484249
4249- /** Reports errors for arguments of `appTree` that have a
4250- * `SearchFailureType`.
4251- */
4252- def issueErrors (fun : Tree , args : List [Tree ]): Tree =
4253- // Prefer other errors over ambiguities. If nested in outer searches a missing
4254- // implicit can be healed by simply dropping this alternative and trying something
4255- // else. But an ambiguity is sticky and propagates outwards. If we have both
4256- // a missing implicit on one argument and an ambiguity on another the whole
4257- // branch should be classified as a missing implicit.
4258- val firstNonAmbiguous = args.tpes.find(tp => tp.isError && ! tp.isInstanceOf [AmbiguousImplicits ])
4259- def firstError = args.tpes.find(_.isInstanceOf [SearchFailureType ]).getOrElse(NoType )
4260- def firstFailure = firstNonAmbiguous.getOrElse(firstError)
4261- val errorType =
4262- firstFailure match
4263- case tp : AmbiguousImplicits =>
4264- AmbiguousImplicits (tp.alt1, tp.alt2, tp.expectedType, tp.argument, nested = true )
4265- case tp =>
4266- tp
4267- val res = untpd.Apply (fun, args).withType(errorType)
4268-
4269- wtp.paramNames.lazyZip(wtp.paramInfos).lazyZip(args).foreach { (paramName, formal, arg) =>
4270- arg.tpe match
4271- case failure : SearchFailureType =>
4272- val methodStr = err.refStr(methPart(fun).tpe)
4273- val paramStr = implicitParamString(paramName, methodStr, fun)
4274- val paramSym = fun.symbol.paramSymss.flatten.find(_.name == paramName)
4275- val paramSymWithMethodCallTree = paramSym.map((_, res))
4276- report.error(
4277- missingArgMsg(arg, formal, paramStr, paramSymWithMethodCallTree),
4278- tree.srcPos.endPos
4279- )
4280- case _ =>
4281- }
4282-
4283- res
4250+ // Pick a failure type to propagate, if any.
4251+ // Prefer other errors over ambiguities. If nested in outer searches a missing
4252+ // implicit can be healed by simply dropping this alternative and trying something
4253+ // else. But an ambiguity is sticky and propagates outwards. If we have both
4254+ // a missing implicit on one argument and an ambiguity on another the whole
4255+ // branch should be classified as a missing implicit.
4256+ def propagatedFailure (args : List [Tree ]): Type = args match
4257+ case arg :: args => arg.tpe match
4258+ case ambi : AmbiguousImplicits => propagatedFailure(args) match
4259+ case NoType | (_ : AmbiguousImplicits ) => ambi
4260+ case failed => failed
4261+ case failed : SearchFailureType => failed
4262+ case _ => propagatedFailure(args)
4263+ case Nil => NoType
4264+
4265+ /** Reports errors for arguments of `appTree` that have a `SearchFailureType`.
4266+ */
4267+ def issueErrors (fun : Tree , args : List [Tree ], failureType : Type ): Tree =
4268+ val errorType = failureType match
4269+ case ai : AmbiguousImplicits => ai.asNested
4270+ case tp => tp
4271+ untpd.Apply (fun, args)
4272+ .withType(errorType)
4273+ .tap: res =>
4274+ wtp.paramNames.lazyZip(wtp.paramInfos).lazyZip(args).foreach: (paramName, formal, arg) =>
4275+ arg.tpe match
4276+ case failure : SearchFailureType =>
4277+ val methodStr = err.refStr(methPart(fun).tpe)
4278+ val paramStr = implicitParamString(paramName, methodStr, fun)
4279+ val paramSym = fun.symbol.paramSymss.flatten.find(_.name == paramName)
4280+ val paramSymWithMethodCallTree = paramSym.map((_, res))
4281+ val msg = missingArgMsg(arg, formal, paramStr, paramSymWithMethodCallTree)
4282+ report.error(msg, tree.srcPos.endPos)
4283+ case _ =>
42844284
42854285 val args = implicitArgs(wtp.paramInfos, 0 , pt)
4286- if (args.tpes.exists(_.isInstanceOf [SearchFailureType ])) {
4286+ val failureType = propagatedFailure(args)
4287+ if failureType.exists then
42874288 // If there are several arguments, some arguments might already
42884289 // have influenced the context, binding variables, but later ones
42894290 // might fail. In that case the constraint and instantiated variables
@@ -4292,32 +4293,40 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
42924293
42934294 // If method has default params, fall back to regular application
42944295 // where all inferred implicits are passed as named args.
4295- if hasDefaultParams then
4296+ if hasDefaultParams && ! failureType. isInstanceOf [ AmbiguousImplicits ] then
42964297 // Only keep the arguments that don't have an error type, or that
4297- // have an `AmbiguousImplicits` error type. The later ensures that a
4298+ // have an `AmbiguousImplicits` error type. The latter ensures that a
42984299 // default argument can't override an ambiguous implicit. See tests
42994300 // `given-ambiguous-default*` and `19414*`.
43004301 val namedArgs =
4301- wtp.paramNames.lazyZip(args)
4302- .filter((_, arg) => ! arg.tpe.isError || arg.tpe.isInstanceOf [AmbiguousImplicits ])
4303- .map((pname, arg) => untpd.NamedArg (pname, untpd.TypedSplice (arg)))
4304-
4305- val app = cpy.Apply (tree)(untpd.TypedSplice (tree), namedArgs)
4306- val needsUsing = wtp.isContextualMethod || wtp.match
4307- case MethodType (ContextBoundParamName (_) :: _) => sourceVersion.isAtLeast(`3.4`)
4308- case _ => false
4309- if needsUsing then app.setApplyKind(ApplyKind .Using )
4310- typr.println(i " try with default implicit args $app" )
4311- val retyped = typed(app, pt, locked)
4312-
4313- // If the retyped tree still has an error type and is an `Apply`
4314- // node, we can report the errors for each argument nicely.
4315- // Otherwise, we don't report anything here.
4316- retyped match
4317- case Apply (tree, args) if retyped.tpe.isError => issueErrors(tree, args)
4318- case _ => retyped
4319- else issueErrors(tree, args)
4320- }
4302+ wtp.paramNames.lazyZip(args).collect:
4303+ case (pname, arg) if ! arg.tpe.isError || arg.tpe.isInstanceOf [AmbiguousImplicits ] =>
4304+ untpd.NamedArg (pname, untpd.TypedSplice (arg))
4305+ .toList
4306+ val usingDefaultArgs =
4307+ wtp.paramNames.zipWithIndex
4308+ .exists((n, i) => ! namedArgs.exists(_.name == n) && ! findDefaultArgument(i).isEmpty)
4309+
4310+ if ! usingDefaultArgs then
4311+ issueErrors(tree, args, failureType)
4312+ else
4313+ val app = cpy.Apply (tree)(untpd.TypedSplice (tree), namedArgs)
4314+ // old-style implicit needs to be marked using so that implicits are searched
4315+ val needsUsing = wtp.isImplicitMethod || wtp.match
4316+ case MethodType (ContextBoundParamName (_) :: _) => sourceVersion.isAtLeast(`3.4`)
4317+ case _ => false
4318+ if needsUsing then app.setApplyKind(ApplyKind .Using )
4319+ typr.println(i " try with default implicit args $app" )
4320+ // If the retyped tree still has an error type and is an `Apply`
4321+ // node, we can report the errors for each argument nicely.
4322+ // Otherwise, we don't report anything here.
4323+ typed(app, pt, locked) match
4324+ case retyped @ Apply (tree, args) if retyped.tpe.isError =>
4325+ propagatedFailure(args) match
4326+ case sft : SearchFailureType => issueErrors(tree, args, sft)
4327+ case _ => issueErrors(tree, args, retyped.tpe)
4328+ case retyped => retyped
4329+ else issueErrors(tree, args, failureType)
43214330 else
43224331 inContext(origCtx):
43234332 // Reset context in case it was set to a supercall context before.
0 commit comments