@@ -8,7 +8,7 @@ import Contexts.Context, Types._, Decorators._, Symbols._, typer._
8
8
import TypeUtils ._ , Flags ._
9
9
import config .Printers .{ transforms => debug }
10
10
11
- /** check runtime realizability of type test
11
+ /** Check runtime realizability of type test, see the documentation for `Checkable`.
12
12
*/
13
13
class IsInstanceOfChecker extends MiniPhase {
14
14
@@ -20,7 +20,7 @@ class IsInstanceOfChecker extends MiniPhase {
20
20
def ensureCheckable (qual : Tree , pt : Tree ): Tree = {
21
21
if (! Checkable .checkable(qual.tpe, pt.tpe))
22
22
ctx.warning(
23
- s " the type test for ${pt.show } cannot be checked at runtime " ,
23
+ s " the type test for ${pt} cannot be checked at runtime " ,
24
24
tree.pos
25
25
)
26
26
@@ -43,42 +43,60 @@ object Checkable {
43
43
44
44
/** Whether `(x:X).isInstanceOf[P]` can be checked at runtime?
45
45
*
46
- * The following cases are not checkable at runtime:
47
- *
48
- * 1 . if `P` refers to an abstract type member
49
- * 2 . if `P` is `pre.F[Ts]` and `pre.F` refers to a class:
46
+ * 0. if `P` is a singleton type, TRUE
47
+ * 1. if `P` refers to an abstract type member, FALSE
48
+ * 2 . if `P = Array[T]`, checkable(E, T) where `E` is the element type of `X`, defaults to `Any`.
49
+ * 3 . if `P` is `pre.F[Ts]` and `pre.F` refers to a class which is not `Array` :
50
50
* (a) replace `Ts` with fresh type variables `Xs`
51
51
* (b) instantiate `Xs` with the constraint `pre.F[Xs] <:< X`
52
- * (c) `pre.F[Xs] <:< P` doesn't hold
53
- * 3. if `P = T1 | T2` or `P = T1 & T2`, checkable(X, T1) && checkable(X, T2).
52
+ * (c) `pre.F[Xs] <:< P2`, where `P2` is `P` with pattern binder types (e.g., `_$1`)
53
+ * replaced with `WildcardType`.
54
+ * 4. if `P = T1 | T2` or `P = T1 & T2`, checkable(X, T1) && checkable(X, T2).
55
+ * 5. otherwise, TRUE
54
56
*/
55
57
def checkable (X : Type , P : Type )(implicit ctx : Context ): Boolean = {
56
58
def Psym = P .dealias.typeSymbol
57
59
58
60
def isAbstract = ! Psym .isClass
59
61
60
- def isClassDetermined (tpe : AppliedType ) = {
62
+ def replaceBinderMap (implicit ctx : Context ) = new TypeMap {
63
+ def apply (tp : Type ) = tp match {
64
+ case tref : TypeRef if ! tref.typeSymbol.isClass && tref.symbol.is(Case ) => WildcardType
65
+ case _ => mapOver(tp)
66
+ }
67
+ }
68
+
69
+ def isClassDetermined (tpe : AppliedType )(implicit ctx : Context ) = {
61
70
val AppliedType (tycon, args) = tpe
62
71
val tvars = tycon.typeParams.map { tparam => newTypeVar(tparam.paramInfo.bounds) }
63
- val P2 = tycon.appliedTo(tvars)
72
+ val P1 = tycon.appliedTo(tvars)
64
73
65
- debug.println(" P2 : " + P2 )
66
- debug.println(" X : " + X )
74
+ debug.println(" P1 : " + P1 )
75
+ debug.println(" X : " + X .widen )
67
76
68
- ! (P2 <:< X .widen) || {
69
- val syms = maximizeType(P2 , Psym .pos, fromScala2x = false )
70
- val res = P2 <:< P
71
- debug.println(" P2: " + P2 .show)
72
- debug.println(" P2 <:< P = " + res)
77
+ ! (P1 <:< X .widen) || {
78
+ // val syms = maximizeType(P1, Psym.pos, fromScala2x = false)
79
+ isFullyDefined(P1 , ForceDegree .noBottom)
80
+ val P2 = replaceBinderMap.apply(P )
81
+ val res = P1 <:< P2
82
+ debug.println(" P1: " + P1 )
83
+ debug.println(" P2: " + P2 )
84
+ debug.println(" P1 <:< P2 = " + res)
73
85
res
74
86
}
75
87
}
76
88
77
89
P match {
78
- case tpe : AppliedType => ! isAbstract && isClassDetermined(tpe)
79
- case AndType (tp1, tp2) => checkable(X , tp1) && checkable(X , tp2)
80
- case OrType (tp1, tp2) => checkable(X , tp1) && checkable(X , tp2)
81
- case _ => ! isAbstract
90
+ case _ : SingletonType => true
91
+ case defn.ArrayOf (tpT) =>
92
+ X match {
93
+ case defn.ArrayOf (tpE) => checkable(tpE, tpT)
94
+ case _ => checkable(defn.AnyType , tpT)
95
+ }
96
+ case tpe : AppliedType => ! isAbstract && isClassDetermined(tpe)(ctx.fresh.setFreshGADTBounds)
97
+ case AndType (tp1, tp2) => checkable(X , tp1) && checkable(X , tp2)
98
+ case OrType (tp1, tp2) => checkable(X , tp1) && checkable(X , tp2)
99
+ case _ => ! isAbstract
82
100
}
83
101
}
84
- }
102
+ }
0 commit comments