Skip to content

Commit 6800e09

Browse files
committed
Drop all IgnoredProto parts before implicit search
Drop all IgnoredProto parts of the expected type before inferring the arguments of an implicit method. That way, we propagate all available info by `constrainResult` into the current constraint before doing the implicit search. This prevents ambiguity errors. See pos/i5773.scala.
1 parent 8e22afd commit 6800e09

File tree

5 files changed

+64
-19
lines changed

5 files changed

+64
-19
lines changed

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,6 @@ object Mode {
104104
/** Read comments from definitions when unpickling from TASTY */
105105
val ReadComments: Mode = newMode(22, "ReadComments")
106106

107-
/** Suppress insertion of apply or implicit conversion on qualifier */
108-
val FixedQualifier: Mode = newMode(23, "FixedQualifier")
107+
/** We are synthesizing the receiver of an extension method */
108+
val SynthesizeExtMethodReceiver: Mode = newMode(23, "SynthesizeExtMethodReceiver")
109109
}

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

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -799,7 +799,9 @@ trait Applications extends Compatibility { self: Typer with Dynamic =>
799799
* part. Return an optional value to indicate success.
800800
*/
801801
def tryWithImplicitOnQualifier(fun1: Tree, proto: FunProto)(implicit ctx: Context): Option[Tree] =
802-
if (ctx.mode.is(Mode.FixedQualifier)) None
802+
if (ctx.mode.is(Mode.SynthesizeExtMethodReceiver))
803+
// Suppress insertion of apply or implicit conversion on extension method receiver
804+
None
803805
else
804806
tryInsertImplicitOnQualifier(fun1, proto, ctx.typerState.ownedVars) flatMap { fun2 =>
805807
tryEither {
@@ -1691,7 +1693,7 @@ trait Applications extends Compatibility { self: Typer with Dynamic =>
16911693
}
16921694
val app =
16931695
typed(untpd.Apply(core, untpd.TypedSplice(receiver) :: Nil), pt1, ctx.typerState.ownedVars)(
1694-
ctx.addMode(Mode.FixedQualifier))
1696+
ctx.addMode(Mode.SynthesizeExtMethodReceiver))
16951697
if (!app.symbol.is(Extension))
16961698
ctx.error(em"not an extension method: $methodRef", receiver.sourcePos)
16971699
app

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

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2211,7 +2211,9 @@ class Typer extends Namer
22112211
def tryImplicit(fallBack: => Tree) =
22122212
tryInsertImplicitOnQualifier(tree, pt.withContext(ctx), locked).getOrElse(fallBack)
22132213

2214-
if (ctx.mode.is(Mode.FixedQualifier)) tree
2214+
if (ctx.mode.is(Mode.SynthesizeExtMethodReceiver))
2215+
// Suppress insertion of apply or implicit conversion on extension method receiver
2216+
tree
22152217
else pt match {
22162218
case pt @ FunProto(Nil, _)
22172219
if tree.symbol.allOverriddenSymbols.exists(_.info.isNullaryMethod) &&
@@ -2395,6 +2397,13 @@ class Typer extends Namer
23952397
}
23962398
}
23972399

2400+
/** Reveal ignored parts of prototype when synthesizing the receiver
2401+
* of an extension method. This is necessary for pos/i5773.scala
2402+
*/
2403+
def revealProtoOfExtMethod(tp: Type)(implicit ctx: Context): Type =
2404+
if (ctx.mode.is(Mode.SynthesizeExtMethodReceiver)) tp.deepenProto
2405+
else tp
2406+
23982407
def adaptNoArgsImplicitMethod(wtp: MethodType): Tree = {
23992408
assert(wtp.isImplicitMethod)
24002409
val tvarsToInstantiate = tvarsInParams(tree, locked).distinct
@@ -2606,7 +2615,8 @@ class Typer extends Namer
26062615
def adaptNoArgs(wtp: Type): Tree = {
26072616
val ptNorm = underlyingApplied(pt)
26082617
def functionExpected = defn.isFunctionType(ptNorm)
2609-
def resultMatch = constrainResult(tree.symbol, wtp, followAlias(pt))
2618+
def resultMatch =
2619+
constrainResult(tree.symbol, wtp, revealProtoOfExtMethod(followAlias(pt)))
26102620
def needsEta = pt match {
26112621
case _: SingletonType => false
26122622
case IgnoredProto(_: FunOrPolyProto) => false

tests/neg/i5773.scala

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
trait Semigroup[T] {
22
def (lhs: T) append (rhs: T): T
3+
def (lhs: Int) appendS (rhs: T): T = ???
34
}
45

56
object Semigroup {
@@ -8,25 +9,24 @@ object Semigroup {
89
}
910

1011
implicit def sumSemigroup[N](implicit N: Numeric[N]): Semigroup[N] = new {
11-
override def (lhs: N) append (rhs: N): N = ??? // N.plus(lhs, rhs)
12-
}
13-
14-
implicit class SumSemigroupDeco[N](implicit N: Numeric[N]) extends Semigroup[N] {
15-
override def (lhs: N) append (rhs: N): N = ??? // N.plus(lhs, rhs)
12+
override def (lhs: N) append (rhs: N): N = N.plus(lhs, rhs)
13+
def (lhs: Int) appendS (rhs: N): N = ??? // N.plus(lhs, rhs)
1614
}
1715
}
1816

1917

2018
object Main {
2119
import Semigroup.sumSemigroup // this is not sufficient
2220
def f1 = {
23-
import Semigroup.stringAppend // necessary to make the extension method visible
24-
println("Hi" append " mum") // ok
25-
println(1 append 2) // error: this won't compile
26-
}
27-
28-
def f2 = {
29-
implicit val intSumAppend: Semigroup[Int] = sumSemigroup[Int]
30-
println(3 append 4) // this will
21+
println(1 appendS 2) // error This should give the following error message:
22+
/*
23+
21 | println(1 appendS 2) // error This should give the following error message:
24+
| ^^^^^^^^^
25+
|value appendS is not a member of Int.
26+
|An extension method was tried, but could not be fully constructed:
27+
|
28+
| Semigroup.sumSemigroup[Any](/* ambiguous */implicitly[Numeric[Any]]).appendS()
29+
one error found
30+
*/
3131
}
3232
}

tests/pos/i5773.scala

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
trait Semigroup[T] {
2+
def (lhs: T) append (rhs: T): T
3+
}
4+
5+
object Semigroup {
6+
implicit object stringAppend extends Semigroup[String] {
7+
override def (lhs: String) append (rhs: String): String = lhs + rhs
8+
}
9+
10+
implicit def sumSemigroup[N](implicit N: Numeric[N]): Semigroup[N] = new {
11+
override def (lhs: N) append (rhs: N): N = ??? // N.plus(lhs, rhs)
12+
}
13+
14+
implicit class SumSemigroupDeco[N](implicit N: Numeric[N]) extends Semigroup[N] {
15+
override def (lhs: N) append (rhs: N): N = ??? // N.plus(lhs, rhs)
16+
}
17+
}
18+
19+
20+
object Main {
21+
import Semigroup.sumSemigroup // this is not sufficient
22+
def f1 = {
23+
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
27+
}
28+
29+
def f2 = {
30+
implicit val intSumAppend: Semigroup[Int] = sumSemigroup[Int]
31+
println(3 append 4) // this will
32+
}
33+
}

0 commit comments

Comments
 (0)