@@ -206,13 +206,13 @@ extends tpd.TreeTraverser:
206206 else fntpe
207207 case _ => tp
208208
209- def isCapabilityClassRef (tp : Type )(using Context ) = tp match
209+ extension (tp : Type ) def isCapabilityClassRef (using Context ) = tp match
210210 case _ : TypeRef | _ : AppliedType => tp.typeSymbol.hasAnnotation(defn.CapabilityAnnot )
211211 case _ => false
212212
213213 /** Map references to capability classes C to C^ */
214214 private def expandCapabilityClass (tp : Type )(using Context ): Type =
215- if isCapabilityClassRef(tp)
215+ if tp.isCapabilityClassRef
216216 then CapturingType (tp, CaptureSet .universal, boxed = false )
217217 else tp
218218
@@ -232,7 +232,7 @@ extends tpd.TreeTraverser:
232232 case t @ AnnotatedType (t1, ann) =>
233233 checkQualifiedRoots(ann.tree)
234234 val t3 =
235- if ann.symbol == defn.RetainsAnnot && isCapabilityClassRef(t1) then t1
235+ if ann.symbol == defn.RetainsAnnot && t1.isCapabilityClassRef then t1
236236 else this (t1)
237237 // Don't map capture sets, since that would implicitly normalize sets that
238238 // are not well-formed.
@@ -317,21 +317,61 @@ extends tpd.TreeTraverser:
317317 private def updateOwner (sym : Symbol )(using Context ) =
318318 if newOwnerFor(sym) != null then updateInfo(sym, sym.info)
319319
320+ extension (sym : Symbol ) def takesCappedParam (using Context ): Boolean =
321+ def search = new TypeAccumulator [Boolean ]:
322+ def apply (x : Boolean , t : Type ): Boolean = // reporting.trace.force(s"hasCapAt $v, $t"):
323+ if x then true
324+ else t match
325+ case t @ AnnotatedType (t1, annot)
326+ if annot.symbol == defn.RetainsAnnot || annot.symbol == defn.RetainsByNameAnnot =>
327+ val elems = annot match
328+ case CaptureAnnotation (refs, _) => refs.elems.toList
329+ case _ => retainedElems(annot.tree).map(_.tpe)
330+ if elems.exists(_.widen.isRef(defn.Caps_Cap )) then true
331+ else ! t1.isCapabilityClassRef && this (x, t1)
332+ case t : PolyType =>
333+ apply(x, t.resType)
334+ case t : MethodType =>
335+ t.paramInfos.exists(apply(false , _))
336+ case _ =>
337+ if t.isRef(defn.Caps_Cap ) || t.isCapabilityClassRef then true
338+ else
339+ val t1 = t.dealiasKeepAnnots
340+ if t1 ne t then this (x, t1)
341+ else foldOver(x, t)
342+ true || sym.info.stripPoly.match
343+ case mt : MethodType =>
344+ mt.paramInfos.exists(search(false , _))
345+ case _ =>
346+ false
347+ end extension
348+
320349 def traverse (tree : Tree )(using Context ): Unit =
321350 tree match
322351 case tree @ DefDef (_, paramss, tpt : TypeTree , _) =>
323- if isExcluded(tree.symbol) then
352+ val meth = tree.symbol
353+ if isExcluded(meth) then
324354 return
325- inContext(ctx.withOwner(tree.symbol)):
326- if tree.symbol.isAnonymousFunction && tree.symbol.definedLocalRoot.exists then
327- // closures that define parameters of type caps.Cap count as level owners
328- tree.symbol.setNestingLevel(ctx.owner.nestingLevel + 1 )
355+
356+ def isCaseClassSynthetic = // TODO drop
357+ meth.owner.isClass && meth.owner.is(Case ) && meth.is(Synthetic ) && meth.info.firstParamNames.isEmpty
358+
359+ inContext(ctx.withOwner(meth)):
360+ val canHaveLocalRoot =
361+ if meth.isAnonymousFunction then
362+ ccState.rhsClosure.remove(meth)
363+ || meth.definedLocalRoot.exists // TODO drop
364+ else ! meth.isConstructor && ! isCaseClassSynthetic
365+ if canHaveLocalRoot && meth.takesCappedParam then
366+ // println(i"level owner: $meth")
367+ ccState.levelOwners += meth
329368 paramss.foreach(traverse)
330369 transformTT(tpt, boxed = false ,
331370 exact = tree.symbol.allOverriddenSymbols.hasNext,
332371 mapRoots = true )
333372 traverse(tree.rhs)
334373 // println(i"TYPE of ${tree.symbol.showLocated} = ${tpt.knownType}")
374+
335375 case tree @ ValDef (_, tpt : TypeTree , _) =>
336376 def containsCap (tp : Type ) = tp.existsPart:
337377 case CapturingType (_, refs) => refs.isUniversal
@@ -342,9 +382,12 @@ extends tpd.TreeTraverser:
342382 case _ : InferredTypeTree => false
343383 case _ : TypeTree => containsCap(expandAliases(tree.tpe))
344384 case _ => false
385+
386+ val sym = tree.symbol
345387 val mapRoots = tree.rhs match
346388 case possiblyTypedClosureDef(ddef) if ! mentionsCap(rhsOfEtaExpansion(ddef)) =>
347- ddef.symbol.setNestingLevel(ctx.owner.nestingLevel + 1 )
389+ // ddef.symbol.setNestingLevel(ctx.owner.nestingLevel + 1)
390+ ccState.rhsClosure += ddef.symbol
348391 // Toplevel closures bound to vals count as level owners
349392 // unless the closure is an implicit eta expansion over a type application
350393 // that mentions `cap`. In that case we prefer not to silently rebind
@@ -354,22 +397,29 @@ extends tpd.TreeTraverser:
354397 // in this case roots in inferred val type count as polymorphic
355398 case _ =>
356399 true
357- transformTT(tpt,
358- boxed = tree.symbol.is(Mutable ), // types of mutable variables are boxed
359- exact = tree.symbol.allOverriddenSymbols.hasNext, // types of symbols that override a parent don't get a capture set
360- mapRoots
361- )
362- capt.println(i " mapped $tree = ${tpt.knownType}" )
363- traverse(tree.rhs)
400+ transformTT(tpt,
401+ boxed = sym.is(Mutable ), // types of mutable variables are boxed
402+ exact = sym.allOverriddenSymbols.hasNext, // types of symbols that override a parent don't get a capture set
403+ mapRoots
404+ )
405+ capt.println(i " mapped $tree = ${tpt.knownType}" )
406+ traverse(tree.rhs)
407+
364408 case tree @ TypeApply (fn, args) =>
365409 traverse(fn)
366410 for case arg : TypeTree <- args do
367411 transformTT(arg, boxed = true , exact = false , mapRoots = true ) // type arguments in type applications are boxed
412+
368413 case tree : Template =>
369- inContext(ctx.withOwner(tree.symbol.owner)):
414+ val cls = tree.symbol.owner
415+ inContext(ctx.withOwner(cls)):
416+ if cls.primaryConstructor.takesCappedParam then
417+ // println(i"level owner $cls")
418+ ccState.levelOwners += cls
370419 traverseChildren(tree)
371420 case tree : Try if Feature .enabled(Feature .saferExceptions) =>
372421 val tryOwner = newSymbol(ctx.owner, nme.TRY_BLOCK , SyntheticMethod , MethodType (Nil , defn.UnitType ))
422+ ccState.levelOwners += tryOwner
373423 ccState.tryBlockOwner(tree) = tryOwner
374424 inContext(ctx.withOwner(tryOwner)):
375425 traverseChildren(tree)
0 commit comments