@@ -55,7 +55,16 @@ import collection.mutable
55
55
56
56
57
57
/** 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
59
68
60
69
/** Empty space */
61
70
case object Empty extends Space
@@ -349,13 +358,6 @@ object SpaceEngine {
349
358
class SpaceEngine (using Context ) extends SpaceLogic {
350
359
import tpd ._
351
360
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
-
359
361
override def intersectUnrelatedAtomicTypes (tp1 : Type , tp2 : Type ): Space = trace(s " atomic intersection: ${AndType (tp1, tp2).show}" , debug) {
360
362
// Precondition: !isSubType(tp1, tp2) && !isSubType(tp2, tp1).
361
363
if ! ctx.mode.is(Mode .SafeNulls ) && (tp1.isNullType || tp2.isNullType) then
@@ -398,7 +400,7 @@ class SpaceEngine(using Context) extends SpaceLogic {
398
400
val funRef = fun1.tpe.asInstanceOf [TermRef ]
399
401
if (fun.symbol.name == nme.unapplySeq)
400
402
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)
402
404
// The exhaustivity and reachability logic already handles decomposing sum types (into its subclasses)
403
405
// and product types (into its components). To get better counter-examples for patterns that are of type
404
406
// 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 {
519
521
/** Space of the pattern: unapplySeq(a, b, c: _*)
520
522
*/
521
523
def projectSeq (pats : List [Tree ]): Space = {
522
- if (pats.isEmpty) return Typ (scalaNilType , false )
524
+ if (pats.isEmpty) return Typ (defn. NilType , false )
523
525
524
526
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 ))
526
528
else
527
- (pats, Typ (scalaNilType , false ))
529
+ (pats, Typ (defn. NilType , false ))
528
530
529
- val unapplyTp = scalaConsType .classSymbol.companionModule.termRef.select(nme.unapply)
531
+ val unapplyTp = defn. ConsType .classSymbol.companionModule.termRef.select(nme.unapply)
530
532
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)
532
534
Prod (consTp, unapplyTp, project(pat) :: acc :: Nil )
533
535
}
534
536
}
@@ -538,13 +540,14 @@ class SpaceEngine(using Context) extends SpaceLogic {
538
540
539
541
private val isSubspaceCache = mutable.HashMap .empty[(Space , Space , Context ), Boolean ]
540
542
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)
543
546
544
547
/** Is `tp1` a subtype of `tp2`? */
545
548
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 ))
548
551
else tp1 <:< tp2
549
552
}
550
553
@@ -593,10 +596,10 @@ class SpaceEngine(using Context) extends SpaceLogic {
593
596
594
597
if (isUnapplySeq) {
595
598
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
597
600
else {
598
601
val sels = productSeqSelectors(resultTp, arity, unappSym.srcPos)
599
- sels.init :+ scalaListType .appliedTo(sels.last)
602
+ sels.init :+ defn. ListType .appliedTo(sels.last)
600
603
}
601
604
}
602
605
else {
@@ -821,17 +824,17 @@ class SpaceEngine(using Context) extends SpaceLogic {
821
824
case Empty => " empty"
822
825
case Typ (c : ConstantType , _) => " " + c.value.value
823
826
case Typ (tp : TermRef , _) =>
824
- if (flattenList && tp <:< scalaNilType ) " "
827
+ if (flattenList && tp <:< defn. NilType ) " "
825
828
else tp.symbol.showName
826
829
case Typ (tp, decomposed) =>
827
830
828
831
val sym = tp.classSymbol
829
832
830
833
if (ctx.definitions.isTupleNType(tp))
831
834
params(tp).map(_ => " _" ).mkString(" (" , " , " , " )" )
832
- else if (scalaListType .isRef(sym))
835
+ else if (defn. ListType .isRef(sym))
833
836
if (flattenList) " _*" else " _: List"
834
- else if (scalaConsType .isRef(sym))
837
+ else if (defn. ConsType .isRef(sym))
835
838
if (flattenList) " _, _*" else " List(_, _*)"
836
839
else if (tp.classSymbol.is(Sealed ) && tp.classSymbol.hasAnonymousChild)
837
840
" _: " + showType(tp) + " (anonymous)"
@@ -843,7 +846,7 @@ class SpaceEngine(using Context) extends SpaceLogic {
843
846
case Prod (tp, fun, params) =>
844
847
if (ctx.definitions.isTupleNType(tp))
845
848
" (" + params.map(doShow(_)).mkString(" , " ) + " )"
846
- else if (tp.isRef(scalaConsType .symbol))
849
+ else if (tp.isRef(defn. ConsType .symbol))
847
850
if (flattenList) params.map(doShow(_, flattenList)).filter(_.nonEmpty).mkString(" , " )
848
851
else params.map(doShow(_, flattenList = true )).filter(! _.isEmpty).mkString(" List(" , " , " , " )" )
849
852
else {
@@ -961,7 +964,7 @@ class SpaceEngine(using Context) extends SpaceLogic {
961
964
962
965
val isNullable = selTyp.classSymbol.isNullableClass
963
966
val targetSpace = if isNullable
964
- then project(OrType (selTyp, constantNullType , soft = false ))
967
+ then project(OrType (selTyp, ConstantType ( Constant ( null )) , soft = false ))
965
968
else project(selTyp)
966
969
debug.println(s " targetSpace: ${show(targetSpace)}" )
967
970
0 commit comments