aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDmitry Petrashko <dark@d-d.me>2015-08-20 14:59:47 +0200
committerDmitry Petrashko <dark@d-d.me>2015-08-20 14:59:47 +0200
commiteec8191fc067358f88bec56d7dbda36e1fcfc131 (patch)
tree3e76fcae6e6b7ed8eb75444a5c756944a464c542
parentdbbc5ca47bc3485f735682c89f8f4cd07c637572 (diff)
parent5a36e2f20bb5dd9cb04a1e8010280995c6305a39 (diff)
downloaddotty-eec8191fc067358f88bec56d7dbda36e1fcfc131.tar.gz
dotty-eec8191fc067358f88bec56d7dbda36e1fcfc131.tar.bz2
dotty-eec8191fc067358f88bec56d7dbda36e1fcfc131.zip
Merge pull request #758 from dotty-staging/fix-liftedTry-capturedVars-interaction
Fix lift try and captured vars interaction
-rw-r--r--src/dotty/tools/dotc/ast/tpd.scala5
-rw-r--r--src/dotty/tools/dotc/core/Decorators.scala2
-rw-r--r--src/dotty/tools/dotc/core/Definitions.scala9
-rw-r--r--src/dotty/tools/dotc/core/Denotations.scala2
-rw-r--r--src/dotty/tools/dotc/core/Phases.scala18
-rw-r--r--src/dotty/tools/dotc/transform/CapturedVars.scala32
-rw-r--r--src/dotty/tools/dotc/transform/TreeChecker.scala2
-rw-r--r--src/dotty/tools/dotc/transform/TreeTransform.scala23
-rw-r--r--test/test/transform/TreeTransformerTest.scala10
-rw-r--r--tests/run/liftedTry.scala12
10 files changed, 73 insertions, 42 deletions
diff --git a/src/dotty/tools/dotc/ast/tpd.scala b/src/dotty/tools/dotc/ast/tpd.scala
index 989cae216..5334bc459 100644
--- a/src/dotty/tools/dotc/ast/tpd.scala
+++ b/src/dotty/tools/dotc/ast/tpd.scala
@@ -641,7 +641,8 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
def traverse(tree: Tree)(implicit ctx: Context) = tree match {
case tree: DefTree =>
val sym = tree.symbol
- if (sym.denot(ctx.withPhase(trans)).owner == from) {
+ val prevDenot = sym.denot(ctx.withPhase(trans))
+ if (prevDenot.owner == from) {
val d = sym.copySymDenotation(owner = to)
d.installAfter(trans)
d.transformAfter(trans, d => if (d.owner eq from) d.copySymDenotation(owner = to) else d)
@@ -651,7 +652,7 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
traverseChildren(tree)
}
}
- traverser.traverse(tree)
+ traverser.traverse(tree)(ctx.withMode(Mode.FutureDefsOK))
tree
}
diff --git a/src/dotty/tools/dotc/core/Decorators.scala b/src/dotty/tools/dotc/core/Decorators.scala
index d90b959ab..60c019bce 100644
--- a/src/dotty/tools/dotc/core/Decorators.scala
+++ b/src/dotty/tools/dotc/core/Decorators.scala
@@ -135,7 +135,7 @@ object Decorators {
*/
implicit class PhaseListDecorator(val names: List[String]) extends AnyVal {
def containsPhase(phase: Phase): Boolean = phase match {
- case phase: TreeTransformer => phase.transformations.exists(trans => containsPhase(trans.phase))
+ case phase: TreeTransformer => phase.miniPhases.exists(containsPhase)
case _ =>
names exists { name =>
name == "all" || {
diff --git a/src/dotty/tools/dotc/core/Definitions.scala b/src/dotty/tools/dotc/core/Definitions.scala
index 502b42987..fcd9ef224 100644
--- a/src/dotty/tools/dotc/core/Definitions.scala
+++ b/src/dotty/tools/dotc/core/Definitions.scala
@@ -592,13 +592,16 @@ class Definitions {
}
/** The classes for which a Ref type exists. */
- lazy val refClasses: collection.Set[Symbol] = ScalaNumericValueClasses + BooleanClass + ObjectClass
+ lazy val refClassKeys: collection.Set[Symbol] = ScalaNumericValueClasses + BooleanClass + ObjectClass
lazy val refClass: Map[Symbol, Symbol] =
- refClasses.map(rc => rc -> ctx.requiredClass(s"scala.runtime.${rc.name}Ref")).toMap
+ refClassKeys.map(rc => rc -> ctx.requiredClass(s"scala.runtime.${rc.name}Ref")).toMap
lazy val volatileRefClass: Map[Symbol, Symbol] =
- refClasses.map(rc => rc -> ctx.requiredClass(s"scala.runtime.Volatile${rc.name}Ref")).toMap
+ refClassKeys.map(rc => rc -> ctx.requiredClass(s"scala.runtime.Volatile${rc.name}Ref")).toMap
+
+ lazy val boxedRefClasses: collection.Set[Symbol] =
+ refClassKeys.flatMap(k => Set(refClass(k), volatileRefClass(k)))
def wrapArrayMethodName(elemtp: Type): TermName = {
val cls = elemtp.classSymbol
diff --git a/src/dotty/tools/dotc/core/Denotations.scala b/src/dotty/tools/dotc/core/Denotations.scala
index fc97fb32b..16a151e89 100644
--- a/src/dotty/tools/dotc/core/Denotations.scala
+++ b/src/dotty/tools/dotc/core/Denotations.scala
@@ -680,7 +680,7 @@ object Denotations {
// println(s"installing $this after $phase/${phase.id}, valid = ${current.validFor}")
// printPeriods(current)
this.validFor = Period(ctx.runId, targetId, current.validFor.lastPhaseId)
- if (current.validFor.firstPhaseId == targetId)
+ if (current.validFor.firstPhaseId >= targetId)
replaceDenotation(current)
else {
// insert this denotation after current
diff --git a/src/dotty/tools/dotc/core/Phases.scala b/src/dotty/tools/dotc/core/Phases.scala
index 6e86c10ab..8d5ec08f7 100644
--- a/src/dotty/tools/dotc/core/Phases.scala
+++ b/src/dotty/tools/dotc/core/Phases.scala
@@ -109,11 +109,9 @@ object Phases {
assert(false, s"Only tree transforms can be squashed, ${phase.phaseName} can not be squashed")
}
}
- val transforms = filteredPhaseBlock.asInstanceOf[List[MiniPhase]].map(_.treeTransform)
val block = new TreeTransformer {
- override def phaseName: String = transformations.map(_.phase.phaseName).mkString("TreeTransform:{", ", ", "}")
-
- override def transformations: Array[TreeTransform] = transforms.toArray
+ override def phaseName: String = miniPhases.map(_.phaseName).mkString("TreeTransform:{", ", ", "}")
+ override def miniPhases: Array[MiniPhase] = filteredPhaseBlock.asInstanceOf[List[MiniPhase]].toArray
}
prevPhases ++= filteredPhaseBlock.map(_.getClazz)
block
@@ -145,7 +143,7 @@ object Phases {
val flatPhases = collection.mutable.ListBuffer[Phase]()
phasess.foreach(p => p match {
- case t: TreeTransformer => flatPhases ++= t.transformations.map(_.phase)
+ case t: TreeTransformer => flatPhases ++= t.miniPhases
case _ => flatPhases += p
})
@@ -173,11 +171,11 @@ object Phases {
val phase = phasess(i)
phase match {
case t: TreeTransformer =>
- val transforms = t.transformations
- transforms.foreach{ x =>
- checkRequirements(x.phase)
- x.phase.init(this, nextPhaseId)}
- t.init(this, transforms.head.phase.id, transforms.last.phase.id)
+ val miniPhases = t.miniPhases
+ miniPhases.foreach{ phase =>
+ checkRequirements(phase)
+ phase.init(this, nextPhaseId)}
+ t.init(this, miniPhases.head.id, miniPhases.last.id)
case _ =>
phase.init(this, nextPhaseId)
checkRequirements(phase)
diff --git a/src/dotty/tools/dotc/transform/CapturedVars.scala b/src/dotty/tools/dotc/transform/CapturedVars.scala
index 86cf80073..0f1a60282 100644
--- a/src/dotty/tools/dotc/transform/CapturedVars.scala
+++ b/src/dotty/tools/dotc/transform/CapturedVars.scala
@@ -92,14 +92,34 @@ class CapturedVars extends MiniPhase with IdentityDenotTransformer { thisTransfo
else id
}
+ /** If assignment is to a boxed ref type, e.g.
+ *
+ * intRef.elem = expr
+ *
+ * rewrite using a temporary var to
+ *
+ * val ev$n = expr
+ * intRef.elem = ev$n
+ *
+ * That way, we avoid the problem that `expr` might contain a `try` that would
+ * run on a non-empty stack (which is illegal under JVM rules). Note that LiftTry
+ * has already run before, so such `try`s would not be eliminated.
+ *
+ * Also: If the ref type lhs is followed by a cast (can be an artifact of nested translation),
+ * drop the cast.
+ */
override def transformAssign(tree: Assign)(implicit ctx: Context, info: TransformerInfo): Tree = {
- val lhs1 = tree.lhs match {
- case TypeApply(Select(qual @ Select(qual2, nme.elem), nme.asInstanceOf_), _) =>
- assert(captured(qual2.symbol))
- qual
- case _ => tree.lhs
+ def recur(lhs: Tree): Tree = lhs match {
+ case TypeApply(Select(qual, nme.asInstanceOf_), _) =>
+ val Select(_, nme.elem) = qual
+ recur(qual)
+ case Select(_, nme.elem) if defn.boxedRefClasses.contains(lhs.symbol.maybeOwner) =>
+ val tempDef = transformFollowing(SyntheticValDef(ctx.freshName("ev$").toTermName, tree.rhs))
+ transformFollowing(Block(tempDef :: Nil, cpy.Assign(tree)(lhs, ref(tempDef.symbol))))
+ case _ =>
+ tree
}
- cpy.Assign(tree)(lhs1, tree.rhs)
+ recur(tree.lhs)
}
}
}
diff --git a/src/dotty/tools/dotc/transform/TreeChecker.scala b/src/dotty/tools/dotc/transform/TreeChecker.scala
index a1847e456..6ae765480 100644
--- a/src/dotty/tools/dotc/transform/TreeChecker.scala
+++ b/src/dotty/tools/dotc/transform/TreeChecker.scala
@@ -103,7 +103,7 @@ class TreeChecker extends Phase with SymTransformer {
private def previousPhases(phases: List[Phase])(implicit ctx: Context): List[Phase] = phases match {
case (phase: TreeTransformer) :: phases1 =>
- val subPhases = phase.transformations.map(_.phase)
+ val subPhases = phase.miniPhases
val previousSubPhases = previousPhases(subPhases.toList)
if (previousSubPhases.length == subPhases.length) previousSubPhases ::: previousPhases(phases1)
else previousSubPhases
diff --git a/src/dotty/tools/dotc/transform/TreeTransform.scala b/src/dotty/tools/dotc/transform/TreeTransform.scala
index 62cd5dbe9..7a2280baa 100644
--- a/src/dotty/tools/dotc/transform/TreeTransform.scala
+++ b/src/dotty/tools/dotc/transform/TreeTransform.scala
@@ -63,9 +63,6 @@ object TreeTransforms {
def treeTransformPhase: Phase = phase.next
- /** id of this treeTransform in group */
- var idx: Int = _
-
def prepareForIdent(tree: Ident)(implicit ctx: Context) = this
def prepareForSelect(tree: Select)(implicit ctx: Context) = this
def prepareForThis(tree: This)(implicit ctx: Context) = this
@@ -137,10 +134,10 @@ object TreeTransforms {
def transform(tree: Tree)(implicit ctx: Context, info: TransformerInfo): Tree = info.group.transform(tree, info, 0)
/** Transform subtree using all transforms following the current one in this group */
- def transformFollowingDeep(tree: Tree)(implicit ctx: Context, info: TransformerInfo): Tree = info.group.transform(tree, info, idx + 1)
+ def transformFollowingDeep(tree: Tree)(implicit ctx: Context, info: TransformerInfo): Tree = info.group.transform(tree, info, phase.idx + 1)
/** Transform single node using all transforms following the current one in this group */
- def transformFollowing(tree: Tree)(implicit ctx: Context, info: TransformerInfo): Tree = info.group.transformSingle(tree, idx + 1)
+ def transformFollowing(tree: Tree)(implicit ctx: Context, info: TransformerInfo): Tree = info.group.transformSingle(tree, phase.idx + 1)
def atGroupEnd[T](action : Context => T)(implicit ctx: Context, info: TransformerInfo) = {
val last = info.transformers(info.transformers.length - 1)
@@ -152,6 +149,9 @@ object TreeTransforms {
trait MiniPhase extends Phase { thisPhase =>
def treeTransform: TreeTransform
+ /** id of this mini phase in group */
+ var idx: Int = _
+
/** List of names of phases that should have finished their processing of all compilation units
* before this phase starts
*/
@@ -159,7 +159,7 @@ object TreeTransforms {
protected def mkTreeTransformer = new TreeTransformer {
override def phaseName: String = thisPhase.phaseName
- override def transformations = Array(treeTransform)
+ override def miniPhases = Array(thisPhase)
}
override def run(implicit ctx: Context): Unit = {
@@ -197,7 +197,6 @@ object TreeTransforms {
@sharable val NoTransform = new TreeTransform {
def phase = unsupported("phase")
- idx = -1
}
type Mutator[T] = (TreeTransform, T, Context) => TreeTransform
@@ -474,7 +473,7 @@ object TreeTransforms {
/** A group of tree transforms that are applied in sequence during the same phase */
abstract class TreeTransformer extends Phase {
- def transformations: Array[TreeTransform]
+ def miniPhases: Array[MiniPhase]
override def run(implicit ctx: Context): Unit = {
val curTree = ctx.compilationUnit.tpdTree
@@ -549,10 +548,10 @@ object TreeTransforms {
val prepForStats: Mutator[List[Tree]] = (trans, trees, ctx) => trans.prepareForStats(trees)(ctx)
val prepForUnit: Mutator[Tree] = (trans, tree, ctx) => trans.prepareForUnit(tree)(ctx)
- val initialTransformationsCache = transformations.zipWithIndex.map {
- case (transform, id) =>
- transform.idx = id
- transform
+ val initialTransformationsCache = miniPhases.zipWithIndex.map {
+ case (miniPhase, id) =>
+ miniPhase.idx = id
+ miniPhase.treeTransform
}
val initialInfoCache = new TransformerInfo(initialTransformationsCache, new NXTransformations(initialTransformationsCache), this)
diff --git a/test/test/transform/TreeTransformerTest.scala b/test/test/transform/TreeTransformerTest.scala
index fadc44ab9..df6175735 100644
--- a/test/test/transform/TreeTransformerTest.scala
+++ b/test/test/transform/TreeTransformerTest.scala
@@ -20,7 +20,7 @@ class TreeTransformerTest extends DottyTest {
init(ctx, ctx.period.firstPhaseId, ctx.period.lastPhaseId)
}
val transformer = new TreeTransformer {
- override def transformations = Array(new EmptyTransform)
+ override def miniPhases = Array(new EmptyTransform)
override def phaseName: String = "test"
}
@@ -42,7 +42,7 @@ class TreeTransformerTest extends DottyTest {
init(ctx, ctx.period.firstPhaseId, ctx.period.lastPhaseId)
}
val transformer = new TreeTransformer {
- override def transformations = Array(new ConstantTransform)
+ override def miniPhases = Array(new ConstantTransform)
override def phaseName: String = "test"
}
@@ -72,7 +72,7 @@ class TreeTransformerTest extends DottyTest {
init(ctx, ctx.period.firstPhaseId, ctx.period.lastPhaseId)
}
val transformer = new TreeTransformer {
- override def transformations = Array(new Transformation)
+ override def miniPhases = Array(new Transformation)
override def phaseName: String = "test"
@@ -119,7 +119,7 @@ class TreeTransformerTest extends DottyTest {
init(ctx, ctx.period.firstPhaseId, ctx.period.lastPhaseId)
}
val transformer = new TreeTransformer {
- override def transformations = Array(new Transformation1, new Transformation2)
+ override def miniPhases = Array(new Transformation1, new Transformation2)
override def phaseName: String = "test"
}
@@ -187,7 +187,7 @@ class TreeTransformerTest extends DottyTest {
init(ctx, ctx.period.firstPhaseId, ctx.period.lastPhaseId)
}
val transformer = new TreeTransformer {
- override def transformations = Array(new Transformation1, new Transformation2)
+ override def miniPhases = Array(new Transformation1, new Transformation2)
override def phaseName: String = "test"
}
diff --git a/tests/run/liftedTry.scala b/tests/run/liftedTry.scala
index 2e4c25c2b..5ff4add6d 100644
--- a/tests/run/liftedTry.scala
+++ b/tests/run/liftedTry.scala
@@ -12,10 +12,20 @@ object Test {
foo(try 3 catch handle)
- def main(args: Array[String]) = {
+ def main(args: Array[String]): Unit = {
assert(x == 1)
assert(foo(2) == 2)
assert(foo(try raise(3) catch handle) == 3)
+ Tr.foo
}
}
+
+object Tr {
+ def fun(a: Int => Unit) = a(2)
+ def foo: Int = {
+ var s = 1
+ s = try {fun(s = _); 3} catch{ case ex: Throwable => val x = 4; s = x; 5 }
+ s
+ }
+}