Skip to content

Commit 3a650e9

Browse files
committed
Take @TargetNAME into account when resolving extension methods of value classes
Before target name we only matched on signatures. This was OK, since multiple extension methods of the same class must be different, otherwise we will get a "have the same erasure" error later at erasurePhase. But with @TargetNAME that's now a legal situation that needs to be resolve correctly. We do this by propagating the target name to the extension method and verifiying that the target names of the original and extension methods match. Fixes #16464
1 parent 716d93d commit 3a650e9

File tree

4 files changed

+56
-3
lines changed

4 files changed

+56
-3
lines changed

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

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -188,9 +188,17 @@ object ExtensionMethods {
188188
val companion = imeth.owner.companionModule
189189
val companionInfo = companion.info
190190
val candidates = companionInfo.decl(extensionName(imeth)).alternatives
191-
val matching =
192-
// See the documentation of `memberSignature` to understand why `.stripPoly.ensureMethodic` is needed here.
193-
candidates filter (c => FullParameterization.memberSignature(c.info) == imeth.info.stripPoly.ensureMethodic.signature)
191+
def matches(candidate: SingleDenotation) =
192+
FullParameterization.memberSignature(candidate.info) == imeth.info.stripPoly.ensureMethodic.signature
193+
// See the documentation of `memberSignature` to understand why `.stripPoly.ensureMethodic` is needed here.
194+
&& (if imeth.targetName == imeth.name then
195+
// imeth does not have a @targetName annotation, candidate should not have one either
196+
candidate.symbol.targetName == candidate.symbol.name
197+
else
198+
// imeth has a @targetName annotation, candidate's target name must match
199+
imeth.targetName == candidate.symbol.targetName
200+
)
201+
val matching = candidates.filter(matches)
194202
assert(matching.nonEmpty,
195203
i"""no extension method found for:
196204
|
@@ -203,6 +211,9 @@ object ExtensionMethods {
203211
| Candidates (signatures normalized):
204212
|
205213
| ${candidates.map(c => s"${c.name}:${c.info.signature}:${FullParameterization.memberSignature(c.info)}").mkString("\n")}""")
214+
if matching.tail.nonEmpty then
215+
// this case will report a "have the same erasure" error later at erasure pahse
216+
report.log(i"mutiple extension methods match $imeth: ${candidates.map(c => i"${c.name}:${c.info}")}")
206217
matching.head.symbol.asTerm
207218
}
208219
}

tests/neg/i16464.scala

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
2+
implicit final class SomeOps(e: Int) extends AnyVal:
3+
def -(other: Seq[Int]) = List(1)
4+
def -(other: Seq[Long]) = List(2) // error: double definition
5+
6+
def main(): Unit = 1 - Seq.empty[Int]

tests/pos/i16464.scala

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import scala.annotation.targetName
2+
3+
object test1:
4+
implicit final class SomeOps(e: Int) extends AnyVal:
5+
@targetName("a")
6+
def -(other: Seq[Int]) = List(1)
7+
@targetName("b")
8+
def -(other: Seq[Long]) = List(2)
9+
10+
def main(): Unit = 1 - Seq.empty[Int]
11+
12+
object test2:
13+
implicit final class SomeOps(e: Int) extends AnyVal:
14+
@targetName("a")
15+
def -(other: Seq[Int]) = List(1)
16+
def -(other: Seq[Long]) = List(2)
17+
18+
def main(): Unit = 1 - Seq.empty[Int]
19+
20+
object test3:
21+
implicit final class SomeOps(e: Int) extends AnyVal:
22+
def -(other: Seq[Int]) = List(1)
23+
@targetName("b")
24+
def -(other: Seq[Long]) = List(2)
25+
26+
def main(): Unit = 1 - Seq.empty[Int]

tests/run/i16464.scala

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import scala.annotation.targetName
2+
3+
implicit final class SomeOps(e: Int) extends AnyVal:
4+
@targetName("a")
5+
def -(other: Seq[Int]) = List(1)
6+
@targetName("b")
7+
def -(other: Seq[Long]) = List(2)
8+
9+
@main
10+
def Test(): Unit = 1 - Seq.empty[Int]

0 commit comments

Comments
 (0)