From 01d8eadb92473754dac89b344dc2078c9803bc0e Mon Sep 17 00:00:00 2001 From: Jan Chyb Date: Mon, 7 Jul 2025 11:02:34 +0200 Subject: [PATCH] Extend caching in the space engine beyond local context Previously isSubspace calls would be cached only as part of individual Space object, so when recursing through their ADT contents, we were not able to reuse the previously computed information. Now the cache is shared across the whole space engine run. --- .../tools/dotc/transform/patmat/Space.scala | 14 ++++++---- tests/pos/i23317.scala | 26 +++++++++++++++++++ 2 files changed, 35 insertions(+), 5 deletions(-) create mode 100644 tests/pos/i23317.scala diff --git a/compiler/src/dotty/tools/dotc/transform/patmat/Space.scala b/compiler/src/dotty/tools/dotc/transform/patmat/Space.scala index ab5885e6278c..8514c897d01e 100644 --- a/compiler/src/dotty/tools/dotc/transform/patmat/Space.scala +++ b/compiler/src/dotty/tools/dotc/transform/patmat/Space.scala @@ -48,11 +48,12 @@ import SpaceEngine.* * */ +/** A key to be used in a context property that caches the unpickled trees */ +private val IsSubspaceCacheKey = new Property.Key[mutable.HashMap[(Space, Space), Boolean]] + /** space definition */ sealed trait Space extends Showable: - @sharable private val isSubspaceCache = mutable.HashMap.empty[Space, Boolean] - def isSubspace(b: Space)(using Context): Boolean = val a = this val a2 = a.simplify @@ -60,7 +61,8 @@ sealed trait Space extends Showable: if (a ne a2) || (b ne b2) then a2.isSubspace(b2) else if a == Empty then true else if b == Empty then false - else isSubspaceCache.getOrElseUpdate(b, computeIsSubspace(a, b)) + else + ctx.property(IsSubspaceCacheKey).get.getOrElseUpdate((a, b), computeIsSubspace(a, b)) @sharable private var mySimplified: Space | Null = null @@ -968,6 +970,8 @@ object SpaceEngine { end checkReachability def checkMatch(m: Match)(using Context): Unit = - if exhaustivityCheckable(m.selector) then checkExhaustivity(m) - if reachabilityCheckable(m.selector) then checkReachability(m) + inContext(ctx.withProperty(IsSubspaceCacheKey, Some(mutable.HashMap.empty))) { + if exhaustivityCheckable(m.selector) then checkExhaustivity(m) + if reachabilityCheckable(m.selector) then checkReachability(m) + } } diff --git a/tests/pos/i23317.scala b/tests/pos/i23317.scala new file mode 100644 index 000000000000..1381aad452d2 --- /dev/null +++ b/tests/pos/i23317.scala @@ -0,0 +1,26 @@ +import scala.quoted.* + +def goImpl(using Quotes): Expr[Int] = + List.empty[Type[?]] match + case Nil => + Expr(0) + case '[t1] :: Nil => + Expr(1) + case '[t1] :: '[t2] :: Nil => + Expr(2) + case '[t1] :: '[t2] :: '[t3] :: Nil => + Expr(3) + case '[t1] :: '[t2] :: '[t3] :: '[t4] :: Nil => + Expr(4) + case '[t1] :: '[t2] :: '[t3] :: '[t4] :: '[t5] :: Nil => + Expr(5) + case '[t1] :: '[t2] :: '[t3] :: '[t4] :: '[t5] :: '[t6] :: Nil => + Expr(6) + case '[t1] :: '[t2] :: '[t3] :: '[t4] :: '[t5] :: '[t6] :: '[t7] :: Nil => + Expr(7) + case '[t1] :: '[t2] :: '[t3] :: '[t4] :: '[t5] :: '[t6] :: '[t7] :: '[t8] :: Nil => + Expr(8) + case '[t1] :: '[t2] :: '[t3] :: '[t4] :: '[t5] :: '[t6] :: '[t7] :: '[t8] :: '[t9] :: Nil => + Expr(9) + case _ => + Expr(999)