Skip to content

Commit 02fbd14

Browse files
authored
Merge pull request #10676 from dotty-staging/fix-gadt-lhs-union
Fix gadt lhs union
2 parents 14d4d84 + cd2a20a commit 02fbd14

File tree

2 files changed

+43
-3
lines changed

2 files changed

+43
-3
lines changed

compiler/src/dotty/tools/dotc/core/TypeComparer.scala

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -431,18 +431,25 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
431431
case Some(b) => return b
432432
case None =>
433433

434+
/** `recur` shouldn't normally be used with approximated types, according to its
435+
* documentation. In the specific examples where this function is
436+
* called, it is sound to do so as long as we freeze GADTs.
437+
*/
438+
def recurInFrozenGadt(tp1: Type, tp2: Type) =
439+
inFrozenGadt { recur(tp1, tp2) }
440+
434441
def widenOK =
435442
(tp2.widenSingletons eq tp2)
436443
&& (tp1.widenSingletons ne tp1)
437-
&& recur(tp1.widenSingletons, tp2)
444+
&& recurInFrozenGadt(tp1.widenSingletons, tp2)
438445

439446
def joinOK = tp2.dealiasKeepRefiningAnnots match {
440447
case tp2: AppliedType if !tp2.tycon.typeSymbol.isClass =>
441448
// If we apply the default algorithm for `A[X] | B[Y] <: C[Z]` where `C` is a
442449
// type parameter, we will instantiate `C` to `A` and then fail when comparing
443450
// with `B[Y]`. To do the right thing, we need to instantiate `C` to the
444451
// common superclass of `A` and `B`.
445-
recur(tp1.join, tp2)
452+
recurInFrozenGadt(tp1.join, tp2)
446453
case _ =>
447454
false
448455
}
@@ -469,7 +476,7 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
469476
widenOK
470477
|| joinOK
471478
|| (tp1.isSoft || constrainRHSVars(tp2)) && recur(tp11, tp2) && recur(tp12, tp2)
472-
|| containsAnd(tp1) && recur(tp1.join, tp2)
479+
|| containsAnd(tp1) && recurInFrozenGadt(tp1.join, tp2)
473480
case tp1: MatchType =>
474481
val reduced = tp1.reduced
475482
if (reduced.exists) recur(reduced, tp2) else thirdTry

tests/neg/gadt-lhs-union.scala

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
object A {
2+
sealed trait Expr[+T]
3+
final case class FooExpr() extends Expr[1 | 2]
4+
5+
object Test {
6+
def foo[T](x: Expr[T]): T = x match {
7+
case x: FooExpr =>
8+
3 // error
9+
}
10+
11+
val x: 1 | 2 = foo(FooExpr())
12+
}
13+
}
14+
15+
object B {
16+
trait C
17+
trait D extends C
18+
trait E extends C
19+
trait F extends C
20+
trait G extends C
21+
22+
sealed trait Expr[+T]
23+
final case class FooExpr[+S >: (D & E) | F]() extends Expr[S]
24+
25+
object Test {
26+
def foo[T](x: Expr[T]): T = x match {
27+
case x: FooExpr[(D & E) | F] =>
28+
new D with E
29+
}
30+
31+
val x: (D & E) | F = foo(FooExpr[(D & E) | F]())
32+
}
33+
}

0 commit comments

Comments
 (0)