Skip to content

Commit dd98d4a

Browse files
Merge pull request #8928 from dotty-staging/fix-8922
Fix #8922: Performance tweak for space computation
2 parents 5d5a3dd + 12f2778 commit dd98d4a

File tree

19 files changed

+489
-28
lines changed

19 files changed

+489
-28
lines changed

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

Lines changed: 23 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -167,7 +167,7 @@ trait SpaceLogic {
167167
def tryDecompose1(tp: Type) = canDecompose(tp) && isSubspace(Or(decompose(tp)), b)
168168
def tryDecompose2(tp: Type) = canDecompose(tp) && isSubspace(a, Or(decompose(tp)))
169169

170-
(simplify(a), b) match {
170+
(simplify(a), simplify(b)) match {
171171
case (Empty, _) => true
172172
case (_, Empty) => false
173173
case (Or(ss), _) =>
@@ -262,15 +262,21 @@ trait SpaceLogic {
262262
case (Typ(tp1, _), Prod(tp2, _, _, false)) =>
263263
a // approximation
264264
case (Prod(tp1, fun1, ss1, full), Prod(tp2, fun2, ss2, _)) =>
265-
if (!isSameUnapply(fun1, fun2)) a
266-
else if (ss1.zip(ss2).exists(p => simplify(intersect(p._1, p._2)) == Empty)) a
267-
else if (ss1.zip(ss2).forall((isSubspace _).tupled)) Empty
265+
if (!isSameUnapply(fun1, fun2)) return a
266+
267+
val range = (0 until ss1.size).toList
268+
val cache = Array.fill[Space](ss2.length)(null)
269+
def sub(i: Int) =
270+
if cache(i) == null then
271+
cache(i) = minus(ss1(i), ss2(i))
272+
cache(i)
273+
end sub
274+
275+
if range.exists(i => isSubspace(ss1(i), sub(i))) then a
276+
else if cache.forall(sub => isSubspace(sub, Empty)) then Empty
268277
else
269278
// `(_, _, _) - (Some, None, _)` becomes `(None, _, _) | (_, Some, _) | (_, _, Empty)`
270-
Or(ss1.zip(ss2).map((minus _).tupled).zip(0 to ss2.length - 1).map {
271-
case (ri, i) => Prod(tp1, fun1, ss1.updated(i, ri), full)
272-
})
273-
279+
Or(range.map { i => Prod(tp1, fun1, ss1.updated(i, sub(i)), full) })
274280
}
275281
}
276282
}
@@ -728,6 +734,7 @@ class SpaceEngine(implicit ctx: Context) extends SpaceLogic {
728734
checkConstraint(genConstraint(sp))(ctx.fresh.setNewTyperState())
729735
}
730736

737+
def show(ss: Seq[Space]): String = ss.map(show).mkString(", ")
731738
/** Display spaces */
732739
def show(s: Space): String = {
733740
def params(tp: Type): List[Type] = tp.classSymbol.primaryConstructor.info.firstParamTypes
@@ -740,7 +747,7 @@ class SpaceEngine(implicit ctx: Context) extends SpaceLogic {
740747
}
741748

742749
def doShow(s: Space, flattenList: Boolean = false): String = s match {
743-
case Empty => ""
750+
case Empty => "empty"
744751
case Typ(c: ConstantType, _) => "" + c.value.value
745752
case Typ(tp: TermRef, _) =>
746753
if (flattenList && tp <:< scalaNilType) ""
@@ -773,11 +780,11 @@ class SpaceEngine(implicit ctx: Context) extends SpaceLogic {
773780
val paramsStr = params.map(doShow(_, flattenList = isUnapplySeq)).mkString("(", ", ", ")")
774781
showType(fun.prefix) + paramsStr
775782
}
776-
case Or(_) =>
777-
throw new Exception("incorrect flatten result " + s)
783+
case Or(ss) =>
784+
ss.map(doShow(_, flattenList)).mkString(" | ")
778785
}
779786

780-
flatten(s).map(doShow(_, flattenList = false)).distinct.mkString(", ")
787+
doShow(s, flattenList = false)
781788
}
782789

783790
private def exhaustivityCheckable(sel: Tree): Boolean = {
@@ -817,11 +824,11 @@ class SpaceEngine(implicit ctx: Context) extends SpaceLogic {
817824

818825
if (!exhaustivityCheckable(sel)) return
819826

820-
val patternSpace = cases.map({ x =>
827+
val patternSpace = Or(cases.foldLeft(List.empty[Space]) { (acc, x) =>
821828
val space = if (x.guard.isEmpty) project(x.pat) else Empty
822829
debug.println(s"${x.pat.show} ====> ${show(space)}")
823-
space
824-
}).reduce((a, b) => Or(List(a, b)))
830+
space :: acc
831+
})
825832

826833
val checkGADTSAT = shouldCheckExamples(selTyp)
827834

@@ -831,7 +838,7 @@ class SpaceEngine(implicit ctx: Context) extends SpaceLogic {
831838
}
832839

833840
if (uncovered.nonEmpty)
834-
ctx.warning(PatternMatchExhaustivity(show(Or(uncovered))), sel.sourcePos)
841+
ctx.warning(PatternMatchExhaustivity(show(uncovered)), sel.sourcePos)
835842
}
836843

837844
private def redundancyCheckable(sel: Tree): Boolean =
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
case class Token(tokenType: TokenType, lexeme: StringV, line: IntV)
2+
3+
sealed trait TokenType
4+
// Single-character tokens.
5+
object MINUS extends TokenType
6+
object PLUS extends TokenType
7+
object SLASH extends TokenType
8+
object STAR extends TokenType
9+
object BANG extends TokenType
10+
object BANG_EQUAL extends TokenType
11+
object EQUAL extends TokenType
12+
object EQUAL_EQUAL extends TokenType
13+
object GREATER extends TokenType
14+
object GREATER_EQUAL extends TokenType
15+
object LESS extends TokenType
16+
object LESS_EQUAL extends TokenType
17+
18+
sealed trait Expr
19+
case class Binary(left: Expr, operator: Token, right: Expr) extends Expr
20+
21+
sealed trait Value
22+
case class StringV(v: String) extends Value
23+
case class IntV(v: Int) extends Value
24+
case class DoubleV(v: Double) extends Value
25+
case class BooleanV(v: Boolean) extends Value
26+
case class UnitV() extends Value
27+
28+
object Interpreter {
29+
def eval(expr: Expr): Value =
30+
expr match {
31+
case Binary(left, op, right) =>
32+
val l = eval(left)
33+
val r = eval(right)
34+
(l, r, op.tokenType) match { // error
35+
case (l: DoubleV, r: DoubleV, PLUS) => ???
36+
case (l: IntV, r: IntV, PLUS) => ???
37+
case (l: DoubleV, r: IntV, PLUS) => ???
38+
case (l: IntV, r: DoubleV, PLUS) => ???
39+
case (l: StringV, r: StringV, PLUS) => ???
40+
case (l: DoubleV, r: DoubleV, MINUS) => ???
41+
case (l: IntV, r: IntV, MINUS) => ???
42+
case (l: DoubleV, r: IntV, MINUS) => ???
43+
case (l: IntV, r: DoubleV, MINUS) => ???
44+
case (l: DoubleV, r: DoubleV, STAR) => ???
45+
case (l: IntV, r: IntV, STAR) => ???
46+
case (l: DoubleV, r: IntV, STAR) => ???
47+
case (l: IntV, r: DoubleV, STAR) => ???
48+
case (l: DoubleV, r: DoubleV, SLASH) => ???
49+
case (l: IntV, r: IntV, SLASH) => ???
50+
case (l: DoubleV, r: IntV, SLASH) => ???
51+
case (l: IntV, r: DoubleV, SLASH) => ???
52+
case (l: DoubleV, r: DoubleV, GREATER) => ???
53+
case (l: IntV, r: IntV, GREATER) => ???
54+
case (l: DoubleV, r: IntV, GREATER) => ???
55+
case (l: IntV, r: DoubleV, GREATER) => ???
56+
case (l: StringV, r: StringV, GREATER) => ???
57+
case (l: DoubleV, r: DoubleV, LESS) => ???
58+
case (l: IntV, r: IntV, LESS) => ???
59+
case (l: DoubleV, r: IntV, LESS) => ???
60+
case (l: IntV, r: DoubleV, LESS) => ???
61+
case (l: StringV, r: StringV, LESS) => ???
62+
case (l: DoubleV, r: DoubleV, LESS_EQUAL) => ???
63+
case (l: IntV, r: IntV, LESS_EQUAL) => ???
64+
case (l: DoubleV, r: IntV, LESS_EQUAL) => ???
65+
case (l: IntV, r: DoubleV, LESS_EQUAL) => ???
66+
case (l: StringV, r: StringV, LESS_EQUAL) => ???
67+
case (l: DoubleV, r: DoubleV, GREATER_EQUAL) => ???
68+
case (l: IntV, r: IntV, GREATER_EQUAL) => ???
69+
case (l: DoubleV, r: IntV, GREATER_EQUAL) => ???
70+
case (l: IntV, r: DoubleV, GREATER_EQUAL) => ???
71+
case (l: StringV, r: StringV, GREATER_EQUAL) => ???
72+
// case _ => ???
73+
}
74+
}
75+
76+
}

tests/patmat/gadt-covariant.check

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
6: Pattern Match Exhaustivity: (BExpr(_), IExpr(_)), (IExpr(_), BExpr(_))
1+
6: Pattern Match Exhaustivity: (IExpr(_), BExpr(_)), (BExpr(_), IExpr(_))

tests/patmat/gadt4.check

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
12: Pattern Match Exhaustivity: (VC(_, _), VN()), (VN(), VC(_, _))
1+
12: Pattern Match Exhaustivity: (VN(), VC(_, _)), (VC(_, _), VN())

tests/patmat/gadt5.check

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
63: Pattern Match Exhaustivity: (Try3.VC(_, _), Try3.VN()), (Try3.VN(), Try3.VC(_, _))
1+
63: Pattern Match Exhaustivity: (Try3.VN(), Try3.VC(_, _)), (Try3.VC(_, _), Try3.VN())

0 commit comments

Comments
 (0)