@@ -869,6 +869,18 @@ abstract class Erasure extends AddInterfaces
869
869
* - Reset all other type attributes to null, thus enforcing a retyping.
870
870
*/
871
871
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
+ }
872
884
873
885
private def preEraseNormalApply (tree : Apply ) = {
874
886
val fn = tree.fun
@@ -878,19 +890,36 @@ abstract class Erasure extends AddInterfaces
878
890
case Select (qual, _) => qual
879
891
case TypeApply (Select (qual, _), _) => qual
880
892
}
893
+
894
+ // TODO SPEC: this should share logic with TypeTestTreeMaker in the pattern matcher,
895
+ // since `x.asInstanceOf[T]` is specified as the pattern match
896
+ // `x match { case x: T => x case null => null case _ => throw new ClassCastException }` (why is the null case needed?)
881
897
def preEraseAsInstanceOf = {
882
898
(fn : @ unchecked) match {
883
899
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
900
+ targ.tpe match {
901
+ case argTp@ SingletonInstanceCheck (cmpOp, cmpArg) if sip23 => // compiler has an unsound asInstanceOf[global.type]...
902
+ atPos(tree.pos) {
903
+ gen.evalOnce(qual, currentOwner, currentUnit) { qual =>
904
+ If (Apply (Select (qual(), cmpOp), List (cmpArg)),
905
+ Typed (qual(), TypeTree (argTp)),
906
+ Throw (ClassCastExceptionClass .tpe_* ))
907
+ }
908
+ }
909
+ case argTp if qual.tpe <:< argTp =>
910
+ atPos(tree.pos) { Typed (qual, TypeTree (argTp)) }
911
+ case argTp if isNumericValueClass(qual.tpe.typeSymbol) && isNumericValueClass(argTp.typeSymbol) =>
912
+ atPos(tree.pos)(numericConversion(qual, argTp.typeSymbol))
913
+ case _ =>
914
+ tree
915
+ }
890
916
}
891
917
// todo: also handle the case where the singleton type is buried in a compound
892
918
}
893
919
920
+ // TODO SPEC: this should share logic with TypeTestTreeMaker in the pattern matcher,
921
+ // since `x.isInstanceOf[T]` is specified as the pattern match
922
+ // `x match { case _: T => true case _ => false }` (modulo numeric conversion)
894
923
def preEraseIsInstanceOf = {
895
924
fn match {
896
925
case TypeApply (sel @ Select (qual, name), List (targ)) =>
@@ -904,11 +933,8 @@ abstract class Erasure extends AddInterfaces
904
933
List (TypeTree (tp) setPos targ.pos)) setPos fn.pos,
905
934
List ()) setPos tree.pos
906
935
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
- }
936
+ case SingletonInstanceCheck (cmpOp, cmpArg) =>
937
+ atPos(tree.pos) { Apply (Select (qual, cmpOp), List (cmpArg)) }
912
938
case RefinedType (parents, decls) if (parents.length >= 2 ) =>
913
939
gen.evalOnce(qual, currentOwner, unit) { q =>
914
940
// Optimization: don't generate isInstanceOf tests if the static type
0 commit comments