Skip to content

Commit 359b140

Browse files
committed
asInstanceOf for singleton types
``` scala> val x = "a" x: "a" = a scala> x.asInstanceOf["a"] res1: "a" = a scala> "1".asInstanceOf["2"] x asInstanceOf Throwable java.lang.ClassCastException ... 33 elided scala> "1".asInstanceOf["1"] res3: "1" = 1 scala> 1.asInstanceOf[1] res4: 1 = 1 scala> 1.asInstanceOf[2] x asInstanceOf Throwable java.lang.ClassCastException ... 33 elided ```
1 parent ee5b81e commit 359b140

File tree

1 file changed

+30
-11
lines changed

1 file changed

+30
-11
lines changed

src/compiler/scala/tools/nsc/transform/Erasure.scala

Lines changed: 30 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -869,6 +869,18 @@ abstract class Erasure extends AddInterfaces
869869
* - Reset all other type attributes to null, thus enforcing a retyping.
870870
*/
871871
private val preTransformer = new TypingTransformer(unit) {
872+
// TODO: since the spec defines instanceOf checks in terms of pattern matching,
873+
// this extractor should share code with TypeTestTreeMaker
874+
object SingletonInstanceCheck {
875+
def unapply(pt: Type): Option[(TermSymbol, Tree)] = pt match {
876+
case SingleType(_, _) | LiteralType(_) | ThisType(_) | SuperType(_, _) =>
877+
val cmpOp = if (pt <:< AnyValTpe) Any_equals else Object_eq
878+
val cmpArg = gen.mkAttributedQualifier(pt)
879+
Some((cmpOp, cmpArg))
880+
case _ =>
881+
None
882+
}
883+
}
872884

873885
private def preEraseNormalApply(tree: Apply) = {
874886
val fn = tree.fun
@@ -881,12 +893,22 @@ abstract class Erasure extends AddInterfaces
881893
def preEraseAsInstanceOf = {
882894
(fn: @unchecked) match {
883895
case TypeApply(Select(qual, _), List(targ)) =>
884-
if (qual.tpe <:< targ.tpe)
885-
atPos(tree.pos) { Typed(qual, TypeTree(targ.tpe)) }
886-
else if (isNumericValueClass(qual.tpe.typeSymbol) && isNumericValueClass(targ.tpe.typeSymbol))
887-
atPos(tree.pos)(numericConversion(qual, targ.tpe.typeSymbol))
888-
else
889-
tree
896+
targ.tpe match {
897+
case argTp@SingletonInstanceCheck(cmpOp, cmpArg) if sip23 => // compiler has an unsound asInstanceOf[global.type]...
898+
atPos(tree.pos) {
899+
gen.evalOnce(qual, currentOwner, currentUnit) { qual =>
900+
If(Apply(Select(qual(), cmpOp), List(cmpArg)),
901+
Typed(qual(), TypeTree(argTp)),
902+
Throw(ClassCastExceptionClass.tpe_*))
903+
}
904+
}
905+
case argTp if qual.tpe <:< argTp =>
906+
atPos(tree.pos) { Typed(qual, TypeTree(argTp)) }
907+
case argTp if isNumericValueClass(qual.tpe.typeSymbol) && isNumericValueClass(argTp.typeSymbol) =>
908+
atPos(tree.pos)(numericConversion(qual, argTp.typeSymbol))
909+
case _ =>
910+
tree
911+
}
890912
}
891913
// todo: also handle the case where the singleton type is buried in a compound
892914
}
@@ -904,11 +926,8 @@ abstract class Erasure extends AddInterfaces
904926
List(TypeTree(tp) setPos targ.pos)) setPos fn.pos,
905927
List()) setPos tree.pos
906928
targ.tpe match {
907-
case SingleType(_, _) | LiteralType(_) | ThisType(_) | SuperType(_, _) =>
908-
val cmpOp = if (targ.tpe <:< AnyValTpe) Any_equals else Object_eq
909-
atPos(tree.pos) {
910-
Apply(Select(qual, cmpOp), List(gen.mkAttributedQualifier(targ.tpe)))
911-
}
929+
case SingletonInstanceCheck(cmpOp, cmpArg) =>
930+
atPos(tree.pos) { Apply(Select(qual, cmpOp), List(cmpArg)) }
912931
case RefinedType(parents, decls) if (parents.length >= 2) =>
913932
gen.evalOnce(qual, currentOwner, unit) { q =>
914933
// Optimization: don't generate isInstanceOf tests if the static type

0 commit comments

Comments
 (0)