Fix even more violations

This commit is contained in:
Richard Feldman 2025-11-26 00:26:14 -05:00
parent eef0fac4b5
commit 55ca8d75db
No known key found for this signature in database
9 changed files with 75 additions and 21 deletions

View file

@ -195,6 +195,11 @@ f32_type_ident: Ident.Idx,
f64_type_ident: Ident.Idx,
dec_type_ident: Ident.Idx,
// Field/tag names used during type checking
before_dot_ident: Ident.Idx,
after_dot_ident: Ident.Idx,
provided_by_compiler_ident: Ident.Idx,
/// Deferred numeric literals collected during type checking
/// These will be validated during comptime evaluation
deferred_numeric_literals: DeferredNumericLiteral.SafeList,
@ -309,6 +314,9 @@ pub fn init(gpa: std.mem.Allocator, source: []const u8) std.mem.Allocator.Error!
const f32_type_ident = try common.insertIdent(gpa, Ident.for_text("Builtin.Num.F32"));
const f64_type_ident = try common.insertIdent(gpa, Ident.for_text("Builtin.Num.F64"));
const dec_type_ident = try common.insertIdent(gpa, Ident.for_text("Builtin.Num.Dec"));
const before_dot_ident = try common.insertIdent(gpa, Ident.for_text("before_dot"));
const after_dot_ident = try common.insertIdent(gpa, Ident.for_text("after_dot"));
const provided_by_compiler_ident = try common.insertIdent(gpa, Ident.for_text("ProvidedByCompiler"));
return Self{
.gpa = gpa,
@ -363,6 +371,9 @@ pub fn init(gpa: std.mem.Allocator, source: []const u8) std.mem.Allocator.Error!
.f32_type_ident = f32_type_ident,
.f64_type_ident = f64_type_ident,
.dec_type_ident = dec_type_ident,
.before_dot_ident = before_dot_ident,
.after_dot_ident = after_dot_ident,
.provided_by_compiler_ident = provided_by_compiler_ident,
.deferred_numeric_literals = try DeferredNumericLiteral.SafeList.initCapacity(gpa, 32),
};
}
@ -1822,6 +1833,9 @@ pub const Serialized = extern struct {
f32_type_ident: Ident.Idx,
f64_type_ident: Ident.Idx,
dec_type_ident: Ident.Idx,
before_dot_ident: Ident.Idx,
after_dot_ident: Ident.Idx,
provided_by_compiler_ident: Ident.Idx,
deferred_numeric_literals: DeferredNumericLiteral.SafeList.Serialized,
/// Serialize a ModuleEnv into this Serialized struct, appending data to the writer
@ -1897,6 +1911,9 @@ pub const Serialized = extern struct {
self.f32_type_ident = env.f32_type_ident;
self.f64_type_ident = env.f64_type_ident;
self.dec_type_ident = env.dec_type_ident;
self.before_dot_ident = env.before_dot_ident;
self.after_dot_ident = env.after_dot_ident;
self.provided_by_compiler_ident = env.provided_by_compiler_ident;
}
/// Deserialize a ModuleEnv from the buffer, updating the ModuleEnv in place
@ -1973,6 +1990,9 @@ pub const Serialized = extern struct {
.f32_type_ident = self.f32_type_ident,
.f64_type_ident = self.f64_type_ident,
.dec_type_ident = self.dec_type_ident,
.before_dot_ident = self.before_dot_ident,
.after_dot_ident = self.after_dot_ident,
.provided_by_compiler_ident = self.provided_by_compiler_ident,
.deferred_numeric_literals = self.deferred_numeric_literals.deserialize(offset).*,
};

View file

@ -1077,7 +1077,13 @@ fn processRequiresTypes(self: *Self, env: *Env) std.mem.Allocator.Error!void {
/// Check that the app's exported values match the platform's required types.
/// This should be called after checkFile() to verify that app exports conform
/// to the platform's requirements.
pub fn checkPlatformRequirements(self: *Self, platform_env: *const ModuleEnv) std.mem.Allocator.Error!void {
/// The `platform_to_app_idents` map translates platform ident indices to app ident indices,
/// built by the caller to avoid string lookups during type checking.
pub fn checkPlatformRequirements(
self: *Self,
platform_env: *const ModuleEnv,
platform_to_app_idents: *const std.AutoHashMap(Ident.Idx, Ident.Idx),
) std.mem.Allocator.Error!void {
const trace = tracy.trace(@src());
defer trace.end();
@ -1088,12 +1094,8 @@ pub fn checkPlatformRequirements(self: *Self, platform_env: *const ModuleEnv) st
// Iterate over the platform's required types
const requires_types_slice = platform_env.requires_types.items.items;
for (requires_types_slice) |required_type| {
// Get the identifier name for this required type and translate to app module
const required_ident = required_type.ident;
const required_ident_text = platform_env.getIdent(required_ident);
// Translate the platform ident to an app module ident (if it exists)
const app_required_ident = self.cir.common.findIdent(required_ident_text);
// Look up the pre-translated app ident for this platform requirement
const app_required_ident = platform_to_app_idents.get(required_type.ident);
// Find the matching export in the app
const app_exports_slice = self.cir.store.sliceDefs(self.cir.exports);

View file

@ -123,6 +123,9 @@ fn loadCompiledModule(gpa: std.mem.Allocator, bin_data: []const u8, module_name:
.f32_type_ident = common.findIdent("Builtin.Num.F32") orelse unreachable,
.f64_type_ident = common.findIdent("Builtin.Num.F64") orelse unreachable,
.dec_type_ident = common.findIdent("Builtin.Num.Dec") orelse unreachable,
.before_dot_ident = common.findIdent("before_dot") orelse unreachable,
.after_dot_ident = common.findIdent("after_dot") orelse unreachable,
.provided_by_compiler_ident = common.findIdent("ProvidedByCompiler") orelse unreachable,
.deferred_numeric_literals = try ModuleEnv.DeferredNumericLiteral.SafeList.initCapacity(gpa, 0),
};

View file

@ -1198,8 +1198,8 @@ const Unifier = struct {
const args_slice = self.types_store.sliceVars(func.args);
if (args_slice.len != 1) return false;
const before_ident = self.module_env.common.findIdent("before_dot") orelse return false;
const after_ident = self.module_env.common.findIdent("after_dot") orelse return false;
const before_ident = self.module_env.before_dot_ident;
const after_ident = self.module_env.after_dot_ident;
const record_desc = self.types_store.resolveVar(args_slice[0]);
const record = switch (record_desc.desc.content) {
@ -1322,7 +1322,7 @@ const Unifier = struct {
// Create nominal List(U8) - List is from Builtin module
// If List ident is not found, something is wrong with the environment
// This should never happen in a properly initialized compiler!
const list_ident = self.module_env.common.findIdent("List") orelse unreachable;
const list_ident = self.module_env.list_type_ident;
// Use the cached builtin_module_ident which represents the "Builtin" module.
const origin_module = if (self.module_lookup.get(self.module_env.builtin_module_ident)) |_|
@ -1341,7 +1341,7 @@ const Unifier = struct {
}) catch return error.AllocatorError;
// Create the [ProvidedByCompiler] tag
const provided_tag_ident = self.module_env.common.findIdent("ProvidedByCompiler") orelse unreachable;
const provided_tag_ident = self.module_env.provided_by_compiler_ident;
const provided_tag = self.types_store.mkTag(provided_tag_ident, &.{}) catch return error.AllocatorError;
const tag_union = TagUnion{
@ -1394,11 +1394,7 @@ const Unifier = struct {
}
// Also check for fully qualified Builtin.Try
if (self.module_env.common.findIdent("Builtin.Try")) |builtin_try_ident| {
return nominal.ident.ident_idx == builtin_try_ident;
}
return false;
return nominal.ident.ident_idx == self.module_env.builtin_try_ident;
}
fn createOutOfRangeTagUnion(self: *Self) Error!Var {

View file

@ -1665,7 +1665,18 @@ pub fn setupSharedMemoryWithModuleEnv(allocs: *Allocators, roc_file_path: []cons
// Check that app exports match platform requirements (if platform exists)
if (platform_main_env) |penv| {
try app_checker.checkPlatformRequirements(penv);
// Build the platform-to-app ident translation map
var platform_to_app_idents = std.AutoHashMap(base.Ident.Idx, base.Ident.Idx).init(allocs.gpa);
defer platform_to_app_idents.deinit();
for (penv.requires_types.items.items) |required_type| {
const platform_ident_text = penv.getIdent(required_type.ident);
if (app_env.common.findIdent(platform_ident_text)) |app_ident| {
try platform_to_app_idents.put(required_type.ident, app_ident);
}
}
try app_checker.checkPlatformRequirements(penv, &platform_to_app_idents);
}
app_env_ptr.* = app_env;

View file

@ -642,8 +642,20 @@ pub const BuildEnv = struct {
);
defer checker.deinit();
// Build the platform-to-app ident translation map
// This translates platform requirement idents to app idents by name
var platform_to_app_idents = std.AutoHashMap(base.Ident.Idx, base.Ident.Idx).init(self.gpa);
defer platform_to_app_idents.deinit();
for (platform_root_env.requires_types.items.items) |required_type| {
const platform_ident_text = platform_root_env.getIdent(required_type.ident);
if (app_root_env.common.findIdent(platform_ident_text)) |app_ident| {
try platform_to_app_idents.put(required_type.ident, app_ident);
}
}
// Check platform requirements against app exports
try checker.checkPlatformRequirements(platform_root_env);
try checker.checkPlatformRequirements(platform_root_env, &platform_to_app_idents);
// If there are type problems, convert them to reports and emit via sink
if (checker.problems.problems.items.len > 0) {

View file

@ -140,6 +140,9 @@ test "ModuleEnv.Serialized roundtrip" {
.f32_type_ident = common.findIdent("Builtin.Num.F32") orelse unreachable,
.f64_type_ident = common.findIdent("Builtin.Num.F64") orelse unreachable,
.dec_type_ident = common.findIdent("Builtin.Num.Dec") orelse unreachable,
.before_dot_ident = common.findIdent("before_dot") orelse unreachable,
.after_dot_ident = common.findIdent("after_dot") orelse unreachable,
.provided_by_compiler_ident = common.findIdent("ProvidedByCompiler") orelse unreachable,
.deferred_numeric_literals = try ModuleEnv.DeferredNumericLiteral.SafeList.initCapacity(deser_alloc, 0),
};
@ -150,7 +153,8 @@ test "ModuleEnv.Serialized roundtrip" {
// initCIRFields inserts the module name ("TestModule") into the interner, so we have 3 total: hello, world, TestModule
// ModuleEnv.init() also interns 19 well-known identifiers: from_int_digits, from_dec_digits, Try, OutOfRange, Builtin, plus, minus, times, div_by, div_trunc_by, rem_by, negate, not, is_lt, is_lte, is_gt, is_gte, is_eq, is_ne
// Plus 17 type identifiers: Builtin.Try, Builtin.Num.Numeral, List, Box, Builtin.Num.{U8, I8, U16, I16, U32, I32, U64, I64, U128, I128, F32, F64, Dec}
try testing.expectEqual(@as(u32, 39), original.common.idents.interner.entry_count);
// Plus 3 field/tag identifiers: before_dot, after_dot, ProvidedByCompiler
try testing.expectEqual(@as(u32, 42), original.common.idents.interner.entry_count);
try testing.expectEqualStrings("hello", original.getIdent(hello_idx));
try testing.expectEqualStrings("world", original.getIdent(world_idx));
@ -159,8 +163,8 @@ test "ModuleEnv.Serialized roundtrip" {
try testing.expectEqual(@as(usize, 2), original.imports.imports.len()); // Should have 2 unique imports
// First verify that the CommonEnv data was preserved after deserialization
// Should have same 39 identifiers as original: hello, world, TestModule + 19 well-known identifiers + 17 type identifiers from ModuleEnv.init()
try testing.expectEqual(@as(u32, 39), env.common.idents.interner.entry_count);
// Should have same 42 identifiers as original: hello, world, TestModule + 19 well-known identifiers + 17 type identifiers + 3 field/tag identifiers from ModuleEnv.init()
try testing.expectEqual(@as(u32, 42), env.common.idents.interner.entry_count);
try testing.expectEqual(@as(usize, 1), env.common.exposed_items.count());
try testing.expectEqual(@as(?u16, 42), env.common.exposed_items.getNodeIndexById(gpa, @as(u32, @bitCast(hello_idx))));

View file

@ -1017,6 +1017,9 @@ fn compileSource(source: []const u8) !CompilerStageData {
.f32_type_ident = common.findIdent("Builtin.Num.F32") orelse unreachable,
.f64_type_ident = common.findIdent("Builtin.Num.F64") orelse unreachable,
.dec_type_ident = common.findIdent("Builtin.Num.Dec") orelse unreachable,
.before_dot_ident = common.findIdent("before_dot") orelse unreachable,
.after_dot_ident = common.findIdent("after_dot") orelse unreachable,
.provided_by_compiler_ident = common.findIdent("ProvidedByCompiler") orelse unreachable,
.deferred_numeric_literals = try ModuleEnv.DeferredNumericLiteral.SafeList.initCapacity(gpa, 0),
};
logDebug("loadCompiledModule: ModuleEnv deserialized successfully\n", .{});

View file

@ -126,6 +126,9 @@ fn loadCompiledModule(gpa: std.mem.Allocator, bin_data: []const u8, module_name:
.f32_type_ident = common.findIdent("Builtin.Num.F32") orelse unreachable,
.f64_type_ident = common.findIdent("Builtin.Num.F64") orelse unreachable,
.dec_type_ident = common.findIdent("Builtin.Num.Dec") orelse unreachable,
.before_dot_ident = common.findIdent("before_dot") orelse unreachable,
.after_dot_ident = common.findIdent("after_dot") orelse unreachable,
.provided_by_compiler_ident = common.findIdent("ProvidedByCompiler") orelse unreachable,
.deferred_numeric_literals = try ModuleEnv.DeferredNumericLiteral.SafeList.initCapacity(gpa, 0),
};