Scoping and Shadowing

Scope behavior, shadowed names, and import lookup.

Zynx uses lexical scopes for local bindings, function bodies, blocks, match arms, loops, and tests.

fn main() {
    let value = 1;
    {
        let value = 2;
        _ = value;
    }
    _ = value;
}

Shadowing

Shadowing is covered by compiler tests. A nested binding may reuse an outer name, and lookup resolves to the innermost valid symbol.

After the nested scope ends, reads and assignments use the outer binding's storage again. This also holds through lowered loop and async state machines.

Imports

Imports add module symbols to scope.

import std.os;
import {
    String
} from std.string;
import {
    Array
} from std.collections;

The LSP and diagnostics include import-related behavior such as unused import warnings and add-import code actions. textDocument/inlayHint also reports semantic type hints for inferred locals such as let value = expr;; declarations that already include an explicit type annotation are left alone.

Lifetime-sensitive Scope

Moves and borrows are scope-sensitive. Loops, match arms, and conditional branches merge analysis state before continuing.