Skip to content

Commit 6dc4b5b

Browse files
committed
Don't detour over tree when going from RetainingAnnotation to capture set
1 parent 5e3c75f commit 6dc4b5b

File tree

9 files changed

+51
-68
lines changed

9 files changed

+51
-68
lines changed

compiler/src/dotty/tools/dotc/cc/Capability.scala

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1035,14 +1035,13 @@ object Capabilities:
10351035
else t match
10361036
case t @ CapturingType(_, _) =>
10371037
mapOver(t)
1038+
case t @ AnnotatedType(parent, ann: RetainingAnnotation)
1039+
if ann.isStrict && ann.toCaptureSet.containsCap =>
1040+
// Applying `this` can cause infinite recursion in some cases during printing.
1041+
// scalac -Xprint:all tests/pos/i23885/S_1.scala tests/pos/i23885/S_2.scala
1042+
mapOver(CapturingType(this(parent), ann.toCaptureSet))
10381043
case t @ AnnotatedType(parent, ann) =>
1039-
val parent1 = this(parent)
1040-
if ann.symbol.isRetains && ann.tree.toCaptureSet.containsCap then
1041-
// Applying `this` can cause infinite recursion in some cases during printing.
1042-
// scalac -Xprint:all tests/pos/i23885/S_1.scala tests/pos/i23885/S_2.scala
1043-
mapOver(CapturingType(parent1, ann.tree.toCaptureSet))
1044-
else
1045-
t.derivedAnnotatedType(parent1, ann)
1044+
t.derivedAnnotatedType(this(parent), ann)
10461045
case defn.RefinedFunctionOf(_) =>
10471046
t // stop at dependent function types
10481047
case _ =>

compiler/src/dotty/tools/dotc/cc/CaptureOps.scala

Lines changed: 8 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -54,28 +54,15 @@ def ccState(using Context): CCState =
5454

5555
extension (tree: Tree)
5656

57-
/** Convert a @retains or @retainsByName annotation tree to the capture set it represents.
58-
* For efficience, the result is cached as an Attachment on the tree.
57+
/** The type representing the capture set of @retains, @retainsCap or @retainsByName
58+
* annotation tree.
5959
*/
60-
def toCaptureSet(using Context): CaptureSet =
61-
tree.getAttachment(Captures) match
62-
case Some(refs) => refs
63-
case None =>
64-
val refs = CaptureSet(tree.retainedSet.retainedElements*)
65-
tree.putAttachment(Captures, refs)
66-
refs
67-
68-
/** The type representing the capture set of @retains, @retainsCap or @retainsByName annotation. */
6960
def retainedSet(using Context): Type =
7061
val rcap = defn.RetainsCapAnnot
7162
if tree.symbol == rcap || tree.symbol.maybeOwner == rcap then
7263
defn.captureRoot.termRef
7364
else tree match
7465
case Apply(TypeApply(_, refs :: Nil), _) => refs.tpe
75-
case tree: TypeTree =>
76-
tree.tpe match
77-
case AppliedType(_, refs :: Nil) => refs
78-
case _ => NoType
7966
case _ => NoType
8067

8168
extension (tp: Type)
@@ -101,8 +88,8 @@ extension (tp: Type)
10188
def retainedElementsRaw(using Context): List[Type] = tp match
10289
case OrType(tp1, tp2) =>
10390
tp1.retainedElementsRaw ++ tp2.retainedElementsRaw
104-
case AnnotatedType(tp1, ann) if tp1.derivesFrom(defn.Caps_CapSet) && ann.symbol.isRetains =>
105-
ann.tree.retainedSet.retainedElementsRaw
91+
case AnnotatedType(tp1, ann: RetainingAnnotation) if tp1.derivesFrom(defn.Caps_CapSet) && ann.isStrict =>
92+
ann.retainedType.retainedElementsRaw
10693
case tp =>
10794
tp.dealiasKeepAnnots match
10895
case tp: TypeRef if tp.symbol == defn.Caps_CapSet =>
@@ -244,10 +231,11 @@ extension (tp: Type)
244231
case tp @ CapturingType(parent, refs) =>
245232
if tp.isBoxed || parent.derivesFrom(defn.Caps_CapSet) then tp
246233
else tp.boxed
234+
case tp @ AnnotatedType(parent, ann: RetainingAnnotation)
235+
if ann.isStrict && !parent.derivesFrom(defn.Caps_CapSet) =>
236+
CapturingType(parent, ann.toCaptureSet, boxed = true)
247237
case tp @ AnnotatedType(parent, ann) =>
248-
if ann.symbol.isRetains && !parent.derivesFrom(defn.Caps_CapSet)
249-
then CapturingType(parent, ann.tree.toCaptureSet, boxed = true)
250-
else tp.derivedAnnotatedType(parent.boxDeeply, ann)
238+
tp.derivedAnnotatedType(parent.boxDeeply, ann)
251239
case tp: (Capability & SingletonType) if tp.isTrackableRef && !tp.isAlwaysPure =>
252240
recur(CapturingType(tp, CaptureSet(tp)))
253241
case tp1 @ AppliedType(tycon, args) if defn.isNonRefinedFunction(tp1) =>

compiler/src/dotty/tools/dotc/cc/CaptureSet.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1674,8 +1674,8 @@ object CaptureSet:
16741674
else empty
16751675
case CapturingType(parent, refs) =>
16761676
recur(parent) ++ refs
1677-
case tp @ AnnotatedType(parent, ann) if ann.symbol.isRetains =>
1678-
recur(parent) ++ ann.tree.toCaptureSet
1677+
case tp @ AnnotatedType(parent, ann: RetainingAnnotation) if ann.isStrict =>
1678+
recur(parent) ++ ann.toCaptureSet
16791679
case tpd @ defn.RefinedFunctionOf(rinfo: MethodOrPoly) if followResult =>
16801680
ofType(tpd.parent, followResult = false) // pick up capture set from parent type
16811681
++ recur(rinfo.resType).freeInResult(rinfo) // add capture set of result

compiler/src/dotty/tools/dotc/cc/CapturingType.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ object CapturingType:
6060
case AnnotatedType(parent, ann: CaptureAnnotation)
6161
if isCaptureCheckingOrSetup =>
6262
Some((parent, ann.refs))
63-
case AnnotatedType(parent, ann) if ann.symbol.isRetains && alsoRetains =>
63+
case AnnotatedType(parent, ann: RetainingAnnotation) if ann.isStrict && alsoRetains =>
6464
// There are some circumstances where we cannot map annotated types
6565
// with retains annotations to capturing types, so this second recognizer
6666
// path still has to exist. One example is when checking capture sets
@@ -75,7 +75,7 @@ object CapturingType:
7575
//
7676
// TODO In other situations we expect that the type is already transformed to a
7777
// CapturingType and we should crash if this not the case.
78-
try Some((parent, ann.tree.toCaptureSet))
78+
try Some((parent, ann.toCaptureSet))
7979
catch case ex: IllegalCaptureRef => None
8080
case _ =>
8181
None

compiler/src/dotty/tools/dotc/cc/RetainingAnnotation.scala

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,13 @@ class RetainingAnnotation(tpe: Type) extends CompactAnnotation(tpe):
3131
override def mapWith(tm: TypeMap)(using Context): Annotation =
3232
if Feature.ccEnabledSomewhere then mapWithCtd(tm) else EmptyAnnotation
3333

34-
/*
34+
def isStrict(using Context): Boolean = symbol.isRetains
35+
36+
def retainedType(using Context): Type =
37+
if symbol == defn.RetainsCapAnnot then defn.captureRoot.termRef
38+
else argumentType(0)
39+
3540
def toCaptureSet(using Context): CaptureSet =
36-
CaptureSet(argumentType(0).retainedElements*)
37-
*/
41+
CaptureSet(retainedType.retainedElements*)
42+
3843
end RetainingAnnotation

compiler/src/dotty/tools/dotc/cc/RetainingType.scala

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,7 @@ object RetainingType:
1414
val annotCls = if byName then defn.RetainsByNameAnnot else defn.RetainsAnnot
1515
AnnotatedType(tp, RetainingAnnotation(annotCls.typeRef.appliedTo(typeElems)))
1616

17-
def unapply(tp: AnnotatedType)(using Context): Option[(Type, Type)] =
18-
val sym = tp.annot.symbol
19-
if sym.isRetainsLike then
20-
tp.annot match
21-
case _: CaptureAnnotation => None
22-
case ann => Some((tp.parent, ann.tree.retainedSet))
23-
else
24-
None
17+
def unapply(tp: AnnotatedType)(using Context): Option[(Type, Type)] = tp.annot match
18+
case ann: RetainingAnnotation => Some((tp.parent, ann.retainedType))
19+
case _ => None
2520
end RetainingType

compiler/src/dotty/tools/dotc/cc/Setup.scala

Lines changed: 19 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -433,23 +433,21 @@ class Setup extends PreRecheck, SymTransformer, SetupAPI:
433433
case t @ CapturingType(parent, refs) =>
434434
checkRetainsOK:
435435
t.derivedCapturingType(stripImpliedCaptureSet(this(parent)), refs)
436-
case t @ AnnotatedType(parent, ann) =>
437-
val parent1 = this(parent)
438-
if ann.symbol.isRetains then
439-
val parent2 = stripImpliedCaptureSet(parent1)
436+
case t @ AnnotatedType(parent, ann: RetainingAnnotation) if ann.isStrict =>
437+
val parent1 = stripImpliedCaptureSet(this(parent))
438+
if !tptToCheck.isEmpty then
439+
checkWellformedLater(parent1, ann, tptToCheck)
440+
try
441+
checkRetainsOK:
442+
CapturingType(parent1, ann.toCaptureSet)
443+
catch case ex: IllegalCaptureRef =>
440444
if !tptToCheck.isEmpty then
441-
checkWellformedLater(parent2, ann.tree, tptToCheck)
442-
try
443-
checkRetainsOK:
444-
CapturingType(parent2, ann.tree.toCaptureSet)
445-
catch case ex: IllegalCaptureRef =>
446-
if !tptToCheck.isEmpty then
447-
report.error(em"Illegal capture reference: ${ex.getMessage}", tptToCheck.srcPos)
448-
parent2
449-
else if ann.symbol == defn.UncheckedCapturesAnnot then
450-
makeUnchecked(apply(parent))
451-
else
452-
t.derivedAnnotatedType(parent1, ann)
445+
report.error(em"Illegal capture reference: ${ex.getMessage}", tptToCheck.srcPos)
446+
parent1
447+
case t @ AnnotatedType(parent, ann) =>
448+
if ann.symbol == defn.UncheckedCapturesAnnot
449+
then makeUnchecked(this(parent))
450+
else t.derivedAnnotatedType(this(parent), ann)
453451
case throwsAlias(res, exc) =>
454452
this(expandThrowsAlias(res, exc, Nil))
455453
case t @ AppliedType(tycon, args)
@@ -972,15 +970,13 @@ class Setup extends PreRecheck, SymTransformer, SetupAPI:
972970
* @param ann the original retains annotation
973971
* @param tpt the tree for which an error or warning should be reported
974972
*/
975-
private def checkWellformed(parent: Type, ann: Tree, tpt: Tree)(using Context): Unit =
976-
capt.println(i"checkWF post $parent ${ann.retainedSet} in $tpt")
973+
private def checkWellformed(parent: Type, ann: RetainingAnnotation, tpt: Tree)(using Context): Unit =
974+
capt.println(i"checkWF post $parent ${ann.retainedType} in $tpt")
977975
try
978-
var retained = ann.retainedSet.retainedElements.toArray
976+
var retained = ann.retainedType.retainedElements.toArray
979977
for i <- 0 until retained.length do
980978
val ref = retained(i)
981-
def pos =
982-
if ann.span.exists then ann.srcPos
983-
else tpt.srcPos
979+
def pos = tpt.srcPos
984980

985981
def check(others: CaptureSet, dom: Type | CaptureSet): Unit =
986982
if others.accountsFor(ref) then
@@ -1013,7 +1009,7 @@ class Setup extends PreRecheck, SymTransformer, SetupAPI:
10131009
* recheck because we find out only then whether capture sets are empty or
10141010
* capabilities are redundant.
10151011
*/
1016-
private def checkWellformedLater(parent: Type, ann: Tree, tpt: Tree)(using Context): Unit =
1012+
private def checkWellformedLater(parent: Type, ann: RetainingAnnotation, tpt: Tree)(using Context): Unit =
10171013
if !tpt.span.isZeroExtent && enclosingInlineds.isEmpty then
10181014
todoAtPostCheck += (ctx1 =>
10191015
checkWellformed(parent, ann, tpt)(using ctx1.withOwner(ctx.owner)))

compiler/src/dotty/tools/dotc/printing/PlainPrinter.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -317,8 +317,8 @@ class PlainPrinter(_ctx: Context) extends Printer {
317317
}
318318
case ExprType(restp) =>
319319
def arrowText: Text = restp match
320-
case AnnotatedType(parent, ann) if ann.symbol == defn.RetainsByNameAnnot =>
321-
ann.tree.retainedSet.retainedElementsRaw match
320+
case AnnotatedType(parent, ann: RetainingAnnotation) if !ann.isStrict =>
321+
ann.retainedType.retainedElementsRaw match
322322
case ref :: Nil if ref.isCapRef => Str("=>")
323323
case refs => Str("->") ~ toTextRetainedElems(refs)
324324
case _ =>

compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -705,7 +705,7 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) {
705705
toTextTemplate(tree)
706706
case Annotated(arg, annot) =>
707707
def captureSet =
708-
annot.asInstanceOf[tpd.Tree].toCaptureSet
708+
CaptureSet(annot.asInstanceOf[tpd.Tree].retainedSet.retainedElements*)
709709
def toTextAnnot =
710710
toTextLocal(arg) ~~ annotText(annot.symbol.enclosingClass, annot)
711711
def toTextRetainsAnnot =

0 commit comments

Comments
 (0)