Ownership, Borrowing, and Types

Type-Level Ownership Modes

  • T: read-only view parameter (default for function parameters).
  • &T: mutable borrow parameter.
  • @T: owned parameter.

Context and Surface Forms

  • In type positions (parameter/return annotations, type terms), Name[...] is a type application/constructor form (for example Pair[i64]).
  • Pointer indirection is written as *T and is non-nullable.
  • Pointer allocation is written as @box(expr) and produces *T when expr: T.
  • Option[T] is a built-in optional type constructor. Use Option[*T] for nullable box references.
  • *T represents one explicit heap edge to inline T, so the immediate payload T cannot itself be another pointer or a built-in heap-handle value.
  • Built-in sequence type forms:
    • [T; N] fixed-size array
    • [T] runtime-sized array
  • In expression positions, name(...) is a call expression.
  • Resolution is context-driven and validated in later semantic passes.

Ownership markers also exist in both spaces:

  • Type-level: T, &T, @T.
  • Local/value-level: let x = expr, let @x = expr, &x, <-x forms.

Copyability Classes

  • Values are copyable by default.
  • Composite types may be explicitly declared linear (non-copyable).
  • In MVP, a user-defined linear type must contain at least one linear field (directly or transitively through contained types).
  • Copyable types may not contain linear fields (transitively).
  • Linear values can be moved and borrowed, but not copied.
  • Copyable containers (Array, slices, Map) reject linear element values in MVP.

Array literals ([a, b, c]) construct fixed-size arrays by default. When a [T] type is expected by context, the same literal form constructs an owned runtime-sized array.

Return annotations do not accept ownership sigils. Return values are always owned.

Local Binding Rules

  • let x = expr introduces a read-only view local.
  • let &x = expr introduces a mutable reference local.
  • let x <- y introduces a read-only local that now owns the moved value from y.
  • let @x = expr introduces an owned local.
  • Plain let locals cannot be assigned through, mutably borrowed, or moved with <-x, even when initialized with <-.
  • Mutable reference locals (let &x = expr) may be assigned through and mutably borrowed.
  • Owned let @x locals may be assigned through, mutably borrowed, and explicitly moved.

Read-only parameters and read-only locals are intentionally different:

  • A parameter of type T may alias caller storage because it is only a read-only view.
  • A local created with let x <- y becomes the new read-only owner of y's storage after the move.

Borrowing Rules

  • Plain T parameters and binders are read-only views. They cannot be assigned through and do not move ownership.
  • &T borrows are exclusive mutable borrows; they cannot coexist with any other mutable access to the same value.
  • Mutable borrow overlap checks are place-aware for struct fields and conservative for index/slice projections.
  • @T parameters receive an owned value. Plain x copies into @T, while <-x moves and invalidates the source binding.
  • Borrowed values are non-owning and may not escape the function or block that created them.

Lifetime and Destruction

  • Heap values are reclaimed when reference count reaches zero.
  • No tracing collector is used.
  • Frees of large object graphs can still cause long delays (for now).
  • Generated Rust and WASM implement box mutation with uniqueness checks before mutable borrows.

For compiler implementation details, see Borrow Checking (Internals).