Skip to content

Commit b42414e

Browse files
committed
Adapt specification to handle narrowed GADT bounds
1 parent 8124053 commit b42414e

File tree

2 files changed

+32
-4
lines changed

2 files changed

+32
-4
lines changed

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

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -43,11 +43,18 @@ object Checkable {
4343

4444
/** Whether `(x:X).isInstanceOf[P]` can be checked at runtime?
4545
*
46-
* Replace `T @unchecked` and pattern binder types (e.g., `_$1`) in P with WildcardType, then check:
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)
52+
*
53+
* Then check:
4754
*
4855
* 1. if `X <:< P`, TRUE
4956
* 2. if `P` is a singleton type, TRUE
50-
* 3. if `P` refers to an abstract type member or type parameter, `X <:< P`
57+
* 3. if `P` refers to an abstract type member or type parameter, FALSE
5158
* 4. if `P = Array[T]`, checkable(E, T) where `E` is the element type of `X`, defaults to `Any`.
5259
* 5. if `P` is `pre.F[Ts]` and `pre.F` refers to a class which is not `Array`:
5360
* (a) replace `Ts` with fresh type variables `Xs`
@@ -60,7 +67,7 @@ object Checkable {
6067
def checkable(X: Type, P: Type)(implicit ctx: Context): Boolean = {
6168
def isAbstract(P: Type) = !P.dealias.typeSymbol.isClass
6269

63-
def replaceBinderMap(implicit ctx: Context) = new TypeMap {
70+
def replaceP(implicit ctx: Context) = new TypeMap {
6471
def apply(tp: Type) = tp match {
6572
case tref: TypeRef
6673
if !tref.typeSymbol.isClass && tref.symbol.is(Case) => WildcardType
@@ -70,6 +77,17 @@ object Checkable {
7077
}
7178
}
7279

80+
def replaceX(implicit ctx: Context) = new TypeMap {
81+
def apply(tp: Type) = tp match {
82+
case tref: TypeRef
83+
if !tref.typeSymbol.isClass && tref.symbol.is(Case) =>
84+
if (variance == 1) tref.info.hiBound
85+
else if (variance == -1) tref.info.loBound
86+
else OrType(defn.AnyType, defn.NothingType)
87+
case _ => mapOver(tp)
88+
}
89+
}
90+
7391
def isClassDetermined(X: Type, P: AppliedType)(implicit ctx: Context) = {
7492
val AppliedType(tycon, _) = P
7593
val typeLambda = tycon.ensureHK.asInstanceOf[TypeLambda]
@@ -85,6 +103,7 @@ object Checkable {
85103
val res = isFullyDefined(P1, ForceDegree.noBottom) && P1 <:< P
86104
debug.println("P1 : " + P1)
87105
debug.println("P1 <:< P = " + res)
106+
88107
res
89108
}
90109

@@ -105,7 +124,7 @@ object Checkable {
105124
case _ => true
106125
})
107126

108-
val res = recur(X.widen, replaceBinderMap.apply(P))
127+
val res = recur(replaceX.apply(X.widen), replaceP.apply(P))
109128

110129
debug.println(i"checking ${X.show} isInstanceOf ${P} = $res")
111130

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
sealed trait Exp[T]
2+
case class Fun[A, B](f: Exp[A => B]) extends Exp[A => B]
3+
4+
class Test {
5+
def eval[T](e: Exp[T]) = e match {
6+
case Fun(x: Fun[Int, Double]) => ??? // error
7+
case Fun(x: Exp[Int => String]) => ??? // error
8+
}
9+
}

0 commit comments

Comments
 (0)