diff options
author | Martin Odersky <odersky@gmail.com> | 2015-08-05 12:26:07 -0700 |
---|---|---|
committer | Martin Odersky <odersky@gmail.com> | 2015-08-05 12:27:01 -0700 |
commit | 2a306ddcfe78589310d462bbf67fb893ce8702aa (patch) | |
tree | 6aaeb10c584d3ef08350aec81ccc2505799651de | |
parent | c8afd79b4c7f145ba090a2d936d627c3ab35b1c2 (diff) | |
download | dotty-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.scala | 12 | ||||
-rw-r--r-- | src/dotty/tools/dotc/transform/NonLocalReturns.scala | 14 |
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)) |