Skip to content

Commit 7e3765b

Browse files
committed
Extend pattern type constraining to closed hierarchies
1 parent f313d16 commit 7e3765b

File tree

4 files changed

+33
-16
lines changed

4 files changed

+33
-16
lines changed

compiler/src/dotty/tools/dotc/core/Flags.scala

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -552,6 +552,8 @@ object Flags {
552552
val JavaOrPrivateOrSynthetic: FlagSet = Artifact | JavaDefined | Private | Synthetic
553553
val PrivateOrSynthetic: FlagSet = Artifact | Private | Synthetic
554554
val EnumCase: FlagSet = Case | Enum
555+
val CaseOrFinalOrSealed: FlagSet = Case | Final | Sealed
556+
val CaseOrSealed: FlagSet = Case | Sealed
555557
val CovariantLocal: FlagSet = Covariant | Local // A covariant type parameter
556558
val ContravariantLocal: FlagSet = Contravariant | Local // A contravariant type parameter
557559
val EffectivelyErased = ConstructorProxy | Erased

compiler/src/dotty/tools/dotc/core/PatternTypeConstrainer.scala

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -233,21 +233,11 @@ trait PatternTypeConstrainer { self: TypeComparer =>
233233
def constrainSimplePatternType(patternTp: Type, scrutineeTp: Type, forceInvariantRefinement: Boolean): Boolean = {
234234
def refinementIsInvariant(tp: Type): Boolean = tp match {
235235
case tp: SingletonType => true
236-
case tp: ClassInfo => tp.cls.is(Final) || tp.cls.is(Case)
236+
case tp: ClassInfo => tp.cls.isOneOf(CaseOrFinalOrSealed)
237237
case tp: TypeProxy => refinementIsInvariant(tp.superType)
238238
case _ => false
239239
}
240240

241-
def widenVariantParams(tp: Type) = tp match {
242-
case tp @ AppliedType(tycon, args) =>
243-
val args1 = args.zipWithConserve(tycon.typeParams)((arg, tparam) =>
244-
if (tparam.paramVarianceSign != 0) TypeBounds.empty else arg
245-
)
246-
tp.derivedAppliedType(tycon, args1)
247-
case tp =>
248-
tp
249-
}
250-
251241
val patternCls = patternTp.classSymbol
252242
val scrutineeCls = scrutineeTp.classSymbol
253243

compiler/src/dotty/tools/dotc/typer/RefChecks.scala

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -807,11 +807,15 @@ object RefChecks {
807807
* can assume invariant refinement for case classes in `constrainPatternType`.
808808
*/
809809
def checkCaseClassInheritanceInvariant() =
810-
for (caseCls <- clazz.info.baseClasses.tail.find(_.is(Case)))
811-
for (baseCls <- caseCls.info.baseClasses.tail)
812-
if (baseCls.typeParams.exists(_.paramVarianceSign != 0))
813-
for (problem <- variantInheritanceProblems(baseCls, caseCls, "non-variant", "case "))
814-
report.errorOrMigrationWarning(problem, clazz.srcPos, from = `3.0`)
810+
for
811+
middle <- clazz.info.baseClasses.tail
812+
if middle.isOneOf(CaseOrSealed)
813+
baseCls <- middle.info.baseClasses.tail
814+
if baseCls.typeParams.exists(_.paramVarianceSign != 0)
815+
middleStr = if middle.is(Case) then "case " else if middle.is(Sealed) then "sealed " else ""
816+
problem <- variantInheritanceProblems(baseCls, middle, "non-variant", middleStr)
817+
do
818+
report.errorOrMigrationWarning(problem, clazz.srcPos, from = `3.0`)
815819
checkNoAbstractMembers()
816820
if (abstractErrors.isEmpty)
817821
checkNoAbstractDecls(clazz)

tests/pos/i4790.scala

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
class Test:
2+
def foo(as: Seq[Int]) =
3+
val List(_, bs: _*) = as: @unchecked
4+
val cs: Seq[Int] = bs
5+
6+
class Test2:
7+
def foo(as: SSeq[Int]) =
8+
val LList(_, tail) = as: @unchecked
9+
val cs: SSeq[Int] = tail
10+
11+
trait SSeq[+A]
12+
sealed trait LList[+A] extends SSeq[A]
13+
final case class CCons[+A](head: A, tail: LList[A]) extends LList[A]
14+
case object NNil extends LList[Nothing]
15+
object LList:
16+
def unapply[A](xs: LList[A]): Extractor[A] = Extractor[A](xs)
17+
final class Extractor[A](private val xs: LList[A]) extends AnyVal:
18+
def get: this.type = this
19+
def isEmpty: Boolean = xs.isInstanceOf[CCons[?]]
20+
def _1: A = xs.asInstanceOf[CCons[A]].head
21+
def _2: SSeq[A] = xs.asInstanceOf[CCons[A]].tail

0 commit comments

Comments
 (0)