@@ -78,15 +78,12 @@ case object Empty extends Space
78
78
*
79
79
*/
80
80
case class Typ (tp : Type , decomposed : Boolean = true ) extends Space :
81
- private var myCanDecompose : java.lang.Boolean = _
82
81
private var myDecompose : List [Typ ] = _
83
82
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
87
84
88
85
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 ))
90
87
myDecompose
91
88
end Typ
92
89
@@ -104,15 +101,15 @@ object SpaceEngine {
104
101
case Prod (tp, fun, spaces) =>
105
102
val sps = spaces.mapconserve(simplify)
106
103
if sps.contains(Empty ) then Empty
107
- else if canDecompose(tp) && decompose(tp).isEmpty then Empty
104
+ else if decompose(tp).isEmpty then Empty
108
105
else if sps eq spaces then space else Prod (tp, fun, sps)
109
106
case Or (spaces) =>
110
107
val spaces2 = spaces.map(simplify).filter(_ != Empty )
111
108
if spaces2.isEmpty then Empty
112
109
else if spaces2.lengthIs == 1 then spaces2.head
113
110
else if spaces2.corresponds(spaces)(_ eq _) then space else Or (spaces2)
114
111
case typ : Typ =>
115
- if canDecompose(typ) && decompose(typ).isEmpty then Empty
112
+ if decompose(typ).isEmpty then Empty
116
113
else space
117
114
case _ => space
118
115
})
@@ -583,43 +580,53 @@ object SpaceEngine {
583
580
def decompose (typ : Typ )(using Context ): List [Typ ] = typ.decompose
584
581
585
582
/** 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
588
597
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) =>
613
617
// It might not obvious that it's OK to apply the type arguments of a parent type to child types.
614
618
// But this is guarded by `tp.classSymbol.children.isEmpty`,
615
619
// meaning we'll decompose to the same class, just not the same type.
616
620
// 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))
621
622
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
+ } =>
623
630
def getChildren (sym : Symbol ): List [Symbol ] =
624
631
sym.children.flatMap { child =>
625
632
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 {
646
653
if inhabited(refined) then refined
647
654
else NoType
648
655
}.filter(_.exists)
649
-
650
656
debug.println(i " $tp decomposes to $parts" )
651
-
652
657
parts
653
- }
654
- rec(tp, Nil ).map(Typ (_, decomposed = true ))
658
+
659
+ case _ => ListOfNoType
660
+ end rec
661
+
662
+ rec(tp, Nil )
655
663
}
656
664
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 ))
676
667
677
668
/** Show friendly type name with current scope in mind
678
669
*
0 commit comments