Skip to content

Commit 2bf1e19

Browse files
committed
simplify exhaustivity check using ConstantType
Now the algorithm is the same as in the paper.
1 parent fe9103d commit 2bf1e19

File tree

1 file changed

+11
-49
lines changed
  • compiler/src/dotty/tools/dotc/transform/patmat

1 file changed

+11
-49
lines changed

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

Lines changed: 11 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@ import config.Printers.{ exhaustivity => debug }
2929
* 3. A union of spaces `S1 | S2 | ...` is a space
3030
* 4. For a case class Kon(x1: T1, x2: T2, .., xn: Tn), if S1, S2, ..., Sn
3131
* are spaces, then `Kon(S1, S2, ..., Sn)` is a space.
32-
* 5. A constant `Const(value, T)` is a point in space
3332
*
3433
* For the problem of exhaustivity check, its formulation in terms of space is as follows:
3534
*
@@ -67,12 +66,6 @@ case class Kon(tp: Type, params: List[Space]) extends Space
6766
/** Union of spaces */
6867
case class Or(spaces: List[Space]) extends Space
6968

70-
/** Point in space */
71-
sealed trait Point extends Space
72-
73-
/** Point representing literal constants in patterns */
74-
case class Const(value: Constant, tp: Type) extends Point
75-
7669
/** abstract space logic */
7770
trait SpaceLogic {
7871
/** Is `tp1` a subtype of `tp2`? */
@@ -157,11 +150,6 @@ trait SpaceLogic {
157150
simplify(minus(a, b)) == Empty
158151
case (Kon(tp1, ss1), Kon(tp2, ss2)) =>
159152
isEqualType(tp1, tp2) && ss1.zip(ss2).forall((isSubspace _).tupled)
160-
case (Const(v1, _), Const(v2, _)) => v1 == v2
161-
case (Const(_, tp1), Typ(tp2, _)) => isSubType(tp1, tp2) || tryDecompose2(tp2)
162-
case (Const(_, _), Or(ss)) => ss.exists(isSubspace(a, _))
163-
case (Const(_, _), _) => false
164-
case (_, Const(_, _)) => false
165153
}
166154

167155
debug.println(s"${show(a)} < ${show(b)} = $res")
@@ -198,18 +186,6 @@ trait SpaceLogic {
198186
if (!isEqualType(tp1, tp2)) Empty
199187
else if (ss1.zip(ss2).exists(p => simplify(intersect(p._1, p._2)) == Empty)) Empty
200188
else Kon(tp1, ss1.zip(ss2).map((intersect _).tupled))
201-
case (Const(v1, _), Const(v2, _)) =>
202-
if (v1 == v2) a else Empty
203-
case (Const(_, tp1), Typ(tp2, _)) =>
204-
if (isSubType(tp1, tp2)) a
205-
else if (canDecompose(tp2)) tryDecompose2(tp2)
206-
else Empty
207-
case (Const(_, _), _) => Empty
208-
case (Typ(tp1, _), Const(_, tp2)) =>
209-
if (isSubType(tp2, tp1)) b
210-
else if (canDecompose(tp1)) tryDecompose1(tp1)
211-
else Empty
212-
case (_, Const(_, _)) => Empty
213189
}
214190

215191
debug.println(s"${show(a)} & ${show(b)} = ${show(res)}")
@@ -255,17 +231,6 @@ trait SpaceLogic {
255231
Or(ss1.zip(ss2).map((minus _).tupled).zip(0 to ss2.length - 1).map {
256232
case (ri, i) => Kon(tp1, ss1.updated(i, ri))
257233
})
258-
case (Const(v1, _), Const(v2, _)) =>
259-
if (v1 == v2) Empty else a
260-
case (Const(_, tp1), Typ(tp2, _)) =>
261-
if (isSubType(tp1, tp2)) Empty
262-
else if (canDecompose(tp2)) tryDecompose2(tp2)
263-
else a
264-
case (Const(_, _), _) => a
265-
case (Typ(tp1, _), Const(_, tp2)) => // Boolean & Java enum
266-
if (canDecompose(tp1)) tryDecompose1(tp1)
267-
else a
268-
case (_, Const(_, _)) => a
269234
}
270235

271236
debug.println(s"${show(a)} - ${show(b)} = ${show(res)}")
@@ -284,17 +249,14 @@ class SpaceEngine(implicit ctx: Context) extends SpaceLogic {
284249
* otherwise approximate extractors to Empty
285250
*/
286251
def project(pat: Tree, roundUp: Boolean = true)(implicit ctx: Context): Space = pat match {
287-
case Literal(c) => Const(c, c.tpe)
252+
case Literal(c) =>
253+
if (c.value.isInstanceOf[Symbol])
254+
Typ(c.value.asInstanceOf[Symbol].termRef, false)
255+
else
256+
Typ(ConstantType(c), false)
288257
case _: BackquotedIdent => Typ(pat.tpe, false)
289258
case Ident(_) | Select(_, _) =>
290-
pat.tpe.stripAnnots match {
291-
case tp: TermRef =>
292-
if (pat.symbol.is(Enum))
293-
Const(Constant(pat.symbol), tp)
294-
else
295-
Typ(tp, false)
296-
case tp => Typ(tp, false)
297-
}
259+
Typ(pat.tpe.stripAnnots, false)
298260
case Alternative(trees) => Or(trees.map(project(_, roundUp)))
299261
case Bind(_, pat) => project(pat)
300262
case UnApply(_, _, pats) =>
@@ -366,11 +328,11 @@ class SpaceEngine(implicit ctx: Context) extends SpaceLogic {
366328
case OrType(tp1, tp2) => List(Typ(tp1, true), Typ(tp2, true))
367329
case _ if tp =:= ctx.definitions.BooleanType =>
368330
List(
369-
Const(Constant(true), ctx.definitions.BooleanType),
370-
Const(Constant(false), ctx.definitions.BooleanType)
331+
Typ(ConstantType(Constant(true)), true),
332+
Typ(ConstantType(Constant(false)), true)
371333
)
372334
case _ if tp.classSymbol.is(Enum) =>
373-
children.map(sym => Const(Constant(sym), tp))
335+
children.map(sym => Typ(sym.termRef, true))
374336
case _ =>
375337
val parts = children.map { sym =>
376338
if (sym.is(ModuleClass))
@@ -419,7 +381,7 @@ class SpaceEngine(implicit ctx: Context) extends SpaceLogic {
419381
tp.classSymbol.is(allOf(Trait, Sealed)) ||
420382
tp.isInstanceOf[OrType] ||
421383
tp =:= ctx.definitions.BooleanType ||
422-
tp.classSymbol.is(Enum)
384+
tp.classSymbol.is(allOf(Enum, Sealed)) // Enum value doesn't have Sealed flag
423385

424386
debug.println(s"decomposable: ${tp.show} = $res")
425387

@@ -475,7 +437,7 @@ class SpaceEngine(implicit ctx: Context) extends SpaceLogic {
475437
def show(s: Space): String = {
476438
def doShow(s: Space, mergeList: Boolean = false): String = s match {
477439
case Empty => ""
478-
case Const(v, _) => v.show
440+
case Typ(c: ConstantType, _) => c.value.show
479441
case Typ(tp: TermRef, _) => tp.symbol.showName
480442
case Typ(tp, decomposed) =>
481443
val sym = tp.widen.classSymbol

0 commit comments

Comments
 (0)