Skip to content

Commit a6a943f

Browse files
committed
add GADT approximation of the stable type in GADT casting
1 parent 042b7e3 commit a6a943f

File tree

4 files changed

+51
-1
lines changed

4 files changed

+51
-1
lines changed

compiler/src/dotty/tools/dotc/typer/Typer.scala

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3779,7 +3779,13 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
37793779
// The check "safeToInstantiate" in `maximizeType` works to prevent unsound GADT casts.
37803780
val target =
37813781
if tree.tpe.isSingleton then
3782-
val conj = AndType(tree.tpe, pt)
3782+
// In the target type, when the singleton type is intersected, we also intersect
3783+
// the GADT-approximated type of the singleton to avoid the loss of
3784+
// information. See #14776.
3785+
val gadtApprox = Inferencing.approximateGADT(tree.tpe.widen)
3786+
gadts.println(i"gadt approx $wtp ~~~ $gadtApprox")
3787+
val conj =
3788+
AndType(AndType(tree.tpe, gadtApprox), pt)
37833789
if tree.tpe.isStable && !conj.isStable then
37843790
// this is needed for -Ycheck. Without the annotation Ycheck will
37853791
// skolemize the result type which will lead to different types before

tests/pos/gadt-cast-singleton.scala

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
enum SUB[-A, +B]:
2+
case Refl[S]() extends SUB[S, S]
3+
4+
trait R {
5+
type Data
6+
}
7+
trait L extends R
8+
9+
def f(x: L): x.Data = ???
10+
11+
def g[T <: R](x: T, ev: T SUB L): x.Data = ev match
12+
case SUB.Refl() =>
13+
f(x)

tests/pos/i14776-patmat.scala

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
trait T1
2+
trait T2 extends T1
3+
4+
trait Expr[T] { val data: T = ??? }
5+
case class Tag2() extends Expr[T2]
6+
7+
def flag: Boolean = ???
8+
9+
def foo[T](e: Expr[T]): T1 = e match {
10+
case Tag2() =>
11+
flag match
12+
case true => new T2 {}
13+
case false => e.data
14+
}
15+

tests/pos/i14776.scala

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
trait T1
2+
trait T2 extends T1
3+
4+
trait Expr[T] { val data: T = ??? }
5+
case class Tag2() extends Expr[T2]
6+
7+
def flag: Boolean = ???
8+
9+
def foo[T](e: Expr[T]): T1 = e match {
10+
case Tag2() =>
11+
if flag then
12+
new T2 {}
13+
else
14+
e.data
15+
}
16+

0 commit comments

Comments
 (0)