Sakura Lang

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).

An error from the capability phase. sakura explain V6003 prints this explanation offline.

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). The runtime closes the file when the callback returns, so an escaped File cannot be used. Read or write inside the callback and return ordinary data. Use-at-most-once is not checked statically in v0.

Wrong:

import std/fs.{Fs, File, Mode, FsError}
import std/path.{Path}
fn keep_open(p: Path) -> File ! {Fs, Fail<FsError>} {
  Fs.with_file(p, Mode.Read, fn(file) { file })
}

Fixed:

fn first_kb(p: Path) -> Bytes ! {Fs, Fail<FsError>} {
  Fs.with_file(p, Mode.Read, fn(file) { Fs.read_chunk(file, 1024) })
}

Wrong program

compiler/tests/ui/V6003_resource_escape.sakura, which the compiler's ui suite runs through sakura check:

import std/fs.{File, Fs, FsError, Mode}
import std/path.{Path}

fn keep_open(p: Path) -> File ! {Fs, Fail<FsError>} {
  Fs.with_file(p, Mode.Read, fn(file) { file })
}

sakura check --json reports this record (pretty-printed; $DIR is the fixture's directory):

{
  "schema_version": "1.0",
  "kind": "diagnostic",
  "id": "d:9a99a69a967c1b07",
  "code": "V6003",
  "severity": "error",
  "phase": "capability",
  "message": "this `File` escapes the callback of `with_file`: it holds a resource, which is closed when the callback returns (design §8.4)",
  "snapshot": "sha256:$SNAPSHOT",
  "symbol_id": "main::V6003_resource_escape::keep_open",
  "spans": [
    {
      "uri": "file://$DIR/V6003_resource_escape.sakura",
      "content_hash": "sha256:579bb06c8d05fa88c34b60f174de613fd71825550c967a76fdccb4e0dd20580f",
      "start_byte": 216,
      "end_byte": 220,
      "role": "primary"
    }
  ],
  "related_ids": [],
  "expected": null,
  "actual": null,
  "obligation": null,
  "counterexample": null,
  "explanation_uri": "sakura://explain/V6003",
  "fixes": []
}

More fixtures for this code: compiler/tests/ui/V6003_route_handler_returns_file.sakura.

Fixed program

compiler/tests/ui/V6003_resource_escape.fixed.sakura, which sakura check accepts with no diagnostics:

import std/fs.{Fs, FsError, Mode}
import std/path.{Path}

fn first_kb(p: Path) -> Bytes ! {Fs, Fail<FsError>} {
  Fs.with_file(p, Mode.Read, fn(file) { Fs.read_chunk(file, 1024) })
}
Edit on GitHub

On this page