@@ -36,7 +36,6 @@ import util.{Property, SimpleIdentityMap, SrcPos}
36
36
import Applications .{tupleComponentTypes , wrapDefs , defaultArgument }
37
37
38
38
import collection .mutable
39
- import annotation .tailrec
40
39
import Implicits .*
41
40
import util .Stats .record
42
41
import config .Printers .{gadts , typr }
@@ -53,7 +52,9 @@ import config.Config
53
52
import transform .CheckUnused .OriginalName
54
53
55
54
import scala .annotation .constructorOnly
55
+ import scala .annotation .{unchecked as _ , * }
56
56
import dotty .tools .dotc .rewrites .Rewrites
57
+ import dotty .tools .dotc .util .chaining .*
57
58
58
59
object Typer {
59
60
@@ -3842,6 +3843,12 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
3842
3843
3843
3844
def addImplicitArgs (using Context ) =
3844
3845
def hasDefaultParams = methPart(tree).symbol.hasDefaultParams
3846
+ def findDefaultArgument (argIndex : Int ): Tree =
3847
+ def appPart (t : Tree ): Tree = t match
3848
+ case Block (_, expr) => appPart(expr)
3849
+ case Inlined (_, _, expr) => appPart(expr)
3850
+ case t => t
3851
+ defaultArgument(appPart(tree), n = argIndex, testOnly = false )
3845
3852
def implicitArgs (formals : List [Type ], argIndex : Int , pt : Type ): List [Tree ] = formals match
3846
3853
case Nil => Nil
3847
3854
case formal :: formals1 =>
@@ -3863,13 +3870,8 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
3863
3870
then implicitArgs(formals, argIndex, pt1)
3864
3871
else arg :: implicitArgs(formals1, argIndex + 1 , pt1)
3865
3872
case failed : SearchFailureType =>
3866
- lazy val defaultArg =
3867
- def appPart (t : Tree ): Tree = t match
3868
- case Block (stats, expr) => appPart(expr)
3869
- case Inlined (_, _, expr) => appPart(expr)
3870
- case _ => t
3871
- defaultArgument(appPart(tree), argIndex, testOnly = false )
3872
- .showing(i " default argument: for $formal, $tree, $argIndex = $result" , typr)
3873
+ lazy val defaultArg = findDefaultArgument(argIndex)
3874
+ .showing(i " default argument: for $formal, $tree, $argIndex = $result" , typr)
3873
3875
if ! hasDefaultParams || defaultArg.isEmpty then
3874
3876
// no need to search further, the adapt fails in any case
3875
3877
// the reason why we continue inferring arguments in case of an AmbiguousImplicits
@@ -3891,44 +3893,44 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
3891
3893
arg :: inferArgsAfter(arg)
3892
3894
end implicitArgs
3893
3895
3894
- /** Reports errors for arguments of `appTree` that have a
3895
- * `SearchFailureType`.
3896
- */
3897
- def issueErrors (fun : Tree , args : List [Tree ]): Tree =
3898
- // Prefer other errors over ambiguities. If nested in outer searches a missing
3899
- // implicit can be healed by simply dropping this alternative and trying something
3900
- // else. But an ambiguity is sticky and propagates outwards. If we have both
3901
- // a missing implicit on one argument and an ambiguity on another the whole
3902
- // branch should be classified as a missing implicit.
3903
- val firstNonAmbiguous = args.tpes.find(tp => tp.isError && ! tp.isInstanceOf [AmbiguousImplicits ])
3904
- def firstError = args.tpes.find(_.isInstanceOf [SearchFailureType ]).getOrElse(NoType )
3905
- def firstFailure = firstNonAmbiguous.getOrElse(firstError)
3906
- val errorType =
3907
- firstFailure match
3908
- case tp : AmbiguousImplicits =>
3909
- AmbiguousImplicits (tp.alt1, tp.alt2, tp.expectedType, tp.argument, nested = true )
3910
- case tp =>
3911
- tp
3912
- val res = untpd.Apply (fun, args).withType(errorType)
3913
-
3914
- wtp.paramNames.lazyZip(wtp.paramInfos).lazyZip(args).foreach { (paramName, formal, arg) =>
3915
- arg.tpe match
3916
- case failure : SearchFailureType =>
3917
- val methodStr = err.refStr(methPart(fun).tpe)
3918
- val paramStr = implicitParamString(paramName, methodStr, fun)
3919
- val paramSym = fun.symbol.paramSymss.flatten.find(_.name == paramName)
3920
- val paramSymWithMethodCallTree = paramSym.map((_, res))
3921
- report.error(
3922
- missingArgMsg(arg, formal, paramStr, paramSymWithMethodCallTree),
3923
- tree.srcPos.endPos
3924
- )
3925
- case _ =>
3926
- }
3927
-
3928
- res
3896
+ // Pick a failure type to propagate, if any.
3897
+ // Prefer other errors over ambiguities. If nested in outer searches a missing
3898
+ // implicit can be healed by simply dropping this alternative and trying something
3899
+ // else. But an ambiguity is sticky and propagates outwards. If we have both
3900
+ // a missing implicit on one argument and an ambiguity on another the whole
3901
+ // branch should be classified as a missing implicit.
3902
+ def propagatedFailure (args : List [Tree ]): Type = args match
3903
+ case arg :: args => arg.tpe match
3904
+ case ambi : AmbiguousImplicits => propagatedFailure(args) match
3905
+ case NoType | (_ : AmbiguousImplicits ) => ambi
3906
+ case failed => failed
3907
+ case failed : SearchFailureType => failed
3908
+ case _ => propagatedFailure(args)
3909
+ case Nil => NoType
3910
+
3911
+ /** Reports errors for arguments of `appTree` that have a `SearchFailureType`.
3912
+ */
3913
+ def issueErrors (fun : Tree , args : List [Tree ], failureType : Type ): Tree =
3914
+ val errorType = failureType match
3915
+ case ai : AmbiguousImplicits => ai.asNested
3916
+ case tp => tp
3917
+ untpd.Apply (fun, args)
3918
+ .withType(errorType)
3919
+ .tap: res =>
3920
+ wtp.paramNames.lazyZip(wtp.paramInfos).lazyZip(args).foreach: (paramName, formal, arg) =>
3921
+ arg.tpe match
3922
+ case failure : SearchFailureType =>
3923
+ val methodStr = err.refStr(methPart(fun).tpe)
3924
+ val paramStr = implicitParamString(paramName, methodStr, fun)
3925
+ val paramSym = fun.symbol.paramSymss.flatten.find(_.name == paramName)
3926
+ val paramSymWithMethodCallTree = paramSym.map((_, res))
3927
+ val msg = missingArgMsg(arg, formal, paramStr, paramSymWithMethodCallTree)
3928
+ report.error(msg, tree.srcPos.endPos)
3929
+ case _ =>
3929
3930
3930
3931
val args = implicitArgs(wtp.paramInfos, 0 , pt)
3931
- if (args.tpes.exists(_.isInstanceOf [SearchFailureType ])) {
3932
+ val failureType = propagatedFailure(args)
3933
+ if failureType.exists then
3932
3934
// If there are several arguments, some arguments might already
3933
3935
// have influenced the context, binding variables, but later ones
3934
3936
// might fail. In that case the constraint and instantiated variables
@@ -3937,29 +3939,36 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
3937
3939
3938
3940
// If method has default params, fall back to regular application
3939
3941
// where all inferred implicits are passed as named args.
3940
- if hasDefaultParams then
3942
+ if hasDefaultParams && ! failureType. isInstanceOf [ AmbiguousImplicits ] then
3941
3943
// Only keep the arguments that don't have an error type, or that
3942
- // have an `AmbiguousImplicits` error type. The later ensures that a
3944
+ // have an `AmbiguousImplicits` error type. The latter ensures that a
3943
3945
// default argument can't override an ambiguous implicit. See tests
3944
3946
// `given-ambiguous-default*` and `19414*`.
3945
3947
val namedArgs =
3946
- wtp.paramNames.lazyZip(args)
3947
- .filter((_, arg) => ! arg.tpe.isError || arg.tpe.isInstanceOf [AmbiguousImplicits ])
3948
- .map((pname, arg) => untpd.NamedArg (pname, untpd.TypedSplice (arg)))
3949
-
3950
- val app = cpy.Apply (tree)(untpd.TypedSplice (tree), namedArgs)
3951
- if (wtp.isContextualMethod) app.setApplyKind(ApplyKind .Using )
3952
- typr.println(i " try with default implicit args $app" )
3953
- val retyped = typed(app, pt, locked)
3954
-
3955
- // If the retyped tree still has an error type and is an `Apply`
3956
- // node, we can report the errors for each argument nicely.
3957
- // Otherwise, we don't report anything here.
3958
- retyped match
3959
- case Apply (tree, args) if retyped.tpe.isError => issueErrors(tree, args)
3960
- case _ => retyped
3961
- else issueErrors(tree, args)
3962
- }
3948
+ wtp.paramNames.lazyZip(args).collect:
3949
+ case (pname, arg) if ! arg.tpe.isError || arg.tpe.isInstanceOf [AmbiguousImplicits ] =>
3950
+ untpd.NamedArg (pname, untpd.TypedSplice (arg))
3951
+ .toList
3952
+ val usingDefaultArgs =
3953
+ wtp.paramNames.zipWithIndex
3954
+ .exists((n, i) => ! namedArgs.exists(_.name == n) && ! findDefaultArgument(i).isEmpty)
3955
+
3956
+ if ! usingDefaultArgs then
3957
+ issueErrors(tree, args, failureType)
3958
+ else
3959
+ val app = cpy.Apply (tree)(untpd.TypedSplice (tree), namedArgs)
3960
+ // old-style implicit needs to be marked using so that implicits are searched
3961
+ typr.println(i " try with default implicit args $app" )
3962
+ // If the retyped tree still has an error type and is an `Apply`
3963
+ // node, we can report the errors for each argument nicely.
3964
+ // Otherwise, we don't report anything here.
3965
+ typed(app, pt, locked) match
3966
+ case retyped @ Apply (tree, args) if retyped.tpe.isError =>
3967
+ propagatedFailure(args) match
3968
+ case sft : SearchFailureType => issueErrors(tree, args, sft)
3969
+ case _ => issueErrors(tree, args, retyped.tpe)
3970
+ case retyped => retyped
3971
+ else issueErrors(tree, args, failureType)
3963
3972
else
3964
3973
inContext(origCtx):
3965
3974
// Reset context in case it was set to a supercall context before.
0 commit comments