Skip to content

Commit 23cee40

Browse files
committed
Space: Prep for caching decompose/canDecompose on Typ
1 parent 53a7827 commit 23cee40

File tree

1 file changed

+67
-90
lines changed
  • compiler/src/dotty/tools/dotc/transform/patmat

1 file changed

+67
-90
lines changed

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

Lines changed: 67 additions & 90 deletions
Original file line numberDiff line numberDiff line change
@@ -92,16 +92,16 @@ object SpaceEngine {
9292
def simplify(space: Space)(using Context): Space = trace(s"simplify ${show(space)} --> ", debug, show)(space match {
9393
case Prod(tp, fun, spaces) =>
9494
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
9797
else if sps eq spaces then space else Prod(tp, fun, sps)
9898
case Or(spaces) =>
9999
val spaces2 = spaces.map(simplify).filter(_ != Empty)
100100
if spaces2.isEmpty then Empty
101101
else if spaces2.lengthIs == 1 then spaces2.head
102102
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
105105
else space
106106
case _ => space
107107
})
@@ -143,116 +143,96 @@ object SpaceEngine {
143143
def isSubspace(a: Space, b: Space)(using Context): Boolean = a.isSubspace(b)
144144

145145
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-
149146
val a2 = simplify(a)
150147
val b2 = simplify(b)
151148
if (a ne a2) || (b ne b2) then isSubspace(a2, b2)
152149
else (a, b) match {
153150
case (Empty, _) => true
154151
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, _)) =>
158158
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)))
165161
case (Prod(tp1, _, _), Typ(tp2, _)) =>
166162
isSubType(tp1, tp2)
167163
case (Typ(tp1, _), Prod(tp2, fun, ss)) =>
168164
isSubType(tp1, tp2)
169165
&& covers(fun, tp1, ss.length)
170166
&& isSubspace(Prod(tp2, fun, signature(fun, tp1, ss.length).map(Typ(_, false))), b)
171167
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)
173169
}
174170
}
175171

176172
/** Intersection of two spaces */
177173
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-
181174
(a, b) match {
182175
case (Empty, _) | (_, Empty) => Empty
183176
case (_, Or(ss)) => Or(ss.map(intersect(a, _)).filter(_ ne Empty))
184177
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)))
190183
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
195188
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
200193
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))
205198
}
206199
}
207200

208201
/** The space of a not covered by b */
209202
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-
213203
(a, b) match {
214204
case (Empty, _) => Empty
215205
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)))
220212
else a
221-
case (Typ(tp1, _), Prod(tp2, fun, ss)) =>
213+
case (a @ Typ(tp1, _), Prod(tp2, fun, ss)) =>
222214
// rationale: every instance of `tp1` is covered by `tp2(_)`
223215
if isSubType(tp1, tp2) && covers(fun, tp1, ss.length) then
224216
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, _)) =>
234220
// 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
243225
case (Prod(tp1, fun1, ss1), Prod(tp2, fun2, ss2))
244-
if (!isSameUnapply(fun1, fun2)) => a
226+
if !isSameUnapply(fun1, fun2) => a
245227
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
250231
val cache = Array.fill[Space | Null](ss2.length)(null)
251232
def sub(i: Int) =
252233
if cache(i) == null then
253234
cache(i) = minus(ss1(i), ss2(i))
254235
cache(i).nn
255-
end sub
256236

257237
if range.exists(i => isSubspace(ss1(i), sub(i))) then a
258238
else if cache.forall(sub => isSubspace(sub.nn, Empty)) then Empty
@@ -610,26 +590,26 @@ object SpaceEngine {
610590
else
611591
decomposeComponent(tp2, tp1)
612592

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))
614594
case tp if tp.isRef(defn.BooleanClass) =>
615595
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)
618598
)
619599
case tp if tp.isRef(defn.UnitClass) =>
620-
Typ(ConstantType(Constant(())), true) :: Nil
600+
Typ(ConstantType(Constant(())), decomposed = true) :: Nil
621601
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))
623603

624604
case tp @ AppliedType(tycon, targs) if tp.classSymbol.children.isEmpty && canDecompose(tycon) =>
625605
// It might not obvious that it's OK to apply the type arguments of a parent type to child types.
626606
// But this is guarded by `tp.classSymbol.children.isEmpty`,
627607
// meaning we'll decompose to the same class, just not the same type.
628608
// 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))
630610

631611
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))
633613

634614
case tp =>
635615
def getChildren(sym: Symbol): List[Symbol] =
@@ -641,30 +621,27 @@ object SpaceEngine {
641621
else List(child)
642622
}
643623
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")
645625

646626
val parts = children.map { sym =>
647627
val sym1 = if (sym.is(ModuleClass)) sym.sourceModule else sym
648628
val refined = TypeOps.refineUsingParent(tp, sym1, mixins)
629+
debug.println(i"$sym1 refined to $refined")
649630

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
660637

661-
if (inhabited(refined)) refined
638+
if inhabited(refined) then refined
662639
else NoType
663-
} filter(_.exists)
640+
}.filter(_.exists)
664641

665-
debug.println(s"${tp.show} decomposes to [${parts.map(_.show).mkString(", ")}]")
642+
debug.println(i"$tp decomposes to $parts")
666643

667-
parts.map(Typ(_, true))
644+
parts.map(Typ(_, decomposed = true))
668645
}
669646
rec(tp, Nil)
670647
}

0 commit comments

Comments
 (0)