@@ -103,9 +103,14 @@ end mapRoots
103
103
extension (tree : Tree )
104
104
105
105
/** Map tree with CaptureRef type to its type, throw IllegalCaptureRef otherwise */
106
- def toCaptureRef (using Context ): CaptureRef = tree.tpe match
107
- case ref : CaptureRef => ref
108
- case tpe => throw IllegalCaptureRef (tpe)
106
+ def toCaptureRef (using Context ): CaptureRef = tree match
107
+ case QualifiedRoot (outer) =>
108
+ ctx.owner.levelOwnerNamed(outer)
109
+ .orElse(defn.captureRoot) // non-existing outer roots are reported in Setup's checkQualifiedRoots
110
+ .localRoot.termRef
111
+ case _ => tree.tpe match
112
+ case ref : CaptureRef => ref
113
+ case tpe => throw IllegalCaptureRef (tpe) // if this was compiled from cc syntax, problem should have been reported at Typer
109
114
110
115
/** Convert a @retains or @retainsByName annotation tree to the capture set it represents.
111
116
* For efficience, the result is cached as an Attachment on the tree.
@@ -266,39 +271,6 @@ extension (tp: Type)
266
271
tp.tp1.isAlwaysPure && tp.tp2.isAlwaysPure
267
272
case _ =>
268
273
false
269
- /* !!!
270
- def capturedLocalRoot(using Context): Symbol =
271
- tp.captureSet.elems.toList
272
- .filter(_.isLocalRootCapability)
273
- .map(_.termSymbol)
274
- .maxByOption(_.ccNestingLevel)
275
- .getOrElse(NoSymbol)
276
-
277
- /** Remap roots defined in `cls` to the ... */
278
- def remapRoots(pre: Type, cls: Symbol)(using Context): Type =
279
- if cls.isStaticOwner then tp
280
- else
281
- val from =
282
- if cls.source == ctx.compilationUnit.source then cls.localRoot
283
- else defn.captureRoot
284
- mapRoots(from, capturedLocalRoot)(tp)
285
-
286
-
287
- def containsRoot(root: Symbol)(using Context): Boolean =
288
- val search = new TypeAccumulator[Boolean]:
289
- def apply(x: Boolean, t: Type): Boolean =
290
- if x then true
291
- else t.dealias match
292
- case t1: TermRef if t1.symbol == root => true
293
- case t1: TypeRef if t1.classSymbol.hasAnnotation(defn.CapabilityAnnot) => true
294
- case t1: MethodType =>
295
- !foldOver(x, t1.paramInfos) && this(x, t1.resType)
296
- case t1 @ AppliedType(tycon, args) if defn.isFunctionSymbol(tycon.typeSymbol) =>
297
- val (inits, last :: Nil) = args.splitAt(args.length - 1): @unchecked
298
- !foldOver(x, inits) && this(x, last)
299
- case t1 => foldOver(x, t1)
300
- search(false, tp)
301
- */
302
274
303
275
extension (cls : ClassSymbol )
304
276
@@ -405,6 +377,7 @@ extension (sym: Symbol)
405
377
case psyms :: _ => psyms.find(_.info.typeSymbol == defn.Caps_Cap ).getOrElse(NoSymbol )
406
378
case _ => NoSymbol
407
379
380
+ /** The local root corresponding to sym's level owner */
408
381
def localRoot (using Context ): Symbol =
409
382
val owner = sym.levelOwner
410
383
assert(owner.exists)
@@ -415,6 +388,24 @@ extension (sym: Symbol)
415
388
else newRoot
416
389
ccState.localRoots.getOrElseUpdate(owner, lclRoot)
417
390
391
+ /** The level owner enclosing `sym` which has the given name, or NoSymbol if none exists.
392
+ * If name refers to a val that has a closure as rhs, we return the closure as level
393
+ * owner.
394
+ */
395
+ def levelOwnerNamed (name : String )(using Context ): Symbol =
396
+ def recur (owner : Symbol , prev : Symbol ): Symbol =
397
+ if owner.name.toString == name then
398
+ if owner.isLevelOwner then owner
399
+ else if owner.isTerm && ! owner.isOneOf(Method | Module ) && prev.exists then prev
400
+ else NoSymbol
401
+ else if owner == defn.RootClass then
402
+ NoSymbol
403
+ else
404
+ val prev1 = if owner.isAnonymousFunction && owner.isLevelOwner then owner else NoSymbol
405
+ recur(owner.owner, prev1)
406
+ recur(sym, NoSymbol )
407
+ .showing(i " find outer $sym [ $name ] = $result" , capt)
408
+
418
409
def maxNested (other : Symbol )(using Context ): Symbol =
419
410
if sym.ccNestingLevel < other.ccNestingLevel then other else sym
420
411
/* does not work yet, we do mix sets with different levels, for instance in cc-this.scala.
0 commit comments