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