Skip to content

Commit

Permalink
Handle sealed prefixes in exh checking
Browse files Browse the repository at this point in the history
  • Loading branch information
dwijnand committed Jan 5, 2023
1 parent 805dda8 commit 96653a9
Show file tree
Hide file tree
Showing 3 changed files with 39 additions and 2 deletions.
14 changes: 12 additions & 2 deletions compiler/src/dotty/tools/dotc/core/TypeOps.scala
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import ast.tpd._
import reporting.trace
import config.Printers.typr
import config.Feature
import transform.SymUtils.*
import typer.ProtoTypes._
import typer.ForceDegree
import typer.Inferencing._
Expand Down Expand Up @@ -846,14 +847,23 @@ object TypeOps:
var prefixTVar: Type | Null = null
def apply(tp: Type): Type = tp match {
case ThisType(tref: TypeRef) if !tref.symbol.isStaticOwner =>
val symbol = tref.symbol
if (tref.symbol.is(Module))
TermRef(this(tref.prefix), tref.symbol.sourceModule)
else if (prefixTVar != null)
this(tref)
else {
prefixTVar = WildcardType // prevent recursive call from assigning it
val tref2 = this(tref.applyIfParameterized(tref.typeParams.map(_ => TypeBounds.empty)))
prefixTVar = newTypeVar(TypeBounds.upper(tref2))
prefixTVar = if symbol.is(Sealed) && symbol.isOneOf(AbstractOrTrait) && symbol.children.sizeIs > 0 && !symbol.hasAnonymousChild then
symbol.children.foldLeft(WildcardType: Type) { (acc, c) =>
val tp = this (c.appliedRef) match
case tp: TypeRef if tp.symbol.is(ModuleVal) => tp.symbol.moduleClass.denot.thisType
case tp => tp
acc | tp
}
else
val tref2 = this(tref.applyIfParameterized(tref.typeParams.map(_ => TypeBounds.empty)))
newTypeVar(TypeBounds.upper(tref2))
prefixTVar.uncheckedNN
}
case tp => mapOver(tp)
Expand Down
9 changes: 9 additions & 0 deletions compiler/src/dotty/tools/dotc/transform/patmat/Space.scala
Original file line number Diff line number Diff line change
Expand Up @@ -628,6 +628,13 @@ class SpaceEngine(using Context) extends SpaceLogic {
Typ(ConstantType(Constant(())), true) :: Nil
case tp if tp.classSymbol.isAllOf(JavaEnumTrait) =>
tp.classSymbol.children.map(sym => Typ(sym.termRef, true))

case tp @ AppliedType(tycon, targs) if tp.classSymbol.children.isEmpty && canDecompose(tycon) =>
rec(tycon, Nil).map(typ => Typ(tp.derivedAppliedType(typ.tp, targs)))

case tp: NamedType if canDecompose(tp.prefix) =>
rec(tp.prefix, Nil).map(typ => Typ(tp.derivedSelect(typ.tp)))

case tp =>
def getChildren(sym: Symbol): List[Symbol] =
sym.children.flatMap { child =>
Expand Down Expand Up @@ -669,6 +676,8 @@ class SpaceEngine(using Context) extends SpaceLogic {
/** Abstract sealed types, or-types, Boolean and Java enums can be decomposed */
def canDecompose(tp: Type): Boolean =
val res = tp.dealias match
case tp: AppliedType => canDecompose(tp.tycon)
case tp: NamedType if tp.classSymbol.children.isEmpty => canDecompose(tp.prefix)
case _: SingletonType => false
case _: OrType => true
case and: AndType => canDecompose(and.tp1) || canDecompose(and.tp2)
Expand Down
18 changes: 18 additions & 0 deletions tests/pos/i15029.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// scalac: -Werror
sealed trait Schema[A]

sealed trait RecordInstances:
case class Field[B]() extends Schema[B]
case object Thing extends Schema[Int]

object X extends RecordInstances
object Y extends RecordInstances

// Match not exhaustive error! (with fatal warnings :P)
class Test:
def handle[T](schema: Schema[T]) =
schema match // was: match may not be exhaustive
case X.Field() =>
case X.Thing =>
case Y.Field() =>
case Y.Thing =>

0 comments on commit 96653a9

Please sign in to comment.