fix(stdlib/E5): source-aware same-name VALUE consts (own-wins / ambiguous / cross-module expr-chains)
Re-land the value-const analog of the E1-E4 type work, reconciled onto the
current source-keyed resolver and hardened. A same-name VALUE const declared in
multiple flat-imported modules is now resolved per declaring source, not the
global last-wins `module_const_map`.
- imports.zig: `isPerSourceDecl` retains every non-function `const_decl`
per-source (value consts + type aliases), so each same-name author reaches
registration as a distinct author of its own module. Functions and var_decls
keep first-wins.
- lower.zig:
* `selectModuleConst` over `module_consts_by_source` — own-wins; exactly one
flat-visible resolves; >=2 flat-visible bare -> loud ambiguous (consistent
with the 0755 type / 0724 fn / 0782 generic ambiguities). Rewires every
consumer: `comptimeIntNamed`, the runtime-id read, the global-init read,
and the float-name path (`lookupFloatName` / `nameIsFloatTyped`).
* `SourceConstCtx` + `foldSourceConstInt`/`Float` + `sourceConstIsFloatTyped`
fold a selected const's RHS with nested same-name leaves re-selected in
their own author source, so VALUE and array-DIMENSION results are coherent.
* `pinConstAuthorSource` pins each fold level to the SELECTED const's author
(F1), including multi-level cross-module chains.
* cycle guard keyed on (name, author-source), not name alone (F3), so
same-name nested consts across modules do not trip a false cycle.
* `emitModuleConst` takes the author source and pins while folding/lowering.
Registration-time struct/inline-type field dimensions route through the now
source-aware stateful reader; the type-alias dimension path resolves each
alias against its own author's consts.
- program_index.zig: expose `isFloatConstType` / `isCountableConstType` for the
source-aware folds.
examples: 0786 own-wins, 0787 ambiguous (exit 1), 0788 expr-chain value+dim
coherent, 0789 leaf-author-pin, 0790 cross-module cycle-guard (F3), 0791
multi-level cross-module chain, 0792 struct-field registration-time dim.
Single-author corpus byte-identical (524 prior markers green); 531 total.
This commit is contained in:
@@ -314,8 +314,8 @@ pub const ResolvedModule = struct {
|
||||
try self.scope.put(name, {});
|
||||
if (seen_list.contains(name)) {
|
||||
// A cross-module name collision: drop from the global list
|
||||
// (first-wins) UNLESS this is a per-source decl (a named type or
|
||||
// a type-alias const), which must reach registration as a
|
||||
// (first-wins) UNLESS this is a per-source decl (a type, alias,
|
||||
// or non-function const), which must reach registration as a
|
||||
// distinct author of its own module (issues 0104/0105).
|
||||
append_to_global = isPerSourceDecl(decl);
|
||||
} else {
|
||||
@@ -352,14 +352,14 @@ pub const ResolvedModule = struct {
|
||||
if (decl.data.declName()) |name| {
|
||||
if (seen_list.contains(name)) {
|
||||
// First-wins on a cross-module name collision — EXCEPT a
|
||||
// per-source decl (a named type or a type-alias const), each
|
||||
// of which must reach registration as a distinct same-name
|
||||
// author of its own module (issues 0104/0105). FUNCTIONS and
|
||||
// VALUE consts keep first-wins (issue 0102 — the shadowed
|
||||
// function stays reachable via its qualified name /
|
||||
// SelectedFunc; same-name value consts are deferred to step
|
||||
// E5). Node identity (above) still de-dups a diamond import of
|
||||
// the SAME decl.
|
||||
// per-source decl (a named type, or any non-function const:
|
||||
// type alias + value const), each of which must reach
|
||||
// registration as a distinct same-name author of its own
|
||||
// module (issues 0104/0105 types, step E5 value consts). Only
|
||||
// FUNCTIONS keep first-wins (issue 0102 — the shadowed author
|
||||
// stays reachable via its qualified name / SelectedFunc).
|
||||
// Node identity (above) still de-dups a diamond import of the
|
||||
// SAME decl.
|
||||
if (!isPerSourceDecl(decl)) continue;
|
||||
} else {
|
||||
try seen_list.put(name, {});
|
||||
@@ -372,43 +372,19 @@ pub const ResolvedModule = struct {
|
||||
|
||||
/// A decl that must register PER-SOURCE: each same-name author across modules
|
||||
/// registers against its OWN module rather than collapsing to a single
|
||||
/// first-wins winner. NAMED types and TYPE-introducing `const_decl`s (type
|
||||
/// aliases + inline type decls, source-keyed via the alias cache) are
|
||||
/// per-source — that is what closes issues 0104/0105 for types and aliases.
|
||||
/// Everything else keeps the first-wins name-merge:
|
||||
/// - FUNCTIONS (issue 0102 — the shadowed author stays reachable via its
|
||||
/// qualified name / SelectedFunc),
|
||||
/// - VALUE `const_decl`s (literal / value-expression RHS): a same-name
|
||||
/// value const keeps the pre-E2 first-wins read; cross-module same-name
|
||||
/// value-const support is a separate concern (step E5), NOT part of the
|
||||
/// 0105 type close,
|
||||
/// - and `var_decl`s, including a `#foreign` extern global declared in two
|
||||
/// files (e.g. `__stdinp : *void #foreign;`) that MUST resolve to the ONE
|
||||
/// libSystem symbol, not split into a duplicate `__stdinp.1`.
|
||||
/// first-wins winner. NAMED types and every non-function `const_decl` (type
|
||||
/// aliases + inline type decls + VALUE consts, source-keyed via the alias /
|
||||
/// const caches) are per-source — that is what closes issues 0104/0105 for
|
||||
/// types/aliases and supports same-name value consts (step E5). Everything
|
||||
/// else keeps the first-wins name-merge: FUNCTIONS (issue 0102 — the shadowed
|
||||
/// author stays reachable via its qualified name / SelectedFunc), and crucially
|
||||
/// `var_decl`s, including a `#foreign` extern global declared in two files
|
||||
/// (e.g. `__stdinp : *void #foreign;`) that MUST resolve to the ONE libSystem
|
||||
/// symbol, not split into a duplicate `__stdinp.1`.
|
||||
fn isPerSourceDecl(decl: *const Node) bool {
|
||||
return switch (decl.data) {
|
||||
.struct_decl, .enum_decl, .union_decl, .error_set_decl, .protocol_decl, .foreign_class_decl => true,
|
||||
// A `const_decl` is per-source ONLY when its RHS introduces a TYPE
|
||||
// (alias / inline type decl). A VALUE const — literal or value
|
||||
// expression — and a function const keep the first-wins merge.
|
||||
.const_decl => |cd| switch (cd.value.data) {
|
||||
.fn_decl,
|
||||
.int_literal,
|
||||
.float_literal,
|
||||
.bool_literal,
|
||||
.string_literal,
|
||||
.null_literal,
|
||||
.undef_literal,
|
||||
.enum_literal,
|
||||
.struct_literal,
|
||||
.array_literal,
|
||||
.tuple_literal,
|
||||
.binary_op,
|
||||
.unary_op,
|
||||
.chained_comparison,
|
||||
=> false,
|
||||
else => true,
|
||||
},
|
||||
.const_decl => |cd| cd.value.data != .fn_decl,
|
||||
else => false,
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user