@@ -51,12 +51,15 @@ sealed abstract class CaptureSet extends Showable:
5151 /** Is this capture set constant (i.e. not an unsolved capture variable)?
5252 * Solved capture variables count as constant.
5353 */
54- def isConst : Boolean
54+ def isConst ( using Context ) : Boolean
5555
5656 /** Is this capture set always empty? For unsolved capture veriables, returns
5757 * always false.
5858 */
59- def isAlwaysEmpty : Boolean
59+ def isAlwaysEmpty (using Context ): Boolean
60+
61+ /** Is this set provisionally solved, so that another cc run might unfreeze it? */
62+ def isProvisionallySolved (using Context ): Boolean
6063
6164 /** An optional level limit, or undefinedLevel if none exists. All elements of the set
6265 * must be at levels equal or smaller than the level of the set, if it is defined.
@@ -71,14 +74,14 @@ sealed abstract class CaptureSet extends Showable:
7174 final def isNotEmpty : Boolean = ! elems.isEmpty
7275
7376 /** Convert to Const. @pre: isConst */
74- def asConst : Const = this match
77+ def asConst ( using Context ) : Const = this match
7578 case c : Const => c
7679 case v : Var =>
7780 assert(v.isConst)
7881 Const (v.elems)
7982
8083 /** Cast to variable. @pre: !isConst */
81- def asVar : Var =
84+ def asVar ( using Context ) : Var =
8285 assert(! isConst)
8386 asInstanceOf [Var ]
8487
@@ -316,23 +319,29 @@ sealed abstract class CaptureSet extends Showable:
316319 * `OtherMapped` provides some approximation to a solution, but it is neither
317320 * sound nor complete.
318321 */
319- def map (tm : TypeMap )(using Context ): CaptureSet = tm match
320- case tm : BiTypeMap =>
321- val mappedElems = elems.map(tm.forward)
322- if isConst then
323- if mappedElems == elems then this
324- else Const (mappedElems)
325- else BiMapped (asVar, tm, mappedElems)
326- case tm : IdentityCaptRefMap =>
327- this
328- case tm : AvoidMap if this .isInstanceOf [HiddenSet ] =>
329- this
330- case _ =>
331- val mapped = mapRefs(elems, tm, tm.variance)
332- if isConst then
333- if mapped.isConst && mapped.elems == elems && ! mapped.keepAlways then this
334- else mapped
335- else Mapped (asVar, tm, tm.variance, mapped)
322+ def map (tm : TypeMap )(using Context ): CaptureSet =
323+ def freeze () = this match
324+ case self : Var if ! isConst && ccConfig.newScheme =>
325+ if tm.variance < 0 then self.solve()
326+ else self.markSolved(provisional = true )
327+ case _ =>
328+ tm match
329+ case tm : BiTypeMap =>
330+ val mappedElems = elems.map(tm.forward)
331+ if isConst then
332+ if mappedElems == elems then this
333+ else Const (mappedElems)
334+ else BiMapped (asVar, tm, mappedElems)
335+ case tm : IdentityCaptRefMap =>
336+ this
337+ case tm : AvoidMap if this .isInstanceOf [HiddenSet ] =>
338+ this
339+ case _ =>
340+ val mapped = mapRefs(elems, tm, tm.variance)
341+ if isConst then
342+ if mapped.isConst && mapped.elems == elems && ! mapped.keepAlways then this
343+ else mapped
344+ else Mapped (asVar, tm, tm.variance, mapped)
336345
337346 /** A mapping resulting from substituting parameters of a BindingType to a list of types */
338347 def substParams (tl : BindingType , to : List [Type ])(using Context ) =
@@ -368,7 +377,7 @@ sealed abstract class CaptureSet extends Showable:
368377 * to this set. This might result in the set being solved to be constant
369378 * itself.
370379 */
371- protected def propagateSolved ()(using Context ): Unit = ()
380+ protected def propagateSolved (provisional : Boolean )(using Context ): Unit = ()
372381
373382 /** This capture set with a description that tells where it comes from */
374383 def withDescription (description : String ): CaptureSet
@@ -438,8 +447,9 @@ object CaptureSet:
438447
439448 /** The subclass of constant capture sets with given elements `elems` */
440449 class Const private [CaptureSet ] (val elems : Refs , val description : String = " " ) extends CaptureSet :
441- def isConst = true
442- def isAlwaysEmpty = elems.isEmpty
450+ def isConst (using Context ) = true
451+ def isAlwaysEmpty (using Context ) = elems.isEmpty
452+ def isProvisionallySolved (using Context ) = false
443453
444454 def addThisElem (elem : CaptureRef )(using Context , VarState ): CompareResult =
445455 addIfHiddenOrFail(elem)
@@ -470,7 +480,7 @@ object CaptureSet:
470480 * were not yet compiled with capture checking on.
471481 */
472482 object Fluid extends Const (emptyRefs):
473- override def isAlwaysEmpty = false
483+ override def isAlwaysEmpty ( using Context ) = false
474484 override def addThisElem (elem : CaptureRef )(using Context , VarState ) = CompareResult .OK
475485 override def accountsFor (x : CaptureRef )(using Context , VarState ): Boolean = true
476486 override def mightAccountFor (x : CaptureRef )(using Context ): Boolean = true
@@ -489,8 +499,13 @@ object CaptureSet:
489499
490500 // assert(id != 40)
491501
492- /** A variable is solved if it is aproximated to a from-then-on constant set. */
493- private var isSolved : Boolean = false
502+ /** A variable is solved if it is aproximated to a from-then-on constant set.
503+ * Interpretation:
504+ * 0 not solved
505+ * Int.MaxValue definitively solved
506+ * n > 0 provisionally solved in iteration n
507+ */
508+ private var solved : Int = 0
494509
495510 /** The elements currently known to be in the set */
496511 protected var myElems : Refs = initialElems
@@ -503,8 +518,9 @@ object CaptureSet:
503518 */
504519 var deps : Deps = SimpleIdentitySet .empty
505520
506- def isConst = isSolved
507- def isAlwaysEmpty = isSolved && elems.isEmpty
521+ def isConst (using Context ) = solved >= ccState.iterCount
522+ def isAlwaysEmpty (using Context ) = isConst && elems.isEmpty
523+ def isProvisionallySolved (using Context ): Boolean = solved > 0 && solved != Int .MaxValue
508524
509525 def isMaybeSet = false // overridden in BiMapped
510526
@@ -656,21 +672,20 @@ object CaptureSet:
656672 * in the results of defs and vals.
657673 */
658674 def solve ()(using Context ): Unit =
659- if ! isConst then
660- CCState .withCapAsRoot: // // OK here since we infer parameter types that get checked later
661- val approx = upperApprox(empty)
662- .map(root.CapToFresh (NoSymbol ).inverse) // Fresh --> cap
663- .showing(i " solve $this = $result" , capt)
664- // println(i"solving var $this $approx ${approx.isConst} deps = ${deps.toList}")
665- val newElems = approx.elems -- elems
666- given VarState ()
667- if tryInclude(newElems, empty).isOK then
668- markSolved()
675+ CCState .withCapAsRoot: // // OK here since we infer parameter types that get checked later
676+ val approx = upperApprox(empty)
677+ .map(root.CapToFresh (NoSymbol ).inverse) // Fresh --> cap
678+ .showing(i " solve $this = $result" , capt)
679+ // println(i"solving var $this $approx ${approx.isConst} deps = ${deps.toList}")
680+ val newElems = approx.elems -- elems
681+ given VarState ()
682+ if tryInclude(newElems, empty).isOK then
683+ markSolved(provisional = false )
669684
670685 /** Mark set as solved and propagate this info to all dependent sets */
671- def markSolved ()(using Context ): Unit =
672- isSolved = true
673- deps.foreach(_.propagateSolved())
686+ def markSolved (provisional : Boolean )(using Context ): Unit =
687+ solved = if provisional then ccState.iterCount else Int . MaxValue
688+ deps.foreach(_.propagateSolved(provisional ))
674689
675690 def withDescription (description : String ): this .type =
676691 this .description = this .description.join(" and " , description)
@@ -728,8 +743,8 @@ object CaptureSet:
728743
729744 addAsDependentTo(source)
730745
731- override def propagateSolved ()(using Context ) =
732- if source.isConst && ! isConst then markSolved()
746+ override def propagateSolved (provisional : Boolean )(using Context ) =
747+ if source.isConst && ! isConst then markSolved(provisional )
733748 end DerivedVar
734749
735750 /** A variable that changes when `source` changes, where all additional new elements are mapped
@@ -823,8 +838,8 @@ object CaptureSet:
823838 else
824839 source.upperApprox(this ).map(tm)
825840
826- override def propagateSolved ()(using Context ) =
827- if initial.isConst then super .propagateSolved()
841+ override def propagateSolved (provisional : Boolean )(using Context ) =
842+ if initial.isConst then super .propagateSolved(provisional )
828843
829844 override def toString = s " Mapped $id( $source, elems = $elems) "
830845 end Mapped
@@ -914,8 +929,8 @@ object CaptureSet:
914929 else res
915930 else res
916931
917- override def propagateSolved ()(using Context ) =
918- if cs1.isConst && cs2.isConst && ! isConst then markSolved()
932+ override def propagateSolved (provisional : Boolean )(using Context ) =
933+ if cs1.isConst && cs2.isConst && ! isConst then markSolved(provisional )
919934 end Union
920935
921936 class Intersection (cs1 : CaptureSet , cs2 : CaptureSet )(using Context )
@@ -941,8 +956,8 @@ object CaptureSet:
941956 else
942957 CaptureSet (elemIntersection(cs1.upperApprox(this ), cs2.upperApprox(this )))
943958
944- override def propagateSolved ()(using Context ) =
945- if cs1.isConst && cs2.isConst && ! isConst then markSolved()
959+ override def propagateSolved (provisional : Boolean )(using Context ) =
960+ if cs1.isConst && cs2.isConst && ! isConst then markSolved(provisional )
946961 end Intersection
947962
948963 def elemIntersection (cs1 : CaptureSet , cs2 : CaptureSet )(using Context ): Refs =
0 commit comments