Skip to content

Commit 27be4f2

Browse files
committed
Handle sealed prefixes in exh checking
1 parent 805dda8 commit 27be4f2

File tree

3 files changed

+47
-3
lines changed

3 files changed

+47
-3
lines changed

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

+12-2
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import ast.tpd._
1313
import reporting.trace
1414
import config.Printers.typr
1515
import config.Feature
16+
import transform.SymUtils.*
1617
import typer.ProtoTypes._
1718
import typer.ForceDegree
1819
import typer.Inferencing._
@@ -846,14 +847,23 @@ object TypeOps:
846847
var prefixTVar: Type | Null = null
847848
def apply(tp: Type): Type = tp match {
848849
case ThisType(tref: TypeRef) if !tref.symbol.isStaticOwner =>
850+
val symbol = tref.symbol
849851
if (tref.symbol.is(Module))
850852
TermRef(this(tref.prefix), tref.symbol.sourceModule)
851853
else if (prefixTVar != null)
852854
this(tref)
853855
else {
854856
prefixTVar = WildcardType // prevent recursive call from assigning it
855-
val tref2 = this(tref.applyIfParameterized(tref.typeParams.map(_ => TypeBounds.empty)))
856-
prefixTVar = newTypeVar(TypeBounds.upper(tref2))
857+
prefixTVar = if symbol.is(Sealed) && symbol.isOneOf(AbstractOrTrait) && symbol.children.sizeIs > 0 && !symbol.hasAnonymousChild then
858+
symbol.children.foldLeft(WildcardType: Type) { (acc, c) =>
859+
val tp = this(c.appliedRef) match
860+
case tp: TypeRef if tp.symbol.is(ModuleVal) => tp.symbol.moduleClass.denot.thisType
861+
case tp => tp
862+
acc | tp
863+
}
864+
else
865+
val tref2 = this(tref.applyIfParameterized(tref.typeParams.map(_ => TypeBounds.empty)))
866+
newTypeVar(TypeBounds.upper(tref2))
857867
prefixTVar.uncheckedNN
858868
}
859869
case tp => mapOver(tp)

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

+10-1
Original file line numberDiff line numberDiff line change
@@ -628,6 +628,13 @@ class SpaceEngine(using Context) extends SpaceLogic {
628628
Typ(ConstantType(Constant(())), true) :: Nil
629629
case tp if tp.classSymbol.isAllOf(JavaEnumTrait) =>
630630
tp.classSymbol.children.map(sym => Typ(sym.termRef, true))
631+
632+
case tp @ AppliedType(tycon, targs) if tp.classSymbol.children.isEmpty && canDecompose(tycon) =>
633+
rec(tycon, Nil).map(typ => Typ(tp.derivedAppliedType(typ.tp, targs)))
634+
635+
case tp: NamedType if canDecompose(tp.prefix) =>
636+
rec(tp.prefix, Nil).map(typ => Typ(tp.derivedSelect(typ.tp)))
637+
631638
case tp =>
632639
def getChildren(sym: Symbol): List[Symbol] =
633640
sym.children.flatMap { child =>
@@ -669,9 +676,11 @@ class SpaceEngine(using Context) extends SpaceLogic {
669676
/** Abstract sealed types, or-types, Boolean and Java enums can be decomposed */
670677
def canDecompose(tp: Type): Boolean =
671678
val res = tp.dealias match
679+
case AppliedType(tycon, _) if canDecompose(tycon) => true
680+
case tp: NamedType if canDecompose(tp.prefix) => true
672681
case _: SingletonType => false
673682
case _: OrType => true
674-
case and: AndType => canDecompose(and.tp1) || canDecompose(and.tp2)
683+
case AndType(tp1, tp2) if canDecompose(tp1) || canDecompose(tp2) => true
675684
case _ =>
676685
val cls = tp.classSymbol
677686
cls.is(Sealed)

tests/pos/i15029.scala

+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
// scalac: -Werror
2+
sealed trait Schema[A]
3+
4+
sealed trait RecordInstances:
5+
case class Field[B]() extends Schema[B]
6+
case object Thing extends Schema[Int]
7+
8+
object X extends RecordInstances
9+
object Y extends RecordInstances
10+
11+
// Match not exhaustive error! (with fatal warnings :P)
12+
class Test:
13+
def handle[T](schema: Schema[T]) =
14+
schema match // was: match may not be exhaustive
15+
case X.Field() =>
16+
case X.Thing =>
17+
case Y.Field() =>
18+
case Y.Thing =>
19+
20+
def t(a: Boolean, b: Boolean) =
21+
(a, b) match
22+
case (false, false) => 1
23+
case (false, true ) => 2
24+
case (true, false) => 3
25+
case (true, true ) => 4

0 commit comments

Comments
 (0)