diff --git a/compiler/src/dotty/tools/dotc/transform/patmat/Space.scala b/compiler/src/dotty/tools/dotc/transform/patmat/Space.scala index c25216e1c7a4..ee17927a2598 100644 --- a/compiler/src/dotty/tools/dotc/transform/patmat/Space.scala +++ b/compiler/src/dotty/tools/dotc/transform/patmat/Space.scala @@ -405,35 +405,22 @@ class SpaceEngine(implicit ctx: Context) extends SpaceLogic { Prod(pat.tpe.stripAnnots, fun.tpe.widen, fun.symbol, pats.map(project), irrefutable(fun)) case Typed(pat @ UnApply(_, _, _), _) => project(pat) case Typed(expr, tpt) => - val unchecked = expr.tpe.hasAnnotation(ctx.definitions.UncheckedAnnot) - def warn(msg: String): Unit = if (!unchecked) ctx.warning(UncheckedTypePattern(msg), tpt.pos) - Typ(erase(expr.tpe.stripAnnots)(warn), true) + Typ(erase(expr.tpe.stripAnnots), true) case _ => debug.println(s"unknown pattern: $pat") Empty } /* Erase a type binding according to erasure semantics in pattern matching */ - def erase(tp: Type)(implicit warn: String => Unit): Type = tp match { + def erase(tp: Type): Type = tp match { case tp @ AppliedType(tycon, args) => if (tycon.isRef(defn.ArrayClass)) tp.derivedAppliedType(tycon, args.map(erase)) - else { - val ignoreWarning = args.forall { p => - p.typeSymbol.is(BindDefinedType) || - p.hasAnnotation(defn.UncheckedAnnot) || - p.isInstanceOf[TypeBounds] - } - if (!ignoreWarning) - warn("type arguments are not checked since they are eliminated by erasure") - - tp.derivedAppliedType(tycon, args.map(t => WildcardType)) - } + else tp.derivedAppliedType(tycon, args.map(t => WildcardType)) case OrType(tp1, tp2) => OrType(erase(tp1), erase(tp2)) case AndType(tp1, tp2) => AndType(erase(tp1), erase(tp2)) case tp: RefinedType => - warn("type refinement is not checked since it is eliminated by erasure") tp.derivedRefinedType(erase(tp.parent), tp.refinedName, WildcardType) case _ => tp } @@ -606,29 +593,27 @@ class SpaceEngine(implicit ctx: Context) extends SpaceLogic { } } - val tvars = tp1.typeParams.map { tparam => newTypeVar(tparam.paramInfo.bounds) } - val protoTp1 = thisTypeMap(tp1.appliedTo(tvars)) - - // replace type parameter references with fresh type vars or bounds + // replace type parameter references with bounds val typeParamMap = new TypeMap { def apply(t: Type): Type = t match { case tp: TypeRef if tp.symbol.is(TypeParam) && tp.underlying.isInstanceOf[TypeBounds] => - // See tests/patmat/gadt.scala tests/patmat/exhausting.scala - val bound = - if (variance == 0) tp.underlying.bounds // non-variant case is not well-founded - else if (variance == 1) TypeBounds.upper(tp) - else TypeBounds.lower(tp) - newTypeVar(bound) - case tp: RefinedType if tp.refinedInfo.isInstanceOf[TypeBounds] => - // Ideally, we would expect type inference to do the job - // Check tests/patmat/t9657.scala - expose(tp) + // See tests/patmat/gadt.scala tests/patmat/exhausting.scala tests/patmat/t9657.scala + val exposed = + if (variance == 0) newTypeVar(tp.underlying.bounds) + else if (variance == 1) mapOver(tp.underlying.hiBound) + else mapOver(tp.underlying.loBound) + + debug.println(s"$tp exposed to =====> $exposed") + exposed case _ => mapOver(t) } } + val tvars = tp1.typeParams.map { tparam => newTypeVar(tparam.paramInfo.bounds) } + val protoTp1 = thisTypeMap(tp1.appliedTo(tvars)) + if (protoTp1 <:< tp2 && isFullyDefined(protoTp1, ForceDegree.noBottom)) protoTp1 else { val protoTp2 = typeParamMap(tp2) @@ -773,51 +758,6 @@ class SpaceEngine(implicit ctx: Context) extends SpaceLogic { res } - - /** Eliminate reference to type parameters in refinements - * - * A <: X :> Y B <: U :> V M { type T <: A :> B } ~~> M { type T <: X :> V } - */ - def expose(tp: Type, refineCtx: Boolean = false, up: Boolean = true): Type = tp match { - case tp: AppliedType => - tp.derivedAppliedType(expose(tp.tycon, refineCtx, up), tp.args.map(expose(_, refineCtx, up))) - - case tp: TypeAlias => - val hi = expose(tp.alias, refineCtx, up) - val lo = expose(tp.alias, refineCtx, up) - - if (hi =:= lo) - tp.derivedTypeAlias(hi) - else - tp.derivedTypeBounds(lo, hi) - - case tp @ TypeBounds(lo, hi) => - tp.derivedTypeBounds(expose(lo, refineCtx, false), expose(hi, refineCtx, true)) - - case tp: RefinedType => - tp.derivedRefinedType( - expose(tp.parent), - tp.refinedName, - expose(tp.refinedInfo, true, up) - ) - case tp: TypeProxy if refineCtx => - tp.underlying match { - case TypeBounds(lo, hi) => - expose(if (up) hi else lo, refineCtx, up) - case _ => - tp - } - - case OrType(tp1, tp2) => - OrType(expose(tp1, refineCtx, up), expose(tp2, refineCtx, up)) - - case AndType(tp1, tp2) => - AndType(expose(tp1, refineCtx, up), expose(tp2, refineCtx, up)) - - case _ => tp - } - - def checkExhaustivity(_match: Match): Unit = { val Match(sel, cases) = _match val selTyp = sel.tpe.widen.dealias diff --git a/tests/patmat/3144.check b/tests/patmat/3144.check deleted file mode 100644 index 207dd36e1d9a..000000000000 --- a/tests/patmat/3144.check +++ /dev/null @@ -1,2 +0,0 @@ -2: Pattern Match Exhaustivity -7: Pattern Match Exhaustivity diff --git a/tests/patmat/3144b.check b/tests/patmat/3144b.check deleted file mode 100644 index d4bd280466da..000000000000 --- a/tests/patmat/3144b.check +++ /dev/null @@ -1,2 +0,0 @@ -4: Pattern Match Exhaustivity -10: Pattern Match Exhaustivity diff --git a/tests/patmat/enum-HList.check b/tests/patmat/enum-HList.check deleted file mode 100644 index 414335be5ea7..000000000000 --- a/tests/patmat/enum-HList.check +++ /dev/null @@ -1 +0,0 @@ -2: Pattern Match Exhaustivity diff --git a/tests/patmat/enum-Tree.check b/tests/patmat/enum-Tree.check deleted file mode 100644 index 84053e20646d..000000000000 --- a/tests/patmat/enum-Tree.check +++ /dev/null @@ -1 +0,0 @@ -8: Pattern Match Exhaustivity \ No newline at end of file diff --git a/tests/patmat/i3443.scala b/tests/patmat/i3443.scala new file mode 100644 index 000000000000..e5cc884cb2a2 --- /dev/null +++ b/tests/patmat/i3443.scala @@ -0,0 +1,19 @@ +object Test { + // shapeless.Coproduct + sealed trait Coproduct extends Product with Serializable + sealed trait :+:[+H, +T <: Coproduct] extends Coproduct + final case class Inl[+H, +T <: Coproduct](head : H) extends :+:[H, T] + final case class Inr[+H, +T <: Coproduct](tail : T) extends :+:[H, T] + sealed trait CNil extends Coproduct + + // Note that this only appears when T is a type parameter. Replaying T with + // a concrete type (CNil or another :+:) leads to accurate warnnings + def f[T <: Coproduct](fa: Int :+: T) = + fa match { + case Inl(x) => 1 + case Inr(x) => 2 // Dotty thinks this unreachable, but it is! + } + + def main(args: Array[String]): Unit = + assert(f(Inr(Inl(-1))) == 2) // Example of reachability +} \ No newline at end of file diff --git a/tests/patmat/t3683.check b/tests/patmat/t3683.check deleted file mode 100644 index 2d090c590d8c..000000000000 --- a/tests/patmat/t3683.check +++ /dev/null @@ -1 +0,0 @@ -7: Pattern Match Exhaustivity \ No newline at end of file diff --git a/tests/patmat/t3683a.check b/tests/patmat/t3683a.check index c39820a1a0be..fdcafc5961b9 100644 --- a/tests/patmat/t3683a.check +++ b/tests/patmat/t3683a.check @@ -1,2 +1 @@ -8: Pattern Match Exhaustivity 14: Pattern Match Exhaustivity: XX()