@@ -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