fix(stdlib/E5): source-aware value-const TYPE inference (F4)
Value-const SELECTION was source-aware for emission/folding (F2/R1/F1), but expression TYPE inference still read the global last-wins `module_const_map`, so an inferred return type / coercion on a same-name const borrowed another module's const TYPE (mixed-type same-name consts were never exercised by the attempt-1 same-typed goldens). - expr_typer.zig: the `.identifier` const path now selects via the source-aware `selectModuleConst` (own-wins / one-flat-visible) instead of the global `module_const_map`. The global map still gates "is this a const name?"; an unpartitioned registration-only author emits its global type, and an ambiguous bare reference yields `.unresolved` (the emission path diagnoses loudly). - lower.zig: expose `selectModuleConst` so the type-inference path shares the one author selector emission/folding already use. Audited every `module_const_map` read: emission (4102) and global-init copy (1447) were already source-aware (attempt-1); the binds-a-value predicate (6400) is a boolean, not a type read; the in-`selectModuleConst` read (13842) is the unwired fallback. No sibling inference site leaks. examples: 0793 mixed-type own-wins inference (A's `K:s32` yields `1`, not the global `f64`'s `1.000000`); 0794 mixed-type bare → loud ambiguous (exit 1), the inference change does not mask the ambiguity. Prior E5 surfaces (0786-0792), the 0105 set (0752-0758), E1-E4 type surfaces (0763-0785) and FFI byte-identical; 533 markers green.
This commit is contained in:
@@ -277,9 +277,21 @@ pub const ExprTyper = struct {
|
||||
if (self.l.program_index.global_names.get(id.name)) |gi| {
|
||||
return gi.ty;
|
||||
}
|
||||
// Check module-level value constants (e.g., WIDTH :f32: 800)
|
||||
if (self.l.program_index.module_const_map.get(id.name)) |ci| {
|
||||
return ci.ty;
|
||||
// Check module-level value constants (e.g., WIDTH :f32: 800).
|
||||
// F4: a same-name VALUE const must infer the SOURCE-AWARE author's
|
||||
// TYPE (own-wins / one-flat-visible), not the global last-wins
|
||||
// `module_const_map` — otherwise a return-type / coercion inferred
|
||||
// on one module's `K` borrows another module's `K` TYPE. The global
|
||||
// map still gates "is this a const name at all?"; `.none` is the
|
||||
// registration-only author with no per-source partition (emit its
|
||||
// global type), and an ambiguous bare reference yields `.unresolved`
|
||||
// (the emission path diagnoses the ambiguity loudly).
|
||||
if (self.l.program_index.module_const_map.get(id.name)) |ci_global| {
|
||||
return switch (self.l.selectModuleConst(id.name)) {
|
||||
.resolved => |sel| sel.info.ty,
|
||||
.none => ci_global.ty,
|
||||
.ambiguous => .unresolved,
|
||||
};
|
||||
}
|
||||
// A bare type name (alias like `Vec4`, struct name, or
|
||||
// builtin primitive) referenced in expression position
|
||||
|
||||
@@ -13837,7 +13837,7 @@ pub const Lowering = struct {
|
||||
/// the querying module is `main_file` there; a fully unwired index (no source
|
||||
/// at all) falls open to the global registration, byte-identical to the legacy
|
||||
/// reader for the registration / comptime-host path.
|
||||
fn selectModuleConst(self: *Lowering, name: []const u8) ConstAuthor {
|
||||
pub fn selectModuleConst(self: *Lowering, name: []const u8) ConstAuthor {
|
||||
const from = self.current_source_file orelse self.main_file orelse {
|
||||
if (self.program_index.module_const_map.get(name)) |ci| return .{ .resolved = .{ .info = ci, .source = null } };
|
||||
return .none;
|
||||
|
||||
Reference in New Issue
Block a user