Skip to content

Commit d0f0819

Browse files
authored
Fix #23885: Skip capture sets in checkNoPrivateLeaks and drop them in posttyper when cc is not enabled (#23886)
Fix #23885
2 parents fc2244e + d1fe1fd commit d0f0819

File tree

5 files changed

+25
-9
lines changed

5 files changed

+25
-9
lines changed

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

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -898,7 +898,9 @@ object Capabilities:
898898
case t @ AnnotatedType(parent, ann) =>
899899
val parent1 = this(parent)
900900
if ann.symbol.isRetains && ann.tree.toCaptureSet.containsCap then
901-
this(CapturingType(parent1, ann.tree.toCaptureSet))
901+
// Applying `this` can cause infinite recursion in some cases during printing.
902+
// scalac -Xprint:all tests/pos/i23885/S_1.scala tests/pos/i23885/S_2.scala
903+
mapOver(CapturingType(parent1, ann.tree.toCaptureSet))
902904
else
903905
t.derivedAnnotatedType(parent1, ann)
904906
case defn.RefinedFunctionOf(_) =>

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

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import Annotations.Annotation
1414
import CaptureSet.VarState
1515
import Capabilities.*
1616
import StdNames.nme
17+
import config.Feature
1718

1819
/** Attachment key for capturing type trees */
1920
private val Captures: Key[CaptureSet] = Key()
@@ -634,13 +635,18 @@ extension (tp: AnnotatedType)
634635
case ann: CaptureAnnotation => ann.boxed
635636
case _ => false
636637

637-
/** Drop retains annotations in the type. */
638+
/** Drop retains annotations in the inferred type if CC is not enabled
639+
* or transform them into RetainingTypes if CC is enabled.
640+
*/
638641
class CleanupRetains(using Context) extends TypeMap:
639-
def apply(tp: Type): Type =
640-
tp match
641-
case AnnotatedType(tp, annot) if annot.symbol == defn.RetainsAnnot || annot.symbol == defn.RetainsByNameAnnot =>
642-
RetainingType(tp, defn.NothingType, byName = annot.symbol == defn.RetainsByNameAnnot)
643-
case _ => mapOver(tp)
642+
def apply(tp: Type): Type = tp match
643+
case AnnotatedType(parent, annot) if annot.symbol.isRetainsLike =>
644+
if Feature.ccEnabled then
645+
if annot.symbol == defn.RetainsAnnot || annot.symbol == defn.RetainsByNameAnnot then
646+
RetainingType(parent, defn.NothingType, byName = annot.symbol == defn.RetainsByNameAnnot)
647+
else mapOver(tp)
648+
else apply(parent)
649+
case _ => mapOver(tp)
644650

645651
/** A base class for extractors that match annotated types with a specific
646652
* Capability annotation.

compiler/src/dotty/tools/dotc/typer/Checking.scala

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -771,8 +771,9 @@ object Checking {
771771
!(symBoundary.isContainedIn(otherBoundary) ||
772772
otherLinkedBoundary.exists && symBoundary.isContainedIn(otherLinkedBoundary))
773773
}
774-
&& !(inCaptureSet && other.isAllOf(LocalParamAccessor))
775-
// class parameters in capture sets are not treated as leaked since in
774+
&& !(inCaptureSet && (!Feature.ccEnabled || other.isAllOf(LocalParamAccessor)))
775+
// All references are skipped in capture sets when CC is not enabled.
776+
// Class parameters in capture sets are not treated as leaked since in
776777
// phase CheckCaptures these are treated as normal vals.
777778

778779
def apply(tp: Type): Type = tp match {

tests/pos/i23885/S_1.scala

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
import language.experimental.captureChecking
2+
3+
class A:
4+
def f(x: A^): A^{this, x} = ???

tests/pos/i23885/S_2.scala

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
class B:
2+
private val a: A = ???
3+
def g(b: A) = a.f(b)

0 commit comments

Comments
 (0)