From 0f78b2039d97eb8a1fb813ec7be1b4d4c6c2718a Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Wed, 11 Feb 2015 11:22:46 +0100 Subject: [PATCH 1/2] Insert correct boxing/unboxing conversions for branches ... of an If, Match, or Try. Fixes #355. --- src/dotty/tools/dotc/transform/Erasure.scala | 30 ++++++++++++++++++++ tests/pos/erased-lub.scala | 27 ++++++++++++++++++ 2 files changed, 57 insertions(+) create mode 100644 tests/pos/erased-lub.scala diff --git a/src/dotty/tools/dotc/transform/Erasure.scala b/src/dotty/tools/dotc/transform/Erasure.scala index a0370fecab75..fe577d3f5802 100644 --- a/src/dotty/tools/dotc/transform/Erasure.scala +++ b/src/dotty/tools/dotc/transform/Erasure.scala @@ -252,6 +252,36 @@ object Erasure extends TypeTestsCasts{ if (tree.typeOpt.isRef(defn.UnitClass)) tree.withType(tree.typeOpt) else super.typedLiteral(tree) + // The following methods, typedIf, typedMatch and typedTry need to compensate + // for the fact that after erasure, a subtype may notbe compatible with the + // type of a lub. Hence we might need to readapt branches to the common type. + // Note that the typing of SeqLiteral faces a similar problem but solves it + // differently: It adapts all elements to the erasure of the type that existed + // before. TODO: It looks like a good idea to harmonize this. + // + override def typedIf(tree: untpd.If, pt: Type)(implicit ctx: Context): If = { + val tree1 = super.typedIf(tree, pt) + println(i"typed if $tree1 with $pt = ${tree1.tpe}") + if (pt.isValueType) tree1 + else cpy.If(tree1)(thenp = adapt(tree1.thenp, tree1.tpe), elsep = adapt(tree1.elsep, tree1.tpe)) + } + + override def typedMatch(tree: untpd.Match, pt: Type)(implicit ctx: Context): Match = { + val tree1 = super.typedMatch(tree, pt).asInstanceOf[Match] + if (pt.isValueType) tree1 + else cpy.Match(tree1)(tree1.selector, tree1.cases.map(adaptCase(_, tree1.tpe))) + } + + override def typedTry(tree: untpd.Try, pt: Type)(implicit ctx: Context): Try = { + val tree1 = super.typedTry(tree, pt) + if (pt.isValueType) tree1 + else cpy.Try(tree1)(expr = adapt(tree1.expr, tree1.tpe), cases = tree1.cases.map(adaptCase(_, tree1.tpe))) + } + + private def adaptCase(cdef: CaseDef, pt: Type)(implicit ctx: Context): CaseDef = + cpy.CaseDef(cdef)(body = adapt(cdef.body, pt)) + + /** 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. diff --git a/tests/pos/erased-lub.scala b/tests/pos/erased-lub.scala new file mode 100644 index 000000000000..d3d2183c123b --- /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) + +} From 3a74f7c38ac6fd26b5463a4c19b41265f25a953a Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Wed, 11 Feb 2015 12:15:20 +0100 Subject: [PATCH 2/2] Removed extraneous debug println. --- src/dotty/tools/dotc/transform/Erasure.scala | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/src/dotty/tools/dotc/transform/Erasure.scala b/src/dotty/tools/dotc/transform/Erasure.scala index fe577d3f5802..885617db73f7 100644 --- a/src/dotty/tools/dotc/transform/Erasure.scala +++ b/src/dotty/tools/dotc/transform/Erasure.scala @@ -251,17 +251,9 @@ 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) - - // The following methods, typedIf, typedMatch and typedTry need to compensate - // for the fact that after erasure, a subtype may notbe compatible with the - // type of a lub. Hence we might need to readapt branches to the common type. - // Note that the typing of SeqLiteral faces a similar problem but solves it - // differently: It adapts all elements to the erasure of the type that existed - // before. TODO: It looks like a good idea to harmonize this. - // + override def typedIf(tree: untpd.If, pt: Type)(implicit ctx: Context): If = { val tree1 = super.typedIf(tree, pt) - println(i"typed if $tree1 with $pt = ${tree1.tpe}") if (pt.isValueType) tree1 else cpy.If(tree1)(thenp = adapt(tree1.thenp, tree1.tpe), elsep = adapt(tree1.elsep, tree1.tpe)) }