@@ -11,74 +11,167 @@ import reporting.trace
11
11
import printing .{Showable , Printer }
12
12
import printing .Texts .*
13
13
14
- case class CaptureSet private (elems : CaptureSet .Refs ) extends Showable :
14
+ /** A class for capture sets. Capture sets can be constants or variables.
15
+ */
16
+ sealed abstract class CaptureSet extends Showable :
15
17
import CaptureSet .*
16
18
17
- def isEmpty : Boolean = elems.isEmpty
19
+ /** The elements of this capture set. For capture variables,
20
+ * the elements known so far.
21
+ */
22
+ def elems : Refs
23
+
24
+ /** Is this capture set constant (i.e. not a capture variable)?
25
+ */
26
+ def isConst : Boolean
27
+
28
+ /** Is this capture set (always) empty? For capture veraiables, returns
29
+ * always false
30
+ */
31
+ def isEmpty : Boolean
18
32
def nonEmpty : Boolean = ! isEmpty
19
33
20
- private var myClosure : Refs | Null = null
21
-
22
- def closure (using Context ): Refs =
23
- if myClosure == null then
24
- var cl = elems
25
- var seen : Refs = SimpleIdentitySet .empty
26
- while
27
- val prev = cl
28
- for ref <- cl do
29
- if ! seen.contains(ref) then
30
- seen += ref
31
- cl = cl ++ ref.captureSetOfInfo.elems
32
- prev ne cl
33
- do ()
34
- myClosure = cl
35
- myClosure
36
-
37
- def ++ (that : CaptureSet ): CaptureSet =
38
- if this .isEmpty then that
39
- else if that.isEmpty then this
40
- else CaptureSet (elems ++ that.elems)
41
-
42
- def + (ref : CaptureRef ) =
43
- if elems.contains(ref) then this
44
- else CaptureSet (elems + ref)
45
-
46
- def intersect (that : CaptureSet ): CaptureSet =
47
- CaptureSet (this .elems.intersect(that.elems))
34
+ /** Add new elements to this capture set if allowed.
35
+ * @pre `newElems` is not empty and does not overlap with `this.elems`.
36
+ * Constant capture sets never allow to add new elements.
37
+ * Variables allow it if and only if the new elements can be included
38
+ * in all their supersets.
39
+ * @return true iff elements were added
40
+ */
41
+ protected def addNewElems (newElems : Refs )(using Context ): Boolean
42
+
43
+ /** If this is a variable, add `cs` as a super set */
44
+ protected def addSuper (cs : CaptureSet ): this .type
45
+
46
+ /** If `cs` is a variable, add this capture set as one of its super sets */
47
+ protected def addSub (cs : CaptureSet ): this .type =
48
+ cs.addSuper(this )
49
+ this
50
+
51
+ /** Try to include all references of `elems` that are not yet accounted by this
52
+ * capture set. Inclusion is via `addElems`.
53
+ * @return true iff elements were added
54
+ */
55
+ protected def tryInclude (elems : Refs )(using Context ): Boolean =
56
+ val unaccounted = elems.filter(! accountsFor(_))
57
+ unaccounted.isEmpty || addNewElems(unaccounted)
48
58
49
59
/** {x} <:< this where <:< is subcapturing */
50
60
def accountsFor (x : CaptureRef )(using Context ) =
51
61
elems.contains(x) || ! x.isRootCapability && x.captureSetOfInfo <:< this
52
62
53
63
/** The subcapturing test */
54
64
def <:< (that : CaptureSet )(using Context ): Boolean =
55
- elems.isEmpty || elems.forall(that.accountsFor)
56
-
65
+ that.tryInclude(elems) && { addSuper(that); true }
66
+
67
+ /** The smallest capture set (via <:<) that is a superset of both
68
+ * `this` and `that`
69
+ */
70
+ def ++ (that : CaptureSet )(using Context ): CaptureSet =
71
+ if this .isConst && this .elems.forall(that.accountsFor) then that
72
+ else if that.isConst && that.elems.forall(this .accountsFor) then this
73
+ else if this .isConst && that.isConst then Const (this .elems ++ that.elems)
74
+ else Var (this .elems ++ that.elems).addSub(this ).addSub(that)
75
+
76
+ /** The smallest superset (via <:<) of this capture set that also contains `ref`.
77
+ */
78
+ def + (ref : CaptureRef )(using Context ) = ++ (ref.singletonCaptureSet)
79
+
80
+ /** The largest capture set (via <:<) that is a subset of both `this` and `that`
81
+ */
82
+ def intersect (that : CaptureSet )(using Context ): CaptureSet =
83
+ if this .isConst && this .elems.forall(that.accountsFor) then this
84
+ else if that.isConst && that.elems.forall(this .accountsFor) then that
85
+ else if this .isConst && that.isConst then Const (this .elems.intersect(that.elems))
86
+ else Var (this .elems.intersect(that.elems)).addSuper(this ).addSuper(that)
87
+
88
+ /** capture set obtained by applying `f` to all elements of the current capture set
89
+ * and joining the results. If the current capture set is a variable, the same
90
+ * transformation is applied to all future additions of new elements.
91
+ */
57
92
def flatMap (f : CaptureRef => CaptureSet )(using Context ): CaptureSet =
58
- (empty /: elems)((cs, ref) => cs ++ f(ref))
93
+ mapRefs(elems, f) match
94
+ case cs : Const => cs
95
+ case cs : Var => Mapped (cs, f)
59
96
60
97
def substParams (tl : BindingType , to : List [Type ])(using Context ) =
61
98
flatMap {
62
99
case ref : ParamRef if ref.binder eq tl => to(ref.paramNum).captureSet
63
100
case ref => ref.singletonCaptureSet
64
101
}
65
102
66
- override def toString = elems.toString
103
+ def toRetainsTypeArg (using Context ): Type =
104
+ assert(isConst)
105
+ ((NoType : Type ) /: elems) ((tp, ref) =>
106
+ if tp.exists then OrType (tp, ref, soft = false ) else ref)
67
107
68
108
override def toText (printer : Printer ): Text =
69
109
Str (" {" ) ~ Text (elems.toList.map(printer.toTextCaptureRef), " , " ) ~ Str (" }" )
70
110
71
111
object CaptureSet :
72
112
type Refs = SimpleIdentitySet [CaptureRef ]
113
+ type Vars = SimpleIdentitySet [Var ]
114
+ type Deps = SimpleIdentitySet [CaptureSet ]
115
+
116
+ private val emptySet = SimpleIdentitySet .empty
117
+ @ sharable private var varId = 0
118
+
119
+ val empty : CaptureSet = Const (emptySet)
73
120
74
- @ sharable val empty : CaptureSet = CaptureSet (SimpleIdentitySet .empty)
121
+ /** The universal capture set `{*}` */
122
+ def universal (using Context ): CaptureSet =
123
+ defn.captureRootType.typeRef.singletonCaptureSet
75
124
76
125
/** Used as a recursion brake */
77
- @ sharable private [core] val Pending = CaptureSet (SimpleIdentitySet .empty)
126
+ @ sharable private [core] val Pending = Const (SimpleIdentitySet .empty)
78
127
79
128
def apply (elems : CaptureRef * )(using Context ): CaptureSet =
80
129
if elems.isEmpty then empty
81
- else CaptureSet (SimpleIdentitySet (elems.map(_.normalizedRef)* ))
130
+ else Const (SimpleIdentitySet (elems.map(_.normalizedRef)* ))
131
+
132
+ class Const private [CaptureSet ] (val elems : Refs ) extends CaptureSet :
133
+ assert(elems != null )
134
+ def isConst = true
135
+ def isEmpty : Boolean = elems.isEmpty
136
+
137
+ def addNewElems (elems : Refs )(using Context ): Boolean = false
138
+ def addSuper (cs : CaptureSet ) = this
139
+
140
+ override def toString = elems.toString
141
+ end Const
142
+
143
+ class Var private [CaptureSet ] (initialElems : Refs ) extends CaptureSet :
144
+ val id =
145
+ varId += 1
146
+ varId
147
+
148
+ var elems : Refs = initialElems
149
+ var deps : Deps = emptySet
150
+ def isConst = false
151
+ def isEmpty = false
152
+
153
+ def addNewElems (newElems : Refs )(using Context ): Boolean =
154
+ deps.forall(_.tryInclude(newElems)) && { elems ++= newElems; true }
155
+
156
+ def addSuper (cs : CaptureSet ) = { deps += cs; this }
157
+
158
+ override def toString = s " Var $id$elems"
159
+ end Var
160
+
161
+ class Mapped private [CaptureSet ] (cv : Var , f : CaptureRef => CaptureSet ) extends Var (cv.elems):
162
+ addSub(cv)
163
+
164
+ override def accountsFor (x : CaptureRef )(using Context ): Boolean =
165
+ f(x).elems.forall(super .accountsFor)
166
+
167
+ override def addNewElems (newElems : Refs )(using Context ): Boolean =
168
+ super .addNewElems(mapRefs(newElems, f).elems)
169
+
170
+ override def toString = s " Mapped $id$elems"
171
+ end Mapped
172
+
173
+ def mapRefs (xs : Refs , f : CaptureRef => CaptureSet )(using Context ): CaptureSet =
174
+ (empty /: xs)((cs, x) => cs ++ f(x))
82
175
83
176
def ofClass (cinfo : ClassInfo , argTypes : List [Type ])(using Context ): CaptureSet =
84
177
def captureSetOf (tp : Type ): CaptureSet = tp match
@@ -105,8 +198,8 @@ object CaptureSet:
105
198
tp.captureSet
106
199
case tp : ParamRef =>
107
200
tp.captureSet
108
- case CapturingType (parent, ref ) =>
109
- recur(parent) + ref
201
+ case CapturingType (parent, refs ) =>
202
+ recur(parent) ++ refs
110
203
case AppliedType (tycon, args) =>
111
204
val cs = recur(tycon)
112
205
tycon.typeParams match
@@ -125,3 +218,8 @@ object CaptureSet:
125
218
recur(tp)
126
219
.showing(i " capture set of $tp = $result" , capt)
127
220
221
+ def fromRetainsTypeArg (tp : Type )(using Context ): CaptureSet = tp match
222
+ case tp : CaptureRef => tp.singletonCaptureSet
223
+ case OrType (tp1, tp2) => fromRetainsTypeArg(tp1) ++ fromRetainsTypeArg(tp2)
224
+
225
+ end CaptureSet
0 commit comments