Skip to content

Commit 71dbcab

Browse files
authored
Merge pull request #5858 from dotty-staging/fix-5826
Fix #5826: specialize union types to avoid constraint cut
2 parents 482de4e + fe21298 commit 71dbcab

File tree

4 files changed

+50
-8
lines changed

4 files changed

+50
-8
lines changed

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

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -96,17 +96,17 @@ object TypeTestsCasts {
9696
val tvars = constrained(typeLambda, untpd.EmptyTree, alwaysAddTypeVars = true)._2.map(_.tpe)
9797
val P1 = tycon.appliedTo(tvars)
9898

99-
debug.println("P : " + P)
100-
debug.println("P1 : " + P1)
101-
debug.println("X : " + X)
99+
debug.println("P : " + P.show)
100+
debug.println("P1 : " + P1.show)
101+
debug.println("X : " + X.show)
102102

103103
P1 <:< X // constraint P1
104104

105105
// use fromScala2x to avoid generating pattern bound symbols
106106
maximizeType(P1, span, fromScala2x = true)
107107

108108
val res = P1 <:< P
109-
debug.println("P1 : " + P1)
109+
debug.println("P1 : " + P1.show)
110110
debug.println("P1 <:< P = " + res)
111111

112112
res
@@ -122,9 +122,19 @@ object TypeTestsCasts {
122122
case _ => recur(defn.AnyType, tpT)
123123
}
124124
case tpe: AppliedType =>
125-
// first try withou striping type parameters for performance
126-
isClassDetermined(X, tpe)(ctx.fresh.setNewTyperState()) ||
127-
isClassDetermined(stripTypeParam(X), tpe)(ctx.fresh.setNewTyperState())
125+
X.widen match {
126+
case OrType(tp1, tp2) =>
127+
// This case is required to retrofit type inference,
128+
// which cut constraints in the following two cases:
129+
// - T1 <:< T2 | T3
130+
// - T1 & T2 <:< T3
131+
// See TypeComparer#either
132+
recur(tp1, P) && recur(tp2, P)
133+
case _ =>
134+
// first try withou striping type parameters for performance
135+
isClassDetermined(X, tpe)(ctx.fresh.setNewTyperState()) ||
136+
isClassDetermined(stripTypeParam(X), tpe)(ctx.fresh.setNewTyperState())
137+
}
128138
case AndType(tp1, tp2) => recur(X, tp1) && recur(X, tp2)
129139
case OrType(tp1, tp2) => recur(X, tp1) && recur(X, tp2)
130140
case AnnotatedType(t, _) => recur(X, t)

tests/neg-custom-args/isInstanceOf/3324f.scala

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ class D[T]
33

44
class Test {
55
def foo[T](x: C[T]) = x match {
6-
case _: D[T] => // error
6+
case _: D[T] => // error
7+
case _: C[Int] => // error
78
}
89
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
class Foo {
2+
def test[A]: List[Int] | A => Int = {
3+
case ls: List[Int] => ls.head // error
4+
case _ => 0
5+
}
6+
7+
def test2: List[Int] | List[String] => Int = {
8+
case ls: List[Int] => ls.head // error
9+
case _ => 0
10+
}
11+
12+
trait A[T]
13+
trait B[T]
14+
15+
// suppose: class C extends A[Int] with B[String]
16+
def test3[X]: A[X] | B[X] => Int = {
17+
case ls: A[X] => 4 // error
18+
case _ => 0
19+
}
20+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
class Foo {
2+
def test1[A]: List[Int] | A => Int = {
3+
case ls: List[_] => ls.head // error
4+
case _ => 0
5+
}
6+
7+
def test2[A]: List[Int] | A => Int = {
8+
case ls: List[_] => ls.size
9+
case _ => 0
10+
}
11+
}

0 commit comments

Comments
 (0)