@@ -5,7 +5,7 @@ import dotty.tools.dotc.util.Positions._
5
5
import TreeTransforms .{MiniPhaseTransform , TransformerInfo }
6
6
import core ._
7
7
import Contexts .Context , Types ._ , Constants ._ , Decorators ._ , Symbols ._
8
- import TypeUtils ._ , TypeErasure ._
8
+ import TypeUtils ._ , TypeErasure ._ , Flags . _
9
9
10
10
11
11
/** Implements partial evaluation of `sc.isInstanceOf[Sel]` according to:
@@ -25,10 +25,11 @@ import TypeUtils._, TypeErasure._
25
25
*
26
26
* 1. evalTypeApply will establish the matrix and choose the appropriate
27
27
* handling for the case:
28
- * 2. a) handleStaticallyKnown
29
- * b) falseIfUnrelated with `scrutinee <:< selector`
30
- * c) handleFalseUnrelated
31
- * d) leave as is (aka `happens`)
28
+ * 2. a) Sel/sc is a value class or scrutinee is `Any`
29
+ * b) handleStaticallyKnown
30
+ * c) falseIfUnrelated with `scrutinee <:< selector`
31
+ * d) handleFalseUnrelated
32
+ * e) leave as is (aka `happens`)
32
33
* 3. Rewrite according to step taken in `2`
33
34
*/
34
35
class IsInstanceOfEvaluator extends MiniPhaseTransform { thisTransformer =>
@@ -43,43 +44,43 @@ class IsInstanceOfEvaluator extends MiniPhaseTransform { thisTransformer =>
43
44
* the correct warnings, or an error if statically known to be false in
44
45
* match
45
46
*/
46
- def handleStaticallyKnown (tree : Select , scrutinee : Type , selector : Type , inMatch : Boolean , pos : Position ): Tree = {
47
+ def handleStaticallyKnown (select : Select , scrutinee : Type , selector : Type , inMatch : Boolean , pos : Position ): Tree = {
47
48
val scrutineeSubSelector = scrutinee <:< selector
48
49
if (! scrutineeSubSelector && inMatch) {
49
50
ctx.error(
50
51
s " this case is unreachable due to ` ${selector.show}` not being a subclass of ` ${scrutinee.show}` " ,
51
52
Position (pos.start - 5 , pos.end - 5 )
52
53
)
53
- rewrite(tree , to = false )
54
+ rewrite(select , to = false )
54
55
} else if (! scrutineeSubSelector && ! inMatch) {
55
56
ctx.warning(
56
57
s " this will always yield false since ` ${scrutinee.show}` is not a subclass of ` ${selector.show}` (will be optimized away) " ,
57
58
pos
58
59
)
59
- rewrite(tree , to = false )
60
+ rewrite(select , to = false )
60
61
} else if (scrutineeSubSelector && ! inMatch) {
61
62
ctx.warning(
62
63
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) " ,
63
64
pos
64
65
)
65
- rewrite(tree , to = true )
66
- } else /* if (scrutineeSubSelector && inMatch) */ rewrite(tree , to = true )
66
+ rewrite(select , to = true )
67
+ } else /* if (scrutineeSubSelector && inMatch) */ rewrite(select , to = true )
67
68
}
68
69
69
70
/** Rewrites cases with unrelated types */
70
- def handleFalseUnrelated (tree : Select , scrutinee : Type , selector : Type , inMatch : Boolean ) =
71
+ def handleFalseUnrelated (select : Select , scrutinee : Type , selector : Type , inMatch : Boolean ) =
71
72
if (inMatch) {
72
73
ctx.error(
73
74
s " will never match since ` ${selector.show}` is not a subclass of ` ${scrutinee.show}` " ,
74
- Position (tree .pos.start - 5 , tree .pos.end - 5 )
75
+ Position (select .pos.start - 5 , select .pos.end - 5 )
75
76
)
76
- rewrite(tree , to = false )
77
+ rewrite(select , to = false )
77
78
} else {
78
79
ctx.warning(
79
80
s " will always yield false since ` ${scrutinee.show}` is not a subclass of ` ${selector.show}` " ,
80
- tree .pos
81
+ select .pos
81
82
)
82
- rewrite(tree , to = false )
83
+ rewrite(select , to = false )
83
84
}
84
85
85
86
/** Rewrites the select to a boolean if `to` is false or if the qualifier
@@ -106,25 +107,30 @@ class IsInstanceOfEvaluator extends MiniPhaseTransform { thisTransformer =>
106
107
val scrutinee = erasure(s.qualifier.tpe.widen)
107
108
val selector = erasure(tree.args.head.tpe.widen)
108
109
109
- val scTrait = scrutinee.typeSymbol is Flags . Trait
110
+ val scTrait = scrutinee.typeSymbol is Trait
110
111
val scClass =
111
112
scrutinee.typeSymbol.isClass &&
112
- ! (scrutinee.typeSymbol is Flags . Trait ) &&
113
- ! (scrutinee.typeSymbol is Flags . Module )
113
+ ! (scrutinee.typeSymbol is Trait ) &&
114
+ ! (scrutinee.typeSymbol is Module )
114
115
115
- val scClassNonFinal = scClass && ! scrutinee.typeSymbol.is( Flags . Final )
116
- val scFinalClass = scClass && (scrutinee.typeSymbol is Flags . Final )
116
+ val scClassNonFinal = scClass && ! ( scrutinee.typeSymbol is Final )
117
+ val scFinalClass = scClass && (scrutinee.typeSymbol is Final )
117
118
118
- val selTrait = selector.typeSymbol is Flags . Trait
119
+ val selTrait = selector.typeSymbol is Trait
119
120
val selClass =
120
121
selector.typeSymbol.isClass &&
121
- ! (selector.typeSymbol is Flags . Trait ) &&
122
- ! (selector.typeSymbol is Flags . Module )
122
+ ! (selector.typeSymbol is Trait ) &&
123
+ ! (selector.typeSymbol is Module )
123
124
124
- val selClassNonFinal = scClass && ! (selector.typeSymbol is Flags . Final )
125
- val selFinalClass = scClass && (selector.typeSymbol is Flags . Final )
125
+ val selClassNonFinal = scClass && ! (selector.typeSymbol is Final )
126
+ val selFinalClass = scClass && (selector.typeSymbol is Final )
126
127
127
128
// Cases ---------------------------------
129
+ val valueClassesOrAny =
130
+ ValueClasses .isDerivedValueClass(scrutinee.typeSymbol) ||
131
+ ValueClasses .isDerivedValueClass(selector.typeSymbol) ||
132
+ scrutinee == defn.ObjectType
133
+
128
134
val knownStatically = scFinalClass
129
135
130
136
val falseIfUnrelated =
@@ -137,13 +143,16 @@ class IsInstanceOfEvaluator extends MiniPhaseTransform { thisTransformer =>
137
143
(scTrait && selClassNonFinal) ||
138
144
(scTrait && selTrait)
139
145
140
- val inMatch = s.qualifier.symbol is Flags . Case
146
+ val inMatch = s.qualifier.symbol is Case
141
147
142
- if (knownStatically)
148
+ if (valueClassesOrAny) tree
149
+ else if (knownStatically)
143
150
handleStaticallyKnown(s, scrutinee, selector, inMatch, tree.pos)
144
151
else if (falseIfUnrelated && scrutinee <:< selector)
152
+ // scrutinee is a subtype of the selector, safe to rewrite
145
153
rewrite(s, to = true )
146
154
else if (falseIfUnrelated && ! (selector <:< scrutinee))
155
+ // selector and scrutinee are unrelated
147
156
handleFalseUnrelated(s, scrutinee, selector, inMatch)
148
157
else if (happens) tree
149
158
else tree
0 commit comments