Skip to content

Commit bbaff2b

Browse files
committed
RefChecks refactoring
Break out the logic that visits all overriding pairs with a given base and tests them with a given check function. We need to re-use that logic in the rechecker.
1 parent 631449f commit bbaff2b

File tree

1 file changed

+49
-44
lines changed

1 file changed

+49
-44
lines changed

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

Lines changed: 49 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,54 @@ object RefChecks {
192192

193193
// Override checking ------------------------------------------------------------
194194

195+
/** A class for checking all overriding pairs of `class` with a given check function */
196+
class OverridingPairsChecker(clazz: ClassSymbol, self: Type)(using Context) extends OverridingPairs.Cursor(clazz):
197+
198+
override def matches(sym1: Symbol, sym2: Symbol): Boolean =
199+
isOverridingPair(sym1, sym2, self)
200+
201+
private def inLinearizationOrder(sym1: Symbol, sym2: Symbol, parent: Symbol): Boolean =
202+
val owner1 = sym1.owner
203+
val owner2 = sym2.owner
204+
def precedesIn(bcs: List[ClassSymbol]): Boolean = (bcs: @unchecked) match
205+
case bc :: bcs1 =>
206+
if owner1 eq bc then true
207+
else if owner2 eq bc then false
208+
else precedesIn(bcs1)
209+
case _ =>
210+
false
211+
precedesIn(parent.asClass.baseClasses)
212+
213+
// We can exclude pairs safely from checking only under two additional conditions
214+
// - their signatures also match in the parent class.
215+
// See neg/i12828.scala for an example where this matters.
216+
// - They overriding/overridden appear in linearization order.
217+
// See neg/i5094.scala for an example where this matters.
218+
override def canBeHandledByParent(sym1: Symbol, sym2: Symbol, parent: Symbol): Boolean =
219+
isOverridingPair(sym1, sym2, parent.thisType)
220+
.showing(i"already handled ${sym1.showLocated}: ${sym1.asSeenFrom(parent.thisType).signature}, ${sym2.showLocated}: ${sym2.asSeenFrom(parent.thisType).signature} = $result", refcheck)
221+
&& inLinearizationOrder(sym1, sym2, parent)
222+
223+
def checkAll(checkOverride: (Symbol, Symbol) => Unit) =
224+
while hasNext do
225+
checkOverride(overriding, overridden)
226+
next()
227+
228+
// The OverridingPairs cursor does assume that concrete overrides abstract
229+
// We have to check separately for an abstract definition in a subclass that
230+
// overrides a concrete definition in a superclass. E.g. the following (inspired
231+
// from neg/i11130.scala) needs to be rejected as well:
232+
//
233+
// class A { type T = B }
234+
// class B extends A { override type T }
235+
for dcl <- clazz.info.decls.iterator do
236+
if dcl.is(Deferred) then
237+
for other <- dcl.allOverriddenSymbols do
238+
if !other.is(Deferred) then
239+
checkOverride(dcl, other)
240+
end checkAll
241+
end OverridingPairsChecker
242+
195243
/** 1. Check all members of class `clazz` for overriding conditions.
196244
* That is for overriding member M and overridden member O:
197245
*
@@ -469,50 +517,7 @@ object RefChecks {
469517
}*/
470518
}
471519

472-
val opc = new OverridingPairs.Cursor(clazz):
473-
override def matches(sym1: Symbol, sym2: Symbol): Boolean =
474-
isOverridingPair(sym1, sym2, self)
475-
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-
499-
while opc.hasNext do
500-
checkOverride(opc.overriding, opc.overridden)
501-
opc.next()
502-
503-
// The OverridingPairs cursor does assume that concrete overrides abstract
504-
// We have to check separately for an abstract definition in a subclass that
505-
// overrides a concrete definition in a superclass. E.g. the following (inspired
506-
// from neg/i11130.scala) needs to be rejected as well:
507-
//
508-
// class A { type T = B }
509-
// class B extends A { override type T }
510-
for dcl <- clazz.info.decls.iterator do
511-
if dcl.is(Deferred) then
512-
for other <- dcl.allOverriddenSymbols do
513-
if !other.is(Deferred) then
514-
checkOverride(dcl, other)
515-
520+
OverridingPairsChecker(clazz, self).checkAll(checkOverride)
516521
printMixinOverrideErrors()
517522

518523
// Verifying a concrete class has nothing unimplemented.

0 commit comments

Comments
 (0)