Skip to content

Rename mut to update #23335

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Jun 10, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion compiler/src/dotty/tools/dotc/ast/untpd.scala
Original file line number Diff line number Diff line change
Expand Up @@ -206,7 +206,7 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo {

case class Var()(implicit @constructorOnly src: SourceFile) extends Mod(Flags.Mutable)

case class Mut()(implicit @constructorOnly src: SourceFile) extends Mod(Flags.Mutable)
case class Update()(implicit @constructorOnly src: SourceFile) extends Mod(Flags.Mutable)

case class Implicit()(implicit @constructorOnly src: SourceFile) extends Mod(Flags.Implicit)

Expand Down
1 change: 0 additions & 1 deletion compiler/src/dotty/tools/dotc/core/StdNames.scala
Original file line number Diff line number Diff line change
Expand Up @@ -553,7 +553,6 @@ object StdNames {
val maybeCapability: N = "maybeCapability"
val mirror : N = "mirror"
val moduleClass : N = "moduleClass"
val mut: N = "mut"
val name: N = "name"
val nameDollar: N = "$name"
val ne: N = "ne"
Expand Down
4 changes: 2 additions & 2 deletions compiler/src/dotty/tools/dotc/parsing/Parsers.scala
Original file line number Diff line number Diff line change
Expand Up @@ -3291,7 +3291,7 @@ object Parsers {
case nme.infix => Mod.Infix()
case nme.tracked => Mod.Tracked()
case nme.erased if in.erasedEnabled => Mod.Erased()
case nme.mut if Feature.ccEnabled => Mod.Mut()
case nme.update if Feature.ccEnabled => Mod.Update()
}
}

Expand Down Expand Up @@ -4708,7 +4708,7 @@ object Parsers {
Nil
tree match
case tree: MemberDef
if !(tree.mods.flags & ModifierFlags).isEmpty && !tree.mods.isMutableVar => // vars are OK, mut defs are not
if !(tree.mods.flags & ModifierFlags).isEmpty && !tree.mods.isMutableVar => // vars are OK, update defs are not
fail(em"refinement cannot be ${(tree.mods.flags & ModifierFlags).flagStrings().mkString("`", "`, `", "`")}")
case tree: DefDef if tree.termParamss.nestedExists(!_.rhs.isEmpty) =>
fail(em"refinement cannot have default arguments")
Expand Down
2 changes: 1 addition & 1 deletion compiler/src/dotty/tools/dotc/parsing/Scanners.scala
Original file line number Diff line number Diff line change
Expand Up @@ -1228,7 +1228,7 @@ object Scanners {
&& (softModifierNames.contains(name)
|| name == nme.erased && erasedEnabled
|| name == nme.tracked && trackedEnabled
|| name == nme.mut && Feature.ccEnabled)
|| name == nme.update && Feature.ccEnabled)

def isSoftModifierInModifierPosition: Boolean =
isSoftModifier && inModifierPosition()
Expand Down
2 changes: 1 addition & 1 deletion compiler/src/dotty/tools/dotc/parsing/Tokens.scala
Original file line number Diff line number Diff line change
Expand Up @@ -299,7 +299,7 @@ object Tokens extends TokensCommon {

final val closingParens = BitSet(RPAREN, RBRACKET, RBRACE)

final val softModifierNames = Set(nme.inline, nme.into, nme.opaque, nme.open, nme.transparent, nme.infix)
final val softModifierNames = Set(nme.inline, nme.into, nme.opaque, nme.open, nme.transparent, nme.infix, nme.update)

def showTokenDetailed(token: Int): String = debugString(token)

Expand Down
30 changes: 15 additions & 15 deletions docs/_docs/internals/exclusive-capabilities.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,27 +18,27 @@ We introduce a new trait
trait Mutable
```
It is used as a base trait for types that define _update methods_ using
a new modifier `mut`.
a new soft modifier `update`.

`mut` can only be used in classes or objects extending `Mutable`. An update method is allowed to access exclusive capabilities in the method's environment. By contrast, a normal method in a type extending `Mutable` may access exclusive capabilities only if they are defined locally or passed to it in parameters.
`update` can only be used in classes or objects extending `Mutable`. An update method is allowed to access exclusive capabilities in the method's environment. By contrast, a normal method in a type extending `Mutable` may access exclusive capabilities only if they are defined locally or passed to it in parameters.

**Example:**
```scala
class Ref(init: Int) extends Mutable:
private var current = init
def get: Int = current
mut def put(x: Int): Unit = current = x
update def put(x: Int): Unit = current = x
```
Here, `put` needs to be declared as an update method since it accesses the exclusive write capability of the variable `current` in its environment.
`mut` can also be used on an inner class of a class or object extending `Mutable`. It gives all code in the class the right
`update` can also be used on an inner class of a class or object extending `Mutable`. It gives all code in the class the right
to access exclusive capabilities in the class environment. Normal classes
can only access exclusive capabilities defined in the class or passed to it in parameters.

```scala
object Registry extends Mutable:
var count = 0
mut class Counter:
mut def next: Int =
update class Counter:
update def next: Int =
count += 1
count
```
Expand Down Expand Up @@ -79,22 +79,22 @@ Consider trait `IterableOnce` from the standard library.
```scala
trait IterableOnce[+T] extends Mutable:
def iterator: Iterator[T]^{this}
mut def foreach(op: T => Unit): Unit
mut def exists(op: T => Boolean): Boolean
update def foreach(op: T => Unit): Unit
update def exists(op: T => Boolean): Boolean
...
```
The trait is a mutable type with many update methods, among them `foreach` and `exists`. These need to be classified as `mut` because their implementation in the subtrait `Iterator` uses the update method `next`.
The trait is a mutable type with many update methods, among them `foreach` and `exists`. These need to be classified as `update` because their implementation in the subtrait `Iterator` uses the update method `next`.
```scala
trait Iterator[T] extends IterableOnce[T]:
def iterator = this
def hasNext: Boolean
mut def next(): T
mut def foreach(op: T => Unit): Unit = ...
mut def exists(op; T => Boolean): Boolean = ...
update def next(): T
update def foreach(op: T => Unit): Unit = ...
update def exists(op; T => Boolean): Boolean = ...
...
```
But there are other implementations of `IterableOnce` that are not mutable types (even though they do indirectly extend the `Mutable` trait). Notably, collection classes implement `IterableOnce` by creating a fresh
`iterator` each time one is required. The mutation via `next()` is then restricted to the state of that iterator, whereas the underlying collection is unaffected. These implementations would implement each `mut` method in `IterableOnce` by a normal method without the `mut` modifier.
`iterator` each time one is required. The mutation via `next()` is then restricted to the state of that iterator, whereas the underlying collection is unaffected. These implementations would implement each `update` method in `IterableOnce` by a normal method without the `update` modifier.

```scala
trait Iterable[T] extends IterableOnce[T]:
Expand Down Expand Up @@ -140,7 +140,7 @@ For instance, a matrix multiplication method can be expressed as follows:

```scala
class Matrix(nrows: Int, ncols: Int) extends Mutable:
mut def update(i: Int, j: Int, x: Double): Unit = ...
update def update(i: Int, j: Int, x: Double): Unit = ...
def apply(i: Int, j: Int): Double = ...

def mul(a: Matrix, b: Matrix, c: Matrix^): Unit =
Expand Down Expand Up @@ -435,7 +435,7 @@ we'd deal with
```scala
val x$ = Ref[T](init)
def x = x$.get
mut def x_=(y: T) = x$.put(y)
update def x_=(y: T) = x$.put(y)
```

There should be a way to exclude a mutable variable or field from tracking. Maybe an annotation or modifier such as `transparent` or `untracked`?
Expand Down
2 changes: 1 addition & 1 deletion tests/neg-custom-args/captures/contracap.scala
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import caps.*
class Ref[T](init: T) extends Mutable:
private var value: T = init
def get: T = value
mut def set(newValue: T): Unit = value = newValue
update def set(newValue: T): Unit = value = newValue

// a library function that assumes that a and b MUST BE separate
def swap[T](a: Ref[Int]^, b: Ref[Int]^): Unit = ???
Expand Down
2 changes: 1 addition & 1 deletion tests/neg-custom-args/captures/linear-buffer-2.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import caps.{cap, consume, Mutable}
import language.experimental.captureChecking

class Buffer[T] extends Mutable:
@consume mut def append(x: T): Buffer[T]^ = this // ok
@consume update def append(x: T): Buffer[T]^ = this // ok

def app[T](@consume buf: Buffer[T]^, elem: T): Buffer[T]^ =
buf.append(elem)
Expand Down
6 changes: 3 additions & 3 deletions tests/neg-custom-args/captures/linear-buffer.check
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
-- Error: tests/neg-custom-args/captures/linear-buffer.scala:5:24 ------------------------------------------------------
5 | mut def append(x: T): BadBuffer[T]^ = this // error
| ^^^^^^^^^^^^^
-- Error: tests/neg-custom-args/captures/linear-buffer.scala:5:27 ------------------------------------------------------
5 | update def append(x: T): BadBuffer[T]^ = this // error
| ^^^^^^^^^^^^^
| Separation failure: method append's result type BadBuffer[T]^ hides non-local this of class class BadBuffer.
| The access must be in a @consume method to allow this.
-- Error: tests/neg-custom-args/captures/linear-buffer.scala:7:13 ------------------------------------------------------
Expand Down
4 changes: 2 additions & 2 deletions tests/neg-custom-args/captures/linear-buffer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,13 @@ import caps.{cap, consume, Mutable}
import language.experimental.captureChecking

class BadBuffer[T] extends Mutable:
mut def append(x: T): BadBuffer[T]^ = this // error
update def append(x: T): BadBuffer[T]^ = this // error
def foo =
def bar: BadBuffer[T]^ = this // error
bar

class Buffer[T] extends Mutable:
@consume mut def append(x: T): Buffer[T]^ = this // ok
@consume update def append(x: T): Buffer[T]^ = this // ok

def app[T](@consume buf: Buffer[T]^, elem: T): Buffer[T]^ =
buf.append(elem)
Expand Down
16 changes: 8 additions & 8 deletions tests/neg-custom-args/captures/mut-outside-mutable.check
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
-- Error: tests/neg-custom-args/captures/mut-outside-mutable.scala:5:10 ------------------------------------------------
5 | mut def foreach(op: T => Unit): Unit // error
| ^
| Update methods can only be used as members of classes extending the `Mutable` trait
-- Error: tests/neg-custom-args/captures/mut-outside-mutable.scala:9:12 ------------------------------------------------
9 | mut def baz() = 1 // error
| ^
| Update methods can only be used as members of classes extending the `Mutable` trait
-- Error: tests/neg-custom-args/captures/mut-outside-mutable.scala:5:13 ------------------------------------------------
5 | update def foreach(op: T => Unit): Unit // error
| ^
| Update methods can only be used as members of classes extending the `Mutable` trait
-- Error: tests/neg-custom-args/captures/mut-outside-mutable.scala:9:15 ------------------------------------------------
9 | update def baz() = 1 // error
| ^
| Update methods can only be used as members of classes extending the `Mutable` trait
4 changes: 2 additions & 2 deletions tests/neg-custom-args/captures/mut-outside-mutable.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ import caps.Mutable

trait IterableOnce[T]:
def iterator: Iterator[T]^{this}
mut def foreach(op: T => Unit): Unit // error
update def foreach(op: T => Unit): Unit // error

trait Foo extends Mutable:
def bar =
mut def baz() = 1 // error
update def baz() = 1 // error
baz()
10 changes: 5 additions & 5 deletions tests/neg-custom-args/captures/mut-override.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,18 @@ import caps.Mutable

trait IterableOnce[T] extends Mutable:
def iterator: Iterator[T]^{this}
mut def foreach(op: T => Unit): Unit
update def foreach(op: T => Unit): Unit

trait Iterator[T] extends IterableOnce[T]:
def iterator = this
def hasNext: Boolean
mut def next(): T
mut def foreach(op: T => Unit): Unit = ???
override mut def toString = ??? // error
update def next(): T
update def foreach(op: T => Unit): Unit = ???
override update def toString = ??? // error

trait Iterable[T] extends IterableOnce[T]:
def iterator: Iterator[T] = ???
def foreach(op: T => Unit) = iterator.foreach(op)

trait BadIterator[T] extends Iterator[T]:
override mut def hasNext: Boolean // error
override update def hasNext: Boolean // error
2 changes: 1 addition & 1 deletion tests/neg-custom-args/captures/readOnly.scala
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import caps.cap
class Ref(init: Int) extends Mutable:
private var current = init
def get: Int = current
mut def put(x: Int): Unit = current = x
update def put(x: Int): Unit = current = x

def Test(c: Object^) =
val a: Ref^ = Ref(1)
Expand Down
2 changes: 1 addition & 1 deletion tests/neg-custom-args/captures/sep-box.scala
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ object NIL extends LIST[Nothing]:
class Ref extends Mutable:
var x = 0
def get: Int = x
mut def put(y: Int): Unit = x = y
update def put(y: Int): Unit = x = y

class Box[+X](val value: X)

Expand Down
2 changes: 1 addition & 1 deletion tests/neg-custom-args/captures/sep-consume.scala
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import caps.*
class Ref extends Mutable:
private var _data = 0
def get: Int = _data
mut def put(x: Int): Unit = _data = x
update def put(x: Int): Unit = _data = x

case class Pair[+A, +B](fst: A, snd: B)

Expand Down
2 changes: 1 addition & 1 deletion tests/neg-custom-args/captures/sep-counter.scala
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import caps.cap
class Ref extends Mutable:
var x = 0
def get: Int = x
mut def put(y: Int): Unit = x = y
update def put(y: Int): Unit = x = y

class Pair[+X, +Y](val fst: X, val snd: Y)

Expand Down
2 changes: 1 addition & 1 deletion tests/neg-custom-args/captures/sep-curried.scala
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import caps.*
class Ref[T](init: T) extends Mutable:
private var value: T = init
def get: T = value
mut def set(newValue: T): Unit = value = newValue
update def set(newValue: T): Unit = value = newValue

// a library function that assumes that a and b MUST BE separate
def swap[T](a: Ref[Int]^, b: Ref[Int]^): Unit = ???
Expand Down
2 changes: 1 addition & 1 deletion tests/neg-custom-args/captures/sep-list.scala
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ object NIL extends LIST[Nothing]:
class Ref extends Mutable:
var x = 0
def get: Int = x
mut def put(y: Int): Unit = x = y
update def put(y: Int): Unit = x = y

def listFresh(n: Int): LIST[Ref^] =
if n == 0 then NIL
Expand Down
2 changes: 1 addition & 1 deletion tests/neg-custom-args/captures/sep-pairs-2.scala
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import caps.cap
class Ref extends Mutable:
var x = 0
def get: Int = x
mut def put(y: Int): Unit = x = y
update def put(y: Int): Unit = x = y

class Pair[+X, +Y](val fst: X, val snd: Y)

Expand Down
2 changes: 1 addition & 1 deletion tests/neg-custom-args/captures/sep-pairs.scala
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import caps.cap
class Ref extends Mutable:
var x = 0
def get: Int = x
mut def put(y: Int): Unit = x = y
update def put(y: Int): Unit = x = y

class Pair[+X, +Y](val fst: X, val snd: Y)

Expand Down
4 changes: 2 additions & 2 deletions tests/neg-custom-args/captures/sepchecks.scala
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ trait Rdr[T]:
class Ref[T](init: T) extends Rdr[T], Mutable:
private var current = init
def get: T = current
mut def put(x: T): Unit = current = x
update def put(x: T): Unit = current = x

def Test(c: Object^): Unit =
val a: Ref[Int]^ = Ref(1)
Expand Down Expand Up @@ -39,7 +39,7 @@ def Test(c: Object^): Unit =
class Matrix(nrows: Int, ncols: Int) extends IMatrix, Mutable:
val arr = Array.fill(nrows, ncols)(0.0)
def apply(i: Int, j: Int): Double = arr(i)(j)
mut def update(i: Int, j: Int, x: Double): Unit = arr(i)(j) = x
update def update(i: Int, j: Int, x: Double): Unit = arr(i)(j) = x

def mul(x: IMatrix^{cap.rd}, y: IMatrix^{cap.rd}, z: Matrix^): Matrix^ = ???

Expand Down
10 changes: 5 additions & 5 deletions tests/neg-custom-args/captures/update-call.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,18 @@ import caps.Mutable

trait IterableOnce[T] extends Mutable:
def iterator: Iterator[T]^{this}
mut def foreach(op: T => Unit): Unit
update def foreach(op: T => Unit): Unit

trait Iterator[T] extends IterableOnce[T]:
def iterator = this
def hasNext: Boolean
mut def next(): T
mut def foreach(op: T => Unit): Unit = ???
override mut def toString = ??? // error
update def next(): T
update def foreach(op: T => Unit): Unit = ???
override update def toString = ??? // error

trait Iterable[T] extends IterableOnce[T]:
def iterator: Iterator[T] = ???
def foreach(op: T => Unit) = iterator.foreach(op)

trait BadIterator[T] extends Iterator[T]:
override mut def hasNext: Boolean // error
override update def hasNext: Boolean // error
2 changes: 1 addition & 1 deletion tests/pos-custom-args/captures/mutRef.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@ import caps.Mutable
class Ref(init: Int) extends Mutable:
private var current = init
def get: Int = current
mut def put(x: Int): Unit = current = x
update def put(x: Int): Unit = current = x
2 changes: 1 addition & 1 deletion tests/pos-custom-args/captures/sep-pairs.scala
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import caps.{cap, consume, use}
class Ref extends Mutable:
var x = 0
def get: Int = x
mut def put(y: Int): Unit = x = y
update def put(y: Int): Unit = x = y

case class Pair[+A, +B](fst: A, snd: B)

Expand Down
Loading