Skip to content

Commit 7f4009b

Browse files
committed
Space: Redefine canDecompose in terms of decompose
1 parent 512a307 commit 7f4009b

File tree

1 file changed

+52
-61
lines changed
  • compiler/src/dotty/tools/dotc/transform/patmat

1 file changed

+52
-61
lines changed

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

Lines changed: 52 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -78,15 +78,12 @@ case object Empty extends Space
7878
*
7979
*/
8080
case class Typ(tp: Type, decomposed: Boolean = true) extends Space:
81-
private var myCanDecompose: java.lang.Boolean = _
8281
private var myDecompose: List[Typ] = _
8382

84-
def canDecompose(using Context): Boolean =
85-
if myCanDecompose == null then myCanDecompose = SpaceEngine.canDecompose(tp)
86-
myCanDecompose
83+
def canDecompose(using Context): Boolean = decompose != SpaceEngine.ListOfTypNoType
8784

8885
def decompose(using Context): List[Typ] =
89-
if myDecompose == null then myDecompose = SpaceEngine.decompose(tp)
86+
if myDecompose == null then myDecompose = SpaceEngine.decompose(tp).map(Typ(_, decomposed = true))
9087
myDecompose
9188
end Typ
9289

@@ -104,15 +101,15 @@ object SpaceEngine {
104101
case Prod(tp, fun, spaces) =>
105102
val sps = spaces.mapconserve(simplify)
106103
if sps.contains(Empty) then Empty
107-
else if canDecompose(tp) && decompose(tp).isEmpty then Empty
104+
else if decompose(tp).isEmpty then Empty
108105
else if sps eq spaces then space else Prod(tp, fun, sps)
109106
case Or(spaces) =>
110107
val spaces2 = spaces.map(simplify).filter(_ != Empty)
111108
if spaces2.isEmpty then Empty
112109
else if spaces2.lengthIs == 1 then spaces2.head
113110
else if spaces2.corresponds(spaces)(_ eq _) then space else Or(spaces2)
114111
case typ: Typ =>
115-
if canDecompose(typ) && decompose(typ).isEmpty then Empty
112+
if decompose(typ).isEmpty then Empty
116113
else space
117114
case _ => space
118115
})
@@ -583,43 +580,53 @@ object SpaceEngine {
583580
def decompose(typ: Typ)(using Context): List[Typ] = typ.decompose
584581

585582
/** Decompose a type into subspaces -- assume the type can be decomposed */
586-
def decompose(tp: Type)(using Context): List[Typ] = trace(i"decompose($tp)", debug, showSpaces) {
587-
def rec(tp: Type, mixins: List[Type]): List[Type] = tp.dealias match {
583+
def decompose(tp: Type)(using Context): List[Type] = trace(i"decompose($tp)", debug) {
584+
var lastType: Type = NoType
585+
var lastParts: List[Type] = Nil
586+
def dec(tp: Type) =
587+
if tp eq lastType then lastParts
588+
else
589+
lastType = tp
590+
lastParts = decompose(tp)
591+
lastParts
592+
def canDec(tp: Type) =
593+
lastParts = dec(tp)
594+
lastParts != ListOfNoType
595+
596+
def rec(tp: Type, mixins: List[Type]): List[Type] = tp.dealias match
588597
case AndType(tp1, tp2) =>
589-
def decomposeComponent(tpA: Type, tpB: Type): List[Type] =
590-
rec(tpA, tpB :: mixins).collect {
591-
case tp if tp <:< tpB => tp
592-
case tp if tpB <:< tp => tpB
593-
case tp if !TypeComparer.provablyDisjoint(tp, tpB) => AndType(tp, tpB)
594-
}
595-
596-
if canDecompose(tp1) then
597-
decomposeComponent(tp1, tp2)
598-
else
599-
decomposeComponent(tp2, tp1)
600-
601-
case OrType(tp1, tp2) => List(tp1, tp2)
602-
case tp if tp.isRef(defn.BooleanClass) =>
603-
List(
604-
ConstantType(Constant(true)),
605-
ConstantType(Constant(false))
606-
)
607-
case tp if tp.isRef(defn.UnitClass) =>
608-
ConstantType(Constant(())) :: Nil
609-
case tp if tp.classSymbol.isAllOf(JavaEnumTrait) =>
610-
tp.classSymbol.children.map(_.termRef)
611-
612-
case tp @ AppliedType(tycon, targs) if tp.classSymbol.children.isEmpty && canDecompose(tycon) =>
598+
var tpB = tp2
599+
var parts = rec(tp1, tp2 :: mixins)
600+
if parts == ListOfNoType then
601+
tpB = tp1
602+
parts = rec(tp2, tp1 :: mixins)
603+
if parts == ListOfNoType then ListOfNoType
604+
else parts.collect:
605+
case tp if tp <:< tpB => tp
606+
case tp if tpB <:< tp => tpB
607+
case tp if !TypeComparer.provablyDisjoint(tp, tpB) => AndType(tp, tpB)
608+
609+
case OrType(tp1, tp2) => List(tp1, tp2)
610+
case _: SingletonType => ListOfNoType
611+
case tp if tp.isRef(defn.BooleanClass) => List(ConstantType(Constant(true)), ConstantType(Constant(false)))
612+
case tp if tp.isRef(defn.UnitClass) => ConstantType(Constant(())) :: Nil
613+
case tp if tp.classSymbol.isAllOf(JavaEnumTrait) => tp.classSymbol.children.map(_.termRef)
614+
case tp: NamedType if canDec(tp.prefix) => dec(tp.prefix).map(tp.derivedSelect)
615+
616+
case tp @ AppliedType(tycon, targs) if tp.classSymbol.children.isEmpty && canDec(tycon) =>
613617
// It might not obvious that it's OK to apply the type arguments of a parent type to child types.
614618
// But this is guarded by `tp.classSymbol.children.isEmpty`,
615619
// meaning we'll decompose to the same class, just not the same type.
616620
// For instance, from i15029, `decompose((X | Y).Field[T]) = [X.Field[T], Y.Field[T]]`.
617-
rec(tycon, Nil).map(tp.derivedAppliedType(_, targs))
618-
619-
case tp: NamedType if canDecompose(tp.prefix) =>
620-
rec(tp.prefix, Nil).map(tp.derivedSelect)
621+
dec(tycon).map(tp.derivedAppliedType(_, targs))
621622

622-
case tp =>
623+
case tp if {
624+
val cls = tp.classSymbol
625+
cls.is(Sealed)
626+
&& cls.isOneOf(AbstractOrTrait)
627+
&& !cls.hasAnonymousChild
628+
&& cls.children.nonEmpty
629+
} =>
623630
def getChildren(sym: Symbol): List[Symbol] =
624631
sym.children.flatMap { child =>
625632
if child eq sym then List(sym) // i3145: sealed trait Baz, val x = new Baz {}, Baz.children returns Baz...
@@ -646,33 +653,17 @@ object SpaceEngine {
646653
if inhabited(refined) then refined
647654
else NoType
648655
}.filter(_.exists)
649-
650656
debug.println(i"$tp decomposes to $parts")
651-
652657
parts
653-
}
654-
rec(tp, Nil).map(Typ(_, decomposed = true))
658+
659+
case _ => ListOfNoType
660+
end rec
661+
662+
rec(tp, Nil)
655663
}
656664

657-
/** Abstract sealed types, or-types, Boolean and Java enums can be decomposed */
658-
def canDecompose(tp: Type)(using Context): Boolean =
659-
val res = tp.dealias match
660-
case AppliedType(tycon, _) if canDecompose(tycon) => true
661-
case tp: NamedType if canDecompose(tp.prefix) => true
662-
case _: SingletonType => false
663-
case _: OrType => true
664-
case AndType(tp1, tp2) => canDecompose(tp1) || canDecompose(tp2)
665-
case _ =>
666-
val cls = tp.classSymbol
667-
cls.is(Sealed)
668-
&& cls.isOneOf(AbstractOrTrait)
669-
&& !cls.hasAnonymousChild
670-
&& cls.children.nonEmpty
671-
|| cls.isAllOf(JavaEnumTrait)
672-
|| tp.isRef(defn.BooleanClass)
673-
|| tp.isRef(defn.UnitClass)
674-
//debug.println(s"decomposable: ${tp.show} = $res")
675-
res
665+
val ListOfNoType = List(NoType)
666+
val ListOfTypNoType = ListOfNoType.map(Typ(_, decomposed = true))
676667

677668
/** Show friendly type name with current scope in mind
678669
*

0 commit comments

Comments
 (0)