aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMartin Odersky <odersky@gmail.com>2015-08-05 12:26:07 -0700
committerMartin Odersky <odersky@gmail.com>2015-08-05 12:27:01 -0700
commit2a306ddcfe78589310d462bbf67fb893ce8702aa (patch)
tree6aaeb10c584d3ef08350aec81ccc2505799651de
parentc8afd79b4c7f145ba090a2d936d627c3ab35b1c2 (diff)
downloaddotty-2a306ddcfe78589310d462bbf67fb893ce8702aa.tar.gz
dotty-2a306ddcfe78589310d462bbf67fb893ce8702aa.tar.bz2
dotty-2a306ddcfe78589310d462bbf67fb893ce8702aa.zip
Make ensureConforms behave gracefully fter erasure
After erasure, if required conformance is between value and non-value types, one should perform boxing and unboxing operations automatically, instead of just issuing a cast, which would be illegal at that point. Also: make isNonLocalReturn available as part of a global object, because we'll need it in LiftTry.
-rw-r--r--src/dotty/tools/dotc/ast/tpd.scala12
-rw-r--r--src/dotty/tools/dotc/transform/NonLocalReturns.scala14
2 files changed, 18 insertions, 8 deletions
diff --git a/src/dotty/tools/dotc/ast/tpd.scala b/src/dotty/tools/dotc/ast/tpd.scala
index 4e9940ac4..989cae216 100644
--- a/src/dotty/tools/dotc/ast/tpd.scala
+++ b/src/dotty/tools/dotc/ast/tpd.scala
@@ -13,6 +13,7 @@ import config.Printers._
import typer.Mode
import collection.mutable
import typer.ErrorReporting._
+import transform.Erasure
import scala.annotation.tailrec
@@ -161,7 +162,7 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
def Bind(sym: TermSymbol, body: Tree)(implicit ctx: Context): Bind =
ta.assignType(untpd.Bind(sym.name, body), sym)
- /** A pattern corrsponding to `sym: tpe` */
+ /** A pattern corresponding to `sym: tpe` */
def BindTyped(sym: TermSymbol, tpe: Type)(implicit ctx: Context): Bind =
Bind(sym, Typed(Underscore(tpe), TypeTree(tpe)))
@@ -737,9 +738,14 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
tree.select(defn.Any_asInstanceOf).appliedToType(tp)
}
- /** `tree.asInstanceOf[tp]` unless tree's type already conforms to `tp` */
+ /** `tree.asInstanceOf[tp]` (or its box/unbox/cast equivalent when after
+ * erasure and value and non-value types are mixed),
+ * unless tree's type already conforms to `tp`.
+ */
def ensureConforms(tp: Type)(implicit ctx: Context): Tree =
- if (tree.tpe <:< tp) tree else asInstance(tp)
+ if (tree.tpe <:< tp) tree
+ else if (!ctx.erasedTypes) asInstance(tp)
+ else Erasure.Boxing.adaptToType(tree, tp)
/** If inititializer tree is `_', the default value of its type,
* otherwise the tree itself.
diff --git a/src/dotty/tools/dotc/transform/NonLocalReturns.scala b/src/dotty/tools/dotc/transform/NonLocalReturns.scala
index d0a2f2ca7..1f18a7318 100644
--- a/src/dotty/tools/dotc/transform/NonLocalReturns.scala
+++ b/src/dotty/tools/dotc/transform/NonLocalReturns.scala
@@ -7,11 +7,18 @@ import TreeTransforms._
import ast.Trees._
import collection.mutable
+object NonLocalReturns {
+ import ast.tpd._
+ def isNonLocalReturn(ret: Return)(implicit ctx: Context) =
+ ret.from.symbol != ctx.owner.enclosingMethod || ctx.owner.is(Lazy)
+}
+
/** Implement non-local returns using NonLocalReturnControl exceptions.
*/
class NonLocalReturns extends MiniPhaseTransform { thisTransformer =>
override def phaseName = "nonLocalReturns"
+ import NonLocalReturns._
import ast.tpd._
override def runsAfter: Set[Class[_ <: Phase]] = Set(classOf[ElimByName])
@@ -44,7 +51,7 @@ class NonLocalReturns extends MiniPhaseTransform { thisTransformer =>
Throw(
New(
defn.NonLocalReturnControlClass.typeRef,
- ref(nonLocalReturnKey(meth)) :: ensureConforms(expr, defn.ObjectType) :: Nil))
+ ref(nonLocalReturnKey(meth)) :: expr.ensureConforms(defn.ObjectType) :: Nil))
/** Transform (body, key) to:
*
@@ -66,16 +73,13 @@ class NonLocalReturns extends MiniPhaseTransform { thisTransformer =>
val pat = BindTyped(ex, nonLocalReturnControl)
val rhs = If(
ref(ex).select(nme.key).appliedToNone.select(nme.eq).appliedTo(ref(key)),
- ensureConforms(ref(ex).select(nme.value), meth.info.finalResultType),
+ ref(ex).select(nme.value).ensureConforms(meth.info.finalResultType),
Throw(ref(ex)))
val catches = CaseDef(pat, EmptyTree, rhs) :: Nil
val tryCatch = Try(body, catches, EmptyTree)
Block(keyDef :: Nil, tryCatch)
}
- def isNonLocalReturn(ret: Return)(implicit ctx: Context) =
- ret.from.symbol != ctx.owner.enclosingMethod || ctx.owner.is(Lazy) // Lazy needed?
-
override def transformDefDef(tree: DefDef)(implicit ctx: Context, info: TransformerInfo): Tree =
nonLocalReturnKeys.remove(tree.symbol) match {
case Some(key) => cpy.DefDef(tree)(rhs = nonLocalReturnTry(tree.rhs, key, tree.symbol))