diff --git a/compiler/src/dotty/tools/dotc/core/Denotations.scala b/compiler/src/dotty/tools/dotc/core/Denotations.scala index 11314ce11666..cf417ed032bb 100644 --- a/compiler/src/dotty/tools/dotc/core/Denotations.scala +++ b/compiler/src/dotty/tools/dotc/core/Denotations.scala @@ -540,7 +540,7 @@ object Denotations { tp2 match case tp2: MethodType if ctx.typeComparer.matchingMethodParams(tp1, tp2) - && (tp1.isImplicitMethod || tp1.isContextualMethod) == (tp2.isImplicitMethod || tp2.isContextualMethod) + && tp1.isImplicitMethod == tp2.isImplicitMethod && tp1.isErasedMethod == tp2.isErasedMethod => val resType = infoMeet(tp1.resType, tp2.resType.subst(tp2, tp1), safeIntersection) if resType.exists then diff --git a/compiler/src/dotty/tools/dotc/transform/PatternMatcher.scala b/compiler/src/dotty/tools/dotc/transform/PatternMatcher.scala index 750683a0419c..42a085232343 100644 --- a/compiler/src/dotty/tools/dotc/transform/PatternMatcher.scala +++ b/compiler/src/dotty/tools/dotc/transform/PatternMatcher.scala @@ -380,7 +380,7 @@ object PatternMatcher { else { def applyImplicits(acc: Tree, implicits: List[Tree], mt: Type): Tree = mt match { case mt: MethodType => - assert(mt.isImplicitMethod || mt.isContextualMethod) + assert(mt.isImplicitMethod) val (args, rest) = implicits.splitAt(mt.paramNames.size) applyImplicits(acc.appliedToArgs(args), rest, mt.resultType) case _ => diff --git a/compiler/src/dotty/tools/dotc/typer/Applications.scala b/compiler/src/dotty/tools/dotc/typer/Applications.scala index 8181791a705d..c97999f30da1 100644 --- a/compiler/src/dotty/tools/dotc/typer/Applications.scala +++ b/compiler/src/dotty/tools/dotc/typer/Applications.scala @@ -533,15 +533,17 @@ trait Applications extends Compatibility { case formal :: formals1 => /** Add result of typing argument `arg` against parameter type `formal`. - * @return A type transformation to apply to all arguments following this one. + * @return The remaining formal parameter types. If the method is parameter-dependent + * this means substituting the actual argument type for the current formal parameter + * in the remaining formal parameters. */ - def addTyped(arg: Arg, formal: Type): Type => Type = { + def addTyped(arg: Arg, formal: Type): List[Type] = addArg(typedArg(arg, formal), formal) - if (methodType.isParamDependent && typeOfArg(arg).exists) + if methodType.isParamDependent && typeOfArg(arg).exists then // `typeOfArg(arg)` could be missing because the evaluation of `arg` produced type errors - safeSubstParam(_, methodType.paramRefs(n), typeOfArg(arg)) - else identity - } + formals1.mapconserve(safeSubstParam(_, methodType.paramRefs(n), typeOfArg(arg))) + else + formals1 def missingArg(n: Int): Unit = { val pname = methodType.paramNames(n) @@ -553,7 +555,7 @@ trait Applications extends Compatibility { def tryDefault(n: Int, args1: List[Arg]): Unit = { val sym = methRef.symbol - val defaultExpr = + val defaultArg = if (isJavaAnnotConstr(sym)) { val cinfo = sym.owner.asClass.classInfo val pname = methodType.paramNames(n) @@ -580,10 +582,12 @@ trait Applications extends Compatibility { EmptyTree } - if (!defaultExpr.isEmpty) { - val substParam = addTyped(treeToArg(defaultExpr), formal) - matchArgs(args1, formals1.mapconserve(substParam), n + 1) - } + def implicitArg = implicitArgTree(formal, appPos.span) + + if !defaultArg.isEmpty then + matchArgs(args1, addTyped(treeToArg(defaultArg), formal), n + 1) + else if methodType.isContextualMethod && ctx.mode.is(Mode.ImplicitsEnabled) then + matchArgs(args1, addTyped(treeToArg(implicitArg), formal), n + 1) else missingArg(n) } @@ -605,8 +609,7 @@ trait Applications extends Compatibility { case EmptyTree :: args1 => tryDefault(n, args1) case arg :: args1 => - val substParam = addTyped(arg, formal) - matchArgs(args1, formals1.mapconserve(substParam), n + 1) + matchArgs(args1, addTyped(arg, formal), n + 1) case nil => tryDefault(n, args) } @@ -1674,10 +1677,7 @@ trait Applications extends Compatibility { pt match case pt: FunProto => if pt.applyKind == ApplyKind.Using then - val alts0 = alts.filterConserve { alt => - val mt = alt.widen.stripPoly - mt.isImplicitMethod || mt.isContextualMethod - } + val alts0 = alts.filterConserve(_.widen.stripPoly.isImplicitMethod) if alts0 ne alts then return resolve(alts0) else if alts.exists(_.widen.stripPoly.isContextualMethod) then return resolveMapped(alts, alt => stripImplicit(alt.widen), pt) diff --git a/tests/run/extra-implicits.check b/tests/run/extra-implicits.check new file mode 100644 index 000000000000..5df402dfaf4d --- /dev/null +++ b/tests/run/extra-implicits.check @@ -0,0 +1,8 @@ +A(explicit) +B(default) +A(explicit) +B(default) +A(default) +B(explicit) +A(explicit) +B(explicit) diff --git a/tests/run/extra-implicits.scala b/tests/run/extra-implicits.scala new file mode 100644 index 000000000000..615bd50a344d --- /dev/null +++ b/tests/run/extra-implicits.scala @@ -0,0 +1,18 @@ + +case class A(x: String) +case class B(x: String) +given a1 as A("default") +given b1 as B("default") +val a2 = A("explicit") +val b2 = B("explicit") + +def f(using a: A, b: B): Unit = + println(a) + println(b) + +@main def Test = + f(using a2) + f(using a = a2) + f(using b = b2) + f(using b = b2, a = a2) +