@@ -26,8 +26,73 @@ const BuiltinIndices = struct {
2626 bool_type : CIR.Statement.Idx ,
2727 /// Statement index of Result type declaration within Result module
2828 result_type : CIR.Statement.Idx ,
29+ /// Statement index of Dict type declaration within Dict module
30+ dict_type : CIR.Statement.Idx ,
31+ /// Statement index of Set type declaration within Set module
32+ set_type : CIR.Statement.Idx ,
33+ /// Statement index of Str type declaration within Str module
34+ str_type : CIR.Statement.Idx ,
2935};
3036
37+ /// Transform all Str nominal types to .str primitive types in a module.
38+ /// This is necessary because the interpreter needs .str to be a primitive type,
39+ /// but we define methods on Str as a nominal type in Str.roc for ergonomics.
40+ ///
41+ /// This transformation happens after type-checking but before serialization,
42+ /// ensuring that the serialized .bin file contains methods associated with
43+ /// the .str primitive type rather than a nominal Str type.
44+ fn transformStrNominalToPrimitive (env : * ModuleEnv ) ! void {
45+ const types_mod = @import ("types" );
46+ const Content = types_mod .Content ;
47+ const FlatType = types_mod .FlatType ;
48+
49+ // Get the Str identifier in this module
50+ const str_ident_opt = env .common .findIdent ("Str" );
51+ if (str_ident_opt == null ) {
52+ // No Str ident found, nothing to transform
53+ return ;
54+ }
55+ const str_ident = str_ident_opt .? ;
56+
57+ // Iterate through all slots in the type store
58+ var i : u32 = 0 ;
59+ while (i < env .types .len ()) : (i += 1 ) {
60+ const var_idx = @as (types_mod .Var , @enumFromInt (i ));
61+
62+ // Skip redirects, only process roots
63+ if (env .types .isRedirect (var_idx )) {
64+ continue ;
65+ }
66+
67+ const resolved = env .types .resolveVar (var_idx );
68+ const desc = resolved .desc ;
69+
70+ // Check if this descriptor contains a nominal type
71+ switch (desc .content ) {
72+ .structure = > | structure | {
73+ switch (structure ) {
74+ .nominal_type = > | nominal | {
75+ // Check if this is the Str nominal type
76+ // TypeIdent has an ident_idx field that references the identifier
77+ if (nominal .ident .ident_idx == str_ident ) {
78+ // Replace with .str primitive type
79+ const new_content = Content { .structure = FlatType .str };
80+ const new_desc = types_mod.Descriptor {
81+ .content = new_content ,
82+ .rank = desc .rank ,
83+ .mark = desc .mark ,
84+ };
85+ try env .types .setVarDesc (var_idx , new_desc );
86+ }
87+ },
88+ else = > {},
89+ }
90+ },
91+ else = > {},
92+ }
93+ }
94+ }
95+
3196/// Build-time compiler that compiles builtin .roc sources into serialized ModuleEnvs.
3297/// This runs during `zig build` on the host machine to generate .bin files
3398/// that get embedded into the final roc executable.
@@ -56,6 +121,8 @@ pub fn main() !void {
56121
57122 const set_roc_source = try std .fs .cwd ().readFileAlloc (gpa , "src/build/roc/Set.roc" , 1024 * 1024 );
58123
124+ const str_roc_source = try std .fs .cwd ().readFileAlloc (gpa , "src/build/roc/Str.roc" , 1024 * 1024 );
125+
59126 // Compile Bool.roc (it's completely self-contained, doesn't use Bool or Result types)
60127 const bool_env = try compileModule (
61128 gpa ,
@@ -124,6 +191,37 @@ pub fn main() !void {
124191 gpa .free (set_roc_source );
125192 }
126193
194+ // Find Dict type declaration via string lookup
195+ const dict_type_idx = try findTypeDeclaration (dict_env , "Dict" );
196+
197+ // Find Set type declaration via string lookup
198+ const set_type_idx = try findTypeDeclaration (set_env , "Set" );
199+
200+ // Compile Str.roc (uses Bool type in method signatures)
201+ const str_env = try compileModule (
202+ gpa ,
203+ "Str" ,
204+ str_roc_source ,
205+ &[_ ]ModuleDep {
206+ .{ .name = "Bool" , .env = bool_env },
207+ },
208+ bool_type_idx , // Provide Bool type index
209+ result_type_idx , // Provide Result type index
210+ );
211+ defer {
212+ str_env .deinit ();
213+ gpa .destroy (str_env );
214+ gpa .free (str_roc_source );
215+ }
216+
217+ // Find Str type declaration via string lookup
218+ const str_type_idx = try findTypeDeclaration (str_env , "Str" );
219+
220+ // Transform Str nominal types to .str primitive types
221+ // This must happen BEFORE serialization to ensure the .bin file contains
222+ // methods associated with the .str primitive, not a nominal type
223+ try transformStrNominalToPrimitive (str_env );
224+
127225 // Create output directory
128226 try std .fs .cwd ().makePath ("zig-out/builtins" );
129227
@@ -132,11 +230,15 @@ pub fn main() !void {
132230 try serializeModuleEnv (gpa , result_env , "zig-out/builtins/Result.bin" );
133231 try serializeModuleEnv (gpa , dict_env , "zig-out/builtins/Dict.bin" );
134232 try serializeModuleEnv (gpa , set_env , "zig-out/builtins/Set.bin" );
233+ try serializeModuleEnv (gpa , str_env , "zig-out/builtins/Str.bin" );
135234
136235 // Create and serialize builtin indices
137236 const builtin_indices = BuiltinIndices {
138237 .bool_type = bool_type_idx ,
139238 .result_type = result_type_idx ,
239+ .dict_type = dict_type_idx ,
240+ .set_type = set_type_idx ,
241+ .str_type = str_type_idx ,
140242 };
141243 try serializeBuiltinIndices (builtin_indices , "zig-out/builtins/builtin_indices.bin" );
142244}
@@ -210,13 +312,11 @@ fn compileModule(
210312 var module_envs = std .AutoHashMap (base .Ident .Idx , Can .AutoImportedType ).init (gpa );
211313 defer module_envs .deinit ();
212314
213- // Create temporary ident store for module name lookup
214- var temp_idents = try base .Ident .Store .initCapacity (gpa , 16 );
215- defer temp_idents .deinit (gpa );
216-
217- // Add dependencies (e.g., Dict for Set)
315+ // Add dependencies (e.g., Dict for Set, Bool for Str)
316+ // IMPORTANT: Use the module's own ident store, not a temporary one,
317+ // because auto-import lookups will use the module's ident store
218318 for (deps ) | dep | {
219- const dep_ident = try temp_idents . insert ( gpa , base .Ident .for_text (dep .name ));
319+ const dep_ident = try module_env . insertIdent ( base .Ident .for_text (dep .name ));
220320 try module_envs .put (dep_ident , .{ .env = dep .env });
221321 }
222322
0 commit comments