|
|
|
@@ -1427,16 +1427,18 @@ pub const Lowering = struct {
|
|
|
|
// same pass-2 before this). E2/F2: copy the SOURCE-AWARE author's
|
|
|
|
// same pass-2 before this). E2/F2: copy the SOURCE-AWARE author's
|
|
|
|
// value (own-wins), and reject a ≥2-flat ambiguity loudly.
|
|
|
|
// value (own-wins), and reject a ≥2-flat ambiguity loudly.
|
|
|
|
if (self.program_index.module_const_map.get(id.name)) |ci_global| {
|
|
|
|
if (self.program_index.module_const_map.get(id.name)) |ci_global| {
|
|
|
|
const ci = switch (self.selectModuleConst(id.name)) {
|
|
|
|
const sel: SelectedConst = switch (self.selectModuleConst(id.name)) {
|
|
|
|
.resolved => |c| c,
|
|
|
|
.resolved => |s| s,
|
|
|
|
.none => ci_global,
|
|
|
|
.none => .{ .info = ci_global, .source = null },
|
|
|
|
.ambiguous => {
|
|
|
|
.ambiguous => {
|
|
|
|
if (self.diagnostics) |d|
|
|
|
|
if (self.diagnostics) |d|
|
|
|
|
d.addFmt(.err, v.span, "'{s}' is ambiguous: it is declared in multiple flat-imported modules; qualify the reference or remove the duplicate import", .{id.name});
|
|
|
|
d.addFmt(.err, v.span, "'{s}' is ambiguous: it is declared in multiple flat-imported modules; qualify the reference or remove the duplicate import", .{id.name});
|
|
|
|
break :blk null;
|
|
|
|
break :blk null;
|
|
|
|
},
|
|
|
|
},
|
|
|
|
};
|
|
|
|
};
|
|
|
|
if (self.constExprValue(ci.value, var_ty)) |cv| break :blk cv;
|
|
|
|
const author_pin = self.pinConstAuthorSource(sel.source);
|
|
|
|
|
|
|
|
defer author_pin.unpin();
|
|
|
|
|
|
|
|
if (self.constExprValue(sel.info.value, var_ty)) |cv| break :blk cv;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (self.diagnostics) |d|
|
|
|
|
if (self.diagnostics) |d|
|
|
|
|
d.addFmt(.err, v.span, "global '{s}' must be initialized by a compile-time constant; '{s}' is not a usable constant here", .{ vd.name, id.name });
|
|
|
|
d.addFmt(.err, v.span, "global '{s}' must be initialized by a compile-time constant; '{s}' is not a usable constant here", .{ vd.name, id.name });
|
|
|
|
@@ -3962,7 +3964,7 @@ pub const Lowering = struct {
|
|
|
|
// silent pick. `.none` after a visible name is the registration-
|
|
|
|
// silent pick. `.none` after a visible name is the registration-
|
|
|
|
// only author (no per-source partition) — emit its global value.
|
|
|
|
// only author (no per-source partition) — emit its global value.
|
|
|
|
switch (self.selectModuleConst(id.name)) {
|
|
|
|
switch (self.selectModuleConst(id.name)) {
|
|
|
|
.resolved => |ci| break :blk self.emitModuleConst(ci),
|
|
|
|
.resolved => |sel| break :blk self.emitModuleConst(sel.info, sel.source),
|
|
|
|
.ambiguous => {
|
|
|
|
.ambiguous => {
|
|
|
|
if (self.diagnostics) |d|
|
|
|
|
if (self.diagnostics) |d|
|
|
|
|
d.addFmt(.err, node.span, "'{s}' is ambiguous: it is declared in multiple flat-imported modules; qualify the reference or remove the duplicate import", .{id.name});
|
|
|
|
d.addFmt(.err, node.span, "'{s}' is ambiguous: it is declared in multiple flat-imported modules; qualify the reference or remove the duplicate import", .{id.name});
|
|
|
|
@@ -3971,7 +3973,7 @@ pub const Lowering = struct {
|
|
|
|
// "unresolved" cascade from `emitError`.
|
|
|
|
// "unresolved" cascade from `emitError`.
|
|
|
|
break :blk self.emitPlaceholder(id.name);
|
|
|
|
break :blk self.emitPlaceholder(id.name);
|
|
|
|
},
|
|
|
|
},
|
|
|
|
.none => break :blk self.emitModuleConst(ci_global),
|
|
|
|
.none => break :blk self.emitModuleConst(ci_global, null),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// Check if it's a function name — produce function pointer reference
|
|
|
|
// Check if it's a function name — produce function pointer reference
|
|
|
|
@@ -13467,10 +13469,12 @@ pub const Lowering = struct {
|
|
|
|
fn foldSourceConstFloat(self: *Lowering, name: []const u8, frame: ?*const ConstFoldFrame) ?f64 {
|
|
|
|
fn foldSourceConstFloat(self: *Lowering, name: []const u8, frame: ?*const ConstFoldFrame) ?f64 {
|
|
|
|
if (constFoldFrameContains(frame, name)) return null;
|
|
|
|
if (constFoldFrameContains(frame, name)) return null;
|
|
|
|
return switch (self.selectModuleConst(name)) {
|
|
|
|
return switch (self.selectModuleConst(name)) {
|
|
|
|
.resolved => |ci| {
|
|
|
|
.resolved => |sel| {
|
|
|
|
if (!program_index_mod.isCountableConstType(&self.module.types, ci.ty)) return null;
|
|
|
|
if (!program_index_mod.isCountableConstType(&self.module.types, sel.info.ty)) return null;
|
|
|
|
var f = ConstFoldFrame{ .name = name, .parent = frame };
|
|
|
|
var f = ConstFoldFrame{ .name = name, .parent = frame };
|
|
|
|
return program_index_mod.evalConstFloatExpr(ci.value, SourceConstCtx{ .lowering = self, .frame = &f });
|
|
|
|
const restore = self.pinConstAuthorSource(sel.source);
|
|
|
|
|
|
|
|
defer restore.unpin();
|
|
|
|
|
|
|
|
return program_index_mod.evalConstFloatExpr(sel.info.value, SourceConstCtx{ .lowering = self, .frame = &f });
|
|
|
|
},
|
|
|
|
},
|
|
|
|
.ambiguous, .none => null,
|
|
|
|
.ambiguous, .none => null,
|
|
|
|
};
|
|
|
|
};
|
|
|
|
@@ -13492,10 +13496,12 @@ pub const Lowering = struct {
|
|
|
|
fn sourceConstIsFloatTyped(self: *Lowering, name: []const u8, frame: ?*const ConstFoldFrame) bool {
|
|
|
|
fn sourceConstIsFloatTyped(self: *Lowering, name: []const u8, frame: ?*const ConstFoldFrame) bool {
|
|
|
|
if (constFoldFrameContains(frame, name)) return false;
|
|
|
|
if (constFoldFrameContains(frame, name)) return false;
|
|
|
|
return switch (self.selectModuleConst(name)) {
|
|
|
|
return switch (self.selectModuleConst(name)) {
|
|
|
|
.resolved => |ci| {
|
|
|
|
.resolved => |sel| {
|
|
|
|
if (program_index_mod.isFloatConstType(ci.ty)) return true;
|
|
|
|
if (program_index_mod.isFloatConstType(sel.info.ty)) return true;
|
|
|
|
var f = ConstFoldFrame{ .name = name, .parent = frame };
|
|
|
|
var f = ConstFoldFrame{ .name = name, .parent = frame };
|
|
|
|
return program_index_mod.isFloatValuedExpr(ci.value, SourceConstCtx{ .lowering = self, .frame = &f });
|
|
|
|
const restore = self.pinConstAuthorSource(sel.source);
|
|
|
|
|
|
|
|
defer restore.unpin();
|
|
|
|
|
|
|
|
return program_index_mod.isFloatValuedExpr(sel.info.value, SourceConstCtx{ .lowering = self, .frame = &f });
|
|
|
|
},
|
|
|
|
},
|
|
|
|
.ambiguous, .none => false,
|
|
|
|
.ambiguous, .none => false,
|
|
|
|
};
|
|
|
|
};
|
|
|
|
@@ -13530,15 +13536,28 @@ pub const Lowering = struct {
|
|
|
|
fn foldSourceConstInt(self: *Lowering, name: []const u8, frame: ?*const ConstFoldFrame) ?i64 {
|
|
|
|
fn foldSourceConstInt(self: *Lowering, name: []const u8, frame: ?*const ConstFoldFrame) ?i64 {
|
|
|
|
if (constFoldFrameContains(frame, name)) return null;
|
|
|
|
if (constFoldFrameContains(frame, name)) return null;
|
|
|
|
return switch (self.selectModuleConst(name)) {
|
|
|
|
return switch (self.selectModuleConst(name)) {
|
|
|
|
.resolved => |ci| {
|
|
|
|
.resolved => |sel| {
|
|
|
|
if (!program_index_mod.isCountableConstType(&self.module.types, ci.ty)) return null;
|
|
|
|
if (!program_index_mod.isCountableConstType(&self.module.types, sel.info.ty)) return null;
|
|
|
|
var f = ConstFoldFrame{ .name = name, .parent = frame };
|
|
|
|
var f = ConstFoldFrame{ .name = name, .parent = frame };
|
|
|
|
return program_index_mod.evalConstIntExpr(ci.value, SourceConstCtx{ .lowering = self, .frame = &f });
|
|
|
|
const restore = self.pinConstAuthorSource(sel.source);
|
|
|
|
|
|
|
|
defer restore.unpin();
|
|
|
|
|
|
|
|
return program_index_mod.evalConstIntExpr(sel.info.value, SourceConstCtx{ .lowering = self, .frame = &f });
|
|
|
|
},
|
|
|
|
},
|
|
|
|
.ambiguous, .none => null,
|
|
|
|
.ambiguous, .none => null,
|
|
|
|
};
|
|
|
|
};
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// A selected module const plus the SOURCE that authored it. `source` pins the
|
|
|
|
|
|
|
|
/// context in which the const's RHS leaves must be folded (F1): a same-name
|
|
|
|
|
|
|
|
/// `K :: M + 1` selected from author `a.sx` folds its nested `M` against `a.sx`,
|
|
|
|
|
|
|
|
/// not against whichever module read `K`. `source` is null only on the
|
|
|
|
|
|
|
|
/// fully-unwired fallback (no source partition at all), where the RHS resolves
|
|
|
|
|
|
|
|
/// through the global registration context unchanged.
|
|
|
|
|
|
|
|
const SelectedConst = struct {
|
|
|
|
|
|
|
|
info: program_index_mod.ModuleConstInfo,
|
|
|
|
|
|
|
|
source: ?[]const u8,
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
/// The source-aware module-const author of `name` from the querying module
|
|
|
|
/// The source-aware module-const author of `name` from the querying module
|
|
|
|
/// (E2/F2) — the value-const analogue of `selectNominalLeaf` (types) and
|
|
|
|
/// (E2/F2) — the value-const analogue of `selectNominalLeaf` (types) and
|
|
|
|
/// `selectPlainCallableAuthor` (functions). Selects over the ONE graph-walk
|
|
|
|
/// `selectPlainCallableAuthor` (functions). Selects over the ONE graph-walk
|
|
|
|
@@ -13556,29 +13575,29 @@ pub const Lowering = struct {
|
|
|
|
/// at all) falls open to the global registration, byte-identical to the legacy
|
|
|
|
/// at all) falls open to the global registration, byte-identical to the legacy
|
|
|
|
/// reader for the registration / comptime-host path.
|
|
|
|
/// reader for the registration / comptime-host path.
|
|
|
|
const ConstAuthor = union(enum) {
|
|
|
|
const ConstAuthor = union(enum) {
|
|
|
|
resolved: program_index_mod.ModuleConstInfo,
|
|
|
|
resolved: SelectedConst,
|
|
|
|
ambiguous,
|
|
|
|
ambiguous,
|
|
|
|
none,
|
|
|
|
none,
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
fn selectModuleConst(self: *Lowering, name: []const u8) ConstAuthor {
|
|
|
|
fn selectModuleConst(self: *Lowering, name: []const u8) ConstAuthor {
|
|
|
|
const from = self.current_source_file orelse self.main_file orelse {
|
|
|
|
const from = self.current_source_file orelse self.main_file orelse {
|
|
|
|
if (self.program_index.module_const_map.get(name)) |ci| return .{ .resolved = ci };
|
|
|
|
if (self.program_index.module_const_map.get(name)) |ci| return .{ .resolved = .{ .info = ci, .source = null } };
|
|
|
|
return .none;
|
|
|
|
return .none;
|
|
|
|
};
|
|
|
|
};
|
|
|
|
var res = self.resolver();
|
|
|
|
var res = self.resolver();
|
|
|
|
const set = res.collectVisibleAuthors(name, from, .user_bare_flat);
|
|
|
|
const set = res.collectVisibleAuthors(name, from, .user_bare_flat);
|
|
|
|
defer if (set.flat.len > 0) self.alloc.free(set.flat);
|
|
|
|
defer if (set.flat.len > 0) self.alloc.free(set.flat);
|
|
|
|
if (set.own) |o| if (self.sourceModuleConst(o.source, name)) |ci| return .{ .resolved = ci };
|
|
|
|
if (set.own) |o| if (self.sourceModuleConst(o.source, name)) |ci| return .{ .resolved = .{ .info = ci, .source = o.source } };
|
|
|
|
var the_one: ?program_index_mod.ModuleConstInfo = null;
|
|
|
|
var the_one: ?SelectedConst = null;
|
|
|
|
var count: usize = 0;
|
|
|
|
var count: usize = 0;
|
|
|
|
for (set.flat) |fa| {
|
|
|
|
for (set.flat) |fa| {
|
|
|
|
const ci = self.sourceModuleConst(fa.source, name) orelse continue;
|
|
|
|
const ci = self.sourceModuleConst(fa.source, name) orelse continue;
|
|
|
|
count += 1;
|
|
|
|
count += 1;
|
|
|
|
if (count >= 2) return .ambiguous;
|
|
|
|
if (count >= 2) return .ambiguous;
|
|
|
|
the_one = ci;
|
|
|
|
the_one = .{ .info = ci, .source = fa.source };
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (the_one) |ci| return .{ .resolved = ci };
|
|
|
|
if (the_one) |sc| return .{ .resolved = sc };
|
|
|
|
return .none;
|
|
|
|
return .none;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@@ -13589,6 +13608,31 @@ pub const Lowering = struct {
|
|
|
|
return inner.get(name);
|
|
|
|
return inner.get(name);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// Saved `current_source_file` for a const-author pin; `unpin()` restores it.
|
|
|
|
|
|
|
|
const ConstSourcePin = struct {
|
|
|
|
|
|
|
|
lowering: *Lowering,
|
|
|
|
|
|
|
|
saved: ?[]const u8,
|
|
|
|
|
|
|
|
active: bool,
|
|
|
|
|
|
|
|
fn unpin(self: ConstSourcePin) void {
|
|
|
|
|
|
|
|
if (self.active) self.lowering.setCurrentSourceFile(self.saved);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// Pin `current_source_file` to a SELECTED const's AUTHOR source while its RHS
|
|
|
|
|
|
|
|
/// is folded / lowered, so nested same-name leaves resolve in the author's
|
|
|
|
|
|
|
|
/// visibility context (F1): `K :: M + 1` selected from `a.sx` always folds `M`
|
|
|
|
|
|
|
|
/// against `a.sx`, regardless of which module read `K`. A null author (the
|
|
|
|
|
|
|
|
/// fully-unwired fallback) leaves the context untouched. Single-author programs
|
|
|
|
|
|
|
|
/// pin to the source they were already in → byte-identical.
|
|
|
|
|
|
|
|
fn pinConstAuthorSource(self: *Lowering, source: ?[]const u8) ConstSourcePin {
|
|
|
|
|
|
|
|
if (source) |s| {
|
|
|
|
|
|
|
|
const saved = self.current_source_file;
|
|
|
|
|
|
|
|
self.setCurrentSourceFile(s);
|
|
|
|
|
|
|
|
return .{ .lowering = self, .saved = saved, .active = true };
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
return .{ .lowering = self, .saved = self.current_source_file, .active = false };
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// Resolve a type node, checking type_bindings first for generic type params.
|
|
|
|
/// Resolve a type node, checking type_bindings first for generic type params.
|
|
|
|
pub fn resolveTypeWithBindings(self: *Lowering, node: *const Node) TypeId {
|
|
|
|
pub fn resolveTypeWithBindings(self: *Lowering, node: *const Node) TypeId {
|
|
|
|
// Pack-index in a type position: `$<pack>[<lit>]` resolves to the
|
|
|
|
// Pack-index in a type position: `$<pack>[<lit>]` resolves to the
|
|
|
|
@@ -16123,7 +16167,14 @@ pub const Lowering = struct {
|
|
|
|
};
|
|
|
|
};
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
fn emitModuleConst(self: *Lowering, ci: ModuleConstInfo) Ref {
|
|
|
|
fn emitModuleConst(self: *Lowering, ci: ModuleConstInfo, author_source: ?[]const u8) Ref {
|
|
|
|
|
|
|
|
// F1: a const read from another module folds/lowers its RHS in the
|
|
|
|
|
|
|
|
// AUTHOR's visibility context, so a same-name leaf (`K :: M + 1` selected
|
|
|
|
|
|
|
|
// from `a.sx`) resolves `M` against `a.sx` — not against the reading
|
|
|
|
|
|
|
|
// module, which may flat-import a different same-name `M`. Single-author /
|
|
|
|
|
|
|
|
// own-read consts pin to the source they were already in → byte-identical.
|
|
|
|
|
|
|
|
const author_pin = self.pinConstAuthorSource(author_source);
|
|
|
|
|
|
|
|
defer author_pin.unpin();
|
|
|
|
// An integer-typed const whose initializer is a compile-time integer —
|
|
|
|
// An integer-typed const whose initializer is a compile-time integer —
|
|
|
|
// an int literal/expression, OR an INTEGRAL float that `typedConstInitFits`
|
|
|
|
// an int literal/expression, OR an INTEGRAL float that `typedConstInitFits`
|
|
|
|
// accepted under the unified narrowing rule — materializes as its folded
|
|
|
|
// accepted under the unified narrowing rule — materializes as its folded
|
|
|
|
|