diff options
author | Lukas Rytz <lukas.rytz@gmail.com> | 2016-05-18 15:24:45 +0200 |
---|---|---|
committer | Lukas Rytz <lukas.rytz@gmail.com> | 2016-05-18 21:53:24 +0200 |
commit | 38ca9dec8807ddce36a988bf13b367f4d6f03b9e (patch) | |
tree | c874aa1a38c6d170ea36d3f092536ba6bf72cb0b /src/compiler/scala/tools/nsc/transform/TypeAdaptingTransformer.scala | |
parent | 39490f709ee6877884b0db11b37605651bfb1bfa (diff) | |
download | scala-38ca9dec8807ddce36a988bf13b367f4d6f03b9e.tar.gz scala-38ca9dec8807ddce36a988bf13b367f4d6f03b9e.tar.bz2 scala-38ca9dec8807ddce36a988bf13b367f4d6f03b9e.zip |
SI-9671, SI-7397 fix null.asInstanceOf[Int] when pt erases to Object
Erasure first replaces null.asInstanceOf[Int] by unbox(null). If the
expected type erases to object, erasure then introduces a box operation,
yielding box(unbox(null)). Note that this value is a box of zero, not
null.
Erasure has an optimization to replace box(unbox(x)) in case x is
of primitive type. 60f1b4b extended this to the case when x is null,
which is incorrect in general. The reason was to prevent creating a
primitive box to be stored in the unused generic field when creating
an instance of a specialized class. A special case ensures that this
optimization is still performed.
Diffstat (limited to 'src/compiler/scala/tools/nsc/transform/TypeAdaptingTransformer.scala')
-rw-r--r-- | src/compiler/scala/tools/nsc/transform/TypeAdaptingTransformer.scala | 22 |
1 files changed, 11 insertions, 11 deletions
diff --git a/src/compiler/scala/tools/nsc/transform/TypeAdaptingTransformer.scala b/src/compiler/scala/tools/nsc/transform/TypeAdaptingTransformer.scala index afafdedce7..52d7c0b897 100644 --- a/src/compiler/scala/tools/nsc/transform/TypeAdaptingTransformer.scala +++ b/src/compiler/scala/tools/nsc/transform/TypeAdaptingTransformer.scala @@ -14,11 +14,18 @@ trait TypeAdaptingTransformer { self: TreeDSL => def typedPos(pos: Position)(tree: Tree): Tree + /** + * SI-4148: can't always replace box(unbox(x)) by x because + * - unboxing x may lead to throwing an exception, e.g. in "aah".asInstanceOf[Int] + * - box(unbox(null)) is not `null` but the box of zero + */ private def isSafelyRemovableUnbox(fn: Tree, arg: Tree): Boolean = { - currentRun.runDefinitions.isUnbox(fn.symbol) && { - val cls = arg.tpe.typeSymbol - (cls == NullClass) || isBoxedValueClass(cls) - } + currentRun.runDefinitions.isUnbox(fn.symbol) && { + // replace box(unbox(null)) by null when passed to the super constructor in a specialized + // class, see comment in SpecializeTypes.forwardCtorCall. + arg.hasAttachment[specializeTypes.SpecializedSuperConstructorCallArgument.type] || + isBoxedValueClass(arg.tpe.typeSymbol) + } } private def isPrimitiveValueType(tpe: Type) = isPrimitiveValueClass(tpe.typeSymbol) @@ -44,14 +51,7 @@ trait TypeAdaptingTransformer { self: TreeDSL => case x => assert(x != ArrayClass) tree match { - /* Can't always remove a Box(Unbox(x)) combination because the process of boxing x - * may lead to throwing an exception. - * - * This is important for specialization: calls to the super constructor should not box/unbox specialized - * fields (see TupleX). (ID) - */ case Apply(boxFun, List(arg)) if isSafelyRemovableUnbox(tree, arg) => - log(s"boxing an unbox: ${tree.symbol} -> ${arg.tpe}") arg case _ => (REF(currentRun.runDefinitions.boxMethod(x)) APPLY tree) setPos (tree.pos) setType ObjectTpe |