Skip to content

Commit 84bf2fa

Browse files
authored
Merge pull request #4298 from dotty-staging/fix-4297
Fix #4297: handle type param reference
2 parents 7b91742 + f282783 commit 84bf2fa

File tree

2 files changed

+40
-11
lines changed

2 files changed

+40
-11
lines changed

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

Lines changed: 29 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -67,17 +67,17 @@ object Checkable {
6767
def isAbstract(P: Type) = !P.dealias.typeSymbol.isClass
6868
def isPatternTypeSymbol(sym: Symbol) = !sym.isClass && sym.is(Case)
6969

70-
def replaceP(implicit ctx: Context) = new TypeMap {
70+
def replaceP(tp: Type)(implicit ctx: Context) = new TypeMap {
7171
def apply(tp: Type) = tp match {
7272
case tref: TypeRef
7373
if isPatternTypeSymbol(tref.typeSymbol) => WildcardType
7474
case AnnotatedType(_, annot)
7575
if annot.symbol == defn.UncheckedAnnot => WildcardType
7676
case _ => mapOver(tp)
7777
}
78-
}
78+
}.apply(tp)
7979

80-
def replaceX(implicit ctx: Context) = new TypeMap {
80+
def replaceX(tp: Type)(implicit ctx: Context) = new TypeMap {
8181
def apply(tp: Type) = tp match {
8282
case tref: TypeRef
8383
if isPatternTypeSymbol(tref.typeSymbol) =>
@@ -86,21 +86,36 @@ object Checkable {
8686
else OrType(defn.AnyType, defn.NothingType)
8787
case _ => mapOver(tp)
8888
}
89-
}
89+
}.apply(tp)
90+
91+
/** Approximate type parameters depending on variance */
92+
def stripTypeParam(tp: Type)(implicit ctx: Context) = new ApproximatingTypeMap {
93+
def apply(tp: Type): Type = tp match {
94+
case tp: TypeRef if tp.underlying.isInstanceOf[TypeBounds] =>
95+
val lo = apply(tp.info.loBound)
96+
val hi = apply(tp.info.hiBound)
97+
range(lo, hi)
98+
case _ =>
99+
mapOver(tp)
100+
}
101+
}.apply(tp)
90102

91103
def isClassDetermined(X: Type, P: AppliedType)(implicit ctx: Context) = {
92104
val AppliedType(tycon, _) = P
93105
val typeLambda = tycon.ensureLambdaSub.asInstanceOf[TypeLambda]
94106
val tvars = constrained(typeLambda, untpd.EmptyTree, alwaysAddTypeVars = true)._2.map(_.tpe)
95107
val P1 = tycon.appliedTo(tvars)
96108

97-
debug.println("P : " + P.show)
98-
debug.println("P1 : " + P1.show)
99-
debug.println("X : " + X.show)
109+
debug.println("P : " + P)
110+
debug.println("P1 : " + P1)
111+
debug.println("X : " + X)
112+
113+
P1 <:< X // constraint P1
100114

101-
P1 <:< X // may fail, ignore
115+
// use fromScala2x to avoid generating pattern bound symbols
116+
maximizeType(P1, pos, fromScala2x = true)
102117

103-
val res = isFullyDefined(P1, ForceDegree.noBottom) && P1 <:< P
118+
val res = P1 <:< P
104119
debug.println("P1 : " + P1)
105120
debug.println("P1 <:< P = " + res)
106121

@@ -116,15 +131,18 @@ object Checkable {
116131
case defn.ArrayOf(tpE) => recur(tpE, tpT)
117132
case _ => recur(defn.AnyType, tpT)
118133
}
119-
case tpe: AppliedType => isClassDetermined(X, tpe)(ctx.fresh.setNewTyperState())
134+
case tpe: AppliedType =>
135+
// first try withou striping type parameters for performance
136+
isClassDetermined(X, tpe)(ctx.fresh.setNewTyperState()) ||
137+
isClassDetermined(stripTypeParam(X), tpe)(ctx.fresh.setNewTyperState())
120138
case AndType(tp1, tp2) => recur(X, tp1) && recur(X, tp2)
121139
case OrType(tp1, tp2) => recur(X, tp1) && recur(X, tp2)
122140
case AnnotatedType(t, _) => recur(X, t)
123141
case _: RefinedType => false
124142
case _ => true
125143
})
126144

127-
val res = recur(replaceX.apply(X.widen), replaceP.apply(P))
145+
val res = recur(replaceX(X.widen), replaceP(P))
128146

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

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
class Test {
2+
def test[X <: Option[Int]](x: X) = x.isInstanceOf[Some[Int]]
3+
def test1[Y <: Int, X <: Option[Y]](x: X) = x.isInstanceOf[Some[Int]]
4+
def test2(x: Any) = x.isInstanceOf[Function1[Nothing, _]]
5+
def test3a(x: Any) = x.isInstanceOf[Function1[Any, _]] // error
6+
def test3b(x: Any) = x.isInstanceOf[Function1[Int, _]] // error
7+
def test4[Y <: Int, X <: Function1[Y, Unit]](x: X) = x.isInstanceOf[Function1[Int, _]] // error
8+
def test5[Y <: Int, X <: Function1[Y, Unit]](x: X) = x.isInstanceOf[Function1[Int, Unit]] // error
9+
def test6[Y <: Int, X <: Function1[Y, Unit]](x: X) = x.isInstanceOf[Function1[Int, Any]] // error
10+
def test7[Y <: Int, X <: Function1[Y, Unit]](x: X) = x.isInstanceOf[Function1[_, Unit]]
11+
}

0 commit comments

Comments
 (0)