@@ -4,9 +4,10 @@ package transform
44import util .Positions ._
55import MegaPhase .MiniPhase
66import core ._
7- import Contexts .Context , Types ._ , Decorators ._ , Symbols ._ , typer ._ , ast ._
7+ import Contexts .Context , Types ._ , Decorators ._ , Symbols ._ , typer ._ , ast ._ , NameKinds . _ , StdNames . _
88import TypeUtils ._ , Flags ._
99import config .Printers .{ transforms => debug }
10+ import collection .mutable .Map
1011
1112/** Check runtime realizability of type test, see the documentation for `Checkable`.
1213 */
@@ -16,9 +17,24 @@ class IsInstanceOfChecker extends MiniPhase {
1617
1718 val phaseName = " isInstanceOfChecker"
1819
19- override def transformTypeApply (tree : TypeApply )(implicit ctx : Context ): Tree = {
20+ override def transformTemplate (tree : Template )(implicit ctx : Context ): Tree = {
21+ // remap to cancel effect of GADT narrowing
22+ val binders = Map .empty[Symbol , Symbol ]
23+
24+ new TreeTraverser () {
25+ override def traverse (tree : Tree )(implicit ctx : Context ): Unit =
26+ tree match {
27+ case t : TypeApply => checkInstanceOf(t, binders)
28+ case _ => traverseChildren(tree)
29+ }
30+ }.traverse(tree)
31+
32+ tree
33+ }
34+
35+ def checkInstanceOf (tree : TypeApply , binders : Map [Symbol , Symbol ])(implicit ctx : Context ): Tree = {
2036 def ensureCheckable (qual : Tree , pt : Tree ): Tree = {
21- if (! Checkable .checkable(qual.tpe, pt.tpe))
37+ if (! Checkable .checkable(qual.tpe, pt.tpe, binders, tree.pos ))
2238 ctx.warning(
2339 s " the type test for ${pt.show} cannot be checked at runtime " ,
2440 tree.pos
@@ -43,12 +59,7 @@ object Checkable {
4359
4460 /** Whether `(x:X).isInstanceOf[P]` can be checked at runtime?
4561 *
46- * First do the following substitution:
47- * (a) replace `T @unchecked` and pattern binder types (e.g., `_$1`) in P with WildcardType
48- * (b) replace pattern binder types (e.g., `_$1`) in X:
49- * - variance = 1 : hiBound
50- * - variance = -1 : loBound
51- * - variance = 0 : OrType(Any, Nothing) // TODO: use original type param bounds
62+ * First cancel the effect of GADT bound narrowing with the map `binders`.
5263 *
5364 * Then check:
5465 *
@@ -58,13 +69,14 @@ object Checkable {
5869 * 4. if `P = Array[T]`, checkable(E, T) where `E` is the element type of `X`, defaults to `Any`.
5970 * 5. if `P` is `pre.F[Ts]` and `pre.F` refers to a class which is not `Array`:
6071 * (a) replace `Ts` with fresh type variables `Xs`
61- * (b) constrain `Xs` with `pre.F[Xs] <:< X` (may fail)
72+ * (b) constrain `Xs` with `pre.F[Xs] <:< X`,
73+ * if `X` cannot be uniquely determined, instantiate `X` with fresh type symbol.
6274 * (c) instantiate Xs and check `pre.F[Xs] <:< P`
6375 * 6. if `P = T1 | T2` or `P = T1 & T2`, checkable(X, T1) && checkable(X, T2).
6476 * 7. if `P` is a refinement type, FALSE
6577 * 8. otherwise, TRUE
6678 */
67- def checkable (X : Type , P : Type )(implicit ctx : Context ): Boolean = {
79+ def checkable (X : Type , P : Type , binders : Map [ Symbol , Symbol ], pos : Position )(implicit ctx : Context ): Boolean = {
6880 def isAbstract (P : Type ) = ! P .dealias.typeSymbol.isClass
6981
7082 def replaceP (implicit ctx : Context ) = new TypeMap {
@@ -88,6 +100,40 @@ object Checkable {
88100 }
89101 }
90102
103+ def replace (implicit ctx : Context ) = new TypeMap {
104+ def mapTypeBoundSymbol (tp : Type , paramInfo : Type ): Type = tp match {
105+ case tref : TypeRef
106+ if ! tref.typeSymbol.isClass && tref.symbol.is(Case ) =>
107+ if (binders.contains(tref.typeSymbol))
108+ binders(tref.typeSymbol).typeRef
109+ else if (tref.typeSymbol.name == tpnme.WILDCARD )
110+ WildcardType
111+ else {
112+ val fresh = ctx.newSymbol(ctx.owner, WildcardParamName .fresh().toTypeName, Case , paramInfo.bounds, coord = pos)
113+ binders(tref.typeSymbol) = fresh
114+ WildcardType (paramInfo.bounds)
115+ }
116+ case _ =>
117+ apply(tp)
118+ }
119+
120+ def apply (tp : Type ) = tp match {
121+ case tapp @ AppliedType (tycon, args) =>
122+ val args2 = args.zip(tycon.typeParams).map { case (arg, paramInfo) => mapTypeBoundSymbol(arg, paramInfo.paramInfo) }
123+ tycon.appliedTo(args2)
124+ case tref : TypeRef if ! tref.typeSymbol.isClass && tref.symbol.is(Case ) =>
125+ if (binders.contains(tref.typeSymbol))
126+ binders(tref.typeSymbol).typeRef
127+ else
128+ // annotation for Array[_] could reach here
129+ tref
130+ case AnnotatedType (_, annot) if annot.symbol == defn.UncheckedAnnot =>
131+ WildcardType
132+ case _ =>
133+ mapOver(tp)
134+ }
135+ }
136+
91137 def isClassDetermined (X : Type , P : AppliedType )(implicit ctx : Context ) = {
92138 val AppliedType (tycon, _) = P
93139 val typeLambda = tycon.ensureHK.asInstanceOf [TypeLambda ]
@@ -100,7 +146,17 @@ object Checkable {
100146
101147 P1 <:< X // may fail, ignore
102148
103- val res = isFullyDefined(P1 , ForceDegree .noBottom) && P1 <:< P
149+ tvars.foreach { case tvar : TypeVar =>
150+ val bounds = ctx.typerState.constraint.entry(tvar.origin)
151+ if (bounds.loBound =:= bounds.hiBound)
152+ tvar.instantiateWith(bounds.loBound)
153+ else {
154+ val wildCard = ctx.newSymbol(ctx.owner, WildcardParamName .fresh().toTypeName, Case , tvar.origin.underlying, coord = pos)
155+ tvar.instantiateWith(wildCard.typeRef)
156+ }
157+ }
158+
159+ val res = P1 <:< P
104160 debug.println(" P1 : " + P1 )
105161 debug.println(" P1 <:< P = " + res)
106162
@@ -119,12 +175,20 @@ object Checkable {
119175 case tpe : AppliedType => isClassDetermined(X , tpe)(ctx.fresh.setNewTyperState())
120176 case AndType (tp1, tp2) => recur(X , tp1) && recur(X , tp2)
121177 case OrType (tp1, tp2) => recur(X , tp1) && recur(X , tp2)
122- case AnnotatedType (t, an) => recur(X , t)
178+ case AnnotatedType (t, _) => recur(X , t)
123179 case _ : RefinedType => false
124180 case _ => true
125181 })
126182
127- val res = recur(replaceX.apply(X .widen), replaceP.apply(P ))
183+ debug.println(s " $X <: $P" )
184+
185+ val X1 = replace.apply(X .widen)
186+ val P1 = replace.apply(P )
187+
188+ debug.println(s " $X ~~> $X1" )
189+ debug.println(s " $P ~~> $P1" )
190+
191+ val res = recur(X1 , P1 )
128192
129193 debug.println(i " checking ${X .show} isInstanceOf ${P } = $res" )
130194
0 commit comments