Skip to content

Commit 61626ea

Browse files
committed
Factor out commonalities between RefChecks and Bridges cursors
1 parent 0a77f6b commit 61626ea

File tree

3 files changed

+35
-33
lines changed

3 files changed

+35
-33
lines changed

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

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -18,26 +18,23 @@ class Bridges(root: ClassSymbol, thisPhase: DenotTransformer)(using Context) {
1818
private val preErasureCtx = ctx.withPhase(erasurePhase)
1919
private lazy val elimErasedCtx = ctx.withPhase(elimErasedValueTypePhase.next)
2020

21-
private class BridgesCursor(using Context) extends OverridingPairs.Cursor(root) {
21+
private class BridgesCursor(using Context) extends OverridingPairs.PreErasureCursor(root):
2222

2323
override def isSubParent(parent: Symbol, bc: Symbol)(using Context) =
2424
true
2525
// Never consider a bridge if there is a superclass that would contain it
2626
// See run/t2857.scala for a test that would break with a VerifyError otherwise.
2727

28-
/** Only use the superclass of `root` as a parent class. This means
29-
* overriding pairs that have a common implementation in a trait parent
30-
* are also counted. This is necessary because we generate bridge methods
31-
* only in classes, never in traits.
32-
*/
3328
override def parents = Array(root.superClass)
29+
// Only use the superclass of `root` as a parent class. This means
30+
// overriding pairs that have a common implementation in a trait parent
31+
// are also counted. This is necessary because we generate bridge methods
32+
// only in classes, never in traits.
3433

3534
override def exclude(sym: Symbol) =
3635
!sym.isOneOf(MethodOrModule) || super.exclude(sym)
3736

38-
override def canBeHandledByParent(sym1: Symbol, sym2: Symbol, parent: Symbol): Boolean =
39-
OverridingPairs.isOverridingPair(sym1, sym2, parent.thisType)
40-
}
37+
end BridgesCursor
4138

4239
val site = root.thisType
4340

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

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,34 @@ object OverridingPairs:
168168
next()
169169
end Cursor
170170

171+
/** A cursor to be used before erasure (i.e. in RefChecks and for bridge construction).
172+
* It differs from a general cursor in imposing two additional conditions when an overriding
173+
* pair can be ignored since it is already handled in a parent class:
174+
* 1. The two symbols must also override each other when seen as members of
175+
* the common parent class. See neg/i12828.scala for an example where this matters.
176+
* 2. The overriding symbol appears before the overridden symbol in the linearization
177+
* of the parent class. See neg/i5094.scala for an example where this matters.
178+
*/
179+
class PreErasureCursor(base: Symbol)(using Context) extends Cursor(base):
180+
181+
private def inLinearizationOrder(sym1: Symbol, sym2: Symbol, parent: Symbol): Boolean =
182+
val owner1 = sym1.owner
183+
val owner2 = sym2.owner
184+
def precedesIn(bcs: List[ClassSymbol]): Boolean = (bcs: @unchecked) match
185+
case bc :: bcs1 =>
186+
if owner1 eq bc then true
187+
else if owner2 eq bc then false
188+
else precedesIn(bcs1)
189+
case _ =>
190+
false
191+
precedesIn(parent.asClass.baseClasses)
192+
193+
override def canBeHandledByParent(sym1: Symbol, sym2: Symbol, parent: Symbol): Boolean =
194+
OverridingPairs.isOverridingPair(sym1, sym2, parent.thisType)
195+
&& inLinearizationOrder(sym1, sym2, parent)
196+
197+
end PreErasureCursor
198+
171199
/** Is this `sym1` considered an override of `sym2` (or vice versa) if both are
172200
* seen as members of `site`?
173201
* We declare a match if either we have a full match including matching names

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

Lines changed: 1 addition & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -469,33 +469,10 @@ object RefChecks {
469469
}*/
470470
}
471471

472-
val opc = new OverridingPairs.Cursor(clazz):
472+
val opc = new OverridingPairs.PreErasureCursor(clazz):
473473
override def matches(sym1: Symbol, sym2: Symbol): Boolean =
474474
isOverridingPair(sym1, sym2, self)
475475

476-
private def inLinearizationOrder(sym1: Symbol, sym2: Symbol, parent: Symbol): Boolean =
477-
val owner1 = sym1.owner
478-
val owner2 = sym2.owner
479-
def precedesIn(bcs: List[ClassSymbol]): Boolean = (bcs: @unchecked) match
480-
case bc :: bcs1 =>
481-
if owner1 eq bc then true
482-
else if owner2 eq bc then false
483-
else precedesIn(bcs1)
484-
case _ =>
485-
false
486-
precedesIn(parent.asClass.baseClasses)
487-
488-
// We can exclude pairs safely from checking only under two additional conditions
489-
// - their signatures also match in the parent class.
490-
// See neg/i12828.scala for an example where this matters.
491-
// - They overriding/overridden appear in linearization order.
492-
// See neg/i5094.scala for an example where this matters.
493-
override def canBeHandledByParent(sym1: Symbol, sym2: Symbol, parent: Symbol): Boolean =
494-
isOverridingPair(sym1, sym2, parent.thisType)
495-
.showing(i"already handled ${sym1.showLocated}: ${sym1.asSeenFrom(parent.thisType).signature}, ${sym2.showLocated}: ${sym2.asSeenFrom(parent.thisType).signature} = $result", refcheck)
496-
&& inLinearizationOrder(sym1, sym2, parent)
497-
end opc
498-
499476
while opc.hasNext do
500477
checkOverride(opc.overriding, opc.overridden)
501478
opc.next()

0 commit comments

Comments
 (0)