@@ -20,7 +20,7 @@ import TypeUtils._, TypeErasure._, Flags._
20
20
*
21
21
* Steps taken:
22
22
*
23
- * 1. `evalTypeApply ` will establish the matrix and choose the appropriate
23
+ * 1. `evalTypeTest ` will establish the matrix and choose the appropriate
24
24
* handling for the case:
25
25
* - Sel/sc is a value class or scrutinee is `Any`
26
26
* - `handleStaticallyKnown`
@@ -45,128 +45,128 @@ class IsInstanceOfEvaluator extends MiniPhaseTransform { thisTransformer =>
45
45
* the correct warnings, or an error if statically known to be false in
46
46
* match
47
47
*/
48
- def handleStaticallyKnown (select : Select , scrutinee : Type , selector : Type , inMatch : Boolean , pos : Position ): Tree = {
48
+ def handleStaticallyKnown (qualifier : Tree , scrutinee : Type , selector : Type , inMatch : Boolean , pos : Position ): Tree = {
49
49
val scrutineeSubSelector = scrutinee <:< selector
50
50
if (! scrutineeSubSelector && inMatch) {
51
51
ctx.error(
52
52
s " this case is unreachable due to ` ${selector.show}` not being a subclass of ` ${scrutinee.show}` " ,
53
53
Position (pos.start - 5 , pos.end - 5 )
54
54
)
55
- rewrite(select , to = false )
55
+ rewrite(qualifier , to = false )
56
56
} else if (! scrutineeSubSelector && ! inMatch) {
57
57
ctx.warning(
58
58
s " this will always yield false since ` ${scrutinee.show}` is not a subclass of ` ${selector.show}` (will be optimized away) " ,
59
59
pos
60
60
)
61
- rewrite(select , to = false )
61
+ rewrite(qualifier , to = false )
62
62
} else if (scrutineeSubSelector && ! inMatch) {
63
63
ctx.warning(
64
64
s " this will always yield true if the scrutinee is non-null, since ` ${scrutinee.show}` is a subclass of ` ${selector.show}` (will be optimized away) " ,
65
65
pos
66
66
)
67
- rewrite(select , to = true )
68
- } else /* if (scrutineeSubSelector && inMatch) */ rewrite(select , to = true )
67
+ rewrite(qualifier , to = true )
68
+ } else /* if (scrutineeSubSelector && inMatch) */ rewrite(qualifier , to = true )
69
69
}
70
70
71
71
/** Rewrites cases with unrelated types */
72
- def handleFalseUnrelated (select : Select , scrutinee : Type , selector : Type , inMatch : Boolean ) =
72
+ def handleFalseUnrelated (qualifier : Tree , scrutinee : Type , selector : Type , inMatch : Boolean ) =
73
73
if (inMatch) {
74
74
ctx.error(
75
75
s " will never match since ` ${selector.show}` is not a subclass of ` ${scrutinee.show}` " ,
76
- Position (select .pos.start - 5 , select .pos.end - 5 )
76
+ Position (qualifier .pos.start - 5 , qualifier .pos.end - 5 ) // WHY 5?
77
77
)
78
- rewrite(select , to = false )
78
+ rewrite(qualifier , to = false )
79
79
} else {
80
80
ctx.warning(
81
81
s " will always yield false since ` ${scrutinee.show}` is not a subclass of ` ${selector.show}` " ,
82
- select .pos
82
+ tree .pos
83
83
)
84
- rewrite(select , to = false )
84
+ rewrite(qualifier , to = false )
85
85
}
86
86
87
- /** Rewrites the select to a boolean if `to` is false or if the qualifier
87
+ /** Rewrites the qualifier of a type test to a boolean if `to` is false or if the qualifier
88
88
* is a value class.
89
89
*
90
90
* If `to` is set to true and the qualifier is not a primitive, the
91
91
* instanceOf is replaced by a null check, since:
92
92
*
93
93
* `scrutinee.isInstanceOf[Selector]` if `scrutinee eq null`
94
94
*/
95
- def rewrite (tree : Select , to : Boolean ): Tree =
96
- if (! to || ! tree. qualifier.tpe.widen.derivesFrom(defn.AnyRefAlias )) {
95
+ def rewrite (qualifier : Tree , to : Boolean ): Tree =
96
+ if (! to || ! qualifier.tpe.widen.derivesFrom(defn.AnyRefAlias )) {
97
97
val literal = Literal (Constant (to))
98
- if (! isPureExpr(tree. qualifier)) Block (List (tree. qualifier), literal)
98
+ if (! isPureExpr(qualifier)) Block (List (qualifier), literal)
99
99
else literal
100
100
} else
101
- Apply (tree. qualifier.select(defn.Object_ne ), List (Literal (Constant (null ))))
101
+ Apply (qualifier.select(defn.Object_ne ), List (Literal (Constant (null ))))
102
102
103
- /** Attempts to rewrite TypeApply to either `scrutinee ne null` or a
104
- * constant
103
+ /** Attempts to rewrite type test to either `scrutinee ne null` or a
104
+ * constant. Any_typeTest nodes have been rewritten to Any_isInstanceOf at this point.
105
+ * @param tree the whole type test <qualifier>.asInstanceOf[T]
106
+ * @param qualifier the <qualifier> part
107
+ * @param inMatch tree was a type test generated by a pattern match.
105
108
*/
106
- def evalTypeApply (tree : TypeApply ): Tree =
107
- if (tree.symbol != defn.Any_isInstanceOf ) tree
108
- else tree.fun match {
109
- case s : Select => {
110
- val scrutinee = erasure(s.qualifier.tpe.widen)
111
- val selector = erasure(tree.args.head.tpe.widen)
112
-
113
- val scTrait = scrutinee.typeSymbol is Trait
114
- val scClass =
115
- scrutinee.typeSymbol.isClass &&
116
- ! (scrutinee.typeSymbol is Trait ) &&
117
- ! (scrutinee.typeSymbol is Module )
118
-
119
- val scClassNonFinal = scClass && ! (scrutinee.typeSymbol is Final )
120
- val scFinalClass = scClass && (scrutinee.typeSymbol is Final )
121
-
122
- val selTrait = selector.typeSymbol is Trait
123
- val selClass =
124
- selector.typeSymbol.isClass &&
125
- ! (selector.typeSymbol is Trait ) &&
126
- ! (selector.typeSymbol is Module )
127
-
128
- val selClassNonFinal = selClass && ! (selector.typeSymbol is Final )
129
- val selFinalClass = selClass && (selector.typeSymbol is Final )
130
-
131
- // Cases ---------------------------------
132
- val valueClassesOrAny =
133
- ValueClasses .isDerivedValueClass(scrutinee.typeSymbol) ||
134
- ValueClasses .isDerivedValueClass(selector.typeSymbol) ||
135
- scrutinee == defn.ObjectType
136
-
137
- val knownStatically = scFinalClass
138
-
139
- val falseIfUnrelated =
140
- (scClassNonFinal && selClassNonFinal) ||
141
- (scClassNonFinal && selFinalClass) ||
142
- (scTrait && selFinalClass)
143
-
144
- val happens =
145
- (scClassNonFinal && selClassNonFinal) ||
146
- (scTrait && selClassNonFinal) ||
147
- (scTrait && selTrait)
148
-
149
- val inMatch = s.qualifier.symbol is Case
150
- // FIXME: This will misclassify case objects! We need to find another way to characterize
151
- // isInstanceOfs generated by matches.
152
- // Probably the most robust way is to use another symbol for the isInstanceOf method.
153
-
154
- if (valueClassesOrAny) tree
155
- else if (knownStatically)
156
- handleStaticallyKnown(s, scrutinee, selector, inMatch, tree.pos)
157
- else if (falseIfUnrelated && scrutinee <:< selector)
158
- // scrutinee is a subtype of the selector, safe to rewrite
159
- rewrite(s, to = true )
160
- else if (falseIfUnrelated && ! (selector <:< scrutinee))
161
- // selector and scrutinee are unrelated
162
- handleFalseUnrelated(s, scrutinee, selector, inMatch)
163
- else if (happens) tree
164
- else tree
165
- }
166
-
167
- case _ => tree
168
- }
109
+ def evalTypeTest (tree : TypeApply , qualifier : Tree , inMatch : Boolean ) = {
110
+ val scrutinee = erasure(qualifier.tpe.widen)
111
+ val selector = erasure(tree.args.head.tpe.widen)
112
+
113
+ val scTrait = scrutinee.typeSymbol is Trait
114
+ val scClass =
115
+ scrutinee.typeSymbol.isClass &&
116
+ ! (scrutinee.typeSymbol is Trait ) &&
117
+ ! (scrutinee.typeSymbol is Module )
118
+
119
+ val scClassNonFinal = scClass && ! (scrutinee.typeSymbol is Final )
120
+ val scFinalClass = scClass && (scrutinee.typeSymbol is Final )
121
+
122
+ val selTrait = selector.typeSymbol is Trait
123
+ val selClass =
124
+ selector.typeSymbol.isClass &&
125
+ ! (selector.typeSymbol is Trait ) &&
126
+ ! (selector.typeSymbol is Module )
127
+
128
+ val selClassNonFinal = selClass && ! (selector.typeSymbol is Final )
129
+ val selFinalClass = selClass && (selector.typeSymbol is Final )
130
+
131
+ // Cases ---------------------------------
132
+ val valueClassesOrAny =
133
+ ValueClasses .isDerivedValueClass(scrutinee.typeSymbol) ||
134
+ ValueClasses .isDerivedValueClass(selector.typeSymbol) ||
135
+ scrutinee == defn.ObjectType
136
+
137
+ val knownStatically = scFinalClass
138
+
139
+ val falseIfUnrelated =
140
+ (scClassNonFinal && selClassNonFinal) ||
141
+ (scClassNonFinal && selFinalClass) ||
142
+ (scTrait && selFinalClass)
143
+
144
+ val happens =
145
+ (scClassNonFinal && selClassNonFinal) ||
146
+ (scTrait && selClassNonFinal) ||
147
+ (scTrait && selTrait)
148
+
149
+ if (valueClassesOrAny) tree
150
+ else if (knownStatically)
151
+ handleStaticallyKnown(qualifier, scrutinee, selector, inMatch, tree.pos)
152
+ else if (falseIfUnrelated && scrutinee <:< selector)
153
+ // scrutinee is a subtype of the selector, safe to rewrite
154
+ rewrite(qualifier, to = true )
155
+ else if (falseIfUnrelated && ! (selector <:< scrutinee))
156
+ // selector and scrutinee are unrelated
157
+ handleFalseUnrelated(qualifier, scrutinee, selector, inMatch)
158
+ else if (happens) tree
159
+ else tree
160
+ }
169
161
170
- evalTypeApply(tree)
162
+ tree.fun match {
163
+ case fn : Select if fn.symbol == defn.Any_typeTest =>
164
+ evalTypeTest(
165
+ cpy.TypeApply (tree)(fn.qualifier.select(defn.Any_isInstanceOf ), tree.args),
166
+ fn.qualifier, inMatch = true )
167
+ case fn : Select if fn.symbol == defn.Any_isInstanceOf =>
168
+ evalTypeTest(tree, fn.qualifier, inMatch = false )
169
+ case _ => tree
170
+ }
171
171
}
172
172
}
0 commit comments