@@ -103,9 +103,14 @@ end mapRoots
103103extension (tree : Tree )
104104
105105 /** 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
109114
110115 /** Convert a @retains or @retainsByName annotation tree to the capture set it represents.
111116 * For efficience, the result is cached as an Attachment on the tree.
@@ -266,39 +271,6 @@ extension (tp: Type)
266271 tp.tp1.isAlwaysPure && tp.tp2.isAlwaysPure
267272 case _ =>
268273 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- */
302274
303275extension (cls : ClassSymbol )
304276
@@ -405,6 +377,7 @@ extension (sym: Symbol)
405377 case psyms :: _ => psyms.find(_.info.typeSymbol == defn.Caps_Cap ).getOrElse(NoSymbol )
406378 case _ => NoSymbol
407379
380+ /** The local root corresponding to sym's level owner */
408381 def localRoot (using Context ): Symbol =
409382 val owner = sym.levelOwner
410383 assert(owner.exists)
@@ -415,6 +388,24 @@ extension (sym: Symbol)
415388 else newRoot
416389 ccState.localRoots.getOrElseUpdate(owner, lclRoot)
417390
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+
418409 def maxNested (other : Symbol )(using Context ): Symbol =
419410 if sym.ccNestingLevel < other.ccNestingLevel then other else sym
420411 /* does not work yet, we do mix sets with different levels, for instance in cc-this.scala.
0 commit comments