Skip to content

Commit b862758

Browse files
authored
Merge pull request #3710 from dotty-staging/fix-#2994
Fix #1905: Detect case where bridge would clash with the member
2 parents 6d91ef2 + f653095 commit b862758

File tree

3 files changed

+46
-6
lines changed

3 files changed

+46
-6
lines changed

compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,12 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) {
170170
case tp: TypeRef =>
171171
if (tp.symbol.isAnonymousClass && !ctx.settings.uniqid.value)
172172
return toText(tp.info)
173+
if (tp.symbol.is(Param))
174+
tp.prefix match {
175+
case pre: ThisType if pre.cls == tp.symbol.owner =>
176+
return nameString(tp.symbol)
177+
case _ =>
178+
}
173179
case ExprType(result) =>
174180
return "=> " ~ toText(result)
175181
case ErasedValueType(tycon, underlying) =>
@@ -501,7 +507,7 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) {
501507
typeDefText(tparamsTxt, toText(rhs))
502508
case LambdaTypeTree(tparams, body) =>
503509
recur(body, tparamsText(tparams))
504-
case rhs: TypeTree if rhs.tpe.isInstanceOf[TypeBounds] =>
510+
case rhs: TypeTree if rhs.typeOpt.isInstanceOf[TypeBounds] =>
505511
typeDefText(tparamsTxt, toText(rhs))
506512
case rhs =>
507513
typeDefText(tparamsTxt, optText(rhs)(" = " ~ _))

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

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ class Bridges(root: ClassSymbol)(implicit ctx: Context) {
1616

1717
assert(ctx.phase == ctx.erasurePhase.next)
1818
private val preErasureCtx = ctx.withPhase(ctx.erasurePhase)
19+
private val elimErasedCtx = ctx.withPhase(ctx.elimErasedValueTypePhase.next)
1920

2021
private class BridgesCursor(implicit ctx: Context) extends OverridingPairs.Cursor(root) {
2122

@@ -35,31 +36,47 @@ class Bridges(root: ClassSymbol)(implicit ctx: Context) {
3536
private val bridgesScope = newScope
3637
private val bridgeTarget = newMutableSymbolMap[Symbol]
3738

39+
def bridgePosFor(member: Symbol) =
40+
if (member.owner == root && member.pos.exists) member.pos else root.pos
41+
3842
/** Add a bridge between `member` and `other`, where `member` overrides `other`
3943
* before erasure, if the following conditions are satisfied.
4044
*
41-
* - `member` and other have different signatures
42-
* - there is not yet a bridge with the same name and signature in `root`
45+
* - `member` and `other` have different signatures
46+
* - there is not yet a bridge with the same name and signature in `root`.
4347
*
4448
* The bridge has the erased info of `other` and forwards to `member`.
49+
* Additionally, if `member` and `other` do have the same signature,
50+
* but not the same type after erasure and before elimErasedValueTypes
51+
* issue an error: A bridge would be needed yet it would clash with the member itself.
52+
* See neg/i1905.scala
4553
*/
4654
private def addBridgeIfNeeded(member: Symbol, other: Symbol) = {
4755
def bridgeExists =
4856
bridgesScope.lookupAll(member.name).exists(bridge =>
4957
bridgeTarget(bridge) == member && bridge.signature == other.signature)
50-
if (!(member.signature == other.signature || bridgeExists))
58+
def info(sym: Symbol)(implicit ctx: Context) = sym.info
59+
def desc(sym: Symbol)= i"$sym${info(sym)(preErasureCtx)} in ${sym.owner}"
60+
if (member.signature == other.signature) {
61+
if (!member.info.matches(other.info))
62+
ctx.error(em"""bridge generated for member ${desc(member)}
63+
|which overrides ${desc(other)}
64+
|clashes with definition of the member itself; both have erased type ${info(member)(elimErasedCtx)}."""",
65+
bridgePosFor(member))
66+
}
67+
else if (!bridgeExists)
5168
addBridge(member, other)
5269
}
5370

5471
/** Generate bridge between `member` and `other`
5572
*/
5673
private def addBridge(member: Symbol, other: Symbol) = {
57-
val bridgePos = if (member.owner == root && member.pos.exists) member.pos else root.pos
5874
val bridge = other.copy(
5975
owner = root,
6076
flags = (member.flags | Method | Bridge | Artifact) &~
6177
(Accessor | ParamAccessor | CaseAccessor | Deferred | Lazy | Module),
62-
coord = bridgePos).enteredAfter(ctx.erasurePhase.asInstanceOf[DenotTransformer]).asTerm
78+
coord = bridgePosFor(member))
79+
.enteredAfter(ctx.erasurePhase.asInstanceOf[DenotTransformer]).asTerm
6380

6481
ctx.debuglog(
6582
i"""generating bridge from ${other.showLocated}: ${other.info}

tests/neg/i1905.scala

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
class Arr[T](private val underlying: scala.Array[T]) extends AnyVal
2+
3+
abstract class SeqMonoTransforms[+A, +Repr] {
4+
protected[this] def fromIterableWithSameElemType(): Repr
5+
def getFIWSET: Repr = fromIterableWithSameElemType()
6+
}
7+
8+
class ArrOps[A](val xs: Arr[A]) extends SeqMonoTransforms[A, Arr[A]] {
9+
def fromIterableWithSameElemType(): Arr[A] = xs // error: bridge clashes with member
10+
}
11+
12+
object Test {
13+
def main(args: Array[String]) = {
14+
val t = new ArrOps(new Arr(Array(1, 2, 3)))
15+
val t2 = t.getFIWSET
16+
}
17+
}

0 commit comments

Comments
 (0)