Skip to content

Commit 7e30b27

Browse files
committed
Introduce transparent vars
1 parent 4569955 commit 7e30b27

File tree

7 files changed

+63
-9
lines changed

7 files changed

+63
-9
lines changed

compiler/src/dotty/tools/dotc/ast/Desugar.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -226,7 +226,7 @@ object desugar {
226226
paramss = (setterParam :: Nil) :: Nil,
227227
tpt = TypeTree(defn.UnitType),
228228
rhs = setterRhs
229-
).withMods((vdef.mods | Accessor) &~ (CaseAccessor | GivenOrImplicit | Lazy))
229+
).withMods((vdef.mods | Accessor) &~ (CaseAccessor | GivenOrImplicit | Lazy | Transparent))
230230
.dropEndMarker() // the end marker should only appear on the getter definition
231231
Thicket(vdef1, setter)
232232
else vdef1

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

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -352,11 +352,14 @@ extension (tp: Type)
352352
case _ =>
353353
false
354354

355-
/** Is this a type extending `Mutable` that has update methods? */
355+
/** Is this a type extending `Mutable` that has update methods
356+
* or non-private mutable fields?
357+
*/
356358
def isMutableType(using Context): Boolean =
357359
tp.derivesFrom(defn.Caps_Mutable)
358-
&& tp.membersBasedOnFlags(Mutable | Method, EmptyFlags)
359-
.exists(_.hasAltWith(_.symbol.isUpdateMethod))
360+
&& tp.membersBasedOnFlags(Mutable, EmptyFlags).exists: mbr =>
361+
if mbr.symbol.is(Method) then mbr.symbol.isUpdateMethod
362+
else !mbr.symbol.is(Transparent)
360363

361364
/** Is this a reference to caps.cap? Note this is _not_ the GlobalCap capability. */
362365
def isCapRef(using Context): Boolean = tp match

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1004,7 +1004,8 @@ class CheckCaptures extends Recheck, SymTransformer:
10041004
val lhsType = recheck(tree.lhs, LhsProto)
10051005
recheck(tree.rhs, lhsType.widen)
10061006
lhsType match
1007-
case lhsType @ TermRef(qualType, _) if qualType ne NoPrefix =>
1007+
case lhsType @ TermRef(qualType, _)
1008+
if (qualType ne NoPrefix) && !lhsType.symbol.is(Transparent) =>
10081009
checkUpdate(qualType, tree.srcPos)(i"Cannot assign to field ${lhsType.name} of ${qualType.showRef}")
10091010
case _ =>
10101011
defn.UnitType

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

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -630,8 +630,13 @@ object Checking {
630630
if sym.is(Transparent) then
631631
if sym.isType then
632632
if !sym.isExtensibleClass then fail(em"`transparent` can only be used for extensible classes and traits")
633+
else if sym.isMutableVar && sym.owner.isClass && Feature.ccEnabled
634+
|| sym.isInlineMethod
635+
then
636+
() // ok
633637
else
634-
if !sym.isInlineMethod then fail(em"`transparent` can only be used for inline methods")
638+
def ccAdd = if Feature.ccEnabled then i" and mutable fields" else ""
639+
fail(em"`transparent` can only be used for inline methods$ccAdd")
635640
if (!sym.isClass && sym.is(Abstract))
636641
fail(OnlyClassesCanBeAbstract(sym))
637642
// note: this is not covered by the next test since terms can be abstract (which is a dual-mode flag)
@@ -691,7 +696,7 @@ object Checking {
691696
if sym.isWrappedToplevelDef && !sym.isType && sym.flags.is(Infix, butNot = Extension) then
692697
fail(ModifierNotAllowedForDefinition(Flags.Infix, s"A top-level ${sym.showKind} cannot be infix."))
693698
if sym.isUpdateMethod && !sym.owner.derivesFrom(defn.Caps_Mutable) then
694-
fail(em"Update methods can only be used as members of classes extending the `Mutable` trait")
699+
fail(em"Update method ${sym.name} must be declared in a class extending the `Mutable` trait.")
695700
if sym.is(Erased) then checkErasedOK(sym)
696701
checkCombination(Final, Open)
697702
checkCombination(Sealed, Open)
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
-- Error: tests/neg-custom-args/captures/mut-outside-mutable.scala:5:13 ------------------------------------------------
22
5 | update def foreach(op: T => Unit): Unit // error
33
| ^
4-
| Update methods can only be used as members of classes extending the `Mutable` trait
4+
| Update method foreach must be declared in a class extending the `Mutable` trait.
55
-- Error: tests/neg-custom-args/captures/mut-outside-mutable.scala:9:15 ------------------------------------------------
66
9 | update def baz() = 1 // error
77
| ^
8-
| Update methods can only be used as members of classes extending the `Mutable` trait
8+
| Update method baz must be declared in a class extending the `Mutable` trait.
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import compiletime.uninitialized
2+
class LazyRef[T](val mkElem: () => T):
3+
transparent var elem: T = uninitialized
4+
transparent var evaluated = false
5+
def get: T =
6+
if !evaluated then
7+
elem = mkElem()
8+
evaluated = true
9+
elem
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
class Ref[T](init: T) extends caps.Mutable:
2+
transparent var fld: T = init
3+
def hide(x: T) = this.fld = x // ok
4+
update def hide2(x: T) = this.fld = x // ok
5+
6+
def sneakyHide(x: T) =
7+
val self = this
8+
self.fld = x // ok
9+
10+
val self3 = () => this
11+
self3().fld = x // ok
12+
13+
def self5() = this
14+
self5().fld = x // ok
15+
16+
class Ref2[T](init: T) extends caps.Mutable:
17+
val x = Ref[T](init)
18+
def set(x: T) = this.x.fld = x // ok
19+
update def set2(x: T) = this.x.fld = x // ok
20+
21+
def test =
22+
val r = Ref(22)
23+
r.fld = 33 // ok
24+
val r1: Ref[Int] = Ref(22)
25+
r1.fld = 33 // ok
26+
27+
val r2 = Ref2(22)
28+
r2.x.fld = 33 // ok
29+
val r3: Ref2[Int] = Ref2(22)
30+
r3.x.fld = 33 // ok
31+
32+
val r4 = () => Ref2(22)
33+
r4().x.fld = 33 // ok
34+
val ref2: Ref2[Int] = Ref2(22)
35+
val r6: () => Ref2[Int] = () => ref2
36+
r6().x.fld = 33 // ok

0 commit comments

Comments
 (0)