Skip to content

Commit 9faabb6

Browse files
authored
Merge pull request #12258 from dotty-staging/fix-12226
Store GADT constraints until PostTyper
2 parents 1a625bc + 96fecb0 commit 9faabb6

File tree

3 files changed

+34
-1
lines changed

3 files changed

+34
-1
lines changed

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

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -255,6 +255,13 @@ class PostTyper extends MacroTransform with IdentityDenotTransformer { thisPhase
255255

256256
override def transform(tree: Tree)(using Context): Tree =
257257
try tree match {
258+
case CaseDef(pat, _, _) =>
259+
val gadtCtx =
260+
pat.removeAttachment(typer.Typer.InferredGadtConstraints) match
261+
case Some(gadt) => ctx.fresh.setGadt(gadt)
262+
case None =>
263+
ctx
264+
super.transform(tree)(using gadtCtx)
258265
case tree: Ident if !tree.isType =>
259266
if tree.symbol.is(Inline) && !Inliner.inInlineMethod then
260267
ctx.compilationUnit.needsInlining = true
@@ -437,4 +444,4 @@ class PostTyper extends MacroTransform with IdentityDenotTransformer { thisPhase
437444
private def normalizeErasedRhs(rhs: Tree, sym: Symbol)(using Context) =
438445
if (sym.isEffectivelyErased) dropInlines.transform(rhs) else rhs
439446
}
440-
}
447+
}

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

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,9 @@ object Typer {
6666
if (!tree.isEmpty && !tree.isInstanceOf[untpd.TypedSplice] && ctx.typerState.isGlobalCommittable)
6767
assert(tree.span.exists, i"position not set for $tree # ${tree.uniqueId} of ${tree.getClass} in ${tree.source}")
6868

69+
/** An attachment for GADT constraints that were inferred for a pattern. */
70+
val InferredGadtConstraints = new Property.StickyKey[core.GadtConstraint]
71+
6972
/** A context property that indicates the owner of any expressions to be typed in the context
7073
* if that owner is different from the context's owner. Typically, a context with a class
7174
* as owner would have a local dummy as ExprOwner value.
@@ -1598,6 +1601,13 @@ class Typer extends Namer
15981601
val pat1 = indexPattern(tree).transform(pat)
15991602
val guard1 = typedExpr(tree.guard, defn.BooleanType)
16001603
var body1 = ensureNoLocalRefs(typedExpr(tree.body, pt1), pt1, ctx.scope.toList)
1604+
if ctx.gadt.nonEmpty then
1605+
// Store GADT constraint to later retrieve it (in PostTyper, for now).
1606+
// GADT constraints are necessary to correctly check bounds of type app,
1607+
// see tests/pos/i12226 and issue #12226. It might be possible that this
1608+
// will end up taking too much memory. If it does, we should just limit
1609+
// how much GADT constraints we infer - it's always sound to infer less.
1610+
pat1.putAttachment(InferredGadtConstraints, ctx.gadt)
16011611
if (pt1.isValueType) // insert a cast if body does not conform to expected type if we disregard gadt bounds
16021612
body1 = body1.ensureConforms(pt1)(using originalCtx)
16031613
assignType(cpy.CaseDef(tree)(pat1, guard1, body1), pat1, body1)

tests/pos/i12226.scala

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
object Test extends App {
2+
sealed trait P[T]
3+
case class C1[T <: String](c1: T) extends P[T]
4+
case class C2[T](c2: T) extends P[T]
5+
6+
def test[T](p: P[T], t: T): Unit = p match {
7+
case C1(_) =>
8+
// T <: String
9+
val t : T = ???
10+
val s : String = t
11+
def test = new C1[T](t)
12+
println(1)
13+
14+
case C2(_) => println(2)
15+
}
16+
}

0 commit comments

Comments
 (0)