diff --git a/src/cache.zig b/src/cache.zig index bc838af1e7..d68c4b73b0 100644 --- a/src/cache.zig +++ b/src/cache.zig @@ -284,10 +284,11 @@ test "NodeStore cache round-trip" { .data_1 = 42, .data_2 = 100, .data_3 = 200, - .region = .{ .start = .{ .offset = 0 }, .end = .{ .offset = 10 } }, .tag = .expr_string, }; const expr_idx = store.nodes.append(store.gpa, expr_node); + const region = base.Region{ .start = .{ .offset = 0 }, .end = .{ .offset = 10 } }; + _ = store.regions.append(store.gpa, region); try store.extra_data.append(store.gpa, 1234); try store.extra_data.append(store.gpa, 5678); diff --git a/src/check/canonicalize.zig b/src/check/canonicalize.zig index f7fa9e152d..f6d58894f0 100644 --- a/src/check/canonicalize.zig +++ b/src/check/canonicalize.zig @@ -162,7 +162,7 @@ fn addBuiltin(self: *Self, ir: *CIR, ident_text: []const u8, idx: CIR.Pattern.Id const gpa = ir.env.gpa; const ident_store = &ir.env.idents; const ident_add = ir.env.idents.insert(gpa, base.Ident.for_text(ident_text), Region.zero()); - const pattern_idx_add = try ir.store.addPattern(CIR.Pattern{ .assign = .{ .ident = ident_add, .region = Region.zero() } }); + const pattern_idx_add = try ir.store.addPattern(CIR.Pattern{ .assign = .{ .ident = ident_add } }, Region.zero()); _ = self.scopeIntroduceInternal(gpa, ident_store, .ident, ident_add, pattern_idx_add, false, true); std.debug.assert(idx == pattern_idx_add); @@ -2150,16 +2150,14 @@ fn canonicalizePattern( // Push a Pattern node for our identifier const assign_idx = try self.can_ir.store.addPattern(CIR.Pattern{ .assign = .{ .ident = ident_idx, - .region = region, - } }); + } }, region); _ = self.can_ir.setTypeVarAtPat(assign_idx, .{ .flex_var = null }); // Introduce the identifier into scope mapping to this pattern node switch (self.scopeIntroduceInternal(self.can_ir.env.gpa, &self.can_ir.env.idents, .ident, ident_idx, assign_idx, false, true)) { .success => {}, .shadowing_warning => |shadowed_pattern_idx| { - const shadowed_pattern = self.can_ir.store.getPattern(shadowed_pattern_idx); - const original_region = shadowed_pattern.toRegion(); + const original_region = self.can_ir.store.getPatternRegion(shadowed_pattern_idx); self.can_ir.pushDiagnostic(CIR.Diagnostic{ .shadowing_warning = .{ .ident = ident_idx, .region = region, @@ -2190,13 +2188,12 @@ fn canonicalizePattern( } }, .underscore => |p| { + const region = self.parse_ir.tokenizedRegionToRegion(p.region); const underscore_pattern = CIR.Pattern{ - .underscore = .{ - .region = self.parse_ir.tokenizedRegionToRegion(p.region), - }, + .underscore = {}, }; - const pattern_idx = try self.can_ir.store.addPattern(underscore_pattern); + const pattern_idx = try self.can_ir.store.addPattern(underscore_pattern, region); _ = self.can_ir.setTypeVarAtPat(pattern_idx, Content{ .flex_var = null }); @@ -2246,10 +2243,9 @@ fn canonicalizePattern( const int_pattern = CIR.Pattern{ .int_literal = .{ .value = .{ .bytes = @bitCast(value), .kind = .i128 }, - .region = region, }, }; - const pattern_idx = try self.can_ir.store.addPattern(int_pattern); + const pattern_idx = try self.can_ir.store.addPattern(int_pattern, region); _ = self.can_ir.setTypeVarAtPat(pattern_idx, Content{ .structure = .{ .num = .{ .num_unbound = int_requirements } }, @@ -2297,19 +2293,17 @@ fn canonicalizePattern( .small_dec_literal = .{ .numerator = small_info.numerator, .denominator_power_of_ten = small_info.denominator_power_of_ten, - .region = region, }, }, .dec => |dec_info| CIR.Pattern{ .dec_literal = .{ .value = dec_info.value, - .region = region, }, }, .f64 => unreachable, // Already handled above }; - const pattern_idx = try self.can_ir.store.addPattern(cir_pattern); + const pattern_idx = try self.can_ir.store.addPattern(cir_pattern, region); _ = self.can_ir.setTypeVarAtPat(pattern_idx, Content{ .structure = .{ .num = .{ .frac_unbound = frac_requirements } }, @@ -2330,10 +2324,9 @@ fn canonicalizePattern( const str_pattern = CIR.Pattern{ .str_literal = .{ .literal = literal, - .region = region, }, }; - const pattern_idx = try self.can_ir.store.addPattern(str_pattern); + const pattern_idx = try self.can_ir.store.addPattern(str_pattern, region); _ = self.can_ir.setTypeVarAtPat(pattern_idx, Content{ .structure = .str }); @@ -2368,10 +2361,9 @@ fn canonicalizePattern( .ext_var = ext_type_var, .tag_name = tag_name, .arguments = args, - .region = region, }, }; - const pattern_idx = try self.can_ir.store.addPattern(tag_pattern); + const pattern_idx = try self.can_ir.store.addPattern(tag_pattern, region); std.debug.assert(@intFromEnum(pattern_idx) == @intFromEnum(final_pattern_idx)); @@ -2412,28 +2404,25 @@ fn canonicalizePattern( // Create the RecordDestruct for this field const record_destruct = CIR.Pattern.RecordDestruct{ - .region = field_region, .label = field_name_ident, .ident = field_name_ident, .kind = .Required, }; - const destruct_idx = self.can_ir.store.addRecordDestruct(record_destruct); + const destruct_idx = self.can_ir.store.addRecordDestruct(record_destruct, field_region); self.can_ir.store.addScratchRecordDestruct(destruct_idx); // Create an assign pattern for this identifier and introduce it into scope const assign_pattern_idx = try self.can_ir.store.addPattern(CIR.Pattern{ .assign = .{ .ident = field_name_ident, - .region = field_region, - } }); + } }, field_region); _ = self.can_ir.setTypeVarAtPat(assign_pattern_idx, .{ .flex_var = null }); // Introduce the identifier into scope switch (self.scopeIntroduceInternal(self.can_ir.env.gpa, &self.can_ir.env.idents, .ident, field_name_ident, assign_pattern_idx, false, true)) { .success => {}, .shadowing_warning => |shadowed_pattern_idx| { - const shadowed_pattern = self.can_ir.store.getPattern(shadowed_pattern_idx); - const original_region = shadowed_pattern.toRegion(); + const original_region = self.can_ir.store.getPatternRegion(shadowed_pattern_idx); self.can_ir.pushDiagnostic(CIR.Diagnostic{ .shadowing_warning = .{ .ident = field_name_ident, .region = field_region, @@ -2477,9 +2466,8 @@ fn canonicalizePattern( .whole_var = whole_var, .ext_var = ext_var, .destructs = destructs_span, - .region = region, }, - }); + }, region); // Set type variable for the pattern _ = self.can_ir.setTypeVarAtPat(pattern_idx, .{ .flex_var = null }); @@ -2513,9 +2501,8 @@ fn canonicalizePattern( const pattern_idx = try self.can_ir.store.addPattern(CIR.Pattern{ .tuple = .{ .patterns = patterns_span, - .region = region, }, - }); + }, region); // Insert concrete type variable for tuple pattern _ = self.can_ir.setTypeVarAtPat( @@ -2566,8 +2553,7 @@ fn canonicalizePattern( const name_region = self.parse_ir.tokenizedRegionToRegion(.{ .start = name_tok, .end = name_tok }); const assign_idx = try self.can_ir.store.addPattern(CIR.Pattern{ .assign = .{ .ident = ident_idx, - .region = name_region, - } }); + } }, name_region); // Set the rest variable's type to be a list of the same element type const rest_list_type = Content{ .structure = .{ .list = elem_var } }; @@ -2577,8 +2563,7 @@ fn canonicalizePattern( switch (self.scopeIntroduceInternal(self.can_ir.env.gpa, &self.can_ir.env.idents, .ident, ident_idx, assign_idx, false, true)) { .success => {}, .shadowing_warning => |shadowed_pattern_idx| { - const shadowed_pattern = self.can_ir.store.getPattern(shadowed_pattern_idx); - const original_region = shadowed_pattern.toRegion(); + const original_region = self.can_ir.store.getPatternRegion(shadowed_pattern_idx); self.can_ir.pushDiagnostic(CIR.Diagnostic{ .shadowing_warning = .{ .ident = ident_idx, .region = name_region, @@ -2636,9 +2621,8 @@ fn canonicalizePattern( .elem_var = elem_var, .patterns = patterns_span, .rest_info = if (rest_index) |idx| .{ .index = idx, .pattern = rest_pattern } else null, - .region = region, }, - }); + }, region); // Set type variable for the pattern - this should be the list type const list_type = Content{ .structure = .{ .list = elem_var } }; @@ -3022,8 +3006,7 @@ fn scopeIntroduceIdent( return pattern_idx; }, .shadowing_warning => |shadowed_pattern_idx| { - const shadowed_pattern = self.can_ir.store.getPattern(shadowed_pattern_idx); - const original_region = shadowed_pattern.toRegion(); + const original_region = self.can_ir.store.getPatternRegion(shadowed_pattern_idx); self.can_ir.pushDiagnostic(CIR.Diagnostic{ .shadowing_warning = .{ .ident = ident_idx, .region = region, @@ -3066,8 +3049,7 @@ fn scopeIntroduceVar( return pattern_idx; }, .shadowing_warning => |shadowed_pattern_idx| { - const shadowed_pattern = self.can_ir.store.getPattern(shadowed_pattern_idx); - const original_region = shadowed_pattern.toRegion(); + const original_region = self.can_ir.store.getPatternRegion(shadowed_pattern_idx); self.can_ir.pushDiagnostic(CIR.Diagnostic{ .shadowing_warning = .{ .ident = ident_idx, .region = region, @@ -3608,7 +3590,7 @@ pub fn canonicalizeStatement(self: *Self, stmt_idx: AST.Statement.Idx) std.mem.A const init_expr_idx = try self.canonicalizeExpr(v.body) orelse return null; // Create pattern for the var - const pattern_idx = try self.can_ir.store.addPattern(CIR.Pattern{ .assign = .{ .ident = var_name, .region = region } }); + const pattern_idx = try self.can_ir.store.addPattern(CIR.Pattern{ .assign = .{ .ident = var_name } }, region); // Introduce the var with function boundary tracking _ = self.scopeIntroduceVar(var_name, pattern_idx, region, true, CIR.Pattern.Idx); @@ -4197,8 +4179,7 @@ fn checkScopeForUnusedVariables(self: *Self, scope: *const Scope) void { } // Get the region for this pattern to provide good error location - const pattern = self.can_ir.store.getPattern(pattern_idx); - const region = pattern.toRegion(); + const region = self.can_ir.store.getPatternRegion(pattern_idx); // Report unused variable self.can_ir.pushDiagnostic(CIR.Diagnostic{ .unused_variable = .{ @@ -5707,11 +5688,10 @@ test "numeric literal patterns use pattern idx as type var" { const int_pattern = CIR.Pattern{ .int_literal = .{ .value = .{ .bytes = @bitCast(@as(i128, 42)), .kind = .i128 }, - .region = Region.zero(), }, }; - const pattern_idx = try cir.store.addPattern(int_pattern); + const pattern_idx = try cir.store.addPattern(int_pattern, base.Region.zero()); // Set the type variable for the pattern _ = cir.setTypeVarAtPat(pattern_idx, Content{ @@ -5756,11 +5736,10 @@ test "numeric literal patterns use pattern idx as type var" { const dec_pattern = CIR.Pattern{ .dec_literal = .{ .value = RocDec.fromF64(3.14) orelse unreachable, - .region = Region.zero(), }, }; - const pattern_idx = try cir.store.addPattern(dec_pattern); + const pattern_idx = try cir.store.addPattern(dec_pattern, base.Region.zero()); // Set the type variable for the pattern _ = cir.setTypeVarAtPat(pattern_idx, Content{ @@ -5811,11 +5790,10 @@ test "numeric pattern types: unbound vs polymorphic" { const pattern = CIR.Pattern{ .int_literal = .{ .value = .{ .bytes = @bitCast(@as(i128, -17)), .kind = .i128 }, - .region = Region.zero(), }, }; - const pattern_idx = try cir.store.addPattern(pattern); + const pattern_idx = try cir.store.addPattern(pattern, base.Region.zero()); // Set as int_unbound (used when pattern matching where type is not yet known) _ = cir.setTypeVarAtPat(pattern_idx, Content{ @@ -5853,11 +5831,10 @@ test "numeric pattern types: unbound vs polymorphic" { const pattern = CIR.Pattern{ .int_literal = .{ .value = .{ .bytes = @bitCast(@as(i128, 255)), .kind = .i128 }, - .region = Region.zero(), }, }; - const pattern_idx = try cir.store.addPattern(pattern); + const pattern_idx = try cir.store.addPattern(pattern, base.Region.zero()); // Create a fresh type variable for polymorphic int const poly_var = env.types.fresh(); @@ -5906,11 +5883,10 @@ test "numeric pattern types: unbound vs polymorphic" { const pattern = CIR.Pattern{ .int_literal = .{ .value = .{ .bytes = @bitCast(@as(i128, 10)), .kind = .i128 }, - .region = Region.zero(), }, }; - const pattern_idx = try cir.store.addPattern(pattern); + const pattern_idx = try cir.store.addPattern(pattern, base.Region.zero()); // Set as num_unbound (decimal literal that could be int or frac) _ = cir.setTypeVarAtPat(pattern_idx, Content{ @@ -5948,11 +5924,10 @@ test "numeric pattern types: unbound vs polymorphic" { const pattern = CIR.Pattern{ .int_literal = .{ .value = .{ .bytes = @bitCast(@as(i128, 5)), .kind = .i128 }, - .region = Region.zero(), }, }; - const pattern_idx = try cir.store.addPattern(pattern); + const pattern_idx = try cir.store.addPattern(pattern, base.Region.zero()); // Create a fresh type variable for polymorphic num const poly_var = env.types.fresh(); @@ -5997,11 +5972,10 @@ test "numeric pattern types: unbound vs polymorphic" { const pattern = CIR.Pattern{ .dec_literal = .{ .value = RocDec.fromF64(2.5) orelse unreachable, - .region = Region.zero(), }, }; - const pattern_idx = try cir.store.addPattern(pattern); + const pattern_idx = try cir.store.addPattern(pattern, base.Region.zero()); // Set as frac_unbound _ = cir.setTypeVarAtPat(pattern_idx, Content{ @@ -6318,11 +6292,10 @@ test "numeric pattern types: unbound vs polymorphic - frac" { const pattern = CIR.Pattern{ .dec_literal = .{ .value = RocDec.fromF64(1000000.0) orelse unreachable, - .region = Region.zero(), }, }; - const pattern_idx = try cir.store.addPattern(pattern); + const pattern_idx = try cir.store.addPattern(pattern, base.Region.zero()); // Create a fresh type variable for polymorphic frac const poly_var = env.types.fresh(); @@ -6378,10 +6351,9 @@ test "pattern numeric literal value edge cases" { const max_pattern = CIR.Pattern{ .int_literal = .{ .value = .{ .bytes = @bitCast(@as(i128, std.math.maxInt(i128))), .kind = .i128 }, - .region = Region.zero(), }, }; - const max_idx = try cir.store.addPattern(max_pattern); + const max_idx = try cir.store.addPattern(max_pattern, base.Region.zero()); const stored_max = cir.store.getPattern(max_idx); try std.testing.expectEqual(std.math.maxInt(i128), @as(i128, @bitCast(stored_max.int_literal.value.bytes))); @@ -6389,10 +6361,9 @@ test "pattern numeric literal value edge cases" { const min_pattern = CIR.Pattern{ .int_literal = .{ .value = .{ .bytes = @bitCast(@as(i128, std.math.minInt(i128))), .kind = .i128 }, - .region = Region.zero(), }, }; - const min_idx = try cir.store.addPattern(min_pattern); + const min_idx = try cir.store.addPattern(min_pattern, base.Region.zero()); const stored_min = cir.store.getPattern(min_idx); try std.testing.expectEqual(std.math.minInt(i128), @as(i128, @bitCast(stored_min.int_literal.value.bytes))); } @@ -6409,11 +6380,11 @@ test "pattern numeric literal value edge cases" { .small_dec_literal = .{ .numerator = 1234, .denominator_power_of_ten = 2, // 12.34 - .region = Region.zero(), + }, }; - const pattern_idx = try cir.store.addPattern(small_dec_pattern); + const pattern_idx = try cir.store.addPattern(small_dec_pattern, base.Region.zero()); const stored = cir.store.getPattern(pattern_idx); try std.testing.expect(stored == .small_dec_literal); @@ -6432,11 +6403,11 @@ test "pattern numeric literal value edge cases" { const dec_pattern = CIR.Pattern{ .dec_literal = .{ .value = RocDec{ .num = 314159265358979323 }, // π * 10^17 - .region = Region.zero(), + }, }; - const pattern_idx = try cir.store.addPattern(dec_pattern); + const pattern_idx = try cir.store.addPattern(dec_pattern, base.Region.zero()); const stored = cir.store.getPattern(pattern_idx); try std.testing.expect(stored == .dec_literal); @@ -6455,10 +6426,9 @@ test "pattern numeric literal value edge cases" { const neg_zero_pattern = CIR.Pattern{ .dec_literal = .{ .value = RocDec.fromF64(-0.0) orelse unreachable, - .region = Region.zero(), }, }; - const neg_zero_idx = try cir.store.addPattern(neg_zero_pattern); + const neg_zero_idx = try cir.store.addPattern(neg_zero_pattern, base.Region.zero()); const stored_neg_zero = cir.store.getPattern(neg_zero_idx); try std.testing.expect(stored_neg_zero == .dec_literal); try std.testing.expectEqual(@as(i128, 0), stored_neg_zero.dec_literal.value.num); @@ -6481,11 +6451,10 @@ test "pattern literal type transitions" { const pattern = CIR.Pattern{ .int_literal = .{ .value = .{ .bytes = @bitCast(@as(i128, 100)), .kind = .i128 }, - .region = Region.zero(), }, }; - const pattern_idx = try cir.store.addPattern(pattern); + const pattern_idx = try cir.store.addPattern(pattern, base.Region.zero()); // Start as num_unbound _ = cir.setTypeVarAtPat(pattern_idx, Content{ @@ -6532,11 +6501,10 @@ test "pattern literal type transitions" { const hex_pattern = CIR.Pattern{ .int_literal = .{ .value = .{ .bytes = @bitCast(@as(i128, 0xFF)), .kind = .i128 }, - .region = Region.zero(), }, }; - const hex_idx = try cir.store.addPattern(hex_pattern); + const hex_idx = try cir.store.addPattern(hex_pattern, base.Region.zero()); // Non-decimal literals use int_unbound (not num_unbound) _ = cir.setTypeVarAtPat(hex_idx, Content{ @@ -6588,7 +6556,6 @@ test "pattern type inference with numeric literals" { .pattern = CIR.Pattern{ .int_literal = .{ .value = .{ .bytes = @bitCast(@as(i128, 42)), .kind = .i128 }, - .region = Region.zero(), }, }, .expected_type = Content{ .structure = .{ .num = .{ .num_unbound = .{ @@ -6601,7 +6568,6 @@ test "pattern type inference with numeric literals" { .pattern = CIR.Pattern{ .int_literal = .{ .value = .{ .bytes = @bitCast(@as(i128, -42)), .kind = .i128 }, - .region = Region.zero(), }, }, .expected_type = Content{ .structure = .{ .num = .{ .num_unbound = .{ @@ -6614,7 +6580,6 @@ test "pattern type inference with numeric literals" { .pattern = CIR.Pattern{ .int_literal = .{ .value = .{ .bytes = @bitCast(@as(i128, 65536)), .kind = .i128 }, - .region = Region.zero(), }, }, .expected_type = Content{ @@ -6631,7 +6596,7 @@ test "pattern type inference with numeric literals" { }; for (patterns) |test_case| { - const pattern_idx = try cir.store.addPattern(test_case.pattern); + const pattern_idx = try cir.store.addPattern(test_case.pattern, base.Region.zero()); _ = cir.setTypeVarAtPat(pattern_idx, test_case.expected_type); // Verify the pattern index works as a type variable @@ -6655,11 +6620,10 @@ test "pattern type inference with numeric literals" { const pattern = CIR.Pattern{ .int_literal = .{ .value = .{ .bytes = @bitCast(@as(i128, 100)), .kind = .i128 }, - .region = Region.zero(), }, }; - const pattern_idx = try cir.store.addPattern(pattern); + const pattern_idx = try cir.store.addPattern(pattern, base.Region.zero()); // Start as num_unbound _ = cir.setTypeVarAtPat(pattern_idx, Content{ diff --git a/src/check/canonicalize/CIR.zig b/src/check/canonicalize/CIR.zig index 38a9057ad4..cd75320019 100644 --- a/src/check/canonicalize/CIR.zig +++ b/src/check/canonicalize/CIR.zig @@ -466,8 +466,8 @@ fn formatPatternIdxNode(gpa: std.mem.Allocator, pattern_idx: Pattern.Idx) SExpr return node; } -test "Node is 24 bytes" { - try testing.expectEqual(24, @sizeOf(Node)); +test "Node is 16 bytes" { + try testing.expectEqual(16, @sizeOf(Node)); } /// A working representation of a record field @@ -710,7 +710,7 @@ pub const Def = struct { var node = SExpr.init(gpa, kind); - var pattern_node = ir.store.getPattern(self.pattern).toSExpr(ir); + var pattern_node = ir.store.getPattern(self.pattern).toSExpr(ir, self.pattern); node.appendNode(gpa, &pattern_node); var expr_node = ir.store.getExpr(self.expr).toSExpr(ir); @@ -1075,10 +1075,10 @@ pub fn toSexprTypes(ir: *CIR, maybe_expr_idx: ?Expr.Idx, source: []const u8) SEx // Extract identifier name from the pattern (assuming it's an assign pattern) const pattern = ir.store.getPattern(def.pattern); switch (pattern) { - .assign => |assign_pat| { + .assign => |_| { var def_node = SExpr.init(gpa, "patt"); - ir.appendRegionInfoToSexprNodeFromRegion(&def_node, assign_pat.region); + ir.appendRegionInfoToSexprNode(&def_node, def_idx); // Get the type variable for this definition // Each definition has a type_var at its node index which represents the type of the definition diff --git a/src/check/canonicalize/Expression.zig b/src/check/canonicalize/Expression.zig index c99ac12f59..babec343f9 100644 --- a/src/check/canonicalize/Expression.zig +++ b/src/check/canonicalize/Expression.zig @@ -715,7 +715,7 @@ pub const Expr = union(enum) { // Handle args span var args_node = SExpr.init(gpa, "args"); for (ir.store.slicePatterns(lambda_expr.args)) |arg_idx| { - var pattern_node = ir.store.getPattern(arg_idx).toSExpr(ir); + var pattern_node = ir.store.getPattern(arg_idx).toSExpr(ir, arg_idx); args_node.appendNode(gpa, &pattern_node); } node.appendNode(gpa, &args_node); @@ -837,7 +837,7 @@ pub const Expr = union(enum) { for (patterns_slice) |branch_pat_idx| { const branch_pat = ir.store.getMatchBranchPattern(branch_pat_idx); const pattern = ir.store.getPattern(branch_pat.pattern); - var pattern_sexpr = pattern.toSExpr(ir); + var pattern_sexpr = pattern.toSExpr(ir, branch_pat.pattern); pattern_sexpr.appendBoolAttr(gpa, "degenerate", branch_pat.degenerate); patterns_node.appendNode(gpa, &pattern_sexpr); } diff --git a/src/check/canonicalize/Node.zig b/src/check/canonicalize/Node.zig index 6ace6a6bf5..78c2593a20 100644 --- a/src/check/canonicalize/Node.zig +++ b/src/check/canonicalize/Node.zig @@ -12,7 +12,6 @@ const collections = @import("../../collections.zig"); data_1: u32, data_2: u32, data_3: u32, -region: base.Region, tag: Tag, /// A list of nodes. diff --git a/src/check/canonicalize/NodeStore.zig b/src/check/canonicalize/NodeStore.zig index 8cd8a693bb..e35f5aa345 100644 --- a/src/check/canonicalize/NodeStore.zig +++ b/src/check/canonicalize/NodeStore.zig @@ -21,6 +21,7 @@ const NodeStore = @This(); gpa: std.mem.Allocator, nodes: Node.List, +regions: Region.List, extra_data: std.ArrayListUnmanaged(u32), scratch_statements: base.Scratch(CIR.Statement.Idx), scratch_exprs: base.Scratch(CIR.Expr.Idx), @@ -50,6 +51,7 @@ pub fn initCapacity(gpa: std.mem.Allocator, capacity: usize) NodeStore { return .{ .gpa = gpa, .nodes = Node.List.initCapacity(gpa, capacity), + .regions = Region.List.initCapacity(gpa, capacity), .extra_data = std.ArrayListUnmanaged(u32).initCapacity(gpa, capacity / 2) catch |err| exitOnOom(err), .scratch_statements = base.Scratch(CIR.Statement.Idx).init(gpa), .scratch_exprs = base.Scratch(CIR.Expr.Idx).init(gpa), @@ -72,6 +74,7 @@ pub fn initCapacity(gpa: std.mem.Allocator, capacity: usize) NodeStore { /// Deinitializes the NodeStore, freeing any allocated resources. pub fn deinit(store: *NodeStore) void { store.nodes.deinit(store.gpa); + store.regions.deinit(store.gpa); store.extra_data.deinit(store.gpa); store.scratch_statements.items.deinit(store.gpa); store.scratch_exprs.items.deinit(store.gpa); @@ -134,10 +137,21 @@ comptime { std.debug.assert(pattern_fields.len == CIR_PATTERN_NODE_COUNT); } +/// Helper function to get a region by node index, handling the type conversion +pub fn getRegionAt(store: *const NodeStore, node_idx: Node.Idx) Region { + const idx: Region.Idx = @enumFromInt(@intFromEnum(node_idx)); + return store.regions.get(idx).*; +} + +/// Helper function to get a region by pattern index +pub fn getPatternRegion(store: *const NodeStore, pattern_idx: CIR.Pattern.Idx) Region { + const node_idx: Node.Idx = @enumFromInt(@intFromEnum(pattern_idx)); + return store.getRegionAt(node_idx); +} + /// Retrieves a region from node from the store. pub fn getNodeRegion(store: *const NodeStore, node_idx: Node.Idx) Region { - const node = store.nodes.get(node_idx); - return node.region; + return store.getRegionAt(node_idx); } /// Retrieves a statement node from the store. @@ -147,40 +161,40 @@ pub fn getStatement(store: *const NodeStore, statement: CIR.Statement.Idx) CIR.S switch (node.tag) { .statement_decl => return CIR.Statement{ .s_decl = .{ - .region = node.region, + .region = store.getRegionAt(node_idx), .expr = @enumFromInt(node.data_1), .pattern = @enumFromInt(node.data_2), } }, .statement_var => return CIR.Statement{ .s_var = .{ - .region = node.region, + .region = store.getRegionAt(node_idx), .expr = @enumFromInt(node.data_1), .pattern_idx = @enumFromInt(node.data_2), } }, .statement_reassign => return CIR.Statement{ .s_reassign = .{ - .region = node.region, + .region = store.getRegionAt(node_idx), .expr = @enumFromInt(node.data_1), .pattern_idx = @enumFromInt(node.data_2), } }, .statement_crash => return CIR.Statement{ .s_crash = .{ .msg = @enumFromInt(node.data_1), - .region = node.region, + .region = store.getRegionAt(node_idx), } }, .statement_expr => return .{ .s_expr = .{ .expr = @enumFromInt(node.data_1), - .region = node.region, + .region = store.getRegionAt(node_idx), } }, .statement_expect => return CIR.Statement{ .s_expect = .{ - .region = node.region, + .region = store.getRegionAt(node_idx), .body = @enumFromInt(node.data_1), } }, .statement_for => return CIR.Statement{ .s_for = .{ - .region = node.region, + .region = store.getRegionAt(node_idx), .body = @enumFromInt(node.data_1), .expr = @enumFromInt(node.data_2), .patt = @enumFromInt(node.data_3), } }, .statement_return => return CIR.Statement{ .s_return = .{ - .region = node.region, + .region = store.getRegionAt(node_idx), .expr = @enumFromInt(node.data_1), } }, .statement_import => { @@ -198,7 +212,7 @@ pub fn getStatement(store: *const NodeStore, statement: CIR.Statement.Idx) CIR.S return CIR.Statement{ .s_import = .{ - .region = node.region, + .region = store.getRegionAt(node_idx), .module_name_tok = @bitCast(node.data_1), .exposes = DataSpan.init(exposes_start, exposes_len).as(CIR.ExposedItem.Span), .alias_tok = alias_tok, @@ -221,7 +235,7 @@ pub fn getStatement(store: *const NodeStore, statement: CIR.Statement.Idx) CIR.S return CIR.Statement{ .s_alias_decl = .{ - .region = node.region, + .region = store.getRegionAt(node_idx), .anno = anno, .header = header, .where = where_clause, @@ -243,7 +257,7 @@ pub fn getStatement(store: *const NodeStore, statement: CIR.Statement.Idx) CIR.S return CIR.Statement{ .s_nominal_decl = .{ - .region = node.region, + .region = store.getRegionAt(node_idx), .anno = anno, .header = header, .where = where_clause, @@ -266,7 +280,7 @@ pub fn getStatement(store: *const NodeStore, statement: CIR.Statement.Idx) CIR.S return CIR.Statement{ .s_type_anno = .{ - .region = node.region, + .region = store.getRegionAt(node_idx), .name = name, .anno = anno, .where = where_clause, @@ -289,7 +303,7 @@ pub fn getExpr(store: *const NodeStore, expr: CIR.Expr.Idx) CIR.Expr { return CIR.Expr{ .e_lookup_local = .{ .pattern_idx = @enumFromInt(node.data_1), - .region = node.region, + .region = store.getRegionAt(node_idx), }, }; }, @@ -305,7 +319,7 @@ pub fn getExpr(store: *const NodeStore, expr: CIR.Expr.Idx) CIR.Expr { return CIR.Expr{ .e_int = .{ .value = .{ .bytes = @bitCast(value_as_u32s.*), .kind = .i128 }, - .region = node.region, + .region = store.getRegionAt(node_idx), }, }; }, @@ -314,7 +328,7 @@ pub fn getExpr(store: *const NodeStore, expr: CIR.Expr.Idx) CIR.Expr { .e_list = .{ .elems = .{ .span = .{ .start = node.data_1, .len = node.data_2 } }, .elem_var = @enumFromInt(node.data_3), - .region = node.region, + .region = store.getRegionAt(node_idx), }, }; }, @@ -322,7 +336,7 @@ pub fn getExpr(store: *const NodeStore, expr: CIR.Expr.Idx) CIR.Expr { return CIR.Expr{ .e_tuple = .{ .elems = .{ .span = .{ .start = node.data_1, .len = node.data_2 } }, - .region = node.region, + .region = store.getRegionAt(node_idx), }, }; }, @@ -338,7 +352,7 @@ pub fn getExpr(store: *const NodeStore, expr: CIR.Expr.Idx) CIR.Expr { .e_call = .{ .args = .{ .span = .{ .start = args_start, .len = args_len } }, .called_via = @enumFromInt(node.data_2), - .region = node.region, + .region = store.getRegionAt(node_idx), }, }; }, @@ -352,7 +366,7 @@ pub fn getExpr(store: *const NodeStore, expr: CIR.Expr.Idx) CIR.Expr { return CIR.Expr{ .e_frac_f64 = .{ .value = value, - .region = node.region, + .region = store.getRegionAt(node_idx), }, }; }, @@ -365,7 +379,7 @@ pub fn getExpr(store: *const NodeStore, expr: CIR.Expr.Idx) CIR.Expr { return CIR.Expr{ .e_frac_dec = .{ .value = RocDec{ .num = value_as_i128 }, - .region = node.region, + .region = store.getRegionAt(node_idx), }, }; }, @@ -380,17 +394,17 @@ pub fn getExpr(store: *const NodeStore, expr: CIR.Expr.Idx) CIR.Expr { .e_dec_small = .{ .numerator = numerator, .denominator_power_of_ten = denominator_power_of_ten, - .region = node.region, + .region = store.getRegionAt(node_idx), }, }; }, .expr_string_segment => return CIR.Expr.initStrSegment( @enumFromInt(node.data_1), - node.region, + store.getRegionAt(node_idx), ), .expr_string => return CIR.Expr.initStr( DataSpan.init(node.data_1, node.data_2).as(CIR.Expr.Span), - node.region, + store.getRegionAt(node_idx), ), .expr_tag => { const extra_start = node.data_1; @@ -406,7 +420,7 @@ pub fn getExpr(store: *const NodeStore, expr: CIR.Expr.Idx) CIR.Expr { .ext_var = ext_var, .name = name, .args = .{ .span = .{ .start = args_start, .len = args_len } }, - .region = node.region, + .region = store.getRegionAt(node_idx), }, }; }, @@ -416,7 +430,7 @@ pub fn getExpr(store: *const NodeStore, expr: CIR.Expr.Idx) CIR.Expr { @enumFromInt(node.data_1), @enumFromInt(node.data_2), @enumFromInt(node.data_3), - node.region, + store.getRegionAt(node_idx), ), }; }, @@ -433,7 +447,7 @@ pub fn getExpr(store: *const NodeStore, expr: CIR.Expr.Idx) CIR.Expr { .e_lambda = .{ .args = .{ .span = .{ .start = args_start, .len = args_len } }, .body = @enumFromInt(body_idx), - .region = node.region, + .region = store.getRegionAt(node_idx), }, }; }, @@ -442,21 +456,21 @@ pub fn getExpr(store: *const NodeStore, expr: CIR.Expr.Idx) CIR.Expr { .e_block = .{ .stmts = .{ .span = .{ .start = node.data_1, .len = node.data_2 } }, .final_expr = @enumFromInt(node.data_3), - .region = node.region, + .region = store.getRegionAt(node_idx), }, }; }, .expr_empty_record => { return CIR.Expr{ .e_empty_record = .{ - .region = node.region, + .region = store.getRegionAt(node_idx), }, }; }, .expr_empty_list => { return CIR.Expr{ .e_empty_list = .{ - .region = node.region, + .region = store.getRegionAt(node_idx), }, }; }, @@ -474,7 +488,7 @@ pub fn getExpr(store: *const NodeStore, expr: CIR.Expr.Idx) CIR.Expr { .e_record = .{ .fields = .{ .span = .{ .start = fields_start, .len = fields_len } }, .ext = ext, - .region = node.region, + .region = store.getRegionAt(node_idx), }, }; }, @@ -490,7 +504,7 @@ pub fn getExpr(store: *const NodeStore, expr: CIR.Expr.Idx) CIR.Expr { return CIR.Expr{ .e_match = CIR.Expr.Match{ .cond = cond, - .region = node.region, + .region = store.getRegionAt(node_idx), .branches = .{ .span = .{ .start = branches_start, .len = branches_len } }, .exhaustive = exhaustive, }, @@ -511,7 +525,7 @@ pub fn getExpr(store: *const NodeStore, expr: CIR.Expr.Idx) CIR.Expr { .variant_var = variant_var, .ext_var = ext_var, .name = name, - .region = node.region, + .region = store.getRegionAt(node_idx), }, }; }, @@ -527,7 +541,7 @@ pub fn getExpr(store: *const NodeStore, expr: CIR.Expr.Idx) CIR.Expr { std.log.debug("TODO: implement getExpr for node type {?}", .{node.tag}); return CIR.Expr{ .e_runtime_error = .{ .diagnostic = @enumFromInt(0), - .region = node.region, + .region = store.getRegionAt(node_idx), } }; }, .expr_if_then_else => { @@ -547,7 +561,7 @@ pub fn getExpr(store: *const NodeStore, expr: CIR.Expr.Idx) CIR.Expr { return CIR.Expr{ .e_if = .{ .branches = branches_span, .final_else = final_else, - .region = node.region, + .region = store.getRegionAt(node_idx), } }; }, .expr_dot_access => { @@ -561,13 +575,13 @@ pub fn getExpr(store: *const NodeStore, expr: CIR.Expr.Idx) CIR.Expr { .receiver = @enumFromInt(node.data_1), .field_name = @bitCast(node.data_2), .args = args_span, - .region = node.region, + .region = store.getRegionAt(node_idx), } }; }, .malformed => { return CIR.Expr{ .e_runtime_error = .{ .diagnostic = @enumFromInt(node.data_1), - .region = node.region, + .region = store.getRegionAt(node_idx), } }; }, @@ -618,7 +632,7 @@ pub fn getMatchBranch(store: *const NodeStore, branch: CIR.Expr.Match.Branch.Idx .value = value_idx, .guard = guard_idx, .redundant = redundant, - .region = node.region, + .region = store.getRegionAt(node_idx), }; } @@ -632,7 +646,7 @@ pub fn getMatchBranchPattern(store: *const NodeStore, branch_pat: CIR.Expr.Match return CIR.Expr.Match.BranchPattern{ .pattern = @enumFromInt(node.data_1), .degenerate = if (node.data_2 == 0) false else true, - .region = node.region, + .region = store.getRegionAt(node_idx), }; } @@ -723,14 +737,12 @@ pub fn getPattern(store: *const NodeStore, pattern_idx: CIR.Pattern.Idx) CIR.Pat .pattern_identifier => return CIR.Pattern{ .assign = .{ .ident = @bitCast(node.data_1), - .region = node.region, }, }, .pattern_as => return CIR.Pattern{ .as = .{ .ident = @bitCast(node.data_1), .pattern = @enumFromInt(node.data_2), - .region = node.region, }, }, .pattern_applied_tag => { @@ -744,7 +756,6 @@ pub fn getPattern(store: *const NodeStore, pattern_idx: CIR.Pattern.Idx) CIR.Pat return CIR.Pattern{ .applied_tag = .{ - .region = node.region, .arguments = DataSpan.init(arguments_start, arguments_len).as(CIR.Pattern.Span), .tag_name = tag_name, .ext_var = ext_var, @@ -762,7 +773,6 @@ pub fn getPattern(store: *const NodeStore, pattern_idx: CIR.Pattern.Idx) CIR.Pat return CIR.Pattern{ .record_destructure = .{ - .region = node.region, .destructs = DataSpan.init(destructs_start, destructs_len).as(CIR.Pattern.RecordDestruct.Span), .ext_var = ext_var, .whole_var = whole_var, @@ -795,7 +805,6 @@ pub fn getPattern(store: *const NodeStore, pattern_idx: CIR.Pattern.Idx) CIR.Pat return CIR.Pattern{ .list = .{ - .region = node.region, .patterns = DataSpan.init(patterns_start, patterns_len).as(CIR.Pattern.Span), .elem_var = elem_var, .list_var = list_var, @@ -805,7 +814,6 @@ pub fn getPattern(store: *const NodeStore, pattern_idx: CIR.Pattern.Idx) CIR.Pat }, .pattern_tuple => return CIR.Pattern{ .tuple = .{ - .region = node.region, .patterns = DataSpan.init(node.data_1, node.data_2).as(CIR.Pattern.Span), }, }, @@ -816,7 +824,6 @@ pub fn getPattern(store: *const NodeStore, pattern_idx: CIR.Pattern.Idx) CIR.Pat return CIR.Pattern{ .int_literal = .{ - .region = node.region, .value = .{ .bytes = @bitCast(value_as_i128), .kind = .i128 }, }, }; @@ -828,7 +835,6 @@ pub fn getPattern(store: *const NodeStore, pattern_idx: CIR.Pattern.Idx) CIR.Pat return CIR.Pattern{ .int_literal = .{ - .region = node.region, .value = .{ .bytes = @bitCast(value_as_i128), .kind = .i128 }, }, }; @@ -840,7 +846,6 @@ pub fn getPattern(store: *const NodeStore, pattern_idx: CIR.Pattern.Idx) CIR.Pat return CIR.Pattern{ .dec_literal = .{ - .region = node.region, .value = RocDec{ .num = value_as_i128 }, }, }; @@ -854,14 +859,12 @@ pub fn getPattern(store: *const NodeStore, pattern_idx: CIR.Pattern.Idx) CIR.Pat return CIR.Pattern{ .small_dec_literal = .{ - .region = node.region, .numerator = numerator, .denominator_power_of_ten = denominator_power_of_ten, }, }; }, .pattern_str_literal => return CIR.Pattern{ .str_literal = .{ - .region = node.region, .literal = @enumFromInt(node.data_1), } }, .pattern_char_literal => { @@ -875,20 +878,16 @@ pub fn getPattern(store: *const NodeStore, pattern_idx: CIR.Pattern.Idx) CIR.Pat return CIR.Pattern{ .char_literal = .{ - .region = node.region, .num_var = num_var, .requirements = .{ .sign_needed = sign_needed, .bits_needed = bits_needed }, .value = value, }, }; }, - .pattern_underscore => return CIR.Pattern{ .underscore = .{ - .region = node.region, - } }, + .pattern_underscore => return CIR.Pattern{ .underscore = {} }, .malformed => { return CIR.Pattern{ .runtime_error = .{ .diagnostic = @enumFromInt(node.data_1), - .region = node.region, } }; }, else => { @@ -914,31 +913,31 @@ pub fn getTypeAnno(store: *const NodeStore, typeAnno: CIR.TypeAnno.Idx) CIR.Type .ty_apply => return CIR.TypeAnno{ .apply = .{ .symbol = @bitCast(node.data_1), .args = .{ .span = .{ .start = node.data_2, .len = node.data_3 } }, - .region = node.region, + .region = store.getRegionAt(node_idx), } }, .ty_var => return CIR.TypeAnno{ .ty_var = .{ .name = @bitCast(node.data_1), - .region = node.region, + .region = store.getRegionAt(node_idx), } }, .ty_underscore => return CIR.TypeAnno{ .underscore = .{ - .region = node.region, + .region = store.getRegionAt(node_idx), } }, .ty_ident => return CIR.TypeAnno{ .ty = .{ .symbol = @bitCast(node.data_1), - .region = node.region, + .region = store.getRegionAt(node_idx), } }, .ty_tag_union => return CIR.TypeAnno{ .tag_union = .{ .tags = .{ .span = .{ .start = node.data_1, .len = node.data_2 } }, .open_anno = if (node.data_3 != 0) @enumFromInt(node.data_3) else null, - .region = node.region, + .region = store.getRegionAt(node_idx), } }, .ty_tuple => return CIR.TypeAnno{ .tuple = .{ .annos = .{ .span = .{ .start = node.data_1, .len = node.data_2 } }, - .region = node.region, + .region = store.getRegionAt(node_idx), } }, .ty_record => return CIR.TypeAnno{ .record = .{ .fields = .{ .span = .{ .start = node.data_1, .len = node.data_2 } }, - .region = node.region, + .region = store.getRegionAt(node_idx), } }, .ty_fn => { const ret_and_effectful = node.data_3; @@ -948,26 +947,26 @@ pub fn getTypeAnno(store: *const NodeStore, typeAnno: CIR.TypeAnno.Idx) CIR.Type .args = .{ .span = .{ .start = node.data_1, .len = node.data_2 } }, .ret = ret, .effectful = effectful, - .region = node.region, + .region = store.getRegionAt(node_idx), } }; }, .ty_parens => return CIR.TypeAnno{ .parens = .{ .anno = @enumFromInt(node.data_1), - .region = node.region, + .region = store.getRegionAt(node_idx), } }, .ty_lookup_external => return CIR.TypeAnno{ .ty_lookup_external = .{ .external_decl = @enumFromInt(node.data_1), - .region = node.region, + .region = store.getRegionAt(node_idx), }, }, .ty_malformed => return CIR.TypeAnno{ .malformed = .{ .diagnostic = @enumFromInt(node.data_1), - .region = node.region, + .region = store.getRegionAt(node_idx), } }, .malformed => return CIR.TypeAnno{ .malformed = .{ .diagnostic = @enumFromInt(node.data_1), - .region = node.region, + .region = store.getRegionAt(node_idx), } }, else => { std.debug.panic("Invalid node tag for TypeAnno: {}", .{node.tag}); @@ -985,17 +984,18 @@ pub fn getTypeHeader(store: *const NodeStore, typeHeader: CIR.TypeHeader.Idx) CI return CIR.TypeHeader{ .name = @bitCast(node.data_1), .args = .{ .span = .{ .start = node.data_2, .len = node.data_3 } }, - .region = node.region, + .region = store.getRegionAt(node_idx), }; } /// Retrieves an annotation record field from the store. pub fn getAnnoRecordField(store: *const NodeStore, annoRecordField: CIR.TypeAnno.RecordField.Idx) CIR.TypeAnno.RecordField { - const node = store.nodes.get(@enumFromInt(@intFromEnum(annoRecordField))); + const node_idx: Node.Idx = @enumFromInt(@intFromEnum(annoRecordField)); + const node = store.nodes.get(node_idx); return .{ .name = @bitCast(node.data_1), .ty = @enumFromInt(node.data_2), - .region = node.region, + .region = store.getRegionAt(node_idx), }; } @@ -1009,7 +1009,7 @@ pub fn getAnnotation(store: *const NodeStore, annotation: CIR.Annotation.Idx) CI return CIR.Annotation{ .type_anno = @enumFromInt(node.data_2), .signature = @enumFromInt(node.data_1), - .region = node.region, + .region = store.getRegionAt(node_idx), }; } @@ -1036,59 +1036,59 @@ pub fn addStatement(store: *NodeStore, statement: CIR.Statement) CIR.Statement.I .data_1 = 0, .data_2 = 0, .data_3 = 0, - .region = base.Region.zero(), .tag = @enumFromInt(0), }; + var region = base.Region.zero(); switch (statement) { .s_decl => |s| { node.tag = .statement_decl; - node.region = s.region; + region = s.region; node.data_1 = @intFromEnum(s.expr); node.data_2 = @intFromEnum(s.pattern); }, .s_var => |s| { node.tag = .statement_var; - node.region = s.region; + region = s.region; node.data_1 = @intFromEnum(s.expr); node.data_2 = @intFromEnum(s.pattern_idx); }, .s_reassign => |s| { node.tag = .statement_reassign; - node.region = s.region; + region = s.region; node.data_1 = @intFromEnum(s.expr); node.data_2 = @intFromEnum(s.pattern_idx); }, .s_crash => |s| { node.tag = .statement_crash; - node.region = s.region; + region = s.region; node.data_1 = @intFromEnum(s.msg); }, .s_expr => |s| { node.tag = .statement_expr; node.data_1 = @intFromEnum(s.expr); - node.region = s.region; + region = s.region; }, .s_expect => |s| { node.tag = .statement_expect; - node.region = s.region; + region = s.region; node.data_1 = @intFromEnum(s.body); }, .s_for => |s| { node.tag = .statement_for; - node.region = s.region; + region = s.region; node.data_1 = @intFromEnum(s.body); node.data_2 = @intFromEnum(s.expr); node.data_3 = @intFromEnum(s.patt); }, .s_return => |s| { node.tag = .statement_return; - node.region = s.region; + region = s.region; node.data_1 = @intFromEnum(s.expr); }, .s_import => |s| { node.tag = .statement_import; - node.region = s.region; + region = s.region; node.data_1 = @bitCast(s.module_name_tok); // Store optional fields in extra_data @@ -1120,7 +1120,7 @@ pub fn addStatement(store: *NodeStore, statement: CIR.Statement) CIR.Statement.I }, .s_alias_decl => |s| { node.tag = .statement_alias_decl; - node.region = s.region; + region = s.region; // Store type_decl data in extra_data const extra_start = @as(u32, @intCast(store.extra_data.items.len)); @@ -1141,7 +1141,7 @@ pub fn addStatement(store: *NodeStore, statement: CIR.Statement) CIR.Statement.I }, .s_nominal_decl => |s| { node.tag = .statement_nominal_decl; - node.region = s.region; + region = s.region; // Store type_decl data in extra_data const extra_start = @as(u32, @intCast(store.extra_data.items.len)); @@ -1162,7 +1162,7 @@ pub fn addStatement(store: *NodeStore, statement: CIR.Statement) CIR.Statement.I }, .s_type_anno => |s| { node.tag = .statement_type_anno; - node.region = s.region; + region = s.region; // Store type_anno data in extra_data const extra_start = @as(u32, @intCast(store.extra_data.items.len)); @@ -1188,7 +1188,9 @@ pub fn addStatement(store: *NodeStore, statement: CIR.Statement) CIR.Statement.I }, } - return @enumFromInt(@intFromEnum(store.nodes.append(store.gpa, node))); + const node_idx = store.nodes.append(store.gpa, node); + _ = store.regions.append(store.gpa, region); + return @enumFromInt(@intFromEnum(node_idx)); } /// Adds an expression node to the store. @@ -1197,25 +1199,25 @@ pub fn addExpr(store: *NodeStore, expr: CIR.Expr) CIR.Expr.Idx { .data_1 = 0, .data_2 = 0, .data_3 = 0, - .region = base.Region.zero(), .tag = @enumFromInt(0), }; + var region = base.Region.zero(); switch (expr) { .e_lookup_local => |local| { - node.region = local.region; + region = local.region; node.tag = .expr_var; node.data_1 = @intFromEnum(local.pattern_idx); }, .e_lookup_external => |external_idx| { // For external lookups, store the external decl index // Use external lookup tag to distinguish from local lookups - node.region = base.Region.zero(); + region = base.Region.zero(); node.tag = .expr_external_lookup; node.data_1 = @intFromEnum(external_idx); }, .e_int => |e| { - node.region = e.region; + region = e.region; node.tag = .expr_int; // Store i128 value in extra_data @@ -1233,24 +1235,24 @@ pub fn addExpr(store: *NodeStore, expr: CIR.Expr) CIR.Expr.Idx { node.data_1 = @intCast(extra_data_start); }, .e_list => |e| { - node.region = e.region; + region = e.region; node.tag = .expr_list; node.data_1 = e.elems.span.start; node.data_2 = e.elems.span.len; node.data_3 = @intFromEnum(e.elem_var); }, .e_empty_list => |e| { - node.region = e.region; + region = e.region; node.tag = .expr_empty_list; }, .e_tuple => |e| { - node.region = e.region; + region = e.region; node.tag = .expr_tuple; node.data_1 = e.elems.span.start; node.data_2 = e.elems.span.len; }, .e_frac_f64 => |e| { - node.region = e.region; + region = e.region; node.tag = .expr_frac_f64; // Store the f64 value in extra_data @@ -1265,7 +1267,7 @@ pub fn addExpr(store: *NodeStore, expr: CIR.Expr) CIR.Expr.Idx { node.data_1 = @intCast(extra_data_start); }, .e_frac_dec => |e| { - node.region = e.region; + region = e.region; node.tag = .expr_frac_dec; // Store the RocDec value in extra_data @@ -1280,7 +1282,7 @@ pub fn addExpr(store: *NodeStore, expr: CIR.Expr) CIR.Expr.Idx { node.data_1 = @intCast(extra_data_start); }, .e_dec_small => |e| { - node.region = e.region; + region = e.region; node.tag = .expr_dec_small; // Pack small dec data into data_1 and data_3 @@ -1290,18 +1292,18 @@ pub fn addExpr(store: *NodeStore, expr: CIR.Expr) CIR.Expr.Idx { node.data_3 = @as(u32, e.denominator_power_of_ten); }, .e_str_segment => |e| { - node.region = e.region; + region = e.region; node.tag = .expr_string_segment; node.data_1 = @intFromEnum(e.literal); }, .e_str => |e| { - node.region = e.region; + region = e.region; node.tag = .expr_string; node.data_1 = e.span.span.start; node.data_2 = e.span.span.len; }, .e_tag => |e| { - node.region = e.region; + region = e.region; node.tag = .expr_tag; // Store tag data in extra_data @@ -1313,7 +1315,7 @@ pub fn addExpr(store: *NodeStore, expr: CIR.Expr) CIR.Expr.Idx { node.data_1 = extra_data_start; }, .e_dot_access => |e| { - node.region = e.region; + region = e.region; node.tag = .expr_dot_access; node.data_1 = @intFromEnum(e.receiver); node.data_2 = @bitCast(e.field_name); @@ -1327,12 +1329,12 @@ pub fn addExpr(store: *NodeStore, expr: CIR.Expr) CIR.Expr.Idx { } }, .e_runtime_error => |e| { - node.region = e.region; + region = e.region; node.data_1 = @intFromEnum(e.diagnostic); node.tag = .malformed; }, .e_match => |e| { - node.region = e.region; + region = e.region; node.tag = .expr_match; // Store when data in extra_data @@ -1354,7 +1356,7 @@ pub fn addExpr(store: *NodeStore, expr: CIR.Expr) CIR.Expr.Idx { store.extra_data.append(store.gpa, e.branches.span.len) catch |err| exitOnOom(err); store.extra_data.append(store.gpa, @intFromEnum(e.final_else)) catch |err| exitOnOom(err); - node.region = e.region; + region = e.region; node.tag = .expr_if_then_else; node.data_1 = extra_start; node.data_2 = extra_start + num_extra_items; @@ -1362,7 +1364,7 @@ pub fn addExpr(store: *NodeStore, expr: CIR.Expr) CIR.Expr.Idx { std.debug.assert(node.data_2 == store.extra_data.items.len); }, .e_call => |e| { - node.region = e.region; + region = e.region; node.tag = .expr_call; // Store call data in extra_data @@ -1377,7 +1379,7 @@ pub fn addExpr(store: *NodeStore, expr: CIR.Expr) CIR.Expr.Idx { node.data_2 = @intFromEnum(e.called_via); }, .e_record => |e| { - node.region = e.region; + region = e.region; node.tag = .expr_record; const extra_data_start = @as(u32, @intCast(store.extra_data.items.len)); @@ -1394,11 +1396,11 @@ pub fn addExpr(store: *NodeStore, expr: CIR.Expr) CIR.Expr.Idx { node.data_2 = 0; // Unused }, .e_empty_record => |e| { - node.region = e.region; + region = e.region; node.tag = .expr_empty_record; }, .e_zero_argument_tag => |e| { - node.region = e.region; + region = e.region; node.tag = .expr_zero_argument_tag; // Store zero argument tag data in extra_data @@ -1410,7 +1412,7 @@ pub fn addExpr(store: *NodeStore, expr: CIR.Expr) CIR.Expr.Idx { node.data_1 = extra_data_start; }, .e_lambda => |e| { - node.region = e.region; + region = e.region; node.tag = .expr_lambda; // Store lambda data in extra_data @@ -1426,14 +1428,14 @@ pub fn addExpr(store: *NodeStore, expr: CIR.Expr) CIR.Expr.Idx { node.data_1 = extra_data_start; }, .e_binop => |e| { - node.region = e.region; + region = e.region; node.tag = .expr_bin_op; node.data_1 = @intFromEnum(e.op); node.data_2 = @intFromEnum(e.lhs); node.data_3 = @intFromEnum(e.rhs); }, .e_block => |e| { - node.region = e.region; + region = e.region; node.tag = .expr_block; node.data_1 = e.stmts.span.start; node.data_2 = e.stmts.span.len; @@ -1441,7 +1443,9 @@ pub fn addExpr(store: *NodeStore, expr: CIR.Expr) CIR.Expr.Idx { }, } - return @enumFromInt(@intFromEnum(store.nodes.append(store.gpa, node))); + const node_idx = store.nodes.append(store.gpa, node); + _ = store.regions.append(store.gpa, region); + return @enumFromInt(@intFromEnum(node_idx)); } /// Adds a record field to the store. @@ -1450,21 +1454,20 @@ pub fn addRecordField(store: *NodeStore, recordField: CIR.RecordField) CIR.Recor .data_1 = @bitCast(recordField.name), .data_2 = @intFromEnum(recordField.value), .data_3 = 0, - .region = base.Region.zero(), .tag = .record_field, }; const nid = store.nodes.append(store.gpa, node); + _ = store.regions.append(store.gpa, base.Region.zero()); return @enumFromInt(@intFromEnum(nid)); } /// Adds a record destructuring to the store. -pub fn addRecordDestruct(store: *NodeStore, record_destruct: CIR.Pattern.RecordDestruct) CIR.Pattern.RecordDestruct.Idx { +pub fn addRecordDestruct(store: *NodeStore, record_destruct: CIR.Pattern.RecordDestruct, region: base.Region) CIR.Pattern.RecordDestruct.Idx { var node = Node{ .data_1 = @bitCast(record_destruct.label), .data_2 = @bitCast(record_destruct.ident), .data_3 = 0, - .region = record_destruct.region, .tag = .record_destruct, }; @@ -1485,7 +1488,9 @@ pub fn addRecordDestruct(store: *NodeStore, record_destruct: CIR.Pattern.RecordD }, } - return @enumFromInt(@intFromEnum(store.nodes.append(store.gpa, node))); + const nid = store.nodes.append(store.gpa, node); + _ = store.regions.append(store.gpa, region); + return @enumFromInt(@intFromEnum(nid)); } /// Adds a 'match' branch to the store. @@ -1494,7 +1499,6 @@ pub fn addMatchBranch(store: *NodeStore, branch: CIR.Expr.Match.Branch) CIR.Expr .data_1 = 0, .data_2 = 0, .data_3 = 0, - .region = branch.region, .tag = .match_branch, }; @@ -1508,7 +1512,9 @@ pub fn addMatchBranch(store: *NodeStore, branch: CIR.Expr.Match.Branch) CIR.Expr store.extra_data.append(store.gpa, @intFromEnum(branch.redundant)) catch |err| exitOnOom(err); node.data_1 = extra_data_start; - return @enumFromInt(@intFromEnum(store.nodes.append(store.gpa, node))); + const nid = store.nodes.append(store.gpa, node); + _ = store.regions.append(store.gpa, branch.region); + return @enumFromInt(@intFromEnum(nid)); } /// Adds a 'match' branch to the store. @@ -1517,10 +1523,11 @@ pub fn addMatchBranchPattern(store: *NodeStore, branchPattern: CIR.Expr.Match.Br .data_1 = @intFromEnum(branchPattern.pattern), .data_2 = @as(u32, @intFromBool(branchPattern.degenerate)), .data_3 = 0, - .region = branchPattern.region, .tag = .match_branch_pattern, }; - return @enumFromInt(@intFromEnum(store.nodes.append(store.gpa, node))); + const nid = store.nodes.append(store.gpa, node); + _ = store.regions.append(store.gpa, branchPattern.region); + return @enumFromInt(@intFromEnum(nid)); } /// Adds a 'where' clause to the store. @@ -1529,7 +1536,6 @@ pub fn addWhereClause(store: *NodeStore, whereClause: CIR.WhereClause) CIR.Where .data_1 = 0, .data_2 = 0, .data_3 = 0, - .region = base.Region.empty(), .tag = .where_clause, }; @@ -1572,16 +1578,17 @@ pub fn addWhereClause(store: *NodeStore, whereClause: CIR.WhereClause) CIR.Where node.data_1 = extra_data_start; - return @enumFromInt(@intFromEnum(store.nodes.append(store.gpa, node))); + const nid = store.nodes.append(store.gpa, node); + _ = store.regions.append(store.gpa, base.Region.empty()); + return @enumFromInt(@intFromEnum(nid)); } /// Adds a pattern to the store. -pub fn addPattern(store: *NodeStore, pattern: CIR.Pattern) std.mem.Allocator.Error!CIR.Pattern.Idx { +pub fn addPattern(store: *NodeStore, pattern: CIR.Pattern, region: base.Region) std.mem.Allocator.Error!CIR.Pattern.Idx { var node = Node{ .data_1 = 0, .data_2 = 0, .data_3 = 0, - .region = base.Region.zero(), .tag = @enumFromInt(0), }; @@ -1589,17 +1596,14 @@ pub fn addPattern(store: *NodeStore, pattern: CIR.Pattern) std.mem.Allocator.Err .assign => |p| { node.data_1 = @bitCast(p.ident); node.tag = .pattern_identifier; - node.region = p.region; }, .as => |p| { node.tag = .pattern_as; - node.region = p.region; node.data_1 = @bitCast(p.ident); node.data_2 = @intFromEnum(p.pattern); }, .applied_tag => |p| { node.tag = .pattern_applied_tag; - node.region = p.region; // Store applied tag data in extra_data const extra_data_start = @as(u32, @intCast(store.extra_data.items.len)); @@ -1611,7 +1615,6 @@ pub fn addPattern(store: *NodeStore, pattern: CIR.Pattern) std.mem.Allocator.Err }, .record_destructure => |p| { node.tag = .pattern_record_destructure; - node.region = p.region; // Store record destructure data in extra_data const extra_data_start = @as(u32, @intCast(store.extra_data.items.len)); @@ -1623,7 +1626,6 @@ pub fn addPattern(store: *NodeStore, pattern: CIR.Pattern) std.mem.Allocator.Err }, .list => |p| { node.tag = .pattern_list; - node.region = p.region; // Store list pattern data in extra_data const extra_data_start = @as(u32, @intCast(store.extra_data.items.len)); @@ -1650,13 +1652,11 @@ pub fn addPattern(store: *NodeStore, pattern: CIR.Pattern) std.mem.Allocator.Err }, .tuple => |p| { node.tag = .pattern_tuple; - node.region = p.region; node.data_1 = p.patterns.span.start; node.data_2 = p.patterns.span.len; }, .int_literal => |p| { node.tag = .pattern_int_literal; - node.region = p.region; // Store the value in extra_data const extra_data_start = store.extra_data.items.len; const value_as_u32s: [4]u32 = @bitCast(p.value.bytes); @@ -1667,7 +1667,6 @@ pub fn addPattern(store: *NodeStore, pattern: CIR.Pattern) std.mem.Allocator.Err }, .small_dec_literal => |p| { node.tag = .pattern_small_dec_literal; - node.region = p.region; // Pack small dec data into data_1 and data_3 // data_1: numerator (i16) - fits in lower 16 bits // data_3: denominator_power_of_ten (u8) in lower 8 bits @@ -1676,7 +1675,6 @@ pub fn addPattern(store: *NodeStore, pattern: CIR.Pattern) std.mem.Allocator.Err }, .dec_literal => |p| { node.tag = .pattern_dec_literal; - node.region = p.region; // Store the RocDec value in extra_data const extra_data_start = store.extra_data.items.len; const value_as_u32s: [4]u32 = @bitCast(p.value.num); @@ -1687,12 +1685,10 @@ pub fn addPattern(store: *NodeStore, pattern: CIR.Pattern) std.mem.Allocator.Err }, .str_literal => |p| { node.tag = .pattern_str_literal; - node.region = p.region; node.data_1 = @intFromEnum(p.literal); }, .char_literal => |p| { node.tag = .pattern_char_literal; - node.region = p.region; // Store char literal data in extra_data const extra_data_start = @as(u32, @intCast(store.extra_data.items.len)); @@ -1702,18 +1698,18 @@ pub fn addPattern(store: *NodeStore, pattern: CIR.Pattern) std.mem.Allocator.Err try store.extra_data.append(store.gpa, @intFromEnum(p.requirements.bits_needed)); node.data_1 = extra_data_start; }, - .underscore => |p| { + .underscore => { node.tag = .pattern_underscore; - node.region = p.region; }, .runtime_error => |e| { node.tag = .malformed; - node.region = e.region; node.data_1 = @intFromEnum(e.diagnostic); }, } - return @enumFromInt(@intFromEnum(store.nodes.append(store.gpa, node))); + const node_idx = store.nodes.append(store.gpa, node); + _ = store.regions.append(store.gpa, region); + return @enumFromInt(@intFromEnum(node_idx)); } /// Adds a pattern record field to the store. @@ -1730,76 +1726,77 @@ pub fn addTypeAnno(store: *NodeStore, typeAnno: CIR.TypeAnno) CIR.TypeAnno.Idx { .data_1 = 0, .data_2 = 0, .data_3 = 0, - .region = base.Region.zero(), .tag = @enumFromInt(0), }; + var region = base.Region.zero(); switch (typeAnno) { .apply => |a| { - node.region = a.region; + region = a.region; node.data_1 = @bitCast(a.symbol); node.data_2 = a.args.span.start; node.data_3 = a.args.span.len; node.tag = .ty_apply; }, .ty_var => |tv| { - node.region = tv.region; + region = tv.region; node.data_1 = @bitCast(tv.name); node.tag = .ty_var; }, .underscore => |u| { - node.region = u.region; + region = u.region; node.tag = .ty_underscore; }, .ty => |t| { - node.region = t.region; + region = t.region; node.data_1 = @bitCast(t.symbol); node.tag = .ty_ident; }, .tag_union => |tu| { - node.region = tu.region; + region = tu.region; node.data_1 = tu.tags.span.start; node.data_2 = tu.tags.span.len; node.data_3 = if (tu.open_anno) |open| @intFromEnum(open) else 0; node.tag = .ty_tag_union; }, .tuple => |t| { - node.region = t.region; + region = t.region; node.data_1 = t.annos.span.start; node.data_2 = t.annos.span.len; node.tag = .ty_tuple; }, .record => |r| { - node.region = r.region; + region = r.region; node.data_1 = r.fields.span.start; node.data_2 = r.fields.span.len; node.tag = .ty_record; }, .@"fn" => |f| { - node.region = f.region; + region = f.region; node.data_1 = f.args.span.start; node.data_2 = f.args.span.len; node.data_3 = @intFromEnum(f.ret) | (if (f.effectful) @as(u32, 1) << 31 else 0); node.tag = .ty_fn; }, .parens => |p| { - node.region = p.region; + region = p.region; node.data_1 = @intFromEnum(p.anno); node.tag = .ty_parens; }, .ty_lookup_external => |tle| { - node.region = tle.region; + region = tle.region; node.data_1 = @intFromEnum(tle.external_decl); node.tag = .ty_lookup_external; }, .malformed => |m| { - node.region = m.region; + region = m.region; node.data_1 = @intFromEnum(m.diagnostic); node.tag = .ty_malformed; }, } const nid = store.nodes.append(store.gpa, node); + _ = store.regions.append(store.gpa, region); return @enumFromInt(@intFromEnum(nid)); } @@ -1809,11 +1806,11 @@ pub fn addTypeHeader(store: *NodeStore, typeHeader: CIR.TypeHeader) CIR.TypeHead .data_1 = @bitCast(typeHeader.name), .data_2 = typeHeader.args.span.start, .data_3 = typeHeader.args.span.len, - .region = typeHeader.region, .tag = .type_header, }; const nid = store.nodes.append(store.gpa, node); + _ = store.regions.append(store.gpa, typeHeader.region); return @enumFromInt(@intFromEnum(nid)); } @@ -1823,11 +1820,11 @@ pub fn addAnnoRecordField(store: *NodeStore, annoRecordField: CIR.TypeAnno.Recor .data_1 = @bitCast(annoRecordField.name), .data_2 = @intFromEnum(annoRecordField.ty), .data_3 = 0, - .region = annoRecordField.region, .tag = .ty_record_field, }; const nid = store.nodes.append(store.gpa, node); + _ = store.regions.append(store.gpa, annoRecordField.region); return @enumFromInt(@intFromEnum(nid)); } @@ -1837,11 +1834,11 @@ pub fn addAnnotation(store: *NodeStore, annotation: CIR.Annotation) CIR.Annotati .data_1 = @intFromEnum(annotation.signature), .data_2 = @intFromEnum(annotation.type_anno), .data_3 = 0, - .region = annotation.region, .tag = .annotation, }; const nid = store.nodes.append(store.gpa, node); + _ = store.regions.append(store.gpa, annotation.region); return @enumFromInt(@intFromEnum(nid)); } @@ -1851,11 +1848,11 @@ pub fn addExposedItem(store: *NodeStore, exposedItem: CIR.ExposedItem) CIR.Expos .data_1 = @bitCast(exposedItem.name), .data_2 = if (exposedItem.alias) |alias| @bitCast(alias) else 0, .data_3 = @intFromBool(exposedItem.is_wildcard), - .region = base.Region.zero(), .tag = .exposed_item, }; const nid = store.nodes.append(store.gpa, node); + _ = store.regions.append(store.gpa, base.Region.zero()); return @enumFromInt(@intFromEnum(nid)); } @@ -1865,7 +1862,6 @@ pub fn addDef(store: *NodeStore, def: CIR.Def) CIR.Def.Idx { .data_1 = 0, .data_2 = 0, .data_3 = 0, - .region = def.pattern_region, // Use pattern region as the def's region .tag = .def, }; @@ -1891,7 +1887,9 @@ pub fn addDef(store: *NodeStore, def: CIR.Def) CIR.Def.Idx { node.data_1 = extra_start; node.data_2 = 7; // Number of extra data items - return @enumFromInt(@intFromEnum(store.nodes.append(store.gpa, node))); + const nid = store.nodes.append(store.gpa, node); + _ = store.regions.append(store.gpa, def.pattern_region); // Use pattern region as the def's region + return @enumFromInt(@intFromEnum(nid)); } /// Retrieves a definition from the store. @@ -1916,7 +1914,7 @@ pub fn getDef(store: *const NodeStore, def_idx: CIR.Def.Idx) CIR.Def { return CIR.Def{ .pattern = pattern, - .pattern_region = node.region, // Stored as node region + .pattern_region = store.getRegionAt(nid), // Get region from regions array .expr = expr, .expr_region = base.Region{ .start = .{ .offset = expr_region_start }, @@ -1938,7 +1936,8 @@ pub fn getRecordField(store: *const NodeStore, idx: CIR.RecordField.Idx) CIR.Rec /// Retrieves a record destructure from the store. pub fn getRecordDestruct(store: *const NodeStore, idx: CIR.Pattern.RecordDestruct.Idx) CIR.Pattern.RecordDestruct { - const node = store.nodes.get(@enumFromInt(@intFromEnum(idx))); + const node_idx: Node.Idx = @enumFromInt(@intFromEnum(idx)); + const node = store.nodes.get(node_idx); // Retrieve kind from extra_data if it exists const kind = if (node.data_3 != 0) blk: { @@ -1949,14 +1948,13 @@ pub fn getRecordDestruct(store: *const NodeStore, idx: CIR.Pattern.RecordDestruc break :blk switch (kind_tag) { 0 => CIR.Pattern.RecordDestruct.Kind.Required, 1 => CIR.Pattern.RecordDestruct.Kind{ .Guard = @enumFromInt(extra_data[1]) }, - else => CIR.Pattern.RecordDestruct.Kind.Required, + else => unreachable, }; } else CIR.Pattern.RecordDestruct.Kind.Required; return CIR.Pattern.RecordDestruct{ .label = @bitCast(node.data_1), .ident = @bitCast(node.data_2), - .region = node.region, .kind = kind, }; } @@ -1971,7 +1969,7 @@ pub fn getIfBranch(store: *const NodeStore, if_branch_idx: CIR.Expr.IfBranch.Idx return CIR.Expr.IfBranch{ .cond = @enumFromInt(node.data_1), .body = @enumFromInt(node.data_2), - .region = node.region, + .region = store.getRegionAt(nid), }; } @@ -2248,10 +2246,10 @@ pub fn addIfBranch(store: *NodeStore, if_branch: CIR.Expr.IfBranch) CIR.Expr.IfB .data_1 = @intFromEnum(if_branch.cond), .data_2 = @intFromEnum(if_branch.body), .data_3 = 0, - .region = if_branch.region, .tag = .if_branch, }; const node_idx = store.nodes.append(store.gpa, node); + _ = store.regions.append(store.gpa, if_branch.region); return @enumFromInt(@intFromEnum(node_idx)); } @@ -2299,44 +2297,44 @@ pub fn addDiagnostic(store: *NodeStore, reason: CIR.Diagnostic) CIR.Diagnostic.I .data_1 = 0, .data_2 = 0, .data_3 = 0, - .region = base.Region.zero(), .tag = @enumFromInt(0), }; + var region = base.Region.zero(); switch (reason) { .not_implemented => |r| { node.tag = .diag_not_implemented; - node.region = r.region; + region = r.region; node.data_1 = @intFromEnum(r.feature); }, .invalid_num_literal => |r| { node.tag = .diag_invalid_num_literal; - node.region = r.region; + region = r.region; }, .invalid_single_quote => |r| { node.tag = .diag_invalid_single_quote; - node.region = r.region; + region = r.region; }, .too_long_single_quote => |r| { node.tag = .diag_too_long_single_quote; - node.region = r.region; + region = r.region; }, .empty_single_quote => |r| { node.tag = .diag_empty_single_quote; - node.region = r.region; + region = r.region; }, .empty_tuple => |r| { node.tag = .diag_empty_tuple; - node.region = r.region; + region = r.region; }, .ident_already_in_scope => |r| { node.tag = .diag_ident_already_in_scope; - node.region = r.region; + region = r.region; node.data_1 = @bitCast(r.ident); }, .ident_not_in_scope => |r| { node.tag = .diag_ident_not_in_scope; - node.region = r.region; + region = r.region; node.data_1 = @bitCast(r.ident); }, .invalid_top_level_statement => |r| { @@ -2345,128 +2343,129 @@ pub fn addDiagnostic(store: *NodeStore, reason: CIR.Diagnostic) CIR.Diagnostic.I }, .expr_not_canonicalized => |r| { node.tag = .diag_expr_not_canonicalized; - node.region = r.region; + region = r.region; }, .invalid_string_interpolation => |r| { node.tag = .diag_invalid_string_interpolation; - node.region = r.region; + region = r.region; }, .pattern_arg_invalid => |r| { node.tag = .diag_pattern_arg_invalid; - node.region = r.region; + region = r.region; }, .pattern_not_canonicalized => |r| { node.tag = .diag_pattern_not_canonicalized; - node.region = r.region; + region = r.region; }, .can_lambda_not_implemented => |r| { node.tag = .diag_can_lambda_not_implemented; - node.region = r.region; + region = r.region; }, .lambda_body_not_canonicalized => |r| { node.tag = .diag_lambda_body_not_canonicalized; - node.region = r.region; + region = r.region; }, .if_condition_not_canonicalized => |r| { node.tag = .diag_if_condition_not_canonicalized; - node.region = r.region; + region = r.region; }, .if_then_not_canonicalized => |r| { node.tag = .diag_if_then_not_canonicalized; - node.region = r.region; + region = r.region; }, .if_else_not_canonicalized => |r| { node.tag = .diag_if_else_not_canonicalized; - node.region = r.region; + region = r.region; }, .malformed_type_annotation => |r| { node.tag = .diag_malformed_type_annotation; - node.region = r.region; + region = r.region; }, .var_across_function_boundary => |r| { node.tag = .diag_var_across_function_boundary; - node.region = r.region; + region = r.region; }, .shadowing_warning => |r| { node.tag = .diag_shadowing_warning; - node.region = r.region; + region = r.region; node.data_1 = @bitCast(r.ident); node.data_2 = r.original_region.start.offset; node.data_3 = r.original_region.end.offset; }, .type_redeclared => |r| { node.tag = .diag_type_redeclared; - node.region = r.redeclared_region; + region = r.redeclared_region; node.data_1 = @bitCast(r.name); node.data_2 = r.original_region.start.offset; node.data_3 = r.original_region.end.offset; }, .undeclared_type => |r| { node.tag = .diag_undeclared_type; - node.region = r.region; + region = r.region; node.data_1 = @bitCast(r.name); }, .undeclared_type_var => |r| { node.tag = .diag_undeclared_type_var; - node.region = r.region; + region = r.region; node.data_1 = @bitCast(r.name); }, .type_alias_redeclared => |r| { node.tag = .diag_type_alias_redeclared; - node.region = r.redeclared_region; + region = r.redeclared_region; node.data_1 = @bitCast(r.name); node.data_2 = r.original_region.start.offset; node.data_3 = r.original_region.end.offset; }, .tuple_elem_not_canonicalized => |r| { node.tag = .diag_tuple_elem_not_canonicalized; - node.region = r.region; + region = r.region; }, .nominal_type_redeclared => |r| { node.tag = .diag_nominal_type_redeclared; - node.region = r.redeclared_region; + region = r.redeclared_region; node.data_1 = @bitCast(r.name); node.data_2 = r.original_region.start.offset; node.data_3 = r.original_region.end.offset; }, .type_shadowed_warning => |r| { node.tag = .diag_type_shadowed_warning; - node.region = r.region; + region = r.region; node.data_1 = @bitCast(r.name); node.data_2 = r.original_region.start.offset; node.data_3 = r.original_region.end.offset | (@as(u32, @intFromBool(r.cross_scope)) << 31); }, .type_parameter_conflict => |r| { node.tag = .diag_type_parameter_conflict; - node.region = r.region; + region = r.region; node.data_1 = @bitCast(r.name); node.data_2 = @bitCast(r.parameter_name); node.data_3 = r.original_region.start.offset; }, .unused_variable => |r| { node.tag = .diag_unused_variable; - node.region = r.region; + region = r.region; node.data_1 = @bitCast(r.ident); }, .used_underscore_variable => |r| { node.tag = .diag_used_underscore_variable; - node.region = r.region; + region = r.region; node.data_1 = @bitCast(r.ident); }, .duplicate_record_field => |r| { node.tag = .diag_duplicate_record_field; - node.region = r.duplicate_region; + region = r.duplicate_region; node.data_1 = @bitCast(r.field_name); node.data_2 = r.original_region.start.offset; node.data_3 = r.original_region.end.offset; }, .f64_pattern_literal => |r| { node.tag = .diag_f64_pattern_literal; - node.region = r.region; + region = r.region; }, } const nid = @intFromEnum(store.nodes.append(store.gpa, node)); + _ = store.regions.append(store.gpa, region); // append to our scratch so we can get a span later of all our diagnostics store.addScratch("scratch_diagnostics", @as(CIR.Diagnostic.Idx, @enumFromInt(nid))); @@ -2496,12 +2495,11 @@ pub fn addMalformed(store: *NodeStore, comptime t: type, reason: CIR.Diagnostic) .data_1 = @intFromEnum(diagnostic_idx), .data_2 = 0, .data_3 = 0, - - .region = reason.toRegion(), .tag = .malformed, }; const malformed_nid = @intFromEnum(store.nodes.append(store.gpa, malformed_node)); + _ = store.regions.append(store.gpa, reason.toRegion()); return @enumFromInt(malformed_nid); } @@ -2516,67 +2514,67 @@ pub fn getDiagnostic(store: *const NodeStore, diagnostic: CIR.Diagnostic.Idx) CI switch (node.tag) { .diag_not_implemented => return CIR.Diagnostic{ .not_implemented = .{ .feature = @enumFromInt(node.data_1), - .region = node.region, + .region = store.getRegionAt(node_idx), } }, .diag_invalid_num_literal => return CIR.Diagnostic{ .invalid_num_literal = .{ - .region = node.region, + .region = store.getRegionAt(node_idx), } }, .diag_invalid_single_quote => return CIR.Diagnostic{ .invalid_single_quote = .{ - .region = node.region, + .region = store.getRegionAt(node_idx), } }, .diag_too_long_single_quote => return CIR.Diagnostic{ .too_long_single_quote = .{ - .region = node.region, + .region = store.getRegionAt(node_idx), } }, .diag_empty_single_quote => return CIR.Diagnostic{ .empty_single_quote = .{ - .region = node.region, + .region = store.getRegionAt(node_idx), } }, .diag_empty_tuple => return CIR.Diagnostic{ .empty_tuple = .{ - .region = node.region, + .region = store.getRegionAt(node_idx), } }, .diag_ident_already_in_scope => return CIR.Diagnostic{ .ident_already_in_scope = .{ .ident = @bitCast(node.data_1), - .region = node.region, + .region = store.getRegionAt(node_idx), } }, .diag_ident_not_in_scope => return CIR.Diagnostic{ .ident_not_in_scope = .{ .ident = @bitCast(node.data_1), - .region = node.region, + .region = store.getRegionAt(node_idx), } }, .diag_invalid_top_level_statement => return CIR.Diagnostic{ .invalid_top_level_statement = .{ .stmt = @enumFromInt(node.data_1), } }, .diag_expr_not_canonicalized => return CIR.Diagnostic{ .expr_not_canonicalized = .{ - .region = node.region, + .region = store.getRegionAt(node_idx), } }, .diag_invalid_string_interpolation => return CIR.Diagnostic{ .invalid_string_interpolation = .{ - .region = node.region, + .region = store.getRegionAt(node_idx), } }, .diag_pattern_arg_invalid => return CIR.Diagnostic{ .pattern_arg_invalid = .{ - .region = node.region, + .region = store.getRegionAt(node_idx), } }, .diag_pattern_not_canonicalized => return CIR.Diagnostic{ .pattern_not_canonicalized = .{ - .region = node.region, + .region = store.getRegionAt(node_idx), } }, .diag_can_lambda_not_implemented => return CIR.Diagnostic{ .can_lambda_not_implemented = .{ - .region = node.region, + .region = store.getRegionAt(node_idx), } }, .diag_lambda_body_not_canonicalized => return CIR.Diagnostic{ .lambda_body_not_canonicalized = .{ - .region = node.region, + .region = store.getRegionAt(node_idx), } }, .diag_if_condition_not_canonicalized => return CIR.Diagnostic{ .if_condition_not_canonicalized = .{ - .region = node.region, + .region = store.getRegionAt(node_idx), } }, .diag_if_then_not_canonicalized => return CIR.Diagnostic{ .if_then_not_canonicalized = .{ - .region = node.region, + .region = store.getRegionAt(node_idx), } }, .diag_if_else_not_canonicalized => return CIR.Diagnostic{ .if_else_not_canonicalized = .{ - .region = node.region, + .region = store.getRegionAt(node_idx), } }, .diag_var_across_function_boundary => return CIR.Diagnostic{ .var_across_function_boundary = .{ - .region = node.region, + .region = store.getRegionAt(node_idx), } }, .diag_shadowing_warning => return CIR.Diagnostic{ .shadowing_warning = .{ .ident = @bitCast(node.data_1), - .region = node.region, + .region = store.getRegionAt(node_idx), .original_region = .{ .start = .{ .offset = node.data_2 }, .end = .{ .offset = node.data_3 }, @@ -2584,7 +2582,7 @@ pub fn getDiagnostic(store: *const NodeStore, diagnostic: CIR.Diagnostic.Idx) CI } }, .diag_type_redeclared => return CIR.Diagnostic{ .type_redeclared = .{ .name = @bitCast(node.data_1), - .redeclared_region = node.region, + .redeclared_region = store.getRegionAt(node_idx), .original_region = .{ .start = .{ .offset = node.data_2 }, .end = .{ .offset = node.data_3 }, @@ -2592,21 +2590,21 @@ pub fn getDiagnostic(store: *const NodeStore, diagnostic: CIR.Diagnostic.Idx) CI } }, .diag_undeclared_type => return CIR.Diagnostic{ .undeclared_type = .{ .name = @bitCast(node.data_1), - .region = node.region, + .region = store.getRegionAt(node_idx), } }, .diag_tuple_elem_not_canonicalized => return CIR.Diagnostic{ .tuple_elem_not_canonicalized = .{ - .region = node.region, + .region = store.getRegionAt(node_idx), } }, .diag_undeclared_type_var => return CIR.Diagnostic{ .undeclared_type_var = .{ .name = @bitCast(node.data_1), - .region = node.region, + .region = store.getRegionAt(node_idx), } }, .diag_malformed_type_annotation => return CIR.Diagnostic{ .malformed_type_annotation = .{ - .region = node.region, + .region = store.getRegionAt(node_idx), } }, .diag_type_alias_redeclared => return CIR.Diagnostic{ .type_alias_redeclared = .{ .name = @bitCast(node.data_1), - .redeclared_region = node.region, + .redeclared_region = store.getRegionAt(node_idx), .original_region = .{ .start = .{ .offset = @intCast(node.data_2) }, .end = .{ .offset = @intCast(node.data_3) }, @@ -2614,7 +2612,7 @@ pub fn getDiagnostic(store: *const NodeStore, diagnostic: CIR.Diagnostic.Idx) CI } }, .diag_nominal_type_redeclared => return CIR.Diagnostic{ .nominal_type_redeclared = .{ .name = @bitCast(node.data_1), - .redeclared_region = node.region, + .redeclared_region = store.getRegionAt(node_idx), .original_region = .{ .start = .{ .offset = @intCast(node.data_2) }, .end = .{ .offset = @intCast(node.data_3 & 0x7FFFFFFF) }, @@ -2622,7 +2620,7 @@ pub fn getDiagnostic(store: *const NodeStore, diagnostic: CIR.Diagnostic.Idx) CI } }, .diag_type_shadowed_warning => return CIR.Diagnostic{ .type_shadowed_warning = .{ .name = @bitCast(node.data_1), - .region = node.region, + .region = store.getRegionAt(node_idx), .original_region = .{ .start = .{ .offset = @intCast(node.data_2) }, .end = .{ .offset = @intCast(node.data_3 & 0x7FFFFFFF) }, @@ -2632,7 +2630,7 @@ pub fn getDiagnostic(store: *const NodeStore, diagnostic: CIR.Diagnostic.Idx) CI .diag_type_parameter_conflict => return CIR.Diagnostic{ .type_parameter_conflict = .{ .name = @bitCast(node.data_1), .parameter_name = @bitCast(node.data_2), - .region = node.region, + .region = store.getRegionAt(node_idx), .original_region = .{ .start = .{ .offset = @intCast(node.data_3) }, .end = .{ .offset = @intCast(node.data_3) }, @@ -2640,29 +2638,30 @@ pub fn getDiagnostic(store: *const NodeStore, diagnostic: CIR.Diagnostic.Idx) CI } }, .diag_unused_variable => return CIR.Diagnostic{ .unused_variable = .{ .ident = @bitCast(node.data_1), - .region = node.region, + .region = store.getRegionAt(node_idx), } }, .diag_used_underscore_variable => return CIR.Diagnostic{ .used_underscore_variable = .{ .ident = @bitCast(node.data_1), - .region = node.region, + .region = store.getRegionAt(node_idx), } }, .diag_duplicate_record_field => return CIR.Diagnostic{ .duplicate_record_field = .{ .field_name = @bitCast(node.data_1), - .duplicate_region = node.region, + .duplicate_region = store.getRegionAt(node_idx), .original_region = .{ .start = .{ .offset = @intCast(node.data_2) }, .end = .{ .offset = @intCast(node.data_3) }, }, } }, .diag_f64_pattern_literal => return CIR.Diagnostic{ .f64_pattern_literal = .{ - .region = node.region, + .region = store.getRegionAt(node_idx), } }, else => { std.debug.print("Error: getDiagnostic called with non-diagnostic node!\n", .{}); std.debug.print(" Node tag: {}\n", .{node.tag}); std.debug.print(" Diagnostic index: {}\n", .{diagnostic}); std.debug.print(" Node index: {}\n", .{node_idx}); - std.debug.print(" Region: {}..{}\n", .{ node.region.start.offset, node.region.end.offset }); + const region = store.getRegionAt(node_idx); + std.debug.print(" Region: {}..{}\n", .{ region.start.offset, region.end.offset }); std.debug.print("\nThis indicates that a non-diagnostic node was added to the diagnostics list.\n", .{}); std.debug.print("Check that addDiagnostic is only called with CIR.Diagnostic values,\n", .{}); std.debug.print("and that no other nodes are being added to scratch_diagnostics.\n", .{}); @@ -2692,8 +2691,8 @@ pub fn addTypeVarSlot(store: *NodeStore, parent_node_idx: Node.Idx, region: base .data_1 = @intFromEnum(parent_node_idx), .data_2 = 0, .data_3 = 0, - .region = region, }); + _ = store.regions.append(store.gpa, region); return @enumFromInt(@intFromEnum(nid)); } @@ -2729,8 +2728,9 @@ pub fn matchBranchPatternSpanFrom(store: *NodeStore, start: u32) CIR.Expr.Match. /// Calculate the size needed to serialize this NodeStore pub fn serializedSize(self: *const NodeStore) usize { - // We only serialize nodes and extra_data (the scratch arrays are transient) + // We only serialize nodes, regions, and extra_data (the scratch arrays are transient) return self.nodes.serializedSize() + + self.regions.serializedSize() + @sizeOf(u32) + // extra_data length (self.extra_data.items.len * @sizeOf(u32)); } @@ -2748,6 +2748,11 @@ pub fn serializeInto(self: *const NodeStore, buffer: []align(@alignOf(Node)) u8) const nodes_slice = try self.nodes.serializeInto(nodes_buffer); offset += nodes_slice.len; + // Serialize regions + const regions_buffer = @as([]align(@alignOf(Region)) u8, @alignCast(buffer[offset..])); + const regions_slice = try self.regions.serializeInto(regions_buffer); + offset += regions_slice.len; + // Serialize extra_data length const extra_len_ptr = @as(*u32, @ptrCast(@alignCast(buffer.ptr + offset))); extra_len_ptr.* = @intCast(self.extra_data.items.len); @@ -2772,6 +2777,11 @@ pub fn deserializeFrom(buffer: []align(@alignOf(Node)) const u8, allocator: std. const nodes = try Node.List.deserializeFrom(nodes_buffer, allocator); offset += nodes.serializedSize(); + // Deserialize regions + const regions_buffer = @as([]align(@alignOf(Region)) const u8, @alignCast(buffer[offset..])); + const regions = try Region.List.deserializeFrom(regions_buffer, allocator); + offset += regions.serializedSize(); + // Deserialize extra_data length if (buffer.len < offset + @sizeOf(u32)) return error.BufferTooSmall; const extra_len = @as(*const u32, @ptrCast(@alignCast(buffer.ptr + offset))).*; @@ -2792,6 +2802,7 @@ pub fn deserializeFrom(buffer: []align(@alignOf(Node)) const u8, allocator: std. return NodeStore{ .gpa = allocator, .nodes = nodes, + .regions = regions, .extra_data = extra_data, // All scratch arrays start empty .scratch_statements = base.Scratch(CIR.Statement.Idx){ .items = .{} }, diff --git a/src/check/canonicalize/Pattern.zig b/src/check/canonicalize/Pattern.zig index a6c7d90f6c..639daaa702 100644 --- a/src/check/canonicalize/Pattern.zig +++ b/src/check/canonicalize/Pattern.zig @@ -38,7 +38,6 @@ pub const Pattern = union(enum) { /// An identifier in the assignment position, e.g. the `x` in `x = foo(1)` assign: struct { ident: Ident.Idx, - region: Region, }, /// A `as` pattern used to rename an identifier /// @@ -49,7 +48,6 @@ pub const Pattern = union(enum) { as: struct { pattern: Pattern.Idx, ident: Ident.Idx, - region: Region, }, /// Pattern that matches a tag with arguments (constructor pattern). /// Used for pattern matching tag unions with payloads. @@ -64,7 +62,6 @@ pub const Pattern = union(enum) { ext_var: TypeVar, tag_name: Ident.Idx, arguments: Pattern.Span, - region: Region, }, /// Pattern that destructures a record, extracting specific fields including nested records. /// @@ -79,7 +76,6 @@ pub const Pattern = union(enum) { whole_var: TypeVar, ext_var: TypeVar, destructs: RecordDestruct.Span, - region: Region, }, /// Pattern that destructures a list, with optional rest pattern. /// Can match specific elements and capture remaining elements. @@ -101,7 +97,6 @@ pub const Pattern = union(enum) { index: u32, // Where the rest appears (split point) pattern: ?Pattern.Idx, // None for `..`, Some(assign) for `.. as name` }, - region: Region, }, /// Pattern that destructures a tuple into its component patterns. /// Tuples have a fixed number of elements with potentially different types. @@ -114,7 +109,6 @@ pub const Pattern = union(enum) { /// ``` tuple: struct { patterns: Pattern.Span, - region: Region, }, /// Pattern that matches a specific integer literal value exactly. /// Used for exact matching in pattern expressions. @@ -128,7 +122,6 @@ pub const Pattern = union(enum) { /// ``` int_literal: struct { value: IntValue, - region: Region, }, /// Pattern that matches a small decimal literal (represented as rational number). /// This is Roc's preferred approach for exact decimal matching, avoiding @@ -144,7 +137,6 @@ pub const Pattern = union(enum) { small_dec_literal: struct { numerator: i16, denominator_power_of_ten: u8, - region: Region, }, /// Pattern that matches a high-precision decimal literal. /// Used for exact decimal matching with arbitrary precision. @@ -157,7 +149,6 @@ pub const Pattern = union(enum) { /// ``` dec_literal: struct { value: RocDec, - region: Region, }, /// Pattern that matches a specific string literal exactly. @@ -172,7 +163,6 @@ pub const Pattern = union(enum) { /// ``` str_literal: struct { literal: StringLiteral.Idx, - region: Region, }, /// Pattern that matches a specific unicode character literal exactly. /// @@ -187,7 +177,6 @@ pub const Pattern = union(enum) { num_var: TypeVar, requirements: types.Num.Int.Requirements, value: u32, - region: Region, }, /// Wildcard pattern that matches anything without binding to a variable. /// Used when you need to match a value but don't care about its contents. @@ -198,36 +187,15 @@ pub const Pattern = union(enum) { /// Err(_) => "some error occurred" /// } /// ``` - underscore: struct { - region: Region, - }, + underscore: void, /// Compiles, but will crash if reached runtime_error: struct { diagnostic: Diagnostic.Idx, - region: Region, }, pub const Idx = enum(u32) { _ }; pub const Span = struct { span: base.DataSpan }; - pub fn toRegion(self: *const @This()) Region { - switch (self.*) { - .assign => |p| return p.region, - .as => |p| return p.region, - .applied_tag => |p| return p.region, - .record_destructure => |p| return p.region, - .list => |p| return p.region, - .tuple => |p| return p.region, - .int_literal => |p| return p.region, - .small_dec_literal => |p| return p.region, - .dec_literal => |p| return p.region, - .str_literal => |p| return p.region, - .char_literal => |p| return p.region, - .underscore => |p| return p.region, - .runtime_error => |p| return p.region, - } - } - /// Represents the destructuring of a single field within a record pattern. /// Each record destructure specifies how to extract a field from a record. /// @@ -237,7 +205,6 @@ pub const Pattern = union(enum) { /// } /// ``` pub const RecordDestruct = struct { - region: Region, label: Ident.Idx, ident: Ident.Idx, kind: Kind, @@ -271,12 +238,11 @@ pub const Pattern = union(enum) { } }; - pub fn toSExpr(self: *const @This(), ir: *const CIR) SExpr { + pub fn toSExpr(self: *const @This(), ir: *const CIR, destruct_idx: RecordDestruct.Idx) SExpr { const gpa = ir.env.gpa; var node = SExpr.init(gpa, "record-destruct"); - - ir.appendRegionInfoToSexprNodeFromRegion(&node, self.region); + ir.appendRegionInfoToSexprNode(&node, destruct_idx); const label_text = ir.env.idents.getText(self.label); const ident_text = ir.env.idents.getText(self.ident); @@ -290,38 +256,39 @@ pub const Pattern = union(enum) { } }; - pub fn toSExpr(self: *const @This(), ir: *const CIR) SExpr { + pub fn toSExpr(self: *const @This(), ir: *const CIR, pattern_idx: Pattern.Idx) SExpr { const gpa = ir.env.gpa; switch (self.*) { .assign => |p| { var node = SExpr.init(gpa, "p-assign"); - ir.appendRegionInfoToSexprNodeFromRegion(&node, p.region); + ir.appendRegionInfoToSexprNode(&node, pattern_idx); const ident = ir.getIdentText(p.ident); node.appendStringAttr(gpa, "ident", ident); return node; }, - .as => |a| { + .as => |p| { var node = SExpr.init(gpa, "p-as"); - ir.appendRegionInfoToSexprNodeFromRegion(&node, a.region); + ir.appendRegionInfoToSexprNode(&node, pattern_idx); - const ident = ir.getIdentText(a.ident); + const ident = ir.getIdentText(p.ident); node.appendStringAttr(gpa, "as", ident); - var pattern_node = ir.store.getPattern(a.pattern).toSExpr(ir); + // Recurse on the inner pattern + var pattern_node = ir.store.getPattern(p.pattern).toSExpr(ir, p.pattern); node.appendNode(gpa, &pattern_node); return node; }, - .applied_tag => |p| { + .applied_tag => |_| { var node = SExpr.init(gpa, "p-applied-tag"); - ir.appendRegionInfoToSexprNodeFromRegion(&node, p.region); + ir.appendRegionInfoToSexprNode(&node, pattern_idx); return node; }, .record_destructure => |p| { var node = SExpr.init(gpa, "p-record-destructure"); - ir.appendRegionInfoToSexprNodeFromRegion(&node, p.region); + ir.appendRegionInfoToSexprNode(&node, pattern_idx); // var pattern_idx_node = formatPatternIdxNode(gpa, pattern_idx); // node.appendNode(gpa, &pattern_idx_node); @@ -330,22 +297,22 @@ pub const Pattern = union(enum) { // Iterate through the destructs span and convert each to SExpr for (ir.store.sliceRecordDestructs(p.destructs)) |destruct_idx| { - var destruct_sexpr = ir.store.getRecordDestruct(destruct_idx).toSExpr(ir); + const destruct = ir.store.getRecordDestruct(destruct_idx); + const destruct_sexpr = destruct.toSExpr(ir, destruct_idx); destructs_node.appendNode(gpa, &destruct_sexpr); } - node.appendNode(gpa, &destructs_node); return node; }, .list => |p| { var node = SExpr.init(gpa, "p-list"); - ir.appendRegionInfoToSexprNodeFromRegion(&node, p.region); + ir.appendRegionInfoToSexprNode(&node, pattern_idx); var patterns_node = SExpr.init(gpa, "patterns"); for (ir.store.slicePatterns(p.patterns)) |patt_idx| { - var patt_sexpr = ir.store.getPattern(patt_idx).toSExpr(ir); + var patt_sexpr = ir.store.getPattern(patt_idx).toSExpr(ir, patt_idx); patterns_node.appendNode(gpa, &patt_sexpr); } @@ -362,7 +329,7 @@ pub const Pattern = union(enum) { // Add the rest pattern if it has a name if (rest.pattern) |rest_pattern_idx| { - var rest_pattern_sexpr = ir.store.getPattern(rest_pattern_idx).toSExpr(ir); + var rest_pattern_sexpr = ir.store.getPattern(rest_pattern_idx).toSExpr(ir, rest_pattern_idx); rest_node.appendNode(gpa, &rest_pattern_sexpr); } @@ -373,7 +340,7 @@ pub const Pattern = union(enum) { }, .tuple => |p| { var node = SExpr.init(gpa, "p-tuple"); - ir.appendRegionInfoToSexprNodeFromRegion(&node, p.region); + ir.appendRegionInfoToSexprNode(&node, pattern_idx); // var pattern_idx_node = formatPatternIdxNode(gpa, pattern_idx); // node.appendNode(gpa, &pattern_idx_node); @@ -381,53 +348,52 @@ pub const Pattern = union(enum) { var patterns_node = SExpr.init(gpa, "patterns"); for (ir.store.slicePatterns(p.patterns)) |patt_idx| { - var patt_sexpr = ir.store.getPattern(patt_idx).toSExpr(ir); + var patt_sexpr = ir.store.getPattern(patt_idx).toSExpr(ir, patt_idx); patterns_node.appendNode(gpa, &patt_sexpr); } - node.appendNode(gpa, &patterns_node); return node; }, - .int_literal => |p| { + .int_literal => |_| { var node = SExpr.init(gpa, "p-int"); - ir.appendRegionInfoToSexprNodeFromRegion(&node, p.region); + ir.appendRegionInfoToSexprNode(&node, pattern_idx); return node; }, - .small_dec_literal => |p| { + .small_dec_literal => |_| { var node = SExpr.init(gpa, "p-small-dec"); - ir.appendRegionInfoToSexprNodeFromRegion(&node, p.region); + ir.appendRegionInfoToSexprNode(&node, pattern_idx); // TODO: add fields return node; }, - .dec_literal => |p| { + .dec_literal => |_| { var node = SExpr.init(gpa, "p-dec"); - ir.appendRegionInfoToSexprNodeFromRegion(&node, p.region); + ir.appendRegionInfoToSexprNode(&node, pattern_idx); // TODO: add fields return node; }, .str_literal => |p| { var node = SExpr.init(gpa, "p-str"); - ir.appendRegionInfoToSexprNodeFromRegion(&node, p.region); + ir.appendRegionInfoToSexprNode(&node, pattern_idx); const text = ir.env.strings.get(p.literal); node.appendStringAttr(gpa, "text", text); return node; }, - .char_literal => |l| { + .char_literal => |p| { var node = SExpr.init(gpa, "p-char"); - ir.appendRegionInfoToSexprNodeFromRegion(&node, l.region); + ir.appendRegionInfoToSexprNode(&node, pattern_idx); - const char_str = std.fmt.allocPrint(gpa, "'\\u({d})'", .{l.value}) catch ""; + const char_str = std.fmt.allocPrint(gpa, "'\\u({d})'", .{p.value}) catch ""; defer gpa.free(char_str); node.appendStringAttr(gpa, "byte", char_str); - // TODO: add num_var and requirements + return node; }, - .underscore => |p| { + .underscore => { var node = SExpr.init(gpa, "p-underscore"); - ir.appendRegionInfoToSexprNodeFromRegion(&node, p.region); + ir.appendRegionInfoToSexprNode(&node, pattern_idx); // var pattern_idx_node = formatPatternIdxNode(gpa, pattern_idx); // node.appendNode(gpa, &pattern_idx_node); @@ -436,7 +402,7 @@ pub const Pattern = union(enum) { }, .runtime_error => |e| { var node = SExpr.init(gpa, "p-runtime-error"); - ir.appendRegionInfoToSexprNodeFromRegion(&node, e.region); + ir.appendRegionInfoToSexprNode(&node, pattern_idx); const diagnostic = ir.store.getDiagnostic(e.diagnostic); diff --git a/src/check/canonicalize/Statement.zig b/src/check/canonicalize/Statement.zig index e0b5bee04f..14df25792b 100644 --- a/src/check/canonicalize/Statement.zig +++ b/src/check/canonicalize/Statement.zig @@ -163,7 +163,7 @@ pub const Statement = union(enum) { var node = SExpr.init(gpa, "s-let"); ir.appendRegionInfoToSexprNodeFromRegion(&node, d.region); - var pattern_node = ir.store.getPattern(d.pattern).toSExpr(ir); + var pattern_node = ir.store.getPattern(d.pattern).toSExpr(ir, d.pattern); node.appendNode(gpa, &pattern_node); var expr_node = ir.store.getExpr(d.expr).toSExpr(ir); @@ -175,7 +175,7 @@ pub const Statement = union(enum) { var node = SExpr.init(gpa, "s-var"); ir.appendRegionInfoToSexprNodeFromRegion(&node, v.region); - var pattern_node = ir.store.getPattern(v.pattern_idx).toSExpr(ir); + var pattern_node = ir.store.getPattern(v.pattern_idx).toSExpr(ir, v.pattern_idx); node.appendNode(gpa, &pattern_node); var expr_node = ir.store.getExpr(v.expr).toSExpr(ir); @@ -187,7 +187,7 @@ pub const Statement = union(enum) { var node = SExpr.init(gpa, "s-reassign"); ir.appendRegionInfoToSexprNodeFromRegion(&node, r.region); - var pattern_node = ir.store.getPattern(r.pattern_idx).toSExpr(ir); + var pattern_node = ir.store.getPattern(r.pattern_idx).toSExpr(ir, r.pattern_idx); node.appendNode(gpa, &pattern_node); var expr_node = ir.store.getExpr(r.expr).toSExpr(ir); @@ -223,7 +223,7 @@ pub const Statement = union(enum) { var node = SExpr.init(gpa, "s-for"); ir.appendRegionInfoToSexprNodeFromRegion(&node, s.region); - var pattern_node = ir.store.getPattern(s.patt).toSExpr(ir); + var pattern_node = ir.store.getPattern(s.patt).toSExpr(ir, s.patt); node.appendNode(gpa, &pattern_node); var expr_node = ir.store.getExpr(s.expr).toSExpr(ir); diff --git a/src/check/canonicalize/test/node_store_test.zig b/src/check/canonicalize/test/node_store_test.zig index 0a3d02dffc..ae995cc799 100644 --- a/src/check/canonicalize/test/node_store_test.zig +++ b/src/check/canonicalize/test/node_store_test.zig @@ -708,14 +708,12 @@ test "NodeStore round trip - Pattern" { try patterns.append(CIR.Pattern{ .assign = .{ .ident = @bitCast(@as(u32, 123)), - .region = from_raw_offsets(10, 20), }, }); try patterns.append(CIR.Pattern{ .as = .{ .pattern = @enumFromInt(234), .ident = @bitCast(@as(u32, 345)), - .region = from_raw_offsets(30, 40), }, }); try patterns.append(CIR.Pattern{ @@ -723,7 +721,6 @@ test "NodeStore round trip - Pattern" { .ext_var = @enumFromInt(456), .tag_name = @bitCast(@as(u32, 567)), .arguments = CIR.Pattern.Span{ .span = base.DataSpan.init(678, 789) }, - .region = from_raw_offsets(50, 60), }, }); try patterns.append(CIR.Pattern{ @@ -731,7 +728,6 @@ test "NodeStore round trip - Pattern" { .whole_var = @enumFromInt(890), .ext_var = @enumFromInt(901), .destructs = CIR.Pattern.RecordDestruct.Span{ .span = base.DataSpan.init(1012, 1123) }, - .region = from_raw_offsets(70, 80), }, }); try patterns.append(CIR.Pattern{ @@ -740,13 +736,11 @@ test "NodeStore round trip - Pattern" { .elem_var = @enumFromInt(1345), .patterns = CIR.Pattern.Span{ .span = base.DataSpan.init(1456, 1567) }, .rest_info = .{ .index = 3, .pattern = @enumFromInt(5676) }, - .region = from_raw_offsets(90, 100), }, }); try patterns.append(CIR.Pattern{ .tuple = .{ .patterns = CIR.Pattern.Span{ .span = base.DataSpan.init(1678, 1789) }, - .region = from_raw_offsets(110, 120), }, }); try patterns.append(CIR.Pattern{ @@ -755,26 +749,22 @@ test "NodeStore round trip - Pattern" { .bytes = @bitCast(@as(i128, 42)), .kind = .i128, }, - .region = from_raw_offsets(130, 140), }, }); try patterns.append(CIR.Pattern{ .small_dec_literal = .{ .numerator = 123, .denominator_power_of_ten = 2, - .region = from_raw_offsets(150, 160), }, }); try patterns.append(CIR.Pattern{ .dec_literal = .{ .value = RocDec.fromU64(1890), - .region = from_raw_offsets(170, 180), }, }); try patterns.append(CIR.Pattern{ .str_literal = .{ .literal = @enumFromInt(1901), - .region = from_raw_offsets(210, 220), }, }); try patterns.append(CIR.Pattern{ @@ -785,24 +775,35 @@ test "NodeStore round trip - Pattern" { .bits_needed = .@"7", }, .value = 65, // 'A' - .region = from_raw_offsets(230, 240), - }, - }); - try patterns.append(CIR.Pattern{ - .underscore = .{ - .region = from_raw_offsets(250, 260), + }, }); + try patterns.append(CIR.Pattern{ .underscore = {} }); try patterns.append(CIR.Pattern{ .runtime_error = .{ .diagnostic = @enumFromInt(2123), - .region = from_raw_offsets(270, 280), }, }); - // Test the round-trip for all patterns - for (patterns.items) |pattern| { - const idx = try store.addPattern(pattern); + // Test the round-trip for all patterns with their original regions + const regions = [_]base.Region{ + from_raw_offsets(10, 20), // assign + from_raw_offsets(30, 40), // as + from_raw_offsets(50, 60), // applied_tag + from_raw_offsets(70, 80), // record_destructure + from_raw_offsets(90, 100), // list + from_raw_offsets(110, 120), // tuple + from_raw_offsets(130, 140), // int_literal + from_raw_offsets(150, 160), // small_dec_literal + from_raw_offsets(170, 180), // dec_literal + from_raw_offsets(210, 220), // str_literal + from_raw_offsets(230, 240), // char_literal + from_raw_offsets(250, 260), // underscore + from_raw_offsets(270, 280), // runtime_error + }; + + for (patterns.items, regions) |pattern, region| { + const idx = try store.addPattern(pattern, region); const retrieved = store.getPattern(idx); testing.expectEqualDeep(pattern, retrieved) catch |err| { @@ -810,6 +811,14 @@ test "NodeStore round trip - Pattern" { std.debug.print("Retrieved: {any}\n\n", .{retrieved}); return err; }; + + // Also verify the region was stored correctly + const stored_region = store.getRegionAt(@enumFromInt(@intFromEnum(idx))); + testing.expectEqualDeep(region, stored_region) catch |err| { + std.debug.print("\n\nExpected region: {any}\n\n", .{region}); + std.debug.print("Stored region: {any}\n\n", .{stored_region}); + return err; + }; } const actual_test_count = patterns.items.len;