aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDmitry Petrashko <dark@d-d.me>2015-02-13 14:31:58 +0100
committerDmitry Petrashko <dark@d-d.me>2015-02-13 14:31:58 +0100
commit2e72811fb1cedb94c7967acf96c92172f010a20b (patch)
tree621fd55bf3967fe734d0192cb491ab0e01bc627b
parentc12f21306ea01bd0411f07074a5a0637f23187ff (diff)
parent37c2dcc2268e6840cfcd89fc5937d461a493e1fd (diff)
downloaddotty-2e72811fb1cedb94c7967acf96c92172f010a20b.tar.gz
dotty-2e72811fb1cedb94c7967acf96c92172f010a20b.tar.bz2
dotty-2e72811fb1cedb94c7967acf96c92172f010a20b.zip
Merge pull request #359 from dotty-staging/fix/erasure-lub-alternative
Fix/erasure lub alternative
-rw-r--r--src/dotty/tools/backend/jvm/LabelDefs.scala103
-rw-r--r--src/dotty/tools/dotc/transform/Erasure.scala24
-rw-r--r--src/dotty/tools/dotc/transform/PatternMatcher.scala2
-rw-r--r--test/dotc/tests.scala2
-rw-r--r--tests/pos/erased-lub.scala27
5 files changed, 109 insertions, 49 deletions
diff --git a/src/dotty/tools/backend/jvm/LabelDefs.scala b/src/dotty/tools/backend/jvm/LabelDefs.scala
index 0e50e9366..18aec6b13 100644
--- a/src/dotty/tools/backend/jvm/LabelDefs.scala
+++ b/src/dotty/tools/backend/jvm/LabelDefs.scala
@@ -32,6 +32,7 @@ import java.lang.AssertionError
import dotty.tools.dotc.util.Positions.Position
import Decorators._
import tpd._
+import Flags._
import StdNames.nme
/**
@@ -80,54 +81,68 @@ class LabelDefs extends MiniPhaseTransform {
val queue = new ArrayBuffer[Tree]()
-
-
- override def transformBlock(tree: tpd.Block)(implicit ctx: Context, info: TransformerInfo): tpd.Tree = {
- collectLabelDefs.clear
- val newStats = collectLabelDefs.transformStats(tree.stats)
- val newExpr = collectLabelDefs.transform(tree.expr)
- val labelCalls = collectLabelDefs.labelCalls
- val entryPoints = collectLabelDefs.parentLabelCalls
- val labelDefs = collectLabelDefs.labelDefs
-
- // make sure that for every label there's a single location it should return and single entry point
- // if theres already a location that it returns to that's a failure
- val disallowed = new mutable.HashMap[Symbol, Tree]()
- queue.sizeHint(labelCalls.size + entryPoints.size)
- def moveLabels(entryPoint: Tree): List[Tree] = {
- if((entryPoint.symbol is Flags.Label) && labelDefs.contains(entryPoint.symbol)) {
- val visitedNow = new mutable.HashMap[Symbol, Tree]()
- val treesToAppend = new ArrayBuffer[Tree]() // order matters. parents should go first
- queue.clear()
-
- var visited = 0
- queue += entryPoint
- while (visited < queue.size) {
- val owningLabelDefSym = queue(visited).symbol
- val owningLabelDef = labelDefs(owningLabelDefSym)
- for (call <- labelCalls(owningLabelDefSym))
- if (disallowed.contains(call.symbol)) {
- val oldCall = disallowed(call.symbol)
- ctx.error(s"Multiple return locations for Label $oldCall and $call", call.symbol.pos)
- } else {
- if ((!visitedNow.contains(call.symbol)) && labelDefs.contains(call.symbol)) {
- val df = labelDefs(call.symbol)
- visitedNow.put(call.symbol, labelDefs(call.symbol))
- queue += call
+ override def transformDefDef(tree: tpd.DefDef)(implicit ctx: Context, info: TransformerInfo): tpd.Tree = {
+ if (tree.symbol is Flags.Label) tree
+ else {
+ collectLabelDefs.clear
+ val newRhs = collectLabelDefs.transform(tree.rhs)
+ val labelCalls = collectLabelDefs.labelCalls
+ var entryPoints = collectLabelDefs.parentLabelCalls
+ var labelDefs = collectLabelDefs.labelDefs
+
+ // make sure that for every label there's a single location it should return and single entry point
+ // if theres already a location that it returns to that's a failure
+ val disallowed = new mutable.HashMap[Symbol, Tree]()
+ queue.sizeHint(labelCalls.size + entryPoints.size)
+ def moveLabels(entryPoint: Tree): List[Tree] = {
+ if ((entryPoint.symbol is Flags.Label) && labelDefs.contains(entryPoint.symbol)) {
+ val visitedNow = new mutable.HashMap[Symbol, Tree]()
+ val treesToAppend = new ArrayBuffer[Tree]() // order matters. parents should go first
+ queue.clear()
+
+ var visited = 0
+ queue += entryPoint
+ while (visited < queue.size) {
+ val owningLabelDefSym = queue(visited).symbol
+ val owningLabelDef = labelDefs(owningLabelDefSym)
+ for (call <- labelCalls(owningLabelDefSym))
+ if (disallowed.contains(call.symbol)) {
+ val oldCall = disallowed(call.symbol)
+ ctx.error(s"Multiple return locations for Label $oldCall and $call", call.symbol.pos)
+ } else {
+ if ((!visitedNow.contains(call.symbol)) && labelDefs.contains(call.symbol)) {
+ visitedNow.put(call.symbol, labelDefs(call.symbol))
+ queue += call
+ }
}
+ if (!treesToAppend.contains(owningLabelDef)) {
+ treesToAppend += owningLabelDef
}
- if(!treesToAppend.contains(owningLabelDef))
- treesToAppend += owningLabelDef
- visited += 1
+ visited += 1
+ }
+ disallowed ++= visitedNow
+
+ treesToAppend.toList
+ } else Nil
+ }
+
+ val putLabelDefsNearCallees = new TreeMap() {
+
+ override def transform(tree: tpd.Tree)(implicit ctx: Context): tpd.Tree = {
+ tree match {
+ case t: Apply if (entryPoints.contains(t)) =>
+ entryPoints = entryPoints - t
+ Block(moveLabels(t), t)
+ case _ => if (entryPoints.nonEmpty && labelDefs.nonEmpty) super.transform(tree) else tree
+ }
}
- disallowed ++= visitedNow
+ }
- treesToAppend.toList
- } else Nil
- }
- cpy.Block(tree)(entryPoints.flatMap(moveLabels).toList ++ newStats, newExpr)
+ val res = cpy.DefDef(tree)(rhs = putLabelDefsNearCallees.transform(newRhs))
+ res
+ }
}
val collectLabelDefs = new TreeMap() {
@@ -137,13 +152,12 @@ class LabelDefs extends MiniPhaseTransform {
var isInsideLabel = false
var isInsideBlock = false
- def shouldMoveLabel = !isInsideBlock
+ def shouldMoveLabel = true
// labelSymbol -> Defining tree
val labelDefs = new mutable.HashMap[Symbol, Tree]()
// owner -> all calls by this owner
val labelCalls = new mutable.HashMap[Symbol, mutable.Set[Tree]]()
- val labelCallCounts = new mutable.HashMap[Symbol, Int]()
def clear = {
parentLabelCalls.clear()
@@ -175,7 +189,6 @@ class LabelDefs extends MiniPhaseTransform {
} else r
case t: Apply if t.symbol is Flags.Label =>
parentLabelCalls = parentLabelCalls + t
- labelCallCounts.get(t.symbol)
super.transform(tree)
case _ =>
super.transform(tree)
diff --git a/src/dotty/tools/dotc/transform/Erasure.scala b/src/dotty/tools/dotc/transform/Erasure.scala
index e8fdcd81c..935482ef0 100644
--- a/src/dotty/tools/dotc/transform/Erasure.scala
+++ b/src/dotty/tools/dotc/transform/Erasure.scala
@@ -251,7 +251,7 @@ object Erasure extends TypeTestsCasts{
override def typedLiteral(tree: untpd.Literal)(implicit ctc: Context): Literal =
if (tree.typeOpt.isRef(defn.UnitClass)) tree.withType(tree.typeOpt)
else super.typedLiteral(tree)
-
+
/** Type check select nodes, applying the following rewritings exhaustively
* on selections `e.m`, where `OT` is the type of the owner of `m` and `ET`
* is the erased type of the selection's original qualifier expression.
@@ -387,9 +387,29 @@ object Erasure extends TypeTestsCasts{
}
}
+ // The following four methods take as the proto-type the erasure of the pre-existing type,
+ // if the original proto-type is not a value type.
+ // This makes all branches be adapted to the correct type.
override def typedSeqLiteral(tree: untpd.SeqLiteral, pt: Type)(implicit ctx: Context) =
super.typedSeqLiteral(tree, erasure(tree.typeOpt))
- // proto type of typed seq literal is original type; this makes elements be adapted to correct type.
+ // proto type of typed seq literal is original type;
+
+ override def typedIf(tree: untpd.If, pt: Type)(implicit ctx: Context) =
+ super.typedIf(tree, adaptProto(tree, pt))
+
+ override def typedMatch(tree: untpd.Match, pt: Type)(implicit ctx: Context) =
+ super.typedMatch(tree, adaptProto(tree, pt))
+
+ override def typedTry(tree: untpd.Try, pt: Type)(implicit ctx: Context) =
+ super.typedTry(tree, adaptProto(tree, pt))
+
+ private def adaptProto(tree: untpd.Tree, pt: Type)(implicit ctx: Context) = {
+ if (pt.isValueType) pt else {
+ if(tree.typeOpt.derivesFrom(ctx.definitions.UnitClass))
+ tree.typeOpt
+ else erasure(tree.typeOpt)
+ }
+ }
override def typedValDef(vdef: untpd.ValDef, sym: Symbol)(implicit ctx: Context): ValDef =
super.typedValDef(untpd.cpy.ValDef(vdef)(
diff --git a/src/dotty/tools/dotc/transform/PatternMatcher.scala b/src/dotty/tools/dotc/transform/PatternMatcher.scala
index 763421ea5..ea41e7592 100644
--- a/src/dotty/tools/dotc/transform/PatternMatcher.scala
+++ b/src/dotty/tools/dotc/transform/PatternMatcher.scala
@@ -57,7 +57,7 @@ class PatternMatcher extends MiniPhaseTransform with DenotTransformer {thisTrans
val selector =
ctx.newSymbol(ctx.owner, ctx.freshName("ex").toTermName, Flags.Synthetic, defn.ThrowableType, coord = tree.pos)
val sel = Ident(selector.termRef).withPos(tree.pos)
- val rethrow = tpd.CaseDef(sel, EmptyTree, Throw(ref(selector)))
+ val rethrow = tpd.CaseDef(EmptyTree, EmptyTree, Throw(ref(selector)))
val newCases = tpd.CaseDef(
Bind(selector,untpd.Ident(nme.WILDCARD).withPos(tree.pos).withType(selector.info)),
EmptyTree,
diff --git a/test/dotc/tests.scala b/test/dotc/tests.scala
index 8b3965e88..615951479 100644
--- a/test/dotc/tests.scala
+++ b/test/dotc/tests.scala
@@ -135,7 +135,7 @@ class tests extends CompilerTest {
@Test def dotc_parsing = compileDir(dotcDir + "tools/dotc/parsing", failedOther)
// Expected primitive types I - Ljava/lang/Object
// Tried to return an object where expected type was Integer
- @Test def dotc_printing = compileDir(dotcDir + "tools/dotc/printing", twice)
+ @Test def dotc_printing = compileDir(dotcDir + "tools/dotc/printing", failedOther)
@Test def dotc_reporting = compileDir(dotcDir + "tools/dotc/reporting", twice)
@Test def dotc_typer = compileDir(dotcDir + "tools/dotc/typer", failedOther) // similar to dotc_config
//@Test def dotc_util = compileDir(dotcDir + "tools/dotc/util") //fails inside ExtensionMethods with ClassCastException
diff --git a/tests/pos/erased-lub.scala b/tests/pos/erased-lub.scala
new file mode 100644
index 000000000..d3d2183c1
--- /dev/null
+++ b/tests/pos/erased-lub.scala
@@ -0,0 +1,27 @@
+// Verify that expressions below perform correct boxings in erasure.
+object Test {
+ def id[T](t: T) = t
+
+ val x = true
+ val one = 1
+
+ { if (x) id(one) else 0 } + 1
+
+ { if (x) new scala.util.Random()}.asInstanceOf[Runnable]
+
+ { x match {
+ case true => id(one)
+ case _ => 0
+ }
+ } + 1
+
+ { try {
+ id(one)
+ } catch {
+ case ex: Exception => 0
+ }
+ }.asInstanceOf[Runnable]
+
+ val arr = Array(id(one), 0)
+
+}