Skip to content

Commit 2a0ba0e

Browse files
committed
Don't treat consume class parameters as refining accessors
We don't want to know what the argument type was, since a consume parameter gets integrated in the class cap.
1 parent f43149a commit 2a0ba0e

File tree

2 files changed

+41
-1
lines changed

2 files changed

+41
-1
lines changed

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

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -583,13 +583,16 @@ extension (sym: Symbol)
583583
&& !defn.isPolymorphicAfterErasure(sym)
584584
&& !defn.isTypeTestOrCast(sym)
585585

586-
/** It's a parameter accessor that is not annotated @constructorOnly or @uncheckedCaptures */
586+
/** It's a parameter accessor that is not annotated @constructorOnly or @uncheckedCaptures
587+
* and that is not a consume accessor.
588+
*/
587589
def isRefiningParamAccessor(using Context): Boolean =
588590
sym.is(ParamAccessor)
589591
&& {
590592
val param = sym.owner.primaryConstructor.paramNamed(sym.name)
591593
!param.hasAnnotation(defn.ConstructorOnlyAnnot)
592594
&& !param.hasAnnotation(defn.UntrackedCapturesAnnot)
595+
&& !param.hasAnnotation(defn.ConsumeAnnot)
593596
}
594597

595598
def hasTrackedParts(using Context): Boolean =
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import language.experimental.captureChecking
2+
import language.experimental.separationChecking
3+
import caps.*
4+
5+
// Create a deep nesting structure for testing suffix paths
6+
class D
7+
class C(val d: D^)
8+
class B(val c: C^)
9+
class A(consume val b: B^) extends Mutable { var x: Int = 0 }
10+
11+
// Test 1: Simple suffix paths after consume
12+
def test1 =
13+
val d: D^ = D()
14+
val c: C^ = C(d)
15+
val b: B^ = B(c)
16+
val a = A(b)
17+
18+
// After 'a' consumes 'b', access nested fields:
19+
println(a.b) // OK - consumed field
20+
println(a.b.c) // OK - suffix: .c after consumed field
21+
println(a.b.c.d) // OK - suffix: .c.d after consumed field
22+
23+
// Test 2: Non-consume wrapper with consumed inner field
24+
class Holder(val a: A^) // Note: NOT consume
25+
26+
def test2 =
27+
val d: D^ = D()
28+
val c: C^ = C(d)
29+
val b: B^ = B(c)
30+
val a = A(b)
31+
val holder = Holder(a)
32+
33+
// Access through holder.a.b where b was consumed by a:
34+
println(holder.a) // OK - not consumed
35+
println(holder.a.b) // OK - accessing consumed field through prefix
36+
println(holder.a.b.c) // OK - suffix .c
37+
println(holder.a.b.c.d) // OK - suffix .c.d

0 commit comments

Comments
 (0)