Avoid some ident lookups at runtime

This commit is contained in:
Richard Feldman 2025-11-17 23:15:07 -05:00
parent b9cd90a9f9
commit 9cb8fe4451
No known key found for this signature in database
2 changed files with 19 additions and 9 deletions

View file

@ -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)

View file

@ -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, &lt.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, &lt.type_scope);