Skip to content

Commit dea5434

Browse files
committed
fix #3443: typeparam should expose according to variance
1 parent 42577bb commit dea5434

File tree

2 files changed

+40
-19
lines changed

2 files changed

+40
-19
lines changed

compiler/src/dotty/tools/dotc/transform/patmat/Space.scala

Lines changed: 21 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -606,20 +606,19 @@ class SpaceEngine(implicit ctx: Context) extends SpaceLogic {
606606
}
607607
}
608608

609-
val tvars = tp1.typeParams.map { tparam => newTypeVar(tparam.paramInfo.bounds) }
610-
val protoTp1 = thisTypeMap(tp1.appliedTo(tvars))
611-
612-
// replace type parameter references with fresh type vars or bounds
609+
// replace type parameter references with bounds
613610
val typeParamMap = new TypeMap {
614611
def apply(t: Type): Type = t match {
615612

616613
case tp: TypeRef if tp.symbol.is(TypeParam) && tp.underlying.isInstanceOf[TypeBounds] =>
617614
// See tests/patmat/gadt.scala tests/patmat/exhausting.scala
618-
val bound =
619-
if (variance == 0) tp.underlying.bounds // non-variant case is not well-founded
620-
else if (variance == 1) TypeBounds.upper(tp)
621-
else TypeBounds.lower(tp)
622-
newTypeVar(bound)
615+
val exposed =
616+
if (variance == 0) newTypeVar(tp.underlying.bounds)
617+
else if (variance == 1) expose(tp, true)
618+
else expose(tp, false)
619+
620+
debug.println(s"$tp exposed to =====> " + exposed)
621+
exposed
623622
case tp: RefinedType if tp.refinedInfo.isInstanceOf[TypeBounds] =>
624623
// Ideally, we would expect type inference to do the job
625624
// Check tests/patmat/t9657.scala
@@ -629,6 +628,9 @@ class SpaceEngine(implicit ctx: Context) extends SpaceLogic {
629628
}
630629
}
631630

631+
val tvars = tp1.typeParams.map { tparam => newTypeVar(tparam.paramInfo.bounds) }
632+
val protoTp1 = thisTypeMap(tp1.appliedTo(tvars))
633+
632634
if (protoTp1 <:< tp2 && isFullyDefined(protoTp1, ForceDegree.noBottom)) protoTp1
633635
else {
634636
val protoTp2 = typeParamMap(tp2)
@@ -778,41 +780,41 @@ class SpaceEngine(implicit ctx: Context) extends SpaceLogic {
778780
*
779781
* A <: X :> Y B <: U :> V M { type T <: A :> B } ~~> M { type T <: X :> V }
780782
*/
781-
def expose(tp: Type, refineCtx: Boolean = false, up: Boolean = true): Type = tp match {
783+
def expose(tp: Type, up: Boolean = true): Type = tp match {
782784
case tp: AppliedType =>
783-
tp.derivedAppliedType(expose(tp.tycon, refineCtx, up), tp.args.map(expose(_, refineCtx, up)))
785+
tp.derivedAppliedType(expose(tp.tycon, up), tp.args.map(expose(_, up)))
784786

785787
case tp: TypeAlias =>
786-
val hi = expose(tp.alias, refineCtx, up)
787-
val lo = expose(tp.alias, refineCtx, up)
788+
val hi = expose(tp.alias, up)
789+
val lo = expose(tp.alias, up)
788790

789791
if (hi =:= lo)
790792
tp.derivedTypeAlias(hi)
791793
else
792794
tp.derivedTypeBounds(lo, hi)
793795

794796
case tp @ TypeBounds(lo, hi) =>
795-
tp.derivedTypeBounds(expose(lo, refineCtx, false), expose(hi, refineCtx, true))
797+
tp.derivedTypeBounds(expose(lo, false), expose(hi, true))
796798

797799
case tp: RefinedType =>
798800
tp.derivedRefinedType(
799801
expose(tp.parent),
800802
tp.refinedName,
801-
expose(tp.refinedInfo, true, up)
803+
expose(tp.refinedInfo, up)
802804
)
803-
case tp: TypeProxy if refineCtx =>
805+
case tp: TypeProxy =>
804806
tp.underlying match {
805807
case TypeBounds(lo, hi) =>
806-
expose(if (up) hi else lo, refineCtx, up)
808+
expose(if (up) hi else lo, up)
807809
case _ =>
808810
tp
809811
}
810812

811813
case OrType(tp1, tp2) =>
812-
OrType(expose(tp1, refineCtx, up), expose(tp2, refineCtx, up))
814+
OrType(expose(tp1, up), expose(tp2, up))
813815

814816
case AndType(tp1, tp2) =>
815-
AndType(expose(tp1, refineCtx, up), expose(tp2, refineCtx, up))
817+
AndType(expose(tp1, up), expose(tp2, up))
816818

817819
case _ => tp
818820
}

tests/patmat/i3443.scala

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
object Test {
2+
// shapeless.Coproduct
3+
sealed trait Coproduct extends Product with Serializable
4+
sealed trait :+:[+H, +T <: Coproduct] extends Coproduct
5+
final case class Inl[+H, +T <: Coproduct](head : H) extends :+:[H, T]
6+
final case class Inr[+H, +T <: Coproduct](tail : T) extends :+:[H, T]
7+
sealed trait CNil extends Coproduct
8+
9+
// Note that this only appears when T is a type parameter. Replaying T with
10+
// a concrete type (CNil or another :+:) leads to accurate warnnings
11+
def f[T <: Coproduct](fa: Int :+: T) =
12+
fa match {
13+
case Inl(x) => 1
14+
case Inr(x) => 2 // Dotty thinks this unreachable, but it is!
15+
}
16+
17+
def main(args: Array[String]): Unit =
18+
assert(f(Inr(Inl(-1))) == 2) // Example of reachability
19+
}

0 commit comments

Comments
 (0)