Skip to content

Commit 8978c6b

Browse files
committed
Check invariant about the flags of pattern-bound symbols
The following invariant should be true for pattern-bound symbols, and *only* for pattern-bound symbols: (sym.isType && !sym.isClass && sym.isOneOf(Case)) || (sym.isTerm && sym.isOneOf(Case, butNot = Enum | Module)) The invariant only holds before patternMatcher. After patternMatcher, there are no more pattern trees, thus the invariant does not hold any more.
1 parent 30c9e3e commit 8978c6b

File tree

2 files changed

+35
-5
lines changed

2 files changed

+35
-5
lines changed

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

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -354,6 +354,7 @@ object Phases {
354354
private[this] var myFlatClasses = false
355355
private[this] var myRefChecked = false
356356
private[this] var myLambdaLifted = false
357+
private[this] var myPatternTranslated = false
357358

358359
private[this] var mySameMembersStartId = NoPhaseId
359360
private[this] var mySameParentsStartId = NoPhaseId
@@ -372,7 +373,8 @@ object Phases {
372373
final def erasedTypes: Boolean = myErasedTypes // Phase is after erasure
373374
final def flatClasses: Boolean = myFlatClasses // Phase is after flatten
374375
final def refChecked: Boolean = myRefChecked // Phase is after RefChecks
375-
final def lambdaLifted: Boolean = myLambdaLifted // Phase is after LambdaLift
376+
final def lambdaLifted: Boolean = myLambdaLifted // Phase is after LambdaLift
377+
final def patternTranslated: Boolean = myPatternTranslated // Phase is after PatternMatcher
376378

377379
final def sameMembersStartId: Int = mySameMembersStartId
378380
// id of first phase where all symbols are guaranteed to have the same members as in this phase
@@ -391,6 +393,7 @@ object Phases {
391393
myFlatClasses = prev.getClass == classOf[Flatten] || prev.flatClasses
392394
myRefChecked = prev.getClass == classOf[RefChecks] || prev.refChecked
393395
myLambdaLifted = prev.getClass == classOf[LambdaLift] || prev.lambdaLifted
396+
myPatternTranslated = prev.getClass == classOf[PatternMatcher] || prev.patternTranslated
394397
mySameMembersStartId = if (changesMembers) id else prev.sameMembersStartId
395398
mySameParentsStartId = if (changesParents) id else prev.sameParentsStartId
396399
mySameBaseTypesStartId = if (changesBaseTypes) id else prev.sameBaseTypesStartId

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

Lines changed: 31 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,7 @@ class TreeChecker extends Phase with SymTransformer {
131131
class Checker(phasesToCheck: Seq[Phase]) extends ReTyper with Checking {
132132

133133
private[this] val nowDefinedSyms = new mutable.HashSet[Symbol]
134+
private[this] val patBoundSyms = new mutable.HashSet[Symbol]
134135
private[this] val everDefinedSyms = newMutableSymbolMap[untpd.Tree]
135136

136137
// don't check value classes after typer, as the constraint about constructors doesn't hold after transform
@@ -171,10 +172,25 @@ class TreeChecker extends Phase with SymTransformer {
171172
res
172173
}
173174

175+
/** The following invariant holds:
176+
*
177+
* patBoundSyms.contains(sym) <=> patternBound(sym)
178+
*/
179+
def patternBound(sym: Symbol)(implicit ctx: Context): Boolean =
180+
(sym.isType && !sym.isClass && sym.isOneOf(Case)) ||
181+
(sym.isTerm && sym.isOneOf(Case, butNot = Enum | Module))
182+
174183
def withPatSyms[T](syms: List[Symbol])(op: => T)(implicit ctx: Context): T = {
175-
nowDefinedSyms ++= syms
184+
syms.foreach { sym =>
185+
assert(
186+
patternBound(sym),
187+
"patBoundSyms.contains(sym) => patternBound(sym) is broken." +
188+
" Pattern bound symbol has incorrect flags: " + sym.flags + ", line " + sym.sourcePos.line
189+
)
190+
}
191+
patBoundSyms ++= syms
176192
val res = op
177-
nowDefinedSyms --= syms
193+
patBoundSyms --= syms
178194
res
179195
}
180196

@@ -189,8 +205,19 @@ class TreeChecker extends Phase with SymTransformer {
189205
}
190206

191207
def assertDefined(tree: untpd.Tree)(implicit ctx: Context): Unit =
192-
if (tree.symbol.maybeOwner.isTerm)
193-
assert(nowDefinedSyms contains tree.symbol, i"undefined symbol ${tree.symbol} at line " + tree.sourcePos.line)
208+
if (tree.symbol.maybeOwner.isTerm) {
209+
val sym = tree.symbol
210+
assert(
211+
nowDefinedSyms.contains(sym) || patBoundSyms.contains(sym),
212+
i"undefined symbol ${sym} at line " + tree.sourcePos.line
213+
)
214+
215+
if (!ctx.phase.patternTranslated)
216+
assert(
217+
!patternBound(sym) || patBoundSyms.contains(sym),
218+
"patternBound(sym) => patBoundSyms.contains(sym) is broken, line " + tree.sourcePos.line
219+
)
220+
}
194221

195222
/** assert Java classes are not used as objects */
196223
def assertIdentNotJavaClass(tree: Tree)(implicit ctx: Context): Unit = tree match {

0 commit comments

Comments
 (0)