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 {...@@ -124,7 +124,7 @@ pub fn generate(gpa: *Allocator, tree: Ast) Allocator.Error!Zir {
124 container_decl,124 container_decl,
125 .Auto,125 .Auto,
126 )) |struct_decl_ref| {126 )) |struct_decl_ref| {
127 astgen.extra.items[@enumToInt(Zir.ExtraIndex.main_struct)] = @enumToInt(struct_decl_ref);127 assert(refToIndex(struct_decl_ref).? == 0);
128 } else |err| switch (err) {128 } else |err| switch (err) {
129 error.OutOfMemory => return error.OutOfMemory,129 error.OutOfMemory => return error.OutOfMemory,
130 error.AnalysisFail => {}, // Handled via compile_errors below.130 error.AnalysisFail => {}, // Handled via compile_errors below.
...@@ -2078,9 +2078,6 @@ fn unusedResultExpr(gz: *GenZir, scope: *Scope, statement: Ast.Node.Index) Inner...@@ -2078,9 +2078,6 @@ fn unusedResultExpr(gz: *GenZir, scope: *Scope, statement: Ast.Node.Index) Inner
2078 .union_init_ptr,2078 .union_init_ptr,
2079 .field_type,2079 .field_type,
2080 .field_type_ref,2080 .field_type_ref,
2081 .opaque_decl,
2082 .opaque_decl_anon,
2083 .opaque_decl_func,
2084 .error_set_decl,2081 .error_set_decl,
2085 .error_set_decl_anon,2082 .error_set_decl_anon,
2086 .error_set_decl_func,2083 .error_set_decl_func,
...@@ -2162,6 +2159,7 @@ fn unusedResultExpr(gz: *GenZir, scope: *Scope, statement: Ast.Node.Index) Inner...@@ -2162,6 +2159,7 @@ fn unusedResultExpr(gz: *GenZir, scope: *Scope, statement: Ast.Node.Index) Inner
2162 .await_nosuspend,2159 .await_nosuspend,
2163 .ret_err_value_code,2160 .ret_err_value_code,
2164 .extended,2161 .extended,
2162 .closure_get,
2165 => break :b false,2163 => break :b false,
21662164
2167 // ZIR instructions that are always `noreturn`.2165 // ZIR instructions that are always `noreturn`.
...@@ -2205,6 +2203,7 @@ fn unusedResultExpr(gz: *GenZir, scope: *Scope, statement: Ast.Node.Index) Inner...@@ -2205,6 +2203,7 @@ fn unusedResultExpr(gz: *GenZir, scope: *Scope, statement: Ast.Node.Index) Inner
2205 .set_cold,2203 .set_cold,
2206 .set_float_mode,2204 .set_float_mode,
2207 .set_runtime_safety,2205 .set_runtime_safety,
2206 .closure_capture,
2208 => break :b true,2207 => break :b true,
2209 }2208 }
2210 } else switch (maybe_unused_result) {2209 } else switch (maybe_unused_result) {
...@@ -3534,8 +3533,9 @@ fn structDeclInner(...@@ -3534,8 +3533,9 @@ fn structDeclInner(
3534 container_decl: Ast.full.ContainerDecl,3533 container_decl: Ast.full.ContainerDecl,
3535 layout: std.builtin.TypeInfo.ContainerLayout,3534 layout: std.builtin.TypeInfo.ContainerLayout,
3536) InnerError!Zir.Inst.Ref {3535) InnerError!Zir.Inst.Ref {
3536 const decl_inst = try gz.reserveInstructionIndex();
3537
3537 if (container_decl.ast.members.len == 0) {3538 if (container_decl.ast.members.len == 0) {
3538 const decl_inst = try gz.reserveInstructionIndex();
3539 try gz.setStruct(decl_inst, .{3539 try gz.setStruct(decl_inst, .{
3540 .src_node = node,3540 .src_node = node,
3541 .layout = layout,3541 .layout = layout,
...@@ -3553,11 +3553,19 @@ fn structDeclInner(...@@ -3553,11 +3553,19 @@ fn structDeclInner(
3553 const node_tags = tree.nodes.items(.tag);3553 const node_tags = tree.nodes.items(.tag);
3554 const node_datas = tree.nodes.items(.data);3554 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
3556 // The struct_decl instruction introduces a scope in which the decls of the struct3564 // The struct_decl instruction introduces a scope in which the decls of the struct
3557 // are in scope, so that field types, alignments, and default value expressions3565 // are in scope, so that field types, alignments, and default value expressions
3558 // can refer to decls within the struct itself.3566 // can refer to decls within the struct itself.
3559 var block_scope: GenZir = .{3567 var block_scope: GenZir = .{
3560 .parent = scope,3568 .parent = &namespace.base,
3561 .decl_node_index = node,3569 .decl_node_index = node,
3562 .decl_line = gz.calcLine(node),3570 .decl_line = gz.calcLine(node),
3563 .astgen = astgen,3571 .astgen = astgen,
...@@ -3566,9 +3574,6 @@ fn structDeclInner(...@@ -3566,9 +3574,6 @@ fn structDeclInner(
3566 };3574 };
3567 defer block_scope.instructions.deinit(gpa);3575 defer block_scope.instructions.deinit(gpa);
35683576
3569 var namespace: Scope.Namespace = .{ .parent = scope, .node = node };
3570 defer namespace.decls.deinit(gpa);
3571
3572 try astgen.scanDecls(&namespace, container_decl.ast.members);3577 try astgen.scanDecls(&namespace, container_decl.ast.members);
35733578
3574 var wip_decls: WipDecls = .{};3579 var wip_decls: WipDecls = .{};
...@@ -3773,7 +3778,6 @@ fn structDeclInner(...@@ -3773,7 +3778,6 @@ fn structDeclInner(
3773 }3778 }
3774 }3779 }
37753780
3776 const decl_inst = try gz.reserveInstructionIndex();
3777 if (block_scope.instructions.items.len != 0) {3781 if (block_scope.instructions.items.len != 0) {
3778 _ = try block_scope.addBreak(.break_inline, decl_inst, .void_value);3782 _ = try block_scope.addBreak(.break_inline, decl_inst, .void_value);
3779 }3783 }
...@@ -3787,11 +3791,18 @@ fn structDeclInner(...@@ -3787,11 +3791,18 @@ fn structDeclInner(
3787 .known_has_bits = known_has_bits,3791 .known_has_bits = known_has_bits,
3788 });3792 });
37893793
3790 try astgen.extra.ensureUnusedCapacity(gpa, bit_bag.items.len +3794 // zig fmt: off
3791 @boolToInt(field_index != 0) + fields_data.items.len +3795 try astgen.extra.ensureUnusedCapacity(gpa,
3796 bit_bag.items.len +
3797 @boolToInt(wip_decls.decl_index != 0) +
3798 wip_decls.payload.items.len +
3792 block_scope.instructions.items.len +3799 block_scope.instructions.items.len +
3793 wip_decls.bit_bag.items.len + @boolToInt(wip_decls.decl_index != 0) +3800 wip_decls.bit_bag.items.len +
3794 wip_decls.payload.items.len);3801 @boolToInt(field_index != 0) +
3802 fields_data.items.len
3803 );
3804 // zig fmt: on
3805
3795 astgen.extra.appendSliceAssumeCapacity(wip_decls.bit_bag.items); // Likely empty.3806 astgen.extra.appendSliceAssumeCapacity(wip_decls.bit_bag.items); // Likely empty.
3796 if (wip_decls.decl_index != 0) {3807 if (wip_decls.decl_index != 0) {
3797 astgen.extra.appendAssumeCapacity(wip_decls.cur_bit_bag);3808 astgen.extra.appendAssumeCapacity(wip_decls.cur_bit_bag);
...@@ -3818,17 +3829,27 @@ fn unionDeclInner(...@@ -3818,17 +3829,27 @@ fn unionDeclInner(
3818 arg_node: Ast.Node.Index,3829 arg_node: Ast.Node.Index,
3819 have_auto_enum: bool,3830 have_auto_enum: bool,
3820) InnerError!Zir.Inst.Ref {3831) InnerError!Zir.Inst.Ref {
3832 const decl_inst = try gz.reserveInstructionIndex();
3833
3821 const astgen = gz.astgen;3834 const astgen = gz.astgen;
3822 const gpa = astgen.gpa;3835 const gpa = astgen.gpa;
3823 const tree = astgen.tree;3836 const tree = astgen.tree;
3824 const node_tags = tree.nodes.items(.tag);3837 const node_tags = tree.nodes.items(.tag);
3825 const node_datas = tree.nodes.items(.data);3838 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
3827 // The union_decl instruction introduces a scope in which the decls of the union3848 // The union_decl instruction introduces a scope in which the decls of the union
3828 // are in scope, so that field types, alignments, and default value expressions3849 // are in scope, so that field types, alignments, and default value expressions
3829 // can refer to decls within the union itself.3850 // can refer to decls within the union itself.
3830 var block_scope: GenZir = .{3851 var block_scope: GenZir = .{
3831 .parent = scope,3852 .parent = &namespace.base,
3832 .decl_node_index = node,3853 .decl_node_index = node,
3833 .decl_line = gz.calcLine(node),3854 .decl_line = gz.calcLine(node),
3834 .astgen = astgen,3855 .astgen = astgen,
...@@ -3837,13 +3858,10 @@ fn unionDeclInner(...@@ -3837,13 +3858,10 @@ fn unionDeclInner(
3837 };3858 };
3838 defer block_scope.instructions.deinit(gpa);3859 defer block_scope.instructions.deinit(gpa);
38393860
3840 var namespace: Scope.Namespace = .{ .parent = scope, .node = node };
3841 defer namespace.decls.deinit(gpa);
3842
3843 try astgen.scanDecls(&namespace, members);3861 try astgen.scanDecls(&namespace, members);
38443862
3845 const arg_inst: Zir.Inst.Ref = if (arg_node != 0)3863 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)
3847 else3865 else
3848 .none;3866 .none;
38493867
...@@ -4056,7 +4074,6 @@ fn unionDeclInner(...@@ -4056,7 +4074,6 @@ fn unionDeclInner(
4056 }4074 }
4057 }4075 }
40584076
4059 const decl_inst = try gz.reserveInstructionIndex();
4060 if (block_scope.instructions.items.len != 0) {4077 if (block_scope.instructions.items.len != 0) {
4061 _ = try block_scope.addBreak(.break_inline, decl_inst, .void_value);4078 _ = try block_scope.addBreak(.break_inline, decl_inst, .void_value);
4062 }4079 }
...@@ -4071,11 +4088,18 @@ fn unionDeclInner(...@@ -4071,11 +4088,18 @@ fn unionDeclInner(
4071 .auto_enum_tag = have_auto_enum,4088 .auto_enum_tag = have_auto_enum,
4072 });4089 });
40734090
4074 try astgen.extra.ensureUnusedCapacity(gpa, bit_bag.items.len +4091 // zig fmt: off
4075 1 + fields_data.items.len +4092 try astgen.extra.ensureUnusedCapacity(gpa,
4093 bit_bag.items.len +
4094 @boolToInt(wip_decls.decl_index != 0) +
4095 wip_decls.payload.items.len +
4076 block_scope.instructions.items.len +4096 block_scope.instructions.items.len +
4077 wip_decls.bit_bag.items.len + @boolToInt(wip_decls.decl_index != 0) +4097 wip_decls.bit_bag.items.len +
4078 wip_decls.payload.items.len);4098 1 + // cur_bit_bag
4099 fields_data.items.len
4100 );
4101 // zig fmt: on
4102
4079 astgen.extra.appendSliceAssumeCapacity(wip_decls.bit_bag.items); // Likely empty.4103 astgen.extra.appendSliceAssumeCapacity(wip_decls.bit_bag.items); // Likely empty.
4080 if (wip_decls.decl_index != 0) {4104 if (wip_decls.decl_index != 0) {
4081 astgen.extra.appendAssumeCapacity(wip_decls.cur_bit_bag);4105 astgen.extra.appendAssumeCapacity(wip_decls.cur_bit_bag);
...@@ -4238,10 +4262,20 @@ fn containerDecl(...@@ -4238,10 +4262,20 @@ fn containerDecl(
4238 // how structs are handled above.4262 // how structs are handled above.
4239 const nonexhaustive = counts.nonexhaustive_node != 0;4263 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
4241 // The enum_decl instruction introduces a scope in which the decls of the enum4275 // The enum_decl instruction introduces a scope in which the decls of the enum
4242 // are in scope, so that tag values can refer to decls within the enum itself.4276 // are in scope, so that tag values can refer to decls within the enum itself.
4243 var block_scope: GenZir = .{4277 var block_scope: GenZir = .{
4244 .parent = scope,4278 .parent = &namespace.base,
4245 .decl_node_index = node,4279 .decl_node_index = node,
4246 .decl_line = gz.calcLine(node),4280 .decl_line = gz.calcLine(node),
4247 .astgen = astgen,4281 .astgen = astgen,
...@@ -4250,13 +4284,10 @@ fn containerDecl(...@@ -4250,13 +4284,10 @@ fn containerDecl(
4250 };4284 };
4251 defer block_scope.instructions.deinit(gpa);4285 defer block_scope.instructions.deinit(gpa);
42524286
4253 var namespace: Scope.Namespace = .{ .parent = scope, .node = node };
4254 defer namespace.decls.deinit(gpa);
4255
4256 try astgen.scanDecls(&namespace, container_decl.ast.members);4287 try astgen.scanDecls(&namespace, container_decl.ast.members);
42574288
4258 const arg_inst: Zir.Inst.Ref = if (container_decl.ast.arg != 0)4289 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)
4260 else4291 else
4261 .none;4292 .none;
42624293
...@@ -4451,7 +4482,6 @@ fn containerDecl(...@@ -4451,7 +4482,6 @@ fn containerDecl(
4451 }4482 }
4452 }4483 }
44534484
4454 const decl_inst = try gz.reserveInstructionIndex();
4455 if (block_scope.instructions.items.len != 0) {4485 if (block_scope.instructions.items.len != 0) {
4456 _ = try block_scope.addBreak(.break_inline, decl_inst, .void_value);4486 _ = try block_scope.addBreak(.break_inline, decl_inst, .void_value);
4457 }4487 }
...@@ -4465,11 +4495,18 @@ fn containerDecl(...@@ -4465,11 +4495,18 @@ fn containerDecl(
4465 .decls_len = @intCast(u32, wip_decls.decl_index),4495 .decls_len = @intCast(u32, wip_decls.decl_index),
4466 });4496 });
44674497
4468 try astgen.extra.ensureUnusedCapacity(gpa, bit_bag.items.len +4498 // zig fmt: off
4469 1 + fields_data.items.len +4499 try astgen.extra.ensureUnusedCapacity(gpa,
4500 bit_bag.items.len +
4501 @boolToInt(wip_decls.decl_index != 0) +
4502 wip_decls.payload.items.len +
4470 block_scope.instructions.items.len +4503 block_scope.instructions.items.len +
4471 wip_decls.bit_bag.items.len + @boolToInt(wip_decls.decl_index != 0) +4504 wip_decls.bit_bag.items.len +
4472 wip_decls.payload.items.len);4505 1 + // cur_bit_bag
4506 fields_data.items.len
4507 );
4508 // zig fmt: on
4509
4473 astgen.extra.appendSliceAssumeCapacity(wip_decls.bit_bag.items); // Likely empty.4510 astgen.extra.appendSliceAssumeCapacity(wip_decls.bit_bag.items); // Likely empty.
4474 if (wip_decls.decl_index != 0) {4511 if (wip_decls.decl_index != 0) {
4475 astgen.extra.appendAssumeCapacity(wip_decls.cur_bit_bag);4512 astgen.extra.appendAssumeCapacity(wip_decls.cur_bit_bag);
...@@ -4486,8 +4523,15 @@ fn containerDecl(...@@ -4486,8 +4523,15 @@ fn containerDecl(
4486 .keyword_opaque => {4523 .keyword_opaque => {
4487 assert(container_decl.ast.arg == 0);4524 assert(container_decl.ast.arg == 0);
44884525
4489 var namespace: Scope.Namespace = .{ .parent = scope, .node = node };4526 const decl_inst = try gz.reserveInstructionIndex();
4490 defer namespace.decls.deinit(gpa);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
4492 try astgen.scanDecls(&namespace, container_decl.ast.members);4536 try astgen.scanDecls(&namespace, container_decl.ast.members);
44934537
...@@ -4625,21 +4669,20 @@ fn containerDecl(...@@ -4625,21 +4669,20 @@ fn containerDecl(
4625 wip_decls.cur_bit_bag >>= @intCast(u5, empty_slot_count * WipDecls.bits_per_field);4669 wip_decls.cur_bit_bag >>= @intCast(u5, empty_slot_count * WipDecls.bits_per_field);
4626 }4670 }
4627 }4671 }
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 +4673 try gz.setOpaque(decl_inst, .{
4637 wip_decls.bit_bag.items.len + @boolToInt(wip_decls.decl_index != 0) +4674 .src_node = node,
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{
4641 .decls_len = @intCast(u32, wip_decls.decl_index),4675 .decls_len = @intCast(u32, wip_decls.decl_index),
4642 });4676 });
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
4643 astgen.extra.appendSliceAssumeCapacity(wip_decls.bit_bag.items); // Likely empty.4686 astgen.extra.appendSliceAssumeCapacity(wip_decls.bit_bag.items); // Likely empty.
4644 if (wip_decls.decl_index != 0) {4687 if (wip_decls.decl_index != 0) {
4645 astgen.extra.appendAssumeCapacity(wip_decls.cur_bit_bag);4688 astgen.extra.appendAssumeCapacity(wip_decls.cur_bit_bag);
...@@ -6380,6 +6423,7 @@ fn identifier(...@@ -6380,6 +6423,7 @@ fn identifier(
63806423
6381 const astgen = gz.astgen;6424 const astgen = gz.astgen;
6382 const tree = astgen.tree;6425 const tree = astgen.tree;
6426 const gpa = astgen.gpa;
6383 const main_tokens = tree.nodes.items(.main_token);6427 const main_tokens = tree.nodes.items(.main_token);
63846428
6385 const ident_token = main_tokens[ident];6429 const ident_token = main_tokens[ident];
...@@ -6426,16 +6470,28 @@ fn identifier(...@@ -6426,16 +6470,28 @@ fn identifier(
6426 const name_str_index = try astgen.identAsString(ident_token);6470 const name_str_index = try astgen.identAsString(ident_token);
6427 var s = scope;6471 var s = scope;
6428 var found_already: ?Ast.Node.Index = null; // we have found a decl with the same name already6472 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;
6430 while (true) switch (s.tag) {6475 while (true) switch (s.tag) {
6431 .local_val => {6476 .local_val => {
6432 const local_val = s.cast(Scope.LocalVal).?;6477 const local_val = s.cast(Scope.LocalVal).?;
64336478
6434 if (local_val.name == name_str_index) {6479 if (local_val.name == name_str_index) {
6435 local_val.used = true;
6436 // Locals cannot shadow anything, so we do not need to look for ambiguous6480 // Locals cannot shadow anything, so we do not need to look for ambiguous
6437 // references in this case.6481 // 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);
6439 }6495 }
6440 s = local_val.parent;6496 s = local_val.parent;
6441 },6497 },
...@@ -6443,16 +6499,29 @@ fn identifier(...@@ -6443,16 +6499,29 @@ fn identifier(
6443 const local_ptr = s.cast(Scope.LocalPtr).?;6499 const local_ptr = s.cast(Scope.LocalPtr).?;
6444 if (local_ptr.name == name_str_index) {6500 if (local_ptr.name == name_str_index) {
6445 local_ptr.used = true;6501 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) {
6447 return astgen.failNodeNotes(ident, "mutable '{s}' not accessible from here", .{ident_name}, &.{6505 return astgen.failNodeNotes(ident, "mutable '{s}' not accessible from here", .{ident_name}, &.{
6448 try astgen.errNoteTok(local_ptr.token_src, "declared mutable here", .{}),6506 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", .{}),
6450 });6508 });
6451 }6509 }
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
6452 switch (rl) {6521 switch (rl) {
6453 .ref, .none_or_ref => return local_ptr.ptr,6522 .ref, .none_or_ref => return ptr_inst,
6454 else => {6523 else => {
6455 const loaded = try gz.addUnNode(.load, local_ptr.ptr, ident);6524 const loaded = try gz.addUnNode(.load, ptr_inst, ident);
6456 return rvalue(gz, rl, loaded, ident);6525 return rvalue(gz, rl, loaded, ident);
6457 },6526 },
6458 }6527 }
...@@ -6473,7 +6542,8 @@ fn identifier(...@@ -6473,7 +6542,8 @@ fn identifier(
6473 // We found a match but must continue looking for ambiguous references to decls.6542 // We found a match but must continue looking for ambiguous references to decls.
6474 found_already = i;6543 found_already = i;
6475 }6544 }
6476 hit_namespace = ns.node;6545 num_namespaces_out += 1;
6546 capturing_namespace = ns;
6477 s = ns.parent;6547 s = ns.parent;
6478 },6548 },
6479 .top => break,6549 .top => break,
...@@ -6493,6 +6563,37 @@ fn identifier(...@@ -6493,6 +6563,37 @@ fn identifier(
6493 }6563 }
6494}6564}
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
6496fn stringLiteral(6597fn stringLiteral(
6497 gz: *GenZir,6598 gz: *GenZir,
6498 rl: ResultLoc,6599 rl: ResultLoc,
...@@ -8961,6 +9062,17 @@ const Scope = struct {...@@ -8961,6 +9062,17 @@ const Scope = struct {
8961 return @fieldParentPtr(T, "base", base);9062 return @fieldParentPtr(T, "base", base);
8962 }9063 }
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
8964 const Tag = enum {9076 const Tag = enum {
8965 gen_zir,9077 gen_zir,
8966 local_val,9078 local_val,
...@@ -8986,7 +9098,7 @@ const Scope = struct {...@@ -8986,7 +9098,7 @@ const Scope = struct {
8986 const LocalVal = struct {9098 const LocalVal = struct {
8987 const base_tag: Tag = .local_val;9099 const base_tag: Tag = .local_val;
8988 base: Scope = Scope{ .tag = base_tag },9100 base: Scope = Scope{ .tag = base_tag },
8989 /// Parents can be: `LocalVal`, `LocalPtr`, `GenZir`, `Defer`.9101 /// Parents can be: `LocalVal`, `LocalPtr`, `GenZir`, `Defer`, `Namespace`.
8990 parent: *Scope,9102 parent: *Scope,
8991 gen_zir: *GenZir,9103 gen_zir: *GenZir,
8992 inst: Zir.Inst.Ref,9104 inst: Zir.Inst.Ref,
...@@ -9005,7 +9117,7 @@ const Scope = struct {...@@ -9005,7 +9117,7 @@ const Scope = struct {
9005 const LocalPtr = struct {9117 const LocalPtr = struct {
9006 const base_tag: Tag = .local_ptr;9118 const base_tag: Tag = .local_ptr;
9007 base: Scope = Scope{ .tag = base_tag },9119 base: Scope = Scope{ .tag = base_tag },
9008 /// Parents can be: `LocalVal`, `LocalPtr`, `GenZir`, `Defer`.9120 /// Parents can be: `LocalVal`, `LocalPtr`, `GenZir`, `Defer`, `Namespace`.
9009 parent: *Scope,9121 parent: *Scope,
9010 gen_zir: *GenZir,9122 gen_zir: *GenZir,
9011 ptr: Zir.Inst.Ref,9123 ptr: Zir.Inst.Ref,
...@@ -9023,7 +9135,7 @@ const Scope = struct {...@@ -9023,7 +9135,7 @@ const Scope = struct {
90239135
9024 const Defer = struct {9136 const Defer = struct {
9025 base: Scope,9137 base: Scope,
9026 /// Parents can be: `LocalVal`, `LocalPtr`, `GenZir`, `Defer`.9138 /// Parents can be: `LocalVal`, `LocalPtr`, `GenZir`, `Defer`, `Namespace`.
9027 parent: *Scope,9139 parent: *Scope,
9028 defer_node: Ast.Node.Index,9140 defer_node: Ast.Node.Index,
9029 };9141 };
...@@ -9034,11 +9146,27 @@ const Scope = struct {...@@ -9034,11 +9146,27 @@ const Scope = struct {
9034 const base_tag: Tag = .namespace;9146 const base_tag: Tag = .namespace;
9035 base: Scope = Scope{ .tag = base_tag },9147 base: Scope = Scope{ .tag = base_tag },
90369148
9149 /// Parents can be: `LocalVal`, `LocalPtr`, `GenZir`, `Defer`, `Namespace`.
9037 parent: *Scope,9150 parent: *Scope,
9038 /// Maps string table index to the source location of declaration,9151 /// Maps string table index to the source location of declaration,
9039 /// for the purposes of reporting name shadowing compile errors.9152 /// for the purposes of reporting name shadowing compile errors.
9040 decls: std.AutoHashMapUnmanaged(u32, Ast.Node.Index) = .{},9153 decls: std.AutoHashMapUnmanaged(u32, Ast.Node.Index) = .{},
9041 node: Ast.Node.Index,9154 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 }
9042 };9170 };
90439171
9044 const Top = struct {9172 const Top = struct {
...@@ -9061,6 +9189,7 @@ const GenZir = struct {...@@ -9061,6 +9189,7 @@ const GenZir = struct {
9061 decl_node_index: Ast.Node.Index,9189 decl_node_index: Ast.Node.Index,
9062 /// The containing decl line index, absolute.9190 /// The containing decl line index, absolute.
9063 decl_line: u32,9191 decl_line: u32,
9192 /// Parents can be: `LocalVal`, `LocalPtr`, `GenZir`, `Defer`, `Namespace`.
9064 parent: *Scope,9193 parent: *Scope,
9065 /// All `GenZir` scopes for the same ZIR share this.9194 /// All `GenZir` scopes for the same ZIR share this.
9066 astgen: *AstGen,9195 astgen: *AstGen,
...@@ -9096,6 +9225,12 @@ const GenZir = struct {...@@ -9096,6 +9225,12 @@ const GenZir = struct {
9096 suspend_node: Ast.Node.Index = 0,9225 suspend_node: Ast.Node.Index = 0,
9097 nosuspend_node: Ast.Node.Index = 0,9226 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
9099 fn makeSubBlock(gz: *GenZir, scope: *Scope) GenZir {9234 fn makeSubBlock(gz: *GenZir, scope: *Scope) GenZir {
9100 return .{9235 return .{
9101 .force_comptime = gz.force_comptime,9236 .force_comptime = gz.force_comptime,
...@@ -9810,6 +9945,22 @@ const GenZir = struct {...@@ -9810,6 +9945,22 @@ const GenZir = struct {
9810 });9945 });
9811 }9946 }
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
9813 fn addNodeExtended(9964 fn addNodeExtended(
9814 gz: *GenZir,9965 gz: *GenZir,
9815 opcode: Zir.Inst.Extended,9966 opcode: Zir.Inst.Extended,
...@@ -10111,6 +10262,37 @@ const GenZir = struct {...@@ -10111,6 +10262,37 @@ const GenZir = struct {
10111 });10262 });
10112 }10263 }
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
10114 fn add(gz: *GenZir, inst: Zir.Inst) !Zir.Inst.Ref {10296 fn add(gz: *GenZir, inst: Zir.Inst) !Zir.Inst.Ref {
10115 return indexToRef(try gz.addAsIndex(inst));10297 return indexToRef(try gz.addAsIndex(inst));
10116 }10298 }
src/Module.zig+119-22
...@@ -275,6 +275,56 @@ pub const DeclPlusEmitH = struct {...@@ -275,6 +275,56 @@ pub const DeclPlusEmitH = struct {
275 emit_h: EmitH,275 emit_h: EmitH,
276};276};
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
278pub const Decl = struct {328pub const Decl = struct {
279 /// Allocated with Module's allocator; outlives the ZIR code.329 /// Allocated with Module's allocator; outlives the ZIR code.
280 name: [*:0]const u8,330 name: [*:0]const u8,
...@@ -290,7 +340,7 @@ pub const Decl = struct {...@@ -290,7 +340,7 @@ pub const Decl = struct {
290 linksection_val: Value,340 linksection_val: Value,
291 /// Populated when `has_tv`.341 /// Populated when `has_tv`.
292 @"addrspace": std.builtin.AddressSpace,342 @"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.
294 /// If this is `null` then there is no memory management needed.344 /// If this is `null` then there is no memory management needed.
295 value_arena: ?*std.heap.ArenaAllocator.State = null,345 value_arena: ?*std.heap.ArenaAllocator.State = null,
296 /// The direct parent namespace of the Decl.346 /// The direct parent namespace of the Decl.
...@@ -299,6 +349,11 @@ pub const Decl = struct {...@@ -299,6 +349,11 @@ pub const Decl = struct {
299 /// the namespace of the struct, since there is no parent.349 /// the namespace of the struct, since there is no parent.
300 namespace: *Scope.Namespace,350 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
302 /// An integer that can be checked against the corresponding incrementing357 /// An integer that can be checked against the corresponding incrementing
303 /// generation field of Module. This is used to determine whether `complete` status358 /// generation field of Module. This is used to determine whether `complete` status
304 /// represents pre- or post- re-analysis.359 /// represents pre- or post- re-analysis.
...@@ -959,6 +1014,7 @@ pub const Scope = struct {...@@ -959,6 +1014,7 @@ pub const Scope = struct {
959 return @fieldParentPtr(T, "base", base);1014 return @fieldParentPtr(T, "base", base);
960 }1015 }
9611016
1017 /// Get the decl that is currently being analyzed
962 pub fn ownerDecl(scope: *Scope) ?*Decl {1018 pub fn ownerDecl(scope: *Scope) ?*Decl {
963 return switch (scope.tag) {1019 return switch (scope.tag) {
964 .block => scope.cast(Block).?.sema.owner_decl,1020 .block => scope.cast(Block).?.sema.owner_decl,
...@@ -967,6 +1023,7 @@ pub const Scope = struct {...@@ -967,6 +1023,7 @@ pub const Scope = struct {
967 };1023 };
968 }1024 }
9691025
1026 /// Get the decl which contains this decl, for the purposes of source reporting
970 pub fn srcDecl(scope: *Scope) ?*Decl {1027 pub fn srcDecl(scope: *Scope) ?*Decl {
971 return switch (scope.tag) {1028 return switch (scope.tag) {
972 .block => scope.cast(Block).?.src_decl,1029 .block => scope.cast(Block).?.src_decl,
...@@ -975,6 +1032,15 @@ pub const Scope = struct {...@@ -975,6 +1032,15 @@ pub const Scope = struct {
975 };1032 };
976 }1033 }
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
978 /// Asserts the scope has a parent which is a Namespace and returns it.1044 /// Asserts the scope has a parent which is a Namespace and returns it.
979 pub fn namespace(scope: *Scope) *Namespace {1045 pub fn namespace(scope: *Scope) *Namespace {
980 switch (scope.tag) {1046 switch (scope.tag) {
...@@ -1311,6 +1377,9 @@ pub const Scope = struct {...@@ -1311,6 +1377,9 @@ pub const Scope = struct {
1311 instructions: ArrayListUnmanaged(Air.Inst.Index),1377 instructions: ArrayListUnmanaged(Air.Inst.Index),
1312 // `param` instructions are collected here to be used by the `func` instruction.1378 // `param` instructions are collected here to be used by the `func` instruction.
1313 params: std.ArrayListUnmanaged(Param) = .{},1379 params: std.ArrayListUnmanaged(Param) = .{},
1380
1381 wip_capture_scope: *CaptureScope,
1382
1314 label: ?*Label = null,1383 label: ?*Label = null,
1315 inlining: ?*Inlining,1384 inlining: ?*Inlining,
1316 /// If runtime_index is not 0 then one of these is guaranteed to be non null.1385 /// If runtime_index is not 0 then one of these is guaranteed to be non null.
...@@ -1372,6 +1441,7 @@ pub const Scope = struct {...@@ -1372,6 +1441,7 @@ pub const Scope = struct {
1372 .sema = parent.sema,1441 .sema = parent.sema,
1373 .src_decl = parent.src_decl,1442 .src_decl = parent.src_decl,
1374 .instructions = .{},1443 .instructions = .{},
1444 .wip_capture_scope = parent.wip_capture_scope,
1375 .label = null,1445 .label = null,
1376 .inlining = parent.inlining,1446 .inlining = parent.inlining,
1377 .is_comptime = parent.is_comptime,1447 .is_comptime = parent.is_comptime,
...@@ -2901,12 +2971,10 @@ pub fn mapOldZirToNew(...@@ -2901,12 +2971,10 @@ pub fn mapOldZirToNew(
2901 var match_stack: std.ArrayListUnmanaged(MatchedZirDecl) = .{};2971 var match_stack: std.ArrayListUnmanaged(MatchedZirDecl) = .{};
2902 defer match_stack.deinit(gpa);2972 defer match_stack.deinit(gpa);
29032973
2904 const old_main_struct_inst = old_zir.getMainStruct();2974 // Main struct inst is always the same
2905 const new_main_struct_inst = new_zir.getMainStruct();
2906
2907 try match_stack.append(gpa, .{2975 try match_stack.append(gpa, .{
2908 .old_inst = old_main_struct_inst,2976 .old_inst = Zir.main_struct_inst,
2909 .new_inst = new_main_struct_inst,2977 .new_inst = Zir.main_struct_inst,
2910 });2978 });
29112979
2912 var old_decls = std.ArrayList(Zir.Inst.Index).init(gpa);2980 var old_decls = std.ArrayList(Zir.Inst.Index).init(gpa);
...@@ -3064,6 +3132,7 @@ pub fn semaFile(mod: *Module, file: *Scope.File) SemaError!void {...@@ -3064,6 +3132,7 @@ pub fn semaFile(mod: *Module, file: *Scope.File) SemaError!void {
3064 const struct_obj = try new_decl_arena.allocator.create(Module.Struct);3132 const struct_obj = try new_decl_arena.allocator.create(Module.Struct);
3065 const struct_ty = try Type.Tag.@"struct".create(&new_decl_arena.allocator, struct_obj);3133 const struct_ty = try Type.Tag.@"struct".create(&new_decl_arena.allocator, struct_obj);
3066 const struct_val = try Value.Tag.ty.create(&new_decl_arena.allocator, struct_ty);3134 const struct_val = try Value.Tag.ty.create(&new_decl_arena.allocator, struct_ty);
3135 const ty_ty = comptime Type.initTag(.type);
3067 struct_obj.* = .{3136 struct_obj.* = .{
3068 .owner_decl = undefined, // set below3137 .owner_decl = undefined, // set below
3069 .fields = .{},3138 .fields = .{},
...@@ -3078,7 +3147,7 @@ pub fn semaFile(mod: *Module, file: *Scope.File) SemaError!void {...@@ -3078,7 +3147,7 @@ pub fn semaFile(mod: *Module, file: *Scope.File) SemaError!void {
3078 .file_scope = file,3147 .file_scope = file,
3079 },3148 },
3080 };3149 };
3081 const new_decl = try mod.allocateNewDecl(&struct_obj.namespace, 0);3150 const new_decl = try mod.allocateNewDecl(&struct_obj.namespace, 0, null);
3082 file.root_decl = new_decl;3151 file.root_decl = new_decl;
3083 struct_obj.owner_decl = new_decl;3152 struct_obj.owner_decl = new_decl;
3084 new_decl.src_line = 0;3153 new_decl.src_line = 0;
...@@ -3087,7 +3156,7 @@ pub fn semaFile(mod: *Module, file: *Scope.File) SemaError!void {...@@ -3087,7 +3156,7 @@ pub fn semaFile(mod: *Module, file: *Scope.File) SemaError!void {
3087 new_decl.is_exported = false;3156 new_decl.is_exported = false;
3088 new_decl.has_align = false;3157 new_decl.has_align = false;
3089 new_decl.has_linksection_or_addrspace = false;3158 new_decl.has_linksection_or_addrspace = false;
3090 new_decl.ty = struct_ty;3159 new_decl.ty = ty_ty;
3091 new_decl.val = struct_val;3160 new_decl.val = struct_val;
3092 new_decl.has_tv = true;3161 new_decl.has_tv = true;
3093 new_decl.owns_tv = true;3162 new_decl.owns_tv = true;
...@@ -3097,7 +3166,7 @@ pub fn semaFile(mod: *Module, file: *Scope.File) SemaError!void {...@@ -3097,7 +3166,7 @@ pub fn semaFile(mod: *Module, file: *Scope.File) SemaError!void {
30973166
3098 if (file.status == .success_zir) {3167 if (file.status == .success_zir) {
3099 assert(file.zir_loaded);3168 assert(file.zir_loaded);
3100 const main_struct_inst = file.zir.getMainStruct();3169 const main_struct_inst = Zir.main_struct_inst;
3101 struct_obj.zir_index = main_struct_inst;3170 struct_obj.zir_index = main_struct_inst;
31023171
3103 var sema_arena = std.heap.ArenaAllocator.init(gpa);3172 var sema_arena = std.heap.ArenaAllocator.init(gpa);
...@@ -3107,6 +3176,7 @@ pub fn semaFile(mod: *Module, file: *Scope.File) SemaError!void {...@@ -3107,6 +3176,7 @@ pub fn semaFile(mod: *Module, file: *Scope.File) SemaError!void {
3107 .mod = mod,3176 .mod = mod,
3108 .gpa = gpa,3177 .gpa = gpa,
3109 .arena = &sema_arena.allocator,3178 .arena = &sema_arena.allocator,
3179 .perm_arena = &new_decl_arena.allocator,
3110 .code = file.zir,3180 .code = file.zir,
3111 .owner_decl = new_decl,3181 .owner_decl = new_decl,
3112 .namespace = &struct_obj.namespace,3182 .namespace = &struct_obj.namespace,
...@@ -3115,10 +3185,15 @@ pub fn semaFile(mod: *Module, file: *Scope.File) SemaError!void {...@@ -3115,10 +3185,15 @@ pub fn semaFile(mod: *Module, file: *Scope.File) SemaError!void {
3115 .owner_func = null,3185 .owner_func = null,
3116 };3186 };
3117 defer sema.deinit();3187 defer sema.deinit();
3188
3189 var wip_captures = try WipCaptureScope.init(gpa, &new_decl_arena.allocator, null);
3190 defer wip_captures.deinit();
3191
3118 var block_scope: Scope.Block = .{3192 var block_scope: Scope.Block = .{
3119 .parent = null,3193 .parent = null,
3120 .sema = &sema,3194 .sema = &sema,
3121 .src_decl = new_decl,3195 .src_decl = new_decl,
3196 .wip_capture_scope = wip_captures.scope,
3122 .instructions = .{},3197 .instructions = .{},
3123 .inlining = null,3198 .inlining = null,
3124 .is_comptime = true,3199 .is_comptime = true,
...@@ -3126,6 +3201,7 @@ pub fn semaFile(mod: *Module, file: *Scope.File) SemaError!void {...@@ -3126,6 +3201,7 @@ pub fn semaFile(mod: *Module, file: *Scope.File) SemaError!void {
3126 defer block_scope.instructions.deinit(gpa);3201 defer block_scope.instructions.deinit(gpa);
31273202
3128 if (sema.analyzeStructDecl(new_decl, main_struct_inst, struct_obj)) |_| {3203 if (sema.analyzeStructDecl(new_decl, main_struct_inst, struct_obj)) |_| {
3204 try wip_captures.finalize();
3129 new_decl.analysis = .complete;3205 new_decl.analysis = .complete;
3130 } else |err| switch (err) {3206 } else |err| switch (err) {
3131 error.OutOfMemory => return error.OutOfMemory,3207 error.OutOfMemory => return error.OutOfMemory,
...@@ -3155,6 +3231,10 @@ fn semaDecl(mod: *Module, decl: *Decl) !bool {...@@ -3155,6 +3231,10 @@ fn semaDecl(mod: *Module, decl: *Decl) !bool {
31553231
3156 decl.analysis = .in_progress;3232 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
3158 var analysis_arena = std.heap.ArenaAllocator.init(gpa);3238 var analysis_arena = std.heap.ArenaAllocator.init(gpa);
3159 defer analysis_arena.deinit();3239 defer analysis_arena.deinit();
31603240
...@@ -3162,6 +3242,7 @@ fn semaDecl(mod: *Module, decl: *Decl) !bool {...@@ -3162,6 +3242,7 @@ fn semaDecl(mod: *Module, decl: *Decl) !bool {
3162 .mod = mod,3242 .mod = mod,
3163 .gpa = gpa,3243 .gpa = gpa,
3164 .arena = &analysis_arena.allocator,3244 .arena = &analysis_arena.allocator,
3245 .perm_arena = &decl_arena.allocator,
3165 .code = zir,3246 .code = zir,
3166 .owner_decl = decl,3247 .owner_decl = decl,
3167 .namespace = decl.namespace,3248 .namespace = decl.namespace,
...@@ -3173,7 +3254,7 @@ fn semaDecl(mod: *Module, decl: *Decl) !bool {...@@ -3173,7 +3254,7 @@ fn semaDecl(mod: *Module, decl: *Decl) !bool {
31733254
3174 if (decl.isRoot()) {3255 if (decl.isRoot()) {
3175 log.debug("semaDecl root {*} ({s})", .{ decl, decl.name });3256 log.debug("semaDecl root {*} ({s})", .{ decl, decl.name });
3176 const main_struct_inst = zir.getMainStruct();3257 const main_struct_inst = Zir.main_struct_inst;
3177 const struct_obj = decl.getStruct().?;3258 const struct_obj = decl.getStruct().?;
3178 // This might not have gotten set in `semaFile` if the first time had3259 // This might not have gotten set in `semaFile` if the first time had
3179 // a ZIR failure, so we set it here in case.3260 // a ZIR failure, so we set it here in case.
...@@ -3185,10 +3266,14 @@ fn semaDecl(mod: *Module, decl: *Decl) !bool {...@@ -3185,10 +3266,14 @@ fn semaDecl(mod: *Module, decl: *Decl) !bool {
3185 }3266 }
3186 log.debug("semaDecl {*} ({s})", .{ decl, decl.name });3267 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
3188 var block_scope: Scope.Block = .{3272 var block_scope: Scope.Block = .{
3189 .parent = null,3273 .parent = null,
3190 .sema = &sema,3274 .sema = &sema,
3191 .src_decl = decl,3275 .src_decl = decl,
3276 .wip_capture_scope = wip_captures.scope,
3192 .instructions = .{},3277 .instructions = .{},
3193 .inlining = null,3278 .inlining = null,
3194 .is_comptime = true,3279 .is_comptime = true,
...@@ -3203,6 +3288,7 @@ fn semaDecl(mod: *Module, decl: *Decl) !bool {...@@ -3203,6 +3288,7 @@ fn semaDecl(mod: *Module, decl: *Decl) !bool {
3203 const extra = zir.extraData(Zir.Inst.Block, inst_data.payload_index);3288 const extra = zir.extraData(Zir.Inst.Block, inst_data.payload_index);
3204 const body = zir.extra[extra.end..][0..extra.data.body_len];3289 const body = zir.extra[extra.end..][0..extra.data.body_len];
3205 const break_index = try sema.analyzeBody(&block_scope, body);3290 const break_index = try sema.analyzeBody(&block_scope, body);
3291 try wip_captures.finalize();
3206 const result_ref = zir_datas[break_index].@"break".operand;3292 const result_ref = zir_datas[break_index].@"break".operand;
3207 const src: LazySrcLoc = .{ .node_offset = 0 };3293 const src: LazySrcLoc = .{ .node_offset = 0 };
3208 const decl_tv = try sema.resolveInstValue(&block_scope, src, result_ref);3294 const decl_tv = try sema.resolveInstValue(&block_scope, src, result_ref);
...@@ -3239,9 +3325,6 @@ fn semaDecl(mod: *Module, decl: *Decl) !bool {...@@ -3239,9 +3325,6 @@ fn semaDecl(mod: *Module, decl: *Decl) !bool {
3239 // not the struct itself.3325 // not the struct itself.
3240 try sema.resolveTypeLayout(&block_scope, src, decl_tv.ty);3326 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();
3245 const decl_arena_state = try decl_arena.allocator.create(std.heap.ArenaAllocator.State);3328 const decl_arena_state = try decl_arena.allocator.create(std.heap.ArenaAllocator.State);
32463329
3247 if (decl.is_usingnamespace) {3330 if (decl.is_usingnamespace) {
...@@ -3638,7 +3721,7 @@ fn scanDecl(iter: *ScanDeclIter, decl_sub_index: usize, flags: u4) SemaError!voi...@@ -3638,7 +3721,7 @@ fn scanDecl(iter: *ScanDeclIter, decl_sub_index: usize, flags: u4) SemaError!voi
3638 // We create a Decl for it regardless of analysis status.3721 // We create a Decl for it regardless of analysis status.
3639 const gop = try namespace.decls.getOrPut(gpa, decl_name);3722 const gop = try namespace.decls.getOrPut(gpa, decl_name);
3640 if (!gop.found_existing) {3723 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);
3642 if (is_usingnamespace) {3725 if (is_usingnamespace) {
3643 namespace.usingnamespace_set.putAssumeCapacity(new_decl, is_pub);3726 namespace.usingnamespace_set.putAssumeCapacity(new_decl, is_pub);
3644 }3727 }
...@@ -3898,10 +3981,15 @@ pub fn analyzeFnBody(mod: *Module, decl: *Decl, func: *Fn, arena: *Allocator) Se...@@ -3898,10 +3981,15 @@ pub fn analyzeFnBody(mod: *Module, decl: *Decl, func: *Fn, arena: *Allocator) Se
38983981
3899 const gpa = mod.gpa;3982 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
3901 var sema: Sema = .{3988 var sema: Sema = .{
3902 .mod = mod,3989 .mod = mod,
3903 .gpa = gpa,3990 .gpa = gpa,
3904 .arena = arena,3991 .arena = arena,
3992 .perm_arena = &decl_arena.allocator,
3905 .code = decl.namespace.file_scope.zir,3993 .code = decl.namespace.file_scope.zir,
3906 .owner_decl = decl,3994 .owner_decl = decl,
3907 .namespace = decl.namespace,3995 .namespace = decl.namespace,
...@@ -3916,10 +4004,14 @@ pub fn analyzeFnBody(mod: *Module, decl: *Decl, func: *Fn, arena: *Allocator) Se...@@ -3916,10 +4004,14 @@ pub fn analyzeFnBody(mod: *Module, decl: *Decl, func: *Fn, arena: *Allocator) Se
3916 try sema.air_extra.ensureTotalCapacity(gpa, reserved_count);4004 try sema.air_extra.ensureTotalCapacity(gpa, reserved_count);
3917 sema.air_extra.items.len += reserved_count;4005 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
3919 var inner_block: Scope.Block = .{4010 var inner_block: Scope.Block = .{
3920 .parent = null,4011 .parent = null,
3921 .sema = &sema,4012 .sema = &sema,
3922 .src_decl = decl,4013 .src_decl = decl,
4014 .wip_capture_scope = wip_captures.scope,
3923 .instructions = .{},4015 .instructions = .{},
3924 .inlining = null,4016 .inlining = null,
3925 .is_comptime = false,4017 .is_comptime = false,
...@@ -3995,6 +4087,8 @@ pub fn analyzeFnBody(mod: *Module, decl: *Decl, func: *Fn, arena: *Allocator) Se...@@ -3995,6 +4087,8 @@ pub fn analyzeFnBody(mod: *Module, decl: *Decl, func: *Fn, arena: *Allocator) Se
3995 else => |e| return e,4087 else => |e| return e,
3996 };4088 };
39974089
4090 try wip_captures.finalize();
4091
3998 // Copy the block into place and mark that as the main block.4092 // Copy the block into place and mark that as the main block.
3999 try sema.air_extra.ensureUnusedCapacity(gpa, @typeInfo(Air.Block).Struct.fields.len +4093 try sema.air_extra.ensureUnusedCapacity(gpa, @typeInfo(Air.Block).Struct.fields.len +
4000 inner_block.instructions.items.len);4094 inner_block.instructions.items.len);
...@@ -4035,7 +4129,7 @@ fn markOutdatedDecl(mod: *Module, decl: *Decl) !void {...@@ -4035,7 +4129,7 @@ fn markOutdatedDecl(mod: *Module, decl: *Decl) !void {
4035 decl.analysis = .outdated;4129 decl.analysis = .outdated;
4036}4130}
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 {
4039 // If we have emit-h then we must allocate a bigger structure to store the emit-h state.4133 // If we have emit-h then we must allocate a bigger structure to store the emit-h state.
4040 const new_decl: *Decl = if (mod.emit_h != null) blk: {4134 const new_decl: *Decl = if (mod.emit_h != null) blk: {
4041 const parent_struct = try mod.gpa.create(DeclPlusEmitH);4135 const parent_struct = try mod.gpa.create(DeclPlusEmitH);
...@@ -4061,6 +4155,7 @@ pub fn allocateNewDecl(mod: *Module, namespace: *Scope.Namespace, src_node: Ast....@@ -4061,6 +4155,7 @@ pub fn allocateNewDecl(mod: *Module, namespace: *Scope.Namespace, src_node: Ast.
4061 .analysis = .unreferenced,4155 .analysis = .unreferenced,
4062 .deletion_flag = false,4156 .deletion_flag = false,
4063 .zir_decl_index = 0,4157 .zir_decl_index = 0,
4158 .src_scope = src_scope,
4064 .link = switch (mod.comp.bin_file.tag) {4159 .link = switch (mod.comp.bin_file.tag) {
4065 .coff => .{ .coff = link.File.Coff.TextBlock.empty },4160 .coff => .{ .coff = link.File.Coff.TextBlock.empty },
4066 .elf => .{ .elf = link.File.Elf.TextBlock.empty },4161 .elf => .{ .elf = link.File.Elf.TextBlock.empty },
...@@ -4087,6 +4182,7 @@ pub fn allocateNewDecl(mod: *Module, namespace: *Scope.Namespace, src_node: Ast....@@ -4087,6 +4182,7 @@ pub fn allocateNewDecl(mod: *Module, namespace: *Scope.Namespace, src_node: Ast.
4087 .alive = false,4182 .alive = false,
4088 .is_usingnamespace = false,4183 .is_usingnamespace = false,
4089 };4184 };
4185
4090 return new_decl;4186 return new_decl;
4091}4187}
40924188
...@@ -4191,25 +4287,26 @@ pub fn createAnonymousDeclNamed(...@@ -4191,25 +4287,26 @@ pub fn createAnonymousDeclNamed(
4191 typed_value: TypedValue,4287 typed_value: TypedValue,
4192 name: [:0]u8,4288 name: [:0]u8,
4193) !*Decl {4289) !*Decl {
4194 return mod.createAnonymousDeclFromDeclNamed(scope.ownerDecl().?, typed_value, name);4290 return mod.createAnonymousDeclFromDeclNamed(scope.ownerDecl().?, scope.srcScope(), typed_value, name);
4195}4291}
41964292
4197pub fn createAnonymousDecl(mod: *Module, scope: *Scope, typed_value: TypedValue) !*Decl {4293pub 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);
4199}4295}
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 {
4202 const name_index = mod.getNextAnonNameIndex();4298 const name_index = mod.getNextAnonNameIndex();
4203 const name = try std.fmt.allocPrintZ(mod.gpa, "{s}__anon_{d}", .{4299 const name = try std.fmt.allocPrintZ(mod.gpa, "{s}__anon_{d}", .{
4204 owner_decl.name, name_index,4300 owner_decl.name, name_index,
4205 });4301 });
4206 return mod.createAnonymousDeclFromDeclNamed(owner_decl, tv, name);4302 return mod.createAnonymousDeclFromDeclNamed(owner_decl, src_scope, tv, name);
4207}4303}
42084304
4209/// Takes ownership of `name` even if it returns an error.4305/// Takes ownership of `name` even if it returns an error.
4210pub fn createAnonymousDeclFromDeclNamed(4306pub fn createAnonymousDeclFromDeclNamed(
4211 mod: *Module,4307 mod: *Module,
4212 owner_decl: *Decl,4308 owner_decl: *Decl,
4309 src_scope: ?*CaptureScope,
4213 typed_value: TypedValue,4310 typed_value: TypedValue,
4214 name: [:0]u8,4311 name: [:0]u8,
4215) !*Decl {4312) !*Decl {
...@@ -4218,7 +4315,7 @@ pub fn createAnonymousDeclFromDeclNamed(...@@ -4218,7 +4315,7 @@ pub fn createAnonymousDeclFromDeclNamed(
4218 const namespace = owner_decl.namespace;4315 const namespace = owner_decl.namespace;
4219 try namespace.anon_decls.ensureUnusedCapacity(mod.gpa, 1);4316 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
4223 new_decl.name = name;4320 new_decl.name = name;
4224 new_decl.src_line = owner_decl.src_line;4321 new_decl.src_line = owner_decl.src_line;
...@@ -4783,7 +4880,7 @@ pub fn populateTestFunctions(mod: *Module) !void {...@@ -4783,7 +4880,7 @@ pub fn populateTestFunctions(mod: *Module) !void {
4783 const arena = &new_decl_arena.allocator;4880 const arena = &new_decl_arena.allocator;
47844881
4785 const test_fn_vals = try arena.alloc(Value, mod.test_functions.count());4882 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, .{
4787 .ty = try Type.Tag.array.create(arena, .{4884 .ty = try Type.Tag.array.create(arena, .{
4788 .len = test_fn_vals.len,4885 .len = test_fn_vals.len,
4789 .elem_type = try tmp_test_fn_ty.copy(arena),4886 .elem_type = try tmp_test_fn_ty.copy(arena),
...@@ -4796,7 +4893,7 @@ pub fn populateTestFunctions(mod: *Module) !void {...@@ -4796,7 +4893,7 @@ pub fn populateTestFunctions(mod: *Module) !void {
4796 var name_decl_arena = std.heap.ArenaAllocator.init(gpa);4893 var name_decl_arena = std.heap.ArenaAllocator.init(gpa);
4797 errdefer name_decl_arena.deinit();4894 errdefer name_decl_arena.deinit();
4798 const bytes = try name_decl_arena.allocator.dupe(u8, test_name_slice);4895 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, .{
4800 .ty = try Type.Tag.array_u8.create(&name_decl_arena.allocator, bytes.len),4897 .ty = try Type.Tag.array_u8.create(&name_decl_arena.allocator, bytes.len),
4801 .val = try Value.Tag.bytes.create(&name_decl_arena.allocator, bytes),4898 .val = try Value.Tag.bytes.create(&name_decl_arena.allocator, bytes),
4802 });4899 });
src/Sema.zig+196-67
...@@ -8,8 +8,12 @@...@@ -8,8 +8,12 @@
8mod: *Module,8mod: *Module,
9/// Alias to `mod.gpa`.9/// Alias to `mod.gpa`.
10gpa: *Allocator,10gpa: *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.
12arena: *Allocator,13arena: *Allocator,
14/// Points to the arena allocator for the owner_decl.
15/// This arena will persist until the decl is invalidated.
16perm_arena: *Allocator,
13code: Zir,17code: Zir,
14air_instructions: std.MultiArrayList(Air.Inst) = .{},18air_instructions: std.MultiArrayList(Air.Inst) = .{},
15air_extra: std.ArrayListUnmanaged(u32) = .{},19air_extra: std.ArrayListUnmanaged(u32) = .{},
...@@ -80,6 +84,8 @@ const Scope = Module.Scope;...@@ -80,6 +84,8 @@ const Scope = Module.Scope;
80const CompileError = Module.CompileError;84const CompileError = Module.CompileError;
81const SemaError = Module.SemaError;85const SemaError = Module.SemaError;
82const Decl = Module.Decl;86const Decl = Module.Decl;
87const CaptureScope = Module.CaptureScope;
88const WipCaptureScope = Module.WipCaptureScope;
83const LazySrcLoc = Module.LazySrcLoc;89const LazySrcLoc = Module.LazySrcLoc;
84const RangeSet = @import("RangeSet.zig");90const RangeSet = @import("RangeSet.zig");
85const target_util = @import("target.zig");91const target_util = @import("target.zig");
...@@ -129,15 +135,29 @@ pub fn analyzeBody(...@@ -129,15 +135,29 @@ pub fn analyzeBody(
129) CompileError!Zir.Inst.Index {135) CompileError!Zir.Inst.Index {
130 // No tracy calls here, to avoid interfering with the tail call mechanism.136 // 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
132 const map = &block.sema.inst_map;150 const map = &block.sema.inst_map;
133 const tags = block.sema.code.instructions.items(.tag);151 const tags = block.sema.code.instructions.items(.tag);
134 const datas = block.sema.code.instructions.items(.data);152 const datas = block.sema.code.instructions.items(.data);
135153
154 var orig_captures: usize = parent_capture_scope.captures.count();
155
136 // We use a while(true) loop here to avoid a redundant way of breaking out of156 // We use a while(true) loop here to avoid a redundant way of breaking out of
137 // the loop. The only way to break out of the loop is with a `noreturn`157 // the loop. The only way to break out of the loop is with a `noreturn`
138 // instruction.158 // instruction.
139 var i: usize = 0;159 var i: usize = 0;
140 while (true) {160 const result = while (true) {
141 const inst = body[i];161 const inst = body[i];
142 const air_inst: Air.Inst.Ref = switch (tags[inst]) {162 const air_inst: Air.Inst.Ref = switch (tags[inst]) {
143 // zig fmt: off163 // zig fmt: off
...@@ -170,6 +190,7 @@ pub fn analyzeBody(...@@ -170,6 +190,7 @@ pub fn analyzeBody(
170 .call_compile_time => try sema.zirCall(block, inst, .compile_time, false),190 .call_compile_time => try sema.zirCall(block, inst, .compile_time, false),
171 .call_nosuspend => try sema.zirCall(block, inst, .no_async, false),191 .call_nosuspend => try sema.zirCall(block, inst, .no_async, false),
172 .call_async => try sema.zirCall(block, inst, .async_kw, false),192 .call_async => try sema.zirCall(block, inst, .async_kw, false),
193 .closure_get => try sema.zirClosureGet(block, inst),
173 .cmp_lt => try sema.zirCmp(block, inst, .lt),194 .cmp_lt => try sema.zirCmp(block, inst, .lt),
174 .cmp_lte => try sema.zirCmp(block, inst, .lte),195 .cmp_lte => try sema.zirCmp(block, inst, .lte),
175 .cmp_eq => try sema.zirCmpEq(block, inst, .eq, .cmp_eq),196 .cmp_eq => try sema.zirCmpEq(block, inst, .eq, .cmp_eq),
...@@ -343,9 +364,6 @@ pub fn analyzeBody(...@@ -343,9 +364,6 @@ pub fn analyzeBody(
343 .trunc => try sema.zirUnaryMath(block, inst),364 .trunc => try sema.zirUnaryMath(block, inst),
344 .round => try sema.zirUnaryMath(block, inst),365 .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),
349 .error_set_decl => try sema.zirErrorSetDecl(block, inst, .parent),367 .error_set_decl => try sema.zirErrorSetDecl(block, inst, .parent),
350 .error_set_decl_anon => try sema.zirErrorSetDecl(block, inst, .anon),368 .error_set_decl_anon => try sema.zirErrorSetDecl(block, inst, .anon),
351 .error_set_decl_func => try sema.zirErrorSetDecl(block, inst, .func),369 .error_set_decl_func => try sema.zirErrorSetDecl(block, inst, .func),
...@@ -362,13 +380,13 @@ pub fn analyzeBody(...@@ -362,13 +380,13 @@ pub fn analyzeBody(
362 // Instructions that we know to *always* be noreturn based solely on their tag.380 // Instructions that we know to *always* be noreturn based solely on their tag.
363 // These functions match the return type of analyzeBody so that we can381 // These functions match the return type of analyzeBody so that we can
364 // tail call them here.382 // tail call them here.
365 .compile_error => return sema.zirCompileError(block, inst),383 .compile_error => break sema.zirCompileError(block, inst),
366 .ret_coerce => return sema.zirRetCoerce(block, inst),384 .ret_coerce => break sema.zirRetCoerce(block, inst),
367 .ret_node => return sema.zirRetNode(block, inst),385 .ret_node => break sema.zirRetNode(block, inst),
368 .ret_load => return sema.zirRetLoad(block, inst),386 .ret_load => break sema.zirRetLoad(block, inst),
369 .ret_err_value => return sema.zirRetErrValue(block, inst),387 .ret_err_value => break sema.zirRetErrValue(block, inst),
370 .@"unreachable" => return sema.zirUnreachable(block, inst),388 .@"unreachable" => break sema.zirUnreachable(block, inst),
371 .panic => return sema.zirPanic(block, inst),389 .panic => break sema.zirPanic(block, inst),
372 // zig fmt: on390 // zig fmt: on
373391
374 // Instructions that we know can *never* be noreturn based solely on392 // Instructions that we know can *never* be noreturn based solely on
...@@ -503,34 +521,49 @@ pub fn analyzeBody(...@@ -503,34 +521,49 @@ pub fn analyzeBody(
503 i += 1;521 i += 1;
504 continue;522 continue;
505 },523 },
524 .closure_capture => {
525 try sema.zirClosureCapture(block, inst);
526 i += 1;
527 continue;
528 },
506529
507 // Special case instructions to handle comptime control flow.530 // Special case instructions to handle comptime control flow.
508 .@"break" => {531 .@"break" => {
509 if (block.is_comptime) {532 if (block.is_comptime) {
510 return inst; // same as break_inline533 break inst; // same as break_inline
511 } else {534 } else {
512 return sema.zirBreak(block, inst);535 break sema.zirBreak(block, inst);
513 }536 }
514 },537 },
515 .break_inline => return inst,538 .break_inline => break inst,
516 .repeat => {539 .repeat => {
517 if (block.is_comptime) {540 if (block.is_comptime) {
518 // Send comptime control flow back to the beginning of this block.541 // Send comptime control flow back to the beginning of this block.
519 const src: LazySrcLoc = .{ .node_offset = datas[inst].node };542 const src: LazySrcLoc = .{ .node_offset = datas[inst].node };
520 try sema.emitBackwardBranch(block, src);543 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 }
521 i = 0;549 i = 0;
522 continue;550 continue;
523 } else {551 } else {
524 const src_node = sema.code.instructions.items(.data)[inst].node;552 const src_node = sema.code.instructions.items(.data)[inst].node;
525 const src: LazySrcLoc = .{ .node_offset = src_node };553 const src: LazySrcLoc = .{ .node_offset = src_node };
526 try sema.requireRuntimeBlock(block, src);554 try sema.requireRuntimeBlock(block, src);
527 return always_noreturn;555 break always_noreturn;
528 }556 }
529 },557 },
530 .repeat_inline => {558 .repeat_inline => {
531 // Send comptime control flow back to the beginning of this block.559 // Send comptime control flow back to the beginning of this block.
532 const src: LazySrcLoc = .{ .node_offset = datas[inst].node };560 const src: LazySrcLoc = .{ .node_offset = datas[inst].node };
533 try sema.emitBackwardBranch(block, src);561 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 }
534 i = 0;567 i = 0;
535 continue;568 continue;
536 },569 },
...@@ -545,7 +578,7 @@ pub fn analyzeBody(...@@ -545,7 +578,7 @@ pub fn analyzeBody(
545 if (inst == break_data.block_inst) {578 if (inst == break_data.block_inst) {
546 break :blk sema.resolveInst(break_data.operand);579 break :blk sema.resolveInst(break_data.operand);
547 } else {580 } else {
548 return break_inst;581 break break_inst;
549 }582 }
550 },583 },
551 .block => blk: {584 .block => blk: {
...@@ -559,7 +592,7 @@ pub fn analyzeBody(...@@ -559,7 +592,7 @@ pub fn analyzeBody(
559 if (inst == break_data.block_inst) {592 if (inst == break_data.block_inst) {
560 break :blk sema.resolveInst(break_data.operand);593 break :blk sema.resolveInst(break_data.operand);
561 } else {594 } else {
562 return break_inst;595 break break_inst;
563 }596 }
564 },597 },
565 .block_inline => blk: {598 .block_inline => blk: {
...@@ -572,11 +605,11 @@ pub fn analyzeBody(...@@ -572,11 +605,11 @@ pub fn analyzeBody(
572 if (inst == break_data.block_inst) {605 if (inst == break_data.block_inst) {
573 break :blk sema.resolveInst(break_data.operand);606 break :blk sema.resolveInst(break_data.operand);
574 } else {607 } else {
575 return break_inst;608 break break_inst;
576 }609 }
577 },610 },
578 .condbr => blk: {611 .condbr => blk: {
579 if (!block.is_comptime) return sema.zirCondbr(block, inst);612 if (!block.is_comptime) break sema.zirCondbr(block, inst);
580 // Same as condbr_inline. TODO https://github.com/ziglang/zig/issues/8220613 // Same as condbr_inline. TODO https://github.com/ziglang/zig/issues/8220
581 const inst_data = datas[inst].pl_node;614 const inst_data = datas[inst].pl_node;
582 const cond_src: LazySrcLoc = .{ .node_offset_if_cond = inst_data.src_node };615 const cond_src: LazySrcLoc = .{ .node_offset_if_cond = inst_data.src_node };
...@@ -590,7 +623,7 @@ pub fn analyzeBody(...@@ -590,7 +623,7 @@ pub fn analyzeBody(
590 if (inst == break_data.block_inst) {623 if (inst == break_data.block_inst) {
591 break :blk sema.resolveInst(break_data.operand);624 break :blk sema.resolveInst(break_data.operand);
592 } else {625 } else {
593 return break_inst;626 break break_inst;
594 }627 }
595 },628 },
596 .condbr_inline => blk: {629 .condbr_inline => blk: {
...@@ -606,15 +639,22 @@ pub fn analyzeBody(...@@ -606,15 +639,22 @@ pub fn analyzeBody(
606 if (inst == break_data.block_inst) {639 if (inst == break_data.block_inst) {
607 break :blk sema.resolveInst(break_data.operand);640 break :blk sema.resolveInst(break_data.operand);
608 } else {641 } else {
609 return break_inst;642 break break_inst;
610 }643 }
611 },644 },
612 };645 };
613 if (sema.typeOf(air_inst).isNoReturn())646 if (sema.typeOf(air_inst).isNoReturn())
614 return always_noreturn;647 break always_noreturn;
615 try map.put(sema.gpa, inst, air_inst);648 try map.put(sema.gpa, inst, air_inst);
616 i += 1;649 i += 1;
650 } else unreachable;
651
652 if (!wip_captures.finalized) {
653 try wip_captures.finalize();
654 block.wip_capture_scope = parent_capture_scope;
617 }655 }
656
657 return result;
618}658}
619659
620fn zirExtended(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {660fn 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...@@ -626,6 +666,7 @@ fn zirExtended(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileEr
626 .struct_decl => return sema.zirStructDecl( block, extended, inst),666 .struct_decl => return sema.zirStructDecl( block, extended, inst),
627 .enum_decl => return sema.zirEnumDecl( block, extended),667 .enum_decl => return sema.zirEnumDecl( block, extended),
628 .union_decl => return sema.zirUnionDecl( block, extended, inst),668 .union_decl => return sema.zirUnionDecl( block, extended, inst),
669 .opaque_decl => return sema.zirOpaqueDecl( block, extended, inst),
629 .ret_ptr => return sema.zirRetPtr( block, extended),670 .ret_ptr => return sema.zirRetPtr( block, extended),
630 .ret_type => return sema.zirRetType( block, extended),671 .ret_type => return sema.zirRetType( block, extended),
631 .this => return sema.zirThis( block, extended),672 .this => return sema.zirThis( block, extended),
...@@ -1011,7 +1052,6 @@ fn zirStructDecl(...@@ -1011,7 +1052,6 @@ fn zirStructDecl(
1011}1052}
10121053
1013fn createTypeName(sema: *Sema, block: *Scope.Block, name_strategy: Zir.Inst.NameStrategy) ![:0]u8 {1054fn createTypeName(sema: *Sema, block: *Scope.Block, name_strategy: Zir.Inst.NameStrategy) ![:0]u8 {
1014 _ = block;
1015 switch (name_strategy) {1055 switch (name_strategy) {
1016 .anon => {1056 .anon => {
1017 // It would be neat to have "struct:line:column" but this name has1057 // 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...@@ -1020,14 +1060,14 @@ fn createTypeName(sema: *Sema, block: *Scope.Block, name_strategy: Zir.Inst.Name
1020 // semantically analyzed.1060 // semantically analyzed.
1021 const name_index = sema.mod.getNextAnonNameIndex();1061 const name_index = sema.mod.getNextAnonNameIndex();
1022 return std.fmt.allocPrintZ(sema.gpa, "{s}__anon_{d}", .{1062 return std.fmt.allocPrintZ(sema.gpa, "{s}__anon_{d}", .{
1023 sema.owner_decl.name, name_index,1063 block.src_decl.name, name_index,
1024 });1064 });
1025 },1065 },
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)),
1027 .func => {1067 .func => {
1028 const name_index = sema.mod.getNextAnonNameIndex();1068 const name_index = sema.mod.getNextAnonNameIndex();
1029 const name = try std.fmt.allocPrintZ(sema.gpa, "{s}__anon_{d}", .{1069 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,
1031 });1071 });
1032 log.warn("TODO: handle NameStrategy.func correctly instead of using anon name '{s}'", .{1072 log.warn("TODO: handle NameStrategy.func correctly instead of using anon name '{s}'", .{
1033 name,1073 name,
...@@ -1083,17 +1123,6 @@ fn zirEnumDecl(...@@ -1083,17 +1123,6 @@ fn zirEnumDecl(
1083 var new_decl_arena = std.heap.ArenaAllocator.init(gpa);1123 var new_decl_arena = std.heap.ArenaAllocator.init(gpa);
1084 errdefer new_decl_arena.deinit();1124 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
1097 const enum_obj = try new_decl_arena.allocator.create(Module.EnumFull);1126 const enum_obj = try new_decl_arena.allocator.create(Module.EnumFull);
1098 const enum_ty_payload = try new_decl_arena.allocator.create(Type.Payload.EnumFull);1127 const enum_ty_payload = try new_decl_arena.allocator.create(Type.Payload.EnumFull);
1099 enum_ty_payload.* = .{1128 enum_ty_payload.* = .{
...@@ -1112,7 +1141,7 @@ fn zirEnumDecl(...@@ -1112,7 +1141,7 @@ fn zirEnumDecl(
11121141
1113 enum_obj.* = .{1142 enum_obj.* = .{
1114 .owner_decl = new_decl,1143 .owner_decl = new_decl,
1115 .tag_ty = tag_ty,1144 .tag_ty = Type.initTag(.@"null"),
1116 .fields = .{},1145 .fields = .{},
1117 .values = .{},1146 .values = .{},
1118 .node_offset = src.node_offset,1147 .node_offset = src.node_offset,
...@@ -1140,16 +1169,6 @@ fn zirEnumDecl(...@@ -1140,16 +1169,6 @@ fn zirEnumDecl(
1140 const body_end = extra_index;1169 const body_end = extra_index;
1141 extra_index += bit_bags_count;1170 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
1153 {1172 {
1154 // We create a block for the field type instructions because they1173 // We create a block for the field type instructions because they
1155 // may need to reference Decls from inside the enum namespace.1174 // may need to reference Decls from inside the enum namespace.
...@@ -1172,10 +1191,14 @@ fn zirEnumDecl(...@@ -1172,10 +1191,14 @@ fn zirEnumDecl(
1172 sema.func = null;1191 sema.func = null;
1173 defer sema.func = prev_func;1192 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
1175 var enum_block: Scope.Block = .{1197 var enum_block: Scope.Block = .{
1176 .parent = null,1198 .parent = null,
1177 .sema = sema,1199 .sema = sema,
1178 .src_decl = new_decl,1200 .src_decl = new_decl,
1201 .wip_capture_scope = wip_captures.scope,
1179 .instructions = .{},1202 .instructions = .{},
1180 .inlining = null,1203 .inlining = null,
1181 .is_comptime = true,1204 .is_comptime = true,
...@@ -1185,7 +1208,30 @@ fn zirEnumDecl(...@@ -1185,7 +1208,30 @@ fn zirEnumDecl(
1185 if (body.len != 0) {1208 if (body.len != 0) {
1186 _ = try sema.analyzeBody(&enum_block, body);1209 _ = try sema.analyzeBody(&enum_block, body);
1187 }1210 }
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;
1188 }1223 }
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
1189 var bit_bag_index: usize = body_end;1235 var bit_bag_index: usize = body_end;
1190 var cur_bit_bag: u32 = undefined;1236 var cur_bit_bag: u32 = undefined;
1191 var field_i: u32 = 0;1237 var field_i: u32 = 0;
...@@ -1224,10 +1270,10 @@ fn zirEnumDecl(...@@ -1224,10 +1270,10 @@ fn zirEnumDecl(
1224 // that points to this default value expression rather than the struct.1270 // that points to this default value expression rather than the struct.
1225 // But only resolve the source location if we need to emit a compile error.1271 // But only resolve the source location if we need to emit a compile error.
1226 const tag_val = (try sema.resolveInstConst(block, src, tag_val_ref)).val;1272 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 });
1228 } else if (any_values) {1274 } else if (any_values) {
1229 const tag_val = try Value.Tag.int_u64.create(&new_decl_arena.allocator, field_i);1275 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 });
1231 }1277 }
1232 }1278 }
12331279
...@@ -1305,20 +1351,14 @@ fn zirUnionDecl(...@@ -1305,20 +1351,14 @@ fn zirUnionDecl(
1305fn zirOpaqueDecl(1351fn zirOpaqueDecl(
1306 sema: *Sema,1352 sema: *Sema,
1307 block: *Scope.Block,1353 block: *Scope.Block,
1354 extended: Zir.Inst.Extended.InstData,
1308 inst: Zir.Inst.Index,1355 inst: Zir.Inst.Index,
1309 name_strategy: Zir.Inst.NameStrategy,
1310) CompileError!Air.Inst.Ref {1356) CompileError!Air.Inst.Ref {
1311 const tracy = trace(@src());1357 const tracy = trace(@src());
1312 defer tracy.end();1358 defer tracy.end();
13131359
1314 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;1360 _ = extended;
1315 const src = inst_data.src();1361 _ = inst;
1316 const extra = sema.code.extraData(Zir.Inst.Block, inst_data.payload_index);
1317
1318 _ = name_strategy;
1319 _ = inst_data;
1320 _ = src;
1321 _ = extra;
1322 return sema.mod.fail(&block.base, sema.src, "TODO implement zirOpaqueDecl", .{});1362 return sema.mod.fail(&block.base, sema.src, "TODO implement zirOpaqueDecl", .{});
1323}1363}
13241364
...@@ -2160,6 +2200,7 @@ fn zirCImport(sema: *Sema, parent_block: *Scope.Block, inst: Zir.Inst.Index) Com...@@ -2160,6 +2200,7 @@ fn zirCImport(sema: *Sema, parent_block: *Scope.Block, inst: Zir.Inst.Index) Com
2160 .parent = parent_block,2200 .parent = parent_block,
2161 .sema = sema,2201 .sema = sema,
2162 .src_decl = parent_block.src_decl,2202 .src_decl = parent_block.src_decl,
2203 .wip_capture_scope = parent_block.wip_capture_scope,
2163 .instructions = .{},2204 .instructions = .{},
2164 .inlining = parent_block.inlining,2205 .inlining = parent_block.inlining,
2165 .is_comptime = parent_block.is_comptime,2206 .is_comptime = parent_block.is_comptime,
...@@ -2214,7 +2255,7 @@ fn zirCImport(sema: *Sema, parent_block: *Scope.Block, inst: Zir.Inst.Index) Com...@@ -2214,7 +2255,7 @@ fn zirCImport(sema: *Sema, parent_block: *Scope.Block, inst: Zir.Inst.Index) Com
2214 try sema.mod.semaFile(result.file);2255 try sema.mod.semaFile(result.file);
2215 const file_root_decl = result.file.root_decl.?;2256 const file_root_decl = result.file.root_decl.?;
2216 try sema.mod.declareDeclDependency(sema.owner_decl, file_root_decl);2257 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);
2218}2259}
22192260
2220fn zirSuspendBlock(sema: *Sema, parent_block: *Scope.Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {2261fn zirSuspendBlock(sema: *Sema, parent_block: *Scope.Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
...@@ -2259,6 +2300,7 @@ fn zirBlock(...@@ -2259,6 +2300,7 @@ fn zirBlock(
2259 .parent = parent_block,2300 .parent = parent_block,
2260 .sema = sema,2301 .sema = sema,
2261 .src_decl = parent_block.src_decl,2302 .src_decl = parent_block.src_decl,
2303 .wip_capture_scope = parent_block.wip_capture_scope,
2262 .instructions = .{},2304 .instructions = .{},
2263 .label = &label,2305 .label = &label,
2264 .inlining = parent_block.inlining,2306 .inlining = parent_block.inlining,
...@@ -2866,10 +2908,14 @@ fn analyzeCall(...@@ -2866,10 +2908,14 @@ fn analyzeCall(
2866 sema.func = module_fn;2908 sema.func = module_fn;
2867 defer sema.func = parent_func;2909 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
2869 var child_block: Scope.Block = .{2914 var child_block: Scope.Block = .{
2870 .parent = null,2915 .parent = null,
2871 .sema = sema,2916 .sema = sema,
2872 .src_decl = module_fn.owner_decl,2917 .src_decl = module_fn.owner_decl,
2918 .wip_capture_scope = wip_captures.scope,
2873 .instructions = .{},2919 .instructions = .{},
2874 .label = null,2920 .label = null,
2875 .inlining = &inlining,2921 .inlining = &inlining,
...@@ -3034,6 +3080,9 @@ fn analyzeCall(...@@ -3034,6 +3080,9 @@ fn analyzeCall(
30343080
3035 break :res2 result;3081 break :res2 result;
3036 };3082 };
3083
3084 try wip_captures.finalize();
3085
3037 break :res res2;3086 break :res res2;
3038 } else if (func_ty_info.is_generic) res: {3087 } else if (func_ty_info.is_generic) res: {
3039 const func_val = try sema.resolveConstValue(block, func_src, func);3088 const func_val = try sema.resolveConstValue(block, func_src, func);
...@@ -3116,7 +3165,8 @@ fn analyzeCall(...@@ -3116,7 +3165,8 @@ fn analyzeCall(
3116 try namespace.anon_decls.ensureUnusedCapacity(gpa, 1);3165 try namespace.anon_decls.ensureUnusedCapacity(gpa, 1);
31173166
3118 // Create a Decl for the new function.3167 // 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);
3120 // TODO better names for generic function instantiations3170 // TODO better names for generic function instantiations
3121 const name_index = mod.getNextAnonNameIndex();3171 const name_index = mod.getNextAnonNameIndex();
3122 new_decl.name = try std.fmt.allocPrintZ(gpa, "{s}__anon_{d}", .{3172 new_decl.name = try std.fmt.allocPrintZ(gpa, "{s}__anon_{d}", .{
...@@ -3147,6 +3197,7 @@ fn analyzeCall(...@@ -3147,6 +3197,7 @@ fn analyzeCall(
3147 .mod = mod,3197 .mod = mod,
3148 .gpa = gpa,3198 .gpa = gpa,
3149 .arena = sema.arena,3199 .arena = sema.arena,
3200 .perm_arena = &new_decl_arena.allocator,
3150 .code = fn_zir,3201 .code = fn_zir,
3151 .owner_decl = new_decl,3202 .owner_decl = new_decl,
3152 .namespace = namespace,3203 .namespace = namespace,
...@@ -3159,10 +3210,14 @@ fn analyzeCall(...@@ -3159,10 +3210,14 @@ fn analyzeCall(
3159 };3210 };
3160 defer child_sema.deinit();3211 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
3162 var child_block: Scope.Block = .{3216 var child_block: Scope.Block = .{
3163 .parent = null,3217 .parent = null,
3164 .sema = &child_sema,3218 .sema = &child_sema,
3165 .src_decl = new_decl,3219 .src_decl = new_decl,
3220 .wip_capture_scope = wip_captures.scope,
3166 .instructions = .{},3221 .instructions = .{},
3167 .inlining = null,3222 .inlining = null,
3168 .is_comptime = true,3223 .is_comptime = true,
...@@ -3250,6 +3305,8 @@ fn analyzeCall(...@@ -3250,6 +3305,8 @@ fn analyzeCall(
3250 arg_i += 1;3305 arg_i += 1;
3251 }3306 }
32523307
3308 try wip_captures.finalize();
3309
3253 // Populate the Decl ty/val with the function and its type.3310 // Populate the Decl ty/val with the function and its type.
3254 new_decl.ty = try child_sema.typeOf(new_func_inst).copy(&new_decl_arena.allocator);3311 new_decl.ty = try child_sema.typeOf(new_func_inst).copy(&new_decl_arena.allocator);
3255 new_decl.val = try Value.Tag.function.create(&new_decl_arena.allocator, new_func);3312 new_decl.val = try Value.Tag.function.create(&new_decl_arena.allocator, new_func);
...@@ -5164,6 +5221,7 @@ fn analyzeSwitch(...@@ -5164,6 +5221,7 @@ fn analyzeSwitch(
5164 .parent = block,5221 .parent = block,
5165 .sema = sema,5222 .sema = sema,
5166 .src_decl = block.src_decl,5223 .src_decl = block.src_decl,
5224 .wip_capture_scope = block.wip_capture_scope,
5167 .instructions = .{},5225 .instructions = .{},
5168 .label = &label,5226 .label = &label,
5169 .inlining = block.inlining,5227 .inlining = block.inlining,
...@@ -5268,12 +5326,19 @@ fn analyzeSwitch(...@@ -5268,12 +5326,19 @@ fn analyzeSwitch(
5268 const body = sema.code.extra[extra_index..][0..body_len];5326 const body = sema.code.extra[extra_index..][0..body_len];
5269 extra_index += body_len;5327 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
5271 case_block.instructions.shrinkRetainingCapacity(0);5332 case_block.instructions.shrinkRetainingCapacity(0);
5333 case_block.wip_capture_scope = wip_captures.scope;
5334
5272 const item = sema.resolveInst(item_ref);5335 const item = sema.resolveInst(item_ref);
5273 // `item` is already guaranteed to be constant known.5336 // `item` is already guaranteed to be constant known.
52745337
5275 _ = try sema.analyzeBody(&case_block, body);5338 _ = try sema.analyzeBody(&case_block, body);
52765339
5340 try wip_captures.finalize();
5341
5277 try cases_extra.ensureUnusedCapacity(gpa, 3 + case_block.instructions.items.len);5342 try cases_extra.ensureUnusedCapacity(gpa, 3 + case_block.instructions.items.len);
5278 cases_extra.appendAssumeCapacity(1); // items_len5343 cases_extra.appendAssumeCapacity(1); // items_len
5279 cases_extra.appendAssumeCapacity(@intCast(u32, case_block.instructions.items.len));5344 cases_extra.appendAssumeCapacity(@intCast(u32, case_block.instructions.items.len));
...@@ -5301,6 +5366,7 @@ fn analyzeSwitch(...@@ -5301,6 +5366,7 @@ fn analyzeSwitch(
5301 extra_index += items_len;5366 extra_index += items_len;
53025367
5303 case_block.instructions.shrinkRetainingCapacity(0);5368 case_block.instructions.shrinkRetainingCapacity(0);
5369 case_block.wip_capture_scope = child_block.wip_capture_scope;
53045370
5305 var any_ok: Air.Inst.Ref = .none;5371 var any_ok: Air.Inst.Ref = .none;
53065372
...@@ -5379,11 +5445,18 @@ fn analyzeSwitch(...@@ -5379,11 +5445,18 @@ fn analyzeSwitch(
5379 var cond_body = case_block.instructions.toOwnedSlice(gpa);5445 var cond_body = case_block.instructions.toOwnedSlice(gpa);
5380 defer gpa.free(cond_body);5446 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
5382 case_block.instructions.shrinkRetainingCapacity(0);5451 case_block.instructions.shrinkRetainingCapacity(0);
5452 case_block.wip_capture_scope = wip_captures.scope;
5453
5383 const body = sema.code.extra[extra_index..][0..body_len];5454 const body = sema.code.extra[extra_index..][0..body_len];
5384 extra_index += body_len;5455 extra_index += body_len;
5385 _ = try sema.analyzeBody(&case_block, body);5456 _ = try sema.analyzeBody(&case_block, body);
53865457
5458 try wip_captures.finalize();
5459
5387 if (is_first) {5460 if (is_first) {
5388 is_first = false;5461 is_first = false;
5389 first_else_body = cond_body;5462 first_else_body = cond_body;
...@@ -5409,9 +5482,16 @@ fn analyzeSwitch(...@@ -5409,9 +5482,16 @@ fn analyzeSwitch(
54095482
5410 var final_else_body: []const Air.Inst.Index = &.{};5483 var final_else_body: []const Air.Inst.Index = &.{};
5411 if (special.body.len != 0) {5484 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
5412 case_block.instructions.shrinkRetainingCapacity(0);5488 case_block.instructions.shrinkRetainingCapacity(0);
5489 case_block.wip_capture_scope = wip_captures.scope;
5490
5413 _ = try sema.analyzeBody(&case_block, special.body);5491 _ = try sema.analyzeBody(&case_block, special.body);
54145492
5493 try wip_captures.finalize();
5494
5415 if (is_first) {5495 if (is_first) {
5416 final_else_body = case_block.instructions.items;5496 final_else_body = case_block.instructions.items;
5417 } else {5497 } else {
...@@ -5693,7 +5773,7 @@ fn zirImport(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileErro...@@ -5693,7 +5773,7 @@ fn zirImport(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileErro
5693 try mod.semaFile(result.file);5773 try mod.semaFile(result.file);
5694 const file_root_decl = result.file.root_decl.?;5774 const file_root_decl = result.file.root_decl.?;
5695 try sema.mod.declareDeclDependency(sema.owner_decl, file_root_decl);5775 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);
5697}5777}
56985778
5699fn zirRetErrValueCode(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {5779fn zirRetErrValueCode(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
...@@ -6536,8 +6616,45 @@ fn zirThis(...@@ -6536,8 +6616,45 @@ fn zirThis(
6536 block: *Scope.Block,6616 block: *Scope.Block,
6537 extended: Zir.Inst.Extended.InstData,6617 extended: Zir.Inst.Extended.InstData,
6538) CompileError!Air.Inst.Ref {6618) CompileError!Air.Inst.Ref {
6619 const this_decl = block.base.namespace().getDecl();
6539 const src: LazySrcLoc = .{ .node_offset = @bitCast(i32, extended.operand) };6620 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);
6541}6658}
65426659
6543fn zirRetAddr(6660fn zirRetAddr(
...@@ -8615,6 +8732,7 @@ fn addSafetyCheck(...@@ -8615,6 +8732,7 @@ fn addSafetyCheck(
8615 var fail_block: Scope.Block = .{8732 var fail_block: Scope.Block = .{
8616 .parent = parent_block,8733 .parent = parent_block,
8617 .sema = sema,8734 .sema = sema,
8735 .wip_capture_scope = parent_block.wip_capture_scope,
8618 .src_decl = parent_block.src_decl,8736 .src_decl = parent_block.src_decl,
8619 .instructions = .{},8737 .instructions = .{},
8620 .inlining = parent_block.inlining,8738 .inlining = parent_block.inlining,
...@@ -8714,7 +8832,7 @@ fn safetyPanic(...@@ -8714,7 +8832,7 @@ fn safetyPanic(
8714 block: *Scope.Block,8832 block: *Scope.Block,
8715 src: LazySrcLoc,8833 src: LazySrcLoc,
8716 panic_id: PanicId,8834 panic_id: PanicId,
8717) !Zir.Inst.Index {8835) CompileError!Zir.Inst.Index {
8718 const msg = switch (panic_id) {8836 const msg = switch (panic_id) {
8719 .unreach => "reached unreachable code",8837 .unreach => "reached unreachable code",
8720 .unwrap_null => "attempt to use null value",8838 .unwrap_null => "attempt to use null value",
...@@ -10666,6 +10784,10 @@ pub fn resolveDeclFields(sema: *Sema, block: *Scope.Block, src: LazySrcLoc, ty:...@@ -10666,6 +10784,10 @@ pub fn resolveDeclFields(sema: *Sema, block: *Scope.Block, src: LazySrcLoc, ty:
10666 sema.namespace = &struct_obj.namespace;10784 sema.namespace = &struct_obj.namespace;
10667 defer sema.namespace = prev_namespace;10785 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
10669 struct_obj.status = .field_types_wip;10791 struct_obj.status = .field_types_wip;
10670 try sema.analyzeStructFields(block, struct_obj);10792 try sema.analyzeStructFields(block, struct_obj);
10671 struct_obj.status = .have_field_types;10793 struct_obj.status = .have_field_types;
...@@ -10684,6 +10806,10 @@ pub fn resolveDeclFields(sema: *Sema, block: *Scope.Block, src: LazySrcLoc, ty:...@@ -10684,6 +10806,10 @@ pub fn resolveDeclFields(sema: *Sema, block: *Scope.Block, src: LazySrcLoc, ty:
10684 sema.namespace = &union_obj.namespace;10806 sema.namespace = &union_obj.namespace;
10685 defer sema.namespace = prev_namespace;10807 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
10687 union_obj.status = .field_types_wip;10813 union_obj.status = .field_types_wip;
10688 try sema.analyzeUnionFields(block, union_obj);10814 try sema.analyzeUnionFields(block, union_obj);
10689 union_obj.status = .have_field_types;10815 union_obj.status = .have_field_types;
...@@ -10885,9 +11011,11 @@ fn analyzeUnionFields(...@@ -10885,9 +11011,11 @@ fn analyzeUnionFields(
10885 const src: LazySrcLoc = .{ .node_offset = union_obj.node_offset };11011 const src: LazySrcLoc = .{ .node_offset = union_obj.node_offset };
10886 extra_index += @boolToInt(small.has_src_node);11012 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]);
10889 extra_index += 1;11016 extra_index += 1;
10890 }11017 break :blk ty_ref;
11018 } else .none;
1089111019
10892 const body_len = if (small.has_body_len) blk: {11020 const body_len = if (small.has_body_len) blk: {
10893 const body_len = zir.extra[extra_index];11021 const body_len = zir.extra[extra_index];
...@@ -10996,6 +11124,7 @@ fn analyzeUnionFields(...@@ -10996,6 +11124,7 @@ fn analyzeUnionFields(
10996 }11124 }
1099711125
10998 // TODO resolve the union tag_type_ref11126 // TODO resolve the union tag_type_ref
11127 _ = tag_type_ref;
10999}11128}
1100011129
11001fn getBuiltin(11130fn getBuiltin(
src/Zir.zig+62-37
...@@ -49,8 +49,6 @@ pub const Header = extern struct {...@@ -49,8 +49,6 @@ pub const Header = extern struct {
49};49};
5050
51pub const ExtraIndex = enum(u32) {51pub const ExtraIndex = enum(u32) {
52 /// Ref. The main struct decl for this file.
53 main_struct,
54 /// If this is 0, no compile errors. Otherwise there is a `CompileErrors`52 /// If this is 0, no compile errors. Otherwise there is a `CompileErrors`
55 /// payload at this index.53 /// payload at this index.
56 compile_errors,54 compile_errors,
...@@ -61,11 +59,6 @@ pub const ExtraIndex = enum(u32) {...@@ -61,11 +59,6 @@ pub const ExtraIndex = enum(u32) {
61 _,59 _,
62};60};
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
69/// Returns the requested data, as well as the new index which is at the start of the62/// Returns the requested data, as well as the new index which is at the start of the
70/// trailers for the object.63/// trailers for the object.
71pub fn extraData(code: Zir, comptime T: type, index: usize) struct { data: T, end: usize } {64pub 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 {...@@ -112,6 +105,10 @@ pub fn deinit(code: *Zir, gpa: *Allocator) void {
112 code.* = undefined;105 code.* = undefined;
113}106}
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
115/// These are untyped instructions generated from an Abstract Syntax Tree.112/// These are untyped instructions generated from an Abstract Syntax Tree.
116/// The data here is immutable because it is possible to have multiple113/// The data here is immutable because it is possible to have multiple
117/// analyses on the same ZIR happening at the same time.114/// analyses on the same ZIR happening at the same time.
...@@ -267,11 +264,6 @@ pub const Inst = struct {...@@ -267,11 +264,6 @@ pub const Inst = struct {
267 /// only the taken branch is analyzed. The then block and else block must264 /// only the taken branch is analyzed. The then block and else block must
268 /// terminate with an "inline" variant of a noreturn instruction.265 /// terminate with an "inline" variant of a noreturn instruction.
269 condbr_inline,266 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,
275 /// An error set type definition. Contains a list of field names.267 /// An error set type definition. Contains a list of field names.
276 /// Uses the `pl_node` union field. Payload is `ErrorSetDecl`.268 /// Uses the `pl_node` union field. Payload is `ErrorSetDecl`.
277 error_set_decl,269 error_set_decl,
...@@ -941,6 +933,17 @@ pub const Inst = struct {...@@ -941,6 +933,17 @@ pub const Inst = struct {
941 @"await",933 @"await",
942 await_nosuspend,934 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
944 /// The ZIR instruction tag is one of the `Extended` ones.947 /// The ZIR instruction tag is one of the `Extended` ones.
945 /// Uses the `extended` union field.948 /// Uses the `extended` union field.
946 extended,949 extended,
...@@ -996,9 +999,6 @@ pub const Inst = struct {...@@ -996,9 +999,6 @@ pub const Inst = struct {
996 .cmp_gt,999 .cmp_gt,
997 .cmp_neq,1000 .cmp_neq,
998 .coerce_result_ptr,1001 .coerce_result_ptr,
999 .opaque_decl,
1000 .opaque_decl_anon,
1001 .opaque_decl_func,
1002 .error_set_decl,1002 .error_set_decl,
1003 .error_set_decl_anon,1003 .error_set_decl_anon,
1004 .error_set_decl_func,1004 .error_set_decl_func,
...@@ -1191,6 +1191,8 @@ pub const Inst = struct {...@@ -1191,6 +1191,8 @@ pub const Inst = struct {
1191 .await_nosuspend,1191 .await_nosuspend,
1192 .ret_err_value_code,1192 .ret_err_value_code,
1193 .extended,1193 .extended,
1194 .closure_get,
1195 .closure_capture,
1194 => false,1196 => false,
11951197
1196 .@"break",1198 .@"break",
...@@ -1258,9 +1260,6 @@ pub const Inst = struct {...@@ -1258,9 +1260,6 @@ pub const Inst = struct {
1258 .coerce_result_ptr = .bin,1260 .coerce_result_ptr = .bin,
1259 .condbr = .pl_node,1261 .condbr = .pl_node,
1260 .condbr_inline = .pl_node,1262 .condbr_inline = .pl_node,
1261 .opaque_decl = .pl_node,
1262 .opaque_decl_anon = .pl_node,
1263 .opaque_decl_func = .pl_node,
1264 .error_set_decl = .pl_node,1263 .error_set_decl = .pl_node,
1265 .error_set_decl_anon = .pl_node,1264 .error_set_decl_anon = .pl_node,
1266 .error_set_decl_func = .pl_node,1265 .error_set_decl_func = .pl_node,
...@@ -1478,6 +1477,9 @@ pub const Inst = struct {...@@ -1478,6 +1477,9 @@ pub const Inst = struct {
1478 .@"await" = .un_node,1477 .@"await" = .un_node,
1479 .await_nosuspend = .un_node,1478 .await_nosuspend = .un_node,
14801479
1480 .closure_capture = .un_tok,
1481 .closure_get = .inst_node,
1482
1481 .extended = .extended,1483 .extended = .extended,
1482 });1484 });
1483 };1485 };
...@@ -1510,6 +1512,10 @@ pub const Inst = struct {...@@ -1510,6 +1512,10 @@ pub const Inst = struct {
1510 /// `operand` is payload index to `UnionDecl`.1512 /// `operand` is payload index to `UnionDecl`.
1511 /// `small` is `UnionDecl.Small`.1513 /// `small` is `UnionDecl.Small`.
1512 union_decl,1514 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,
1513 /// Obtains a pointer to the return value.1519 /// Obtains a pointer to the return value.
1514 /// `operand` is `src_node: i32`.1520 /// `operand` is `src_node: i32`.
1515 ret_ptr,1521 ret_ptr,
...@@ -2194,6 +2200,18 @@ pub const Inst = struct {...@@ -2194,6 +2200,18 @@ pub const Inst = struct {
2194 line: u32,2200 line: u32,
2195 column: u32,2201 column: u32,
2196 },2202 },
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
2198 // Make sure we don't accidentally add a field to make this union2216 // Make sure we don't accidentally add a field to make this union
2199 // bigger than expected. Note that in Debug builds, Zig is allowed2217 // bigger than expected. Note that in Debug builds, Zig is allowed
...@@ -2231,6 +2249,7 @@ pub const Inst = struct {...@@ -2231,6 +2249,7 @@ pub const Inst = struct {
2231 @"break",2249 @"break",
2232 switch_capture,2250 switch_capture,
2233 dbg_stmt,2251 dbg_stmt,
2252 inst_node,
2234 };2253 };
2235 };2254 };
22362255
...@@ -2662,13 +2681,15 @@ pub const Inst = struct {...@@ -2662,13 +2681,15 @@ pub const Inst = struct {
2662 };2681 };
26632682
2664 /// Trailing:2683 /// Trailing:
2665 /// 0. decl_bits: u32 // for every 8 decls2684 /// 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
2666 /// - sets of 4 bits:2687 /// - sets of 4 bits:
2667 /// 0b000X: whether corresponding decl is pub2688 /// 0b000X: whether corresponding decl is pub
2668 /// 0b00X0: whether corresponding decl is exported2689 /// 0b00X0: whether corresponding decl is exported
2669 /// 0b0X00: whether corresponding decl has an align expression2690 /// 0b0X00: whether corresponding decl has an align expression
2670 /// 0bX000: whether corresponding decl has a linksection or an address space expression2691 /// 0bX000: whether corresponding decl has a linksection or an address space expression
2671 /// 1. decl: { // for every decls_len2692 /// 3. decl: { // for every decls_len
2672 /// src_hash: [4]u32, // hash of source bytes2693 /// src_hash: [4]u32, // hash of source bytes
2673 /// line: u32, // line number of decl, relative to parent2694 /// line: u32, // line number of decl, relative to parent
2674 /// name: u32, // null terminated string index2695 /// name: u32, // null terminated string index
...@@ -2685,7 +2706,12 @@ pub const Inst = struct {...@@ -2685,7 +2706,12 @@ pub const Inst = struct {
2685 /// }2706 /// }
2686 /// }2707 /// }
2687 pub const OpaqueDecl = struct {2708 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 };
2689 };2715 };
26902716
2691 /// Trailing: field_name: u32 // for every field: null terminated string index2717 /// Trailing: field_name: u32 // for every field: null terminated string index
...@@ -2937,15 +2963,6 @@ pub fn declIterator(zir: Zir, decl_inst: u32) DeclIterator {...@@ -2937,15 +2963,6 @@ pub fn declIterator(zir: Zir, decl_inst: u32) DeclIterator {
2937 const tags = zir.instructions.items(.tag);2963 const tags = zir.instructions.items(.tag);
2938 const datas = zir.instructions.items(.data);2964 const datas = zir.instructions.items(.data);
2939 switch (tags[decl_inst]) {2965 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
2949 // Functions are allowed and yield no iterations.2966 // Functions are allowed and yield no iterations.
2950 // There is one case matching this in the extended instruction set below.2967 // There is one case matching this in the extended instruction set below.
2951 .func,2968 .func,
...@@ -3000,6 +3017,18 @@ pub fn declIterator(zir: Zir, decl_inst: u32) DeclIterator {...@@ -3000,6 +3017,18 @@ pub fn declIterator(zir: Zir, decl_inst: u32) DeclIterator {
30003017
3001 return declIteratorInner(zir, extra_index, decls_len);3018 return declIteratorInner(zir, extra_index, decls_len);
3002 },3019 },
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 },
3003 else => unreachable,3032 else => unreachable,
3004 }3033 }
3005 },3034 },
...@@ -3037,13 +3066,6 @@ fn findDeclsInner(...@@ -3037,13 +3066,6 @@ fn findDeclsInner(
3037 const datas = zir.instructions.items(.data);3066 const datas = zir.instructions.items(.data);
30383067
3039 switch (tags[inst]) {3068 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
3047 // Functions instructions are interesting and have a body.3069 // Functions instructions are interesting and have a body.
3048 .func,3070 .func,
3049 .func_inferred,3071 .func_inferred,
...@@ -3071,9 +3093,12 @@ fn findDeclsInner(...@@ -3071,9 +3093,12 @@ fn findDeclsInner(
3071 return zir.findDeclsBody(list, body);3093 return zir.findDeclsBody(list, body);
3072 },3094 },
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.
3074 .struct_decl,3098 .struct_decl,
3075 .union_decl,3099 .union_decl,
3076 .enum_decl,3100 .enum_decl,
3101 .opaque_decl,
3077 => return list.append(inst),3102 => return list.append(inst),
30783103
3079 else => return,3104 else => return,
src/print_zir.zig+37-16
...@@ -26,7 +26,7 @@ pub fn renderAsTextToFile(...@@ -26,7 +26,7 @@ pub fn renderAsTextToFile(
26 .parent_decl_node = 0,26 .parent_decl_node = 0,
27 };27 };
2828
29 const main_struct_inst = scope_file.zir.getMainStruct();29 const main_struct_inst = Zir.main_struct_inst;
30 try fs_file.writer().print("%{d} ", .{main_struct_inst});30 try fs_file.writer().print("%{d} ", .{main_struct_inst});
31 try writer.writeInstToStream(fs_file.writer(), main_struct_inst);31 try writer.writeInstToStream(fs_file.writer(), main_struct_inst);
32 try fs_file.writeAll("\n");32 try fs_file.writeAll("\n");
...@@ -171,6 +171,7 @@ const Writer = struct {...@@ -171,6 +171,7 @@ const Writer = struct {
171 .ref,171 .ref,
172 .ret_coerce,172 .ret_coerce,
173 .ensure_err_payload_void,173 .ensure_err_payload_void,
174 .closure_capture,
174 => try self.writeUnTok(stream, inst),175 => try self.writeUnTok(stream, inst),
175176
176 .bool_br_and,177 .bool_br_and,
...@@ -307,10 +308,6 @@ const Writer = struct {...@@ -307,10 +308,6 @@ const Writer = struct {
307 .condbr_inline,308 .condbr_inline,
308 => try self.writePlNodeCondBr(stream, inst),309 => 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
314 .error_set_decl => try self.writeErrorSetDecl(stream, inst, .parent),311 .error_set_decl => try self.writeErrorSetDecl(stream, inst, .parent),
315 .error_set_decl_anon => try self.writeErrorSetDecl(stream, inst, .anon),312 .error_set_decl_anon => try self.writeErrorSetDecl(stream, inst, .anon),
316 .error_set_decl_func => try self.writeErrorSetDecl(stream, inst, .func),313 .error_set_decl_func => try self.writeErrorSetDecl(stream, inst, .func),
...@@ -371,6 +368,8 @@ const Writer = struct {...@@ -371,6 +368,8 @@ const Writer = struct {
371368
372 .dbg_stmt => try self.writeDbgStmt(stream, inst),369 .dbg_stmt => try self.writeDbgStmt(stream, inst),
373370
371 .closure_get => try self.writeInstNode(stream, inst),
372
374 .extended => try self.writeExtended(stream, inst),373 .extended => try self.writeExtended(stream, inst),
375 }374 }
376 }375 }
...@@ -412,6 +411,7 @@ const Writer = struct {...@@ -412,6 +411,7 @@ const Writer = struct {
412 .struct_decl => try self.writeStructDecl(stream, extended),411 .struct_decl => try self.writeStructDecl(stream, extended),
413 .union_decl => try self.writeUnionDecl(stream, extended),412 .union_decl => try self.writeUnionDecl(stream, extended),
414 .enum_decl => try self.writeEnumDecl(stream, extended),413 .enum_decl => try self.writeEnumDecl(stream, extended),
414 .opaque_decl => try self.writeOpaqueDecl(stream, extended),
415415
416 .c_undef, .c_include => {416 .c_undef, .c_include => {
417 const inst_data = self.code.extraData(Zir.Inst.UnNode, extended.operand).data;417 const inst_data = self.code.extraData(Zir.Inst.UnNode, extended.operand).data;
...@@ -745,6 +745,17 @@ const Writer = struct {...@@ -745,6 +745,17 @@ const Writer = struct {
745 try self.writeSrc(stream, src);745 try self.writeSrc(stream, src);
746 }746 }
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
748 fn writeAsm(self: *Writer, stream: anytype, extended: Zir.Inst.Extended.InstData) !void {759 fn writeAsm(self: *Writer, stream: anytype, extended: Zir.Inst.Extended.InstData) !void {
749 const extra = self.code.extraData(Zir.Inst.Asm, extended.operand);760 const extra = self.code.extraData(Zir.Inst.Asm, extended.operand);
750 const src: LazySrcLoc = .{ .node_offset = extra.data.src_node };761 const src: LazySrcLoc = .{ .node_offset = extra.data.src_node };
...@@ -1365,26 +1376,36 @@ const Writer = struct {...@@ -1365,26 +1376,36 @@ const Writer = struct {
1365 fn writeOpaqueDecl(1376 fn writeOpaqueDecl(
1366 self: *Writer,1377 self: *Writer,
1367 stream: anytype,1378 stream: anytype,
1368 inst: Zir.Inst.Index,1379 extended: Zir.Inst.Extended.InstData,
1369 name_strategy: Zir.Inst.NameStrategy,
1370 ) !void {1380 ) !void {
1371 const inst_data = self.code.instructions.items(.data)[inst].pl_node;1381 const small = @bitCast(Zir.Inst.OpaqueDecl.Small, extended.small);
1372 const extra = self.code.extraData(Zir.Inst.OpaqueDecl, inst_data.payload_index);1382 var extra_index: usize = extended.operand;
1373 const decls_len = extra.data.decls_len;
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
1377 if (decls_len == 0) {1398 if (decls_len == 0) {
1378 try stream.writeAll("}) ");1399 try stream.writeAll("{})");
1379 } else {1400 } else {
1380 try stream.writeAll("\n");1401 try stream.writeAll("{\n");
1381 self.indent += 2;1402 self.indent += 2;
1382 _ = try self.writeDecls(stream, decls_len, extra.end);1403 _ = try self.writeDecls(stream, decls_len, extra_index);
1383 self.indent -= 2;1404 self.indent -= 2;
1384 try stream.writeByteNTimes(' ', self.indent);1405 try stream.writeByteNTimes(' ', self.indent);
1385 try stream.writeAll("}) ");1406 try stream.writeAll("})");
1386 }1407 }
1387 try self.writeSrc(stream, inst_data.src());1408 try self.writeSrcNode(stream, src_node);
1388 }1409 }
13891410
1390 fn writeErrorSetDecl(1411 fn writeErrorSetDecl(
test/behavior.zig+10-9
...@@ -1,20 +1,22 @@...@@ -1,20 +1,22 @@
1const builtin = @import("builtin");1const builtin = @import("builtin");
22
3test {3test {
4 _ = @import("behavior/bool.zig");4 // Tests that pass for both.
5 _ = @import("behavior/array.zig");
6 _ = @import("behavior/atomics.zig");
5 _ = @import("behavior/basic.zig");7 _ = @import("behavior/basic.zig");
6 _ = @import("behavior/generics.zig");8 _ = @import("behavior/bool.zig");
9 _ = @import("behavior/cast.zig");
7 _ = @import("behavior/eval.zig");10 _ = @import("behavior/eval.zig");
8 _ = @import("behavior/pointers.zig");11 _ = @import("behavior/generics.zig");
9 _ = @import("behavior/if.zig");12 _ = @import("behavior/if.zig");
10 _ = @import("behavior/cast.zig");13 _ = @import("behavior/pointers.zig");
11 _ = @import("behavior/array.zig");
12 _ = @import("behavior/usingnamespace.zig");
13 _ = @import("behavior/atomics.zig");
14 _ = @import("behavior/sizeof_and_typeof.zig");14 _ = @import("behavior/sizeof_and_typeof.zig");
15 _ = @import("behavior/translate_c_macros.zig");
16 _ = @import("behavior/struct.zig");15 _ = @import("behavior/struct.zig");
16 _ = @import("behavior/this.zig");
17 _ = @import("behavior/translate_c_macros.zig");
17 _ = @import("behavior/union.zig");18 _ = @import("behavior/union.zig");
19 _ = @import("behavior/usingnamespace.zig");
18 _ = @import("behavior/widening.zig");20 _ = @import("behavior/widening.zig");
1921
20 if (builtin.zig_is_stage2) {22 if (builtin.zig_is_stage2) {
...@@ -142,7 +144,6 @@ test {...@@ -142,7 +144,6 @@ test {
142 _ = @import("behavior/switch.zig");144 _ = @import("behavior/switch.zig");
143 _ = @import("behavior/switch_prong_err_enum.zig");145 _ = @import("behavior/switch_prong_err_enum.zig");
144 _ = @import("behavior/switch_prong_implicit_cast.zig");146 _ = @import("behavior/switch_prong_implicit_cast.zig");
145 _ = @import("behavior/this.zig");
146 _ = @import("behavior/truncate.zig");147 _ = @import("behavior/truncate.zig");
147 _ = @import("behavior/try.zig");148 _ = @import("behavior/try.zig");
148 _ = @import("behavior/tuple.zig");149 _ = @import("behavior/tuple.zig");
test/behavior/this.zig+4-5
...@@ -24,11 +24,10 @@ test "this refer to module call private fn" {...@@ -24,11 +24,10 @@ test "this refer to module call private fn" {
24}24}
2525
26test "this refer to container" {26test "this refer to container" {
27 var pt = Point(i32){27 var pt: Point(i32) = undefined;
28 .x = 12,28 pt.x = 12;
29 .y = 34,29 pt.y = 34;
30 };30 Point(i32).addOne(&pt);
31 pt.addOne();
32 try expect(pt.x == 13);31 try expect(pt.x == 13);
33 try expect(pt.y == 35);32 try expect(pt.y == 35);
34}33}