cleanup: drop resolved-issue citations from src comments

Sweep all src/**.zig comments that cite resolved issues (issue NNNN /
fix-NNNN / KB-N): the invariant or mechanism each comment states is
kept; the historical citation is dropped, per the no-conclusion-comments
rule. Pure-history parentheticals are removed outright. References to
the 16 still-open issues (0030, 0041-0056) are untouched, as are test
NAMES carrying regression provenance (matching the sanctioned
"Regression (issue NNNN)" example-header convention).

Also removes the issues/0019-import-non-transitive-c-scope/ fixture dir
— the issue is superseded and its behavior is covered by
examples/0706-modules-import-non-transitive.sx (the .md writeup stays).
issues/0030's repro .sx stays: that issue is an open feature request.

Gate: zig build OK; zig build test 426/426; run_examples 541/0; zero
expected/ snapshot churn.
This commit is contained in:
agra
2026-06-10 16:34:17 +03:00
parent 8b2a6598a9
commit 2b8041a828
40 changed files with 254 additions and 301 deletions

View File

@@ -34,7 +34,7 @@ pub fn lowerCall(self: *Lowering, c_in: *const ast.Call) Ref {
// function. `TypeName(val)` is not a cast (casts are `cast(T, val)`), so
// there is no ambiguity. Rewrite the callee to an identifier so the
// normal call machinery resolves it, symmetric to the bare-value
// reference that already resolves via scope/globals (issue 0089).
// reference that already resolves via scope/globals.
//
// Scoped to RAW provenance: only a backtick (`is_raw`) or `#import c`
// foreign fn declaration may legally carry a reserved-name spelling
@@ -55,7 +55,7 @@ pub fn lowerCall(self: *Lowering, c_in: *const ast.Call) Ref {
c = rewritten;
};
}
// fix-0102 F2 / R5 §C: select the bare / value-UFCS same-name call author
// R5 §C: select the bare / value-UFCS same-name call author
// ONCE, via `CallResolver.selectedFreeAuthor` — the SINGLE producer of
// this verdict, the exact same one `CallResolver.plan` consumes for typing.
// The call-path consumers (default expansion, param typing, dispatch) all
@@ -128,7 +128,7 @@ pub fn lowerCall(self: *Lowering, c_in: *const ast.Call) Ref {
// If argument is a bare function name, create a proper closure from it
if (arg.data == .identifier) {
const fn_name = arg.data.identifier.name;
// fix-0102d site 2: `closure(fn)` over a genuine flat same-name
// `closure(fn)` over a genuine flat same-name
// collision must capture the RESOLVED author's FuncId, not the
// first-wins winner's. Plain bare name only; `.ambiguous`
// → loud diagnostic; `.none` → existing first-wins path.
@@ -188,7 +188,7 @@ pub fn lowerCall(self: *Lowering, c_in: *const ast.Call) Ref {
}
break :blk scoped;
};
// fix-0102 F2 / R5 §C: the early pack/comptime/generic dispatch reads
// R5 §C: the early pack/comptime/generic dispatch reads
// the SAME author the call resolver SELECTED — not the first-wins
// winner — whenever a genuine flat same-name collision rerouted the
// call (`sel_author != null`). The selector only ever returns a plain
@@ -455,14 +455,14 @@ pub fn lowerCall(self: *Lowering, c_in: *const ast.Call) Ref {
}
}
}
// fix-0102c / R5 §C: a genuine flat same-name collision — bind the
// R5 §C: a genuine flat same-name collision — bind the
// author the call resolver selected (own-author-wins, or the single
// flat-reachable author), or reject a bare call to a name ≥2
// imported modules author. `selectedFreeAuthor` (computed once
// above, and the exact verdict `plan` consumes for typing) is the
// single producer; lowering CONSUMES it rather than re-resolving
// the name, so typing and dispatch read the SAME author and can't
// disagree (fix-0102 F2). Reached only for an identifier callee, so
// disagree. Reached only for an identifier callee, so
// `sel_author` / `author_ambiguous` here are the bare verdict.
if (author_ambiguous) {
if (self.diagnostics) |d|
@@ -476,7 +476,7 @@ pub fn lowerCall(self: *Lowering, c_in: *const ast.Call) Ref {
const params = func.params;
// The RESOLVED author's decl drives variadic packing — not a
// first-wins re-lookup by name, whose variadic shape may
// differ (fix-0102c F1).
// differ.
self.packVariadicCallArgs(sf.decl, c, &args);
const final_args = self.prependCtxIfNeeded(func, args.items);
self.coerceCallArgs(final_args, params);
@@ -956,13 +956,13 @@ pub fn lowerCall(self: *Lowering, c_in: *const ast.Call) Ref {
// Try to resolve as bare function name (free-function UFCS:
// `recv.fn(args)` → `fn(recv, args)`). Lazily lower the body —
// a function reached ONLY via UFCS would otherwise be declared
// but never emitted (issue 0063: undefined symbol at link).
// but never emitted (undefined symbol at link).
//
// fix-0102d site 3 / R5 §C: a free-function UFCS target with a
// R5 §C: a free-function UFCS target with a
// genuine flat same-name collision dispatches to the author the
// call PLAN selected for the receiver's source — the SAME author
// plan typed the call's result as, so dispatch and typing can't
// disagree (fix-0102 F2; without this, a string-typed winner over
// disagree (without this, a string-typed winner over
// an s64 shadow boxes a raw int as a string pointer → segfault).
// The plan is the single producer; lowering consumes its verdict
// (`sel_author` / `cplan.ambiguous_collision`, computed once above)
@@ -991,7 +991,7 @@ pub fn lowerCall(self: *Lowering, c_in: *const ast.Call) Ref {
// Same implicit address-of as a struct-defined method: if the
// free function's first param is `*T` and the receiver is a
// value `T`, pass its address instead of a by-value copy
// (issue 0063).
self.fixupMethodReceiver(&method_args, func, effective_obj_node, obj_ty);
const final_args = self.prependCtxIfNeeded(func, method_args.items);
self.coerceCallArgs(final_args, params);
@@ -1517,7 +1517,7 @@ pub fn tryLowerReflectionCall(self: *Lowering, name: []const u8, c: *const ast.C
// Strict `$T: Type` guard for the type-introspection builtins. A
// value argument (`6`, `true`, `5.2`, a struct) is rejected with a
// diagnostic instead of being silently reinterpreted as a TypeId
// index / sized via its `typeof` (issue 0090). One shared
// index / sized via its `typeof`. One shared
// classification covers all 7; it runs before dispatch.
if (self.reflectionTypeArgGuard(name, c)) |sentinel| return sentinel;
@@ -1776,7 +1776,7 @@ pub fn reflectionArgIsType(self: *Lowering, arg: *const Node) bool {
/// `field_count`, `type_name`, `type_eq`, `type_is_unsigned`,
/// `is_flags`): every argument must denote a type. A value argument is
/// rejected with a diagnostic rather than silently reinterpreted as a
/// TypeId index or sized via its `typeof` (issue 0090).
/// TypeId index or sized via its `typeof`.
///
/// Returns null when `name` is not a guarded builtin OR every argument
/// is a type (→ fall through to normal dispatch). Returns a harmless
@@ -1866,7 +1866,7 @@ pub fn expandCallDefaults(self: *Lowering, c: *const ast.Call, sel_author: ?*con
}
break :blk2 scoped;
};
// fix-0102d site 1 / R5 §C: for a genuine flat same-name
// R5 §C: for a genuine flat same-name
// collision the omitted trailing args are filled from the
// author the call resolver selected — its `*FnDecl` defaults —
// not the first-wins winner's. lowering consumes the ONE author
@@ -2097,7 +2097,7 @@ pub fn resolveCallParamTypes(self: *Lowering, c: *const ast.Call, sel_author: ?*
break :blk scoped;
};
// fix-0102c F2 / R5 §C: a genuine flat same-name collision must type this
// R5 §C: a genuine flat same-name collision must type this
// call's args against the author the call resolver selected, not the
// first-wins winner's params. lowering consumes the ONE author verdict
// (`selectedFreeAuthor`, computed once in `lowerCall`) rather than

View File

@@ -189,7 +189,7 @@ pub fn lowerLambda(self: *Lowering, lam: *const ast.Lambda) Ref {
// `defer`s, not the enclosing function's. Open a fresh defer window
// (like `lowerFunction`/`monomorphizeFunction`) and restore on exit —
// otherwise lowering a closure literal inside a `defer` body re-enters
// the enclosing function's defer drain (infinite recursion — issue 0073).
// the enclosing function's defer drain (infinite recursion).
const saved_func_defer_base = self.func_defer_base;
const saved_defer_len = self.defer_stack.items.len;
defer {

View File

@@ -543,8 +543,8 @@ pub fn zeroValue(self: *Lowering, ty: TypeId) Ref {
};
}
/// Emit the unified non-integral float→int narrowing diagnostic (F0.11 /
/// issue 0095). ONE wording, ONE place: every site that rejects an implicit
/// Emit the unified non-integral float→int narrowing diagnostic (F0.11).
/// ONE wording, ONE place: every site that rejects an implicit
/// narrowing of a non-integral compile-time float to an integer type calls
/// this, so the message + fix-it stay identical across the typed-binding
/// coerce arm, the field/param-default sites, the typed-const path, and the

View File

@@ -45,7 +45,7 @@ pub fn constArrayLiteral(self: *Lowering, elements: []const *const Node, array_t
/// Try to convert a single AST expression into a compile-time ConstantValue.
/// `expected_ty` is the destination element/field type — it lets aggregate
/// leaves (struct literals, nested arrays) serialize with the correct shape
/// rather than collapsing to null (issue 0080). Returns null if the
/// rather than collapsing to null. Returns null if the
/// expression is not constant-foldable here.
pub fn constExprValue(self: *Lowering, expr: *const Node, expected_ty: TypeId) ?inst_mod.ConstantValue {
return switch (expr.data) {
@@ -66,7 +66,7 @@ pub fn constExprValue(self: *Lowering, expr: *const Node, expected_ty: TypeId) ?
.undef_literal => .zeroinit,
// A `null` in a pointer (or optional-pointer) field is a
// compile-time constant: the zero pointer. Without this arm the
// aggregate is wrongly rejected as non-constant (issue 0081).
// aggregate is wrongly rejected as non-constant.
.null_literal => .null_val,
.unary_op => |uo| switch (uo.op) {
.negate => switch (uo.operand.data) {
@@ -80,7 +80,7 @@ pub fn constExprValue(self: *Lowering, expr: *const Node, expected_ty: TypeId) ?
.struct_literal => |sl| self.constStructLiteral(&sl, expected_ty),
// An enum tag as an aggregate leaf (`[2]Color = .[.green, .blue]`, or
// an enum field inside a global struct) serializes to its tag int
// against the leaf's declared enum type (issue 0082).
// against the leaf's declared enum type.
.enum_literal => |el| self.constEnumLiteral(&el, expected_ty, expr.span),
else => null,
};
@@ -92,7 +92,7 @@ pub fn constExprValue(self: *Lowering, expr: *const Node, expected_ty: TypeId) ?
/// (`enum { a; b :: 5; }`); the enum's backing width is applied by the
/// const emitters via the destination type's LLVM type. Plain enums only —
/// a tagged-union or non-enum destination is diagnosed loudly rather than
/// silently zero-initialized (issue 0082).
/// silently zero-initialized.
pub fn constEnumLiteral(self: *Lowering, el: *const ast.EnumLiteral, ty: TypeId, span: ast.Span) ?inst_mod.ConstantValue {
if (!ty.isBuiltin()) {
const info = self.module.types.get(ty);
@@ -543,7 +543,7 @@ pub fn lowerComptimeCall(self: *Lowering, fd: *const ast.FnDecl, call_node: *con
// its return type + anything it `#insert`s, e.g. `build_format` / `out`
// / `emit` inside `std.print` / `log.*`), so those bare names resolve
// in the defining module's visibility context rather than the call
// site's (issue 0106). The call-site ARGS above are deliberately lowered
// site's. The call-site ARGS above are deliberately lowered
// BEFORE this, in the caller's context. Mirrors `lowerFunctionBodyInto`,
// which switches to `func.source_file`. The defining path is stamped on
// the body node by `resolveImports`; a sourceless body keeps the
@@ -848,7 +848,7 @@ const ConstAuthor = union(enum) {
///
/// - **own-wins**: the querying module's OWN const author is selected outright.
/// - else the FLAT-import-reachable const authors: exactly one → it; ≥2 distinct
/// → `.ambiguous` (issue 0105 / 0760 — never a silent first-/last-wins pick).
/// → `.ambiguous` (never a silent first-/last-wins pick).
/// - none visible → `.none` (a namespaced-only const must be qualified `ns.X`;
/// a non-const name folds to `.none` too).
///

View File

@@ -779,7 +779,7 @@ pub fn lowerMatch(self: *Lowering, me: *const ast.MatchExpr) Ref {
if (has_value_merge) {
// Lower the arm body against the merge's result type so literals
// (and negated literals) in the arm pick the right width — the
// phi operands must all match `result_type` (issue 0066).
// phi operands must all match `result_type`.
const saved_arm_target = self.target_type;
self.target_type = result_type;
const maybe_v = self.lowerBlockValue(arm.body);
@@ -790,7 +790,7 @@ pub fn lowerMatch(self: *Lowering, me: *const ast.MatchExpr) Ref {
// Only materialize a value + branch to the merge when the arm
// body did NOT diverge. A diverging arm (e.g. `return x`) has
// already terminated its block; emitting the fallback const
// here would land AFTER the terminator (the issue-0057 bug).
// here would land AFTER the terminator .
if (!self.currentBlockHasTerminator()) {
var v = maybe_v orelse if (result_type == .string or !result_type.isBuiltin())
self.builder.constUndef(result_type)

View File

@@ -92,7 +92,7 @@ pub fn lowerRoot(self: *Lowering, root: *const Node) void {
// any error before codegen.
self.errorFlow().checkErrorFlow(decls);
// Pass 1f: reject identifiers used in a type position that name no
// declared type / primitive / in-scope generic param (issue 0064).
// declared type / primitive / in-scope generic param.
// Runs after scanning (so every real type name is registered) and
// before body lowering, so the diagnostic halts via `core.zig`
// `hasErrors()` before the empty-struct stub can reach codegen. Owned by
@@ -447,11 +447,11 @@ pub fn scanDecls(self: *Lowering, decls: []const *const Node) void {
// declaration order (pass 1) and typed ones only after the alias fixpoint
// (pass 2) — so an alias declared before its const, or any alias over a
// typed const, saw an empty table and miscompiled the dimension to length
// 0 (issue 0083). A float-valued const resolves to a dimension only when
// 0. A float-valued const resolves to a dimension only when
// its value is integral (`floatToIntExact`); pre-registering it keeps the
// forward-alias float path identical to the int path. The dimension only
// needs the value, so a placeholder type is fine; pass 2 overwrites typed
// consts with the resolved annotation type (issue 0070).
// consts with the resolved annotation type.
for (decls) |decl| {
if (decl.data != .const_decl) continue;
const cd = decl.data.const_decl;
@@ -467,7 +467,7 @@ pub fn scanDecls(self: *Lowering, decls: []const *const Node) void {
// A const whose RHS is an integer EXPRESSION over other consts
// (`M :: 2; N :: M + 1`) is itself a usable count: register it so
// `moduleConstInt` can fold the RHS through `evalConstIntExpr`
// (issue 0083). Placeholder `.s64` type — the count consumers read
//. Placeholder `.s64` type — the count consumers read
// only the value; if the expression doesn't fold (references a
// non-const), `moduleConstInt` yields null and the use diagnoses.
.binary_op, .unary_op => {
@@ -483,7 +483,7 @@ pub fn scanDecls(self: *Lowering, decls: []const *const Node) void {
// self (`next: *Box`), or a forward / mutual ref to a shadow declared LATER
// in the same module (`peer: *Node`) — then binds to its OWN nominal TypeId
// via `type_decl_tids`, never the global findByName first-author fallback
// (issue 0105).
//
// "Genuine" = ≥2 DISTINCT decls of the SAME KIND in THIS scan author the name
// (so it needs ≥2 distinct nominal TypeIds). Grouping by (kind, name) keeps a
@@ -529,7 +529,7 @@ pub fn scanDecls(self: *Lowering, decls: []const *const Node) void {
// re-introduces a same-named function (e.g. a second module
// also exporting `parse`) must NOT clobber the AST while the
// function table keeps the first — that split lowers one
// signature against the other's body (issue 0100). The
// signature against the other's body. The
// shadowed function stays reachable via its qualified name.
if (!self.program_index.fn_ast_map.contains(fd.name)) {
self.program_index.fn_ast_map.put(fd.name, &decl.data.fn_decl) catch {};
@@ -574,7 +574,7 @@ pub fn scanDecls(self: *Lowering, decls: []const *const Node) void {
// dimension is not a compile-time integer constant. Surface
// it as a clean diagnostic so the build aborts here rather
// than letting `.unresolved` reach codegen and `@panic` in
// sizeOf (issue 0083 — no fabricated 0-length array). For a
// sizeOf (no fabricated 0-length array). For a
// top-level array alias, re-fold the dimension so an
// oversized / negative constant emits the SAME precise
// message as the direct form (`a : [N]T`) via the shared
@@ -710,7 +710,7 @@ pub fn scanDecls(self: *Lowering, decls: []const *const Node) void {
// Typed value constants (`AF_INET :s32: 2`) are registered in
// pass 2 below — after the forward-alias fixpoint — so a
// forward identifier alias in the annotation resolves to its
// target instead of a fabricated stub (issue 0070). Untyped
// target instead of a fabricated stub. Untyped
// literal constants carry no annotation to resolve, so they
// stay here (their type comes from the literal / inference).
if (cd.type_annotation == null) {
@@ -765,7 +765,7 @@ pub fn scanDecls(self: *Lowering, decls: []const *const Node) void {
},
// Top-level globals are registered in a second pass (below),
// after the forward-alias fixpoint, so a forward identifier
// alias used as a global's type annotation resolves (issue 0070).
// alias used as a global's type annotation resolves.
.var_decl => {},
else => {},
}
@@ -773,7 +773,7 @@ pub fn scanDecls(self: *Lowering, decls: []const *const Node) void {
self.resolveForwardIdentifierAliases(decls);
// Pass 2: registrations that resolve a top-level type annotation run
// after the alias fixpoint, so a forward identifier alias used as the
// annotation resolves to its target (issue 0070).
// annotation resolves to its target.
for (decls) |decl| {
self.setCurrentSourceFile(decl.source_file);
switch (decl.data) {
@@ -788,14 +788,14 @@ pub fn scanDecls(self: *Lowering, decls: []const *const Node) void {
/// scanDecls pass 2 (after `resolveForwardIdentifierAliases`) so a forward
/// identifier alias in the annotation (`A :: B; B :: s32; K : A : 42;`)
/// resolves to its target rather than a fabricated empty-struct stub, which
/// would otherwise mistype the constant (issue 0070).
/// would otherwise mistype the constant.
pub fn registerTypedModuleConst(self: *Lowering, cd: *const ast.ConstDecl) void {
const ta = cd.type_annotation orelse return;
// Only initializer shapes that pass 0 (binary_op / unary_op → placeholder
// `.s64`) or the literal path register as a USABLE module const need
// reconciling against the annotation. Every other shape (call,
// struct/array literal, bare identifier) is never registered as a
// foldable / emittable const, so it cannot manifest the issue-0088
// foldable / emittable const, so it cannot manifest a
// wrong-type fold/emit; a use-site diagnostic covers it.
switch (cd.value.data) {
.int_literal, .float_literal, .bool_literal, .string_literal, .undef_literal, .null_literal, .binary_op, .unary_op => {},
@@ -901,8 +901,7 @@ pub fn typedConstInitFits(self: *Lowering, value: *const Node, dst_ty: TypeId) b
// Const-EXPRESSION initializer (binary_op / unary_op — the only
// non-literal kinds the caller admits): validate by the initializer's
// INFERRED type so coverage is type-based, not a per-node-kind
// allowlist where an unenumerated kind silently escapes (issue 0088,
// attempt 2). The integer/float fit mirrors the literal arms above.
// allowlist where an unenumerated kind silently escapes. The integer/float fit mirrors the literal arms above.
else => self.constExprInitFits(self.inferExprType(value), dst_ty),
};
}
@@ -930,7 +929,7 @@ pub fn constExprInitFits(self: *Lowering, init_ty: TypeId, dst_ty: TypeId) bool
/// in the type annotation (`A :: B; B :: s32; g : A = 7;`) resolves to its
/// target instead of a fabricated empty-struct stub, which would otherwise
/// give the global a type that mismatches its initializer at LLVM
/// verification (issue 0070). Globals can't be named in a type position, so
/// verification. Globals can't be named in a type position, so
/// deferring them past type/alias registration introduces no ordering hazard.
pub fn registerTopLevelGlobal(self: *Lowering, vd: *const ast.VarDecl) void {
// Use self.resolveType so type aliases like `Handle :: u32;` resolve
@@ -967,7 +966,7 @@ pub fn registerTopLevelGlobal(self: *Lowering, vd: *const ast.VarDecl) void {
/// Foreign globals (extern symbol) and value-less declarations carry no
/// payload — they default to zero/extern at link, which is correct. An
/// identifier initializer that names a module constant is materialized from
/// the recorded constant (`K : A : 42; g : A = K;` → 42, issue 0071); a
/// the recorded constant (`K : A : 42; g : A = K;` → 42); a
/// global initialized from an identifier that resolves to no usable constant
/// is rejected with a diagnostic rather than silently zero-initialized — a
/// global has no run site for a dynamic initializer.
@@ -1026,7 +1025,7 @@ pub fn globalInitValue(self: *Lowering, vd: *const ast.VarDecl, var_ty: TypeId)
// Any other initializer shape (`.field_access` on a const, a call, an
// arithmetic expression, …) is not a static constant the compiler can
// evaluate here. Diagnose loudly rather than emit a null payload that
// silently zero-initializes the global (issues 0071/0072).
// silently zero-initializes the global.
else => blk: {
if (self.diagnostics) |d|
d.addFmt(.err, v.span, "global '{s}' must be initialized by a compile-time constant", .{vd.name});
@@ -1038,7 +1037,7 @@ pub fn globalInitValue(self: *Lowering, vd: *const ast.VarDecl, var_ty: TypeId)
/// A global aggregate initializer (array/struct literal) that does not fully
/// reduce to a compile-time constant is rejected loudly. Without this the
/// `null` payload would fall through to a zero-initialized global, silently
/// dropping the declared fields (issues 0071/0072/0080).
/// dropping the declared fields.
pub fn diagnoseNonConstGlobal(self: *Lowering, vd: *const ast.VarDecl, v: *const Node) ?inst_mod.ConstantValue {
if (self.diagnostics) |d|
d.addFmt(.err, v.span, "global '{s}' must be initialized by a compile-time constant", .{vd.name});
@@ -1049,11 +1048,11 @@ pub fn diagnoseNonConstGlobal(self: *Lowering, vd: *const ast.VarDecl, v: *const
/// file. The forward scan above only registers an alias (`A :: B`) when `B`
/// is already resolved as a type author; a forward target isn't yet present,
/// so `A` is left unregistered and its uses get falsely flagged as an unknown
/// type (issue 0069). Re-resolve to a fixpoint now that every top-level name
/// type. Re-resolve to a fixpoint now that every top-level name
/// has been seen, so `A :: B; B :: s32;` converges the same as the ordered
/// `B :: s32; A :: B;`. A value const is never an `.identifier` node
/// (`NotAType :: 123` is an int literal), and an alias whose target is a value
/// const stays unresolved, so neither this pass nor issue 0068 can register a
/// const stays unresolved, so neither this pass nor the unknown-type suppression can register a
/// non-type name.
///
/// SOURCE-AWARE (R5 §4, E1.5). The target `B` is resolved AS SEEN FROM `A`'s
@@ -1116,8 +1115,7 @@ pub fn aliasResolvedInSource(self: *Lowering, src: []const u8, name: []const u8)
/// Pass 2: Lower main function body and comptime side-effects.
pub fn lowerMainAndComptime(self: *Lowering, decls: []const *const Node) void {
for (decls) |decl| {
// A `#run` body lowers in its OWN module's source context (fix-0102d
// site 4): `NAME :: #run f()` written in an imported module must
// A `#run` body lowers in its OWN module's source context: `NAME :: #run f()` written in an imported module must
// resolve a bare `f` from that module's flat imports, not the main
// file's. Without this, `selectPlainCallableAuthor` runs with the main
// file's perspective and reports a genuine per-source author as
@@ -1154,15 +1152,15 @@ pub fn lowerMainAndComptime(self: *Lowering, decls: []const *const Node) void {
/// Lower every SHADOWED same-name function author into its OWN FuncId with a
/// real (non-extern) body — the identity-addressable lowering PATH this step
/// adds (fix-0102b). It does NOT run during a default compile: the name path
/// stays the sole resolver, so the suite is byte-for-byte unchanged. fix-0102c
/// invokes it as part of routing bare flat calls to the right author; until
/// adds. It does NOT run during a default compile: the name path
/// stays the sole resolver, so the suite is byte-for-byte unchanged. The bare-call
/// disambiguation invokes it as part of routing bare flat calls to the right author; until
/// then it is exercised by the lower-test regression that asserts two distinct
/// non-extern bodies for a same-name collision.
///
/// The first-wins flat/directory merge keeps exactly one author per name in
/// the merged decl list; `scanDecls` declares that WINNER (lowered on demand
/// through the name-keyed `lazyLowerFunction`). fix-0102a retained every
/// through the name-keyed `lazyLowerFunction`). The merge retains every
/// dropped same-name author in the `module_decls` raw facts (path → name →
/// `RawDeclRef`) without touching resolution; this walks that index, filters
/// each author to its `*FnDecl` (`fnDeclOfRaw`), and gives each shadowed
@@ -1211,7 +1209,7 @@ pub fn lowerRetainedSameNameAuthors(self: *Lowering) void {
}
}
/// Result of bare-call disambiguation (fix-0102c, now over the Phase B
/// Result of bare-call disambiguation (now over the Phase B
/// author collector).
pub const BareCallee = union(enum) {
/// Bind the call to this specific author, carried as the shared
@@ -1219,7 +1217,7 @@ pub const BareCallee = union(enum) {
/// materialized on demand. Every callee-signature decision in the call
/// path (variadic packing, param typing, default expansion) reads the
/// RESOLVED author from this one object — never a first-wins re-lookup
/// by name (fix-0102c F1).
/// by name.
func: SelectedFunc,
/// ≥2 distinct flat authors are reachable from the caller and none is
/// the caller's own — the bare call can't pick one; require a qualifier.
@@ -1285,13 +1283,13 @@ pub const TypeHeadResolution = union(enum) {
/// would mis-size it).
not_visible,
/// ≥2 DISTINCT same-name type authors are flat-visible from the querying
/// source and none is its own (E2, issue 0105). The selection is genuinely
/// source and none is its own (E2). The selection is genuinely
/// ambiguous: `resolveNominalLeaf` emits a loud diagnostic and returns the
/// `.unresolved` poison sentinel — never a silent first-/last-wins pick.
ambiguous,
};
/// THE plain bare-name call selector (fix-0102c, R5 §C). `resolveBareCallee`'s
/// THE plain bare-name call selector. `resolveBareCallee`'s
/// body verbatim, now over the Phase B author collector
/// (`resolver.collectVisibleAuthors` — the ONE graph-walk) instead of a direct
/// `module_decls` + `flat_import_graph` traversal. Routes a bare identifier
@@ -1372,7 +1370,7 @@ pub fn selectPlainCallableAuthor(self: *Lowering, name: []const u8, caller_file:
/// selected author's OWN source — never the global `findByName` first-match
/// nor the global `type_alias_map`.
///
/// `raw` is the backtick raw-identifier escape (issue 0089): a raw reference
/// `raw` is the backtick raw-identifier escape: a raw reference
/// bypasses the builtin classifier and resolves only through the nominal
/// author / alias path.
///
@@ -1454,7 +1452,7 @@ pub fn selectNominalLeaf(self: *Lowering, name: []const u8, from: []const u8, ra
const author_set = res_walk.collectVisibleAuthors(name, from, .user_bare_flat);
defer if (author_set.flat.len > 0) self.alloc.free(author_set.flat);
// 1a. Own type author wins outright (own-wins, issue 0105/0107).
// 1a. Own type author wins outright (own-wins).
if (author_set.own) |own| switch (own.raw) {
.const_decl => {
// Type alias: present in type_aliases_by_source → resolved.
@@ -1462,7 +1460,7 @@ pub fn selectNominalLeaf(self: *Lowering, name: []const u8, from: []const u8, ra
if (inner.get(name)) |tid| return .{ .resolved = tid };
}
// Own const_decl not yet resolved: pending (own takes priority
// over any flat author — prevents issue 0107 flat-preemption).
// over any flat author — prevents flat-preemption).
return .pending;
},
else => if (isNamedTypeKind(own.raw)) {
@@ -1559,7 +1557,7 @@ pub fn isNamedTypeKind(raw: resolver_mod.RawDeclRef) bool {
/// mid-registration → the caller yields the legacy empty-struct stub). A
/// STRUCT resolves first through its `type_decl_tids` nominal identity (E2)
/// keyed by the raw-facts decl pointer, so two same-name struct authors in
/// different sources resolve to their OWN distinct TypeIds (issue 0105). A
/// different sources resolve to their OWN distinct TypeIds. A
/// `type_decl_tids` MISS falls back to the global `findByName` — correct for a
/// SINGLE-author struct registered via a non-`internNamedTypeDecl` path (a
/// `struct #compiler`, a protocol-backed struct, a generic instance) or before
@@ -1773,7 +1771,7 @@ pub fn selectedFuncId(self: *Lowering, sf: *SelectedFunc, name: []const u8) Func
/// winner): the winner owns the name-keyed slot and lowers through the
/// normal lazy path, so `selectPlainCallableAuthor` returns `.none` for it. A shadow
/// is declared a fresh same-name FuncId in its OWN module's visibility
/// context and its body lowered into that slot via fix-0102b's identity-
/// context and its body lowered into that slot via the identity-
/// addressable `lowerFunctionBodyInto`. Idempotent: `lowered_fids` tracks
/// which slots already carry a body.
pub fn bareAuthorFuncId(self: *Lowering, fd: *const ast.FnDecl, name: []const u8, path: []const u8) FuncId {
@@ -1868,7 +1866,7 @@ pub fn declareFunction(self: *Lowering, fd: *const ast.FnDecl, name: []const u8)
/// modules each exporting a top-level `parse` otherwise collide in the
/// bare-name `fn_ast_map` / function table (last-wins) while `resolveFuncByName`
/// picks the first declared, so `lazyLowerFunction` lowers one signature
/// against the other's body and trips its param-count assert (issue 0100).
/// against the other's body and trips its param-count assert.
/// The bare recursion in `scanDecls` still registers intra-module bare calls;
/// this adds the qualified identity the `pkg.fn(...)` resolution paths in
/// `CallResolver.plan` / `lowerCall` already prefer.
@@ -1894,7 +1892,7 @@ pub fn registerQualifiedFn(self: *Lowering, ns_name: []const u8, fd: *const ast.
// comptime / pack functions (`Vector`, `print`, `any_to_string`) are
// dispatched by monomorphization off their BARE template name, not the
// plain `resolveFuncByName` / `lazyLowerFunction` path that trips the
// collision assert (issue 0100); registering a qualified alias for them
// collision assert; registering a qualified alias for them
// would divert that machinery and strand a per-call type binding.
if (fd.type_params.len > 0 or hasComptimeParams(fd) or isPackFn(fd)) return;
// Foreign / builtin / #compiler bodies keep their literal name; a
@@ -1911,7 +1909,7 @@ pub fn registerQualifiedFn(self: *Lowering, ns_name: []const u8, fd: *const ast.
// `registerNamespaceQualifiedFns` pins `current_source_file` to the
// decl's source before each call). `lazyLowerFunction`'s null-FuncId
// path restores this so `ns.fn`'s body lowers in its own module's
// visibility context, not the call site's (issue 0100 F1).
// visibility context, not the call site's.
if (self.current_source_file) |src| {
self.program_index.qualified_fn_source.put(qualified, src) catch {};
}
@@ -2032,7 +2030,7 @@ pub fn lazyLowerFunction(self: *Lowering, name: []const u8) void {
// Find the existing extern stub (from scanDecls), keyed by NAME — the
// FIRST author of a name owns this slot. A shadowed same-name author is
// not here (it has no name-keyed slot); it is lowered out-of-line into
// its OWN FuncId by `lowerRetainedSameNameAuthors` (fix-0102b).
// its OWN FuncId by `lowerRetainedSameNameAuthors`.
const name_id = self.module.types.internString(name);
var func_id: ?FuncId = null;
for (self.module.functions.items, 0..) |func, i| {
@@ -2048,7 +2046,7 @@ pub fn lazyLowerFunction(self: *Lowering, name: []const u8) void {
}
// Function not yet declared — create it fresh via lowerFunction. A
// module-qualified alias (`ns.fn`, issue 0100) is registered in
// module-qualified alias (`ns.fn`) is registered in
// `fn_ast_map` without an eager `declareFunction`, so there's no
// `Function.source_file` to switch to. Restore the alias's OWN declaring
// source before lowering its body, otherwise it lowers in the caller's
@@ -2067,9 +2065,9 @@ pub fn lazyLowerFunction(self: *Lowering, name: []const u8) void {
/// real function. Identity-addressable: the caller passes the exact FuncId,
/// so a SHADOWED same-name author lowers into its OWN slot instead of
/// colliding on the name-keyed `resolveFuncByName` (which returns the first
/// author, the very split that trips issue 0100's param-count assert). Self-
/// author, the very split that trips the param-count assert). Self-
/// contained — the `FnBodyReentry` guard makes the nested lowering
/// transparent to any in-progress caller body (issue 0100 F2) — so it serves
/// transparent to any in-progress caller body — so it serves
/// both `lazyLowerFunction`'s name-keyed found path and the out-of-line
/// `lowerRetainedSameNameAuthors` pass.
pub fn lowerFunctionBodyInto(self: *Lowering, fd: *const ast.FnDecl, fid: FuncId, name: []const u8) void {
@@ -2086,7 +2084,7 @@ pub fn lowerFunctionBodyInto(self: *Lowering, fd: *const ast.FnDecl, fid: FuncId
// Re-use the existing function slot — switch builder to it. Pin the
// function's OWN source BEFORE resolving the return type, so a same-name
// shadowed type in the signature (issue 0105) resolves against THIS
// shadowed type in the signature resolves against THIS
// function's module rather than the caller's (which, importing two
// same-name authors, would be ambiguous). Param types below already
// resolve after this point.
@@ -2229,7 +2227,7 @@ pub fn lowerFunction(self: *Lowering, fd: *const ast.FnDecl, name: []const u8, i
// Record the declaring source so the function carries its own module
// for diagnostics/emit and for any later `lazyLowerFunction` re-entry
// that switches to `func.source_file`. The caller sets
// `current_source_file` to the decl's source before lowering (issue 0100 F1).
// `current_source_file` to the decl's source before lowering.
self.builder.currentFunc().source_file = self.current_source_file;
// Set linkage. Default for fn defs is `internal` (LLVM DCE-friendly,

View File

@@ -472,7 +472,7 @@ pub fn lowerFieldAccess(self: *Lowering, fa: *const ast.FieldAccess, span: ast.S
// const of the queried type (sibling of the identifier-receiver
// intercepts above). Placed AFTER `Struct.CONST` so a user const named
// `min`/`max` wins on its own struct; a builtin type name can never
// name a user struct (reserved — issue 0076), so they never collide.
// name a user struct (reserved), so they never collide.
if (self.lowerNumericLimit(fa, span)) |ref| return ref;
// M1.3 — `obj.class` on any Obj-C-class pointer lowers to
@@ -558,9 +558,9 @@ pub fn lowerFieldAccess(self: *Lowering, fa: *const ast.FieldAccess, span: ast.S
/// constants `module_const_map`. The numeric-limit intercept must defer to
/// ordinary field access whenever ANY of the three binds the name, so a
/// raw value field read is never hijacked into a numeric-limit fold
/// (issues 0092 local / 0093 global + module-const). A single helper used
/// (locals, globals, and module-consts alike). A single helper used
/// by both lowering and inference keeps the two resolvers in lockstep
/// (issue-0083 two-resolver defect class).
/// (two-resolver defect class).
pub fn identifierBindsValue(self: *Lowering, name: []const u8) bool {
if (self.scope) |scope| {
if (scope.lookup(name) != null) return true;
@@ -600,7 +600,7 @@ pub fn lowerNumericLimit(self: *Lowering, fa: *const ast.FieldAccess, span: ast.
// value is an ordinary field read, not a numeric-limit fold — defer to
// the normal field-access path when the receiver identifier resolves to
// a value binding through any of scope / globals / module consts
// (issues 0092, 0093). A `.type_expr` receiver is unambiguously a type
//. A `.type_expr` receiver is unambiguously a type
// and can never be value-shadowed.
if (fa.object.data == .identifier and self.identifierBindsValue(name)) return null;
@@ -684,7 +684,7 @@ pub fn lowerOptionalChain(self: *Lowering, obj: Ref, fa: *const ast.FieldAccess,
/// aliases `.r`/`.g`/`.b`/`.a`) to its lane index. Returns null for any
/// other field name so the read path (`lowerFieldAccessOnType`) and the
/// write path (`lowerAssignment`) share one resolver and reject a
/// non-lane field identically (issue 0086).
/// non-lane field identically.
pub fn vectorLaneIndex(field: []const u8) ?u32 {
if (std.mem.eql(u8, field, "x") or std.mem.eql(u8, field, "r")) return 0;
if (std.mem.eql(u8, field, "y") or std.mem.eql(u8, field, "g")) return 1;
@@ -1079,7 +1079,7 @@ pub fn lowerArrayLiteral(self: *Lowering, al: *const ast.ArrayLiteral) Ref {
// aggregate array `[N]U` (lowerArrayLiteral always yields an array
// value); materialize it into a `[]U` slice so the element is a real
// {ptr,len} header rather than a raw array the callee would read its
// header off of (issue 0085). This per-element coercion recurses with
// header off of. This per-element coercion recurses with
// the literal nesting, so `[][]T` and deeper coerce at every level.
if (!elem_ty.isBuiltin()) {
const ei = self.module.types.get(elem_ty);
@@ -1570,7 +1570,7 @@ pub fn lowerExpr(self: *Lowering, node: *const Node) Ref {
}
// F2: emit the SOURCE-AWARE author's value (own-wins), not the
// global last-wins `ci_global`. ≥2 flat-visible same-name const
// authors → a loud ambiguity (issue 0105 / 0760), never a silent
// authors → a loud ambiguity, never a silent
// pick. `.none` after a visible name is the registration-only
// author (no per-source partition) — emit its global value.
switch (self.selectModuleConst(id.name)) {
@@ -1607,7 +1607,7 @@ pub fn lowerExpr(self: *Lowering, node: *const Node) Ref {
const str = self.builder.constString(sid);
break :blk self.builder.boxAny(str, .string);
}
// fix-0102d site 2: taking a bare same-name fn as a VALUE
// taking a bare same-name fn as a VALUE
// (func_ref, fn-ptr / closure coercion) must capture the
// RESOLVED author's FuncId for a genuine flat collision, not
// the first-wins winner's. Plain bare name only; `.ambiguous`

View File

@@ -73,7 +73,7 @@ pub fn monomorphizeFunction(self: *Lowering, fd: *const ast.FnDecl, mangled_name
// — e.g. `List(T).append`'s `alloc: Allocator` default-param type, or a
// body reference to a type visible only in the template's module —
// resolves where it is visible, not at the (possibly cross-module) call
// site. This is the issue-0100-F1 plain-fn pin extended to generic
// site. This is the namespaced-fn-body plain-fn pin extended to generic
// instantiation; without it the non-transitive bare-TYPE gate (E4) would
// reject a 2-flat-hop library type the call site cannot see directly.
// A synthesized / sourceless body keeps the caller's context.
@@ -291,7 +291,7 @@ pub fn isStaticTypeRef(self: *Lowering, node: *const Node) bool {
/// must itself denote a type; a non-type element — e.g. the `1` in
/// `(s32, 1)` — is a user error. Emit a diagnostic pointing at the offending
/// element and return `.unresolved`; never fabricate a tuple with a bogus
/// field (issue 0067). type_bridge.resolveAstType builds the tuple only after
/// field. type_bridge.resolveAstType builds the tuple only after
/// this validation passes.
pub fn resolveTupleLiteralTypeArg(self: *Lowering, node: *const Node) TypeId {
for (node.data.tuple_literal.elements) |el| {
@@ -806,7 +806,7 @@ pub fn hasComptimeParams(fd: *const ast.FnDecl) bool {
/// A plain free function: no type params (not generic) and an ordinary sx
/// body (not `#foreign` / `#builtin` / `#compiler`). Only these get an
/// out-of-line identity-addressable slot — the bare-call disambiguation
/// (fix-0102c) and the shadow-author lowering pass leave every other shape
/// and the shadow-author lowering pass leave every other shape
/// to the existing name-keyed dispatch.
pub fn isPlainFreeFn(fd: *const ast.FnDecl) bool {
if (fd.type_params.len > 0) return false;
@@ -835,7 +835,7 @@ pub fn isPlainFreeFn(fd: *const ast.FnDecl) bool {
pub fn resolveValueParamArg(self: *Lowering, arg_node: *const Node, param_name: []const u8, type_name: ?[]const u8) ?i64 {
// Resolve an ALIASED integer constraint (`$K: Count` where `Count :: u32`,
// `$K: Small` where `Small :: s8`) to its underlying builtin so the range
// gate below treats it exactly like `$K: u32` / `$K: s8` (issue 0083 — an
// gate below treats it exactly like `$K: u32` / `$K: s8` (an
// alias previously slipped past `intTypeRange`, so `Box(5_000_000_000)`
// with `$K: Count` bound a truncated value). A non-integer / unrecognised
// constraint yields null → no range bound (fold only), as before.

View File

@@ -68,7 +68,7 @@ pub fn stampNominalId(info: types.TypeInfo, nid: u32) types.TypeInfo {
/// BEFORE any field resolves, so a self / forward / mutual reference to a shadow
/// name (`next: *Box`; `peer: *Node` where Node is a shadow declared later)
/// binds to ITS nominal TypeId via `type_decl_tids` instead of the global
/// findByName first-author fallback (issue 0105 / F1). Called only from the
/// findByName first-author fallback. Called only from the
/// `scanDecls` genuine-shadow pass, which has already established that ≥2
/// distinct struct decls author this name; ALL of them reserve — the FIRST at
/// id 0, the rest at fresh nonzero ids — so none falls through to the name-only
@@ -192,7 +192,7 @@ pub fn reserveShadowSlot(self: *Lowering, td: ShadowTypeDecl) void {
/// orelse intern) — BYTE-IDENTICAL to pre-E2 registration. For a genuinely
/// multi-authored name, the FIRST source keeps id 0 and later sources get
/// fresh ids → DISTINCT TypeIds, so the authors no longer collapse last-wins
/// (issue 0105). Idempotent per `decl_key`: a re-registration — OR an up-front
///. Idempotent per `decl_key`: a re-registration — OR an up-front
/// shadow reservation — reuses the recorded slot, refreshing its body via
/// `updatePreservingKey` (key-stable because a struct's intern key is its
/// name + nominal id, not its fields).
@@ -593,7 +593,7 @@ pub fn registerStructDecl(self: *Lowering, sd: *const ast.StructDecl, source_fil
// shadow author's slot was already reserved before fields resolved, so this
// fills it (key-stable updatePreservingKey); a first / single author adopts
// any forward-reference stub. Same-name structs in DIFFERENT sources get
// distinct TypeIds instead of last-wins clobbering the first (issue 0105).
// distinct TypeIds instead of last-wins clobbering the first.
const info: types.TypeInfo = .{ .@"struct" = .{ .name = name_id, .fields = fields.items } };
_ = self.internNamedTypeDecl(decl_key, name_id, info, nominal_id);

View File

@@ -627,7 +627,7 @@ pub fn lowerPackFnCall(self: *Lowering, fd: *const ast.FnDecl, call_node: *const
// `target_type`) would cast to the stale target — e.g. `format("…", xx i)`
// inside a `-> string` fn mis-typed the arg as `string`, monomorphizing
// `__pack_string` and ABI-coercing the 4-byte int as a 16-byte fat
// pointer → memory corruption (issue 0057).
// pointer → memory corruption.
const saved_pack_tt = self.target_type;
self.target_type = null;
var pack_refs = std.ArrayList(Ref).empty;
@@ -895,7 +895,7 @@ pub fn monomorphizePackFn(
// OWN module (E4), so a 2-flat-hop library type named in the signature is
// bare-visible — mirrors the body pin further down and the
// `monomorphizeFunction` pin. The comptime call-site args below are
// lowered AFTER this restore, in the caller's context (issue 0106).
// lowered AFTER this restore, in the caller's context.
const saved_sig_src = self.current_source_file;
if (fd.body.source_file) |src| self.setCurrentSourceFile(src);
@@ -1023,7 +1023,7 @@ pub fn monomorphizePackFn(
// Pin to the metaprogram's OWN module for the BODY lowering only, so its
// bare names (and anything it `#insert`s — e.g. `build_format` / `out` /
// `emit` inside `std.print`) resolve in the defining module's visibility
// context, not the call site's (issue 0106). The comptime-param call-site
// context, not the call site's. The comptime-param call-site
// args above were deliberately lowered FIRST, in the caller's context.
// Mirrors `lowerFunctionBodyInto`, which switches to `func.source_file`;
// the defining path is stamped on the body node by `resolveImports`. A

View File

@@ -689,7 +689,7 @@ pub fn lowerAssignment(self: *Lowering, asgn: *const ast.Assignment) void {
// the shared lvalue resolver — the same one the address-of
// and multi-target store paths use — so the three never
// resolve a field to a different slot or default field 0
// (issue 0094 / issue-0083 two-resolver class). fl.ptr is
// (two-resolver defect class). fl.ptr is
// *field_ty (the store handler unwraps one pointer level);
// fl.ty is the value type to coerce the rhs to.
const src_ty = self.builder.getRefType(val);
@@ -701,7 +701,7 @@ pub fn lowerAssignment(self: *Lowering, asgn: *const ast.Assignment) void {
// diagnostic the read path uses (emitFieldError) and bail;
// building a pointer with field_ty = .unresolved would
// otherwise store through a pointer-to-.unresolved that
// panics at LLVM emission (issue 0094).
// panics at LLVM emission.
_ = self.emitFieldError(obj_ty, fa.field, asgn.target.span);
}
},
@@ -786,7 +786,7 @@ const FieldLvalue = struct { ptr: Ref, ty: TypeId };
/// Single source of lvalue field resolution shared by all three store/
/// address-of sites — lowerAssignment (single-target store), lowerExprAsPtr
/// (address-of), and lowerMultiAssign (multi-target store) — so they never
/// resolve a field to a different slot or default field 0 (issue 0094).
/// resolve a field to a different slot or default field 0.
pub fn fieldLvaluePtr(self: *Lowering, obj_ptr: Ref, obj_ty: TypeId, field: []const u8) ?FieldLvalue {
if (obj_ty.isBuiltin()) return null;
const field_name_id = self.module.types.internString(field);
@@ -918,7 +918,7 @@ pub fn lowerExprAsPtr(self: *Lowering, node: *const Node) Ref {
// field-not-found diagnostic (lowerFieldAccessOnType →
// emitFieldError) instead of silently GEPing field 0 as .s64;
// that bogus pointer reaches LLVM emission as ptrTo(.unresolved)
// and panics (issue 0094).
// and panics.
if (self.fieldLvaluePtr(obj_ptr, obj_ty, fa.field)) |r| return r.ptr;
return self.emitFieldError(obj_ty, fa.field, node.span);
},
@@ -1150,7 +1150,7 @@ pub fn lowerMultiAssign(self: *Lowering, ma: *const ast.MultiAssign) void {
// the same one address-of uses — so a missing field emits a
// diagnostic instead of defaulting to field 0 / field_ty
// .unresolved, which silently corrupted a neighbouring field
// (or panicked at LLVM emission) (issue 0094).
// (or panicked at LLVM emission).
if (self.fieldLvaluePtr(obj_ptr, obj_ty, fa.field)) |r| {
const val_ty = self.builder.getRefType(val);
const store_val = if (val_ty != r.ty and val_ty != .void and r.ty != .void)