Skip to content

Commit 7ed93ad

Browse files
Merge pull request #9347 from dotty-staging/change-infer-implicit
Infer missing implicit args in using clause
2 parents 38553ce + 55d7300 commit 7ed93ad

File tree

5 files changed

+45
-19
lines changed

5 files changed

+45
-19
lines changed

compiler/src/dotty/tools/dotc/core/Denotations.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -540,7 +540,7 @@ object Denotations {
540540
tp2 match
541541
case tp2: MethodType
542542
if ctx.typeComparer.matchingMethodParams(tp1, tp2)
543-
&& (tp1.isImplicitMethod || tp1.isContextualMethod) == (tp2.isImplicitMethod || tp2.isContextualMethod)
543+
&& tp1.isImplicitMethod == tp2.isImplicitMethod
544544
&& tp1.isErasedMethod == tp2.isErasedMethod =>
545545
val resType = infoMeet(tp1.resType, tp2.resType.subst(tp2, tp1), safeIntersection)
546546
if resType.exists then

compiler/src/dotty/tools/dotc/transform/PatternMatcher.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -380,7 +380,7 @@ object PatternMatcher {
380380
else {
381381
def applyImplicits(acc: Tree, implicits: List[Tree], mt: Type): Tree = mt match {
382382
case mt: MethodType =>
383-
assert(mt.isImplicitMethod || mt.isContextualMethod)
383+
assert(mt.isImplicitMethod)
384384
val (args, rest) = implicits.splitAt(mt.paramNames.size)
385385
applyImplicits(acc.appliedToArgs(args), rest, mt.resultType)
386386
case _ =>

compiler/src/dotty/tools/dotc/typer/Applications.scala

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -533,15 +533,17 @@ trait Applications extends Compatibility {
533533
case formal :: formals1 =>
534534

535535
/** Add result of typing argument `arg` against parameter type `formal`.
536-
* @return A type transformation to apply to all arguments following this one.
536+
* @return The remaining formal parameter types. If the method is parameter-dependent
537+
* this means substituting the actual argument type for the current formal parameter
538+
* in the remaining formal parameters.
537539
*/
538-
def addTyped(arg: Arg, formal: Type): Type => Type = {
540+
def addTyped(arg: Arg, formal: Type): List[Type] =
539541
addArg(typedArg(arg, formal), formal)
540-
if (methodType.isParamDependent && typeOfArg(arg).exists)
542+
if methodType.isParamDependent && typeOfArg(arg).exists then
541543
// `typeOfArg(arg)` could be missing because the evaluation of `arg` produced type errors
542-
safeSubstParam(_, methodType.paramRefs(n), typeOfArg(arg))
543-
else identity
544-
}
544+
formals1.mapconserve(safeSubstParam(_, methodType.paramRefs(n), typeOfArg(arg)))
545+
else
546+
formals1
545547

546548
def missingArg(n: Int): Unit = {
547549
val pname = methodType.paramNames(n)
@@ -553,7 +555,7 @@ trait Applications extends Compatibility {
553555
def tryDefault(n: Int, args1: List[Arg]): Unit = {
554556
val sym = methRef.symbol
555557

556-
val defaultExpr =
558+
val defaultArg =
557559
if (isJavaAnnotConstr(sym)) {
558560
val cinfo = sym.owner.asClass.classInfo
559561
val pname = methodType.paramNames(n)
@@ -580,10 +582,12 @@ trait Applications extends Compatibility {
580582
EmptyTree
581583
}
582584

583-
if (!defaultExpr.isEmpty) {
584-
val substParam = addTyped(treeToArg(defaultExpr), formal)
585-
matchArgs(args1, formals1.mapconserve(substParam), n + 1)
586-
}
585+
def implicitArg = implicitArgTree(formal, appPos.span)
586+
587+
if !defaultArg.isEmpty then
588+
matchArgs(args1, addTyped(treeToArg(defaultArg), formal), n + 1)
589+
else if methodType.isContextualMethod && ctx.mode.is(Mode.ImplicitsEnabled) then
590+
matchArgs(args1, addTyped(treeToArg(implicitArg), formal), n + 1)
587591
else
588592
missingArg(n)
589593
}
@@ -605,8 +609,7 @@ trait Applications extends Compatibility {
605609
case EmptyTree :: args1 =>
606610
tryDefault(n, args1)
607611
case arg :: args1 =>
608-
val substParam = addTyped(arg, formal)
609-
matchArgs(args1, formals1.mapconserve(substParam), n + 1)
612+
matchArgs(args1, addTyped(arg, formal), n + 1)
610613
case nil =>
611614
tryDefault(n, args)
612615
}
@@ -1674,10 +1677,7 @@ trait Applications extends Compatibility {
16741677
pt match
16751678
case pt: FunProto =>
16761679
if pt.applyKind == ApplyKind.Using then
1677-
val alts0 = alts.filterConserve { alt =>
1678-
val mt = alt.widen.stripPoly
1679-
mt.isImplicitMethod || mt.isContextualMethod
1680-
}
1680+
val alts0 = alts.filterConserve(_.widen.stripPoly.isImplicitMethod)
16811681
if alts0 ne alts then return resolve(alts0)
16821682
else if alts.exists(_.widen.stripPoly.isContextualMethod) then
16831683
return resolveMapped(alts, alt => stripImplicit(alt.widen), pt)

tests/run/extra-implicits.check

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
A(explicit)
2+
B(default)
3+
A(explicit)
4+
B(default)
5+
A(default)
6+
B(explicit)
7+
A(explicit)
8+
B(explicit)

tests/run/extra-implicits.scala

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
2+
case class A(x: String)
3+
case class B(x: String)
4+
given a1 as A("default")
5+
given b1 as B("default")
6+
val a2 = A("explicit")
7+
val b2 = B("explicit")
8+
9+
def f(using a: A, b: B): Unit =
10+
println(a)
11+
println(b)
12+
13+
@main def Test =
14+
f(using a2)
15+
f(using a = a2)
16+
f(using b = b2)
17+
f(using b = b2, a = a2)
18+

0 commit comments

Comments
 (0)