Skip to content

Commit 95d660b

Browse files
committed
Documentation and code cleanups
1 parent d1909db commit 95d660b

File tree

1 file changed

+55
-47
lines changed

1 file changed

+55
-47
lines changed

compiler/src/dotty/tools/dotc/transform/TypeTestsCasts.scala

Lines changed: 55 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)