diff options
Diffstat (limited to 'src/dotty/tools/dotc')
-rw-r--r-- | src/dotty/tools/dotc/ast/tpd.scala | 7 | ||||
-rw-r--r-- | src/dotty/tools/dotc/core/Decorators.scala | 5 | ||||
-rw-r--r-- | src/dotty/tools/dotc/transform/TreeChecker.scala | 46 | ||||
-rw-r--r-- | src/dotty/tools/dotc/typer/Typer.scala | 38 |
4 files changed, 76 insertions, 20 deletions
diff --git a/src/dotty/tools/dotc/ast/tpd.scala b/src/dotty/tools/dotc/ast/tpd.scala index 9b7c9cbae..4c21fcf49 100644 --- a/src/dotty/tools/dotc/ast/tpd.scala +++ b/src/dotty/tools/dotc/ast/tpd.scala @@ -9,6 +9,7 @@ import SymDenotations._, Symbols._, StdNames._, Annotations._, Trees._, Symbols. import Denotations._, Decorators._ import config.Printers._ import typer.Mode +import collection.mutable import typer.ErrorReporting._ import scala.annotation.tailrec @@ -620,6 +621,12 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo { } acc(false, tree) } + + def filterSubTrees(f: Tree => Boolean): List[Tree] = { + val buf = new mutable.ListBuffer[Tree] + foreachSubTree { tree => if (f(tree)) buf += tree } + buf.toList + } } implicit class ListOfTreeDecorator(val xs: List[tpd.Tree]) extends AnyVal { diff --git a/src/dotty/tools/dotc/core/Decorators.scala b/src/dotty/tools/dotc/core/Decorators.scala index 99af4d0cb..e0d7fae33 100644 --- a/src/dotty/tools/dotc/core/Decorators.scala +++ b/src/dotty/tools/dotc/core/Decorators.scala @@ -100,6 +100,11 @@ object Decorators { else x1 :: xs1 } + def foldRightBN[U](z: => U)(op: (T, => U) => U): U = xs match { + case Nil => z + case x :: xs1 => op(x, xs1.foldRightBN(z)(op)) + } + final def hasSameLengthAs[U](ys: List[U]): Boolean = { @tailrec def loop(xs: List[T], ys: List[U]): Boolean = if (xs.isEmpty) ys.isEmpty 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 diff --git a/src/dotty/tools/dotc/typer/Typer.scala b/src/dotty/tools/dotc/typer/Typer.scala index 1cab2fa46..1afa5f9f3 100644 --- a/src/dotty/tools/dotc/typer/Typer.scala +++ b/src/dotty/tools/dotc/typer/Typer.scala @@ -610,29 +610,29 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit accu(Set.empty, selType) } - def typedCase(tree: untpd.CaseDef): CaseDef = track("typedCase") { - def caseRest(pat: Tree)(implicit ctx: Context) = { - gadtSyms foreach (_.resetGADTFlexType) - pat foreachSubTree { - case b: Bind => - if (ctx.scope.lookup(b.name) == NoSymbol) ctx.enter(b.symbol) - else ctx.error(d"duplicate pattern variable: ${b.name}", b.pos) - case _ => - } - val guard1 = typedExpr(tree.guard, defn.BooleanType) - val body1 = typedExpr(tree.body, pt) - assignType(cpy.CaseDef(tree)(pat, guard1, body1), body1) - } - val doCase: () => CaseDef = - () => caseRest(typedPattern(tree.pat, selType))(ctx.fresh.setNewScope) - (doCase /: gadtSyms)((op, tsym) => tsym.withGADTFlexType(op))() - } - - val cases1 = tree.cases mapconserve typedCase + val cases1 = tree.cases mapconserve (typedCase(_, pt, selType, gadtSyms)) assignType(cpy.Match(tree)(sel1, cases1), cases1) } } + def typedCase(tree: untpd.CaseDef, pt: Type, selType: Type, gadtSyms: Set[Symbol])(implicit ctx: Context): CaseDef = track("typedCase") { + def caseRest(pat: Tree)(implicit ctx: Context) = { + gadtSyms foreach (_.resetGADTFlexType) + pat foreachSubTree { + case b: Bind => + if (ctx.scope.lookup(b.name) == NoSymbol) ctx.enter(b.symbol) + else ctx.error(d"duplicate pattern variable: ${b.name}", b.pos) + case _ => + } + val guard1 = typedExpr(tree.guard, defn.BooleanType) + val body1 = typedExpr(tree.body, pt) + assignType(cpy.CaseDef(tree)(pat, guard1, body1), body1) + } + val doCase: () => CaseDef = + () => caseRest(typedPattern(tree.pat, selType))(ctx.fresh.setNewScope) + (doCase /: gadtSyms)((op, tsym) => tsym.withGADTFlexType(op))() + } + def typedReturn(tree: untpd.Return)(implicit ctx: Context): Return = track("typedReturn") { def returnProto(owner: Symbol) = if (owner.isConstructor) defn.UnitType else owner.info.finalResultType |