aboutsummaryrefslogtreecommitdiff
path: root/src/dotty/tools
diff options
context:
space:
mode:
authorMartin Odersky <odersky@gmail.com>2014-09-06 11:35:07 +0200
committerMartin Odersky <odersky@gmail.com>2014-09-06 11:36:35 +0200
commitb58b90683652e1b6e2c32412f0a03ba614b61b33 (patch)
treeb86490f67c73d5d91bcc54f691469812f6b88a73 /src/dotty/tools
parente1040935cbcc1d767933c38a141372538ef63ac2 (diff)
downloaddotty-b58b90683652e1b6e2c32412f0a03ba614b61b33.tar.gz
dotty-b58b90683652e1b6e2c32412f0a03ba614b61b33.tar.bz2
dotty-b58b90683652e1b6e2c32412f0a03ba614b61b33.zip
Generalize phase postcondition checking.
Have a general way how a phase can establish a postcondition which will be checked each time a later phase is tree-checked. Moves erasure constraints from TreeChecker to Erasure's post condition.
Diffstat (limited to 'src/dotty/tools')
-rw-r--r--src/dotty/tools/dotc/Run.scala9
-rw-r--r--src/dotty/tools/dotc/core/Phases.scala8
-rw-r--r--src/dotty/tools/dotc/transform/Erasure.scala31
-rw-r--r--src/dotty/tools/dotc/transform/TreeChecker.scala39
4 files changed, 49 insertions, 38 deletions
diff --git a/src/dotty/tools/dotc/Run.scala b/src/dotty/tools/dotc/Run.scala
index a639b20cd..a4c862a84 100644
--- a/src/dotty/tools/dotc/Run.scala
+++ b/src/dotty/tools/dotc/Run.scala
@@ -37,17 +37,18 @@ class Run(comp: Compiler)(implicit ctx: Context) {
val phasesToRun = ctx.allPhases.init
.takeWhile(!stoppedBefore(_))
.filterNot(ctx.settings.Yskip.value.containsPhase(_))
- for (phase <- phasesToRun) {
+ for (phase <- phasesToRun)
if (!ctx.reporter.hasErrors) {
phase.runOn(units)
def foreachUnit(op: Context => Unit)(implicit ctx: Context): Unit =
for (unit <- units) op(ctx.fresh.setPhase(phase.next).setCompilationUnit(unit))
if (ctx.settings.Xprint.value.containsPhase(phase))
foreachUnit(printTree)
- if (ctx.settings.Ycheck.value.containsPhase(phase) && !ctx.reporter.hasErrors)
- foreachUnit(TreeChecker.check)
+ if (ctx.settings.Ycheck.value.containsPhase(phase) && !ctx.reporter.hasErrors) {
+ assert(phase.isCheckable, s"phase $phase is not checkable")
+ foreachUnit(TreeChecker.check(phasesToRun, _))
+ }
}
- }
}
}
diff --git a/src/dotty/tools/dotc/core/Phases.scala b/src/dotty/tools/dotc/core/Phases.scala
index 6baec3cf6..27b7cd77d 100644
--- a/src/dotty/tools/dotc/core/Phases.scala
+++ b/src/dotty/tools/dotc/core/Phases.scala
@@ -12,6 +12,7 @@ import dotty.tools.dotc.transform.TreeTransforms.{TreeTransformer, MiniPhase, Tr
import dotty.tools.dotc.transform.TreeTransforms
import Periods._
import typer.{FrontEnd, RefChecks}
+import ast.tpd
import dotty.tools.dotc.transform.{Erasure, Flatten}
trait Phases {
@@ -191,7 +192,12 @@ object Phases {
def description: String = phaseName
- def checkable: Boolean = true
+ /** Output should be checkable by TreeChecker */
+ def isCheckable: Boolean = true
+
+ /** Check what the phase achieves, to be called at any point after it is finished.
+ */
+ def checkPostCondition(tree: tpd.Tree)(implicit ctx: Context): Unit = ()
def exists: Boolean = true
diff --git a/src/dotty/tools/dotc/transform/Erasure.scala b/src/dotty/tools/dotc/transform/Erasure.scala
index fe5e516bf..f9e48ac5d 100644
--- a/src/dotty/tools/dotc/transform/Erasure.scala
+++ b/src/dotty/tools/dotc/transform/Erasure.scala
@@ -71,6 +71,37 @@ class Erasure extends Phase with DenotTransformer { thisTransformer =>
val unit = ctx.compilationUnit
unit.tpdTree = eraser.typedExpr(unit.tpdTree)(ctx.fresh.setPhase(this.next))
}
+
+ override def checkPostCondition(tree: tpd.Tree)(implicit ctx: Context) = {
+ assertErased(tree)
+ tree match {
+ case res: tpd.This =>
+ assert(!ExplicitOuter.referencesOuter(ctx.owner.enclosingClass, res),
+ i"Reference to $res from ${ctx.owner.showLocated}")
+ case _ =>
+ }
+ }
+
+ /** Assert that tree type and its widened underlying type are erased.
+ * Also assert that term refs have fixed symbols (so we are sure
+ * they need not be reloaded using member; this would likely fail as signatures
+ * may change after erasure).
+ */
+ def assertErased(tree: tpd.Tree)(implicit ctx: Context): Unit = {
+ assertErased(tree.typeOpt, tree)
+ if (!(tree.symbol == defn.Any_isInstanceOf || tree.symbol == defn.Any_asInstanceOf))
+ assertErased(tree.typeOpt.widen, tree)
+ if (ctx.mode.isExpr)
+ tree.tpe match {
+ case ref: TermRef =>
+ assert(ref.denot.isInstanceOf[SymDenotation],
+ i"non-sym type $ref of class ${ref.getClass} with denot of class ${ref.denot.getClass} of $tree")
+ case _ =>
+ }
+ }
+
+ def assertErased(tp: Type, tree: tpd.Tree = tpd.EmptyTree)(implicit ctx: Context): Unit =
+ assert(isErasedType(tp), i"The type $tp - ${tp.toString} of class ${tp.getClass} of tree $tree / ${tree.getClass} is illegal after erasure, phase = ${ctx.phase}")
}
object Erasure {
diff --git a/src/dotty/tools/dotc/transform/TreeChecker.scala b/src/dotty/tools/dotc/transform/TreeChecker.scala
index 5847796b3..39c5ce8b6 100644
--- a/src/dotty/tools/dotc/transform/TreeChecker.scala
+++ b/src/dotty/tools/dotc/transform/TreeChecker.scala
@@ -13,6 +13,7 @@ import core.Constants._
import core.StdNames._
import core.Decorators._
import core.TypeErasure.isErasedType
+import core.Phases.Phase
import typer._
import typer.ErrorReporting._
import reporting.ThrowingReporter
@@ -34,14 +35,15 @@ import java.lang.AssertionError
class TreeChecker {
import ast.tpd._
- def check(ctx: Context) = {
+ def check(phasesToRun: Seq[Phase], ctx: Context) = {
println(s"checking ${ctx.compilationUnit} after phase ${ctx.phase.prev}")
val checkingCtx = ctx.fresh
.setTyperState(ctx.typerState.withReporter(new ThrowingReporter(ctx.typerState.reporter)))
- Checker.typedExpr(ctx.compilationUnit.tpdTree)(checkingCtx)
+ val checker = new Checker(phasesToRun.takeWhile(_ ne ctx.phase) :+ ctx.phase)
+ checker.typedExpr(ctx.compilationUnit.tpdTree)(checkingCtx)
}
- object Checker extends ReTyper {
+ class Checker(phasesToCheck: Seq[Phase]) extends ReTyper {
override def typed(tree: untpd.Tree, pt: Type)(implicit ctx: Context) = {
val res = tree match {
case _: untpd.UnApply =>
@@ -67,15 +69,7 @@ class TreeChecker {
assert(isSubType(tree1.tpe, tree.typeOpt), divergenceMsg(tree1.tpe, tree.typeOpt))
tree1
}
- if (ctx.erasedTypes) {
- assertErased(res)
- res match {
- case res: This =>
- assert(!ExplicitOuter.referencesOuter(ctx.owner.enclosingClass, res),
- i"Reference to $res from ${ctx.owner.showLocated}")
- case _ =>
- }
- }
+ phasesToCheck.foreach(_.checkPostCondition(res))
res
}
@@ -126,27 +120,6 @@ class TreeChecker {
tree
}
}
-
- def assertErased(tp: Type, tree: Tree = EmptyTree)(implicit ctx: Context): Unit =
- assert(isErasedType(tp), i"The type $tp - ${tp.toString} of class ${tp.getClass} of tree $tree / ${tree.getClass} is illegal after erasure, phase = ${ctx.phase}")
-
- /** Assert that tree type and its widened underlying type are erased.
- * Also assert that term refs have fixed symbols (so we are sure
- * they need not be reloaded using member; this would likely fail as signatures
- * may change after erasure).
- */
- def assertErased(tree: Tree)(implicit ctx: Context): Unit = {
- assertErased(tree.typeOpt, tree)
- if (!(tree.symbol == defn.Any_isInstanceOf || tree.symbol == defn.Any_asInstanceOf))
- assertErased(tree.typeOpt.widen, tree)
- if (ctx.mode.isExpr)
- tree.tpe match {
- case ref: TermRef =>
- assert(ref.denot.isInstanceOf[SymDenotation],
- i"non-sym type $ref of class ${ref.getClass} with denot of class ${ref.denot.getClass} of $tree")
- case _ =>
- }
- }
}
object TreeChecker extends TreeChecker \ No newline at end of file