authorgravatar for spexguy070@gmail.comMartin Wickham <spexguy070@gmail.com> 2021-09-23 12:17:06-05:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2021-09-23 13:17:06-04:00
loga0a847f2e40046387e2e2b8a0b8dae9cb27ca22a
tree2fdaa3bdd0ab7d63eb54e1bd92aca1f1607cca14
parentf615648d7bdcb5c7ed38ad15169a8fa90bd86ca0
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Stage2: Implement comptime closures and the This builtin (#9823)


7 files changed, 669 insertions(+), 215 deletions(-)

src/AstGen.zig+241-59
......@@ -124,7 +124,7 @@ pub fn generate(gpa: *Allocator, tree: Ast) Allocator.Error!Zir {
124124 container_decl,
125125 .Auto,
126126 )) |struct_decl_ref| {
127 astgen.extra.items[@enumToInt(Zir.ExtraIndex.main_struct)] = @enumToInt(struct_decl_ref);
127 assert(refToIndex(struct_decl_ref).? == 0);
128128 } else |err| switch (err) {
129129 error.OutOfMemory => return error.OutOfMemory,
130130 error.AnalysisFail => {}, // Handled via compile_errors below.
......@@ -2078,9 +2078,6 @@ fn unusedResultExpr(gz: *GenZir, scope: *Scope, statement: Ast.Node.Index) Inner
20782078 .union_init_ptr,
20792079 .field_type,
20802080 .field_type_ref,
2081 .opaque_decl,
2082 .opaque_decl_anon,
2083 .opaque_decl_func,
20842081 .error_set_decl,
20852082 .error_set_decl_anon,
20862083 .error_set_decl_func,
......@@ -2162,6 +2159,7 @@ fn unusedResultExpr(gz: *GenZir, scope: *Scope, statement: Ast.Node.Index) Inner
21622159 .await_nosuspend,
21632160 .ret_err_value_code,
21642161 .extended,
2162 .closure_get,
21652163 => break :b false,
21662164
21672165 // ZIR instructions that are always `noreturn`.
......@@ -2205,6 +2203,7 @@ fn unusedResultExpr(gz: *GenZir, scope: *Scope, statement: Ast.Node.Index) Inner
22052203 .set_cold,
22062204 .set_float_mode,
22072205 .set_runtime_safety,
2206 .closure_capture,
22082207 => break :b true,
22092208 }
22102209 } else switch (maybe_unused_result) {
......@@ -3534,8 +3533,9 @@ fn structDeclInner(
35343533 container_decl: Ast.full.ContainerDecl,
35353534 layout: std.builtin.TypeInfo.ContainerLayout,
35363535) InnerError!Zir.Inst.Ref {
3536 const decl_inst = try gz.reserveInstructionIndex();
3537
35373538 if (container_decl.ast.members.len == 0) {
3538 const decl_inst = try gz.reserveInstructionIndex();
35393539 try gz.setStruct(decl_inst, .{
35403540 .src_node = node,
35413541 .layout = layout,
......@@ -3553,11 +3553,19 @@ fn structDeclInner(
35533553 const node_tags = tree.nodes.items(.tag);
35543554 const node_datas = tree.nodes.items(.data);
35553555
3556 var namespace: Scope.Namespace = .{
3557 .parent = scope,
3558 .node = node,
3559 .inst = decl_inst,
3560 .declaring_gz = gz,
3561 };
3562 defer namespace.deinit(gpa);
3563
35563564 // The struct_decl instruction introduces a scope in which the decls of the struct
35573565 // are in scope, so that field types, alignments, and default value expressions
35583566 // can refer to decls within the struct itself.
35593567 var block_scope: GenZir = .{
3560 .parent = scope,
3568 .parent = &namespace.base,
35613569 .decl_node_index = node,
35623570 .decl_line = gz.calcLine(node),
35633571 .astgen = astgen,
......@@ -3566,9 +3574,6 @@ fn structDeclInner(
35663574 };
35673575 defer block_scope.instructions.deinit(gpa);
35683576
3569 var namespace: Scope.Namespace = .{ .parent = scope, .node = node };
3570 defer namespace.decls.deinit(gpa);
3571
35723577 try astgen.scanDecls(&namespace, container_decl.ast.members);
35733578
35743579 var wip_decls: WipDecls = .{};
......@@ -3773,7 +3778,6 @@ fn structDeclInner(
37733778 }
37743779 }
37753780
3776 const decl_inst = try gz.reserveInstructionIndex();
37773781 if (block_scope.instructions.items.len != 0) {
37783782 _ = try block_scope.addBreak(.break_inline, decl_inst, .void_value);
37793783 }
......@@ -3787,11 +3791,18 @@ fn structDeclInner(
37873791 .known_has_bits = known_has_bits,
37883792 });
37893793
3790 try astgen.extra.ensureUnusedCapacity(gpa, bit_bag.items.len +
3791 @boolToInt(field_index != 0) + fields_data.items.len +
3794 // zig fmt: off
3795 try astgen.extra.ensureUnusedCapacity(gpa,
3796 bit_bag.items.len +
3797 @boolToInt(wip_decls.decl_index != 0) +
3798 wip_decls.payload.items.len +
37923799 block_scope.instructions.items.len +
3793 wip_decls.bit_bag.items.len + @boolToInt(wip_decls.decl_index != 0) +
3794 wip_decls.payload.items.len);
3800 wip_decls.bit_bag.items.len +
3801 @boolToInt(field_index != 0) +
3802 fields_data.items.len
3803 );
3804 // zig fmt: on
3805
37953806 astgen.extra.appendSliceAssumeCapacity(wip_decls.bit_bag.items); // Likely empty.
37963807 if (wip_decls.decl_index != 0) {
37973808 astgen.extra.appendAssumeCapacity(wip_decls.cur_bit_bag);
......@@ -3818,17 +3829,27 @@ fn unionDeclInner(
38183829 arg_node: Ast.Node.Index,
38193830 have_auto_enum: bool,
38203831) InnerError!Zir.Inst.Ref {
3832 const decl_inst = try gz.reserveInstructionIndex();
3833
38213834 const astgen = gz.astgen;
38223835 const gpa = astgen.gpa;
38233836 const tree = astgen.tree;
38243837 const node_tags = tree.nodes.items(.tag);
38253838 const node_datas = tree.nodes.items(.data);
38263839
3840 var namespace: Scope.Namespace = .{
3841 .parent = scope,
3842 .node = node,
3843 .inst = decl_inst,
3844 .declaring_gz = gz,
3845 };
3846 defer namespace.deinit(gpa);
3847
38273848 // The union_decl instruction introduces a scope in which the decls of the union
38283849 // are in scope, so that field types, alignments, and default value expressions
38293850 // can refer to decls within the union itself.
38303851 var block_scope: GenZir = .{
3831 .parent = scope,
3852 .parent = &namespace.base,
38323853 .decl_node_index = node,
38333854 .decl_line = gz.calcLine(node),
38343855 .astgen = astgen,
......@@ -3837,13 +3858,10 @@ fn unionDeclInner(
38373858 };
38383859 defer block_scope.instructions.deinit(gpa);
38393860
3840 var namespace: Scope.Namespace = .{ .parent = scope, .node = node };
3841 defer namespace.decls.deinit(gpa);
3842
38433861 try astgen.scanDecls(&namespace, members);
38443862
38453863 const arg_inst: Zir.Inst.Ref = if (arg_node != 0)
3846 try typeExpr(gz, &namespace.base, arg_node)
3864 try typeExpr(&block_scope, &namespace.base, arg_node)
38473865 else
38483866 .none;
38493867
......@@ -4056,7 +4074,6 @@ fn unionDeclInner(
40564074 }
40574075 }
40584076
4059 const decl_inst = try gz.reserveInstructionIndex();
40604077 if (block_scope.instructions.items.len != 0) {
40614078 _ = try block_scope.addBreak(.break_inline, decl_inst, .void_value);
40624079 }
......@@ -4071,11 +4088,18 @@ fn unionDeclInner(
40714088 .auto_enum_tag = have_auto_enum,
40724089 });
40734090
4074 try astgen.extra.ensureUnusedCapacity(gpa, bit_bag.items.len +
4075 1 + fields_data.items.len +
4091 // zig fmt: off
4092 try astgen.extra.ensureUnusedCapacity(gpa,
4093 bit_bag.items.len +
4094 @boolToInt(wip_decls.decl_index != 0) +
4095 wip_decls.payload.items.len +
40764096 block_scope.instructions.items.len +
4077 wip_decls.bit_bag.items.len + @boolToInt(wip_decls.decl_index != 0) +
4078 wip_decls.payload.items.len);
4097 wip_decls.bit_bag.items.len +
4098 1 + // cur_bit_bag
4099 fields_data.items.len
4100 );
4101 // zig fmt: on
4102
40794103 astgen.extra.appendSliceAssumeCapacity(wip_decls.bit_bag.items); // Likely empty.
40804104 if (wip_decls.decl_index != 0) {
40814105 astgen.extra.appendAssumeCapacity(wip_decls.cur_bit_bag);
......@@ -4238,10 +4262,20 @@ fn containerDecl(
42384262 // how structs are handled above.
42394263 const nonexhaustive = counts.nonexhaustive_node != 0;
42404264
4265 const decl_inst = try gz.reserveInstructionIndex();
4266
4267 var namespace: Scope.Namespace = .{
4268 .parent = scope,
4269 .node = node,
4270 .inst = decl_inst,
4271 .declaring_gz = gz,
4272 };
4273 defer namespace.deinit(gpa);
4274
42414275 // The enum_decl instruction introduces a scope in which the decls of the enum
42424276 // are in scope, so that tag values can refer to decls within the enum itself.
42434277 var block_scope: GenZir = .{
4244 .parent = scope,
4278 .parent = &namespace.base,
42454279 .decl_node_index = node,
42464280 .decl_line = gz.calcLine(node),
42474281 .astgen = astgen,
......@@ -4250,13 +4284,10 @@ fn containerDecl(
42504284 };
42514285 defer block_scope.instructions.deinit(gpa);
42524286
4253 var namespace: Scope.Namespace = .{ .parent = scope, .node = node };
4254 defer namespace.decls.deinit(gpa);
4255
42564287 try astgen.scanDecls(&namespace, container_decl.ast.members);
42574288
42584289 const arg_inst: Zir.Inst.Ref = if (container_decl.ast.arg != 0)
4259 try comptimeExpr(gz, &namespace.base, .{ .ty = .type_type }, container_decl.ast.arg)
4290 try comptimeExpr(&block_scope, &namespace.base, .{ .ty = .type_type }, container_decl.ast.arg)
42604291 else
42614292 .none;
42624293
......@@ -4451,7 +4482,6 @@ fn containerDecl(
44514482 }
44524483 }
44534484
4454 const decl_inst = try gz.reserveInstructionIndex();
44554485 if (block_scope.instructions.items.len != 0) {
44564486 _ = try block_scope.addBreak(.break_inline, decl_inst, .void_value);
44574487 }
......@@ -4465,11 +4495,18 @@ fn containerDecl(
44654495 .decls_len = @intCast(u32, wip_decls.decl_index),
44664496 });
44674497
4468 try astgen.extra.ensureUnusedCapacity(gpa, bit_bag.items.len +
4469 1 + fields_data.items.len +
4498 // zig fmt: off
4499 try astgen.extra.ensureUnusedCapacity(gpa,
4500 bit_bag.items.len +
4501 @boolToInt(wip_decls.decl_index != 0) +
4502 wip_decls.payload.items.len +
44704503 block_scope.instructions.items.len +
4471 wip_decls.bit_bag.items.len + @boolToInt(wip_decls.decl_index != 0) +
4472 wip_decls.payload.items.len);
4504 wip_decls.bit_bag.items.len +
4505 1 + // cur_bit_bag
4506 fields_data.items.len
4507 );
4508 // zig fmt: on
4509
44734510 astgen.extra.appendSliceAssumeCapacity(wip_decls.bit_bag.items); // Likely empty.
44744511 if (wip_decls.decl_index != 0) {
44754512 astgen.extra.appendAssumeCapacity(wip_decls.cur_bit_bag);
......@@ -4486,8 +4523,15 @@ fn containerDecl(
44864523 .keyword_opaque => {
44874524 assert(container_decl.ast.arg == 0);
44884525
4489 var namespace: Scope.Namespace = .{ .parent = scope, .node = node };
4490 defer namespace.decls.deinit(gpa);
4526 const decl_inst = try gz.reserveInstructionIndex();
4527
4528 var namespace: Scope.Namespace = .{
4529 .parent = scope,
4530 .node = node,
4531 .inst = decl_inst,
4532 .declaring_gz = gz,
4533 };
4534 defer namespace.deinit(gpa);
44914535
44924536 try astgen.scanDecls(&namespace, container_decl.ast.members);
44934537
......@@ -4625,21 +4669,20 @@ fn containerDecl(
46254669 wip_decls.cur_bit_bag >>= @intCast(u5, empty_slot_count * WipDecls.bits_per_field);
46264670 }
46274671 }
4628 const tag: Zir.Inst.Tag = switch (gz.anon_name_strategy) {
4629 .parent => .opaque_decl,
4630 .anon => .opaque_decl_anon,
4631 .func => .opaque_decl_func,
4632 };
4633 const decl_inst = try gz.addBlock(tag, node);
4634 try gz.instructions.append(gpa, decl_inst);
46354672
4636 try astgen.extra.ensureUnusedCapacity(gpa, @typeInfo(Zir.Inst.OpaqueDecl).Struct.fields.len +
4637 wip_decls.bit_bag.items.len + @boolToInt(wip_decls.decl_index != 0) +
4638 wip_decls.payload.items.len);
4639 const zir_datas = astgen.instructions.items(.data);
4640 zir_datas[decl_inst].pl_node.payload_index = astgen.addExtraAssumeCapacity(Zir.Inst.OpaqueDecl{
4673 try gz.setOpaque(decl_inst, .{
4674 .src_node = node,
46414675 .decls_len = @intCast(u32, wip_decls.decl_index),
46424676 });
4677
4678 // zig fmt: off
4679 try astgen.extra.ensureUnusedCapacity(gpa,
4680 wip_decls.bit_bag.items.len +
4681 @boolToInt(wip_decls.decl_index != 0) +
4682 wip_decls.payload.items.len
4683 );
4684 // zig fmt: on
4685
46434686 astgen.extra.appendSliceAssumeCapacity(wip_decls.bit_bag.items); // Likely empty.
46444687 if (wip_decls.decl_index != 0) {
46454688 astgen.extra.appendAssumeCapacity(wip_decls.cur_bit_bag);
......@@ -6380,6 +6423,7 @@ fn identifier(
63806423
63816424 const astgen = gz.astgen;
63826425 const tree = astgen.tree;
6426 const gpa = astgen.gpa;
63836427 const main_tokens = tree.nodes.items(.main_token);
63846428
63856429 const ident_token = main_tokens[ident];
......@@ -6426,16 +6470,28 @@ fn identifier(
64266470 const name_str_index = try astgen.identAsString(ident_token);
64276471 var s = scope;
64286472 var found_already: ?Ast.Node.Index = null; // we have found a decl with the same name already
6429 var hit_namespace: Ast.Node.Index = 0;
6473 var num_namespaces_out: u32 = 0;
6474 var capturing_namespace: ?*Scope.Namespace = null;
64306475 while (true) switch (s.tag) {
64316476 .local_val => {
64326477 const local_val = s.cast(Scope.LocalVal).?;
64336478
64346479 if (local_val.name == name_str_index) {
6435 local_val.used = true;
64366480 // Locals cannot shadow anything, so we do not need to look for ambiguous
64376481 // references in this case.
6438 return rvalue(gz, rl, local_val.inst, ident);
6482 local_val.used = true;
6483
6484 const value_inst = try tunnelThroughClosure(
6485 gz,
6486 ident,
6487 num_namespaces_out,
6488 capturing_namespace,
6489 local_val.inst,
6490 local_val.token_src,
6491 gpa,
6492 );
6493
6494 return rvalue(gz, rl, value_inst, ident);
64396495 }
64406496 s = local_val.parent;
64416497 },
......@@ -6443,16 +6499,29 @@ fn identifier(
64436499 const local_ptr = s.cast(Scope.LocalPtr).?;
64446500 if (local_ptr.name == name_str_index) {
64456501 local_ptr.used = true;
6446 if (hit_namespace != 0 and !local_ptr.maybe_comptime) {
6502
6503 // Can't close over a runtime variable
6504 if (num_namespaces_out != 0 and !local_ptr.maybe_comptime) {
64476505 return astgen.failNodeNotes(ident, "mutable '{s}' not accessible from here", .{ident_name}, &.{
64486506 try astgen.errNoteTok(local_ptr.token_src, "declared mutable here", .{}),
6449 try astgen.errNoteNode(hit_namespace, "crosses namespace boundary here", .{}),
6507 try astgen.errNoteNode(capturing_namespace.?.node, "crosses namespace boundary here", .{}),
64506508 });
64516509 }
6510
6511 const ptr_inst = try tunnelThroughClosure(
6512 gz,
6513 ident,
6514 num_namespaces_out,
6515 capturing_namespace,
6516 local_ptr.ptr,
6517 local_ptr.token_src,
6518 gpa,
6519 );
6520
64526521 switch (rl) {
6453 .ref, .none_or_ref => return local_ptr.ptr,
6522 .ref, .none_or_ref => return ptr_inst,
64546523 else => {
6455 const loaded = try gz.addUnNode(.load, local_ptr.ptr, ident);
6524 const loaded = try gz.addUnNode(.load, ptr_inst, ident);
64566525 return rvalue(gz, rl, loaded, ident);
64576526 },
64586527 }
......@@ -6473,7 +6542,8 @@ fn identifier(
64736542 // We found a match but must continue looking for ambiguous references to decls.
64746543 found_already = i;
64756544 }
6476 hit_namespace = ns.node;
6545 num_namespaces_out += 1;
6546 capturing_namespace = ns;
64776547 s = ns.parent;
64786548 },
64796549 .top => break,
......@@ -6493,6 +6563,37 @@ fn identifier(
64936563 }
64946564}
64956565
6566/// Adds a capture to a namespace, if needed.
6567/// Returns the index of the closure_capture instruction.
6568fn tunnelThroughClosure(
6569 gz: *GenZir,
6570 inner_ref_node: Ast.Node.Index,
6571 num_tunnels: u32,
6572 ns: ?*Scope.Namespace,
6573 value: Zir.Inst.Ref,
6574 token: Ast.TokenIndex,
6575 gpa: *Allocator,
6576) !Zir.Inst.Ref {
6577 // For trivial values, we don't need a tunnel.
6578 // Just return the ref.
6579 if (num_tunnels == 0 or refToIndex(value) == null) {
6580 return value;
6581 }
6582
6583 // Otherwise we need a tunnel. Check if this namespace
6584 // already has one for this value.
6585 const gop = try ns.?.captures.getOrPut(gpa, refToIndex(value).?);
6586 if (!gop.found_existing) {
6587 // Make a new capture for this value
6588 const capture_ref = try ns.?.declaring_gz.?.addUnTok(.closure_capture, value, token);
6589 gop.value_ptr.* = refToIndex(capture_ref).?;
6590 }
6591
6592 // Add an instruction to get the value from the closure into
6593 // our current context
6594 return try gz.addInstNode(.closure_get, gop.value_ptr.*, inner_ref_node);
6595}
6596
64966597fn stringLiteral(
64976598 gz: *GenZir,
64986599 rl: ResultLoc,
......@@ -8961,6 +9062,17 @@ const Scope = struct {
89619062 return @fieldParentPtr(T, "base", base);
89629063 }
89639064
9065 fn parent(base: *Scope) ?*Scope {
9066 return switch (base.tag) {
9067 .gen_zir => base.cast(GenZir).?.parent,
9068 .local_val => base.cast(LocalVal).?.parent,
9069 .local_ptr => base.cast(LocalPtr).?.parent,
9070 .defer_normal, .defer_error => base.cast(Defer).?.parent,
9071 .namespace => base.cast(Namespace).?.parent,
9072 .top => null,
9073 };
9074 }
9075
89649076 const Tag = enum {
89659077 gen_zir,
89669078 local_val,
......@@ -8986,7 +9098,7 @@ const Scope = struct {
89869098 const LocalVal = struct {
89879099 const base_tag: Tag = .local_val;
89889100 base: Scope = Scope{ .tag = base_tag },
8989 /// Parents can be: `LocalVal`, `LocalPtr`, `GenZir`, `Defer`.
9101 /// Parents can be: `LocalVal`, `LocalPtr`, `GenZir`, `Defer`, `Namespace`.
89909102 parent: *Scope,
89919103 gen_zir: *GenZir,
89929104 inst: Zir.Inst.Ref,
......@@ -9005,7 +9117,7 @@ const Scope = struct {
90059117 const LocalPtr = struct {
90069118 const base_tag: Tag = .local_ptr;
90079119 base: Scope = Scope{ .tag = base_tag },
9008 /// Parents can be: `LocalVal`, `LocalPtr`, `GenZir`, `Defer`.
9120 /// Parents can be: `LocalVal`, `LocalPtr`, `GenZir`, `Defer`, `Namespace`.
90099121 parent: *Scope,
90109122 gen_zir: *GenZir,
90119123 ptr: Zir.Inst.Ref,
......@@ -9023,7 +9135,7 @@ const Scope = struct {
90239135
90249136 const Defer = struct {
90259137 base: Scope,
9026 /// Parents can be: `LocalVal`, `LocalPtr`, `GenZir`, `Defer`.
9138 /// Parents can be: `LocalVal`, `LocalPtr`, `GenZir`, `Defer`, `Namespace`.
90279139 parent: *Scope,
90289140 defer_node: Ast.Node.Index,
90299141 };
......@@ -9034,11 +9146,27 @@ const Scope = struct {
90349146 const base_tag: Tag = .namespace;
90359147 base: Scope = Scope{ .tag = base_tag },
90369148
9149 /// Parents can be: `LocalVal`, `LocalPtr`, `GenZir`, `Defer`, `Namespace`.
90379150 parent: *Scope,
90389151 /// Maps string table index to the source location of declaration,
90399152 /// for the purposes of reporting name shadowing compile errors.
90409153 decls: std.AutoHashMapUnmanaged(u32, Ast.Node.Index) = .{},
90419154 node: Ast.Node.Index,
9155 inst: Zir.Inst.Index,
9156
9157 /// The astgen scope containing this namespace.
9158 /// Only valid during astgen.
9159 declaring_gz: ?*GenZir,
9160
9161 /// Map from the raw captured value to the instruction
9162 /// ref of the capture for decls in this namespace
9163 captures: std.AutoHashMapUnmanaged(Zir.Inst.Index, Zir.Inst.Index) = .{},
9164
9165 pub fn deinit(self: *Namespace, gpa: *Allocator) void {
9166 self.decls.deinit(gpa);
9167 self.captures.deinit(gpa);
9168 self.* = undefined;
9169 }
90429170 };
90439171
90449172 const Top = struct {
......@@ -9061,6 +9189,7 @@ const GenZir = struct {
90619189 decl_node_index: Ast.Node.Index,
90629190 /// The containing decl line index, absolute.
90639191 decl_line: u32,
9192 /// Parents can be: `LocalVal`, `LocalPtr`, `GenZir`, `Defer`, `Namespace`.
90649193 parent: *Scope,
90659194 /// All `GenZir` scopes for the same ZIR share this.
90669195 astgen: *AstGen,
......@@ -9096,6 +9225,12 @@ const GenZir = struct {
90969225 suspend_node: Ast.Node.Index = 0,
90979226 nosuspend_node: Ast.Node.Index = 0,
90989227
9228 /// Namespace members are lazy. When executing a decl within a namespace,
9229 /// any references to external instructions need to be treated specially.
9230 /// This list tracks those references. See also .closure_capture and .closure_get.
9231 /// Keys are the raw instruction index, values are the closure_capture instruction.
9232 captures: std.AutoHashMapUnmanaged(Zir.Inst.Index, Zir.Inst.Index) = .{},
9233
90999234 fn makeSubBlock(gz: *GenZir, scope: *Scope) GenZir {
91009235 return .{
91019236 .force_comptime = gz.force_comptime,
......@@ -9810,6 +9945,22 @@ const GenZir = struct {
98109945 });
98119946 }
98129947
9948 fn addInstNode(
9949 gz: *GenZir,
9950 tag: Zir.Inst.Tag,
9951 inst: Zir.Inst.Index,
9952 /// Absolute node index. This function does the conversion to offset from Decl.
9953 src_node: Ast.Node.Index,
9954 ) !Zir.Inst.Ref {
9955 return gz.add(.{
9956 .tag = tag,
9957 .data = .{ .inst_node = .{
9958 .inst = inst,
9959 .src_node = gz.nodeIndexToRelative(src_node),
9960 } },
9961 });
9962 }
9963
98139964 fn addNodeExtended(
98149965 gz: *GenZir,
98159966 opcode: Zir.Inst.Extended,
......@@ -10111,6 +10262,37 @@ const GenZir = struct {
1011110262 });
1011210263 }
1011310264
10265 fn setOpaque(gz: *GenZir, inst: Zir.Inst.Index, args: struct {
10266 src_node: Ast.Node.Index,
10267 decls_len: u32,
10268 }) !void {
10269 const astgen = gz.astgen;
10270 const gpa = astgen.gpa;
10271
10272 try astgen.extra.ensureUnusedCapacity(gpa, 2);
10273 const payload_index = @intCast(u32, astgen.extra.items.len);
10274
10275 if (args.src_node != 0) {
10276 const node_offset = gz.nodeIndexToRelative(args.src_node);
10277 astgen.extra.appendAssumeCapacity(@bitCast(u32, node_offset));
10278 }
10279 if (args.decls_len != 0) {
10280 astgen.extra.appendAssumeCapacity(args.decls_len);
10281 }
10282 astgen.instructions.set(inst, .{
10283 .tag = .extended,
10284 .data = .{ .extended = .{
10285 .opcode = .opaque_decl,
10286 .small = @bitCast(u16, Zir.Inst.OpaqueDecl.Small{
10287 .has_src_node = args.src_node != 0,
10288 .has_decls_len = args.decls_len != 0,
10289 .name_strategy = gz.anon_name_strategy,
10290 }),
10291 .operand = payload_index,
10292 } },
10293 });
10294 }
10295
1011410296 fn add(gz: *GenZir, inst: Zir.Inst) !Zir.Inst.Ref {
1011510297 return indexToRef(try gz.addAsIndex(inst));
1011610298 }
src/Module.zig+119-22
......@@ -275,6 +275,56 @@ pub const DeclPlusEmitH = struct {
275275 emit_h: EmitH,
276276};
277277
278pub const CaptureScope = struct {
279 parent: ?*CaptureScope,
280
281 /// Values from this decl's evaluation that will be closed over in
282 /// child decls. Values stored in the value_arena of the linked decl.
283 /// During sema, this map is backed by the gpa. Once sema completes,
284 /// it is reallocated using the value_arena.
285 captures: std.AutoHashMapUnmanaged(Zir.Inst.Index, TypedValue) = .{},
286};
287
288pub const WipCaptureScope = struct {
289 scope: *CaptureScope,
290 finalized: bool,
291 gpa: *Allocator,
292 perm_arena: *Allocator,
293
294 pub fn init(gpa: *Allocator, perm_arena: *Allocator, parent: ?*CaptureScope) !@This() {
295 const scope = try perm_arena.create(CaptureScope);
296 scope.* = .{ .parent = parent };
297 return @This(){
298 .scope = scope,
299 .finalized = false,
300 .gpa = gpa,
301 .perm_arena = perm_arena,
302 };
303 }
304
305 pub fn finalize(noalias self: *@This()) !void {
306 assert(!self.finalized);
307 // use a temp to avoid unintentional aliasing due to RLS
308 const tmp = try self.scope.captures.clone(self.perm_arena);
309 self.scope.captures = tmp;
310 self.finalized = true;
311 }
312
313 pub fn reset(noalias self: *@This(), parent: ?*CaptureScope) !void {
314 if (!self.finalized) try self.finalize();
315 self.scope = try self.perm_arena.create(CaptureScope);
316 self.scope.* = .{ .parent = parent };
317 self.finalized = false;
318 }
319
320 pub fn deinit(noalias self: *@This()) void {
321 if (!self.finalized) {
322 self.scope.captures.deinit(self.gpa);
323 }
324 self.* = undefined;
325 }
326};
327
278328pub const Decl = struct {
279329 /// Allocated with Module's allocator; outlives the ZIR code.
280330 name: [*:0]const u8,
......@@ -290,7 +340,7 @@ pub const Decl = struct {
290340 linksection_val: Value,
291341 /// Populated when `has_tv`.
292342 @"addrspace": std.builtin.AddressSpace,
293 /// The memory for ty, val, align_val, linksection_val.
343 /// The memory for ty, val, align_val, linksection_val, and captures.
294344 /// If this is `null` then there is no memory management needed.
295345 value_arena: ?*std.heap.ArenaAllocator.State = null,
296346 /// The direct parent namespace of the Decl.
......@@ -299,6 +349,11 @@ pub const Decl = struct {
299349 /// the namespace of the struct, since there is no parent.
300350 namespace: *Scope.Namespace,
301351
352 /// The scope which lexically contains this decl. A decl must depend
353 /// on its lexical parent, in order to ensure that this pointer is valid.
354 /// This scope is allocated out of the arena of the parent decl.
355 src_scope: ?*CaptureScope,
356
302357 /// An integer that can be checked against the corresponding incrementing
303358 /// generation field of Module. This is used to determine whether `complete` status
304359 /// represents pre- or post- re-analysis.
......@@ -959,6 +1014,7 @@ pub const Scope = struct {
9591014 return @fieldParentPtr(T, "base", base);
9601015 }
9611016
1017 /// Get the decl that is currently being analyzed
9621018 pub fn ownerDecl(scope: *Scope) ?*Decl {
9631019 return switch (scope.tag) {
9641020 .block => scope.cast(Block).?.sema.owner_decl,
......@@ -967,6 +1023,7 @@ pub const Scope = struct {
9671023 };
9681024 }
9691025
1026 /// Get the decl which contains this decl, for the purposes of source reporting
9701027 pub fn srcDecl(scope: *Scope) ?*Decl {
9711028 return switch (scope.tag) {
9721029 .block => scope.cast(Block).?.src_decl,
......@@ -975,6 +1032,15 @@ pub const Scope = struct {
9751032 };
9761033 }
9771034
1035 /// Get the scope which contains this decl, for resolving closure_get instructions.
1036 pub fn srcScope(scope: *Scope) ?*CaptureScope {
1037 return switch (scope.tag) {
1038 .block => scope.cast(Block).?.wip_capture_scope,
1039 .file => null,
1040 .namespace => scope.cast(Namespace).?.getDecl().src_scope,
1041 };
1042 }
1043
9781044 /// Asserts the scope has a parent which is a Namespace and returns it.
9791045 pub fn namespace(scope: *Scope) *Namespace {
9801046 switch (scope.tag) {
......@@ -1311,6 +1377,9 @@ pub const Scope = struct {
13111377 instructions: ArrayListUnmanaged(Air.Inst.Index),
13121378 // `param` instructions are collected here to be used by the `func` instruction.
13131379 params: std.ArrayListUnmanaged(Param) = .{},
1380
1381 wip_capture_scope: *CaptureScope,
1382
13141383 label: ?*Label = null,
13151384 inlining: ?*Inlining,
13161385 /// If runtime_index is not 0 then one of these is guaranteed to be non null.
......@@ -1372,6 +1441,7 @@ pub const Scope = struct {
13721441 .sema = parent.sema,
13731442 .src_decl = parent.src_decl,
13741443 .instructions = .{},
1444 .wip_capture_scope = parent.wip_capture_scope,
13751445 .label = null,
13761446 .inlining = parent.inlining,
13771447 .is_comptime = parent.is_comptime,
......@@ -2901,12 +2971,10 @@ pub fn mapOldZirToNew(
29012971 var match_stack: std.ArrayListUnmanaged(MatchedZirDecl) = .{};
29022972 defer match_stack.deinit(gpa);
29032973
2904 const old_main_struct_inst = old_zir.getMainStruct();
2905 const new_main_struct_inst = new_zir.getMainStruct();
2906
2974 // Main struct inst is always the same
29072975 try match_stack.append(gpa, .{
2908 .old_inst = old_main_struct_inst,
2909 .new_inst = new_main_struct_inst,
2976 .old_inst = Zir.main_struct_inst,
2977 .new_inst = Zir.main_struct_inst,
29102978 });
29112979
29122980 var old_decls = std.ArrayList(Zir.Inst.Index).init(gpa);
......@@ -3064,6 +3132,7 @@ pub fn semaFile(mod: *Module, file: *Scope.File) SemaError!void {
30643132 const struct_obj = try new_decl_arena.allocator.create(Module.Struct);
30653133 const struct_ty = try Type.Tag.@"struct".create(&new_decl_arena.allocator, struct_obj);
30663134 const struct_val = try Value.Tag.ty.create(&new_decl_arena.allocator, struct_ty);
3135 const ty_ty = comptime Type.initTag(.type);
30673136 struct_obj.* = .{
30683137 .owner_decl = undefined, // set below
30693138 .fields = .{},
......@@ -3078,7 +3147,7 @@ pub fn semaFile(mod: *Module, file: *Scope.File) SemaError!void {
30783147 .file_scope = file,
30793148 },
30803149 };
3081 const new_decl = try mod.allocateNewDecl(&struct_obj.namespace, 0);
3150 const new_decl = try mod.allocateNewDecl(&struct_obj.namespace, 0, null);
30823151 file.root_decl = new_decl;
30833152 struct_obj.owner_decl = new_decl;
30843153 new_decl.src_line = 0;
......@@ -3087,7 +3156,7 @@ pub fn semaFile(mod: *Module, file: *Scope.File) SemaError!void {
30873156 new_decl.is_exported = false;
30883157 new_decl.has_align = false;
30893158 new_decl.has_linksection_or_addrspace = false;
3090 new_decl.ty = struct_ty;
3159 new_decl.ty = ty_ty;
30913160 new_decl.val = struct_val;
30923161 new_decl.has_tv = true;
30933162 new_decl.owns_tv = true;
......@@ -3097,7 +3166,7 @@ pub fn semaFile(mod: *Module, file: *Scope.File) SemaError!void {
30973166
30983167 if (file.status == .success_zir) {
30993168 assert(file.zir_loaded);
3100 const main_struct_inst = file.zir.getMainStruct();
3169 const main_struct_inst = Zir.main_struct_inst;
31013170 struct_obj.zir_index = main_struct_inst;
31023171
31033172 var sema_arena = std.heap.ArenaAllocator.init(gpa);
......@@ -3107,6 +3176,7 @@ pub fn semaFile(mod: *Module, file: *Scope.File) SemaError!void {
31073176 .mod = mod,
31083177 .gpa = gpa,
31093178 .arena = &sema_arena.allocator,
3179 .perm_arena = &new_decl_arena.allocator,
31103180 .code = file.zir,
31113181 .owner_decl = new_decl,
31123182 .namespace = &struct_obj.namespace,
......@@ -3115,10 +3185,15 @@ pub fn semaFile(mod: *Module, file: *Scope.File) SemaError!void {
31153185 .owner_func = null,
31163186 };
31173187 defer sema.deinit();
3188
3189 var wip_captures = try WipCaptureScope.init(gpa, &new_decl_arena.allocator, null);
3190 defer wip_captures.deinit();
3191
31183192 var block_scope: Scope.Block = .{
31193193 .parent = null,
31203194 .sema = &sema,
31213195 .src_decl = new_decl,
3196 .wip_capture_scope = wip_captures.scope,
31223197 .instructions = .{},
31233198 .inlining = null,
31243199 .is_comptime = true,
......@@ -3126,6 +3201,7 @@ pub fn semaFile(mod: *Module, file: *Scope.File) SemaError!void {
31263201 defer block_scope.instructions.deinit(gpa);
31273202
31283203 if (sema.analyzeStructDecl(new_decl, main_struct_inst, struct_obj)) |_| {
3204 try wip_captures.finalize();
31293205 new_decl.analysis = .complete;
31303206 } else |err| switch (err) {
31313207 error.OutOfMemory => return error.OutOfMemory,
......@@ -3155,6 +3231,10 @@ fn semaDecl(mod: *Module, decl: *Decl) !bool {
31553231
31563232 decl.analysis = .in_progress;
31573233
3234 // We need the memory for the Type to go into the arena for the Decl
3235 var decl_arena = std.heap.ArenaAllocator.init(gpa);
3236 errdefer decl_arena.deinit();
3237
31583238 var analysis_arena = std.heap.ArenaAllocator.init(gpa);
31593239 defer analysis_arena.deinit();
31603240
......@@ -3162,6 +3242,7 @@ fn semaDecl(mod: *Module, decl: *Decl) !bool {
31623242 .mod = mod,
31633243 .gpa = gpa,
31643244 .arena = &analysis_arena.allocator,
3245 .perm_arena = &decl_arena.allocator,
31653246 .code = zir,
31663247 .owner_decl = decl,
31673248 .namespace = decl.namespace,
......@@ -3173,7 +3254,7 @@ fn semaDecl(mod: *Module, decl: *Decl) !bool {
31733254
31743255 if (decl.isRoot()) {
31753256 log.debug("semaDecl root {*} ({s})", .{ decl, decl.name });
3176 const main_struct_inst = zir.getMainStruct();
3257 const main_struct_inst = Zir.main_struct_inst;
31773258 const struct_obj = decl.getStruct().?;
31783259 // This might not have gotten set in `semaFile` if the first time had
31793260 // a ZIR failure, so we set it here in case.
......@@ -3185,10 +3266,14 @@ fn semaDecl(mod: *Module, decl: *Decl) !bool {
31853266 }
31863267 log.debug("semaDecl {*} ({s})", .{ decl, decl.name });
31873268
3269 var wip_captures = try WipCaptureScope.init(gpa, &decl_arena.allocator, decl.src_scope);
3270 defer wip_captures.deinit();
3271
31883272 var block_scope: Scope.Block = .{
31893273 .parent = null,
31903274 .sema = &sema,
31913275 .src_decl = decl,
3276 .wip_capture_scope = wip_captures.scope,
31923277 .instructions = .{},
31933278 .inlining = null,
31943279 .is_comptime = true,
......@@ -3203,6 +3288,7 @@ fn semaDecl(mod: *Module, decl: *Decl) !bool {
32033288 const extra = zir.extraData(Zir.Inst.Block, inst_data.payload_index);
32043289 const body = zir.extra[extra.end..][0..extra.data.body_len];
32053290 const break_index = try sema.analyzeBody(&block_scope, body);
3291 try wip_captures.finalize();
32063292 const result_ref = zir_datas[break_index].@"break".operand;
32073293 const src: LazySrcLoc = .{ .node_offset = 0 };
32083294 const decl_tv = try sema.resolveInstValue(&block_scope, src, result_ref);
......@@ -3239,9 +3325,6 @@ fn semaDecl(mod: *Module, decl: *Decl) !bool {
32393325 // not the struct itself.
32403326 try sema.resolveTypeLayout(&block_scope, src, decl_tv.ty);
32413327
3242 // We need the memory for the Type to go into the arena for the Decl
3243 var decl_arena = std.heap.ArenaAllocator.init(gpa);
3244 errdefer decl_arena.deinit();
32453328 const decl_arena_state = try decl_arena.allocator.create(std.heap.ArenaAllocator.State);
32463329
32473330 if (decl.is_usingnamespace) {
......@@ -3638,7 +3721,7 @@ fn scanDecl(iter: *ScanDeclIter, decl_sub_index: usize, flags: u4) SemaError!voi
36383721 // We create a Decl for it regardless of analysis status.
36393722 const gop = try namespace.decls.getOrPut(gpa, decl_name);
36403723 if (!gop.found_existing) {
3641 const new_decl = try mod.allocateNewDecl(namespace, decl_node);
3724 const new_decl = try mod.allocateNewDecl(namespace, decl_node, iter.parent_decl.src_scope);
36423725 if (is_usingnamespace) {
36433726 namespace.usingnamespace_set.putAssumeCapacity(new_decl, is_pub);
36443727 }
......@@ -3898,10 +3981,15 @@ pub fn analyzeFnBody(mod: *Module, decl: *Decl, func: *Fn, arena: *Allocator) Se
38983981
38993982 const gpa = mod.gpa;
39003983
3984 // Use the Decl's arena for captured values.
3985 var decl_arena = decl.value_arena.?.promote(gpa);
3986 defer decl.value_arena.?.* = decl_arena.state;
3987
39013988 var sema: Sema = .{
39023989 .mod = mod,
39033990 .gpa = gpa,
39043991 .arena = arena,
3992 .perm_arena = &decl_arena.allocator,
39053993 .code = decl.namespace.file_scope.zir,
39063994 .owner_decl = decl,
39073995 .namespace = decl.namespace,
......@@ -3916,10 +4004,14 @@ pub fn analyzeFnBody(mod: *Module, decl: *Decl, func: *Fn, arena: *Allocator) Se
39164004 try sema.air_extra.ensureTotalCapacity(gpa, reserved_count);
39174005 sema.air_extra.items.len += reserved_count;
39184006
4007 var wip_captures = try WipCaptureScope.init(gpa, &decl_arena.allocator, decl.src_scope);
4008 defer wip_captures.deinit();
4009
39194010 var inner_block: Scope.Block = .{
39204011 .parent = null,
39214012 .sema = &sema,
39224013 .src_decl = decl,
4014 .wip_capture_scope = wip_captures.scope,
39234015 .instructions = .{},
39244016 .inlining = null,
39254017 .is_comptime = false,
......@@ -3995,6 +4087,8 @@ pub fn analyzeFnBody(mod: *Module, decl: *Decl, func: *Fn, arena: *Allocator) Se
39954087 else => |e| return e,
39964088 };
39974089
4090 try wip_captures.finalize();
4091
39984092 // Copy the block into place and mark that as the main block.
39994093 try sema.air_extra.ensureUnusedCapacity(gpa, @typeInfo(Air.Block).Struct.fields.len +
40004094 inner_block.instructions.items.len);
......@@ -4035,7 +4129,7 @@ fn markOutdatedDecl(mod: *Module, decl: *Decl) !void {
40354129 decl.analysis = .outdated;
40364130}
40374131
4038pub fn allocateNewDecl(mod: *Module, namespace: *Scope.Namespace, src_node: Ast.Node.Index) !*Decl {
4132pub fn allocateNewDecl(mod: *Module, namespace: *Scope.Namespace, src_node: Ast.Node.Index, src_scope: ?*CaptureScope) !*Decl {
40394133 // If we have emit-h then we must allocate a bigger structure to store the emit-h state.
40404134 const new_decl: *Decl = if (mod.emit_h != null) blk: {
40414135 const parent_struct = try mod.gpa.create(DeclPlusEmitH);
......@@ -4061,6 +4155,7 @@ pub fn allocateNewDecl(mod: *Module, namespace: *Scope.Namespace, src_node: Ast.
40614155 .analysis = .unreferenced,
40624156 .deletion_flag = false,
40634157 .zir_decl_index = 0,
4158 .src_scope = src_scope,
40644159 .link = switch (mod.comp.bin_file.tag) {
40654160 .coff => .{ .coff = link.File.Coff.TextBlock.empty },
40664161 .elf => .{ .elf = link.File.Elf.TextBlock.empty },
......@@ -4087,6 +4182,7 @@ pub fn allocateNewDecl(mod: *Module, namespace: *Scope.Namespace, src_node: Ast.
40874182 .alive = false,
40884183 .is_usingnamespace = false,
40894184 };
4185
40904186 return new_decl;
40914187}
40924188
......@@ -4191,25 +4287,26 @@ pub fn createAnonymousDeclNamed(
41914287 typed_value: TypedValue,
41924288 name: [:0]u8,
41934289) !*Decl {
4194 return mod.createAnonymousDeclFromDeclNamed(scope.ownerDecl().?, typed_value, name);
4290 return mod.createAnonymousDeclFromDeclNamed(scope.ownerDecl().?, scope.srcScope(), typed_value, name);
41954291}
41964292
41974293pub fn createAnonymousDecl(mod: *Module, scope: *Scope, typed_value: TypedValue) !*Decl {
4198 return mod.createAnonymousDeclFromDecl(scope.ownerDecl().?, typed_value);
4294 return mod.createAnonymousDeclFromDecl(scope.ownerDecl().?, scope.srcScope(), typed_value);
41994295}
42004296
4201pub fn createAnonymousDeclFromDecl(mod: *Module, owner_decl: *Decl, tv: TypedValue) !*Decl {
4297pub fn createAnonymousDeclFromDecl(mod: *Module, owner_decl: *Decl, src_scope: ?*CaptureScope, tv: TypedValue) !*Decl {
42024298 const name_index = mod.getNextAnonNameIndex();
42034299 const name = try std.fmt.allocPrintZ(mod.gpa, "{s}__anon_{d}", .{
42044300 owner_decl.name, name_index,
42054301 });
4206 return mod.createAnonymousDeclFromDeclNamed(owner_decl, tv, name);
4302 return mod.createAnonymousDeclFromDeclNamed(owner_decl, src_scope, tv, name);
42074303}
42084304
42094305/// Takes ownership of `name` even if it returns an error.
42104306pub fn createAnonymousDeclFromDeclNamed(
42114307 mod: *Module,
42124308 owner_decl: *Decl,
4309 src_scope: ?*CaptureScope,
42134310 typed_value: TypedValue,
42144311 name: [:0]u8,
42154312) !*Decl {
......@@ -4218,7 +4315,7 @@ pub fn createAnonymousDeclFromDeclNamed(
42184315 const namespace = owner_decl.namespace;
42194316 try namespace.anon_decls.ensureUnusedCapacity(mod.gpa, 1);
42204317
4221 const new_decl = try mod.allocateNewDecl(namespace, owner_decl.src_node);
4318 const new_decl = try mod.allocateNewDecl(namespace, owner_decl.src_node, src_scope);
42224319
42234320 new_decl.name = name;
42244321 new_decl.src_line = owner_decl.src_line;
......@@ -4783,7 +4880,7 @@ pub fn populateTestFunctions(mod: *Module) !void {
47834880 const arena = &new_decl_arena.allocator;
47844881
47854882 const test_fn_vals = try arena.alloc(Value, mod.test_functions.count());
4786 const array_decl = try mod.createAnonymousDeclFromDecl(decl, .{
4883 const array_decl = try mod.createAnonymousDeclFromDecl(decl, null, .{
47874884 .ty = try Type.Tag.array.create(arena, .{
47884885 .len = test_fn_vals.len,
47894886 .elem_type = try tmp_test_fn_ty.copy(arena),
......@@ -4796,7 +4893,7 @@ pub fn populateTestFunctions(mod: *Module) !void {
47964893 var name_decl_arena = std.heap.ArenaAllocator.init(gpa);
47974894 errdefer name_decl_arena.deinit();
47984895 const bytes = try name_decl_arena.allocator.dupe(u8, test_name_slice);
4799 const test_name_decl = try mod.createAnonymousDeclFromDecl(array_decl, .{
4896 const test_name_decl = try mod.createAnonymousDeclFromDecl(array_decl, null, .{
48004897 .ty = try Type.Tag.array_u8.create(&name_decl_arena.allocator, bytes.len),
48014898 .val = try Value.Tag.bytes.create(&name_decl_arena.allocator, bytes),
48024899 });
src/Sema.zig+196-67
......@@ -8,8 +8,12 @@
88mod: *Module,
99/// Alias to `mod.gpa`.
1010gpa: *Allocator,
11/// Points to the arena allocator of the Decl.
11/// Points to the temporary arena allocator of the Sema.
12/// This arena will be cleared when the sema is destroyed.
1213arena: *Allocator,
14/// Points to the arena allocator for the owner_decl.
15/// This arena will persist until the decl is invalidated.
16perm_arena: *Allocator,
1317code: Zir,
1418air_instructions: std.MultiArrayList(Air.Inst) = .{},
1519air_extra: std.ArrayListUnmanaged(u32) = .{},
......@@ -80,6 +84,8 @@ const Scope = Module.Scope;
8084const CompileError = Module.CompileError;
8185const SemaError = Module.SemaError;
8286const Decl = Module.Decl;
87const CaptureScope = Module.CaptureScope;
88const WipCaptureScope = Module.WipCaptureScope;
8389const LazySrcLoc = Module.LazySrcLoc;
8490const RangeSet = @import("RangeSet.zig");
8591const target_util = @import("target.zig");
......@@ -129,15 +135,29 @@ pub fn analyzeBody(
129135) CompileError!Zir.Inst.Index {
130136 // No tracy calls here, to avoid interfering with the tail call mechanism.
131137
138 const parent_capture_scope = block.wip_capture_scope;
139
140 var wip_captures = WipCaptureScope{
141 .finalized = true,
142 .scope = parent_capture_scope,
143 .perm_arena = sema.perm_arena,
144 .gpa = sema.gpa,
145 };
146 defer if (wip_captures.scope != parent_capture_scope) {
147 wip_captures.deinit();
148 };
149
132150 const map = &block.sema.inst_map;
133151 const tags = block.sema.code.instructions.items(.tag);
134152 const datas = block.sema.code.instructions.items(.data);
135153
154 var orig_captures: usize = parent_capture_scope.captures.count();
155
136156 // We use a while(true) loop here to avoid a redundant way of breaking out of
137157 // the loop. The only way to break out of the loop is with a `noreturn`
138158 // instruction.
139159 var i: usize = 0;
140 while (true) {
160 const result = while (true) {
141161 const inst = body[i];
142162 const air_inst: Air.Inst.Ref = switch (tags[inst]) {
143163 // zig fmt: off
......@@ -170,6 +190,7 @@ pub fn analyzeBody(
170190 .call_compile_time => try sema.zirCall(block, inst, .compile_time, false),
171191 .call_nosuspend => try sema.zirCall(block, inst, .no_async, false),
172192 .call_async => try sema.zirCall(block, inst, .async_kw, false),
193 .closure_get => try sema.zirClosureGet(block, inst),
173194 .cmp_lt => try sema.zirCmp(block, inst, .lt),
174195 .cmp_lte => try sema.zirCmp(block, inst, .lte),
175196 .cmp_eq => try sema.zirCmpEq(block, inst, .eq, .cmp_eq),
......@@ -343,9 +364,6 @@ pub fn analyzeBody(
343364 .trunc => try sema.zirUnaryMath(block, inst),
344365 .round => try sema.zirUnaryMath(block, inst),
345366
346 .opaque_decl => try sema.zirOpaqueDecl(block, inst, .parent),
347 .opaque_decl_anon => try sema.zirOpaqueDecl(block, inst, .anon),
348 .opaque_decl_func => try sema.zirOpaqueDecl(block, inst, .func),
349367 .error_set_decl => try sema.zirErrorSetDecl(block, inst, .parent),
350368 .error_set_decl_anon => try sema.zirErrorSetDecl(block, inst, .anon),
351369 .error_set_decl_func => try sema.zirErrorSetDecl(block, inst, .func),
......@@ -362,13 +380,13 @@ pub fn analyzeBody(
362380 // Instructions that we know to *always* be noreturn based solely on their tag.
363381 // These functions match the return type of analyzeBody so that we can
364382 // tail call them here.
365 .compile_error => return sema.zirCompileError(block, inst),
366 .ret_coerce => return sema.zirRetCoerce(block, inst),
367 .ret_node => return sema.zirRetNode(block, inst),
368 .ret_load => return sema.zirRetLoad(block, inst),
369 .ret_err_value => return sema.zirRetErrValue(block, inst),
370 .@"unreachable" => return sema.zirUnreachable(block, inst),
371 .panic => return sema.zirPanic(block, inst),
383 .compile_error => break sema.zirCompileError(block, inst),
384 .ret_coerce => break sema.zirRetCoerce(block, inst),
385 .ret_node => break sema.zirRetNode(block, inst),
386 .ret_load => break sema.zirRetLoad(block, inst),
387 .ret_err_value => break sema.zirRetErrValue(block, inst),
388 .@"unreachable" => break sema.zirUnreachable(block, inst),
389 .panic => break sema.zirPanic(block, inst),
372390 // zig fmt: on
373391
374392 // Instructions that we know can *never* be noreturn based solely on
......@@ -503,34 +521,49 @@ pub fn analyzeBody(
503521 i += 1;
504522 continue;
505523 },
524 .closure_capture => {
525 try sema.zirClosureCapture(block, inst);
526 i += 1;
527 continue;
528 },
506529
507530 // Special case instructions to handle comptime control flow.
508531 .@"break" => {
509532 if (block.is_comptime) {
510 return inst; // same as break_inline
533 break inst; // same as break_inline
511534 } else {
512 return sema.zirBreak(block, inst);
535 break sema.zirBreak(block, inst);
513536 }
514537 },
515 .break_inline => return inst,
538 .break_inline => break inst,
516539 .repeat => {
517540 if (block.is_comptime) {
518541 // Send comptime control flow back to the beginning of this block.
519542 const src: LazySrcLoc = .{ .node_offset = datas[inst].node };
520543 try sema.emitBackwardBranch(block, src);
544 if (wip_captures.scope.captures.count() != orig_captures) {
545 try wip_captures.reset(parent_capture_scope);
546 block.wip_capture_scope = wip_captures.scope;
547 orig_captures = 0;
548 }
521549 i = 0;
522550 continue;
523551 } else {
524552 const src_node = sema.code.instructions.items(.data)[inst].node;
525553 const src: LazySrcLoc = .{ .node_offset = src_node };
526554 try sema.requireRuntimeBlock(block, src);
527 return always_noreturn;
555 break always_noreturn;
528556 }
529557 },
530558 .repeat_inline => {
531559 // Send comptime control flow back to the beginning of this block.
532560 const src: LazySrcLoc = .{ .node_offset = datas[inst].node };
533561 try sema.emitBackwardBranch(block, src);
562 if (wip_captures.scope.captures.count() != orig_captures) {
563 try wip_captures.reset(parent_capture_scope);
564 block.wip_capture_scope = wip_captures.scope;
565 orig_captures = 0;
566 }
534567 i = 0;
535568 continue;
536569 },
......@@ -545,7 +578,7 @@ pub fn analyzeBody(
545578 if (inst == break_data.block_inst) {
546579 break :blk sema.resolveInst(break_data.operand);
547580 } else {
548 return break_inst;
581 break break_inst;
549582 }
550583 },
551584 .block => blk: {
......@@ -559,7 +592,7 @@ pub fn analyzeBody(
559592 if (inst == break_data.block_inst) {
560593 break :blk sema.resolveInst(break_data.operand);
561594 } else {
562 return break_inst;
595 break break_inst;
563596 }
564597 },
565598 .block_inline => blk: {
......@@ -572,11 +605,11 @@ pub fn analyzeBody(
572605 if (inst == break_data.block_inst) {
573606 break :blk sema.resolveInst(break_data.operand);
574607 } else {
575 return break_inst;
608 break break_inst;
576609 }
577610 },
578611 .condbr => blk: {
579 if (!block.is_comptime) return sema.zirCondbr(block, inst);
612 if (!block.is_comptime) break sema.zirCondbr(block, inst);
580613 // Same as condbr_inline. TODO https://github.com/ziglang/zig/issues/8220
581614 const inst_data = datas[inst].pl_node;
582615 const cond_src: LazySrcLoc = .{ .node_offset_if_cond = inst_data.src_node };
......@@ -590,7 +623,7 @@ pub fn analyzeBody(
590623 if (inst == break_data.block_inst) {
591624 break :blk sema.resolveInst(break_data.operand);
592625 } else {
593 return break_inst;
626 break break_inst;
594627 }
595628 },
596629 .condbr_inline => blk: {
......@@ -606,15 +639,22 @@ pub fn analyzeBody(
606639 if (inst == break_data.block_inst) {
607640 break :blk sema.resolveInst(break_data.operand);
608641 } else {
609 return break_inst;
642 break break_inst;
610643 }
611644 },
612645 };
613646 if (sema.typeOf(air_inst).isNoReturn())
614 return always_noreturn;
647 break always_noreturn;
615648 try map.put(sema.gpa, inst, air_inst);
616649 i += 1;
650 } else unreachable;
651
652 if (!wip_captures.finalized) {
653 try wip_captures.finalize();
654 block.wip_capture_scope = parent_capture_scope;
617655 }
656
657 return result;
618658}
619659
620660fn zirExtended(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
......@@ -626,6 +666,7 @@ fn zirExtended(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileEr
626666 .struct_decl => return sema.zirStructDecl( block, extended, inst),
627667 .enum_decl => return sema.zirEnumDecl( block, extended),
628668 .union_decl => return sema.zirUnionDecl( block, extended, inst),
669 .opaque_decl => return sema.zirOpaqueDecl( block, extended, inst),
629670 .ret_ptr => return sema.zirRetPtr( block, extended),
630671 .ret_type => return sema.zirRetType( block, extended),
631672 .this => return sema.zirThis( block, extended),
......@@ -1011,7 +1052,6 @@ fn zirStructDecl(
10111052}
10121053
10131054fn createTypeName(sema: *Sema, block: *Scope.Block, name_strategy: Zir.Inst.NameStrategy) ![:0]u8 {
1014 _ = block;
10151055 switch (name_strategy) {
10161056 .anon => {
10171057 // It would be neat to have "struct:line:column" but this name has
......@@ -1020,14 +1060,14 @@ fn createTypeName(sema: *Sema, block: *Scope.Block, name_strategy: Zir.Inst.Name
10201060 // semantically analyzed.
10211061 const name_index = sema.mod.getNextAnonNameIndex();
10221062 return std.fmt.allocPrintZ(sema.gpa, "{s}__anon_{d}", .{
1023 sema.owner_decl.name, name_index,
1063 block.src_decl.name, name_index,
10241064 });
10251065 },
1026 .parent => return sema.gpa.dupeZ(u8, mem.spanZ(sema.owner_decl.name)),
1066 .parent => return sema.gpa.dupeZ(u8, mem.spanZ(block.src_decl.name)),
10271067 .func => {
10281068 const name_index = sema.mod.getNextAnonNameIndex();
10291069 const name = try std.fmt.allocPrintZ(sema.gpa, "{s}__anon_{d}", .{
1030 sema.owner_decl.name, name_index,
1070 block.src_decl.name, name_index,
10311071 });
10321072 log.warn("TODO: handle NameStrategy.func correctly instead of using anon name '{s}'", .{
10331073 name,
......@@ -1083,17 +1123,6 @@ fn zirEnumDecl(
10831123 var new_decl_arena = std.heap.ArenaAllocator.init(gpa);
10841124 errdefer new_decl_arena.deinit();
10851125
1086 const tag_ty = blk: {
1087 if (tag_type_ref != .none) {
1088 // TODO better source location
1089 // TODO (needs AstGen fix too) move this eval to the block so it gets allocated
1090 // in the new decl arena.
1091 break :blk try sema.resolveType(block, src, tag_type_ref);
1092 }
1093 const bits = std.math.log2_int_ceil(usize, fields_len);
1094 break :blk try Type.Tag.int_unsigned.create(&new_decl_arena.allocator, bits);
1095 };
1096
10971126 const enum_obj = try new_decl_arena.allocator.create(Module.EnumFull);
10981127 const enum_ty_payload = try new_decl_arena.allocator.create(Type.Payload.EnumFull);
10991128 enum_ty_payload.* = .{
......@@ -1112,7 +1141,7 @@ fn zirEnumDecl(
11121141
11131142 enum_obj.* = .{
11141143 .owner_decl = new_decl,
1115 .tag_ty = tag_ty,
1144 .tag_ty = Type.initTag(.@"null"),
11161145 .fields = .{},
11171146 .values = .{},
11181147 .node_offset = src.node_offset,
......@@ -1140,16 +1169,6 @@ fn zirEnumDecl(
11401169 const body_end = extra_index;
11411170 extra_index += bit_bags_count;
11421171
1143 try enum_obj.fields.ensureTotalCapacity(&new_decl_arena.allocator, fields_len);
1144 const any_values = for (sema.code.extra[body_end..][0..bit_bags_count]) |bag| {
1145 if (bag != 0) break true;
1146 } else false;
1147 if (any_values) {
1148 try enum_obj.values.ensureTotalCapacityContext(&new_decl_arena.allocator, fields_len, .{
1149 .ty = tag_ty,
1150 });
1151 }
1152
11531172 {
11541173 // We create a block for the field type instructions because they
11551174 // may need to reference Decls from inside the enum namespace.
......@@ -1172,10 +1191,14 @@ fn zirEnumDecl(
11721191 sema.func = null;
11731192 defer sema.func = prev_func;
11741193
1194 var wip_captures = try WipCaptureScope.init(gpa, sema.perm_arena, new_decl.src_scope);
1195 defer wip_captures.deinit();
1196
11751197 var enum_block: Scope.Block = .{
11761198 .parent = null,
11771199 .sema = sema,
11781200 .src_decl = new_decl,
1201 .wip_capture_scope = wip_captures.scope,
11791202 .instructions = .{},
11801203 .inlining = null,
11811204 .is_comptime = true,
......@@ -1185,7 +1208,30 @@ fn zirEnumDecl(
11851208 if (body.len != 0) {
11861209 _ = try sema.analyzeBody(&enum_block, body);
11871210 }
1211
1212 try wip_captures.finalize();
1213
1214 const tag_ty = blk: {
1215 if (tag_type_ref != .none) {
1216 // TODO better source location
1217 break :blk try sema.resolveType(block, src, tag_type_ref);
1218 }
1219 const bits = std.math.log2_int_ceil(usize, fields_len);
1220 break :blk try Type.Tag.int_unsigned.create(&new_decl_arena.allocator, bits);
1221 };
1222 enum_obj.tag_ty = tag_ty;
11881223 }
1224
1225 try enum_obj.fields.ensureTotalCapacity(&new_decl_arena.allocator, fields_len);
1226 const any_values = for (sema.code.extra[body_end..][0..bit_bags_count]) |bag| {
1227 if (bag != 0) break true;
1228 } else false;
1229 if (any_values) {
1230 try enum_obj.values.ensureTotalCapacityContext(&new_decl_arena.allocator, fields_len, .{
1231 .ty = enum_obj.tag_ty,
1232 });
1233 }
1234
11891235 var bit_bag_index: usize = body_end;
11901236 var cur_bit_bag: u32 = undefined;
11911237 var field_i: u32 = 0;
......@@ -1224,10 +1270,10 @@ fn zirEnumDecl(
12241270 // that points to this default value expression rather than the struct.
12251271 // But only resolve the source location if we need to emit a compile error.
12261272 const tag_val = (try sema.resolveInstConst(block, src, tag_val_ref)).val;
1227 enum_obj.values.putAssumeCapacityNoClobberContext(tag_val, {}, .{ .ty = tag_ty });
1273 enum_obj.values.putAssumeCapacityNoClobberContext(tag_val, {}, .{ .ty = enum_obj.tag_ty });
12281274 } else if (any_values) {
12291275 const tag_val = try Value.Tag.int_u64.create(&new_decl_arena.allocator, field_i);
1230 enum_obj.values.putAssumeCapacityNoClobberContext(tag_val, {}, .{ .ty = tag_ty });
1276 enum_obj.values.putAssumeCapacityNoClobberContext(tag_val, {}, .{ .ty = enum_obj.tag_ty });
12311277 }
12321278 }
12331279
......@@ -1305,20 +1351,14 @@ fn zirUnionDecl(
13051351fn zirOpaqueDecl(
13061352 sema: *Sema,
13071353 block: *Scope.Block,
1354 extended: Zir.Inst.Extended.InstData,
13081355 inst: Zir.Inst.Index,
1309 name_strategy: Zir.Inst.NameStrategy,
13101356) CompileError!Air.Inst.Ref {
13111357 const tracy = trace(@src());
13121358 defer tracy.end();
13131359
1314 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
1315 const src = inst_data.src();
1316 const extra = sema.code.extraData(Zir.Inst.Block, inst_data.payload_index);
1317
1318 _ = name_strategy;
1319 _ = inst_data;
1320 _ = src;
1321 _ = extra;
1360 _ = extended;
1361 _ = inst;
13221362 return sema.mod.fail(&block.base, sema.src, "TODO implement zirOpaqueDecl", .{});
13231363}
13241364
......@@ -2160,6 +2200,7 @@ fn zirCImport(sema: *Sema, parent_block: *Scope.Block, inst: Zir.Inst.Index) Com
21602200 .parent = parent_block,
21612201 .sema = sema,
21622202 .src_decl = parent_block.src_decl,
2203 .wip_capture_scope = parent_block.wip_capture_scope,
21632204 .instructions = .{},
21642205 .inlining = parent_block.inlining,
21652206 .is_comptime = parent_block.is_comptime,
......@@ -2214,7 +2255,7 @@ fn zirCImport(sema: *Sema, parent_block: *Scope.Block, inst: Zir.Inst.Index) Com
22142255 try sema.mod.semaFile(result.file);
22152256 const file_root_decl = result.file.root_decl.?;
22162257 try sema.mod.declareDeclDependency(sema.owner_decl, file_root_decl);
2217 return sema.addType(file_root_decl.ty);
2258 return sema.addConstant(file_root_decl.ty, file_root_decl.val);
22182259}
22192260
22202261fn zirSuspendBlock(sema: *Sema, parent_block: *Scope.Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
......@@ -2259,6 +2300,7 @@ fn zirBlock(
22592300 .parent = parent_block,
22602301 .sema = sema,
22612302 .src_decl = parent_block.src_decl,
2303 .wip_capture_scope = parent_block.wip_capture_scope,
22622304 .instructions = .{},
22632305 .label = &label,
22642306 .inlining = parent_block.inlining,
......@@ -2866,10 +2908,14 @@ fn analyzeCall(
28662908 sema.func = module_fn;
28672909 defer sema.func = parent_func;
28682910
2911 var wip_captures = try WipCaptureScope.init(gpa, sema.perm_arena, module_fn.owner_decl.src_scope);
2912 defer wip_captures.deinit();
2913
28692914 var child_block: Scope.Block = .{
28702915 .parent = null,
28712916 .sema = sema,
28722917 .src_decl = module_fn.owner_decl,
2918 .wip_capture_scope = wip_captures.scope,
28732919 .instructions = .{},
28742920 .label = null,
28752921 .inlining = &inlining,
......@@ -3034,6 +3080,9 @@ fn analyzeCall(
30343080
30353081 break :res2 result;
30363082 };
3083
3084 try wip_captures.finalize();
3085
30373086 break :res res2;
30383087 } else if (func_ty_info.is_generic) res: {
30393088 const func_val = try sema.resolveConstValue(block, func_src, func);
......@@ -3116,7 +3165,8 @@ fn analyzeCall(
31163165 try namespace.anon_decls.ensureUnusedCapacity(gpa, 1);
31173166
31183167 // Create a Decl for the new function.
3119 const new_decl = try mod.allocateNewDecl(namespace, module_fn.owner_decl.src_node);
3168 const src_decl = namespace.getDecl();
3169 const new_decl = try mod.allocateNewDecl(namespace, module_fn.owner_decl.src_node, src_decl.src_scope);
31203170 // TODO better names for generic function instantiations
31213171 const name_index = mod.getNextAnonNameIndex();
31223172 new_decl.name = try std.fmt.allocPrintZ(gpa, "{s}__anon_{d}", .{
......@@ -3147,6 +3197,7 @@ fn analyzeCall(
31473197 .mod = mod,
31483198 .gpa = gpa,
31493199 .arena = sema.arena,
3200 .perm_arena = &new_decl_arena.allocator,
31503201 .code = fn_zir,
31513202 .owner_decl = new_decl,
31523203 .namespace = namespace,
......@@ -3159,10 +3210,14 @@ fn analyzeCall(
31593210 };
31603211 defer child_sema.deinit();
31613212
3213 var wip_captures = try WipCaptureScope.init(gpa, sema.perm_arena, new_decl.src_scope);
3214 defer wip_captures.deinit();
3215
31623216 var child_block: Scope.Block = .{
31633217 .parent = null,
31643218 .sema = &child_sema,
31653219 .src_decl = new_decl,
3220 .wip_capture_scope = wip_captures.scope,
31663221 .instructions = .{},
31673222 .inlining = null,
31683223 .is_comptime = true,
......@@ -3250,6 +3305,8 @@ fn analyzeCall(
32503305 arg_i += 1;
32513306 }
32523307
3308 try wip_captures.finalize();
3309
32533310 // Populate the Decl ty/val with the function and its type.
32543311 new_decl.ty = try child_sema.typeOf(new_func_inst).copy(&new_decl_arena.allocator);
32553312 new_decl.val = try Value.Tag.function.create(&new_decl_arena.allocator, new_func);
......@@ -5164,6 +5221,7 @@ fn analyzeSwitch(
51645221 .parent = block,
51655222 .sema = sema,
51665223 .src_decl = block.src_decl,
5224 .wip_capture_scope = block.wip_capture_scope,
51675225 .instructions = .{},
51685226 .label = &label,
51695227 .inlining = block.inlining,
......@@ -5268,12 +5326,19 @@ fn analyzeSwitch(
52685326 const body = sema.code.extra[extra_index..][0..body_len];
52695327 extra_index += body_len;
52705328
5329 var wip_captures = try WipCaptureScope.init(gpa, sema.perm_arena, child_block.wip_capture_scope);
5330 defer wip_captures.deinit();
5331
52715332 case_block.instructions.shrinkRetainingCapacity(0);
5333 case_block.wip_capture_scope = wip_captures.scope;
5334
52725335 const item = sema.resolveInst(item_ref);
52735336 // `item` is already guaranteed to be constant known.
52745337
52755338 _ = try sema.analyzeBody(&case_block, body);
52765339
5340 try wip_captures.finalize();
5341
52775342 try cases_extra.ensureUnusedCapacity(gpa, 3 + case_block.instructions.items.len);
52785343 cases_extra.appendAssumeCapacity(1); // items_len
52795344 cases_extra.appendAssumeCapacity(@intCast(u32, case_block.instructions.items.len));
......@@ -5301,6 +5366,7 @@ fn analyzeSwitch(
53015366 extra_index += items_len;
53025367
53035368 case_block.instructions.shrinkRetainingCapacity(0);
5369 case_block.wip_capture_scope = child_block.wip_capture_scope;
53045370
53055371 var any_ok: Air.Inst.Ref = .none;
53065372
......@@ -5379,11 +5445,18 @@ fn analyzeSwitch(
53795445 var cond_body = case_block.instructions.toOwnedSlice(gpa);
53805446 defer gpa.free(cond_body);
53815447
5448 var wip_captures = try WipCaptureScope.init(gpa, sema.perm_arena, child_block.wip_capture_scope);
5449 defer wip_captures.deinit();
5450
53825451 case_block.instructions.shrinkRetainingCapacity(0);
5452 case_block.wip_capture_scope = wip_captures.scope;
5453
53835454 const body = sema.code.extra[extra_index..][0..body_len];
53845455 extra_index += body_len;
53855456 _ = try sema.analyzeBody(&case_block, body);
53865457
5458 try wip_captures.finalize();
5459
53875460 if (is_first) {
53885461 is_first = false;
53895462 first_else_body = cond_body;
......@@ -5409,9 +5482,16 @@ fn analyzeSwitch(
54095482
54105483 var final_else_body: []const Air.Inst.Index = &.{};
54115484 if (special.body.len != 0) {
5485 var wip_captures = try WipCaptureScope.init(gpa, sema.perm_arena, child_block.wip_capture_scope);
5486 defer wip_captures.deinit();
5487
54125488 case_block.instructions.shrinkRetainingCapacity(0);
5489 case_block.wip_capture_scope = wip_captures.scope;
5490
54135491 _ = try sema.analyzeBody(&case_block, special.body);
54145492
5493 try wip_captures.finalize();
5494
54155495 if (is_first) {
54165496 final_else_body = case_block.instructions.items;
54175497 } else {
......@@ -5693,7 +5773,7 @@ fn zirImport(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileErro
56935773 try mod.semaFile(result.file);
56945774 const file_root_decl = result.file.root_decl.?;
56955775 try sema.mod.declareDeclDependency(sema.owner_decl, file_root_decl);
5696 return sema.addType(file_root_decl.ty);
5776 return sema.addConstant(file_root_decl.ty, file_root_decl.val);
56975777}
56985778
56995779fn zirRetErrValueCode(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
......@@ -6536,8 +6616,45 @@ fn zirThis(
65366616 block: *Scope.Block,
65376617 extended: Zir.Inst.Extended.InstData,
65386618) CompileError!Air.Inst.Ref {
6619 const this_decl = block.base.namespace().getDecl();
65396620 const src: LazySrcLoc = .{ .node_offset = @bitCast(i32, extended.operand) };
6540 return sema.mod.fail(&block.base, src, "TODO: implement Sema.zirThis", .{});
6621 return sema.analyzeDeclVal(block, src, this_decl);
6622}
6623
6624fn zirClosureCapture(
6625 sema: *Sema,
6626 block: *Scope.Block,
6627 inst: Zir.Inst.Index,
6628) CompileError!void {
6629 // TODO: Compile error when closed over values are modified
6630 const inst_data = sema.code.instructions.items(.data)[inst].un_tok;
6631 const tv = try sema.resolveInstConst(block, inst_data.src(), inst_data.operand);
6632 try block.wip_capture_scope.captures.putNoClobber(sema.gpa, inst, .{
6633 .ty = try tv.ty.copy(sema.perm_arena),
6634 .val = try tv.val.copy(sema.perm_arena),
6635 });
6636}
6637
6638fn zirClosureGet(
6639 sema: *Sema,
6640 block: *Scope.Block,
6641 inst: Zir.Inst.Index,
6642) CompileError!Air.Inst.Ref {
6643 // TODO CLOSURE: Test this with inline functions
6644 const inst_data = sema.code.instructions.items(.data)[inst].inst_node;
6645 var scope: *CaptureScope = block.src_decl.src_scope.?;
6646 // Note: The target closure must be in this scope list.
6647 // If it's not here, the zir is invalid, or the list is broken.
6648 const tv = while (true) {
6649 // Note: We don't need to add a dependency here, because
6650 // decls always depend on their lexical parents.
6651 if (scope.captures.getPtr(inst_data.inst)) |tv| {
6652 break tv;
6653 }
6654 scope = scope.parent.?;
6655 } else unreachable;
6656
6657 return sema.addConstant(tv.ty, tv.val);
65416658}
65426659
65436660fn zirRetAddr(
......@@ -8615,6 +8732,7 @@ fn addSafetyCheck(
86158732 var fail_block: Scope.Block = .{
86168733 .parent = parent_block,
86178734 .sema = sema,
8735 .wip_capture_scope = parent_block.wip_capture_scope,
86188736 .src_decl = parent_block.src_decl,
86198737 .instructions = .{},
86208738 .inlining = parent_block.inlining,
......@@ -8714,7 +8832,7 @@ fn safetyPanic(
87148832 block: *Scope.Block,
87158833 src: LazySrcLoc,
87168834 panic_id: PanicId,
8717) !Zir.Inst.Index {
8835) CompileError!Zir.Inst.Index {
87188836 const msg = switch (panic_id) {
87198837 .unreach => "reached unreachable code",
87208838 .unwrap_null => "attempt to use null value",
......@@ -10666,6 +10784,10 @@ pub fn resolveDeclFields(sema: *Sema, block: *Scope.Block, src: LazySrcLoc, ty:
1066610784 sema.namespace = &struct_obj.namespace;
1066710785 defer sema.namespace = prev_namespace;
1066810786
10787 const old_src = block.src_decl;
10788 defer block.src_decl = old_src;
10789 block.src_decl = struct_obj.owner_decl;
10790
1066910791 struct_obj.status = .field_types_wip;
1067010792 try sema.analyzeStructFields(block, struct_obj);
1067110793 struct_obj.status = .have_field_types;
......@@ -10684,6 +10806,10 @@ pub fn resolveDeclFields(sema: *Sema, block: *Scope.Block, src: LazySrcLoc, ty:
1068410806 sema.namespace = &union_obj.namespace;
1068510807 defer sema.namespace = prev_namespace;
1068610808
10809 const old_src = block.src_decl;
10810 defer block.src_decl = old_src;
10811 block.src_decl = union_obj.owner_decl;
10812
1068710813 union_obj.status = .field_types_wip;
1068810814 try sema.analyzeUnionFields(block, union_obj);
1068910815 union_obj.status = .have_field_types;
......@@ -10885,9 +11011,11 @@ fn analyzeUnionFields(
1088511011 const src: LazySrcLoc = .{ .node_offset = union_obj.node_offset };
1088611012 extra_index += @boolToInt(small.has_src_node);
1088711013
10888 if (small.has_tag_type) {
11014 const tag_type_ref: Zir.Inst.Ref = if (small.has_tag_type) blk: {
11015 const ty_ref = @intToEnum(Zir.Inst.Ref, zir.extra[extra_index]);
1088911016 extra_index += 1;
10890 }
11017 break :blk ty_ref;
11018 } else .none;
1089111019
1089211020 const body_len = if (small.has_body_len) blk: {
1089311021 const body_len = zir.extra[extra_index];
......@@ -10996,6 +11124,7 @@ fn analyzeUnionFields(
1099611124 }
1099711125
1099811126 // TODO resolve the union tag_type_ref
11127 _ = tag_type_ref;
1099911128}
1100011129
1100111130fn getBuiltin(
src/Zir.zig+62-37
......@@ -49,8 +49,6 @@ pub const Header = extern struct {
4949};
5050
5151pub const ExtraIndex = enum(u32) {
52 /// Ref. The main struct decl for this file.
53 main_struct,
5452 /// If this is 0, no compile errors. Otherwise there is a `CompileErrors`
5553 /// payload at this index.
5654 compile_errors,
......@@ -61,11 +59,6 @@ pub const ExtraIndex = enum(u32) {
6159 _,
6260};
6361
64pub fn getMainStruct(zir: Zir) Inst.Index {
65 return zir.extra[@enumToInt(ExtraIndex.main_struct)] -
66 @intCast(u32, Inst.Ref.typed_value_map.len);
67}
68
6962/// Returns the requested data, as well as the new index which is at the start of the
7063/// trailers for the object.
7164pub fn extraData(code: Zir, comptime T: type, index: usize) struct { data: T, end: usize } {
......@@ -112,6 +105,10 @@ pub fn deinit(code: *Zir, gpa: *Allocator) void {
112105 code.* = undefined;
113106}
114107
108/// ZIR is structured so that the outermost "main" struct of any file
109/// is always at index 0.
110pub const main_struct_inst: Inst.Index = 0;
111
115112/// These are untyped instructions generated from an Abstract Syntax Tree.
116113/// The data here is immutable because it is possible to have multiple
117114/// analyses on the same ZIR happening at the same time.
......@@ -267,11 +264,6 @@ pub const Inst = struct {
267264 /// only the taken branch is analyzed. The then block and else block must
268265 /// terminate with an "inline" variant of a noreturn instruction.
269266 condbr_inline,
270 /// An opaque type definition. Provides an AST node only.
271 /// Uses the `pl_node` union field. Payload is `OpaqueDecl`.
272 opaque_decl,
273 opaque_decl_anon,
274 opaque_decl_func,
275267 /// An error set type definition. Contains a list of field names.
276268 /// Uses the `pl_node` union field. Payload is `ErrorSetDecl`.
277269 error_set_decl,
......@@ -941,6 +933,17 @@ pub const Inst = struct {
941933 @"await",
942934 await_nosuspend,
943935
936 /// When a type or function refers to a comptime value from an outer
937 /// scope, that forms a closure over comptime value. The outer scope
938 /// will record a capture of that value, which encodes its current state
939 /// and marks it to persist. Uses `un_tok` field. Operand is the
940 /// instruction value to capture.
941 closure_capture,
942 /// The inner scope of a closure uses closure_get to retrieve the value
943 /// stored by the outer scope. Uses `inst_node` field. Operand is the
944 /// closure_capture instruction ref.
945 closure_get,
946
944947 /// The ZIR instruction tag is one of the `Extended` ones.
945948 /// Uses the `extended` union field.
946949 extended,
......@@ -996,9 +999,6 @@ pub const Inst = struct {
996999 .cmp_gt,
9971000 .cmp_neq,
9981001 .coerce_result_ptr,
999 .opaque_decl,
1000 .opaque_decl_anon,
1001 .opaque_decl_func,
10021002 .error_set_decl,
10031003 .error_set_decl_anon,
10041004 .error_set_decl_func,
......@@ -1191,6 +1191,8 @@ pub const Inst = struct {
11911191 .await_nosuspend,
11921192 .ret_err_value_code,
11931193 .extended,
1194 .closure_get,
1195 .closure_capture,
11941196 => false,
11951197
11961198 .@"break",
......@@ -1258,9 +1260,6 @@ pub const Inst = struct {
12581260 .coerce_result_ptr = .bin,
12591261 .condbr = .pl_node,
12601262 .condbr_inline = .pl_node,
1261 .opaque_decl = .pl_node,
1262 .opaque_decl_anon = .pl_node,
1263 .opaque_decl_func = .pl_node,
12641263 .error_set_decl = .pl_node,
12651264 .error_set_decl_anon = .pl_node,
12661265 .error_set_decl_func = .pl_node,
......@@ -1478,6 +1477,9 @@ pub const Inst = struct {
14781477 .@"await" = .un_node,
14791478 .await_nosuspend = .un_node,
14801479
1480 .closure_capture = .un_tok,
1481 .closure_get = .inst_node,
1482
14811483 .extended = .extended,
14821484 });
14831485 };
......@@ -1510,6 +1512,10 @@ pub const Inst = struct {
15101512 /// `operand` is payload index to `UnionDecl`.
15111513 /// `small` is `UnionDecl.Small`.
15121514 union_decl,
1515 /// An opaque type definition. Contains references to decls and captures.
1516 /// `operand` is payload index to `OpaqueDecl`.
1517 /// `small` is `OpaqueDecl.Small`.
1518 opaque_decl,
15131519 /// Obtains a pointer to the return value.
15141520 /// `operand` is `src_node: i32`.
15151521 ret_ptr,
......@@ -2194,6 +2200,18 @@ pub const Inst = struct {
21942200 line: u32,
21952201 column: u32,
21962202 },
2203 /// Used for unary operators which reference an inst,
2204 /// with an AST node source location.
2205 inst_node: struct {
2206 /// Offset from Decl AST node index.
2207 src_node: i32,
2208 /// The meaning of this operand depends on the corresponding `Tag`.
2209 inst: Index,
2210
2211 pub fn src(self: @This()) LazySrcLoc {
2212 return .{ .node_offset = self.src_node };
2213 }
2214 },
21972215
21982216 // Make sure we don't accidentally add a field to make this union
21992217 // bigger than expected. Note that in Debug builds, Zig is allowed
......@@ -2231,6 +2249,7 @@ pub const Inst = struct {
22312249 @"break",
22322250 switch_capture,
22332251 dbg_stmt,
2252 inst_node,
22342253 };
22352254 };
22362255
......@@ -2662,13 +2681,15 @@ pub const Inst = struct {
26622681 };
26632682
26642683 /// Trailing:
2665 /// 0. decl_bits: u32 // for every 8 decls
2684 /// 0. src_node: i32, // if has_src_node
2685 /// 1. decls_len: u32, // if has_decls_len
2686 /// 2. decl_bits: u32 // for every 8 decls
26662687 /// - sets of 4 bits:
26672688 /// 0b000X: whether corresponding decl is pub
26682689 /// 0b00X0: whether corresponding decl is exported
26692690 /// 0b0X00: whether corresponding decl has an align expression
26702691 /// 0bX000: whether corresponding decl has a linksection or an address space expression
2671 /// 1. decl: { // for every decls_len
2692 /// 3. decl: { // for every decls_len
26722693 /// src_hash: [4]u32, // hash of source bytes
26732694 /// line: u32, // line number of decl, relative to parent
26742695 /// name: u32, // null terminated string index
......@@ -2685,7 +2706,12 @@ pub const Inst = struct {
26852706 /// }
26862707 /// }
26872708 pub const OpaqueDecl = struct {
2688 decls_len: u32,
2709 pub const Small = packed struct {
2710 has_src_node: bool,
2711 has_decls_len: bool,
2712 name_strategy: NameStrategy,
2713 _: u12 = undefined,
2714 };
26892715 };
26902716
26912717 /// Trailing: field_name: u32 // for every field: null terminated string index
......@@ -2937,15 +2963,6 @@ pub fn declIterator(zir: Zir, decl_inst: u32) DeclIterator {
29372963 const tags = zir.instructions.items(.tag);
29382964 const datas = zir.instructions.items(.data);
29392965 switch (tags[decl_inst]) {
2940 .opaque_decl,
2941 .opaque_decl_anon,
2942 .opaque_decl_func,
2943 => {
2944 const inst_data = datas[decl_inst].pl_node;
2945 const extra = zir.extraData(Inst.OpaqueDecl, inst_data.payload_index);
2946 return declIteratorInner(zir, extra.end, extra.data.decls_len);
2947 },
2948
29492966 // Functions are allowed and yield no iterations.
29502967 // There is one case matching this in the extended instruction set below.
29512968 .func,
......@@ -3000,6 +3017,18 @@ pub fn declIterator(zir: Zir, decl_inst: u32) DeclIterator {
30003017
30013018 return declIteratorInner(zir, extra_index, decls_len);
30023019 },
3020 .opaque_decl => {
3021 const small = @bitCast(Inst.OpaqueDecl.Small, extended.small);
3022 var extra_index: usize = extended.operand;
3023 extra_index += @boolToInt(small.has_src_node);
3024 const decls_len = if (small.has_decls_len) decls_len: {
3025 const decls_len = zir.extra[extra_index];
3026 extra_index += 1;
3027 break :decls_len decls_len;
3028 } else 0;
3029
3030 return declIteratorInner(zir, extra_index, decls_len);
3031 },
30033032 else => unreachable,
30043033 }
30053034 },
......@@ -3037,13 +3066,6 @@ fn findDeclsInner(
30373066 const datas = zir.instructions.items(.data);
30383067
30393068 switch (tags[inst]) {
3040 // Decl instructions are interesting but have no body.
3041 // TODO yes they do have a body actually. recurse over them just like block instructions.
3042 .opaque_decl,
3043 .opaque_decl_anon,
3044 .opaque_decl_func,
3045 => return list.append(inst),
3046
30473069 // Functions instructions are interesting and have a body.
30483070 .func,
30493071 .func_inferred,
......@@ -3071,9 +3093,12 @@ fn findDeclsInner(
30713093 return zir.findDeclsBody(list, body);
30723094 },
30733095
3096 // Decl instructions are interesting but have no body.
3097 // TODO yes they do have a body actually. recurse over them just like block instructions.
30743098 .struct_decl,
30753099 .union_decl,
30763100 .enum_decl,
3101 .opaque_decl,
30773102 => return list.append(inst),
30783103
30793104 else => return,
src/print_zir.zig+37-16
......@@ -26,7 +26,7 @@ pub fn renderAsTextToFile(
2626 .parent_decl_node = 0,
2727 };
2828
29 const main_struct_inst = scope_file.zir.getMainStruct();
29 const main_struct_inst = Zir.main_struct_inst;
3030 try fs_file.writer().print("%{d} ", .{main_struct_inst});
3131 try writer.writeInstToStream(fs_file.writer(), main_struct_inst);
3232 try fs_file.writeAll("\n");
......@@ -171,6 +171,7 @@ const Writer = struct {
171171 .ref,
172172 .ret_coerce,
173173 .ensure_err_payload_void,
174 .closure_capture,
174175 => try self.writeUnTok(stream, inst),
175176
176177 .bool_br_and,
......@@ -307,10 +308,6 @@ const Writer = struct {
307308 .condbr_inline,
308309 => try self.writePlNodeCondBr(stream, inst),
309310
310 .opaque_decl => try self.writeOpaqueDecl(stream, inst, .parent),
311 .opaque_decl_anon => try self.writeOpaqueDecl(stream, inst, .anon),
312 .opaque_decl_func => try self.writeOpaqueDecl(stream, inst, .func),
313
314311 .error_set_decl => try self.writeErrorSetDecl(stream, inst, .parent),
315312 .error_set_decl_anon => try self.writeErrorSetDecl(stream, inst, .anon),
316313 .error_set_decl_func => try self.writeErrorSetDecl(stream, inst, .func),
......@@ -371,6 +368,8 @@ const Writer = struct {
371368
372369 .dbg_stmt => try self.writeDbgStmt(stream, inst),
373370
371 .closure_get => try self.writeInstNode(stream, inst),
372
374373 .extended => try self.writeExtended(stream, inst),
375374 }
376375 }
......@@ -412,6 +411,7 @@ const Writer = struct {
412411 .struct_decl => try self.writeStructDecl(stream, extended),
413412 .union_decl => try self.writeUnionDecl(stream, extended),
414413 .enum_decl => try self.writeEnumDecl(stream, extended),
414 .opaque_decl => try self.writeOpaqueDecl(stream, extended),
415415
416416 .c_undef, .c_include => {
417417 const inst_data = self.code.extraData(Zir.Inst.UnNode, extended.operand).data;
......@@ -745,6 +745,17 @@ const Writer = struct {
745745 try self.writeSrc(stream, src);
746746 }
747747
748 fn writeInstNode(
749 self: *Writer,
750 stream: anytype,
751 inst: Zir.Inst.Index,
752 ) (@TypeOf(stream).Error || error{OutOfMemory})!void {
753 const inst_data = self.code.instructions.items(.data)[inst].inst_node;
754 try self.writeInstIndex(stream, inst_data.inst);
755 try stream.writeAll(") ");
756 try self.writeSrc(stream, inst_data.src());
757 }
758
748759 fn writeAsm(self: *Writer, stream: anytype, extended: Zir.Inst.Extended.InstData) !void {
749760 const extra = self.code.extraData(Zir.Inst.Asm, extended.operand);
750761 const src: LazySrcLoc = .{ .node_offset = extra.data.src_node };
......@@ -1365,26 +1376,36 @@ const Writer = struct {
13651376 fn writeOpaqueDecl(
13661377 self: *Writer,
13671378 stream: anytype,
1368 inst: Zir.Inst.Index,
1369 name_strategy: Zir.Inst.NameStrategy,
1379 extended: Zir.Inst.Extended.InstData,
13701380 ) !void {
1371 const inst_data = self.code.instructions.items(.data)[inst].pl_node;
1372 const extra = self.code.extraData(Zir.Inst.OpaqueDecl, inst_data.payload_index);
1373 const decls_len = extra.data.decls_len;
1381 const small = @bitCast(Zir.Inst.OpaqueDecl.Small, extended.small);
1382 var extra_index: usize = extended.operand;
13741383
1375 try stream.print("{s}, ", .{@tagName(name_strategy)});
1384 const src_node: ?i32 = if (small.has_src_node) blk: {
1385 const src_node = @bitCast(i32, self.code.extra[extra_index]);
1386 extra_index += 1;
1387 break :blk src_node;
1388 } else null;
1389
1390 const decls_len = if (small.has_decls_len) blk: {
1391 const decls_len = self.code.extra[extra_index];
1392 extra_index += 1;
1393 break :blk decls_len;
1394 } else 0;
1395
1396 try stream.print("{s}, ", .{@tagName(small.name_strategy)});
13761397
13771398 if (decls_len == 0) {
1378 try stream.writeAll("}) ");
1399 try stream.writeAll("{})");
13791400 } else {
1380 try stream.writeAll("\n");
1401 try stream.writeAll("{\n");
13811402 self.indent += 2;
1382 _ = try self.writeDecls(stream, decls_len, extra.end);
1403 _ = try self.writeDecls(stream, decls_len, extra_index);
13831404 self.indent -= 2;
13841405 try stream.writeByteNTimes(' ', self.indent);
1385 try stream.writeAll("}) ");
1406 try stream.writeAll("})");
13861407 }
1387 try self.writeSrc(stream, inst_data.src());
1408 try self.writeSrcNode(stream, src_node);
13881409 }
13891410
13901411 fn writeErrorSetDecl(
test/behavior.zig+10-9
......@@ -1,20 +1,22 @@
11const builtin = @import("builtin");
22
33test {
4 _ = @import("behavior/bool.zig");
4 // Tests that pass for both.
5 _ = @import("behavior/array.zig");
6 _ = @import("behavior/atomics.zig");
57 _ = @import("behavior/basic.zig");
6 _ = @import("behavior/generics.zig");
8 _ = @import("behavior/bool.zig");
9 _ = @import("behavior/cast.zig");
710 _ = @import("behavior/eval.zig");
8 _ = @import("behavior/pointers.zig");
11 _ = @import("behavior/generics.zig");
912 _ = @import("behavior/if.zig");
10 _ = @import("behavior/cast.zig");
11 _ = @import("behavior/array.zig");
12 _ = @import("behavior/usingnamespace.zig");
13 _ = @import("behavior/atomics.zig");
13 _ = @import("behavior/pointers.zig");
1414 _ = @import("behavior/sizeof_and_typeof.zig");
15 _ = @import("behavior/translate_c_macros.zig");
1615 _ = @import("behavior/struct.zig");
16 _ = @import("behavior/this.zig");
17 _ = @import("behavior/translate_c_macros.zig");
1718 _ = @import("behavior/union.zig");
19 _ = @import("behavior/usingnamespace.zig");
1820 _ = @import("behavior/widening.zig");
1921
2022 if (builtin.zig_is_stage2) {
......@@ -142,7 +144,6 @@ test {
142144 _ = @import("behavior/switch.zig");
143145 _ = @import("behavior/switch_prong_err_enum.zig");
144146 _ = @import("behavior/switch_prong_implicit_cast.zig");
145 _ = @import("behavior/this.zig");
146147 _ = @import("behavior/truncate.zig");
147148 _ = @import("behavior/try.zig");
148149 _ = @import("behavior/tuple.zig");
test/behavior/this.zig+4-5
......@@ -24,11 +24,10 @@ test "this refer to module call private fn" {
2424}
2525
2626test "this refer to container" {
27 var pt = Point(i32){
28 .x = 12,
29 .y = 34,
30 };
31 pt.addOne();
27 var pt: Point(i32) = undefined;
28 pt.x = 12;
29 pt.y = 34;
30 Point(i32).addOne(&pt);
3231 try expect(pt.x == 13);
3332 try expect(pt.y == 35);
3433}