Skip to content

Commit a0ec2dc

Browse files
committed
Space: Move isSubspace cache to Space instance
This is in preparation for making SpaceEngine an object, so also remove the other vals too.
1 parent 5817920 commit a0ec2dc

File tree

3 files changed

+32
-26
lines changed

3 files changed

+32
-26
lines changed

compiler/src/dotty/tools/dotc/core/Definitions.scala

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -530,9 +530,12 @@ class Definitions {
530530
})
531531

532532
@tu lazy val ListClass: Symbol = requiredClass("scala.collection.immutable.List")
533+
def ListType: TypeRef = ListClass.typeRef
533534
@tu lazy val ListModule: Symbol = requiredModule("scala.collection.immutable.List")
534535
@tu lazy val NilModule: Symbol = requiredModule("scala.collection.immutable.Nil")
536+
def NilType: TermRef = NilModule.termRef
535537
@tu lazy val ConsClass: Symbol = requiredClass("scala.collection.immutable.::")
538+
def ConsType: TypeRef = ConsClass.typeRef
536539
@tu lazy val SeqFactoryClass: Symbol = requiredClass("scala.collection.SeqFactory")
537540

538541
@tu lazy val SingletonClass: ClassSymbol =

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

Lines changed: 28 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,16 @@ import collection.mutable
5555

5656

5757
/** space definition */
58-
sealed trait Space
58+
sealed trait Space:
59+
private val isSubspaceCache = mutable.HashMap.empty[Space, Boolean]
60+
61+
def isSubspace(b: Space)(engine: SpaceEngine)(using Context): Boolean =
62+
if this == Empty then true
63+
else if b == Empty then false
64+
else trace(s"isSubspace(${engine.show(this)}, ${engine.show(b)})", debug) {
65+
isSubspaceCache.getOrElseUpdate(b, engine.computeIsSubspace(this, b))
66+
}
67+
end Space
5968

6069
/** Empty space */
6170
case object Empty extends Space
@@ -349,13 +358,6 @@ object SpaceEngine {
349358
class SpaceEngine(using Context) extends SpaceLogic {
350359
import tpd._
351360

352-
private val scalaSeqFactoryClass = defn.SeqFactoryClass
353-
private val scalaListType = defn.ListClass.typeRef
354-
private val scalaNilType = defn.NilModule.termRef
355-
private val scalaConsType = defn.ConsClass.typeRef
356-
357-
private val constantNullType = ConstantType(Constant(null))
358-
359361
override def intersectUnrelatedAtomicTypes(tp1: Type, tp2: Type): Space = trace(s"atomic intersection: ${AndType(tp1, tp2).show}", debug) {
360362
// Precondition: !isSubType(tp1, tp2) && !isSubType(tp2, tp1).
361363
if !ctx.mode.is(Mode.SafeNulls) && (tp1.isNullType || tp2.isNullType) then
@@ -398,7 +400,7 @@ class SpaceEngine(using Context) extends SpaceLogic {
398400
val funRef = fun1.tpe.asInstanceOf[TermRef]
399401
if (fun.symbol.name == nme.unapplySeq)
400402
val (arity, elemTp, resultTp) = unapplySeqInfo(fun.tpe.widen.finalResultType, fun.srcPos)
401-
if (fun.symbol.owner == scalaSeqFactoryClass && scalaListType.appliedTo(elemTp) <:< pat.tpe)
403+
if (fun.symbol.owner == defn.SeqFactoryClass && defn.ListType.appliedTo(elemTp) <:< pat.tpe)
402404
// The exhaustivity and reachability logic already handles decomposing sum types (into its subclasses)
403405
// and product types (into its components). To get better counter-examples for patterns that are of type
404406
// List (or a super-type of list, like LinearSeq) we project them into spaces that use `::` and Nil.
@@ -519,16 +521,16 @@ class SpaceEngine(using Context) extends SpaceLogic {
519521
/** Space of the pattern: unapplySeq(a, b, c: _*)
520522
*/
521523
def projectSeq(pats: List[Tree]): Space = {
522-
if (pats.isEmpty) return Typ(scalaNilType, false)
524+
if (pats.isEmpty) return Typ(defn.NilType, false)
523525

524526
val (items, zero) = if (isWildcardStarArg(pats.last))
525-
(pats.init, Typ(scalaListType.appliedTo(pats.last.tpe.elemType), false))
527+
(pats.init, Typ(defn.ListType.appliedTo(pats.last.tpe.elemType), false))
526528
else
527-
(pats, Typ(scalaNilType, false))
529+
(pats, Typ(defn.NilType, false))
528530

529-
val unapplyTp = scalaConsType.classSymbol.companionModule.termRef.select(nme.unapply)
531+
val unapplyTp = defn.ConsType.classSymbol.companionModule.termRef.select(nme.unapply)
530532
items.foldRight[Space](zero) { (pat, acc) =>
531-
val consTp = scalaConsType.appliedTo(pats.head.tpe.widen)
533+
val consTp = defn.ConsType.appliedTo(pats.head.tpe.widen)
532534
Prod(consTp, unapplyTp, project(pat) :: acc :: Nil)
533535
}
534536
}
@@ -538,13 +540,14 @@ class SpaceEngine(using Context) extends SpaceLogic {
538540

539541
private val isSubspaceCache = mutable.HashMap.empty[(Space, Space, Context), Boolean]
540542

541-
override def isSubspace(a: Space, b: Space)(using Context): Boolean =
542-
isSubspaceCache.getOrElseUpdate((a, b, ctx), super.isSubspace(a, b))
543+
override def isSubspace(a: Space, b: Space)(using Context): Boolean = a.isSubspace(b)(this)
544+
545+
def computeIsSubspace(a: Space, b: Space)(using Context): Boolean = super.isSubspace(a, b)
543546

544547
/** Is `tp1` a subtype of `tp2`? */
545548
def isSubType(tp1: Type, tp2: Type): Boolean = trace(i"$tp1 <:< $tp2", debug, show = true) {
546-
if tp1 == constantNullType && !ctx.mode.is(Mode.SafeNulls)
547-
then tp2 == constantNullType
549+
if tp1 == ConstantType(Constant(null)) && !ctx.mode.is(Mode.SafeNulls)
550+
then tp2 == ConstantType(Constant(null))
548551
else tp1 <:< tp2
549552
}
550553

@@ -593,10 +596,10 @@ class SpaceEngine(using Context) extends SpaceLogic {
593596

594597
if (isUnapplySeq) {
595598
val (arity, elemTp, resultTp) = unapplySeqInfo(resTp, unappSym.srcPos)
596-
if (elemTp.exists) scalaListType.appliedTo(elemTp) :: Nil
599+
if (elemTp.exists) defn.ListType.appliedTo(elemTp) :: Nil
597600
else {
598601
val sels = productSeqSelectors(resultTp, arity, unappSym.srcPos)
599-
sels.init :+ scalaListType.appliedTo(sels.last)
602+
sels.init :+ defn.ListType.appliedTo(sels.last)
600603
}
601604
}
602605
else {
@@ -821,17 +824,17 @@ class SpaceEngine(using Context) extends SpaceLogic {
821824
case Empty => "empty"
822825
case Typ(c: ConstantType, _) => "" + c.value.value
823826
case Typ(tp: TermRef, _) =>
824-
if (flattenList && tp <:< scalaNilType) ""
827+
if (flattenList && tp <:< defn.NilType) ""
825828
else tp.symbol.showName
826829
case Typ(tp, decomposed) =>
827830

828831
val sym = tp.classSymbol
829832

830833
if (ctx.definitions.isTupleNType(tp))
831834
params(tp).map(_ => "_").mkString("(", ", ", ")")
832-
else if (scalaListType.isRef(sym))
835+
else if (defn.ListType.isRef(sym))
833836
if (flattenList) "_*" else "_: List"
834-
else if (scalaConsType.isRef(sym))
837+
else if (defn.ConsType.isRef(sym))
835838
if (flattenList) "_, _*" else "List(_, _*)"
836839
else if (tp.classSymbol.is(Sealed) && tp.classSymbol.hasAnonymousChild)
837840
"_: " + showType(tp) + " (anonymous)"
@@ -843,7 +846,7 @@ class SpaceEngine(using Context) extends SpaceLogic {
843846
case Prod(tp, fun, params) =>
844847
if (ctx.definitions.isTupleNType(tp))
845848
"(" + params.map(doShow(_)).mkString(", ") + ")"
846-
else if (tp.isRef(scalaConsType.symbol))
849+
else if (tp.isRef(defn.ConsType.symbol))
847850
if (flattenList) params.map(doShow(_, flattenList)).filter(_.nonEmpty).mkString(", ")
848851
else params.map(doShow(_, flattenList = true)).filter(!_.isEmpty).mkString("List(", ", ", ")")
849852
else {
@@ -961,7 +964,7 @@ class SpaceEngine(using Context) extends SpaceLogic {
961964

962965
val isNullable = selTyp.classSymbol.isNullableClass
963966
val targetSpace = if isNullable
964-
then project(OrType(selTyp, constantNullType, soft = false))
967+
then project(OrType(selTyp, ConstantType(Constant(null)), soft = false))
965968
else project(selTyp)
966969
debug.println(s"targetSpace: ${show(targetSpace)}")
967970

compiler/test/dotty/tools/dotc/transform/patmat/SpaceEngineTest.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ class SpaceEngineTest:
2020
val engine = patmat.SpaceEngine()
2121
import engine.*
2222

23-
val tp = defn.ConsClass.typeRef.appliedTo(defn.AnyType)
23+
val tp = defn.ConsType.appliedTo(defn.AnyType)
2424
val unappTp = requiredMethod("scala.collection.immutable.::.unapply").termRef
2525
val params = List(Empty, Typ(tp))
2626

0 commit comments

Comments
 (0)