-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Add freeze wrapper #24423
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
base: main
Are you sure you want to change the base?
Add freeze wrapper #24423
Conversation
1. Mutable and ExclsuiveCapability are not longer classifiers. This means
Mutable classes can capture other capabilities. Red is still a classifier.
2. Update methods in nested classes can access exclsuive capabilities external
to enclosing classes.
- Allow to charge read-only set on unboxing (previously it was always the exclusive set that was charged). - Treat also methods outside Mutable types as read-only members. Previously we charged read-only when calling a read-only method of a mutable type, but not when calling an inherited method such as `eq`. - Use the same criterion for read-only everywhere. - Distinguish between read- and write-accesses to mutable fields.
…hecking We do get sometimes capabilities like `async.rd` where `async` is shared. It does not look straightforward to prevent that, so instead we count async.rd as shared if async is.
We need a way to distinguish C^{} and C^{cap} when printing. We
print C^{cap} as C is C is a capability class.
This fix removed quite a few spurious error notes.
Needed to invalidate the relation
C^{} <: C^
for Mutable types C
- New section in separation checking doc page - Slight generalization of expectsReadOnly - Lots of tests variations of scala#24373
e3944d7 to
05f7026
Compare
05f7026 to
aeb0411
Compare
| * result of pure operation `op`, turning them into immutable types. | ||
| */ | ||
| @experimental | ||
| def immutable[T](op: -> T): T = op |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
to me this sounds like a block where mutability should be prevented on the inside, (i.e. like its some pure scope). Alternatively this has an effect similar to "freeze" in other languages (i.e the result is now immutable).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, I was unsure as well. I also thought of freeze before. Do you know which other languages have a construct like this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK, I renamed to freeze. A search showed that it is used like this in Javascript and Haskell and it was proposed for beta.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the mechanism in most cases is assignment to an immutable variable (const in C++, let in Swift, Rust), so not a property of the type. Javascript has Objects.freeze. .NET has a Freezable abstract class
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ruby's root Object class also has a universal freeze method
aeb0411 to
23f66a6
Compare
23f66a6 to
4a17d29
Compare
| * result of pure operation `op`, turning them into immutable types. | ||
| */ | ||
| @experimental | ||
| def immutable[T](op: -> T): T = op |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is not yet renamed to freeze.
|
A soundness issue related to boxes: |
|
Another counter-example related to double-flips: import language.experimental.captureChecking
import language.experimental.separationChecking
import caps.{Mutable, immutable}
// A mutable ref and its immutable version
class Ref extends Mutable:
private var data: Int = 0
def get: Int = data
update def set(x: Int): Unit = data = x
def allocRef(): Ref^ = Ref()
type IRef = Ref^{}
def test1(): Unit =
val magic = immutable: // should be error, but ok
(x: Ref^) => (op: Ref^ => IRef) => op(x)
val reallybad: Ref^ -> Ref^{} = x => magic(x)(x => x)
|
|
@Linyxus Can you try to make this work to fix the unsoundness? |
|
Is the first example compiling because putting a into a Box is a pure operation (doesn't charge a)? |
Based on #24352