diff --git a/src/layout/store.zig b/src/layout/store.zig index 7f6b6a6ea6..b82e34aae9 100644 --- a/src/layout/store.zig +++ b/src/layout/store.zig @@ -61,6 +61,9 @@ pub const Store = struct { // Reusable work stack for addTypeVar (so it can be stack-safe instead of recursing) work: work.Work, + // Cached List ident to avoid repeated string lookups (null if List doesn't exist in this env) + list_ident: ?Ident.Idx, + // Number of primitive types that are pre-populated in the layout store // Must be kept in sync with the sentinel values in layout.zig Idx enum const num_scalars = 16; @@ -144,6 +147,7 @@ pub const Store = struct { .tuple_data = try collections.SafeList(TupleData).initCapacity(env.gpa, 256), .layouts_by_var = layouts_by_var, .work = try Work.initCapacity(env.gpa, 32), + .list_ident = null, // Lazily initialized on first use }; } @@ -882,13 +886,19 @@ pub const Store = struct { }, .nominal_type => |nominal_type| { // Special handling for Builtin.List - const list_ident = self.env.common.findIdent("List"); - if (list_ident != null and nominal_type.ident.ident_idx == list_ident.?) { + // Lazily initialize list_ident if not yet cached + if (self.list_ident == null) { + self.list_ident = self.env.common.findIdent("List"); + } + const is_builtin_list = if (self.list_ident) |list_ident| + nominal_type.origin_module == self.env.builtin_module_ident and + nominal_type.ident.ident_idx == list_ident + else + false; + if (is_builtin_list) { // Extract the element type from the type arguments const type_args = self.types_store.sliceNominalArgs(nominal_type); - if (type_args.len != 1) { - @panic("List nominal type must have exactly 1 type parameter"); - } + std.debug.assert(type_args.len == 1); // List must have exactly 1 type parameter const elem_var = type_args[0]; // Check if the element type is unbound (flex or rigid) diff --git a/src/layout/store_test.zig b/src/layout/store_test.zig index 71fc5ed24e..4ac09278ae 100644 --- a/src/layout/store_test.zig +++ b/src/layout/store_test.zig @@ -465,8 +465,8 @@ test "nested ZST detection - List of record with ZST field" { // List of this record should be list_of_zst since the record only has ZST fields const list_ident_idx = try lt.module_env.getIdentStore().insert(lt.module_env.gpa, Ident.for_text("List")); const list_type_ident = types.TypeIdent{ .ident_idx = list_ident_idx }; - const origin_module = Ident.Idx{ .attributes = .{ .effectful = false, .ignored = false, .reassignable = false }, .idx = 0 }; - const list_content = try lt.type_store.mkNominal(list_type_ident, record_var, &[_]types.Var{record_var}, origin_module); + const builtin_module_idx = try lt.module_env.insertIdent(Ident.for_text("Builtin")); + const list_content = try lt.type_store.mkNominal(list_type_ident, record_var, &[_]types.Var{record_var}, builtin_module_idx); const list_var = try lt.type_store.freshFromContent(list_content); const list_idx = try lt.layout_store.addTypeVar(list_var, <.type_scope); try testing.expect(lt.layout_store.getLayout(list_idx).tag == .list_of_zst); @@ -530,8 +530,8 @@ test "nested ZST detection - deeply nested" { // List({ field: ({ field2: {} }, ()) }) const list_ident_idx = try lt.module_env.getIdentStore().insert(lt.module_env.gpa, Ident.for_text("List")); const list_type_ident = types.TypeIdent{ .ident_idx = list_ident_idx }; - const origin_module = Ident.Idx{ .attributes = .{ .effectful = false, .ignored = false, .reassignable = false }, .idx = 0 }; - const list_content = try lt.type_store.mkNominal(list_type_ident, outer_record_var, &[_]types.Var{outer_record_var}, origin_module); + const builtin_module_idx = try lt.module_env.insertIdent(Ident.for_text("Builtin")); + const list_content = try lt.type_store.mkNominal(list_type_ident, outer_record_var, &[_]types.Var{outer_record_var}, builtin_module_idx); const list_var = try lt.type_store.freshFromContent(list_content); const list_idx = try lt.layout_store.addTypeVar(list_var, <.type_scope);