Skip to content

Commit 95193e7

Browse files
committed
refactor GADT cast insertion into a separate method
1 parent a6a943f commit 95193e7

File tree

1 file changed

+39
-23
lines changed

1 file changed

+39
-23
lines changed

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

Lines changed: 39 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1137,7 +1137,8 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
11371137

11381138
def gadtAdaptBranch(tree: Tree, branchPt: Type): Tree =
11391139
TypeComparer.testSubType(tree.tpe.widenExpr, branchPt) match {
1140-
case CompareResult.OKwithGADTUsed => tree.cast(branchPt)
1140+
case CompareResult.OKwithGADTUsed =>
1141+
insertGadtCast(tree, tree.tpe.widen, branchPt)
11411142
case _ => tree
11421143
}
11431144

@@ -1157,8 +1158,10 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
11571158

11581159
val resType = thenp1.tpe | elsep1.tpe
11591160

1160-
val thenp2 = gadtAdaptBranch(thenp1, resType)
1161-
val elsep2 = gadtAdaptBranch(elsep1, resType)
1161+
val thenp2 :: elsep2 :: Nil =
1162+
(thenp1 :: elsep1 :: Nil) map { t =>
1163+
gadtAdaptBranch(t, resType)
1164+
}: @unchecked
11621165

11631166
cpy.If(tree)(cond1, thenp2, elsep2).withType(resType)
11641167

@@ -3775,26 +3778,7 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
37753778
gadts.println(i"unnecessary GADTused for $tree: ${tree.tpe.widenExpr} vs $pt in ${ctx.source}")
37763779
res
37773780
} =>
3778-
// Insert an explicit cast, so that -Ycheck in later phases succeeds.
3779-
// The check "safeToInstantiate" in `maximizeType` works to prevent unsound GADT casts.
3780-
val target =
3781-
if tree.tpe.isSingleton then
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)
3789-
if tree.tpe.isStable && !conj.isStable then
3790-
// this is needed for -Ycheck. Without the annotation Ycheck will
3791-
// skolemize the result type which will lead to different types before
3792-
// and after checking. See i11955.scala.
3793-
AnnotatedType(conj, Annotation(defn.UncheckedStableAnnot))
3794-
else conj
3795-
else pt
3796-
gadts.println(i"insert GADT cast from $tree to $target")
3797-
tree.cast(target)
3781+
insertGadtCast(tree, wtp, pt)
37983782
case _ =>
37993783
//typr.println(i"OK ${tree.tpe}\n${TypeComparer.explained(_.isSubType(tree.tpe, pt))}") // uncomment for unexpected successes
38003784
tree
@@ -4225,4 +4209,36 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
42254209
EmptyTree
42264210
else typedExpr(call, defn.AnyType)
42274211

4212+
/** Insert GADT cast to target type `pt` on the `tree`
4213+
* so that -Ycheck in later phases succeeds.
4214+
* The check "safeToInstantiate" in `maximizeType` works to prevent unsound GADT casts.
4215+
*/
4216+
private def insertGadtCast(tree: Tree, wtp: Type, pt: Type)(using Context): Tree =
4217+
val target =
4218+
if tree.tpe.isSingleton then
4219+
// In the target type, when the singleton type is intersected, we also intersect
4220+
// the GADT-approximated type of the singleton to avoid the loss of
4221+
// information. See #14776.
4222+
val gadtApprox = Inferencing.approximateGADT(wtp)
4223+
gadts.println(i"gadt approx $wtp ~~~ $gadtApprox")
4224+
val conj =
4225+
TypeComparer.testSubType(gadtApprox, pt) match {
4226+
case CompareResult.OK =>
4227+
// GADT approximation of the tree type is a subtype of expected type under empty GADT
4228+
// constraints, so it is enough to only have the GADT approximation.
4229+
AndType(tree.tpe, gadtApprox)
4230+
case _ =>
4231+
// In other cases, we intersect both the approximated type and the expected type.
4232+
AndType(AndType(tree.tpe, gadtApprox), pt)
4233+
}
4234+
if tree.tpe.isStable && !conj.isStable then
4235+
// this is needed for -Ycheck. Without the annotation Ycheck will
4236+
// skolemize the result type which will lead to different types before
4237+
// and after checking. See i11955.scala.
4238+
AnnotatedType(conj, Annotation(defn.UncheckedStableAnnot))
4239+
else conj
4240+
else pt
4241+
gadts.println(i"insert GADT cast from $tree to $target")
4242+
tree.cast(target)
4243+
end insertGadtCast
42284244
}

0 commit comments

Comments
 (0)