Skip to content

Commit 2a306dd

Browse files
committed
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.
1 parent c8afd79 commit 2a306dd

File tree

2 files changed

+18
-8
lines changed

2 files changed

+18
-8
lines changed

src/dotty/tools/dotc/ast/tpd.scala

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import config.Printers._
1313
import typer.Mode
1414
import collection.mutable
1515
import typer.ErrorReporting._
16+
import transform.Erasure
1617

1718
import scala.annotation.tailrec
1819

@@ -161,7 +162,7 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
161162
def Bind(sym: TermSymbol, body: Tree)(implicit ctx: Context): Bind =
162163
ta.assignType(untpd.Bind(sym.name, body), sym)
163164

164-
/** A pattern corrsponding to `sym: tpe` */
165+
/** A pattern corresponding to `sym: tpe` */
165166
def BindTyped(sym: TermSymbol, tpe: Type)(implicit ctx: Context): Bind =
166167
Bind(sym, Typed(Underscore(tpe), TypeTree(tpe)))
167168

@@ -737,9 +738,14 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
737738
tree.select(defn.Any_asInstanceOf).appliedToType(tp)
738739
}
739740

740-
/** `tree.asInstanceOf[tp]` unless tree's type already conforms to `tp` */
741+
/** `tree.asInstanceOf[tp]` (or its box/unbox/cast equivalent when after
742+
* erasure and value and non-value types are mixed),
743+
* unless tree's type already conforms to `tp`.
744+
*/
741745
def ensureConforms(tp: Type)(implicit ctx: Context): Tree =
742-
if (tree.tpe <:< tp) tree else asInstance(tp)
746+
if (tree.tpe <:< tp) tree
747+
else if (!ctx.erasedTypes) asInstance(tp)
748+
else Erasure.Boxing.adaptToType(tree, tp)
743749

744750
/** If inititializer tree is `_', the default value of its type,
745751
* otherwise the tree itself.

src/dotty/tools/dotc/transform/NonLocalReturns.scala

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,18 @@ import TreeTransforms._
77
import ast.Trees._
88
import collection.mutable
99

10+
object NonLocalReturns {
11+
import ast.tpd._
12+
def isNonLocalReturn(ret: Return)(implicit ctx: Context) =
13+
ret.from.symbol != ctx.owner.enclosingMethod || ctx.owner.is(Lazy)
14+
}
15+
1016
/** Implement non-local returns using NonLocalReturnControl exceptions.
1117
*/
1218
class NonLocalReturns extends MiniPhaseTransform { thisTransformer =>
1319
override def phaseName = "nonLocalReturns"
1420

21+
import NonLocalReturns._
1522
import ast.tpd._
1623

1724
override def runsAfter: Set[Class[_ <: Phase]] = Set(classOf[ElimByName])
@@ -44,7 +51,7 @@ class NonLocalReturns extends MiniPhaseTransform { thisTransformer =>
4451
Throw(
4552
New(
4653
defn.NonLocalReturnControlClass.typeRef,
47-
ref(nonLocalReturnKey(meth)) :: ensureConforms(expr, defn.ObjectType) :: Nil))
54+
ref(nonLocalReturnKey(meth)) :: expr.ensureConforms(defn.ObjectType) :: Nil))
4855

4956
/** Transform (body, key) to:
5057
*
@@ -66,16 +73,13 @@ class NonLocalReturns extends MiniPhaseTransform { thisTransformer =>
6673
val pat = BindTyped(ex, nonLocalReturnControl)
6774
val rhs = If(
6875
ref(ex).select(nme.key).appliedToNone.select(nme.eq).appliedTo(ref(key)),
69-
ensureConforms(ref(ex).select(nme.value), meth.info.finalResultType),
76+
ref(ex).select(nme.value).ensureConforms(meth.info.finalResultType),
7077
Throw(ref(ex)))
7178
val catches = CaseDef(pat, EmptyTree, rhs) :: Nil
7279
val tryCatch = Try(body, catches, EmptyTree)
7380
Block(keyDef :: Nil, tryCatch)
7481
}
7582

76-
def isNonLocalReturn(ret: Return)(implicit ctx: Context) =
77-
ret.from.symbol != ctx.owner.enclosingMethod || ctx.owner.is(Lazy) // Lazy needed?
78-
7983
override def transformDefDef(tree: DefDef)(implicit ctx: Context, info: TransformerInfo): Tree =
8084
nonLocalReturnKeys.remove(tree.symbol) match {
8185
case Some(key) => cpy.DefDef(tree)(rhs = nonLocalReturnTry(tree.rhs, key, tree.symbol))

0 commit comments

Comments
 (0)