@@ -77,7 +77,18 @@ case object Empty extends Space
77
77
* @param decomposed: does the space result from decomposition? Used for pretty print
78
78
*
79
79
*/
80
- case class Typ (tp : Type , decomposed : Boolean = true ) extends Space
80
+ case class Typ (tp : Type , decomposed : Boolean = true ) extends Space :
81
+ private var myCanDecompose : java.lang.Boolean = _
82
+ private var myDecompose : List [Typ ] = _
83
+
84
+ def canDecompose (using Context ): Boolean =
85
+ if myCanDecompose == null then myCanDecompose = SpaceEngine .canDecompose(tp)
86
+ myCanDecompose
87
+
88
+ def decompose (using Context ): List [Typ ] =
89
+ if myDecompose == null then myDecompose = SpaceEngine .decompose(tp)
90
+ myDecompose
91
+ end Typ
81
92
82
93
/** Space representing an extractor pattern */
83
94
case class Prod (tp : Type , unappTp : TermRef , params : List [Space ]) extends Space
@@ -101,7 +112,7 @@ object SpaceEngine {
101
112
else if spaces2.lengthIs == 1 then spaces2.head
102
113
else if spaces2.corresponds(spaces)(_ eq _) then space else Or (spaces2)
103
114
case typ : Typ =>
104
- if canDecompose(typ.tp ) && decompose(typ.tp ).isEmpty then Empty
115
+ if canDecompose(typ) && decompose(typ).isEmpty then Empty
105
116
else space
106
117
case _ => space
107
118
})
@@ -152,12 +163,12 @@ object SpaceEngine {
152
163
case (Or (ss), _) => ss.forall(isSubspace(_, b))
153
164
case (a @ Typ (tp1, _), Or (ss)) => // optimization: don't go to subtraction too early
154
165
ss.exists(isSubspace(a, _))
155
- || canDecompose(tp1 ) && isSubspace(Or (decompose(tp1 )), b)
166
+ || canDecompose(a ) && isSubspace(Or (decompose(a )), b)
156
167
case (_, Or (_)) => simplify(minus(a, b)) == Empty
157
168
case (a @ Typ (tp1, _), b @ Typ (tp2, _)) =>
158
169
isSubType(tp1, tp2)
159
- || canDecompose(tp1 ) && isSubspace(Or (decompose(tp1 )), b)
160
- || canDecompose(tp2 ) && isSubspace(a, Or (decompose(tp2 )))
170
+ || canDecompose(a ) && isSubspace(Or (decompose(a )), b)
171
+ || canDecompose(b ) && isSubspace(a, Or (decompose(b )))
161
172
case (Prod (tp1, _, _), Typ (tp2, _)) =>
162
173
isSubType(tp1, tp2)
163
174
case (Typ (tp1, _), Prod (tp2, fun, ss)) =>
@@ -178,17 +189,17 @@ object SpaceEngine {
178
189
case (a @ Typ (tp1, _), b @ Typ (tp2, _)) =>
179
190
if isSubType(tp1, tp2) then a
180
191
else if isSubType(tp2, tp1) then b
181
- else if canDecompose(tp1 ) then intersect(Or (decompose(tp1 )), b)
182
- else if canDecompose(tp2 ) then intersect(a, Or (decompose(tp2 )))
192
+ else if canDecompose(a ) then intersect(Or (decompose(a )), b)
193
+ else if canDecompose(b ) then intersect(a, Or (decompose(b )))
183
194
else intersectUnrelatedAtomicTypes(tp1, tp2)(a)
184
195
case (a @ Typ (tp1, _), Prod (tp2, fun, ss)) =>
185
196
if isSubType(tp2, tp1) then b
186
- else if canDecompose(tp1 ) then intersect(Or (decompose(tp1 )), b)
197
+ else if canDecompose(a ) then intersect(Or (decompose(a )), b)
187
198
else if isSubType(tp1, tp2) then a // problematic corner case: inheriting a case class
188
199
else intersectUnrelatedAtomicTypes(tp1, tp2)(b)
189
200
case (Prod (tp1, fun, ss), b @ Typ (tp2, _)) =>
190
201
if isSubType(tp1, tp2) then a
191
- else if canDecompose(tp2 ) then intersect(a, Or (decompose(tp2 )))
202
+ else if canDecompose(b ) then intersect(a, Or (decompose(b )))
192
203
else if isSubType(tp2, tp1) then a // problematic corner case: inheriting a case class
193
204
else intersectUnrelatedAtomicTypes(tp1, tp2)(a)
194
205
case (a @ Prod (tp1, fun1, ss1), Prod (tp2, fun2, ss2)) =>
@@ -207,20 +218,20 @@ object SpaceEngine {
207
218
case (_, Or (ss)) => ss.foldLeft(a)(minus)
208
219
case (a @ Typ (tp1, _), b @ Typ (tp2, _)) =>
209
220
if isSubType(tp1, tp2) then Empty
210
- else if canDecompose(tp1 ) then minus(Or (decompose(tp1 )), b)
211
- else if canDecompose(tp2 ) then minus(a, Or (decompose(tp2 )))
221
+ else if canDecompose(a ) then minus(Or (decompose(a )), b)
222
+ else if canDecompose(b ) then minus(a, Or (decompose(b )))
212
223
else a
213
224
case (a @ Typ (tp1, _), Prod (tp2, fun, ss)) =>
214
225
// rationale: every instance of `tp1` is covered by `tp2(_)`
215
226
if isSubType(tp1, tp2) && covers(fun, tp1, ss.length) then
216
227
minus(Prod (tp1, fun, signature(fun, tp1, ss.length).map(Typ (_, false ))), b)
217
- else if canDecompose(tp1 ) then minus(Or (decompose(tp1 )), b)
228
+ else if canDecompose(a ) then minus(Or (decompose(a )), b)
218
229
else a
219
230
case (Prod (tp1, fun, ss), b @ Typ (tp2, _)) =>
220
231
// uncovered corner case: tp2 :< tp1, may happen when inheriting case class
221
232
if isSubType(tp1, tp2) then Empty
222
233
else if simplify(a) == Empty then Empty
223
- else if canDecompose(tp2 ) then minus(a, Or (decompose(tp2 )))
234
+ else if canDecompose(b ) then minus(a, Or (decompose(b )))
224
235
else a
225
236
case (Prod (tp1, fun1, ss1), Prod (tp2, fun2, ss2))
226
237
if ! isSameUnapply(fun1, fun2) => a
@@ -568,6 +579,9 @@ object SpaceEngine {
568
579
scrutineeTp <:< tp
569
580
}
570
581
582
+ def canDecompose (typ : Typ )(using Context ): Boolean = typ.canDecompose
583
+ def decompose (typ : Typ )(using Context ): List [Typ ] = typ.decompose
584
+
571
585
/** Decompose a type into subspaces -- assume the type can be decomposed */
572
586
def decompose (tp : Type )(using Context ): List [Typ ] = trace(i " decompose( $tp) " , debug, showSpaces) {
573
587
def rec (tp : Type , mixins : List [Type ]): List [Typ ] = tp.dealias match {
0 commit comments