V6002 scoped_value_escape
A scoped value escapes the with that bounds it (design §6.3, §17.70).
An error from the capability phase. sakura explain V6002 prints this explanation offline.
A scoped value escapes the with that bounds it (design §6.3, §17.70). Scoped types are
external types (Dir, File, Scope, …), Handler<…> and any type containing one; a lambda is
scoped when its type is, or when it captures a scoped local. This fires when the value of a
with expression is scoped, when a top-level let has a scoped type, and when the lambda given
to Task.spawn captures a scoped local bound inside a with that encloses the spawn but not the
binding of its Scope. Returning a scoped value from an ordinary function is allowed.
Wrong:
import std/fs.{Fs}
fn leak() -> Handler<Fs> ! {Fs} {
with Fs.rooted(Fs.root()) { Fs.rooted(Fs.root()) }
}Fixed (use the handler inside the with and return data):
import std/fs.{Fs, FsError}
import std/path.{Path}
fn read_config() -> Bytes ! {Fs, Fail<FsError>} {
with Fs.rooted(Fs.root()) { Fs.read(Path.of("config.toml")) }
}Wrong program
compiler/tests/ui/V6002_scoped_value_escape.sakura, which the compiler's ui suite runs through sakura check:
import std/fs.{Fs}
fn leak() -> Handler<Fs> ! {Fs} { with Fs.rooted(Fs.root()) { Fs.rooted(Fs.root()) } }sakura check --json reports this record (pretty-printed; $DIR is the fixture's directory):
{
"schema_version": "1.0",
"kind": "diagnostic",
"id": "d:1aa70ab5e952dc43",
"code": "V6002",
"severity": "error",
"phase": "capability",
"message": "the value of this `with` is a `Handler<Fs>`, a scoped value: capabilities, handlers and resources may not outlive the `with` that produced them (design §6.3)",
"snapshot": "sha256:$SNAPSHOT",
"symbol_id": "main::V6002_scoped_value_escape::leak",
"spans": [
{
"uri": "file://$DIR/V6002_scoped_value_escape.sakura",
"content_hash": "sha256:afc99366219bd0d4a54a4e2ac146eb68f3f379f6e940a7d3dba2b8d2f5d5411b",
"start_byte": 140,
"end_byte": 160,
"role": "primary"
}
],
"related_ids": [],
"expected": null,
"actual": null,
"obligation": null,
"counterexample": null,
"explanation_uri": "sakura://explain/V6002",
"fixes": []
}More fixtures for this code: compiler/tests/ui/V6002_spawn_captures_inner_with.sakura, compiler/tests/ui/V6002_spawn_nested_lambda.sakura.
Fixed program
compiler/tests/ui/V6002_scoped_value_escape.fixed.sakura, which sakura check accepts with no diagnostics:
import std/fs.{Fs, FsError}
import std/path.{Path}
fn read_config() -> Bytes ! {Fs, Fail<FsError>} {
with Fs.rooted(Fs.root()) { Fs.read(Path.of("config.toml")) }
}V6001 capability_construction
Capability values (Dir, NetScope, EnvScope, SecretStore) cannot be constructed by user code.
V6003 resource_escape
A @resource value (v0: File) escapes the callback of the operation that introduced it: the callback returns a type containing it (directly, or inside a record, list or closure), or the value is stored in handler var state (design §8.4, §17.70).