@@ -11,7 +11,10 @@ import typer.ErrorReporting.errorType
11
11
import Names .TermName
12
12
import NameKinds .ExistentialBinderName
13
13
import NameOps .isImpureFunction
14
+ import CaptureSet .IdempotentCaptRefMap
14
15
import reporting .Message
16
+ import util .EqHashMap
17
+ import util .Spans .NoSpan
15
18
16
19
/**
17
20
@@ -229,6 +232,19 @@ object Existential:
229
232
def apply (mk : TermParamRef => Type )(using Context ): Type =
230
233
exMethodType(mk).toFunctionType(alwaysDependent = true )
231
234
235
+ /** The (super-) type of existentially bound references */
236
+ type Var = AnnotatedType
237
+
238
+ /** An extractor for existentially bound references of the form ex @existential
239
+ * where ex is a TermParamRef of type Exists
240
+ */
241
+ object Var :
242
+ def apply (boundVar : TermParamRef )(using Context ): Var =
243
+ AnnotatedType (boundVar, Annotation (defn.ExistentialAnnot , NoSpan ))
244
+ def unapply (tp : Var )(using Context ): Option [TermParamRef ] = tp match
245
+ case AnnotatedType (bv : TermParamRef , ann) if ann.symbol == defn.ExistentialAnnot => Some (bv)
246
+ case _ => None
247
+
232
248
/** Create existential if bound variable appears in result of `mk` */
233
249
def wrap (mk : TermParamRef => Type )(using Context ): Type =
234
250
val mt = exMethodType(mk)
@@ -242,10 +258,23 @@ object Existential:
242
258
case _ =>
243
259
core
244
260
261
+ /** Map existentially bound references referring to `boundVar` one-to-one
262
+ * to Fresh.Cap instances
263
+ */
264
+ def boundVarToCap (boundVar : TermParamRef , tp : Type )(using Context ) =
265
+ val subst = new IdempotentCaptRefMap :
266
+ val seen = EqHashMap [Annotation , CaptureRef ]()
267
+ def apply (t : Type ): Type = t match
268
+ case t @ Var (`boundVar`) =>
269
+ seen.getOrElseUpdate(t.annot, Fresh .Cap (NoSymbol ))
270
+ case _ =>
271
+ mapOver(t)
272
+ subst(tp)
273
+
245
274
/** Map top-level existentials to `Fresh.Cap`. */
246
275
def toCap (tp : Type )(using Context ): Type = tp.dealiasKeepAnnots match
247
276
case Existential (boundVar, unpacked) =>
248
- unpacked.substParam (boundVar, Fresh . Cap ( NoSymbol ) )
277
+ boundVarToCap (boundVar, unpacked )
249
278
case tp1 @ CapturingType (parent, refs) =>
250
279
tp1.derivedCapturingType(toCap(parent), refs)
251
280
case tp1 @ AnnotatedType (parent, ann) =>
@@ -256,7 +285,7 @@ object Existential:
256
285
*/
257
286
def toCapDeeply (tp : Type )(using Context ): Type = tp.dealiasKeepAnnots match
258
287
case Existential (boundVar, unpacked) =>
259
- toCapDeeply(unpacked.substParam (boundVar, Fresh . Cap ( NoSymbol ) ))
288
+ toCapDeeply(boundVarToCap (boundVar, unpacked ))
260
289
case tp1 @ FunctionOrMethod (args, res) =>
261
290
val tp2 = tp1.derivedFunctionOrMethod(args, toCapDeeply(res))
262
291
if tp2 ne tp1 then tp2 else tp
@@ -293,11 +322,13 @@ object Existential:
293
322
super .mapOver(t)
294
323
295
324
class Wrap (boundVar : TermParamRef ) extends CapMap :
325
+ private val seen = EqHashMap [CaptureRef , Var ]()
326
+
296
327
def apply (t : Type ) = t match
297
- case t : CaptureRef if t.isCapOrFresh => // !!! we should map different fresh refs to different existentials
328
+ case t : CaptureRef if t.isCapOrFresh =>
298
329
if variance > 0 then
299
330
needsWrap = true
300
- boundVar
331
+ seen.getOrElseUpdate(t, Var ( boundVar))
301
332
else
302
333
if variance == 0 then
303
334
fail(em """ $tp captures the root capability `cap` in invariant position """ )
@@ -310,16 +341,27 @@ object Existential:
310
341
if variance > 0 then
311
342
needsWrap = true
312
343
super .mapOver:
313
- defn.FunctionNOf (args, res, contextual).capturing(boundVar.singletonCaptureSet)
344
+ defn.FunctionNOf (args, res, contextual)
345
+ .capturing(Var (boundVar).singletonCaptureSet)
314
346
else mapOver(t)
315
347
case _ =>
316
348
mapOver(t)
317
349
// .showing(i"mapcap $t = $result")
318
350
319
351
lazy val inverse = new BiTypeMap :
320
- lazy val freshCap = Fresh .Cap (NoSymbol )
321
352
def apply (t : Type ) = t match
322
- case t : TermParamRef if t eq boundVar => freshCap
353
+ case t @ Var (`boundVar`) =>
354
+ // do a reverse getOrElseUpdate on `seen` to produce the
355
+ // `Fresh.Cap` assosicated with `t`
356
+ val it = seen.iterator
357
+ var ref : CaptureRef | Null = null
358
+ while it.hasNext && ref == null do
359
+ val (k, v) = it.next
360
+ if v.annot eq t.annot then ref = k
361
+ if ref == null then
362
+ ref = Fresh .Cap (NoSymbol )
363
+ seen(ref) = t
364
+ ref
323
365
case _ => mapOver(t)
324
366
def inverse = Wrap .this
325
367
override def toString = " Wrap.inverse"
@@ -359,8 +401,8 @@ object Existential:
359
401
case (info : TypeRef ) :: rest => info.symbol == defn.Caps_Exists && rest.isEmpty
360
402
case _ => false
361
403
362
- /** Is `ref` this an existentially bound variable ? */
363
- def isExistentialVar (ref : CaptureRef )(using Context ) = ref match
404
+ /** Is `ref` a TermParamRef representing existentially bound variables ? */
405
+ def isBinder (ref : CaptureRef )(using Context ) = ref match
364
406
case ref : TermParamRef => isExistentialMethod(ref.binder)
365
407
case _ => false
366
408
0 commit comments