11package dotty .tools .dotc
22package transform
33
4- import core .Contexts ._
5- import core .Symbols ._
6- import core .Types ._
7- import core .Constants ._
8- import core .StdNames ._
9- import core .TypeErasure .isUnboundedGeneric
4+ import core ._
5+ import Contexts ._ , Symbols ._ , Types ._ , Constants ._ , StdNames ._ , Decorators ._
106import ast .Trees ._
117import Erasure .Boxing ._
12- import core . TypeErasure ._
8+ import TypeErasure ._
139import ValueClasses ._
10+ import core .Flags ._
11+ import util .Positions ._
12+
1413
1514/** This transform normalizes type tests and type casts,
1615 * also replacing type tests with singleton argument type with reference equality check
@@ -26,8 +25,6 @@ import ValueClasses._
2625trait TypeTestsCasts {
2726 import ast .tpd ._
2827
29- // override def phaseName: String = "typeTestsCasts"
30-
3128 def interceptTypeApply (tree : TypeApply )(implicit ctx : Context ): Tree = ctx.traceIndented(s " transforming ${tree.show}" , show = true ) {
3229 tree.fun match {
3330 case fun @ Select (qual, selector) =>
@@ -38,88 +35,122 @@ trait TypeTestsCasts {
3835 def derivedTree (qual1 : Tree , sym : Symbol , tp : Type ) =
3936 cpy.TypeApply (tree)(qual1.select(sym).withPos(qual.pos), List (TypeTree (tp)))
4037
41- def qualCls = qual.tpe.widen.classSymbol
38+ def foundCls = qual.tpe.widen.classSymbol
39+ // println(i"ta $tree, found = $foundCls")
4240
43- def transformIsInstanceOf (expr: Tree , argType : Type ): Tree = {
44- def argCls = argType.classSymbol
45- if ((expr.tpe <:< argType) && isPureExpr(expr))
46- Literal (Constant (true )) withPos tree.pos
47- else if (argCls.isPrimitiveValueClass)
48- if (qualCls.isPrimitiveValueClass) Literal (Constant (qualCls == argCls)) withPos tree.pos
49- else transformIsInstanceOf(expr, defn.boxedType(argCls.typeRef))
50- else argType.dealias match {
51- case _ : SingletonType =>
52- val cmpOp = if (argType derivesFrom defn.AnyValClass ) defn.Any_equals else defn.Object_eq
53- expr.select(cmpOp).appliedTo(singleton(argType))
54- case AndType (tp1, tp2) =>
55- evalOnce(expr) { fun =>
56- val erased1 = transformIsInstanceOf(fun, tp1)
57- val erased2 = transformIsInstanceOf(fun, tp2)
58- erased1 match {
59- case Literal (Constant (true )) => erased2
60- case _ =>
61- erased2 match {
62- case Literal (Constant (true )) => erased1
63- case _ => erased1 and erased2
64- }
65- }
41+ def inMatch =
42+ fun.symbol == defn.Any_typeTest || // new scheme
43+ qual.symbol.is(Case ) // old scheme
44+
45+ def transformIsInstanceOf (expr: Tree , testType : Type , flagUnrelated : Boolean ): Tree = {
46+ def testCls = testType.classSymbol
47+
48+ def unreachable (why : => String ) =
49+ if (flagUnrelated)
50+ if (inMatch) ctx.error(em " this case is unreachable since $why" , expr.pos)
51+ else ctx.warning(em " this will always yield false since $why" , expr.pos)
52+
53+ def checkSensical : Boolean = {
54+ val foundCls = erasure(qual.tpe.widen).typeSymbol
55+ val testCls = testType.typeSymbol
56+ ! foundCls.isClass ||
57+ ! testCls.isClass ||
58+ testCls.isPrimitiveValueClass ||
59+ ValueClasses .isDerivedValueClass(foundCls) ||
60+ ValueClasses .isDerivedValueClass(testCls) ||
61+ foundCls == defn.ObjectClass ||
62+ foundCls.derivesFrom(testCls) || {
63+ if (foundCls.is(Final )) {
64+ unreachable(i " $foundCls is not a subclass of $testCls" )
65+ false
6666 }
67- case defn.MultiArrayOf (elem, ndims) if isUnboundedGeneric(elem) =>
68- def isArrayTest (arg : Tree ) =
69- ref(defn.runtimeMethodRef(nme.isArray)).appliedTo(arg, Literal (Constant (ndims)))
70- if (ndims == 1 ) isArrayTest(qual)
71- else evalOnce(qual) { qual1 =>
72- derivedTree(qual1, defn.Any_isInstanceOf , qual1.tpe) and isArrayTest(qual1)
67+ else if (! testCls.derivesFrom(foundCls) &&
68+ (testCls.is(Final ) || ! testCls.is(Trait ) && ! foundCls.is(Trait ))) {
69+ unreachable(i " $foundCls and $testCls are unrelated " )
70+ false
7371 }
72+ else true
73+ }
74+ }
75+ println(i " test ii $tree ${expr.tpe} $testType" )
76+
77+ if (expr.tpe <:< testType)
78+ if (expr.tpe.isNotNull) {
79+ ctx.warning(
80+ em " this will always yield true, since ` $foundCls` is a subclass of ` $testCls` " ,
81+ expr.pos)
82+ constant(expr, Literal (Constant (true )))
83+ }
84+ else expr.testNotNull
85+ else if (! checkSensical)
86+ constant(expr, Literal (Constant (false )))
87+ else if (testCls.isPrimitiveValueClass)
88+ if (foundCls.isPrimitiveValueClass)
89+ constant(expr, Literal (Constant (foundCls == testCls)))
90+ else
91+ transformIsInstanceOf(expr, defn.boxedType(testCls.typeRef), flagUnrelated)
92+ else testType.dealias match {
93+ case _ : SingletonType =>
94+ val cmpOp =
95+ if (testType derivesFrom defn.AnyValClass ) defn.Any_equals
96+ else defn.Object_eq
97+ expr.select(cmpOp).appliedTo(singleton(testType))
7498 case _ =>
75- derivedTree(expr, defn.Any_isInstanceOf , argType )
99+ derivedTree(expr, defn.Any_isInstanceOf , testType )
76100 }
77101 }
78102
79- def transformAsInstanceOf (argType : Type ): Tree = {
80- def argCls = argType .widen.classSymbol
81- if (qual.tpe <:< argType )
103+ def transformAsInstanceOf (testType : Type ): Tree = {
104+ def testCls = testType .widen.classSymbol
105+ if (qual.tpe <:< testType )
82106 Typed (qual, tree.args.head)
83- else if (qualCls .isPrimitiveValueClass) {
84- if (argCls .isPrimitiveValueClass) primitiveConversion(qual, argCls )
85- else derivedTree(box(qual), defn.Any_asInstanceOf , argType )
107+ else if (foundCls .isPrimitiveValueClass) {
108+ if (testCls .isPrimitiveValueClass) primitiveConversion(qual, testCls )
109+ else derivedTree(box(qual), defn.Any_asInstanceOf , testType )
86110 }
87- else if (argCls .isPrimitiveValueClass)
88- unbox(qual.ensureConforms(defn.ObjectType ), argType )
89- else if (isDerivedValueClass(argCls )) {
111+ else if (testCls .isPrimitiveValueClass)
112+ unbox(qual.ensureConforms(defn.ObjectType ), testType )
113+ else if (isDerivedValueClass(testCls )) {
90114 qual // adaptToType in Erasure will do the necessary type adaptation
91115 }
92116 else
93- derivedTree(qual, defn.Any_asInstanceOf , argType )
117+ derivedTree(qual, defn.Any_asInstanceOf , testType )
94118 }
95119
96120 /** Transform isInstanceOf OrType
97121 *
98122 * expr.isInstanceOf[A | B] ~~> expr.isInstanceOf[A] | expr.isInstanceOf[B]
99123 * expr.isInstanceOf[A & B] ~~> expr.isInstanceOf[A] & expr.isInstanceOf[B]
100124 *
101- * The transform happens before erasure of `argType `, thus cannot be merged
102- * with `transformIsInstanceOf`, which depends on erased type of `argType `.
125+ * The transform happens before erasure of `testType `, thus cannot be merged
126+ * with `transformIsInstanceOf`, which depends on erased type of `testType `.
103127 */
104- def transformTypeTest (qual : Tree , argType : Type ): Tree = argType .dealias match {
128+ def transformTypeTest (qual : Tree , testType : Type , flagUnrelated : Boolean ): Tree = testType .dealias match {
105129 case OrType (tp1, tp2) =>
106130 evalOnce(qual) { fun =>
107- transformTypeTest(fun, tp1)
131+ transformTypeTest(fun, tp1, flagUnrelated = false )
108132 .select(defn.Boolean_|| )
109- .appliedTo(transformTypeTest(fun, tp2))
133+ .appliedTo(transformTypeTest(fun, tp2, flagUnrelated = false ))
110134 }
111135 case AndType (tp1, tp2) =>
112136 evalOnce(qual) { fun =>
113- transformTypeTest(fun, tp1)
137+ transformTypeTest(fun, tp1, flagUnrelated )
114138 .select(defn.Boolean_&& )
115- .appliedTo(transformTypeTest(fun, tp2))
139+ .appliedTo(transformTypeTest(fun, tp2, flagUnrelated))
140+ }
141+ case defn.MultiArrayOf (elem, ndims) if isUnboundedGeneric(elem) =>
142+ def isArrayTest (arg : Tree ) =
143+ ref(defn.runtimeMethodRef(nme.isArray)).appliedTo(arg, Literal (Constant (ndims)))
144+ if (ndims == 1 ) isArrayTest(qual)
145+ else evalOnce(qual) { qual1 =>
146+ derivedTree(qual1, defn.Any_isInstanceOf , qual1.tpe) and isArrayTest(qual1)
116147 }
117148 case _ =>
118- transformIsInstanceOf(qual, erasure(argType) )
149+ transformIsInstanceOf(qual, erasure(testType), flagUnrelated )
119150 }
120151
121- if (sym eq defn.Any_isInstanceOf )
122- transformTypeTest(qual, tree.args.head.tpe)
152+ if (( sym eq defn.Any_isInstanceOf ) || (sym eq defn. Any_typeTest ) )
153+ transformTypeTest(qual, tree.args.head.tpe, flagUnrelated = true )
123154 else if (sym eq defn.Any_asInstanceOf )
124155 transformAsInstanceOf(erasure(tree.args.head.tpe))
125156 else tree
0 commit comments