| author | |
| committer | |
| log | a0a847f2e40046387e2e2b8a0b8dae9cb27ca22a |
| tree | 2fdaa3bdd0ab7d63eb54e1bd92aca1f1607cca14 |
| parent | f615648d7bdcb5c7ed38ad15169a8fa90bd86ca0 |
| signature |
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, |
| 2166 | 2164 | ||
| 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); |
| 3555 | 3555 | ||
| 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 struct | 3564 | // 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 expressions | 3565 | // 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); |
| 3568 | 3576 | ||
| 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); |
| 3573 | 3578 | ||
| 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 | } |
| 3775 | 3780 | ||
| 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 | }); |
| 3789 | 3793 | ||
| 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); |
| 3826 | 3839 | ||
| 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 union | 3848 | // 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 expressions | 3849 | // 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); |
| 3839 | 3860 | ||
| 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); |
| 3844 | 3862 | ||
| 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 | else | 3865 | else |
| 3848 | .none; | 3866 | .none; |
| 3849 | 3867 | ||
| ... | @@ -4056,7 +4074,6 @@ fn unionDeclInner( | ... | @@ -4056,7 +4074,6 @@ fn unionDeclInner( |
| 4056 | } | 4074 | } |
| 4057 | } | 4075 | } |
| 4058 | 4076 | ||
| 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 | }); |
| 4073 | 4090 | ||
| 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; |
| 4240 | 4264 | ||
| 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 enum | 4275 | // 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); |
| 4252 | 4286 | ||
| 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); |
| 4257 | 4288 | ||
| 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 | else | 4291 | else |
| 4261 | .none; | 4292 | .none; |
| 4262 | 4293 | ||
| ... | @@ -4451,7 +4482,6 @@ fn containerDecl( | ... | @@ -4451,7 +4482,6 @@ fn containerDecl( |
| 4451 | } | 4482 | } |
| 4452 | } | 4483 | } |
| 4453 | 4484 | ||
| 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 | }); |
| 4467 | 4497 | ||
| 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); |
| 4488 | 4525 | ||
| 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); | ||
| 4491 | 4535 | ||
| 4492 | try astgen.scanDecls(&namespace, container_decl.ast.members); | 4536 | try astgen.scanDecls(&namespace, container_decl.ast.members); |
| 4493 | 4537 | ||
| ... | @@ -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); | ||
| 4635 | 4672 | ||
| 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( |
| 6380 | 6423 | ||
| 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); |
| 6384 | 6428 | ||
| 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 already | 6472 | 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).?; |
| 6433 | 6478 | ||
| 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 ambiguous | 6480 | // 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 | } |
| 6495 | 6565 | ||
| 6566 | /// Adds a capture to a namespace, if needed. | ||
| 6567 | /// Returns the index of the closure_capture instruction. | ||
| 6568 | fn 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 | |||
| 6496 | fn stringLiteral( | 6597 | fn 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 | } |
| 8963 | 9064 | ||
| 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 { |
| 9023 | 9135 | ||
| 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 }, |
| 9036 | 9148 | ||
| 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 | }; |
| 9043 | 9171 | ||
| 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, |
| 9098 | 9227 | ||
| 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 | } |
| 9812 | 9947 | ||
| 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 | } |
| 10113 | 10264 | ||
| 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 | }; |
| 277 | 277 | ||
| 278 | pub 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 | |||
| 288 | pub 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 | |||
| 278 | pub const Decl = struct { | 328 | pub 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, |
| 301 | 351 | ||
| 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 incrementing | 357 | /// An integer that can be checked against the corresponding incrementing |
| 303 | /// generation field of Module. This is used to determine whether `complete` status | 358 | /// 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 | } |
| 961 | 1016 | ||
| 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 | } |
| 969 | 1025 | ||
| 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 | } |
| 977 | 1034 | ||
| 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); |
| 2903 | 2973 | ||
| 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 | }); |
| 2911 | 2979 | ||
| 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 below | 3137 | .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 { |
| 3097 | 3166 | ||
| 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; |
| 3102 | 3171 | ||
| 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); |
| 3127 | 3202 | ||
| 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 { |
| 3155 | 3231 | ||
| 3156 | decl.analysis = .in_progress; | 3232 | decl.analysis = .in_progress; |
| 3157 | 3233 | ||
| 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(); |
| 3160 | 3240 | ||
| ... | @@ -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 { |
| 3173 | 3254 | ||
| 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 had | 3259 | // 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 }); |
| 3187 | 3268 | ||
| 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); |
| 3241 | 3327 | ||
| 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); |
| 3246 | 3329 | ||
| 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 |
| 3898 | 3981 | ||
| 3899 | const gpa = mod.gpa; | 3982 | const gpa = mod.gpa; |
| 3900 | 3983 | ||
| 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; |
| 3918 | 4006 | ||
| 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 | }; |
| 3997 | 4089 | ||
| 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 | } |
| 4037 | 4131 | ||
| 4038 | pub fn allocateNewDecl(mod: *Module, namespace: *Scope.Namespace, src_node: Ast.Node.Index) !*Decl { | 4132 | pub 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 | } |
| 4092 | 4188 | ||
| ... | @@ -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 | } |
| 4196 | 4292 | ||
| 4197 | pub fn createAnonymousDecl(mod: *Module, scope: *Scope, typed_value: TypedValue) !*Decl { | 4293 | pub 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 | } |
| 4200 | 4296 | ||
| 4201 | pub fn createAnonymousDeclFromDecl(mod: *Module, owner_decl: *Decl, tv: TypedValue) !*Decl { | 4297 | pub 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 | } |
| 4208 | 4304 | ||
| 4209 | /// Takes ownership of `name` even if it returns an error. | 4305 | /// Takes ownership of `name` even if it returns an error. |
| 4210 | pub fn createAnonymousDeclFromDeclNamed( | 4306 | pub 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); |
| 4220 | 4317 | ||
| 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); |
| 4222 | 4319 | ||
| 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; |
| 4784 | 4881 | ||
| 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 @@ |
| 8 | mod: *Module, | 8 | mod: *Module, |
| 9 | /// Alias to `mod.gpa`. | 9 | /// Alias to `mod.gpa`. |
| 10 | gpa: *Allocator, | 10 | gpa: *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. | ||
| 12 | arena: *Allocator, | 13 | arena: *Allocator, |
| 14 | /// Points to the arena allocator for the owner_decl. | ||
| 15 | /// This arena will persist until the decl is invalidated. | ||
| 16 | perm_arena: *Allocator, | ||
| 13 | code: Zir, | 17 | code: Zir, |
| 14 | air_instructions: std.MultiArrayList(Air.Inst) = .{}, | 18 | air_instructions: std.MultiArrayList(Air.Inst) = .{}, |
| 15 | air_extra: std.ArrayListUnmanaged(u32) = .{}, | 19 | air_extra: std.ArrayListUnmanaged(u32) = .{}, |
| ... | @@ -80,6 +84,8 @@ const Scope = Module.Scope; | ... | @@ -80,6 +84,8 @@ const Scope = Module.Scope; |
| 80 | const CompileError = Module.CompileError; | 84 | const CompileError = Module.CompileError; |
| 81 | const SemaError = Module.SemaError; | 85 | const SemaError = Module.SemaError; |
| 82 | const Decl = Module.Decl; | 86 | const Decl = Module.Decl; |
| 87 | const CaptureScope = Module.CaptureScope; | ||
| 88 | const WipCaptureScope = Module.WipCaptureScope; | ||
| 83 | const LazySrcLoc = Module.LazySrcLoc; | 89 | const LazySrcLoc = Module.LazySrcLoc; |
| 84 | const RangeSet = @import("RangeSet.zig"); | 90 | const RangeSet = @import("RangeSet.zig"); |
| 85 | const target_util = @import("target.zig"); | 91 | const 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. |
| 131 | 137 | ||
| 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); |
| 135 | 153 | ||
| 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 of | 156 | // 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: off | 163 | // 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), |
| 345 | 366 | ||
| 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 can | 381 | // 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: on | 390 | // zig fmt: on |
| 373 | 391 | ||
| 374 | // Instructions that we know can *never* be noreturn based solely on | 392 | // 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 | }, | ||
| 506 | 529 | ||
| 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_inline | 533 | 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/8220 | 613 | // 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 | } |
| 619 | 659 | ||
| 620 | fn zirExtended(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { | 660 | fn 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 | } |
| 1012 | 1053 | ||
| 1013 | fn createTypeName(sema: *Sema, block: *Scope.Block, name_strategy: Zir.Inst.NameStrategy) ![:0]u8 { | 1054 | fn 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 has | 1057 | // 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(); |
| 1085 | 1125 | ||
| 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( |
| 1112 | 1141 | ||
| 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; |
| 1142 | 1171 | ||
| 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 they | 1173 | // 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; |
| 1174 | 1193 | ||
| 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 | } |
| 1233 | 1279 | ||
| ... | @@ -1305,20 +1351,14 @@ fn zirUnionDecl( | ... | @@ -1305,20 +1351,14 @@ fn zirUnionDecl( |
| 1305 | fn zirOpaqueDecl( | 1351 | fn 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(); |
| 1313 | 1359 | ||
| 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 | } |
| 1324 | 1364 | ||
| ... | @@ -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 | } |
| 2219 | 2260 | ||
| 2220 | fn zirSuspendBlock(sema: *Sema, parent_block: *Scope.Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { | 2261 | fn 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; |
| 2868 | 2910 | ||
| 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( |
| 3034 | 3080 | ||
| 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); |
| 3117 | 3166 | ||
| 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 instantiations | 3170 | // 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(); |
| 3161 | 3212 | ||
| 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 | } |
| 3252 | 3307 | ||
| 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; |
| 5270 | 5328 | ||
| 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. |
| 5274 | 5337 | ||
| 5275 | _ = try sema.analyzeBody(&case_block, body); | 5338 | _ = try sema.analyzeBody(&case_block, body); |
| 5276 | 5339 | ||
| 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_len | 5343 | 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; |
| 5302 | 5367 | ||
| 5303 | case_block.instructions.shrinkRetainingCapacity(0); | 5368 | case_block.instructions.shrinkRetainingCapacity(0); |
| 5369 | case_block.wip_capture_scope = child_block.wip_capture_scope; | ||
| 5304 | 5370 | ||
| 5305 | var any_ok: Air.Inst.Ref = .none; | 5371 | var any_ok: Air.Inst.Ref = .none; |
| 5306 | 5372 | ||
| ... | @@ -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); |
| 5381 | 5447 | ||
| 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); |
| 5386 | 5457 | ||
| 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( |
| 5409 | 5482 | ||
| 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); |
| 5414 | 5492 | ||
| 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 | } |
| 5698 | 5778 | ||
| 5699 | fn zirRetErrValueCode(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { | 5779 | fn 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 | |||
| 6624 | fn 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 | |||
| 6638 | fn 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 | } |
| 6542 | 6659 | ||
| 6543 | fn zirRetAddr( | 6660 | fn 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; |
| 10668 | 10786 | ||
| 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; |
| 10686 | 10808 | ||
| 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); |
| 10887 | 11013 | ||
| 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; | ||
| 10891 | 11019 | ||
| 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 | } |
| 10997 | 11125 | ||
| 10998 | // TODO resolve the union tag_type_ref | 11126 | // TODO resolve the union tag_type_ref |
| 11127 | _ = tag_type_ref; | ||
| 10999 | } | 11128 | } |
| 11000 | 11129 | ||
| 11001 | fn getBuiltin( | 11130 | fn 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 | }; |
| 50 | 50 | ||
| 51 | pub const ExtraIndex = enum(u32) { | 51 | pub 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 | }; |
| 63 | 61 | ||
| 64 | pub 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 the | 62 | /// 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. |
| 71 | pub fn extraData(code: Zir, comptime T: type, index: usize) struct { data: T, end: usize } { | 64 | pub 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 | } |
| 114 | 107 | ||
| 108 | /// ZIR is structured so that the outermost "main" struct of any file | ||
| 109 | /// is always at index 0. | ||
| 110 | pub 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 multiple | 113 | /// 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 must | 264 | /// 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, |
| 943 | 935 | ||
| 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, |
| 1195 | 1197 | ||
| 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, |
| 1480 | 1479 | ||
| 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 | }, | ||
| 2197 | 2215 | ||
| 2198 | // Make sure we don't accidentally add a field to make this union | 2216 | // Make sure we don't accidentally add a field to make this union |
| 2199 | // bigger than expected. Note that in Debug builds, Zig is allowed | 2217 | // 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 | }; |
| 2236 | 2255 | ||
| ... | @@ -2662,13 +2681,15 @@ pub const Inst = struct { | ... | @@ -2662,13 +2681,15 @@ pub const Inst = struct { |
| 2662 | }; | 2681 | }; |
| 2663 | 2682 | ||
| 2664 | /// Trailing: | 2683 | /// Trailing: |
| 2665 | /// 0. decl_bits: u32 // for every 8 decls | 2684 | /// 0. src_node: i32, // if has_src_node |
| 2685 | /// 1. decls_len: u32, // if has_decls_len | ||
| 2686 | /// 2. decl_bits: u32 // for every 8 decls | ||
| 2666 | /// - sets of 4 bits: | 2687 | /// - sets of 4 bits: |
| 2667 | /// 0b000X: whether corresponding decl is pub | 2688 | /// 0b000X: whether corresponding decl is pub |
| 2668 | /// 0b00X0: whether corresponding decl is exported | 2689 | /// 0b00X0: whether corresponding decl is exported |
| 2669 | /// 0b0X00: whether corresponding decl has an align expression | 2690 | /// 0b0X00: whether corresponding decl has an align expression |
| 2670 | /// 0bX000: whether corresponding decl has a linksection or an address space expression | 2691 | /// 0bX000: whether corresponding decl has a linksection or an address space expression |
| 2671 | /// 1. decl: { // for every decls_len | 2692 | /// 3. decl: { // for every decls_len |
| 2672 | /// src_hash: [4]u32, // hash of source bytes | 2693 | /// src_hash: [4]u32, // hash of source bytes |
| 2673 | /// line: u32, // line number of decl, relative to parent | 2694 | /// line: u32, // line number of decl, relative to parent |
| 2674 | /// name: u32, // null terminated string index | 2695 | /// 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 | }; |
| 2690 | 2716 | ||
| 2691 | /// Trailing: field_name: u32 // for every field: null terminated string index | 2717 | /// 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 { |
| 3000 | 3017 | ||
| 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); |
| 3038 | 3067 | ||
| 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 | }, |
| 3073 | 3095 | ||
| 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), |
| 3078 | 3103 | ||
| 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 | }; |
| 28 | 28 | ||
| 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), |
| 175 | 176 | ||
| 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), |
| 309 | 310 | ||
| 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 { |
| 371 | 368 | ||
| 372 | .dbg_stmt => try self.writeDbgStmt(stream, inst), | 369 | .dbg_stmt => try self.writeDbgStmt(stream, inst), |
| 373 | 370 | ||
| 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), | ||
| 415 | 415 | ||
| 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 | } |
| 747 | 747 | ||
| 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; | ||
| 1374 | 1383 | ||
| 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)}); | ||
| 1376 | 1397 | ||
| 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 | } |
| 1389 | 1410 | ||
| 1390 | fn writeErrorSetDecl( | 1411 | fn writeErrorSetDecl( |
test/behavior.zig+10-9| ... | @@ -1,20 +1,22 @@ | ... | @@ -1,20 +1,22 @@ |
| 1 | const builtin = @import("builtin"); | 1 | const builtin = @import("builtin"); |
| 2 | 2 | ||
| 3 | test { | 3 | test { |
| 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"); |
| 19 | 21 | ||
| 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 | } |
| 25 | 25 | ||
| 26 | test "this refer to container" { | 26 | test "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 | } |