Skip to content

Commit 6dab4c2

Browse files
authored
Merge pull request #3446 from dotty-staging/fix-3443
Fix #3443: adapt child compatibility check
2 parents ed2feb2 + 253f505 commit 6dab4c2

File tree

8 files changed

+34
-83
lines changed

8 files changed

+34
-83
lines changed

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

Lines changed: 15 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -405,35 +405,22 @@ class SpaceEngine(implicit ctx: Context) extends SpaceLogic {
405405
Prod(pat.tpe.stripAnnots, fun.tpe.widen, fun.symbol, pats.map(project), irrefutable(fun))
406406
case Typed(pat @ UnApply(_, _, _), _) => project(pat)
407407
case Typed(expr, tpt) =>
408-
val unchecked = expr.tpe.hasAnnotation(ctx.definitions.UncheckedAnnot)
409-
def warn(msg: String): Unit = if (!unchecked) ctx.warning(UncheckedTypePattern(msg), tpt.pos)
410-
Typ(erase(expr.tpe.stripAnnots)(warn), true)
408+
Typ(erase(expr.tpe.stripAnnots), true)
411409
case _ =>
412410
debug.println(s"unknown pattern: $pat")
413411
Empty
414412
}
415413

416414
/* Erase a type binding according to erasure semantics in pattern matching */
417-
def erase(tp: Type)(implicit warn: String => Unit): Type = tp match {
415+
def erase(tp: Type): Type = tp match {
418416
case tp @ AppliedType(tycon, args) =>
419417
if (tycon.isRef(defn.ArrayClass)) tp.derivedAppliedType(tycon, args.map(erase))
420-
else {
421-
val ignoreWarning = args.forall { p =>
422-
p.typeSymbol.is(BindDefinedType) ||
423-
p.hasAnnotation(defn.UncheckedAnnot) ||
424-
p.isInstanceOf[TypeBounds]
425-
}
426-
if (!ignoreWarning)
427-
warn("type arguments are not checked since they are eliminated by erasure")
428-
429-
tp.derivedAppliedType(tycon, args.map(t => WildcardType))
430-
}
418+
else tp.derivedAppliedType(tycon, args.map(t => WildcardType))
431419
case OrType(tp1, tp2) =>
432420
OrType(erase(tp1), erase(tp2))
433421
case AndType(tp1, tp2) =>
434422
AndType(erase(tp1), erase(tp2))
435423
case tp: RefinedType =>
436-
warn("type refinement is not checked since it is eliminated by erasure")
437424
tp.derivedRefinedType(erase(tp.parent), tp.refinedName, WildcardType)
438425
case _ => tp
439426
}
@@ -606,29 +593,27 @@ class SpaceEngine(implicit ctx: Context) extends SpaceLogic {
606593
}
607594
}
608595

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
596+
// replace type parameter references with bounds
613597
val typeParamMap = new TypeMap {
614598
def apply(t: Type): Type = t match {
615599

616600
case tp: TypeRef if tp.symbol.is(TypeParam) && tp.underlying.isInstanceOf[TypeBounds] =>
617-
// 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)
623-
case tp: RefinedType if tp.refinedInfo.isInstanceOf[TypeBounds] =>
624-
// Ideally, we would expect type inference to do the job
625-
// Check tests/patmat/t9657.scala
626-
expose(tp)
601+
// See tests/patmat/gadt.scala tests/patmat/exhausting.scala tests/patmat/t9657.scala
602+
val exposed =
603+
if (variance == 0) newTypeVar(tp.underlying.bounds)
604+
else if (variance == 1) mapOver(tp.underlying.hiBound)
605+
else mapOver(tp.underlying.loBound)
606+
607+
debug.println(s"$tp exposed to =====> $exposed")
608+
exposed
627609
case _ =>
628610
mapOver(t)
629611
}
630612
}
631613

614+
val tvars = tp1.typeParams.map { tparam => newTypeVar(tparam.paramInfo.bounds) }
615+
val protoTp1 = thisTypeMap(tp1.appliedTo(tvars))
616+
632617
if (protoTp1 <:< tp2 && isFullyDefined(protoTp1, ForceDegree.noBottom)) protoTp1
633618
else {
634619
val protoTp2 = typeParamMap(tp2)
@@ -773,51 +758,6 @@ class SpaceEngine(implicit ctx: Context) extends SpaceLogic {
773758
res
774759
}
775760

776-
777-
/** Eliminate reference to type parameters in refinements
778-
*
779-
* A <: X :> Y B <: U :> V M { type T <: A :> B } ~~> M { type T <: X :> V }
780-
*/
781-
def expose(tp: Type, refineCtx: Boolean = false, up: Boolean = true): Type = tp match {
782-
case tp: AppliedType =>
783-
tp.derivedAppliedType(expose(tp.tycon, refineCtx, up), tp.args.map(expose(_, refineCtx, up)))
784-
785-
case tp: TypeAlias =>
786-
val hi = expose(tp.alias, refineCtx, up)
787-
val lo = expose(tp.alias, refineCtx, up)
788-
789-
if (hi =:= lo)
790-
tp.derivedTypeAlias(hi)
791-
else
792-
tp.derivedTypeBounds(lo, hi)
793-
794-
case tp @ TypeBounds(lo, hi) =>
795-
tp.derivedTypeBounds(expose(lo, refineCtx, false), expose(hi, refineCtx, true))
796-
797-
case tp: RefinedType =>
798-
tp.derivedRefinedType(
799-
expose(tp.parent),
800-
tp.refinedName,
801-
expose(tp.refinedInfo, true, up)
802-
)
803-
case tp: TypeProxy if refineCtx =>
804-
tp.underlying match {
805-
case TypeBounds(lo, hi) =>
806-
expose(if (up) hi else lo, refineCtx, up)
807-
case _ =>
808-
tp
809-
}
810-
811-
case OrType(tp1, tp2) =>
812-
OrType(expose(tp1, refineCtx, up), expose(tp2, refineCtx, up))
813-
814-
case AndType(tp1, tp2) =>
815-
AndType(expose(tp1, refineCtx, up), expose(tp2, refineCtx, up))
816-
817-
case _ => tp
818-
}
819-
820-
821761
def checkExhaustivity(_match: Match): Unit = {
822762
val Match(sel, cases) = _match
823763
val selTyp = sel.tpe.widen.dealias

tests/patmat/3144.check

Lines changed: 0 additions & 2 deletions
This file was deleted.

tests/patmat/3144b.check

Lines changed: 0 additions & 2 deletions
This file was deleted.

tests/patmat/enum-HList.check

Lines changed: 0 additions & 1 deletion
This file was deleted.

tests/patmat/enum-Tree.check

Lines changed: 0 additions & 1 deletion
This file was deleted.

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+
}

tests/patmat/t3683.check

Lines changed: 0 additions & 1 deletion
This file was deleted.

tests/patmat/t3683a.check

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1 @@
1-
8: Pattern Match Exhaustivity
21
14: Pattern Match Exhaustivity: XX()

0 commit comments

Comments
 (0)