Skip to content

Commit 589bc94

Browse files
committed
Allow local exclusive caps in lazy val initializer
1 parent 5fc747a commit 589bc94

File tree

2 files changed

+27
-10
lines changed

2 files changed

+27
-10
lines changed

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

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -746,14 +746,18 @@ class CheckCaptures extends Recheck, SymTransformer:
746746
checkUpdate(qualType, tree.srcPos):
747747
i"Cannot call update ${tree.symbol} of ${qualType.showRef}"
748748

749-
// Additionally, lazy val initializers should not call update methods
749+
// Additionally, lazy val initializers should not call update methods on
750+
// non-local exclusive capabilities (capabilities defined outside the lazy val)
750751
if curEnv.owner.is(Lazy) then
751752
qualType.captureSet.elems.foreach: elem =>
752753
if elem.isExclusive then
753-
report.error(
754-
em"""Lazy val initializer calls update method on exclusive capability $elem;
755-
|lazy val initializers should only access capabilities in a read-only fashion.""",
756-
tree.srcPos)
754+
val owner = elem.pathOwner
755+
// Allow update methods on local capabilities (owned by the lazy val or nested within it)
756+
if !owner.isContainedIn(curEnv.owner) && owner != curEnv.owner then
757+
report.error(
758+
em"""Lazy val initializer calls update method on non-local exclusive capability $elem;
759+
|lazy val initializers should only access non-local capabilities in a read-only fashion.""",
760+
tree.srcPos)
757761

758762
// If selecting a lazy val member, charge the qualifier since accessing
759763
// the lazy val can trigger initialization that uses the qualifier's capabilities

tests/neg-custom-args/captures/lazyvals-sep.scala

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -93,8 +93,21 @@ class WrapperRd(val ref: Ref^{cap.rd}):
9393
case _: Exception => 0
9494
() => r.get() + x
9595

96-
// // Test case 12: Local exclusive access - should be OK
97-
// lazy val lazyVal12: () => Int =
98-
// val r3: Ref^ = Ref(10)
99-
// r3.set(100) FIXME should work
100-
// () => r3.get()
96+
// Test case 12: Local exclusive access - should be OK
97+
lazy val lazyVal12: () => Int =
98+
val r3: Ref^ = Ref(10)
99+
r3.set(100) // ok
100+
val i = r3.get()
101+
() => i
102+
103+
// Test case 13: Local exclusive access - should be OK
104+
lazy val lazyVal13: () => Int =
105+
val r3: Ref^ = Ref(10)
106+
r3.set(100) // ok
107+
() => r3.get()
108+
109+
// Test case 14: Local exclusive access - should be OK
110+
lazy val lazyVal14: () => Ref^ =
111+
val r3: Ref^ = Ref(10)
112+
r3.set(100) // ok
113+
() => r3

0 commit comments

Comments
 (0)