feat(lang): universal backtick raw identifier — valid in value, decl, AND type position [F0.6]

AGRA ruling (attempt 4): `` `name `` is THE LITERAL identifier `name`, usable in
EVERY position — the backtick only means "treat this token as a plain identifier,
never the reserved keyword/type", and is never part of the name's text.

- Raw in TYPE position is now VALID (reverses attempt-2 "raw is not a type"):
  `parseTypeExpr` emits a raw `type_expr`; `TypeResolver.resolveNamed` gains a
  `skip_builtin` flag (threaded from `te.is_raw` via lower.zig + type_bridge) so a
  `` `s2 `` reference resolves to a `` `s2 ``-declared type (struct/enum/union/alias),
  else a normal "unknown type 's2'" error (reportIfUnknownType skips the builtin
  exemption when raw). Bare `s2` in type position stays the builtin int.
- Every declaration-name site is is_raw-exemptible: `is_raw` added to TypeExpr +
  StructDecl/EnumDecl/UnionDecl/ErrorSetDecl/ProtocolDecl/ForeignClassDecl/UfcsAlias/
  NamespaceDecl/ImportDecl/CImportDecl/LibraryDecl; parser threads name_is_raw to
  every decl parse fn; namespace imports carry it through imports.addNamespace.
  Typed-const path (`` `s2 : s64 : 5 ``) now threads name_span+is_raw (fixes the
  1:1-caret bug).
- Check<->exemption made structurally symmetric: checkBindingName/checkDeclName take
  is_raw as a REQUIRED argument and skip inside the check, so no call site can
  validate a name without honoring the exemption (the desync cause of prior rounds).
- Bare reserved-name declarations of every kind still error (0076 preserved);
  `#import c` foreign names stay auto-raw + bare-callable.

specs.md + readme.md updated to the universal model. issue 0089 RESOLVED banner
rewritten. Examples: replace 1139 (raw-not-a-type) with 0154 (raw type reference);
add 0155 (typed const + union tag) and 1141 (bare type-decl negatives).
Gate: zig build + zig build test + run_examples (426 passed, 0 failed).
This commit is contained in:
agra
2026-06-04 20:27:53 +03:00
parent c0e1a5db82
commit 023971cae5
26 changed files with 441 additions and 212 deletions

View File

@@ -380,12 +380,19 @@ pub const EnumDecl = struct {
is_flags: bool = false,
variant_values: []const ?*Node = &.{}, // explicit value per variant (null = auto), empty = all auto
backing_type: ?*Node = null, // optional backing type: enum u8 { ... }
/// True when the declared NAME was a backtick raw identifier
/// (`` `s2 :: enum { … } ``) — exempt from the reserved-type-name decl
/// check (issue 0089). A bare reserved-name decl still errors.
is_raw: bool = false,
};
pub const UnionDecl = struct {
name: []const u8,
field_names: []const []const u8,
field_types: []const *Node,
/// True when the declared NAME was a backtick raw identifier — exempt from
/// the reserved-type-name decl check (issue 0089).
is_raw: bool = false,
};
/// `Foo :: error { TagA, TagB }` — a named error set. Tags are bare
@@ -393,6 +400,9 @@ pub const UnionDecl = struct {
pub const ErrorSetDecl = struct {
name: []const u8,
tag_names: []const []const u8,
/// True when the declared NAME was a backtick raw identifier — exempt from
/// the reserved-type-name decl check (issue 0089).
is_raw: bool = false,
};
pub const StructTypeParam = struct {
@@ -418,6 +428,10 @@ pub const StructDecl = struct {
using_entries: []const UsingEntry = &.{},
methods: []const *Node = &.{}, // fn_decl nodes for struct methods
constants: []const *Node = &.{}, // const_decl nodes for struct-level constants
/// True when the declared NAME was a backtick raw identifier
/// (`` `s2 :: struct { … } ``) — exempt from the reserved-type-name decl
/// check (issue 0089). A bare reserved-name decl still errors.
is_raw: bool = false,
};
pub const StructFieldInit = struct {
@@ -444,6 +458,12 @@ pub const TypeExpr = struct {
name: []const u8,
is_generic: bool = false,
protocol_constraints: []const []const u8 = &.{}, // e.g. ["Eq", "Hashable"] for $T/Eq/Hashable
/// True when written as a backtick raw identifier in type position
/// (`` `s2 ``). Such a reference is the LITERAL name `s2` used as a type —
/// resolution skips the builtin/reserved classifier and looks up a
/// `` `s2 ``-declared type (struct/enum/union/alias), else "unknown type"
/// (issue 0089). A bare `s2` keeps `is_raw = false` and is the int type.
is_raw: bool = false,
};
/// `$<pack_name>[<index>]` in type position. Resolves to the i-th
@@ -530,6 +550,10 @@ pub const ReturnStmt = struct {
pub const ImportDecl = struct {
path: []const u8,
name: ?[]const u8,
/// True when the namespace NAME was a backtick raw identifier
/// (`` `s2 :: #import "…" ``) — exempt from the reserved-type-name decl
/// check (issue 0089). A flat `#import` (name == null) binds nothing.
is_raw: bool = false,
};
pub const ArrayTypeExpr = struct {
@@ -638,6 +662,9 @@ pub const SpreadExpr = struct {
pub const NamespaceDecl = struct {
name: []const u8,
decls: []const *Node,
/// True when the namespace NAME was a backtick raw identifier — exempt
/// from the reserved-type-name decl check (issue 0089).
is_raw: bool = false,
};
pub const ForeignExpr = struct {
@@ -648,6 +675,9 @@ pub const ForeignExpr = struct {
pub const LibraryDecl = struct {
lib_name: []const u8,
name: []const u8, // sx-side constant name
/// True when the constant NAME was a backtick raw identifier — exempt from
/// the reserved-type-name decl check (issue 0089).
is_raw: bool = false,
};
pub const FrameworkDecl = struct {
@@ -691,6 +721,9 @@ pub const TupleElement = struct {
pub const UfcsAlias = struct {
name: []const u8,
target: []const u8,
/// True when the alias NAME was a backtick raw identifier — exempt from
/// the reserved-type-name decl check (issue 0089).
is_raw: bool = false,
};
pub const CImportDecl = struct {
@@ -700,6 +733,9 @@ pub const CImportDecl = struct {
flags: []const []const u8,
name: ?[]const u8 = null,
bitcode_paths: []const []const u8 = &.{}, // populated during import resolution
/// True when the namespace NAME was a backtick raw identifier — exempt
/// from the reserved-type-name decl check (issue 0089).
is_raw: bool = false,
};
pub const ProtocolMethodDecl = struct {
@@ -720,6 +756,9 @@ pub const ProtocolDecl = struct {
methods: []const ProtocolMethodDecl,
is_inline: bool = false, // #inline — embedded fn ptrs instead of vtable pointer
type_params: []const StructTypeParam = &.{}, // for `protocol(Target: Type) { ... }`
/// True when the declared NAME was a backtick raw identifier — exempt from
/// the reserved-type-name decl check (issue 0089).
is_raw: bool = false,
};
pub const ForeignRuntime = enum {
@@ -776,6 +815,9 @@ pub const ForeignClassDecl = struct {
members: []const ForeignClassMember = &.{},
is_foreign: bool = false, // `#foreign #...` prefix — class is provided by the foreign runtime; we only reference it
is_main: bool = false, // `#jni_main` / `#objc_main` — class is the launchable entry (Activity / UIApplicationDelegate / ...)
/// True when the sx-side alias NAME was a backtick raw identifier — exempt
/// from the reserved-type-name decl check (issue 0089).
is_raw: bool = false,
};
pub const JniEnvBlock = struct {