feat(lang): backtick raw identifier in every binding form + raw-not-a-type + foreign reserved-name fn bare-call [F0.6]

Completes the issue-0089 backtick raw-identifier / `#import c` exemption
across all remaining identifier positions and closes three boundary gaps
the F0.6 review found.

1. Exhaustive raw-binding coverage. The `is_raw` bit now threads through
   `ast.Identifier` and EVERY binding/capture form — `IfExpr`/`WhileExpr`
   optional bindings, `ForExpr` capture + index, `MatchArm` capture,
   `CatchExpr`/`OnFailStmt` tag bindings, `DestructureDecl` per-name, and
   the protocol-default-body / foreign-class method param lists — not just
   `var_decl`/`param`. `UnknownTypeChecker` skips the reserved-name check at
   each arm when raw, so a backtick works in every identifier position while
   a bare reserved spelling still errors (issue 0076 preserved).

2. Raw identifier is never a type. `parseTypeExpr`'s atom rejects a raw
   identifier in type position (`x : `s2 = 1`, `List(`s2)`) with an accurate
   diagnostic instead of silently type-classifying it.

3. Reserved-name function bare-callable. A bare `s2(4)` parses its callee as
   a `.type_expr` (reserved spelling); `lowerCall` now rewrites a type_expr
   callee to an identifier when a function of that name is in scope, so a
   backtick-declared sx fn and a `#import c` foreign fn whose C name collides
   with a reserved type spelling both resolve by their bare name.
   (`TypeName(val)` is not a cast, so there is no ambiguity.)

Tests: examples/0152 (every control-flow/capture form + bare ref/call/member
access), examples/1054 (catch/onfail tag bindings), examples/1139 (raw in
type position rejected), examples/1220 extended (foreign reserved-name
function bare-call). 0076 negatives 1119/1121/1122/1123/1124/1125 stay green.
Gate: zig build + zig build test + 422 examples pass. specs.md + readme.md
updated; issues/0089 RESOLVED banner refreshed.
This commit is contained in:
agra
2026-06-04 18:31:08 +03:00
parent 0dbdc530ba
commit 640f59dc54
23 changed files with 356 additions and 56 deletions

View File

@@ -188,6 +188,10 @@ pub const StringLiteral = struct {
pub const Identifier = struct {
name: []const u8,
/// True when written as a backtick raw identifier (`` `s2 ``). Carried so a
/// destructure target (`` `s2, b := … ``) can be recognised as raw and
/// exempted from the reserved-type-name binding check (issue 0089).
is_raw: bool = false,
};
pub const EnumLiteral = struct {
@@ -277,6 +281,9 @@ pub const IfExpr = struct {
is_comptime: bool = false, // true for `inline if` — compile-time branch elimination
binding_name: ?[]const u8 = null, // for `if val := expr { ... }` optional binding
binding_span: ?Span = null, // span of `binding_name` (set iff `binding_name` is)
/// True when the optional binding was a backtick raw identifier
/// (`` if `s2 := … ``) — exempt from the reserved-type-name check (issue 0089).
binding_is_raw: bool = false,
};
pub const MatchExpr = struct {
@@ -291,6 +298,9 @@ pub const MatchArm = struct {
is_break: bool,
capture: ?[]const u8 = null, // payload binding name: case .variant: (name) { ... }
capture_span: ?Span = null, // span of `capture` (set iff `capture` is)
/// True when the capture was a backtick raw identifier
/// (`` case .v: (`s2) ``) — exempt from the reserved-type-name check (issue 0089).
capture_is_raw: bool = false,
};
pub const ConstDecl = struct {
@@ -341,6 +351,10 @@ pub const MultiAssign = struct {
pub const DestructureDecl = struct {
names: []const []const u8,
name_spans: []const Span, // one per entry in `names`, same order
/// One per entry in `names`, same order: true when that target was a
/// backtick raw identifier (`` `s2, b := … ``) — exempt from the
/// reserved-type-name binding check (issue 0089).
name_is_raw: []const bool,
value: *Node,
};
@@ -462,6 +476,9 @@ pub const CatchExpr = struct {
operand: *Node,
binding: ?[]const u8 = null,
binding_span: ?Span = null, // span of `binding` (set iff `binding` is)
/// True when the binding was a backtick raw identifier
/// (`` x catch `s2 { … } ``) — exempt from the reserved-type-name check (issue 0089).
binding_is_raw: bool = false,
body: *Node,
is_match_body: bool = false,
};
@@ -472,6 +489,9 @@ pub const CatchExpr = struct {
pub const OnFailStmt = struct {
binding: ?[]const u8 = null,
binding_span: ?Span = null, // span of `binding` (set iff `binding` is)
/// True when the binding was a backtick raw identifier
/// (`` onfail `s2 { … } ``) — exempt from the reserved-type-name check (issue 0089).
binding_is_raw: bool = false,
body: *Node,
};
@@ -566,6 +586,9 @@ pub const WhileExpr = struct {
body: *Node,
binding_name: ?[]const u8 = null, // for `while val := expr { ... }` optional binding
binding_span: ?Span = null, // span of `binding_name` (set iff `binding_name` is)
/// True when the optional binding was a backtick raw identifier
/// (`` while `s2 := … ``) — exempt from the reserved-type-name check (issue 0089).
binding_is_raw: bool = false,
};
pub const ForExpr = struct {
@@ -573,8 +596,14 @@ pub const ForExpr = struct {
body: *Node,
capture_name: []const u8,
capture_span: ?Span = null, // span of `capture_name` (null when omitted, e.g. `for 0..N { }`)
/// True when `capture_name` was a backtick raw identifier
/// (`` for xs: (`s2) ``) — exempt from the reserved-type-name check (issue 0089).
capture_is_raw: bool = false,
index_name: ?[]const u8 = null,
index_span: ?Span = null, // span of `index_name` (set iff `index_name` is)
/// True when `index_name` was a backtick raw identifier
/// (`` for xs: (x, `s2) ``) — exempt from the reserved-type-name check (issue 0089).
index_is_raw: bool = false,
/// Range form `for start..end (i) { }`: `iterable` is the start, `range_end`
/// the (exclusive) end. Null for the iterate-a-collection form
/// (`for coll : (x) { }`). For the range form `capture_name` is the cursor
@@ -663,6 +692,10 @@ pub const ProtocolMethodDecl = struct {
params: []const *Node, // type_expr nodes for parameter types (excluding implicit self)
param_names: []const []const u8, // parameter names (excluding implicit self)
param_name_spans: []const Span = &.{}, // one per `param_names` entry; empty for synthesized methods
/// One per `param_names` entry: true when written as a backtick raw
/// identifier — exempt from the reserved-type-name check (issue 0089).
/// Empty for synthesized methods (treated as all-false).
param_name_is_raw: []const bool = &.{},
return_type: ?*Node, // null = void return
default_body: ?*Node, // null = required method, non-null = default implementation
};
@@ -689,6 +722,10 @@ pub const ForeignMethodDecl = struct {
params: []const *Node, // type_expr nodes — first is `*Self` for instance methods
param_names: []const []const u8,
param_name_spans: []const Span = &.{}, // one per `param_names` entry; empty for synthesized methods
/// One per `param_names` entry: true when written as a backtick raw
/// identifier — exempt from the reserved-type-name check (issue 0089).
/// Empty for synthesized methods (treated as all-false).
param_name_is_raw: []const bool = &.{},
return_type: ?*Node, // null = void
is_static: bool = false, // true for `static name :: ...`
jni_descriptor_override: ?[]const u8 = null, // `#jni_method_descriptor("(Sig)Ret")` — JNI runtime only