-
Notifications
You must be signed in to change notification settings - Fork 1.1k
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
Exclusive capabilities #22218
base: main
Are you sure you want to change the base?
Exclusive capabilities #22218
Conversation
8cbc022
to
0a73a26
Compare
0da66e2
to
eae9c07
Compare
498f43d
to
af23b3f
Compare
I squashed commits and arranged them in a more logical order. Ready for review now. |
A soundness hole: import caps.cap
import language.future
import language.experimental.captureChecking
def par(op1: () => Unit)(op2: () => Unit): Unit = ()
def bad(io: Object^): () => Unit =
val x: () => Unit = () => println(io)
x
def test(io: Object^): Unit =
par(() => println(io))(() => println(io)) // error // (1)
val f = bad(io)
par(f)(() => println(io)) // no error, but it is equivalent to (1) and should fail The problem is with To properly handle these things I think it is necessary to support |
@Linyxus This is still a work in progress. Separation checking for parameters and returns is not yet implemented. But we'll get back to the test case once it lands. |
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.
LGTM! Just left some minor comments
|
||
/** If true, turn on separation checking */ | ||
def useFresh(using Context): Boolean = |
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.
Let it have a more descriptive name? E.g. useSeparationChecking
|
||
/** A trait for references in CaptureSets. These can be NamedTypes, ThisTypes or ParamRefs, | ||
* as well as two kinds of AnnotatedTypes representing reach and maybe capabilities. | ||
* as well as three kinds of AnnotatedTypes representing readOnly, reach, and maybe capabilities. | ||
* If there are several annotations they come with an orderL |
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.
Is orderL
a typo?
@@ -976,8 +1051,7 @@ object CaptureSet: | |||
def getElems(v: Var): Option[Refs] = elemsMap.get(v) | |||
|
|||
/** Record elements, return whether this was allowed. | |||
* By default, recording is allowed but the special state FrozenState | |||
* overrides this. | |||
* By default, recording is allowed in regular both not in frozen states. |
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.
* By default, recording is allowed in regular both not in frozen states. | |
* By default, recording is allowed in regular but not in frozen states. |
@@ -988,58 +1062,104 @@ object CaptureSet: | |||
def getDeps(v: Var): Option[Deps] = depsMap.get(v) | |||
|
|||
/** Record dependent sets, return whether this was allowed. | |||
* By default, recording is allowed but the special state FrozenState | |||
* overrides this. | |||
* By default, recording is allowed in regular both not in frozen states. |
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.
* By default, recording is allowed in regular both not in frozen states. | |
* By default, recording is allowed in regular but not in frozen states. |
if seen.add(ref) then | ||
try pred finally seen -= ref | ||
else false | ||
|
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.
end VarState | |
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 leave out the end VarState
if the next line is object VarState
. That way, we need only one end
. IN a sense object VarState
is that static part of class VarState
.
* The unboxed condition ensures that the expected is not a type variable | ||
* that's upper bounded by a read-only type. In this case it would not be sound | ||
* to narrow to the read-only set, since that set can be propagated | ||
* by the type variable instantiatiin. |
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.
* by the type variable instantiatiin. | |
* by the type variable instantiation. |
|
||
var reach = false | ||
|
||
private def initHidden = |
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 appears to be a duplicate of ownerToHidden
above. Consolidate?
private def transformTT(tree: TypeTree, boxed: Boolean)(using Context): Unit = | ||
private val paramSigChange = util.EqHashSet[Tree]() | ||
|
||
/** Transform type of tree, and remember the transformed type as the type the tree |
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.
/** Transform type of tree, and remember the transformed type as the type the tree | |
/** Transform type of tree, and remember the transformed type as the type of the tree |
package internal | ||
|
||
/** An annotation used internally for fresh capability wrappers of `cap` | ||
*/ |
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.
Show example just as in readOnlyCapability.scala
library/src/scala/caps.scala
Outdated
@@ -41,6 +43,12 @@ import annotation.{experimental, compileTimeOnly, retainsCap} | |||
*/ | |||
extension (x: Any) def reachCapability: Any = x | |||
|
|||
/** Unique capabilities x! which appear as terms in @retains annotations are encoded | |||
* as `caps.uniqueCapability(x)`. When converted to CaptureRef types in capture sets | |||
* they are represented as `x.type @annotation.internal.uniqueCapability`. |
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.
Do you mean freshCapability
? I don't see uniqueCapability
anywhere.
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.
Also, the extension this comment is attached is named readOnlyCapability
. Is there something missing perhaps?
When printing a type `C^` where `C` extends `Capability`, don't show the `^`. This is overridden under -Yprint-debug.
- Add Mutable trait and mut modifier. - Add dedicated tests `isMutableVar` and `isMutableVarOrAccessor` so that update methods can share the same flag `Mutable` with mutable vars. - Disallow update methods overriding normal methods - Disallow update methods which are not members of classes extending Mutable - Add design document from papers repo to docs/internals - Add readOnly capabilities - Implement raeadOnly access - Check that update methods are only called on references with exclusive capture sets. - Use cap.rd as default capture set of Capability subtypes - Make Mutable a Capability, this means Mutable class references get {cap.rd} as default capture set. - Use {cap} as captu
….toCap If existentials are mapped to fresh, it matters where they are opened. Pure or not arguments don't have anything to do with that.
These are represented as Fresh.Cap(hidden) where hidden is the set of capabilities subsumed by a fresh. The underlying representation is as an annotated type `T @annotation.internal.freshCapability`. Require -source `3.7` for caps to be converted to Fresh.Cap Also: - Refacture and document CaputureSet - Make SimpleIdentitySets showable - Refactor VarState - Drop Frozen enum - Make VarState subclasses inner classes of companion object - Rename them - Give implicit parameter VarState of subCapture method a default value - Fix printing of capturesets containing cap and some other capability - Revise handing of @uncheckedAnnotation
Check separation from source 3.7 on. We currently only check applications, other areas of separation checking are still to be implemented.
Check that a capability that gets hidden in the (result-)type of some definition is not used afterwards in the same or a nested scope.
When checking whether two items overlap we should always check their deep capture sets. Buried aliases should count as well.
This is necessary since capability sets are IdentitySets.
3.7 is already on us, so bump by one. Two new tests for separation checking. One i15749a required a change in SepCheck: We need to be able to declare reach capabilities in dependencies. The reach is imply dropped. But we can't sometimes use a normal capability since its capture set might be empty.
79f8ef1
to
0b9acb3
Compare
A draft PR to implement Capybara-like mutation checking