@@ -27,20 +27,20 @@ trait TypeTestsCasts {
2727
2828 def interceptTypeApply (tree : TypeApply )(implicit ctx : Context ): Tree = ctx.traceIndented(s " transforming ${tree.show}" , show = true ) {
2929 tree.fun match {
30- case fun @ Select (qual , selector) =>
30+ case fun @ Select (expr , selector) =>
3131 val sym = tree.symbol
3232
3333 def isPrimitive (tp : Type ) = tp.classSymbol.isPrimitiveValueClass
3434
35- def derivedTree (qual1 : Tree , sym : Symbol , tp : Type ) =
36- cpy.TypeApply (tree)(qual1 .select(sym).withPos(qual .pos), List (TypeTree (tp)))
35+ def derivedTree (expr1 : Tree , sym : Symbol , tp : Type ) =
36+ cpy.TypeApply (tree)(expr1 .select(sym).withPos(expr .pos), List (TypeTree (tp)))
3737
38- def foundCls = qual .tpe.widen.classSymbol
38+ def foundCls = expr .tpe.widen.classSymbol
3939 // println(i"ta $tree, found = $foundCls")
4040
4141 def inMatch =
4242 fun.symbol == defn.Any_typeTest || // new scheme
43- qual .symbol.is(Case ) // old scheme
43+ expr .symbol.is(Case ) // old scheme
4444
4545 def transformIsInstanceOf (expr: Tree , testType : Type , flagUnrelated : Boolean ): Tree = {
4646 def testCls = testType.classSymbol
@@ -50,28 +50,40 @@ trait TypeTestsCasts {
5050 if (inMatch) ctx.error(em " this case is unreachable since $why" , expr.pos)
5151 else ctx.warning(em " this will always yield false since $why" , expr.pos)
5252
53- def checkSensical : Boolean = {
54- val foundCls = erasure(qual.tpe.widen).typeSymbol
55- val testCls = testType.typeSymbol
56- ! foundCls.isClass ||
57- ! testCls.isClass ||
58- foundCls.isPrimitiveValueClass != testCls.isPrimitiveValueClass ||
59- ValueClasses .isDerivedValueClass(foundCls) ||
60- ValueClasses .isDerivedValueClass(testCls) ||
61- foundCls == defn.ObjectClass ||
62- foundCls.derivesFrom(testCls) || {
53+ /** Are `foundCls` and `testCls` classes that allow checks
54+ * whether a test would be always false?
55+ */
56+ def isCheckable =
57+ foundCls.isClass && testCls.isClass &&
58+ foundCls.isPrimitiveValueClass == testCls.isPrimitiveValueClass &&
59+ // if `found` is primitive but `test` is not, it's illegal anyway
60+ // if `test` is primitive but `found` is not, we might have a case like
61+ // found = java.lang.Integer, test = Int, which could be true
62+ // (not sure why that is so, but scalac behaves the same way)
63+ ! isDerivedValueClass(foundCls) && ! isDerivedValueClass(testCls) &&
64+ // we don't have the logic to handle derived value classes
65+ foundCls != defn.ObjectClass
66+ // if `foundCls == Object`, it could have been `Any` before erasure.
67+
68+ /** Check whether a runtime test that a value of `foundCls` can be a `testCls`
69+ * can be true in some cases. Issure a warning or an error if that's not the case.
70+ */
71+ def checkSensical : Boolean =
72+ if (! isCheckable) true
73+ else if (! foundCls.derivesFrom(testCls)) {
6374 if (foundCls.is(Final )) {
6475 unreachable(i " $foundCls is not a subclass of $testCls" )
6576 false
6677 }
6778 else if (! testCls.derivesFrom(foundCls) &&
68- (testCls.is(Final ) || ! testCls.is(Trait ) && ! foundCls.is(Trait ))) {
79+ (testCls.is(Final ) ||
80+ ! testCls.is(Trait ) && ! foundCls.is(Trait ))) {
6981 unreachable(i " $foundCls and $testCls are unrelated " )
7082 false
7183 }
7284 else true
7385 }
74- }
86+ else true
7587
7688 if (expr.tpe <:< testType)
7789 if (expr.tpe.isNotNull) {
@@ -88,32 +100,25 @@ trait TypeTestsCasts {
88100 constant(expr, Literal (Constant (foundCls == testCls)))
89101 else
90102 transformIsInstanceOf(expr, defn.boxedType(testCls.typeRef), flagUnrelated)
91- else testType.dealias match {
92- case _ : SingletonType =>
93- val cmpOp =
94- if (testType derivesFrom defn.AnyValClass ) defn.Any_equals
95- else defn.Object_eq
96- expr.select(cmpOp).appliedTo(singleton(testType))
97- case _ =>
98- derivedTree(expr, defn.Any_isInstanceOf , testType)
99- }
103+ else
104+ derivedTree(expr, defn.Any_isInstanceOf , testType)
100105 }
101106
102107 def transformAsInstanceOf (testType : Type ): Tree = {
103108 def testCls = testType.widen.classSymbol
104- if (qual .tpe <:< testType)
105- Typed (qual , tree.args.head)
109+ if (expr .tpe <:< testType)
110+ Typed (expr , tree.args.head)
106111 else if (foundCls.isPrimitiveValueClass) {
107- if (testCls.isPrimitiveValueClass) primitiveConversion(qual , testCls)
108- else derivedTree(box(qual ), defn.Any_asInstanceOf , testType)
112+ if (testCls.isPrimitiveValueClass) primitiveConversion(expr , testCls)
113+ else derivedTree(box(expr ), defn.Any_asInstanceOf , testType)
109114 }
110115 else if (testCls.isPrimitiveValueClass)
111- unbox(qual .ensureConforms(defn.ObjectType ), testType)
116+ unbox(expr .ensureConforms(defn.ObjectType ), testType)
112117 else if (isDerivedValueClass(testCls)) {
113- qual // adaptToType in Erasure will do the necessary type adaptation
118+ expr // adaptToType in Erasure will do the necessary type adaptation
114119 }
115120 else
116- derivedTree(qual , defn.Any_asInstanceOf , testType)
121+ derivedTree(expr , defn.Any_asInstanceOf , testType)
117122 }
118123
119124 /** Transform isInstanceOf OrType
@@ -124,32 +129,35 @@ trait TypeTestsCasts {
124129 * The transform happens before erasure of `testType`, thus cannot be merged
125130 * with `transformIsInstanceOf`, which depends on erased type of `testType`.
126131 */
127- def transformTypeTest (qual : Tree , testType : Type , flagUnrelated : Boolean ): Tree = testType.dealias match {
132+ def transformTypeTest (expr : Tree , testType : Type , flagUnrelated : Boolean ): Tree = testType.dealias match {
133+ case _ : SingletonType =>
134+ val cmpOp =
135+ if (testType derivesFrom defn.AnyValClass ) defn.Any_equals else defn.Object_eq
136+ expr.select(cmpOp).appliedTo(singleton(testType))
128137 case OrType (tp1, tp2) =>
129- evalOnce(qual) { fun =>
130- transformTypeTest(fun, tp1, flagUnrelated = false )
131- .select(defn.Boolean_|| )
132- .appliedTo(transformTypeTest(fun, tp2, flagUnrelated = false ))
138+ evalOnce(expr) { e =>
139+ transformTypeTest(e, tp1, flagUnrelated = false )
140+ .or(transformTypeTest(e, tp2, flagUnrelated = false ))
133141 }
134142 case AndType (tp1, tp2) =>
135- evalOnce(qual) { fun =>
136- transformTypeTest(fun, tp1, flagUnrelated)
137- .select(defn.Boolean_&& )
138- .appliedTo(transformTypeTest(fun, tp2, flagUnrelated))
143+ evalOnce(expr) { e =>
144+ transformTypeTest(e, tp1, flagUnrelated)
145+ .and(transformTypeTest(e, tp2, flagUnrelated))
139146 }
140147 case defn.MultiArrayOf (elem, ndims) if isUnboundedGeneric(elem) =>
141148 def isArrayTest (arg : Tree ) =
142149 ref(defn.runtimeMethodRef(nme.isArray)).appliedTo(arg, Literal (Constant (ndims)))
143- if (ndims == 1 ) isArrayTest(qual)
144- else evalOnce(qual) { qual1 =>
145- derivedTree(qual1, defn.Any_isInstanceOf , qual1.tpe) and isArrayTest(qual1)
150+ if (ndims == 1 ) isArrayTest(expr)
151+ else evalOnce(expr) { e =>
152+ derivedTree(e, defn.Any_isInstanceOf , e.tpe)
153+ .and(isArrayTest(e))
146154 }
147155 case _ =>
148- transformIsInstanceOf(qual , erasure(testType), flagUnrelated)
156+ transformIsInstanceOf(expr , erasure(testType), flagUnrelated)
149157 }
150158
151159 if ((sym eq defn.Any_isInstanceOf ) || (sym eq defn.Any_typeTest ))
152- transformTypeTest(qual , tree.args.head.tpe, flagUnrelated = true )
160+ transformTypeTest(expr , tree.args.head.tpe, flagUnrelated = true )
153161 else if (sym eq defn.Any_asInstanceOf )
154162 transformAsInstanceOf(erasure(tree.args.head.tpe))
155163 else tree
0 commit comments