1
1
package dotty .tools .dotc
2
2
package transform
3
3
4
- import TreeTransforms ._
5
- import core .Denotations ._
6
- import core .SymDenotations ._
7
4
import core .Contexts ._
8
5
import core .Symbols ._
9
6
import core .Types ._
10
7
import core .Constants ._
11
8
import core .StdNames ._
12
9
import core .TypeErasure .isUnboundedGeneric
13
- import typer .ErrorReporting ._
14
10
import ast .Trees ._
15
11
import Erasure .Boxing ._
16
12
import core .TypeErasure ._
17
13
import ValueClasses ._
14
+ import core .Decorators ._
15
+ import core .Flags ._
18
16
19
17
/** This transform normalizes type tests and type casts,
20
18
* also replacing type tests with singleton argument type with reference equality check
@@ -80,7 +78,7 @@ trait TypeTestsCasts {
80
78
}
81
79
}
82
80
83
- def transformAsInstanceOf (argType : Type ): Tree = {
81
+ def transformAsInstanceOf (qual : Tree , argType : Type ): Tree = {
84
82
def argCls = argType.widen.classSymbol
85
83
if (qual.tpe <:< argType)
86
84
Typed (qual, tree.args.head)
@@ -92,14 +90,57 @@ trait TypeTestsCasts {
92
90
unbox(qual.ensureConforms(defn.ObjectType ), argType)
93
91
else if (isDerivedValueClass(argCls)) {
94
92
qual // adaptToType in Erasure will do the necessary type adaptation
95
- } else
93
+ }
94
+ else
96
95
derivedTree(qual, defn.Any_asInstanceOf , argType)
97
96
}
98
- def erasedArg = erasure(tree.args.head.tpe)
97
+
98
+ /** Transform isInstanceOf OrType
99
+ *
100
+ * expr.isInstanceOf[A | B] ~~> expr.isInstanceOf[A] | expr.isInstanceOf[B]
101
+ *
102
+ * The transform happens before erasure of `argType`, thus cannot be merged
103
+ * with the transformIsInstanceOf, which depends on erased type of `argType`.
104
+ */
105
+ def transformOrTypeTest (qual : Tree , argType : Type ): Tree = argType match {
106
+ case OrType (tp1, tp2) =>
107
+ evalOnce(qual) { fun =>
108
+ transformOrTypeTest(fun, tp1)
109
+ .select(nme.OR )
110
+ .appliedTo(transformOrTypeTest(fun, tp2))
111
+ }
112
+ case _ =>
113
+ transformIsInstanceOf(qual, erasure(argType))
114
+ }
115
+
116
+ /** Transform asInstanceOf OrType
117
+ *
118
+ * expr.asInstanceOf[A | B] ~~> try expr.asInstanceOf[A] catch {
119
+ * case ex: Throwable => expr.asInstanceOf[B]
120
+ * }
121
+ *
122
+ * The transform happens before erasure of `argType`, thus cannot be merged
123
+ * with the transformAsInstanceOf, which depends on erased type of `argType`.
124
+ */
125
+ def transformOrTypeCast (qual : Tree , argType : Type ): Tree = argType match {
126
+ case OrType (tp1, tp2) =>
127
+ evalOnce(qual) { fun =>
128
+ val exName = ctx.freshName(" ex" ).toTermName
129
+ val exSymbol =
130
+ ctx.newSymbol(ctx.owner, exName, Synthetic | Case , defn.ThrowableType , coord = tree.pos)
131
+
132
+ Try (transformOrTypeCast(fun, tp1),
133
+ List (CaseDef (BindTyped (exSymbol, exSymbol.info), EmptyTree , transformOrTypeCast(fun, tp2))),
134
+ EmptyTree )
135
+ }
136
+ case _ =>
137
+ transformAsInstanceOf(qual, erasure(argType))
138
+ }
139
+
99
140
if (sym eq defn.Any_isInstanceOf )
100
- transformIsInstanceOf (qual, erasedArg )
141
+ transformOrTypeTest (qual, tree.args.head.tpe )
101
142
else if (sym eq defn.Any_asInstanceOf )
102
- transformAsInstanceOf(erasedArg )
143
+ transformOrTypeCast(qual, tree.args.head.tpe )
103
144
else tree
104
145
105
146
case _ =>
0 commit comments