Skip to content

Commit 4d85a7d

Browse files
committed
Deepen prototype on AmbiguousImplicits
If an inferred argument is ambiguous, try to deepen the prototyoe, and if that succeeds, try again.
1 parent 30396ea commit 4d85a7d

File tree

2 files changed

+23
-15
lines changed

2 files changed

+23
-15
lines changed

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

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2413,13 +2413,16 @@ class Typer extends Namer
24132413
def dummyArg(tp: Type) = untpd.Ident(nme.???).withTypeUnchecked(tp)
24142414

24152415
def addImplicitArgs(implicit ctx: Context) = {
2416-
def implicitArgs(formals: List[Type], argIndex: Int): List[Tree] = formals match {
2416+
def implicitArgs(formals: List[Type], argIndex: Int, pt: Type): List[Tree] = formals match {
24172417
case Nil => Nil
24182418
case formal :: formals1 =>
24192419
val arg = inferImplicitArg(formal, tree.span.endPos)
24202420
arg.tpe match {
2421-
case failed: SearchFailureType
2422-
if !failed.isInstanceOf[AmbiguousImplicits] && !tree.symbol.hasDefaultParams =>
2421+
case failed: AmbiguousImplicits =>
2422+
val pt1 = pt.deepenProto
2423+
if ((pt1 `ne` pt) && resultMatches(wtp, pt1)) implicitArgs(formals, argIndex, pt1)
2424+
else arg :: implicitArgs(formals1, argIndex + 1, pt1)
2425+
case failed: SearchFailureType if !tree.symbol.hasDefaultParams =>
24232426
// no need to search further, the adapt fails in any case
24242427
// the reason why we continue inferring arguments in case of an AmbiguousImplicits
24252428
// is that we need to know whether there are further errors.
@@ -2433,10 +2436,10 @@ class Typer extends Namer
24332436
if (wtp.isParamDependent && arg.tpe.exists)
24342437
formals1.mapconserve(f1 => safeSubstParam(f1, wtp.paramRefs(argIndex), arg.tpe))
24352438
else formals1
2436-
arg :: implicitArgs(formals2, argIndex + 1)
2439+
arg :: implicitArgs(formals2, argIndex + 1, pt)
24372440
}
24382441
}
2439-
val args = implicitArgs(wtp.paramInfos, 0)
2442+
val args = implicitArgs(wtp.paramInfos, 0, pt)
24402443

24412444
def propagatedFailure(args: List[Tree]): Type = args match {
24422445
case arg :: args1 =>
@@ -2612,11 +2615,12 @@ class Typer extends Namer
26122615
case _ => tp
26132616
}
26142617

2618+
def resultMatches(wtp: Type, pt: Type) =
2619+
constrainResult(tree.symbol, wtp, revealProtoOfExtMethod(followAlias(pt)))
2620+
26152621
def adaptNoArgs(wtp: Type): Tree = {
26162622
val ptNorm = underlyingApplied(pt)
26172623
def functionExpected = defn.isFunctionType(ptNorm)
2618-
def resultMatch =
2619-
constrainResult(tree.symbol, wtp, revealProtoOfExtMethod(followAlias(pt)))
26202624
def needsEta = pt match {
26212625
case _: SingletonType => false
26222626
case IgnoredProto(_: FunOrPolyProto) => false
@@ -2627,8 +2631,9 @@ class Typer extends Namer
26272631
case wtp: ExprType =>
26282632
readaptSimplified(tree.withType(wtp.resultType))
26292633
case wtp: MethodType if wtp.isImplicitMethod &&
2630-
({ resMatch = resultMatch; resMatch } || !functionExpected) =>
2631-
if (resMatch || ctx.mode.is(Mode.ImplicitsEnabled)) adaptNoArgsImplicitMethod(wtp)
2634+
({ resMatch = resultMatches(wtp, pt); resMatch } || !functionExpected) =>
2635+
if (resMatch || ctx.mode.is(Mode.ImplicitsEnabled))
2636+
adaptNoArgsImplicitMethod(wtp)
26322637
else {
26332638
// Don't proceed with implicit search if result type cannot match - the search
26342639
// will likely be under-constrained, which means that an unbounded number of alternatives

tests/pos/i5773.scala

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,23 +11,26 @@ object Semigroup {
1111
override def (lhs: N) append (rhs: N): N = ??? // N.plus(lhs, rhs)
1212
}
1313

14-
implicit class SumSemigroupDeco[N](implicit N: Numeric[N]) extends Semigroup[N] {
14+
implicit class SumSemiGroupDeco[N](implicit N: Numeric[N]) extends Semigroup[N] {
1515
override def (lhs: N) append (rhs: N): N = ??? // N.plus(lhs, rhs)
1616
}
1717
}
1818

19-
2019
object Main {
2120
import Semigroup.sumSemigroup // this is not sufficient
2221
def f1 = {
2322
import Semigroup.stringAppend // necessary to make the extension method visible
24-
println("Hi" append " mum") // ok
25-
//sumSemigroup.apply(1)(2)
26-
println(1 append 2) // error: this won't compile
23+
println("Hi" append " mum")
24+
println(1 append 2)
2725
}
2826

2927
def f2 = {
3028
implicit val intSumAppend: Semigroup[Int] = sumSemigroup[Int]
31-
println(3 append 4) // this will
29+
println(3 append 4)
30+
}
31+
32+
def f3 = {
33+
import Semigroup.SumSemiGroupDeco
34+
sumSemigroup.append(1)(2)
3235
}
3336
}

0 commit comments

Comments
 (0)