@@ -92,16 +92,16 @@ object SpaceEngine {
92
92
def simplify (space : Space )(using Context ): Space = trace(s " simplify ${show(space)} --> " , debug, show)(space match {
93
93
case Prod (tp, fun, spaces) =>
94
94
val sps = spaces.mapconserve(simplify)
95
- if ( sps.contains(Empty )) Empty
96
- else if ( canDecompose(tp) && decompose(tp).isEmpty) Empty
95
+ if sps.contains(Empty ) then Empty
96
+ else if canDecompose(tp) && decompose(tp).isEmpty then Empty
97
97
else if sps eq spaces then space else Prod (tp, fun, sps)
98
98
case Or (spaces) =>
99
99
val spaces2 = spaces.map(simplify).filter(_ != Empty )
100
100
if spaces2.isEmpty then Empty
101
101
else if spaces2.lengthIs == 1 then spaces2.head
102
102
else if spaces2.corresponds(spaces)(_ eq _) then space else Or (spaces2)
103
- case Typ (tp, _) =>
104
- if ( canDecompose(tp) && decompose(tp).isEmpty) Empty
103
+ case typ : Typ =>
104
+ if canDecompose(typ. tp) && decompose(typ. tp).isEmpty then Empty
105
105
else space
106
106
case _ => space
107
107
})
@@ -143,116 +143,96 @@ object SpaceEngine {
143
143
def isSubspace (a : Space , b : Space )(using Context ): Boolean = a.isSubspace(b)
144
144
145
145
def computeIsSubspace (a : Space , b : Space )(using Context ): Boolean = {
146
- def tryDecompose1 (tp : Type ) = canDecompose(tp) && isSubspace(Or (decompose(tp)), b)
147
- def tryDecompose2 (tp : Type ) = canDecompose(tp) && isSubspace(a, Or (decompose(tp)))
148
-
149
146
val a2 = simplify(a)
150
147
val b2 = simplify(b)
151
148
if (a ne a2) || (b ne b2) then isSubspace(a2, b2)
152
149
else (a, b) match {
153
150
case (Empty , _) => true
154
151
case (_, Empty ) => false
155
- case (Or (ss), _) =>
156
- ss.forall(isSubspace(_, b))
157
- case (Typ (tp1, _), Typ (tp2, _)) =>
152
+ case (Or (ss), _) => ss.forall(isSubspace(_, b))
153
+ case (a @ Typ (tp1, _), Or (ss)) => // optimization: don't go to subtraction too early
154
+ ss.exists(isSubspace(a, _))
155
+ || canDecompose(tp1) && isSubspace(Or (decompose(tp1)), b)
156
+ case (_, Or (_)) => simplify(minus(a, b)) == Empty
157
+ case (a @ Typ (tp1, _), b @ Typ (tp2, _)) =>
158
158
isSubType(tp1, tp2)
159
- || canDecompose(tp1) && tryDecompose1(tp1)
160
- || canDecompose(tp2) && tryDecompose2(tp2)
161
- case (Typ (tp1, _), Or (ss)) => // optimization: don't go to subtraction too early
162
- ss.exists(isSubspace(a, _)) || tryDecompose1(tp1)
163
- case (_, Or (_)) =>
164
- simplify(minus(a, b)) == Empty
159
+ || canDecompose(tp1) && isSubspace(Or (decompose(tp1)), b)
160
+ || canDecompose(tp2) && isSubspace(a, Or (decompose(tp2)))
165
161
case (Prod (tp1, _, _), Typ (tp2, _)) =>
166
162
isSubType(tp1, tp2)
167
163
case (Typ (tp1, _), Prod (tp2, fun, ss)) =>
168
164
isSubType(tp1, tp2)
169
165
&& covers(fun, tp1, ss.length)
170
166
&& isSubspace(Prod (tp2, fun, signature(fun, tp1, ss.length).map(Typ (_, false ))), b)
171
167
case (Prod (_, fun1, ss1), Prod (_, fun2, ss2)) =>
172
- isSameUnapply(fun1, fun2) && ss1.zip (ss2).forall(( isSubspace _).tupled )
168
+ isSameUnapply(fun1, fun2) && ss1.lazyZip (ss2).forall(isSubspace)
173
169
}
174
170
}
175
171
176
172
/** Intersection of two spaces */
177
173
def intersect (a : Space , b : Space )(using Context ): Space = trace(s " ${show(a)} & ${show(b)}" , debug, show) {
178
- def tryDecompose1 (tp : Type ) = intersect(Or (decompose(tp)), b)
179
- def tryDecompose2 (tp : Type ) = intersect(a, Or (decompose(tp)))
180
-
181
174
(a, b) match {
182
175
case (Empty , _) | (_, Empty ) => Empty
183
176
case (_, Or (ss)) => Or (ss.map(intersect(a, _)).filter(_ ne Empty ))
184
177
case (Or (ss), _) => Or (ss.map(intersect(_, b)).filter(_ ne Empty ))
185
- case (Typ (tp1, _), Typ (tp2, _)) =>
186
- if ( isSubType(tp1, tp2)) a
187
- else if ( isSubType(tp2, tp1)) b
188
- else if ( canDecompose(tp1)) tryDecompose1( tp1)
189
- else if ( canDecompose(tp2)) tryDecompose2( tp2)
178
+ case (a @ Typ (tp1, _), b @ Typ (tp2, _)) =>
179
+ if isSubType(tp1, tp2) then a
180
+ 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)) )
190
183
else intersectUnrelatedAtomicTypes(tp1, tp2)(a)
191
- case (Typ (tp1, _), Prod (tp2, fun, ss)) =>
192
- if ( isSubType(tp2, tp1)) b
193
- else if ( canDecompose(tp1)) tryDecompose1( tp1)
194
- else if ( isSubType(tp1, tp2)) a // problematic corner case: inheriting a case class
184
+ case (a @ Typ (tp1, _), Prod (tp2, fun, ss)) =>
185
+ if isSubType(tp2, tp1) then b
186
+ else if canDecompose(tp1) then intersect( Or (decompose( tp1)), b )
187
+ else if isSubType(tp1, tp2) then a // problematic corner case: inheriting a case class
195
188
else intersectUnrelatedAtomicTypes(tp1, tp2)(b)
196
- case (Prod (tp1, fun, ss), Typ (tp2, _)) =>
197
- if ( isSubType(tp1, tp2)) a
198
- else if ( canDecompose(tp2)) tryDecompose2( tp2)
199
- else if ( isSubType(tp2, tp1)) a // problematic corner case: inheriting a case class
189
+ case (Prod (tp1, fun, ss), b @ Typ (tp2, _)) =>
190
+ if isSubType(tp1, tp2) then a
191
+ else if canDecompose(tp2) then intersect(a, Or (decompose( tp2)) )
192
+ else if isSubType(tp2, tp1) then a // problematic corner case: inheriting a case class
200
193
else intersectUnrelatedAtomicTypes(tp1, tp2)(a)
201
- case (Prod (tp1, fun1, ss1), Prod (tp2, fun2, ss2)) =>
202
- if ( ! isSameUnapply(fun1, fun2)) intersectUnrelatedAtomicTypes(tp1, tp2)(a)
203
- else if ( ss1.zip (ss2).exists(p => simplify(intersect(p._1, p._2 )) == Empty )) Empty
204
- else Prod (tp1, fun1, ss1.zip (ss2).map(( intersect _).tupled ))
194
+ case (a @ Prod (tp1, fun1, ss1), Prod (tp2, fun2, ss2)) =>
195
+ if ! isSameUnapply(fun1, fun2) then intersectUnrelatedAtomicTypes(tp1, tp2)(a)
196
+ else if ss1.lazyZip (ss2).exists((a, b) => simplify(intersect(a, b )) == Empty ) then Empty
197
+ else Prod (tp1, fun1, ss1.lazyZip (ss2).map(intersect))
205
198
}
206
199
}
207
200
208
201
/** The space of a not covered by b */
209
202
def minus (a : Space , b : Space )(using Context ): Space = trace(s " ${show(a)} - ${show(b)}" , debug, show) {
210
- def tryDecompose1 (tp : Type ) = minus(Or (decompose(tp)), b)
211
- def tryDecompose2 (tp : Type ) = minus(a, Or (decompose(tp)))
212
-
213
203
(a, b) match {
214
204
case (Empty , _) => Empty
215
205
case (_, Empty ) => a
216
- case (Typ (tp1, _), Typ (tp2, _)) =>
217
- if (isSubType(tp1, tp2)) Empty
218
- else if (canDecompose(tp1)) tryDecompose1(tp1)
219
- else if (canDecompose(tp2)) tryDecompose2(tp2)
206
+ case (Or (ss), _) => Or (ss.map(minus(_, b)))
207
+ case (_, Or (ss)) => ss.foldLeft(a)(minus)
208
+ case (a @ Typ (tp1, _), b @ Typ (tp2, _)) =>
209
+ 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)))
220
212
else a
221
- case (Typ (tp1, _), Prod (tp2, fun, ss)) =>
213
+ case (a @ Typ (tp1, _), Prod (tp2, fun, ss)) =>
222
214
// rationale: every instance of `tp1` is covered by `tp2(_)`
223
215
if isSubType(tp1, tp2) && covers(fun, tp1, ss.length) then
224
216
minus(Prod (tp1, fun, signature(fun, tp1, ss.length).map(Typ (_, false ))), b)
225
- else if canDecompose(tp1) then
226
- tryDecompose1(tp1)
227
- else
228
- a
229
- case (Or (ss), _) =>
230
- Or (ss.map(minus(_, b)))
231
- case (_, Or (ss)) =>
232
- ss.foldLeft(a)(minus)
233
- case (Prod (tp1, fun, ss), Typ (tp2, _)) =>
217
+ else if canDecompose(tp1) then minus(Or (decompose(tp1)), b)
218
+ else a
219
+ case (Prod (tp1, fun, ss), b @ Typ (tp2, _)) =>
234
220
// uncovered corner case: tp2 :< tp1, may happen when inheriting case class
235
- if (isSubType(tp1, tp2))
236
- Empty
237
- else if (simplify(a) == Empty )
238
- Empty
239
- else if (canDecompose(tp2))
240
- tryDecompose2(tp2)
241
- else
242
- a
221
+ if isSubType(tp1, tp2) then Empty
222
+ else if simplify(a) == Empty then Empty
223
+ else if canDecompose(tp2) then minus(a, Or (decompose(tp2)))
224
+ else a
243
225
case (Prod (tp1, fun1, ss1), Prod (tp2, fun2, ss2))
244
- if ( ! isSameUnapply(fun1, fun2) ) => a
226
+ if ! isSameUnapply(fun1, fun2) => a
245
227
case (Prod (tp1, fun1, ss1), Prod (tp2, fun2, ss2))
246
- if (fun1.symbol.name == nme.unapply && ss1.length != ss2.length) => a
247
- case (Prod (tp1, fun1, ss1), Prod (tp2, fun2, ss2)) =>
248
-
249
- val range = (0 until ss1.size).toList
228
+ if fun1.symbol.name == nme.unapply && ss1.length != ss2.length => a
229
+ case (a @ Prod (tp1, fun1, ss1), Prod (tp2, fun2, ss2)) =>
230
+ val range = ss1.indices.toList
250
231
val cache = Array .fill[Space | Null ](ss2.length)(null )
251
232
def sub (i : Int ) =
252
233
if cache(i) == null then
253
234
cache(i) = minus(ss1(i), ss2(i))
254
235
cache(i).nn
255
- end sub
256
236
257
237
if range.exists(i => isSubspace(ss1(i), sub(i))) then a
258
238
else if cache.forall(sub => isSubspace(sub.nn, Empty )) then Empty
@@ -610,26 +590,26 @@ object SpaceEngine {
610
590
else
611
591
decomposeComponent(tp2, tp1)
612
592
613
- case OrType (tp1, tp2) => List (Typ (tp1, true ), Typ (tp2, true ))
593
+ case OrType (tp1, tp2) => List (Typ (tp1, decomposed = true ), Typ (tp2, decomposed = true ))
614
594
case tp if tp.isRef(defn.BooleanClass ) =>
615
595
List (
616
- Typ (ConstantType (Constant (true )), true ),
617
- Typ (ConstantType (Constant (false )), true )
596
+ Typ (ConstantType (Constant (true )), decomposed = true ),
597
+ Typ (ConstantType (Constant (false )), decomposed = true )
618
598
)
619
599
case tp if tp.isRef(defn.UnitClass ) =>
620
- Typ (ConstantType (Constant (())), true ) :: Nil
600
+ Typ (ConstantType (Constant (())), decomposed = true ) :: Nil
621
601
case tp if tp.classSymbol.isAllOf(JavaEnumTrait ) =>
622
- tp.classSymbol.children.map(sym => Typ (sym.termRef, true ))
602
+ tp.classSymbol.children.map(sym => Typ (sym.termRef, decomposed = true ))
623
603
624
604
case tp @ AppliedType (tycon, targs) if tp.classSymbol.children.isEmpty && canDecompose(tycon) =>
625
605
// It might not obvious that it's OK to apply the type arguments of a parent type to child types.
626
606
// But this is guarded by `tp.classSymbol.children.isEmpty`,
627
607
// meaning we'll decompose to the same class, just not the same type.
628
608
// For instance, from i15029, `decompose((X | Y).Field[T]) = [X.Field[T], Y.Field[T]]`.
629
- rec(tycon, Nil ).map(typ => Typ (tp.derivedAppliedType(typ.tp, targs)))
609
+ rec(tycon, Nil ).map(typ => Typ (tp.derivedAppliedType(typ.tp, targs), decomposed = true ))
630
610
631
611
case tp : NamedType if canDecompose(tp.prefix) =>
632
- rec(tp.prefix, Nil ).map(typ => Typ (tp.derivedSelect(typ.tp)))
612
+ rec(tp.prefix, Nil ).map(typ => Typ (tp.derivedSelect(typ.tp), decomposed = true ))
633
613
634
614
case tp =>
635
615
def getChildren (sym : Symbol ): List [Symbol ] =
@@ -641,30 +621,27 @@ object SpaceEngine {
641
621
else List (child)
642
622
}
643
623
val children = getChildren(tp.classSymbol)
644
- debug.println(s " candidates for ${tp.show} : [ ${ children.map(_.show).mkString( " , " )} ] " )
624
+ debug.println(i " candidates for $tp : $ children" )
645
625
646
626
val parts = children.map { sym =>
647
627
val sym1 = if (sym.is(ModuleClass )) sym.sourceModule else sym
648
628
val refined = TypeOps .refineUsingParent(tp, sym1, mixins)
629
+ debug.println(i " $sym1 refined to $refined" )
649
630
650
- debug.println(sym1.show + " refined to " + refined.show)
651
-
652
- def inhabited (tp : Type ): Boolean =
653
- tp.dealias match {
654
- case AndType (tp1, tp2) => ! TypeComparer .provablyDisjoint(tp1, tp2)
655
- case OrType (tp1, tp2) => inhabited(tp1) || inhabited(tp2)
656
- case tp : RefinedType => inhabited(tp.parent)
657
- case tp : TypeRef => inhabited(tp.prefix)
658
- case _ => true
659
- }
631
+ def inhabited (tp : Type ): Boolean = tp.dealias match
632
+ case AndType (tp1, tp2) => ! TypeComparer .provablyDisjoint(tp1, tp2)
633
+ case OrType (tp1, tp2) => inhabited(tp1) || inhabited(tp2)
634
+ case tp : RefinedType => inhabited(tp.parent)
635
+ case tp : TypeRef => inhabited(tp.prefix)
636
+ case _ => true
660
637
661
- if ( inhabited(refined)) refined
638
+ if inhabited(refined) then refined
662
639
else NoType
663
- } filter(_.exists)
640
+ }. filter(_.exists)
664
641
665
- debug.println(s " ${tp.show} decomposes to [ ${ parts.map(_.show).mkString( " , " )} ] " )
642
+ debug.println(i " $tp decomposes to $ parts" )
666
643
667
- parts.map(Typ (_, true ))
644
+ parts.map(Typ (_, decomposed = true ))
668
645
}
669
646
rec(tp, Nil )
670
647
}
0 commit comments