diff options
author | Martin Odersky <odersky@gmail.com> | 2014-10-24 18:32:48 +0200 |
---|---|---|
committer | Martin Odersky <odersky@gmail.com> | 2014-10-26 16:24:02 +0100 |
commit | 3a250720a0833d42ed6b23b5837de64b6ce34aed (patch) | |
tree | 008c0b58a9f598da559286deb3fd9f8ab94a2d55 /src/dotty/tools/dotc/transform/TreeChecker.scala | |
parent | 4d370b6073bec9706d427f82c4a6a40fa22fe6d0 (diff) | |
download | dotty-3a250720a0833d42ed6b23b5837de64b6ce34aed.tar.gz dotty-3a250720a0833d42ed6b23b5837de64b6ce34aed.tar.bz2 dotty-3a250720a0833d42ed6b23b5837de64b6ce34aed.zip |
Add missing and double symbol checking to TreeChecker
TreeChecker now tests that a symbol does not have two definitions that define it,
and that every reference to a symbol owner by a term is in the scope of a definition
of that symbol.
Both tests fail on several files for pattern matcher.
Diffstat (limited to 'src/dotty/tools/dotc/transform/TreeChecker.scala')
-rw-r--r-- | src/dotty/tools/dotc/transform/TreeChecker.scala | 46 |
1 files changed, 45 insertions, 1 deletions
diff --git a/src/dotty/tools/dotc/transform/TreeChecker.scala b/src/dotty/tools/dotc/transform/TreeChecker.scala index 1448e8bf9..77e504e25 100644 --- a/src/dotty/tools/dotc/transform/TreeChecker.scala +++ b/src/dotty/tools/dotc/transform/TreeChecker.scala @@ -20,6 +20,7 @@ import reporting.ThrowingReporter import ast.Trees._ import ast.{tpd, untpd} import util.SourcePosition +import collection.mutable import ProtoTypes._ import java.lang.AssertionError @@ -57,6 +58,32 @@ class TreeChecker { } class Checker(phasesToCheck: Seq[Phase]) extends ReTyper { + + val definedSyms = new mutable.HashSet[Symbol] + + def withDefinedSym[T](tree: untpd.Tree)(op: => T)(implicit ctx: Context): T = { + if (tree.isDef) { + //assert(!definedSyms.contains(tree.symbol), i"doubly defined symbol: ${tree.symbol}in $tree") + definedSyms += tree.symbol + //println(i"defined: ${tree.symbol}") + val res = op + definedSyms -= tree.symbol + //println(i"undefined: ${tree.symbol}") + res + } + else op + } + + def withDefinedSyms[T](trees: List[untpd.Tree])(op: => T)(implicit ctx: Context) = + trees.foldRightBN(op)(withDefinedSym(_)(_)) + + def withDefinedSymss[T](vparamss: List[List[untpd.ValDef]])(op: => T)(implicit ctx: Context): T = + vparamss.foldRightBN(op)(withDefinedSyms(_)(_)) + + def assertDefined(tree: untpd.Tree)(implicit ctx: Context) = + if (tree.symbol.maybeOwner.isTerm) + ()//assert(definedSyms contains tree.symbol, i"undefined symbol ${tree.symbol}") + override def typed(tree: untpd.Tree, pt: Type)(implicit ctx: Context) = { val res = tree match { case _: untpd.UnApply => @@ -88,7 +115,8 @@ class TreeChecker { override def typedIdent(tree: untpd.Ident, pt: Type)(implicit ctx: Context): Tree = { assert(tree.isTerm || !ctx.isAfterTyper, tree.show + " at " + ctx.phase) - assert(tree.isType || !needsSelect(tree.tpe), i"bad type ${tree.tpe} for $tree") + assert(tree.isType || !needsSelect(tree.tpe), i"bad type ${tree.tpe} for $tree # ${tree.uniqueId}") + assertDefined(tree) super.typedIdent(tree, pt) } @@ -117,6 +145,22 @@ class TreeChecker { super.typedClassDef(cdef, cls) } + override def typedDefDef(ddef: untpd.DefDef, sym: Symbol)(implicit ctx: Context) = + withDefinedSyms(ddef.tparams) { + withDefinedSymss(ddef.vparamss) { + super.typedDefDef(ddef, sym) + } + } + + override def typedCase(tree: untpd.CaseDef, pt: Type, selType: Type, gadtSyms: Set[Symbol])(implicit ctx: Context): CaseDef = { + withDefinedSyms(tree.pat.asInstanceOf[tpd.Tree].filterSubTrees(_.isInstanceOf[ast.Trees.Bind[_]])) { + super.typedCase(tree, pt, selType, gadtSyms) + } + } + + override def typedBlock(tree: untpd.Block, pt: Type)(implicit ctx: Context) = + withDefinedSyms(tree.stats) { super.typedBlock(tree, pt) } + /** Check that all defined symbols have legal owners. * An owner is legal if it is either the same as the context's owner * or there's an owner chain of valdefs starting at the context's owner and |