@@ -206,13 +206,13 @@ extends tpd.TreeTraverser:
206
206
else fntpe
207
207
case _ => tp
208
208
209
- def isCapabilityClassRef (tp : Type )(using Context ) = tp match
209
+ extension (tp : Type ) def isCapabilityClassRef (using Context ) = tp match
210
210
case _ : TypeRef | _ : AppliedType => tp.typeSymbol.hasAnnotation(defn.CapabilityAnnot )
211
211
case _ => false
212
212
213
213
/** Map references to capability classes C to C^ */
214
214
private def expandCapabilityClass (tp : Type )(using Context ): Type =
215
- if isCapabilityClassRef(tp)
215
+ if tp.isCapabilityClassRef
216
216
then CapturingType (tp, CaptureSet .universal, boxed = false )
217
217
else tp
218
218
@@ -232,7 +232,7 @@ extends tpd.TreeTraverser:
232
232
case t @ AnnotatedType (t1, ann) =>
233
233
checkQualifiedRoots(ann.tree)
234
234
val t3 =
235
- if ann.symbol == defn.RetainsAnnot && isCapabilityClassRef(t1) then t1
235
+ if ann.symbol == defn.RetainsAnnot && t1.isCapabilityClassRef then t1
236
236
else this (t1)
237
237
// Don't map capture sets, since that would implicitly normalize sets that
238
238
// are not well-formed.
@@ -317,21 +317,61 @@ extends tpd.TreeTraverser:
317
317
private def updateOwner (sym : Symbol )(using Context ) =
318
318
if newOwnerFor(sym) != null then updateInfo(sym, sym.info)
319
319
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
+
320
349
def traverse (tree : Tree )(using Context ): Unit =
321
350
tree match
322
351
case tree @ DefDef (_, paramss, tpt : TypeTree , _) =>
323
- if isExcluded(tree.symbol) then
352
+ val meth = tree.symbol
353
+ if isExcluded(meth) then
324
354
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
329
368
paramss.foreach(traverse)
330
369
transformTT(tpt, boxed = false ,
331
370
exact = tree.symbol.allOverriddenSymbols.hasNext,
332
371
mapRoots = true )
333
372
traverse(tree.rhs)
334
373
// println(i"TYPE of ${tree.symbol.showLocated} = ${tpt.knownType}")
374
+
335
375
case tree @ ValDef (_, tpt : TypeTree , _) =>
336
376
def containsCap (tp : Type ) = tp.existsPart:
337
377
case CapturingType (_, refs) => refs.isUniversal
@@ -342,9 +382,12 @@ extends tpd.TreeTraverser:
342
382
case _ : InferredTypeTree => false
343
383
case _ : TypeTree => containsCap(expandAliases(tree.tpe))
344
384
case _ => false
385
+
386
+ val sym = tree.symbol
345
387
val mapRoots = tree.rhs match
346
388
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
348
391
// Toplevel closures bound to vals count as level owners
349
392
// unless the closure is an implicit eta expansion over a type application
350
393
// that mentions `cap`. In that case we prefer not to silently rebind
@@ -354,22 +397,29 @@ extends tpd.TreeTraverser:
354
397
// in this case roots in inferred val type count as polymorphic
355
398
case _ =>
356
399
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
+
364
408
case tree @ TypeApply (fn, args) =>
365
409
traverse(fn)
366
410
for case arg : TypeTree <- args do
367
411
transformTT(arg, boxed = true , exact = false , mapRoots = true ) // type arguments in type applications are boxed
412
+
368
413
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
370
419
traverseChildren(tree)
371
420
case tree : Try if Feature .enabled(Feature .saferExceptions) =>
372
421
val tryOwner = newSymbol(ctx.owner, nme.TRY_BLOCK , SyntheticMethod , MethodType (Nil , defn.UnitType ))
422
+ ccState.levelOwners += tryOwner
373
423
ccState.tryBlockOwner(tree) = tryOwner
374
424
inContext(ctx.withOwner(tryOwner)):
375
425
traverseChildren(tree)
0 commit comments