@@ -1137,7 +1137,8 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
1137
1137
1138
1138
def gadtAdaptBranch (tree : Tree , branchPt : Type ): Tree =
1139
1139
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)
1141
1142
case _ => tree
1142
1143
}
1143
1144
@@ -1157,8 +1158,10 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
1157
1158
1158
1159
val resType = thenp1.tpe | elsep1.tpe
1159
1160
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
1162
1165
1163
1166
cpy.If (tree)(cond1, thenp2, elsep2).withType(resType)
1164
1167
@@ -3775,28 +3778,7 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
3775
3778
gadts.println(i " unnecessary GADTused for $tree: ${tree.tpe.widenExpr} vs $pt in ${ctx.source}" )
3776
3779
res
3777
3780
} =>
3778
- // Insert an explicit cast, so that -Ycheck in later phases succeeds.
3779
- // I suspect, but am not 100% sure that this might affect inferred types,
3780
- // if the expected type is a supertype of the GADT bound. It would be good to come
3781
- // up with a test case for this.
3782
- val target =
3783
- if tree.tpe.isSingleton then
3784
- // In the target type, when the singleton type is intersected, we also intersect
3785
- // the GADT-approximated type of the singleton to avoid the loss of
3786
- // information. See #14776.
3787
- val gadtApprox = Inferencing .approximateGADT(tree.tpe.widen)
3788
- gadts.println(i " gadt approx $wtp ~~~ $gadtApprox" )
3789
- val conj =
3790
- AndType (AndType (tree.tpe, gadtApprox), pt)
3791
- if tree.tpe.isStable && ! conj.isStable then
3792
- // this is needed for -Ycheck. Without the annotation Ycheck will
3793
- // skolemize the result type which will lead to different types before
3794
- // and after checking. See i11955.scala.
3795
- AnnotatedType (conj, Annotation (defn.UncheckedStableAnnot ))
3796
- else conj
3797
- else pt
3798
- gadts.println(i " insert GADT cast from $tree to $target" )
3799
- tree.cast(target)
3781
+ insertGadtCast(tree, wtp, pt)
3800
3782
case _ =>
3801
3783
// typr.println(i"OK ${tree.tpe}\n${TypeComparer.explained(_.isSubType(tree.tpe, pt))}") // uncomment for unexpected successes
3802
3784
tree
@@ -4227,4 +4209,38 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
4227
4209
EmptyTree
4228
4210
else typedExpr(call, defn.AnyType )
4229
4211
4212
+ /** Insert GADT cast to target type `pt` on the `tree`
4213
+ * so that -Ycheck in later phases succeeds.
4214
+ * I suspect, but am not 100% sure that this might affect inferred types,
4215
+ * if the expected type is a supertype of the GADT bound. It would be good to come
4216
+ * up with a test case for this.
4217
+ */
4218
+ private def insertGadtCast (tree : Tree , wtp : Type , pt : Type )(using Context ): Tree =
4219
+ val target =
4220
+ if tree.tpe.isSingleton then
4221
+ // In the target type, when the singleton type is intersected, we also intersect
4222
+ // the GADT-approximated type of the singleton to avoid the loss of
4223
+ // information. See #14776.
4224
+ val gadtApprox = Inferencing .approximateGADT(wtp)
4225
+ gadts.println(i " gadt approx $wtp ~~~ $gadtApprox" )
4226
+ val conj =
4227
+ TypeComparer .testSubType(gadtApprox, pt) match {
4228
+ case CompareResult .OK =>
4229
+ // GADT approximation of the tree type is a subtype of expected type under empty GADT
4230
+ // constraints, so it is enough to only have the GADT approximation.
4231
+ AndType (tree.tpe, gadtApprox)
4232
+ case _ =>
4233
+ // In other cases, we intersect both the approximated type and the expected type.
4234
+ AndType (AndType (tree.tpe, gadtApprox), pt)
4235
+ }
4236
+ if tree.tpe.isStable && ! conj.isStable then
4237
+ // this is needed for -Ycheck. Without the annotation Ycheck will
4238
+ // skolemize the result type which will lead to different types before
4239
+ // and after checking. See i11955.scala.
4240
+ AnnotatedType (conj, Annotation (defn.UncheckedStableAnnot ))
4241
+ else conj
4242
+ else pt
4243
+ gadts.println(i " insert GADT cast from $tree to $target" )
4244
+ tree.cast(target)
4245
+ end insertGadtCast
4230
4246
}
0 commit comments