| author | |
| committer | |
| log | 4929cf23cedef2ca8a8cfb2f9379d136681a6f37 |
| tree | 04156c9a729b5029a3682ff25fef088156addfdd |
| parent | 2b05e85107dd1c637ab40f8b145b232d18e8d6c6 |
| parent | f0374fe3f04925a6e686077c2ffcb51b8eafc926 |
| signature |
Incremental compilation progress19 files changed, 3171 insertions(+), 966 deletions(-)
lib/std/bounded_array.zig+5| ... | @@ -72,6 +72,11 @@ pub fn BoundedArrayAligned( | ... | @@ -72,6 +72,11 @@ pub fn BoundedArrayAligned( |
| 72 | self.len = @intCast(len); | 72 | self.len = @intCast(len); |
| 73 | } | 73 | } |
| 74 | 74 | ||
| 75 | /// Remove all elements from the slice. | ||
| 76 | pub fn clear(self: *Self) void { | ||
| 77 | self.len = 0; | ||
| 78 | } | ||
| 79 | |||
| 75 | /// Copy the content of an existing slice. | 80 | /// Copy the content of an existing slice. |
| 76 | pub fn fromSlice(m: []const T) error{Overflow}!Self { | 81 | pub fn fromSlice(m: []const T) error{Overflow}!Self { |
| 77 | var list = try init(m.len); | 82 | var list = try init(m.len); |
lib/std/zig/Zir.zig+606-54| ... | @@ -603,7 +603,7 @@ pub const Inst = struct { | ... | @@ -603,7 +603,7 @@ pub const Inst = struct { |
| 603 | /// Uses the `un_node` field. | 603 | /// Uses the `un_node` field. |
| 604 | typeof, | 604 | typeof, |
| 605 | /// Implements `@TypeOf` for one operand. | 605 | /// Implements `@TypeOf` for one operand. |
| 606 | /// Uses the `pl_node` field. | 606 | /// Uses the `pl_node` field. Payload is `Block`. |
| 607 | typeof_builtin, | 607 | typeof_builtin, |
| 608 | /// Given a value, look at the type of it, which must be an integer type. | 608 | /// Given a value, look at the type of it, which must be an integer type. |
| 609 | /// Returns the integer type for the RHS of a shift operation. | 609 | /// Returns the integer type for the RHS of a shift operation. |
| ... | @@ -2727,6 +2727,9 @@ pub const Inst = struct { | ... | @@ -2727,6 +2727,9 @@ pub const Inst = struct { |
| 2727 | field_name_start: NullTerminatedString, | 2727 | field_name_start: NullTerminatedString, |
| 2728 | }; | 2728 | }; |
| 2729 | 2729 | ||
| 2730 | /// There is a body of instructions at `extra[body_index..][0..body_len]`. | ||
| 2731 | /// Trailing: | ||
| 2732 | /// 0. operand: Ref // for each `operands_len` | ||
| 2730 | pub const TypeOfPeer = struct { | 2733 | pub const TypeOfPeer = struct { |
| 2731 | src_node: i32, | 2734 | src_node: i32, |
| 2732 | body_len: u32, | 2735 | body_len: u32, |
| ... | @@ -2844,6 +2847,40 @@ pub const Inst = struct { | ... | @@ -2844,6 +2847,40 @@ pub const Inst = struct { |
| 2844 | src_line: u32, | 2847 | src_line: u32, |
| 2845 | }; | 2848 | }; |
| 2846 | 2849 | ||
| 2850 | /// Trailing: | ||
| 2851 | /// 0. multi_cases_len: u32 // if `has_multi_cases` | ||
| 2852 | /// 1. err_capture_inst: u32 // if `any_uses_err_capture` | ||
| 2853 | /// 2. non_err_body { | ||
| 2854 | /// info: ProngInfo, | ||
| 2855 | /// inst: Index // for every `info.body_len` | ||
| 2856 | /// } | ||
| 2857 | /// 3. else_body { // if `has_else` | ||
| 2858 | /// info: ProngInfo, | ||
| 2859 | /// inst: Index // for every `info.body_len` | ||
| 2860 | /// } | ||
| 2861 | /// 4. scalar_cases: { // for every `scalar_cases_len` | ||
| 2862 | /// item: Ref, | ||
| 2863 | /// info: ProngInfo, | ||
| 2864 | /// inst: Index // for every `info.body_len` | ||
| 2865 | /// } | ||
| 2866 | /// 5. multi_cases: { // for every `multi_cases_len` | ||
| 2867 | /// items_len: u32, | ||
| 2868 | /// ranges_len: u32, | ||
| 2869 | /// info: ProngInfo, | ||
| 2870 | /// item: Ref // for every `items_len` | ||
| 2871 | /// ranges: { // for every `ranges_len` | ||
| 2872 | /// item_first: Ref, | ||
| 2873 | /// item_last: Ref, | ||
| 2874 | /// } | ||
| 2875 | /// inst: Index // for every `info.body_len` | ||
| 2876 | /// } | ||
| 2877 | /// | ||
| 2878 | /// When analyzing a case body, the switch instruction itself refers to the | ||
| 2879 | /// captured error, or to the success value in `non_err_body`. Whether this | ||
| 2880 | /// is captured by reference or by value depends on whether the `byref` bit | ||
| 2881 | /// is set for the corresponding body. `err_capture_inst` refers to the error | ||
| 2882 | /// capture outside of the `switch`, i.e. `err` in | ||
| 2883 | /// `x catch |err| switch (err) { ... }`. | ||
| 2847 | pub const SwitchBlockErrUnion = struct { | 2884 | pub const SwitchBlockErrUnion = struct { |
| 2848 | operand: Ref, | 2885 | operand: Ref, |
| 2849 | bits: Bits, | 2886 | bits: Bits, |
| ... | @@ -3153,7 +3190,7 @@ pub const Inst = struct { | ... | @@ -3153,7 +3190,7 @@ pub const Inst = struct { |
| 3153 | /// 1. captures_len: u32 // if has_captures_len | 3190 | /// 1. captures_len: u32 // if has_captures_len |
| 3154 | /// 2. body_len: u32, // if has_body_len | 3191 | /// 2. body_len: u32, // if has_body_len |
| 3155 | /// 3. fields_len: u32, // if has_fields_len | 3192 | /// 3. fields_len: u32, // if has_fields_len |
| 3156 | /// 4. decls_len: u37, // if has_decls_len | 3193 | /// 4. decls_len: u32, // if has_decls_len |
| 3157 | /// 5. capture: Capture // for every captures_len | 3194 | /// 5. capture: Capture // for every captures_len |
| 3158 | /// 6. decl: Index, // for every decls_len; points to a `declaration` instruction | 3195 | /// 6. decl: Index, // for every decls_len; points to a `declaration` instruction |
| 3159 | /// 7. inst: Index // for every body_len | 3196 | /// 7. inst: Index // for every body_len |
| ... | @@ -3624,33 +3661,492 @@ pub fn declIterator(zir: Zir, decl_inst: Zir.Inst.Index) DeclIterator { | ... | @@ -3624,33 +3661,492 @@ pub fn declIterator(zir: Zir, decl_inst: Zir.Inst.Index) DeclIterator { |
| 3624 | } | 3661 | } |
| 3625 | } | 3662 | } |
| 3626 | 3663 | ||
| 3627 | /// The iterator would have to allocate memory anyway to iterate. So here we populate | 3664 | /// Find all type declarations, recursively, within a `declaration` instruction. Does not recurse through |
| 3628 | /// an ArrayList as the result. | 3665 | /// said type declarations' declarations; to find all declarations, call this function on the declarations |
| 3629 | pub fn findDecls(zir: Zir, list: *std.ArrayList(Inst.Index), decl_inst: Zir.Inst.Index) !void { | 3666 | /// of the discovered types recursively. |
| 3667 | /// The iterator would have to allocate memory anyway to iterate, so an `ArrayList` is populated as the result. | ||
| 3668 | pub fn findDecls(zir: Zir, gpa: Allocator, list: *std.ArrayListUnmanaged(Inst.Index), decl_inst: Zir.Inst.Index) !void { | ||
| 3630 | list.clearRetainingCapacity(); | 3669 | list.clearRetainingCapacity(); |
| 3631 | const declaration, const extra_end = zir.getDeclaration(decl_inst); | 3670 | const declaration, const extra_end = zir.getDeclaration(decl_inst); |
| 3632 | const bodies = declaration.getBodies(extra_end, zir); | 3671 | const bodies = declaration.getBodies(extra_end, zir); |
| 3633 | 3672 | ||
| 3634 | try zir.findDeclsBody(list, bodies.value_body); | 3673 | // `defer` instructions duplicate the same body arbitrarily many times, but we only want to traverse |
| 3635 | if (bodies.align_body) |b| try zir.findDeclsBody(list, b); | 3674 | // their contents once per defer. So, we store the extra index of the body here to deduplicate. |
| 3636 | if (bodies.linksection_body) |b| try zir.findDeclsBody(list, b); | 3675 | var found_defers: std.AutoHashMapUnmanaged(u32, void) = .{}; |
| 3637 | if (bodies.addrspace_body) |b| try zir.findDeclsBody(list, b); | 3676 | defer found_defers.deinit(gpa); |
| 3677 | |||
| 3678 | try zir.findDeclsBody(gpa, list, &found_defers, bodies.value_body); | ||
| 3679 | if (bodies.align_body) |b| try zir.findDeclsBody(gpa, list, &found_defers, b); | ||
| 3680 | if (bodies.linksection_body) |b| try zir.findDeclsBody(gpa, list, &found_defers, b); | ||
| 3681 | if (bodies.addrspace_body) |b| try zir.findDeclsBody(gpa, list, &found_defers, b); | ||
| 3638 | } | 3682 | } |
| 3639 | 3683 | ||
| 3640 | fn findDeclsInner( | 3684 | fn findDeclsInner( |
| 3641 | zir: Zir, | 3685 | zir: Zir, |
| 3642 | list: *std.ArrayList(Inst.Index), | 3686 | gpa: Allocator, |
| 3687 | list: *std.ArrayListUnmanaged(Inst.Index), | ||
| 3688 | defers: *std.AutoHashMapUnmanaged(u32, void), | ||
| 3643 | inst: Inst.Index, | 3689 | inst: Inst.Index, |
| 3644 | ) Allocator.Error!void { | 3690 | ) Allocator.Error!void { |
| 3645 | const tags = zir.instructions.items(.tag); | 3691 | const tags = zir.instructions.items(.tag); |
| 3646 | const datas = zir.instructions.items(.data); | 3692 | const datas = zir.instructions.items(.data); |
| 3647 | 3693 | ||
| 3648 | switch (tags[@intFromEnum(inst)]) { | 3694 | switch (tags[@intFromEnum(inst)]) { |
| 3695 | .declaration => unreachable, | ||
| 3696 | |||
| 3697 | // Boring instruction tags first. These have no body and are not declarations or type declarations. | ||
| 3698 | .add, | ||
| 3699 | .addwrap, | ||
| 3700 | .add_sat, | ||
| 3701 | .add_unsafe, | ||
| 3702 | .sub, | ||
| 3703 | .subwrap, | ||
| 3704 | .sub_sat, | ||
| 3705 | .mul, | ||
| 3706 | .mulwrap, | ||
| 3707 | .mul_sat, | ||
| 3708 | .div_exact, | ||
| 3709 | .div_floor, | ||
| 3710 | .div_trunc, | ||
| 3711 | .mod, | ||
| 3712 | .rem, | ||
| 3713 | .mod_rem, | ||
| 3714 | .shl, | ||
| 3715 | .shl_exact, | ||
| 3716 | .shl_sat, | ||
| 3717 | .shr, | ||
| 3718 | .shr_exact, | ||
| 3719 | .param_anytype, | ||
| 3720 | .param_anytype_comptime, | ||
| 3721 | .array_cat, | ||
| 3722 | .array_mul, | ||
| 3723 | .array_type, | ||
| 3724 | .array_type_sentinel, | ||
| 3725 | .vector_type, | ||
| 3726 | .elem_type, | ||
| 3727 | .indexable_ptr_elem_type, | ||
| 3728 | .vector_elem_type, | ||
| 3729 | .indexable_ptr_len, | ||
| 3730 | .anyframe_type, | ||
| 3731 | .as_node, | ||
| 3732 | .as_shift_operand, | ||
| 3733 | .bit_and, | ||
| 3734 | .bitcast, | ||
| 3735 | .bit_not, | ||
| 3736 | .bit_or, | ||
| 3737 | .bool_not, | ||
| 3738 | .bool_br_and, | ||
| 3739 | .bool_br_or, | ||
| 3740 | .@"break", | ||
| 3741 | .break_inline, | ||
| 3742 | .check_comptime_control_flow, | ||
| 3743 | .builtin_call, | ||
| 3744 | .cmp_lt, | ||
| 3745 | .cmp_lte, | ||
| 3746 | .cmp_eq, | ||
| 3747 | .cmp_gte, | ||
| 3748 | .cmp_gt, | ||
| 3749 | .cmp_neq, | ||
| 3750 | .error_set_decl, | ||
| 3751 | .dbg_stmt, | ||
| 3752 | .dbg_var_ptr, | ||
| 3753 | .dbg_var_val, | ||
| 3754 | .decl_ref, | ||
| 3755 | .decl_val, | ||
| 3756 | .load, | ||
| 3757 | .div, | ||
| 3758 | .elem_ptr_node, | ||
| 3759 | .elem_ptr, | ||
| 3760 | .elem_val_node, | ||
| 3761 | .elem_val, | ||
| 3762 | .elem_val_imm, | ||
| 3763 | .ensure_result_used, | ||
| 3764 | .ensure_result_non_error, | ||
| 3765 | .ensure_err_union_payload_void, | ||
| 3766 | .error_union_type, | ||
| 3767 | .error_value, | ||
| 3768 | .@"export", | ||
| 3769 | .export_value, | ||
| 3770 | .field_ptr, | ||
| 3771 | .field_val, | ||
| 3772 | .field_ptr_named, | ||
| 3773 | .field_val_named, | ||
| 3774 | .import, | ||
| 3775 | .int, | ||
| 3776 | .int_big, | ||
| 3777 | .float, | ||
| 3778 | .float128, | ||
| 3779 | .int_type, | ||
| 3780 | .is_non_null, | ||
| 3781 | .is_non_null_ptr, | ||
| 3782 | .is_non_err, | ||
| 3783 | .is_non_err_ptr, | ||
| 3784 | .ret_is_non_err, | ||
| 3785 | .repeat, | ||
| 3786 | .repeat_inline, | ||
| 3787 | .for_len, | ||
| 3788 | .merge_error_sets, | ||
| 3789 | .ref, | ||
| 3790 | .ret_node, | ||
| 3791 | .ret_load, | ||
| 3792 | .ret_implicit, | ||
| 3793 | .ret_err_value, | ||
| 3794 | .ret_err_value_code, | ||
| 3795 | .ret_ptr, | ||
| 3796 | .ret_type, | ||
| 3797 | .ptr_type, | ||
| 3798 | .slice_start, | ||
| 3799 | .slice_end, | ||
| 3800 | .slice_sentinel, | ||
| 3801 | .slice_length, | ||
| 3802 | .store_node, | ||
| 3803 | .store_to_inferred_ptr, | ||
| 3804 | .str, | ||
| 3805 | .negate, | ||
| 3806 | .negate_wrap, | ||
| 3807 | .typeof, | ||
| 3808 | .typeof_log2_int_type, | ||
| 3809 | .@"unreachable", | ||
| 3810 | .xor, | ||
| 3811 | .optional_type, | ||
| 3812 | .optional_payload_safe, | ||
| 3813 | .optional_payload_unsafe, | ||
| 3814 | .optional_payload_safe_ptr, | ||
| 3815 | .optional_payload_unsafe_ptr, | ||
| 3816 | .err_union_payload_unsafe, | ||
| 3817 | .err_union_payload_unsafe_ptr, | ||
| 3818 | .err_union_code, | ||
| 3819 | .err_union_code_ptr, | ||
| 3820 | .enum_literal, | ||
| 3821 | .validate_deref, | ||
| 3822 | .validate_destructure, | ||
| 3823 | .field_type_ref, | ||
| 3824 | .opt_eu_base_ptr_init, | ||
| 3825 | .coerce_ptr_elem_ty, | ||
| 3826 | .validate_ref_ty, | ||
| 3827 | .struct_init_empty, | ||
| 3828 | .struct_init_empty_result, | ||
| 3829 | .struct_init_empty_ref_result, | ||
| 3830 | .struct_init_anon, | ||
| 3831 | .struct_init, | ||
| 3832 | .struct_init_ref, | ||
| 3833 | .validate_struct_init_ty, | ||
| 3834 | .validate_struct_init_result_ty, | ||
| 3835 | .validate_ptr_struct_init, | ||
| 3836 | .struct_init_field_type, | ||
| 3837 | .struct_init_field_ptr, | ||
| 3838 | .array_init_anon, | ||
| 3839 | .array_init, | ||
| 3840 | .array_init_ref, | ||
| 3841 | .validate_array_init_ty, | ||
| 3842 | .validate_array_init_result_ty, | ||
| 3843 | .validate_array_init_ref_ty, | ||
| 3844 | .validate_ptr_array_init, | ||
| 3845 | .array_init_elem_type, | ||
| 3846 | .array_init_elem_ptr, | ||
| 3847 | .union_init, | ||
| 3848 | .type_info, | ||
| 3849 | .size_of, | ||
| 3850 | .bit_size_of, | ||
| 3851 | .int_from_ptr, | ||
| 3852 | .compile_error, | ||
| 3853 | .set_eval_branch_quota, | ||
| 3854 | .int_from_enum, | ||
| 3855 | .align_of, | ||
| 3856 | .int_from_bool, | ||
| 3857 | .embed_file, | ||
| 3858 | .error_name, | ||
| 3859 | .panic, | ||
| 3860 | .trap, | ||
| 3861 | .set_runtime_safety, | ||
| 3862 | .sqrt, | ||
| 3863 | .sin, | ||
| 3864 | .cos, | ||
| 3865 | .tan, | ||
| 3866 | .exp, | ||
| 3867 | .exp2, | ||
| 3868 | .log, | ||
| 3869 | .log2, | ||
| 3870 | .log10, | ||
| 3871 | .abs, | ||
| 3872 | .floor, | ||
| 3873 | .ceil, | ||
| 3874 | .trunc, | ||
| 3875 | .round, | ||
| 3876 | .tag_name, | ||
| 3877 | .type_name, | ||
| 3878 | .frame_type, | ||
| 3879 | .frame_size, | ||
| 3880 | .int_from_float, | ||
| 3881 | .float_from_int, | ||
| 3882 | .ptr_from_int, | ||
| 3883 | .enum_from_int, | ||
| 3884 | .float_cast, | ||
| 3885 | .int_cast, | ||
| 3886 | .ptr_cast, | ||
| 3887 | .truncate, | ||
| 3888 | .has_decl, | ||
| 3889 | .has_field, | ||
| 3890 | .clz, | ||
| 3891 | .ctz, | ||
| 3892 | .pop_count, | ||
| 3893 | .byte_swap, | ||
| 3894 | .bit_reverse, | ||
| 3895 | .bit_offset_of, | ||
| 3896 | .offset_of, | ||
| 3897 | .splat, | ||
| 3898 | .reduce, | ||
| 3899 | .shuffle, | ||
| 3900 | .atomic_load, | ||
| 3901 | .atomic_rmw, | ||
| 3902 | .atomic_store, | ||
| 3903 | .mul_add, | ||
| 3904 | .memcpy, | ||
| 3905 | .memset, | ||
| 3906 | .min, | ||
| 3907 | .max, | ||
| 3908 | .alloc, | ||
| 3909 | .alloc_mut, | ||
| 3910 | .alloc_comptime_mut, | ||
| 3911 | .alloc_inferred, | ||
| 3912 | .alloc_inferred_mut, | ||
| 3913 | .alloc_inferred_comptime, | ||
| 3914 | .alloc_inferred_comptime_mut, | ||
| 3915 | .resolve_inferred_alloc, | ||
| 3916 | .make_ptr_const, | ||
| 3917 | .@"resume", | ||
| 3918 | .@"await", | ||
| 3919 | .save_err_ret_index, | ||
| 3920 | .restore_err_ret_index_unconditional, | ||
| 3921 | .restore_err_ret_index_fn_entry, | ||
| 3922 | => return, | ||
| 3923 | |||
| 3924 | .extended => { | ||
| 3925 | const extended = datas[@intFromEnum(inst)].extended; | ||
| 3926 | switch (extended.opcode) { | ||
| 3927 | .value_placeholder => unreachable, | ||
| 3928 | |||
| 3929 | // Once again, we start with the boring tags. | ||
| 3930 | .variable, | ||
| 3931 | .this, | ||
| 3932 | .ret_addr, | ||
| 3933 | .builtin_src, | ||
| 3934 | .error_return_trace, | ||
| 3935 | .frame, | ||
| 3936 | .frame_address, | ||
| 3937 | .alloc, | ||
| 3938 | .builtin_extern, | ||
| 3939 | .@"asm", | ||
| 3940 | .asm_expr, | ||
| 3941 | .compile_log, | ||
| 3942 | .min_multi, | ||
| 3943 | .max_multi, | ||
| 3944 | .add_with_overflow, | ||
| 3945 | .sub_with_overflow, | ||
| 3946 | .mul_with_overflow, | ||
| 3947 | .shl_with_overflow, | ||
| 3948 | .c_undef, | ||
| 3949 | .c_include, | ||
| 3950 | .c_define, | ||
| 3951 | .wasm_memory_size, | ||
| 3952 | .wasm_memory_grow, | ||
| 3953 | .prefetch, | ||
| 3954 | .fence, | ||
| 3955 | .set_float_mode, | ||
| 3956 | .set_align_stack, | ||
| 3957 | .set_cold, | ||
| 3958 | .error_cast, | ||
| 3959 | .await_nosuspend, | ||
| 3960 | .breakpoint, | ||
| 3961 | .disable_instrumentation, | ||
| 3962 | .select, | ||
| 3963 | .int_from_error, | ||
| 3964 | .error_from_int, | ||
| 3965 | .builtin_async_call, | ||
| 3966 | .cmpxchg, | ||
| 3967 | .c_va_arg, | ||
| 3968 | .c_va_copy, | ||
| 3969 | .c_va_end, | ||
| 3970 | .c_va_start, | ||
| 3971 | .ptr_cast_full, | ||
| 3972 | .ptr_cast_no_dest, | ||
| 3973 | .work_item_id, | ||
| 3974 | .work_group_size, | ||
| 3975 | .work_group_id, | ||
| 3976 | .in_comptime, | ||
| 3977 | .restore_err_ret_index, | ||
| 3978 | .closure_get, | ||
| 3979 | .field_parent_ptr, | ||
| 3980 | => return, | ||
| 3981 | |||
| 3982 | // `@TypeOf` has a body. | ||
| 3983 | .typeof_peer => { | ||
| 3984 | const extra = zir.extraData(Zir.Inst.TypeOfPeer, extended.operand); | ||
| 3985 | const body = zir.bodySlice(extra.data.body_index, extra.data.body_len); | ||
| 3986 | try zir.findDeclsBody(gpa, list, defers, body); | ||
| 3987 | }, | ||
| 3988 | |||
| 3989 | // Reifications and opaque declarations need tracking, but have no body. | ||
| 3990 | .reify, .opaque_decl => return list.append(gpa, inst), | ||
| 3991 | |||
| 3992 | // Struct declarations need tracking and have bodies. | ||
| 3993 | .struct_decl => { | ||
| 3994 | try list.append(gpa, inst); | ||
| 3995 | |||
| 3996 | const small: Zir.Inst.StructDecl.Small = @bitCast(extended.small); | ||
| 3997 | const extra = zir.extraData(Zir.Inst.StructDecl, extended.operand); | ||
| 3998 | var extra_index = extra.end; | ||
| 3999 | const captures_len = if (small.has_captures_len) blk: { | ||
| 4000 | const captures_len = zir.extra[extra_index]; | ||
| 4001 | extra_index += 1; | ||
| 4002 | break :blk captures_len; | ||
| 4003 | } else 0; | ||
| 4004 | const fields_len = if (small.has_fields_len) blk: { | ||
| 4005 | const fields_len = zir.extra[extra_index]; | ||
| 4006 | extra_index += 1; | ||
| 4007 | break :blk fields_len; | ||
| 4008 | } else 0; | ||
| 4009 | const decls_len = if (small.has_decls_len) blk: { | ||
| 4010 | const decls_len = zir.extra[extra_index]; | ||
| 4011 | extra_index += 1; | ||
| 4012 | break :blk decls_len; | ||
| 4013 | } else 0; | ||
| 4014 | extra_index += captures_len; | ||
| 4015 | if (small.has_backing_int) { | ||
| 4016 | const backing_int_body_len = zir.extra[extra_index]; | ||
| 4017 | extra_index += 1; | ||
| 4018 | if (backing_int_body_len == 0) { | ||
| 4019 | extra_index += 1; // backing_int_ref | ||
| 4020 | } else { | ||
| 4021 | const body = zir.bodySlice(extra_index, backing_int_body_len); | ||
| 4022 | extra_index += backing_int_body_len; | ||
| 4023 | try zir.findDeclsBody(gpa, list, defers, body); | ||
| 4024 | } | ||
| 4025 | } | ||
| 4026 | extra_index += decls_len; | ||
| 4027 | |||
| 4028 | // This ZIR is structured in a slightly awkward way, so we have to split up the iteration. | ||
| 4029 | // `extra_index` iterates `flags` (bags of bits). | ||
| 4030 | // `fields_extra_index` iterates `fields`. | ||
| 4031 | // We accumulate the total length of bodies into `total_bodies_len`. This is sufficient because | ||
| 4032 | // the bodies are packed together in `extra` and we only need to traverse their instructions (we | ||
| 4033 | // don't really care about the structure). | ||
| 4034 | |||
| 4035 | const bits_per_field = 4; | ||
| 4036 | const fields_per_u32 = 32 / bits_per_field; | ||
| 4037 | const bit_bags_count = std.math.divCeil(usize, fields_len, fields_per_u32) catch unreachable; | ||
| 4038 | var cur_bit_bag: u32 = undefined; | ||
| 4039 | |||
| 4040 | var fields_extra_index = extra_index + bit_bags_count; | ||
| 4041 | var total_bodies_len: u32 = 0; | ||
| 4042 | |||
| 4043 | for (0..fields_len) |field_i| { | ||
| 4044 | if (field_i % fields_per_u32 == 0) { | ||
| 4045 | cur_bit_bag = zir.extra[extra_index]; | ||
| 4046 | extra_index += 1; | ||
| 4047 | } | ||
| 4048 | |||
| 4049 | const has_align = @as(u1, @truncate(cur_bit_bag)) != 0; | ||
| 4050 | cur_bit_bag >>= 1; | ||
| 4051 | const has_init = @as(u1, @truncate(cur_bit_bag)) != 0; | ||
| 4052 | cur_bit_bag >>= 2; // also skip `is_comptime`; we don't care | ||
| 4053 | const has_type_body = @as(u1, @truncate(cur_bit_bag)) != 0; | ||
| 4054 | cur_bit_bag >>= 1; | ||
| 4055 | |||
| 4056 | fields_extra_index += @intFromBool(!small.is_tuple); // field_name | ||
| 4057 | fields_extra_index += 1; // doc_comment | ||
| 4058 | |||
| 4059 | if (has_type_body) { | ||
| 4060 | const field_type_body_len = zir.extra[fields_extra_index]; | ||
| 4061 | total_bodies_len += field_type_body_len; | ||
| 4062 | } | ||
| 4063 | fields_extra_index += 1; // field_type or field_type_body_len | ||
| 4064 | |||
| 4065 | if (has_align) { | ||
| 4066 | const align_body_len = zir.extra[fields_extra_index]; | ||
| 4067 | fields_extra_index += 1; | ||
| 4068 | total_bodies_len += align_body_len; | ||
| 4069 | } | ||
| 4070 | |||
| 4071 | if (has_init) { | ||
| 4072 | const init_body_len = zir.extra[fields_extra_index]; | ||
| 4073 | fields_extra_index += 1; | ||
| 4074 | total_bodies_len += init_body_len; | ||
| 4075 | } | ||
| 4076 | } | ||
| 4077 | |||
| 4078 | // Now, `fields_extra_index` points to `bodies`. Let's treat this as one big body. | ||
| 4079 | const merged_bodies = zir.bodySlice(fields_extra_index, total_bodies_len); | ||
| 4080 | try zir.findDeclsBody(gpa, list, defers, merged_bodies); | ||
| 4081 | }, | ||
| 4082 | |||
| 4083 | // Union declarations need tracking and have a body. | ||
| 4084 | .union_decl => { | ||
| 4085 | try list.append(gpa, inst); | ||
| 4086 | |||
| 4087 | const small: Zir.Inst.UnionDecl.Small = @bitCast(extended.small); | ||
| 4088 | const extra = zir.extraData(Zir.Inst.UnionDecl, extended.operand); | ||
| 4089 | var extra_index = extra.end; | ||
| 4090 | extra_index += @intFromBool(small.has_tag_type); | ||
| 4091 | const captures_len = if (small.has_captures_len) blk: { | ||
| 4092 | const captures_len = zir.extra[extra_index]; | ||
| 4093 | extra_index += 1; | ||
| 4094 | break :blk captures_len; | ||
| 4095 | } else 0; | ||
| 4096 | const body_len = if (small.has_body_len) blk: { | ||
| 4097 | const body_len = zir.extra[extra_index]; | ||
| 4098 | extra_index += 1; | ||
| 4099 | break :blk body_len; | ||
| 4100 | } else 0; | ||
| 4101 | extra_index += @intFromBool(small.has_fields_len); | ||
| 4102 | const decls_len = if (small.has_decls_len) blk: { | ||
| 4103 | const decls_len = zir.extra[extra_index]; | ||
| 4104 | extra_index += 1; | ||
| 4105 | break :blk decls_len; | ||
| 4106 | } else 0; | ||
| 4107 | extra_index += captures_len; | ||
| 4108 | extra_index += decls_len; | ||
| 4109 | const body = zir.bodySlice(extra_index, body_len); | ||
| 4110 | try zir.findDeclsBody(gpa, list, defers, body); | ||
| 4111 | }, | ||
| 4112 | |||
| 4113 | // Enum declarations need tracking and have a body. | ||
| 4114 | .enum_decl => { | ||
| 4115 | try list.append(gpa, inst); | ||
| 4116 | |||
| 4117 | const small: Zir.Inst.EnumDecl.Small = @bitCast(extended.small); | ||
| 4118 | const extra = zir.extraData(Zir.Inst.EnumDecl, extended.operand); | ||
| 4119 | var extra_index = extra.end; | ||
| 4120 | extra_index += @intFromBool(small.has_tag_type); | ||
| 4121 | const captures_len = if (small.has_captures_len) blk: { | ||
| 4122 | const captures_len = zir.extra[extra_index]; | ||
| 4123 | extra_index += 1; | ||
| 4124 | break :blk captures_len; | ||
| 4125 | } else 0; | ||
| 4126 | const body_len = if (small.has_body_len) blk: { | ||
| 4127 | const body_len = zir.extra[extra_index]; | ||
| 4128 | extra_index += 1; | ||
| 4129 | break :blk body_len; | ||
| 4130 | } else 0; | ||
| 4131 | extra_index += @intFromBool(small.has_fields_len); | ||
| 4132 | const decls_len = if (small.has_decls_len) blk: { | ||
| 4133 | const decls_len = zir.extra[extra_index]; | ||
| 4134 | extra_index += 1; | ||
| 4135 | break :blk decls_len; | ||
| 4136 | } else 0; | ||
| 4137 | extra_index += captures_len; | ||
| 4138 | extra_index += decls_len; | ||
| 4139 | const body = zir.bodySlice(extra_index, body_len); | ||
| 4140 | try zir.findDeclsBody(gpa, list, defers, body); | ||
| 4141 | }, | ||
| 4142 | } | ||
| 4143 | }, | ||
| 4144 | |||
| 3649 | // Functions instructions are interesting and have a body. | 4145 | // Functions instructions are interesting and have a body. |
| 3650 | .func, | 4146 | .func, |
| 3651 | .func_inferred, | 4147 | .func_inferred, |
| 3652 | => { | 4148 | => { |
| 3653 | try list.append(inst); | 4149 | try list.append(gpa, inst); |
| 3654 | 4150 | ||
| 3655 | const inst_data = datas[@intFromEnum(inst)].pl_node; | 4151 | const inst_data = datas[@intFromEnum(inst)].pl_node; |
| 3656 | const extra = zir.extraData(Inst.Func, inst_data.payload_index); | 4152 | const extra = zir.extraData(Inst.Func, inst_data.payload_index); |
| ... | @@ -3661,14 +4157,14 @@ fn findDeclsInner( | ... | @@ -3661,14 +4157,14 @@ fn findDeclsInner( |
| 3661 | else => { | 4157 | else => { |
| 3662 | const body = zir.bodySlice(extra_index, extra.data.ret_body_len); | 4158 | const body = zir.bodySlice(extra_index, extra.data.ret_body_len); |
| 3663 | extra_index += body.len; | 4159 | extra_index += body.len; |
| 3664 | try zir.findDeclsBody(list, body); | 4160 | try zir.findDeclsBody(gpa, list, defers, body); |
| 3665 | }, | 4161 | }, |
| 3666 | } | 4162 | } |
| 3667 | const body = zir.bodySlice(extra_index, extra.data.body_len); | 4163 | const body = zir.bodySlice(extra_index, extra.data.body_len); |
| 3668 | return zir.findDeclsBody(list, body); | 4164 | return zir.findDeclsBody(gpa, list, defers, body); |
| 3669 | }, | 4165 | }, |
| 3670 | .func_fancy => { | 4166 | .func_fancy => { |
| 3671 | try list.append(inst); | 4167 | try list.append(gpa, inst); |
| 3672 | 4168 | ||
| 3673 | const inst_data = datas[@intFromEnum(inst)].pl_node; | 4169 | const inst_data = datas[@intFromEnum(inst)].pl_node; |
| 3674 | const extra = zir.extraData(Inst.FuncFancy, inst_data.payload_index); | 4170 | const extra = zir.extraData(Inst.FuncFancy, inst_data.payload_index); |
| ... | @@ -3679,7 +4175,7 @@ fn findDeclsInner( | ... | @@ -3679,7 +4175,7 @@ fn findDeclsInner( |
| 3679 | const body_len = zir.extra[extra_index]; | 4175 | const body_len = zir.extra[extra_index]; |
| 3680 | extra_index += 1; | 4176 | extra_index += 1; |
| 3681 | const body = zir.bodySlice(extra_index, body_len); | 4177 | const body = zir.bodySlice(extra_index, body_len); |
| 3682 | try zir.findDeclsBody(list, body); | 4178 | try zir.findDeclsBody(gpa, list, defers, body); |
| 3683 | extra_index += body.len; | 4179 | extra_index += body.len; |
| 3684 | } else if (extra.data.bits.has_align_ref) { | 4180 | } else if (extra.data.bits.has_align_ref) { |
| 3685 | extra_index += 1; | 4181 | extra_index += 1; |
| ... | @@ -3689,7 +4185,7 @@ fn findDeclsInner( | ... | @@ -3689,7 +4185,7 @@ fn findDeclsInner( |
| 3689 | const body_len = zir.extra[extra_index]; | 4185 | const body_len = zir.extra[extra_index]; |
| 3690 | extra_index += 1; | 4186 | extra_index += 1; |
| 3691 | const body = zir.bodySlice(extra_index, body_len); | 4187 | const body = zir.bodySlice(extra_index, body_len); |
| 3692 | try zir.findDeclsBody(list, body); | 4188 | try zir.findDeclsBody(gpa, list, defers, body); |
| 3693 | extra_index += body.len; | 4189 | extra_index += body.len; |
| 3694 | } else if (extra.data.bits.has_addrspace_ref) { | 4190 | } else if (extra.data.bits.has_addrspace_ref) { |
| 3695 | extra_index += 1; | 4191 | extra_index += 1; |
| ... | @@ -3699,7 +4195,7 @@ fn findDeclsInner( | ... | @@ -3699,7 +4195,7 @@ fn findDeclsInner( |
| 3699 | const body_len = zir.extra[extra_index]; | 4195 | const body_len = zir.extra[extra_index]; |
| 3700 | extra_index += 1; | 4196 | extra_index += 1; |
| 3701 | const body = zir.bodySlice(extra_index, body_len); | 4197 | const body = zir.bodySlice(extra_index, body_len); |
| 3702 | try zir.findDeclsBody(list, body); | 4198 | try zir.findDeclsBody(gpa, list, defers, body); |
| 3703 | extra_index += body.len; | 4199 | extra_index += body.len; |
| 3704 | } else if (extra.data.bits.has_section_ref) { | 4200 | } else if (extra.data.bits.has_section_ref) { |
| 3705 | extra_index += 1; | 4201 | extra_index += 1; |
| ... | @@ -3709,7 +4205,7 @@ fn findDeclsInner( | ... | @@ -3709,7 +4205,7 @@ fn findDeclsInner( |
| 3709 | const body_len = zir.extra[extra_index]; | 4205 | const body_len = zir.extra[extra_index]; |
| 3710 | extra_index += 1; | 4206 | extra_index += 1; |
| 3711 | const body = zir.bodySlice(extra_index, body_len); | 4207 | const body = zir.bodySlice(extra_index, body_len); |
| 3712 | try zir.findDeclsBody(list, body); | 4208 | try zir.findDeclsBody(gpa, list, defers, body); |
| 3713 | extra_index += body.len; | 4209 | extra_index += body.len; |
| 3714 | } else if (extra.data.bits.has_cc_ref) { | 4210 | } else if (extra.data.bits.has_cc_ref) { |
| 3715 | extra_index += 1; | 4211 | extra_index += 1; |
| ... | @@ -3719,7 +4215,7 @@ fn findDeclsInner( | ... | @@ -3719,7 +4215,7 @@ fn findDeclsInner( |
| 3719 | const body_len = zir.extra[extra_index]; | 4215 | const body_len = zir.extra[extra_index]; |
| 3720 | extra_index += 1; | 4216 | extra_index += 1; |
| 3721 | const body = zir.bodySlice(extra_index, body_len); | 4217 | const body = zir.bodySlice(extra_index, body_len); |
| 3722 | try zir.findDeclsBody(list, body); | 4218 | try zir.findDeclsBody(gpa, list, defers, body); |
| 3723 | extra_index += body.len; | 4219 | extra_index += body.len; |
| 3724 | } else if (extra.data.bits.has_ret_ty_ref) { | 4220 | } else if (extra.data.bits.has_ret_ty_ref) { |
| 3725 | extra_index += 1; | 4221 | extra_index += 1; |
| ... | @@ -3728,62 +4224,99 @@ fn findDeclsInner( | ... | @@ -3728,62 +4224,99 @@ fn findDeclsInner( |
| 3728 | extra_index += @intFromBool(extra.data.bits.has_any_noalias); | 4224 | extra_index += @intFromBool(extra.data.bits.has_any_noalias); |
| 3729 | 4225 | ||
| 3730 | const body = zir.bodySlice(extra_index, extra.data.body_len); | 4226 | const body = zir.bodySlice(extra_index, extra.data.body_len); |
| 3731 | return zir.findDeclsBody(list, body); | 4227 | return zir.findDeclsBody(gpa, list, defers, body); |
| 3732 | }, | ||
| 3733 | .extended => { | ||
| 3734 | const extended = datas[@intFromEnum(inst)].extended; | ||
| 3735 | switch (extended.opcode) { | ||
| 3736 | |||
| 3737 | // Decl instructions are interesting but have no body. | ||
| 3738 | // TODO yes they do have a body actually. recurse over them just like block instructions. | ||
| 3739 | .struct_decl, | ||
| 3740 | .union_decl, | ||
| 3741 | .enum_decl, | ||
| 3742 | .opaque_decl, | ||
| 3743 | .reify, | ||
| 3744 | => return list.append(inst), | ||
| 3745 | |||
| 3746 | else => return, | ||
| 3747 | } | ||
| 3748 | }, | 4228 | }, |
| 3749 | 4229 | ||
| 3750 | // Block instructions, recurse over the bodies. | 4230 | // Block instructions, recurse over the bodies. |
| 3751 | 4231 | ||
| 3752 | .block, .block_comptime, .block_inline => { | 4232 | .block, |
| 4233 | .block_comptime, | ||
| 4234 | .block_inline, | ||
| 4235 | .c_import, | ||
| 4236 | .typeof_builtin, | ||
| 4237 | .loop, | ||
| 4238 | => { | ||
| 3753 | const inst_data = datas[@intFromEnum(inst)].pl_node; | 4239 | const inst_data = datas[@intFromEnum(inst)].pl_node; |
| 3754 | const extra = zir.extraData(Inst.Block, inst_data.payload_index); | 4240 | const extra = zir.extraData(Inst.Block, inst_data.payload_index); |
| 3755 | const body = zir.bodySlice(extra.end, extra.data.body_len); | 4241 | const body = zir.bodySlice(extra.end, extra.data.body_len); |
| 3756 | return zir.findDeclsBody(list, body); | 4242 | return zir.findDeclsBody(gpa, list, defers, body); |
| 3757 | }, | 4243 | }, |
| 3758 | .condbr, .condbr_inline => { | 4244 | .condbr, .condbr_inline => { |
| 3759 | const inst_data = datas[@intFromEnum(inst)].pl_node; | 4245 | const inst_data = datas[@intFromEnum(inst)].pl_node; |
| 3760 | const extra = zir.extraData(Inst.CondBr, inst_data.payload_index); | 4246 | const extra = zir.extraData(Inst.CondBr, inst_data.payload_index); |
| 3761 | const then_body = zir.bodySlice(extra.end, extra.data.then_body_len); | 4247 | const then_body = zir.bodySlice(extra.end, extra.data.then_body_len); |
| 3762 | const else_body = zir.bodySlice(extra.end + then_body.len, extra.data.else_body_len); | 4248 | const else_body = zir.bodySlice(extra.end + then_body.len, extra.data.else_body_len); |
| 3763 | try zir.findDeclsBody(list, then_body); | 4249 | try zir.findDeclsBody(gpa, list, defers, then_body); |
| 3764 | try zir.findDeclsBody(list, else_body); | 4250 | try zir.findDeclsBody(gpa, list, defers, else_body); |
| 3765 | }, | 4251 | }, |
| 3766 | .@"try", .try_ptr => { | 4252 | .@"try", .try_ptr => { |
| 3767 | const inst_data = datas[@intFromEnum(inst)].pl_node; | 4253 | const inst_data = datas[@intFromEnum(inst)].pl_node; |
| 3768 | const extra = zir.extraData(Inst.Try, inst_data.payload_index); | 4254 | const extra = zir.extraData(Inst.Try, inst_data.payload_index); |
| 3769 | const body = zir.bodySlice(extra.end, extra.data.body_len); | 4255 | const body = zir.bodySlice(extra.end, extra.data.body_len); |
| 3770 | try zir.findDeclsBody(list, body); | 4256 | try zir.findDeclsBody(gpa, list, defers, body); |
| 3771 | }, | 4257 | }, |
| 3772 | .switch_block => return findDeclsSwitch(zir, list, inst), | 4258 | .switch_block, .switch_block_ref => return zir.findDeclsSwitch(gpa, list, defers, inst, .normal), |
| 4259 | .switch_block_err_union => return zir.findDeclsSwitch(gpa, list, defers, inst, .err_union), | ||
| 3773 | 4260 | ||
| 3774 | .suspend_block => @panic("TODO iterate suspend block"), | 4261 | .suspend_block => @panic("TODO iterate suspend block"), |
| 3775 | 4262 | ||
| 3776 | else => return, // Regular instruction, not interesting. | 4263 | .param, .param_comptime => { |
| 4264 | const inst_data = datas[@intFromEnum(inst)].pl_tok; | ||
| 4265 | const extra = zir.extraData(Inst.Param, inst_data.payload_index); | ||
| 4266 | const body = zir.bodySlice(extra.end, extra.data.body_len); | ||
| 4267 | try zir.findDeclsBody(gpa, list, defers, body); | ||
| 4268 | }, | ||
| 4269 | |||
| 4270 | inline .call, .field_call => |tag| { | ||
| 4271 | const inst_data = datas[@intFromEnum(inst)].pl_node; | ||
| 4272 | const extra = zir.extraData(switch (tag) { | ||
| 4273 | .call => Inst.Call, | ||
| 4274 | .field_call => Inst.FieldCall, | ||
| 4275 | else => unreachable, | ||
| 4276 | }, inst_data.payload_index); | ||
| 4277 | // It's easiest to just combine all the arg bodies into one body, like we do above for `struct_decl`. | ||
| 4278 | const args_len = extra.data.flags.args_len; | ||
| 4279 | if (args_len > 0) { | ||
| 4280 | const first_arg_start_off = args_len; | ||
| 4281 | const final_arg_end_off = zir.extra[extra.end + args_len - 1]; | ||
| 4282 | const args_body = zir.bodySlice(extra.end + first_arg_start_off, final_arg_end_off - first_arg_start_off); | ||
| 4283 | try zir.findDeclsBody(gpa, list, defers, args_body); | ||
| 4284 | } | ||
| 4285 | }, | ||
| 4286 | .@"defer" => { | ||
| 4287 | const inst_data = datas[@intFromEnum(inst)].@"defer"; | ||
| 4288 | const gop = try defers.getOrPut(gpa, inst_data.index); | ||
| 4289 | if (!gop.found_existing) { | ||
| 4290 | const body = zir.bodySlice(inst_data.index, inst_data.len); | ||
| 4291 | try zir.findDeclsBody(gpa, list, defers, body); | ||
| 4292 | } | ||
| 4293 | }, | ||
| 4294 | .defer_err_code => { | ||
| 4295 | const inst_data = datas[@intFromEnum(inst)].defer_err_code; | ||
| 4296 | const extra = zir.extraData(Inst.DeferErrCode, inst_data.payload_index).data; | ||
| 4297 | const gop = try defers.getOrPut(gpa, extra.index); | ||
| 4298 | if (!gop.found_existing) { | ||
| 4299 | const body = zir.bodySlice(extra.index, extra.len); | ||
| 4300 | try zir.findDeclsBody(gpa, list, defers, body); | ||
| 4301 | } | ||
| 4302 | }, | ||
| 3777 | } | 4303 | } |
| 3778 | } | 4304 | } |
| 3779 | 4305 | ||
| 3780 | fn findDeclsSwitch( | 4306 | fn findDeclsSwitch( |
| 3781 | zir: Zir, | 4307 | zir: Zir, |
| 3782 | list: *std.ArrayList(Inst.Index), | 4308 | gpa: Allocator, |
| 4309 | list: *std.ArrayListUnmanaged(Inst.Index), | ||
| 4310 | defers: *std.AutoHashMapUnmanaged(u32, void), | ||
| 3783 | inst: Inst.Index, | 4311 | inst: Inst.Index, |
| 4312 | /// Distinguishes between `switch_block[_ref]` and `switch_block_err_union`. | ||
| 4313 | comptime kind: enum { normal, err_union }, | ||
| 3784 | ) Allocator.Error!void { | 4314 | ) Allocator.Error!void { |
| 3785 | const inst_data = zir.instructions.items(.data)[@intFromEnum(inst)].pl_node; | 4315 | const inst_data = zir.instructions.items(.data)[@intFromEnum(inst)].pl_node; |
| 3786 | const extra = zir.extraData(Inst.SwitchBlock, inst_data.payload_index); | 4316 | const extra = zir.extraData(switch (kind) { |
| 4317 | .normal => Inst.SwitchBlock, | ||
| 4318 | .err_union => Inst.SwitchBlockErrUnion, | ||
| 4319 | }, inst_data.payload_index); | ||
| 3787 | 4320 | ||
| 3788 | var extra_index: usize = extra.end; | 4321 | var extra_index: usize = extra.end; |
| 3789 | 4322 | ||
| ... | @@ -3793,18 +4326,35 @@ fn findDeclsSwitch( | ... | @@ -3793,18 +4326,35 @@ fn findDeclsSwitch( |
| 3793 | break :blk multi_cases_len; | 4326 | break :blk multi_cases_len; |
| 3794 | } else 0; | 4327 | } else 0; |
| 3795 | 4328 | ||
| 3796 | if (extra.data.bits.any_has_tag_capture) { | 4329 | if (switch (kind) { |
| 4330 | .normal => extra.data.bits.any_has_tag_capture, | ||
| 4331 | .err_union => extra.data.bits.any_uses_err_capture, | ||
| 4332 | }) { | ||
| 3797 | extra_index += 1; | 4333 | extra_index += 1; |
| 3798 | } | 4334 | } |
| 3799 | 4335 | ||
| 3800 | const special_prong = extra.data.bits.specialProng(); | 4336 | const has_special = switch (kind) { |
| 3801 | if (special_prong != .none) { | 4337 | .normal => extra.data.bits.specialProng() != .none, |
| 4338 | .err_union => has_special: { | ||
| 4339 | // Handle `non_err_body` first. | ||
| 4340 | const prong_info: Inst.SwitchBlock.ProngInfo = @bitCast(zir.extra[extra_index]); | ||
| 4341 | extra_index += 1; | ||
| 4342 | const body = zir.bodySlice(extra_index, prong_info.body_len); | ||
| 4343 | extra_index += body.len; | ||
| 4344 | |||
| 4345 | try zir.findDeclsBody(gpa, list, defers, body); | ||
| 4346 | |||
| 4347 | break :has_special extra.data.bits.has_else; | ||
| 4348 | }, | ||
| 4349 | }; | ||
| 4350 | |||
| 4351 | if (has_special) { | ||
| 3802 | const prong_info: Inst.SwitchBlock.ProngInfo = @bitCast(zir.extra[extra_index]); | 4352 | const prong_info: Inst.SwitchBlock.ProngInfo = @bitCast(zir.extra[extra_index]); |
| 3803 | extra_index += 1; | 4353 | extra_index += 1; |
| 3804 | const body = zir.bodySlice(extra_index, prong_info.body_len); | 4354 | const body = zir.bodySlice(extra_index, prong_info.body_len); |
| 3805 | extra_index += body.len; | 4355 | extra_index += body.len; |
| 3806 | 4356 | ||
| 3807 | try zir.findDeclsBody(list, body); | 4357 | try zir.findDeclsBody(gpa, list, defers, body); |
| 3808 | } | 4358 | } |
| 3809 | 4359 | ||
| 3810 | { | 4360 | { |
| ... | @@ -3816,7 +4366,7 @@ fn findDeclsSwitch( | ... | @@ -3816,7 +4366,7 @@ fn findDeclsSwitch( |
| 3816 | const body = zir.bodySlice(extra_index, prong_info.body_len); | 4366 | const body = zir.bodySlice(extra_index, prong_info.body_len); |
| 3817 | extra_index += body.len; | 4367 | extra_index += body.len; |
| 3818 | 4368 | ||
| 3819 | try zir.findDeclsBody(list, body); | 4369 | try zir.findDeclsBody(gpa, list, defers, body); |
| 3820 | } | 4370 | } |
| 3821 | } | 4371 | } |
| 3822 | { | 4372 | { |
| ... | @@ -3833,18 +4383,20 @@ fn findDeclsSwitch( | ... | @@ -3833,18 +4383,20 @@ fn findDeclsSwitch( |
| 3833 | const body = zir.bodySlice(extra_index, prong_info.body_len); | 4383 | const body = zir.bodySlice(extra_index, prong_info.body_len); |
| 3834 | extra_index += body.len; | 4384 | extra_index += body.len; |
| 3835 | 4385 | ||
| 3836 | try zir.findDeclsBody(list, body); | 4386 | try zir.findDeclsBody(gpa, list, defers, body); |
| 3837 | } | 4387 | } |
| 3838 | } | 4388 | } |
| 3839 | } | 4389 | } |
| 3840 | 4390 | ||
| 3841 | fn findDeclsBody( | 4391 | fn findDeclsBody( |
| 3842 | zir: Zir, | 4392 | zir: Zir, |
| 3843 | list: *std.ArrayList(Inst.Index), | 4393 | gpa: Allocator, |
| 4394 | list: *std.ArrayListUnmanaged(Inst.Index), | ||
| 4395 | defers: *std.AutoHashMapUnmanaged(u32, void), | ||
| 3844 | body: []const Inst.Index, | 4396 | body: []const Inst.Index, |
| 3845 | ) Allocator.Error!void { | 4397 | ) Allocator.Error!void { |
| 3846 | for (body) |member| { | 4398 | for (body) |member| { |
| 3847 | try zir.findDeclsInner(list, member); | 4399 | try zir.findDeclsInner(gpa, list, defers, member); |
| 3848 | } | 4400 | } |
| 3849 | } | 4401 | } |
| 3850 | 4402 | ||
| ... | @@ -4042,7 +4594,7 @@ pub fn getAssociatedSrcHash(zir: Zir, inst: Zir.Inst.Index) ?std.zig.SrcHash { | ... | @@ -4042,7 +4594,7 @@ pub fn getAssociatedSrcHash(zir: Zir, inst: Zir.Inst.Index) ?std.zig.SrcHash { |
| 4042 | return null; | 4594 | return null; |
| 4043 | } | 4595 | } |
| 4044 | const extra_index = extra.end + | 4596 | const extra_index = extra.end + |
| 4045 | 1 + | 4597 | extra.data.ret_body_len + |
| 4046 | extra.data.body_len + | 4598 | extra.data.body_len + |
| 4047 | @typeInfo(Inst.Func.SrcLocs).Struct.fields.len; | 4599 | @typeInfo(Inst.Func.SrcLocs).Struct.fields.len; |
| 4048 | return @bitCast([4]u32{ | 4600 | return @bitCast([4]u32{ |
src/Compilation.zig+74-104| ... | @@ -2264,13 +2264,19 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) !void { | ... | @@ -2264,13 +2264,19 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) !void { |
| 2264 | } | 2264 | } |
| 2265 | } | 2265 | } |
| 2266 | 2266 | ||
| 2267 | zcu.analysis_roots.clear(); | ||
| 2268 | |||
| 2267 | try comp.queueJob(.{ .analyze_mod = std_mod }); | 2269 | try comp.queueJob(.{ .analyze_mod = std_mod }); |
| 2268 | if (comp.config.is_test) { | 2270 | zcu.analysis_roots.appendAssumeCapacity(std_mod); |
| 2271 | |||
| 2272 | if (comp.config.is_test and zcu.main_mod != std_mod) { | ||
| 2269 | try comp.queueJob(.{ .analyze_mod = zcu.main_mod }); | 2273 | try comp.queueJob(.{ .analyze_mod = zcu.main_mod }); |
| 2274 | zcu.analysis_roots.appendAssumeCapacity(zcu.main_mod); | ||
| 2270 | } | 2275 | } |
| 2271 | 2276 | ||
| 2272 | if (zcu.root_mod.deps.get("compiler_rt")) |compiler_rt_mod| { | 2277 | if (zcu.root_mod.deps.get("compiler_rt")) |compiler_rt_mod| { |
| 2273 | try comp.queueJob(.{ .analyze_mod = compiler_rt_mod }); | 2278 | try comp.queueJob(.{ .analyze_mod = compiler_rt_mod }); |
| 2279 | zcu.analysis_roots.appendAssumeCapacity(compiler_rt_mod); | ||
| 2274 | } | 2280 | } |
| 2275 | } | 2281 | } |
| 2276 | 2282 | ||
| ... | @@ -2294,7 +2300,7 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) !void { | ... | @@ -2294,7 +2300,7 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) !void { |
| 2294 | zcu.intern_pool.dumpGenericInstances(gpa); | 2300 | zcu.intern_pool.dumpGenericInstances(gpa); |
| 2295 | } | 2301 | } |
| 2296 | 2302 | ||
| 2297 | if (comp.config.is_test and comp.totalErrorCount() == 0) { | 2303 | if (comp.config.is_test) { |
| 2298 | // The `test_functions` decl has been intentionally postponed until now, | 2304 | // The `test_functions` decl has been intentionally postponed until now, |
| 2299 | // at which point we must populate it with the list of test functions that | 2305 | // at which point we must populate it with the list of test functions that |
| 2300 | // have been discovered and not filtered out. | 2306 | // have been discovered and not filtered out. |
| ... | @@ -2304,7 +2310,7 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) !void { | ... | @@ -2304,7 +2310,7 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) !void { |
| 2304 | try pt.processExports(); | 2310 | try pt.processExports(); |
| 2305 | } | 2311 | } |
| 2306 | 2312 | ||
| 2307 | if (comp.totalErrorCount() != 0) { | 2313 | if (try comp.totalErrorCount() != 0) { |
| 2308 | // Skip flushing and keep source files loaded for error reporting. | 2314 | // Skip flushing and keep source files loaded for error reporting. |
| 2309 | comp.link_error_flags = .{}; | 2315 | comp.link_error_flags = .{}; |
| 2310 | return; | 2316 | return; |
| ... | @@ -2388,7 +2394,8 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) !void { | ... | @@ -2388,7 +2394,8 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) !void { |
| 2388 | } | 2394 | } |
| 2389 | 2395 | ||
| 2390 | try flush(comp, arena, .main, main_progress_node); | 2396 | try flush(comp, arena, .main, main_progress_node); |
| 2391 | if (comp.totalErrorCount() != 0) return; | 2397 | |
| 2398 | if (try comp.totalErrorCount() != 0) return; | ||
| 2392 | 2399 | ||
| 2393 | // Failure here only means an unnecessary cache miss. | 2400 | // Failure here only means an unnecessary cache miss. |
| 2394 | man.writeManifest() catch |err| { | 2401 | man.writeManifest() catch |err| { |
| ... | @@ -2405,7 +2412,6 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) !void { | ... | @@ -2405,7 +2412,6 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) !void { |
| 2405 | }, | 2412 | }, |
| 2406 | .incremental => { | 2413 | .incremental => { |
| 2407 | try flush(comp, arena, .main, main_progress_node); | 2414 | try flush(comp, arena, .main, main_progress_node); |
| 2408 | if (comp.totalErrorCount() != 0) return; | ||
| 2409 | }, | 2415 | }, |
| 2410 | } | 2416 | } |
| 2411 | } | 2417 | } |
| ... | @@ -3041,82 +3047,6 @@ fn addBuf(list: *std.ArrayList(std.posix.iovec_const), buf: []const u8) void { | ... | @@ -3041,82 +3047,6 @@ fn addBuf(list: *std.ArrayList(std.posix.iovec_const), buf: []const u8) void { |
| 3041 | list.appendAssumeCapacity(.{ .base = buf.ptr, .len = buf.len }); | 3047 | list.appendAssumeCapacity(.{ .base = buf.ptr, .len = buf.len }); |
| 3042 | } | 3048 | } |
| 3043 | 3049 | ||
| 3044 | /// This function is temporally single-threaded. | ||
| 3045 | pub fn totalErrorCount(comp: *Compilation) u32 { | ||
| 3046 | var total: usize = | ||
| 3047 | comp.misc_failures.count() + | ||
| 3048 | @intFromBool(comp.alloc_failure_occurred) + | ||
| 3049 | comp.lld_errors.items.len; | ||
| 3050 | |||
| 3051 | for (comp.failed_c_objects.values()) |bundle| { | ||
| 3052 | total += bundle.diags.len; | ||
| 3053 | } | ||
| 3054 | |||
| 3055 | for (comp.failed_win32_resources.values()) |errs| { | ||
| 3056 | total += errs.errorMessageCount(); | ||
| 3057 | } | ||
| 3058 | |||
| 3059 | if (comp.module) |zcu| { | ||
| 3060 | const ip = &zcu.intern_pool; | ||
| 3061 | |||
| 3062 | total += zcu.failed_exports.count(); | ||
| 3063 | total += zcu.failed_embed_files.count(); | ||
| 3064 | |||
| 3065 | for (zcu.failed_files.keys(), zcu.failed_files.values()) |file, error_msg| { | ||
| 3066 | if (error_msg) |_| { | ||
| 3067 | total += 1; | ||
| 3068 | } else { | ||
| 3069 | assert(file.zir_loaded); | ||
| 3070 | const payload_index = file.zir.extra[@intFromEnum(Zir.ExtraIndex.compile_errors)]; | ||
| 3071 | assert(payload_index != 0); | ||
| 3072 | const header = file.zir.extraData(Zir.Inst.CompileErrors, payload_index); | ||
| 3073 | total += header.data.items_len; | ||
| 3074 | } | ||
| 3075 | } | ||
| 3076 | |||
| 3077 | // Skip errors for Decls within files that failed parsing. | ||
| 3078 | // When a parse error is introduced, we keep all the semantic analysis for | ||
| 3079 | // the previous parse success, including compile errors, but we cannot | ||
| 3080 | // emit them until the file succeeds parsing. | ||
| 3081 | for (zcu.failed_analysis.keys()) |anal_unit| { | ||
| 3082 | const file_index = switch (anal_unit.unwrap()) { | ||
| 3083 | .cau => |cau| zcu.namespacePtr(ip.getCau(cau).namespace).file_scope, | ||
| 3084 | .func => |ip_index| zcu.funcInfo(ip_index).zir_body_inst.resolveFull(ip).file, | ||
| 3085 | }; | ||
| 3086 | if (zcu.fileByIndex(file_index).okToReportErrors()) { | ||
| 3087 | total += 1; | ||
| 3088 | if (zcu.cimport_errors.get(anal_unit)) |errors| { | ||
| 3089 | total += errors.errorMessageCount(); | ||
| 3090 | } | ||
| 3091 | } | ||
| 3092 | } | ||
| 3093 | |||
| 3094 | if (zcu.intern_pool.global_error_set.getNamesFromMainThread().len > zcu.error_limit) { | ||
| 3095 | total += 1; | ||
| 3096 | } | ||
| 3097 | |||
| 3098 | for (zcu.failed_codegen.keys()) |_| { | ||
| 3099 | total += 1; | ||
| 3100 | } | ||
| 3101 | } | ||
| 3102 | |||
| 3103 | // The "no entry point found" error only counts if there are no semantic analysis errors. | ||
| 3104 | if (total == 0) { | ||
| 3105 | total += @intFromBool(comp.link_error_flags.no_entry_point_found); | ||
| 3106 | } | ||
| 3107 | total += @intFromBool(comp.link_error_flags.missing_libc); | ||
| 3108 | total += comp.link_errors.items.len; | ||
| 3109 | |||
| 3110 | // Compile log errors only count if there are no other errors. | ||
| 3111 | if (total == 0) { | ||
| 3112 | if (comp.module) |zcu| { | ||
| 3113 | total += @intFromBool(zcu.compile_log_sources.count() != 0); | ||
| 3114 | } | ||
| 3115 | } | ||
| 3116 | |||
| 3117 | return @as(u32, @intCast(total)); | ||
| 3118 | } | ||
| 3119 | |||
| 3120 | /// This function is temporally single-threaded. | 3050 | /// This function is temporally single-threaded. |
| 3121 | pub fn getAllErrorsAlloc(comp: *Compilation) !ErrorBundle { | 3051 | pub fn getAllErrorsAlloc(comp: *Compilation) !ErrorBundle { |
| 3122 | const gpa = comp.gpa; | 3052 | const gpa = comp.gpa; |
| ... | @@ -3159,12 +3089,13 @@ pub fn getAllErrorsAlloc(comp: *Compilation) !ErrorBundle { | ... | @@ -3159,12 +3089,13 @@ pub fn getAllErrorsAlloc(comp: *Compilation) !ErrorBundle { |
| 3159 | .msg = try bundle.addString("memory allocation failure"), | 3089 | .msg = try bundle.addString("memory allocation failure"), |
| 3160 | }); | 3090 | }); |
| 3161 | } | 3091 | } |
| 3092 | |||
| 3093 | var all_references: ?std.AutoHashMapUnmanaged(InternPool.AnalUnit, ?Zcu.ResolvedReference) = null; | ||
| 3094 | defer if (all_references) |*a| a.deinit(gpa); | ||
| 3095 | |||
| 3162 | if (comp.module) |zcu| { | 3096 | if (comp.module) |zcu| { |
| 3163 | const ip = &zcu.intern_pool; | 3097 | const ip = &zcu.intern_pool; |
| 3164 | 3098 | ||
| 3165 | var all_references = try zcu.resolveReferences(); | ||
| 3166 | defer all_references.deinit(gpa); | ||
| 3167 | |||
| 3168 | for (zcu.failed_files.keys(), zcu.failed_files.values()) |file, error_msg| { | 3099 | for (zcu.failed_files.keys(), zcu.failed_files.values()) |file, error_msg| { |
| 3169 | if (error_msg) |msg| { | 3100 | if (error_msg) |msg| { |
| 3170 | try addModuleErrorMsg(zcu, &bundle, msg.*, &all_references); | 3101 | try addModuleErrorMsg(zcu, &bundle, msg.*, &all_references); |
| ... | @@ -3190,8 +3121,14 @@ pub fn getAllErrorsAlloc(comp: *Compilation) !ErrorBundle { | ... | @@ -3190,8 +3121,14 @@ pub fn getAllErrorsAlloc(comp: *Compilation) !ErrorBundle { |
| 3190 | pub fn lessThan(ctx: @This(), lhs_index: usize, rhs_index: usize) bool { | 3121 | pub fn lessThan(ctx: @This(), lhs_index: usize, rhs_index: usize) bool { |
| 3191 | if (ctx.err.*) |_| return lhs_index < rhs_index; | 3122 | if (ctx.err.*) |_| return lhs_index < rhs_index; |
| 3192 | const errors = ctx.zcu.failed_analysis.values(); | 3123 | const errors = ctx.zcu.failed_analysis.values(); |
| 3193 | const lhs_src_loc = errors[lhs_index].src_loc.upgrade(ctx.zcu); | 3124 | const lhs_src_loc = errors[lhs_index].src_loc.upgradeOrLost(ctx.zcu) orelse { |
| 3194 | const rhs_src_loc = errors[rhs_index].src_loc.upgrade(ctx.zcu); | 3125 | // LHS source location lost, so should never be referenced. Just sort it to the end. |
| 3126 | return false; | ||
| 3127 | }; | ||
| 3128 | const rhs_src_loc = errors[rhs_index].src_loc.upgradeOrLost(ctx.zcu) orelse { | ||
| 3129 | // RHS source location lost, so should never be referenced. Just sort it to the end. | ||
| 3130 | return true; | ||
| 3131 | }; | ||
| 3195 | return if (lhs_src_loc.file_scope != rhs_src_loc.file_scope) std.mem.order( | 3132 | return if (lhs_src_loc.file_scope != rhs_src_loc.file_scope) std.mem.order( |
| 3196 | u8, | 3133 | u8, |
| 3197 | lhs_src_loc.file_scope.sub_file_path, | 3134 | lhs_src_loc.file_scope.sub_file_path, |
| ... | @@ -3212,9 +3149,16 @@ pub fn getAllErrorsAlloc(comp: *Compilation) !ErrorBundle { | ... | @@ -3212,9 +3149,16 @@ pub fn getAllErrorsAlloc(comp: *Compilation) !ErrorBundle { |
| 3212 | if (err) |e| return e; | 3149 | if (err) |e| return e; |
| 3213 | } | 3150 | } |
| 3214 | for (zcu.failed_analysis.keys(), zcu.failed_analysis.values()) |anal_unit, error_msg| { | 3151 | for (zcu.failed_analysis.keys(), zcu.failed_analysis.values()) |anal_unit, error_msg| { |
| 3152 | if (comp.incremental) { | ||
| 3153 | if (all_references == null) { | ||
| 3154 | all_references = try zcu.resolveReferences(); | ||
| 3155 | } | ||
| 3156 | if (!all_references.?.contains(anal_unit)) continue; | ||
| 3157 | } | ||
| 3158 | |||
| 3215 | const file_index = switch (anal_unit.unwrap()) { | 3159 | const file_index = switch (anal_unit.unwrap()) { |
| 3216 | .cau => |cau| zcu.namespacePtr(ip.getCau(cau).namespace).file_scope, | 3160 | .cau => |cau| zcu.namespacePtr(ip.getCau(cau).namespace).file_scope, |
| 3217 | .func => |ip_index| zcu.funcInfo(ip_index).zir_body_inst.resolveFull(ip).file, | 3161 | .func => |ip_index| (zcu.funcInfo(ip_index).zir_body_inst.resolveFull(ip) orelse continue).file, |
| 3218 | }; | 3162 | }; |
| 3219 | 3163 | ||
| 3220 | // Skip errors for AnalUnits within files that had a parse failure. | 3164 | // Skip errors for AnalUnits within files that had a parse failure. |
| ... | @@ -3243,7 +3187,8 @@ pub fn getAllErrorsAlloc(comp: *Compilation) !ErrorBundle { | ... | @@ -3243,7 +3187,8 @@ pub fn getAllErrorsAlloc(comp: *Compilation) !ErrorBundle { |
| 3243 | } | 3187 | } |
| 3244 | } | 3188 | } |
| 3245 | } | 3189 | } |
| 3246 | for (zcu.failed_codegen.values()) |error_msg| { | 3190 | for (zcu.failed_codegen.keys(), zcu.failed_codegen.values()) |nav, error_msg| { |
| 3191 | if (!zcu.navFileScope(nav).okToReportErrors()) continue; | ||
| 3247 | try addModuleErrorMsg(zcu, &bundle, error_msg.*, &all_references); | 3192 | try addModuleErrorMsg(zcu, &bundle, error_msg.*, &all_references); |
| 3248 | } | 3193 | } |
| 3249 | for (zcu.failed_exports.values()) |value| { | 3194 | for (zcu.failed_exports.values()) |value| { |
| ... | @@ -3304,9 +3249,6 @@ pub fn getAllErrorsAlloc(comp: *Compilation) !ErrorBundle { | ... | @@ -3304,9 +3249,6 @@ pub fn getAllErrorsAlloc(comp: *Compilation) !ErrorBundle { |
| 3304 | 3249 | ||
| 3305 | if (comp.module) |zcu| { | 3250 | if (comp.module) |zcu| { |
| 3306 | if (bundle.root_list.items.len == 0 and zcu.compile_log_sources.count() != 0) { | 3251 | if (bundle.root_list.items.len == 0 and zcu.compile_log_sources.count() != 0) { |
| 3307 | var all_references = try zcu.resolveReferences(); | ||
| 3308 | defer all_references.deinit(gpa); | ||
| 3309 | |||
| 3310 | const values = zcu.compile_log_sources.values(); | 3252 | const values = zcu.compile_log_sources.values(); |
| 3311 | // First one will be the error; subsequent ones will be notes. | 3253 | // First one will be the error; subsequent ones will be notes. |
| 3312 | const src_loc = values[0].src(); | 3254 | const src_loc = values[0].src(); |
| ... | @@ -3328,12 +3270,30 @@ pub fn getAllErrorsAlloc(comp: *Compilation) !ErrorBundle { | ... | @@ -3328,12 +3270,30 @@ pub fn getAllErrorsAlloc(comp: *Compilation) !ErrorBundle { |
| 3328 | } | 3270 | } |
| 3329 | } | 3271 | } |
| 3330 | 3272 | ||
| 3331 | assert(comp.totalErrorCount() == bundle.root_list.items.len); | 3273 | if (comp.module) |zcu| { |
| 3274 | if (comp.incremental and bundle.root_list.items.len == 0) { | ||
| 3275 | const should_have_error = for (zcu.transitive_failed_analysis.keys()) |failed_unit| { | ||
| 3276 | if (all_references == null) { | ||
| 3277 | all_references = try zcu.resolveReferences(); | ||
| 3278 | } | ||
| 3279 | if (all_references.?.contains(failed_unit)) break true; | ||
| 3280 | } else false; | ||
| 3281 | if (should_have_error) { | ||
| 3282 | @panic("referenced transitive analysis errors, but none actually emitted"); | ||
| 3283 | } | ||
| 3284 | } | ||
| 3285 | } | ||
| 3332 | 3286 | ||
| 3333 | const compile_log_text = if (comp.module) |m| m.compile_log_text.items else ""; | 3287 | const compile_log_text = if (comp.module) |m| m.compile_log_text.items else ""; |
| 3334 | return bundle.toOwnedBundle(compile_log_text); | 3288 | return bundle.toOwnedBundle(compile_log_text); |
| 3335 | } | 3289 | } |
| 3336 | 3290 | ||
| 3291 | fn totalErrorCount(comp: *Compilation) !u32 { | ||
| 3292 | var errors = try comp.getAllErrorsAlloc(); | ||
| 3293 | defer errors.deinit(comp.gpa); | ||
| 3294 | return errors.errorMessageCount(); | ||
| 3295 | } | ||
| 3296 | |||
| 3337 | pub const ErrorNoteHashContext = struct { | 3297 | pub const ErrorNoteHashContext = struct { |
| 3338 | eb: *const ErrorBundle.Wip, | 3298 | eb: *const ErrorBundle.Wip, |
| 3339 | 3299 | ||
| ... | @@ -3384,7 +3344,7 @@ pub fn addModuleErrorMsg( | ... | @@ -3384,7 +3344,7 @@ pub fn addModuleErrorMsg( |
| 3384 | mod: *Zcu, | 3344 | mod: *Zcu, |
| 3385 | eb: *ErrorBundle.Wip, | 3345 | eb: *ErrorBundle.Wip, |
| 3386 | module_err_msg: Zcu.ErrorMsg, | 3346 | module_err_msg: Zcu.ErrorMsg, |
| 3387 | all_references: *const std.AutoHashMapUnmanaged(InternPool.AnalUnit, Zcu.ResolvedReference), | 3347 | all_references: *?std.AutoHashMapUnmanaged(InternPool.AnalUnit, ?Zcu.ResolvedReference), |
| 3388 | ) !void { | 3348 | ) !void { |
| 3389 | const gpa = eb.gpa; | 3349 | const gpa = eb.gpa; |
| 3390 | const ip = &mod.intern_pool; | 3350 | const ip = &mod.intern_pool; |
| ... | @@ -3408,13 +3368,18 @@ pub fn addModuleErrorMsg( | ... | @@ -3408,13 +3368,18 @@ pub fn addModuleErrorMsg( |
| 3408 | defer ref_traces.deinit(gpa); | 3368 | defer ref_traces.deinit(gpa); |
| 3409 | 3369 | ||
| 3410 | if (module_err_msg.reference_trace_root.unwrap()) |rt_root| { | 3370 | if (module_err_msg.reference_trace_root.unwrap()) |rt_root| { |
| 3371 | if (all_references.* == null) { | ||
| 3372 | all_references.* = try mod.resolveReferences(); | ||
| 3373 | } | ||
| 3374 | |||
| 3411 | var seen: std.AutoHashMapUnmanaged(InternPool.AnalUnit, void) = .{}; | 3375 | var seen: std.AutoHashMapUnmanaged(InternPool.AnalUnit, void) = .{}; |
| 3412 | defer seen.deinit(gpa); | 3376 | defer seen.deinit(gpa); |
| 3413 | 3377 | ||
| 3414 | const max_references = mod.comp.reference_trace orelse Sema.default_reference_trace_len; | 3378 | const max_references = mod.comp.reference_trace orelse Sema.default_reference_trace_len; |
| 3415 | 3379 | ||
| 3416 | var referenced_by = rt_root; | 3380 | var referenced_by = rt_root; |
| 3417 | while (all_references.get(referenced_by)) |ref| { | 3381 | while (all_references.*.?.get(referenced_by)) |maybe_ref| { |
| 3382 | const ref = maybe_ref orelse break; | ||
| 3418 | const gop = try seen.getOrPut(gpa, ref.referencer); | 3383 | const gop = try seen.getOrPut(gpa, ref.referencer); |
| 3419 | if (gop.found_existing) break; | 3384 | if (gop.found_existing) break; |
| 3420 | if (ref_traces.items.len < max_references) { | 3385 | if (ref_traces.items.len < max_references) { |
| ... | @@ -3423,6 +3388,7 @@ pub fn addModuleErrorMsg( | ... | @@ -3423,6 +3388,7 @@ pub fn addModuleErrorMsg( |
| 3423 | const span = try src.span(gpa); | 3388 | const span = try src.span(gpa); |
| 3424 | const loc = std.zig.findLineColumn(source.bytes, span.main); | 3389 | const loc = std.zig.findLineColumn(source.bytes, span.main); |
| 3425 | const rt_file_path = try src.file_scope.fullPath(gpa); | 3390 | const rt_file_path = try src.file_scope.fullPath(gpa); |
| 3391 | defer gpa.free(rt_file_path); | ||
| 3426 | const name = switch (ref.referencer.unwrap()) { | 3392 | const name = switch (ref.referencer.unwrap()) { |
| 3427 | .cau => |cau| switch (ip.getCau(cau).owner.unwrap()) { | 3393 | .cau => |cau| switch (ip.getCau(cau).owner.unwrap()) { |
| 3428 | .nav => |nav| ip.getNav(nav).name.toSlice(ip), | 3394 | .nav => |nav| ip.getNav(nav).name.toSlice(ip), |
| ... | @@ -3537,6 +3503,8 @@ pub fn performAllTheWork( | ... | @@ -3537,6 +3503,8 @@ pub fn performAllTheWork( |
| 3537 | mod.sema_prog_node = std.Progress.Node.none; | 3503 | mod.sema_prog_node = std.Progress.Node.none; |
| 3538 | mod.codegen_prog_node.end(); | 3504 | mod.codegen_prog_node.end(); |
| 3539 | mod.codegen_prog_node = std.Progress.Node.none; | 3505 | mod.codegen_prog_node = std.Progress.Node.none; |
| 3506 | |||
| 3507 | mod.generation += 1; | ||
| 3540 | }; | 3508 | }; |
| 3541 | try comp.performAllTheWorkInner(main_progress_node); | 3509 | try comp.performAllTheWorkInner(main_progress_node); |
| 3542 | if (!InternPool.single_threaded) if (comp.codegen_work.job_error) |job_error| return job_error; | 3510 | if (!InternPool.single_threaded) if (comp.codegen_work.job_error) |job_error| return job_error; |
| ... | @@ -3608,10 +3576,9 @@ fn performAllTheWorkInner( | ... | @@ -3608,10 +3576,9 @@ fn performAllTheWorkInner( |
| 3608 | // Pre-load these things from our single-threaded context since they | 3576 | // Pre-load these things from our single-threaded context since they |
| 3609 | // will be needed by the worker threads. | 3577 | // will be needed by the worker threads. |
| 3610 | const path_digest = zcu.filePathDigest(file_index); | 3578 | const path_digest = zcu.filePathDigest(file_index); |
| 3611 | const old_root_type = zcu.fileRootType(file_index); | ||
| 3612 | const file = zcu.fileByIndex(file_index); | 3579 | const file = zcu.fileByIndex(file_index); |
| 3613 | comp.thread_pool.spawnWgId(&astgen_wait_group, workerAstGenFile, .{ | 3580 | comp.thread_pool.spawnWgId(&astgen_wait_group, workerAstGenFile, .{ |
| 3614 | comp, file, file_index, path_digest, old_root_type, zir_prog_node, &astgen_wait_group, .root, | 3581 | comp, file, file_index, path_digest, zir_prog_node, &astgen_wait_group, .root, |
| 3615 | }); | 3582 | }); |
| 3616 | } | 3583 | } |
| 3617 | } | 3584 | } |
| ... | @@ -3649,11 +3616,15 @@ fn performAllTheWorkInner( | ... | @@ -3649,11 +3616,15 @@ fn performAllTheWorkInner( |
| 3649 | } | 3616 | } |
| 3650 | try reportMultiModuleErrors(pt); | 3617 | try reportMultiModuleErrors(pt); |
| 3651 | try zcu.flushRetryableFailures(); | 3618 | try zcu.flushRetryableFailures(); |
| 3619 | |||
| 3652 | zcu.sema_prog_node = main_progress_node.start("Semantic Analysis", 0); | 3620 | zcu.sema_prog_node = main_progress_node.start("Semantic Analysis", 0); |
| 3653 | zcu.codegen_prog_node = main_progress_node.start("Code Generation", 0); | 3621 | zcu.codegen_prog_node = main_progress_node.start("Code Generation", 0); |
| 3654 | } | 3622 | } |
| 3655 | 3623 | ||
| 3656 | if (!InternPool.single_threaded) comp.thread_pool.spawnWgId(&work_queue_wait_group, codegenThread, .{comp}); | 3624 | if (!InternPool.single_threaded) { |
| 3625 | comp.codegen_work.done = false; // may be `true` from a prior update | ||
| 3626 | comp.thread_pool.spawnWgId(&work_queue_wait_group, codegenThread, .{comp}); | ||
| 3627 | } | ||
| 3657 | defer if (!InternPool.single_threaded) { | 3628 | defer if (!InternPool.single_threaded) { |
| 3658 | { | 3629 | { |
| 3659 | comp.codegen_work.mutex.lock(); | 3630 | comp.codegen_work.mutex.lock(); |
| ... | @@ -4283,7 +4254,6 @@ fn workerAstGenFile( | ... | @@ -4283,7 +4254,6 @@ fn workerAstGenFile( |
| 4283 | file: *Zcu.File, | 4254 | file: *Zcu.File, |
| 4284 | file_index: Zcu.File.Index, | 4255 | file_index: Zcu.File.Index, |
| 4285 | path_digest: Cache.BinDigest, | 4256 | path_digest: Cache.BinDigest, |
| 4286 | old_root_type: InternPool.Index, | ||
| 4287 | prog_node: std.Progress.Node, | 4257 | prog_node: std.Progress.Node, |
| 4288 | wg: *WaitGroup, | 4258 | wg: *WaitGroup, |
| 4289 | src: Zcu.AstGenSrc, | 4259 | src: Zcu.AstGenSrc, |
| ... | @@ -4292,7 +4262,7 @@ fn workerAstGenFile( | ... | @@ -4292,7 +4262,7 @@ fn workerAstGenFile( |
| 4292 | defer child_prog_node.end(); | 4262 | defer child_prog_node.end(); |
| 4293 | 4263 | ||
| 4294 | const pt: Zcu.PerThread = .{ .zcu = comp.module.?, .tid = @enumFromInt(tid) }; | 4264 | const pt: Zcu.PerThread = .{ .zcu = comp.module.?, .tid = @enumFromInt(tid) }; |
| 4295 | pt.astGenFile(file, path_digest, old_root_type) catch |err| switch (err) { | 4265 | pt.astGenFile(file, path_digest) catch |err| switch (err) { |
| 4296 | error.AnalysisFail => return, | 4266 | error.AnalysisFail => return, |
| 4297 | else => { | 4267 | else => { |
| 4298 | file.status = .retryable_failure; | 4268 | file.status = .retryable_failure; |
| ... | @@ -4323,7 +4293,7 @@ fn workerAstGenFile( | ... | @@ -4323,7 +4293,7 @@ fn workerAstGenFile( |
| 4323 | // `@import("builtin")` is handled specially. | 4293 | // `@import("builtin")` is handled specially. |
| 4324 | if (mem.eql(u8, import_path, "builtin")) continue; | 4294 | if (mem.eql(u8, import_path, "builtin")) continue; |
| 4325 | 4295 | ||
| 4326 | const import_result, const imported_path_digest, const imported_root_type = blk: { | 4296 | const import_result, const imported_path_digest = blk: { |
| 4327 | comp.mutex.lock(); | 4297 | comp.mutex.lock(); |
| 4328 | defer comp.mutex.unlock(); | 4298 | defer comp.mutex.unlock(); |
| 4329 | 4299 | ||
| ... | @@ -4338,8 +4308,7 @@ fn workerAstGenFile( | ... | @@ -4338,8 +4308,7 @@ fn workerAstGenFile( |
| 4338 | comp.appendFileSystemInput(fsi, res.file.mod.root, res.file.sub_file_path) catch continue; | 4308 | comp.appendFileSystemInput(fsi, res.file.mod.root, res.file.sub_file_path) catch continue; |
| 4339 | }; | 4309 | }; |
| 4340 | const imported_path_digest = pt.zcu.filePathDigest(res.file_index); | 4310 | const imported_path_digest = pt.zcu.filePathDigest(res.file_index); |
| 4341 | const imported_root_type = pt.zcu.fileRootType(res.file_index); | 4311 | break :blk .{ res, imported_path_digest }; |
| 4342 | break :blk .{ res, imported_path_digest, imported_root_type }; | ||
| 4343 | }; | 4312 | }; |
| 4344 | if (import_result.is_new) { | 4313 | if (import_result.is_new) { |
| 4345 | log.debug("AstGen of {s} has import '{s}'; queuing AstGen of {s}", .{ | 4314 | log.debug("AstGen of {s} has import '{s}'; queuing AstGen of {s}", .{ |
| ... | @@ -4350,7 +4319,7 @@ fn workerAstGenFile( | ... | @@ -4350,7 +4319,7 @@ fn workerAstGenFile( |
| 4350 | .import_tok = item.data.token, | 4319 | .import_tok = item.data.token, |
| 4351 | } }; | 4320 | } }; |
| 4352 | comp.thread_pool.spawnWgId(wg, workerAstGenFile, .{ | 4321 | comp.thread_pool.spawnWgId(wg, workerAstGenFile, .{ |
| 4353 | comp, import_result.file, import_result.file_index, imported_path_digest, imported_root_type, prog_node, wg, sub_src, | 4322 | comp, import_result.file, import_result.file_index, imported_path_digest, prog_node, wg, sub_src, |
| 4354 | }); | 4323 | }); |
| 4355 | } | 4324 | } |
| 4356 | } | 4325 | } |
| ... | @@ -6443,7 +6412,8 @@ fn buildOutputFromZig( | ... | @@ -6443,7 +6412,8 @@ fn buildOutputFromZig( |
| 6443 | 6412 | ||
| 6444 | try comp.updateSubCompilation(sub_compilation, misc_task_tag, prog_node); | 6413 | try comp.updateSubCompilation(sub_compilation, misc_task_tag, prog_node); |
| 6445 | 6414 | ||
| 6446 | assert(out.* == null); | 6415 | // Under incremental compilation, `out` may already be populated from a prior update. |
| 6416 | assert(out.* == null or comp.incremental); | ||
| 6447 | out.* = try sub_compilation.toCrtFile(); | 6417 | out.* = try sub_compilation.toCrtFile(); |
| 6448 | } | 6418 | } |
| 6449 | 6419 |
src/InternPool.zig+307-48| ... | @@ -62,22 +62,60 @@ const want_multi_threaded = true; | ... | @@ -62,22 +62,60 @@ const want_multi_threaded = true; |
| 62 | /// Whether a single-threaded intern pool impl is in use. | 62 | /// Whether a single-threaded intern pool impl is in use. |
| 63 | pub const single_threaded = builtin.single_threaded or !want_multi_threaded; | 63 | pub const single_threaded = builtin.single_threaded or !want_multi_threaded; |
| 64 | 64 | ||
| 65 | /// A `TrackedInst.Index` provides a single, unchanging reference to a ZIR instruction across a whole | ||
| 66 | /// compilation. From this index, you can acquire a `TrackedInst`, which containss a reference to both | ||
| 67 | /// the file which the instruction lives in, and the instruction index itself, which is updated on | ||
| 68 | /// incremental updates by `Zcu.updateZirRefs`. | ||
| 65 | pub const TrackedInst = extern struct { | 69 | pub const TrackedInst = extern struct { |
| 66 | file: FileIndex, | 70 | file: FileIndex, |
| 67 | inst: Zir.Inst.Index, | 71 | inst: Zir.Inst.Index, |
| 68 | comptime { | 72 | |
| 69 | // The fields should be tightly packed. See also serialiation logic in `Compilation.saveState`. | 73 | /// It is possible on an incremental update that we "lose" a ZIR instruction: some tracked `%x` in |
| 70 | assert(@sizeOf(@This()) == @sizeOf(FileIndex) + @sizeOf(Zir.Inst.Index)); | 74 | /// the old ZIR failed to map to any `%y` in the new ZIR. For this reason, we actually store values |
| 71 | } | 75 | /// of type `MaybeLost`, which uses `ZirIndex.lost` to represent this case. `Index.resolve` etc |
| 76 | /// return `null` when the `TrackedInst` being resolved has been lost. | ||
| 77 | pub const MaybeLost = extern struct { | ||
| 78 | file: FileIndex, | ||
| 79 | inst: ZirIndex, | ||
| 80 | pub const ZirIndex = enum(u32) { | ||
| 81 | /// Tracking failed for this ZIR instruction. Uses of it should fail. | ||
| 82 | lost = std.math.maxInt(u32), | ||
| 83 | _, | ||
| 84 | pub fn unwrap(inst: ZirIndex) ?Zir.Inst.Index { | ||
| 85 | return switch (inst) { | ||
| 86 | .lost => null, | ||
| 87 | _ => @enumFromInt(@intFromEnum(inst)), | ||
| 88 | }; | ||
| 89 | } | ||
| 90 | pub fn wrap(inst: Zir.Inst.Index) ZirIndex { | ||
| 91 | return @enumFromInt(@intFromEnum(inst)); | ||
| 92 | } | ||
| 93 | }; | ||
| 94 | comptime { | ||
| 95 | // The fields should be tightly packed. See also serialiation logic in `Compilation.saveState`. | ||
| 96 | assert(@sizeOf(@This()) == @sizeOf(FileIndex) + @sizeOf(ZirIndex)); | ||
| 97 | } | ||
| 98 | }; | ||
| 99 | |||
| 72 | pub const Index = enum(u32) { | 100 | pub const Index = enum(u32) { |
| 73 | _, | 101 | _, |
| 74 | pub fn resolveFull(tracked_inst_index: TrackedInst.Index, ip: *const InternPool) TrackedInst { | 102 | pub fn resolveFull(tracked_inst_index: TrackedInst.Index, ip: *const InternPool) ?TrackedInst { |
| 103 | const tracked_inst_unwrapped = tracked_inst_index.unwrap(ip); | ||
| 104 | const tracked_insts = ip.getLocalShared(tracked_inst_unwrapped.tid).tracked_insts.acquire(); | ||
| 105 | const maybe_lost = tracked_insts.view().items(.@"0")[tracked_inst_unwrapped.index]; | ||
| 106 | return .{ | ||
| 107 | .file = maybe_lost.file, | ||
| 108 | .inst = maybe_lost.inst.unwrap() orelse return null, | ||
| 109 | }; | ||
| 110 | } | ||
| 111 | pub fn resolveFile(tracked_inst_index: TrackedInst.Index, ip: *const InternPool) FileIndex { | ||
| 75 | const tracked_inst_unwrapped = tracked_inst_index.unwrap(ip); | 112 | const tracked_inst_unwrapped = tracked_inst_index.unwrap(ip); |
| 76 | const tracked_insts = ip.getLocalShared(tracked_inst_unwrapped.tid).tracked_insts.acquire(); | 113 | const tracked_insts = ip.getLocalShared(tracked_inst_unwrapped.tid).tracked_insts.acquire(); |
| 77 | return tracked_insts.view().items(.@"0")[tracked_inst_unwrapped.index]; | 114 | const maybe_lost = tracked_insts.view().items(.@"0")[tracked_inst_unwrapped.index]; |
| 115 | return maybe_lost.file; | ||
| 78 | } | 116 | } |
| 79 | pub fn resolve(i: TrackedInst.Index, ip: *const InternPool) Zir.Inst.Index { | 117 | pub fn resolve(i: TrackedInst.Index, ip: *const InternPool) ?Zir.Inst.Index { |
| 80 | return i.resolveFull(ip).inst; | 118 | return (i.resolveFull(ip) orelse return null).inst; |
| 81 | } | 119 | } |
| 82 | 120 | ||
| 83 | pub fn toOptional(i: TrackedInst.Index) Optional { | 121 | pub fn toOptional(i: TrackedInst.Index) Optional { |
| ... | @@ -120,7 +158,11 @@ pub fn trackZir( | ... | @@ -120,7 +158,11 @@ pub fn trackZir( |
| 120 | tid: Zcu.PerThread.Id, | 158 | tid: Zcu.PerThread.Id, |
| 121 | key: TrackedInst, | 159 | key: TrackedInst, |
| 122 | ) Allocator.Error!TrackedInst.Index { | 160 | ) Allocator.Error!TrackedInst.Index { |
| 123 | const full_hash = Hash.hash(0, std.mem.asBytes(&key)); | 161 | const maybe_lost_key: TrackedInst.MaybeLost = .{ |
| 162 | .file = key.file, | ||
| 163 | .inst = TrackedInst.MaybeLost.ZirIndex.wrap(key.inst), | ||
| 164 | }; | ||
| 165 | const full_hash = Hash.hash(0, std.mem.asBytes(&maybe_lost_key)); | ||
| 124 | const hash: u32 = @truncate(full_hash >> 32); | 166 | const hash: u32 = @truncate(full_hash >> 32); |
| 125 | const shard = &ip.shards[@intCast(full_hash & (ip.shards.len - 1))]; | 167 | const shard = &ip.shards[@intCast(full_hash & (ip.shards.len - 1))]; |
| 126 | var map = shard.shared.tracked_inst_map.acquire(); | 168 | var map = shard.shared.tracked_inst_map.acquire(); |
| ... | @@ -132,12 +174,11 @@ pub fn trackZir( | ... | @@ -132,12 +174,11 @@ pub fn trackZir( |
| 132 | const entry = &map.entries[map_index]; | 174 | const entry = &map.entries[map_index]; |
| 133 | const index = entry.acquire().unwrap() orelse break; | 175 | const index = entry.acquire().unwrap() orelse break; |
| 134 | if (entry.hash != hash) continue; | 176 | if (entry.hash != hash) continue; |
| 135 | if (std.meta.eql(index.resolveFull(ip), key)) return index; | 177 | if (std.meta.eql(index.resolveFull(ip) orelse continue, key)) return index; |
| 136 | } | 178 | } |
| 137 | shard.mutate.tracked_inst_map.mutex.lock(); | 179 | shard.mutate.tracked_inst_map.mutex.lock(); |
| 138 | defer shard.mutate.tracked_inst_map.mutex.unlock(); | 180 | defer shard.mutate.tracked_inst_map.mutex.unlock(); |
| 139 | if (map.entries != shard.shared.tracked_inst_map.entries) { | 181 | if (map.entries != shard.shared.tracked_inst_map.entries) { |
| 140 | shard.mutate.tracked_inst_map.len += 1; | ||
| 141 | map = shard.shared.tracked_inst_map; | 182 | map = shard.shared.tracked_inst_map; |
| 142 | map_mask = map.header().mask(); | 183 | map_mask = map.header().mask(); |
| 143 | map_index = hash; | 184 | map_index = hash; |
| ... | @@ -147,7 +188,7 @@ pub fn trackZir( | ... | @@ -147,7 +188,7 @@ pub fn trackZir( |
| 147 | const entry = &map.entries[map_index]; | 188 | const entry = &map.entries[map_index]; |
| 148 | const index = entry.acquire().unwrap() orelse break; | 189 | const index = entry.acquire().unwrap() orelse break; |
| 149 | if (entry.hash != hash) continue; | 190 | if (entry.hash != hash) continue; |
| 150 | if (std.meta.eql(index.resolveFull(ip), key)) return index; | 191 | if (std.meta.eql(index.resolveFull(ip) orelse continue, key)) return index; |
| 151 | } | 192 | } |
| 152 | defer shard.mutate.tracked_inst_map.len += 1; | 193 | defer shard.mutate.tracked_inst_map.len += 1; |
| 153 | const local = ip.getLocal(tid); | 194 | const local = ip.getLocal(tid); |
| ... | @@ -161,7 +202,7 @@ pub fn trackZir( | ... | @@ -161,7 +202,7 @@ pub fn trackZir( |
| 161 | .tid = tid, | 202 | .tid = tid, |
| 162 | .index = list.mutate.len, | 203 | .index = list.mutate.len, |
| 163 | }).wrap(ip); | 204 | }).wrap(ip); |
| 164 | list.appendAssumeCapacity(.{key}); | 205 | list.appendAssumeCapacity(.{maybe_lost_key}); |
| 165 | entry.release(index.toOptional()); | 206 | entry.release(index.toOptional()); |
| 166 | return index; | 207 | return index; |
| 167 | } | 208 | } |
| ... | @@ -205,12 +246,94 @@ pub fn trackZir( | ... | @@ -205,12 +246,94 @@ pub fn trackZir( |
| 205 | .tid = tid, | 246 | .tid = tid, |
| 206 | .index = list.mutate.len, | 247 | .index = list.mutate.len, |
| 207 | }).wrap(ip); | 248 | }).wrap(ip); |
| 208 | list.appendAssumeCapacity(.{key}); | 249 | list.appendAssumeCapacity(.{maybe_lost_key}); |
| 209 | map.entries[map_index] = .{ .value = index.toOptional(), .hash = hash }; | 250 | map.entries[map_index] = .{ .value = index.toOptional(), .hash = hash }; |
| 210 | shard.shared.tracked_inst_map.release(new_map); | 251 | shard.shared.tracked_inst_map.release(new_map); |
| 211 | return index; | 252 | return index; |
| 212 | } | 253 | } |
| 213 | 254 | ||
| 255 | /// At the start of an incremental update, we update every entry in `tracked_insts` to include | ||
| 256 | /// the new ZIR index. Once this is done, we must update the hashmap metadata so that lookups | ||
| 257 | /// return correct entries where they already exist. | ||
| 258 | pub fn rehashTrackedInsts( | ||
| 259 | ip: *InternPool, | ||
| 260 | gpa: Allocator, | ||
| 261 | tid: Zcu.PerThread.Id, | ||
| 262 | ) Allocator.Error!void { | ||
| 263 | assert(tid == .main); // we shouldn't have any other threads active right now | ||
| 264 | |||
| 265 | // TODO: this function doesn't handle OOM well. What should it do? | ||
| 266 | |||
| 267 | // We don't lock anything, as this function assumes that no other thread is | ||
| 268 | // accessing `tracked_insts`. This is necessary because we're going to be | ||
| 269 | // iterating the `TrackedInst`s in each `Local`, so we have to know that | ||
| 270 | // none will be added as we work. | ||
| 271 | |||
| 272 | // Figure out how big each shard need to be and store it in its mutate `len`. | ||
| 273 | for (ip.shards) |*shard| shard.mutate.tracked_inst_map.len = 0; | ||
| 274 | for (ip.locals) |*local| { | ||
| 275 | // `getMutableTrackedInsts` is okay only because no other thread is currently active. | ||
| 276 | // We need the `mutate` for the len. | ||
| 277 | for (local.getMutableTrackedInsts(gpa).viewAllowEmpty().items(.@"0")) |tracked_inst| { | ||
| 278 | if (tracked_inst.inst == .lost) continue; // we can ignore this one! | ||
| 279 | const full_hash = Hash.hash(0, std.mem.asBytes(&tracked_inst)); | ||
| 280 | const shard = &ip.shards[@intCast(full_hash & (ip.shards.len - 1))]; | ||
| 281 | shard.mutate.tracked_inst_map.len += 1; | ||
| 282 | } | ||
| 283 | } | ||
| 284 | |||
| 285 | const Map = Shard.Map(TrackedInst.Index.Optional); | ||
| 286 | |||
| 287 | const arena_state = &ip.getLocal(tid).mutate.arena; | ||
| 288 | |||
| 289 | // We know how big each shard must be, so ensure we have the capacity we need. | ||
| 290 | for (ip.shards) |*shard| { | ||
| 291 | const want_capacity = std.math.ceilPowerOfTwo(u32, shard.mutate.tracked_inst_map.len * 5 / 3) catch unreachable; | ||
| 292 | const have_capacity = shard.shared.tracked_inst_map.header().capacity; // no acquire because we hold the mutex | ||
| 293 | if (have_capacity >= want_capacity) { | ||
| 294 | @memset(shard.shared.tracked_inst_map.entries[0..have_capacity], .{ .value = .none, .hash = undefined }); | ||
| 295 | continue; | ||
| 296 | } | ||
| 297 | var arena = arena_state.promote(gpa); | ||
| 298 | defer arena_state.* = arena.state; | ||
| 299 | const new_map_buf = try arena.allocator().alignedAlloc( | ||
| 300 | u8, | ||
| 301 | Map.alignment, | ||
| 302 | Map.entries_offset + want_capacity * @sizeOf(Map.Entry), | ||
| 303 | ); | ||
| 304 | const new_map: Map = .{ .entries = @ptrCast(new_map_buf[Map.entries_offset..].ptr) }; | ||
| 305 | new_map.header().* = .{ .capacity = want_capacity }; | ||
| 306 | @memset(new_map.entries[0..want_capacity], .{ .value = .none, .hash = undefined }); | ||
| 307 | shard.shared.tracked_inst_map.release(new_map); | ||
| 308 | } | ||
| 309 | |||
| 310 | // Now, actually insert the items. | ||
| 311 | for (ip.locals, 0..) |*local, local_tid| { | ||
| 312 | // `getMutableTrackedInsts` is okay only because no other thread is currently active. | ||
| 313 | // We need the `mutate` for the len. | ||
| 314 | for (local.getMutableTrackedInsts(gpa).viewAllowEmpty().items(.@"0"), 0..) |tracked_inst, local_inst_index| { | ||
| 315 | if (tracked_inst.inst == .lost) continue; // we can ignore this one! | ||
| 316 | const full_hash = Hash.hash(0, std.mem.asBytes(&tracked_inst)); | ||
| 317 | const hash: u32 = @truncate(full_hash >> 32); | ||
| 318 | const shard = &ip.shards[@intCast(full_hash & (ip.shards.len - 1))]; | ||
| 319 | const map = shard.shared.tracked_inst_map; // no acquire because we hold the mutex | ||
| 320 | const map_mask = map.header().mask(); | ||
| 321 | var map_index = hash; | ||
| 322 | const entry = while (true) : (map_index += 1) { | ||
| 323 | map_index &= map_mask; | ||
| 324 | const entry = &map.entries[map_index]; | ||
| 325 | if (entry.acquire() == .none) break entry; | ||
| 326 | }; | ||
| 327 | const index = TrackedInst.Index.Unwrapped.wrap(.{ | ||
| 328 | .tid = @enumFromInt(local_tid), | ||
| 329 | .index = @intCast(local_inst_index), | ||
| 330 | }, ip); | ||
| 331 | entry.hash = hash; | ||
| 332 | entry.release(index.toOptional()); | ||
| 333 | } | ||
| 334 | } | ||
| 335 | } | ||
| 336 | |||
| 214 | /// Analysis Unit. Represents a single entity which undergoes semantic analysis. | 337 | /// Analysis Unit. Represents a single entity which undergoes semantic analysis. |
| 215 | /// This is either a `Cau` or a runtime function. | 338 | /// This is either a `Cau` or a runtime function. |
| 216 | /// The LSB is used as a tag bit. | 339 | /// The LSB is used as a tag bit. |
| ... | @@ -572,10 +695,6 @@ pub fn dependencyIterator(ip: *const InternPool, dependee: Dependee) DependencyI | ... | @@ -572,10 +695,6 @@ pub fn dependencyIterator(ip: *const InternPool, dependee: Dependee) DependencyI |
| 572 | .ip = ip, | 695 | .ip = ip, |
| 573 | .next_entry = .none, | 696 | .next_entry = .none, |
| 574 | }; | 697 | }; |
| 575 | if (ip.dep_entries.items[@intFromEnum(first_entry)].depender == .none) return .{ | ||
| 576 | .ip = ip, | ||
| 577 | .next_entry = .none, | ||
| 578 | }; | ||
| 579 | return .{ | 698 | return .{ |
| 580 | .ip = ip, | 699 | .ip = ip, |
| 581 | .next_entry = first_entry.toOptional(), | 700 | .next_entry = first_entry.toOptional(), |
| ... | @@ -612,7 +731,6 @@ pub fn addDependency(ip: *InternPool, gpa: Allocator, depender: AnalUnit, depend | ... | @@ -612,7 +731,6 @@ pub fn addDependency(ip: *InternPool, gpa: Allocator, depender: AnalUnit, depend |
| 612 | 731 | ||
| 613 | if (gop.found_existing and ip.dep_entries.items[@intFromEnum(gop.value_ptr.*)].depender == .none) { | 732 | if (gop.found_existing and ip.dep_entries.items[@intFromEnum(gop.value_ptr.*)].depender == .none) { |
| 614 | // Dummy entry, so we can reuse it rather than allocating a new one! | 733 | // Dummy entry, so we can reuse it rather than allocating a new one! |
| 615 | ip.dep_entries.items[@intFromEnum(gop.value_ptr.*)].next = .none; | ||
| 616 | break :new_index gop.value_ptr.*; | 734 | break :new_index gop.value_ptr.*; |
| 617 | } | 735 | } |
| 618 | 736 | ||
| ... | @@ -620,7 +738,12 @@ pub fn addDependency(ip: *InternPool, gpa: Allocator, depender: AnalUnit, depend | ... | @@ -620,7 +738,12 @@ pub fn addDependency(ip: *InternPool, gpa: Allocator, depender: AnalUnit, depend |
| 620 | const new_index: DepEntry.Index, const ptr = if (ip.free_dep_entries.popOrNull()) |new_index| new: { | 738 | const new_index: DepEntry.Index, const ptr = if (ip.free_dep_entries.popOrNull()) |new_index| new: { |
| 621 | break :new .{ new_index, &ip.dep_entries.items[@intFromEnum(new_index)] }; | 739 | break :new .{ new_index, &ip.dep_entries.items[@intFromEnum(new_index)] }; |
| 622 | } else .{ @enumFromInt(ip.dep_entries.items.len), ip.dep_entries.addOneAssumeCapacity() }; | 740 | } else .{ @enumFromInt(ip.dep_entries.items.len), ip.dep_entries.addOneAssumeCapacity() }; |
| 623 | ptr.next = if (gop.found_existing) gop.value_ptr.*.toOptional() else .none; | 741 | if (gop.found_existing) { |
| 742 | ptr.next = gop.value_ptr.*.toOptional(); | ||
| 743 | ip.dep_entries.items[@intFromEnum(gop.value_ptr.*)].prev = new_index.toOptional(); | ||
| 744 | } else { | ||
| 745 | ptr.next = .none; | ||
| 746 | } | ||
| 624 | gop.value_ptr.* = new_index; | 747 | gop.value_ptr.* = new_index; |
| 625 | break :new_index new_index; | 748 | break :new_index new_index; |
| 626 | }, | 749 | }, |
| ... | @@ -642,10 +765,9 @@ pub const NamespaceNameKey = struct { | ... | @@ -642,10 +765,9 @@ pub const NamespaceNameKey = struct { |
| 642 | }; | 765 | }; |
| 643 | 766 | ||
| 644 | pub const DepEntry = extern struct { | 767 | pub const DepEntry = extern struct { |
| 645 | /// If null, this is a dummy entry - all other fields are `undefined`. It is | 768 | /// If null, this is a dummy entry. `next_dependee` is undefined. This is the first |
| 646 | /// the first and only entry in one of `intern_pool.*_deps`, and does not | 769 | /// entry in one of `*_deps`, and does not appear in any list by `first_dependency`, |
| 647 | /// appear in any list by `first_dependency`, but is not in | 770 | /// but is not in `free_dep_entries` since `*_deps` stores a reference to it. |
| 648 | /// `free_dep_entries` since `*_deps` stores a reference to it. | ||
| 649 | depender: AnalUnit.Optional, | 771 | depender: AnalUnit.Optional, |
| 650 | /// Index into `dep_entries` forming a doubly linked list of all dependencies on this dependee. | 772 | /// Index into `dep_entries` forming a doubly linked list of all dependencies on this dependee. |
| 651 | /// Used to iterate all dependers for a given dependee during an update. | 773 | /// Used to iterate all dependers for a given dependee during an update. |
| ... | @@ -684,6 +806,14 @@ const Local = struct { | ... | @@ -684,6 +806,14 @@ const Local = struct { |
| 684 | /// This state is fully local to the owning thread and does not require any | 806 | /// This state is fully local to the owning thread and does not require any |
| 685 | /// atomic access. | 807 | /// atomic access. |
| 686 | mutate: struct { | 808 | mutate: struct { |
| 809 | /// When we need to allocate any long-lived buffer for mutating the `InternPool`, it is | ||
| 810 | /// allocated into this `arena` (for the `Id` of the thread performing the mutation). An | ||
| 811 | /// arena is used to avoid contention on the GPA, and to ensure that any code which retains | ||
| 812 | /// references to old state remains valid. For instance, when reallocing hashmap metadata, | ||
| 813 | /// a racing lookup on another thread may still retain a handle to the old metadata pointer, | ||
| 814 | /// so it must remain valid. | ||
| 815 | /// This arena's lifetime is tied to that of `Compilation`, although it can be cleared on | ||
| 816 | /// garbage collection (currently vaporware). | ||
| 687 | arena: std.heap.ArenaAllocator.State, | 817 | arena: std.heap.ArenaAllocator.State, |
| 688 | 818 | ||
| 689 | items: ListMutate, | 819 | items: ListMutate, |
| ... | @@ -728,7 +858,7 @@ const Local = struct { | ... | @@ -728,7 +858,7 @@ const Local = struct { |
| 728 | else => @compileError("unsupported host"), | 858 | else => @compileError("unsupported host"), |
| 729 | }; | 859 | }; |
| 730 | const Strings = List(struct { u8 }); | 860 | const Strings = List(struct { u8 }); |
| 731 | const TrackedInsts = List(struct { TrackedInst }); | 861 | const TrackedInsts = List(struct { TrackedInst.MaybeLost }); |
| 732 | const Maps = List(struct { FieldMap }); | 862 | const Maps = List(struct { FieldMap }); |
| 733 | const Caus = List(struct { Cau }); | 863 | const Caus = List(struct { Cau }); |
| 734 | const Navs = List(Nav.Repr); | 864 | const Navs = List(Nav.Repr); |
| ... | @@ -959,6 +1089,14 @@ const Local = struct { | ... | @@ -959,6 +1089,14 @@ const Local = struct { |
| 959 | mutable.list.release(new_list); | 1089 | mutable.list.release(new_list); |
| 960 | } | 1090 | } |
| 961 | 1091 | ||
| 1092 | pub fn viewAllowEmpty(mutable: Mutable) View { | ||
| 1093 | const capacity = mutable.list.header().capacity; | ||
| 1094 | return .{ | ||
| 1095 | .bytes = mutable.list.bytes, | ||
| 1096 | .len = mutable.mutate.len, | ||
| 1097 | .capacity = capacity, | ||
| 1098 | }; | ||
| 1099 | } | ||
| 962 | pub fn view(mutable: Mutable) View { | 1100 | pub fn view(mutable: Mutable) View { |
| 963 | const capacity = mutable.list.header().capacity; | 1101 | const capacity = mutable.list.header().capacity; |
| 964 | assert(capacity > 0); // optimizes `MultiArrayList.Slice.items` | 1102 | assert(capacity > 0); // optimizes `MultiArrayList.Slice.items` |
| ... | @@ -996,7 +1134,6 @@ const Local = struct { | ... | @@ -996,7 +1134,6 @@ const Local = struct { |
| 996 | fn header(list: ListSelf) *Header { | 1134 | fn header(list: ListSelf) *Header { |
| 997 | return @ptrFromInt(@intFromPtr(list.bytes) - bytes_offset); | 1135 | return @ptrFromInt(@intFromPtr(list.bytes) - bytes_offset); |
| 998 | } | 1136 | } |
| 999 | |||
| 1000 | pub fn view(list: ListSelf) View { | 1137 | pub fn view(list: ListSelf) View { |
| 1001 | const capacity = list.header().capacity; | 1138 | const capacity = list.header().capacity; |
| 1002 | assert(capacity > 0); // optimizes `MultiArrayList.Slice.items` | 1139 | assert(capacity > 0); // optimizes `MultiArrayList.Slice.items` |
| ... | @@ -2570,7 +2707,12 @@ pub const Key = union(enum) { | ... | @@ -2570,7 +2707,12 @@ pub const Key = union(enum) { |
| 2570 | 2707 | ||
| 2571 | .variable => |a_info| { | 2708 | .variable => |a_info| { |
| 2572 | const b_info = b.variable; | 2709 | const b_info = b.variable; |
| 2573 | return a_info.owner_nav == b_info.owner_nav; | 2710 | return a_info.owner_nav == b_info.owner_nav and |
| 2711 | a_info.ty == b_info.ty and | ||
| 2712 | a_info.init == b_info.init and | ||
| 2713 | a_info.lib_name == b_info.lib_name and | ||
| 2714 | a_info.is_threadlocal == b_info.is_threadlocal and | ||
| 2715 | a_info.is_weak_linkage == b_info.is_weak_linkage; | ||
| 2574 | }, | 2716 | }, |
| 2575 | .@"extern" => |a_info| { | 2717 | .@"extern" => |a_info| { |
| 2576 | const b_info = b.@"extern"; | 2718 | const b_info = b.@"extern"; |
| ... | @@ -6958,6 +7100,7 @@ fn getOrPutKeyEnsuringAdditionalCapacity( | ... | @@ -6958,6 +7100,7 @@ fn getOrPutKeyEnsuringAdditionalCapacity( |
| 6958 | const index = entry.acquire(); | 7100 | const index = entry.acquire(); |
| 6959 | if (index == .none) break; | 7101 | if (index == .none) break; |
| 6960 | if (entry.hash != hash) continue; | 7102 | if (entry.hash != hash) continue; |
| 7103 | if (ip.isRemoved(index)) continue; | ||
| 6961 | if (ip.indexToKey(index).eql(key, ip)) return .{ .existing = index }; | 7104 | if (ip.indexToKey(index).eql(key, ip)) return .{ .existing = index }; |
| 6962 | } | 7105 | } |
| 6963 | shard.mutate.map.mutex.lock(); | 7106 | shard.mutate.map.mutex.lock(); |
| ... | @@ -7032,6 +7175,43 @@ fn getOrPutKeyEnsuringAdditionalCapacity( | ... | @@ -7032,6 +7175,43 @@ fn getOrPutKeyEnsuringAdditionalCapacity( |
| 7032 | .map_index = map_index, | 7175 | .map_index = map_index, |
| 7033 | } }; | 7176 | } }; |
| 7034 | } | 7177 | } |
| 7178 | /// Like `getOrPutKey`, but asserts that the key already exists, and prepares to replace | ||
| 7179 | /// its shard entry with a new `Index` anyway. After finalizing this, the old index remains | ||
| 7180 | /// valid (in that `indexToKey` and similar queries will behave as before), but it will | ||
| 7181 | /// never be returned from a lookup (`getOrPutKey` etc). | ||
| 7182 | /// This is used by incremental compilation when an existing container type is outdated. In | ||
| 7183 | /// this case, the type must be recreated at a new `InternPool.Index`, but the old index must | ||
| 7184 | /// remain valid since now-unreferenced `AnalUnit`s may retain references to it. The old index | ||
| 7185 | /// will be cleaned up when the `Zcu` undergoes garbage collection. | ||
| 7186 | fn putKeyReplace( | ||
| 7187 | ip: *InternPool, | ||
| 7188 | tid: Zcu.PerThread.Id, | ||
| 7189 | key: Key, | ||
| 7190 | ) GetOrPutKey { | ||
| 7191 | const full_hash = key.hash64(ip); | ||
| 7192 | const hash: u32 = @truncate(full_hash >> 32); | ||
| 7193 | const shard = &ip.shards[@intCast(full_hash & (ip.shards.len - 1))]; | ||
| 7194 | shard.mutate.map.mutex.lock(); | ||
| 7195 | errdefer shard.mutate.map.mutex.unlock(); | ||
| 7196 | const map = shard.shared.map; | ||
| 7197 | const map_mask = map.header().mask(); | ||
| 7198 | var map_index = hash; | ||
| 7199 | while (true) : (map_index += 1) { | ||
| 7200 | map_index &= map_mask; | ||
| 7201 | const entry = &map.entries[map_index]; | ||
| 7202 | const index = entry.value; | ||
| 7203 | assert(index != .none); // key not present | ||
| 7204 | if (entry.hash == hash and ip.indexToKey(index).eql(key, ip)) { | ||
| 7205 | break; // we found the entry to replace | ||
| 7206 | } | ||
| 7207 | } | ||
| 7208 | return .{ .new = .{ | ||
| 7209 | .ip = ip, | ||
| 7210 | .tid = tid, | ||
| 7211 | .shard = shard, | ||
| 7212 | .map_index = map_index, | ||
| 7213 | } }; | ||
| 7214 | } | ||
| 7035 | 7215 | ||
| 7036 | pub fn get(ip: *InternPool, gpa: Allocator, tid: Zcu.PerThread.Id, key: Key) Allocator.Error!Index { | 7216 | pub fn get(ip: *InternPool, gpa: Allocator, tid: Zcu.PerThread.Id, key: Key) Allocator.Error!Index { |
| 7037 | var gop = try ip.getOrPutKey(gpa, tid, key); | 7217 | var gop = try ip.getOrPutKey(gpa, tid, key); |
| ... | @@ -7859,6 +8039,10 @@ pub const UnionTypeInit = struct { | ... | @@ -7859,6 +8039,10 @@ pub const UnionTypeInit = struct { |
| 7859 | zir_index: TrackedInst.Index, | 8039 | zir_index: TrackedInst.Index, |
| 7860 | captures: []const CaptureValue, | 8040 | captures: []const CaptureValue, |
| 7861 | }, | 8041 | }, |
| 8042 | declared_owned_captures: struct { | ||
| 8043 | zir_index: TrackedInst.Index, | ||
| 8044 | captures: CaptureValue.Slice, | ||
| 8045 | }, | ||
| 7862 | reified: struct { | 8046 | reified: struct { |
| 7863 | zir_index: TrackedInst.Index, | 8047 | zir_index: TrackedInst.Index, |
| 7864 | type_hash: u64, | 8048 | type_hash: u64, |
| ... | @@ -7871,17 +8055,28 @@ pub fn getUnionType( | ... | @@ -7871,17 +8055,28 @@ pub fn getUnionType( |
| 7871 | gpa: Allocator, | 8055 | gpa: Allocator, |
| 7872 | tid: Zcu.PerThread.Id, | 8056 | tid: Zcu.PerThread.Id, |
| 7873 | ini: UnionTypeInit, | 8057 | ini: UnionTypeInit, |
| 8058 | /// If it is known that there is an existing type with this key which is outdated, | ||
| 8059 | /// this is passed as `true`, and the type is replaced with one at a fresh index. | ||
| 8060 | replace_existing: bool, | ||
| 7874 | ) Allocator.Error!WipNamespaceType.Result { | 8061 | ) Allocator.Error!WipNamespaceType.Result { |
| 7875 | var gop = try ip.getOrPutKey(gpa, tid, .{ .union_type = switch (ini.key) { | 8062 | const key: Key = .{ .union_type = switch (ini.key) { |
| 7876 | .declared => |d| .{ .declared = .{ | 8063 | .declared => |d| .{ .declared = .{ |
| 7877 | .zir_index = d.zir_index, | 8064 | .zir_index = d.zir_index, |
| 7878 | .captures = .{ .external = d.captures }, | 8065 | .captures = .{ .external = d.captures }, |
| 7879 | } }, | 8066 | } }, |
| 8067 | .declared_owned_captures => |d| .{ .declared = .{ | ||
| 8068 | .zir_index = d.zir_index, | ||
| 8069 | .captures = .{ .owned = d.captures }, | ||
| 8070 | } }, | ||
| 7880 | .reified => |r| .{ .reified = .{ | 8071 | .reified => |r| .{ .reified = .{ |
| 7881 | .zir_index = r.zir_index, | 8072 | .zir_index = r.zir_index, |
| 7882 | .type_hash = r.type_hash, | 8073 | .type_hash = r.type_hash, |
| 7883 | } }, | 8074 | } }, |
| 7884 | } }); | 8075 | } }; |
| 8076 | var gop = if (replace_existing) | ||
| 8077 | ip.putKeyReplace(tid, key) | ||
| 8078 | else | ||
| 8079 | try ip.getOrPutKey(gpa, tid, key); | ||
| 7885 | defer gop.deinit(); | 8080 | defer gop.deinit(); |
| 7886 | if (gop == .existing) return .{ .existing = gop.existing }; | 8081 | if (gop == .existing) return .{ .existing = gop.existing }; |
| 7887 | 8082 | ||
| ... | @@ -7896,7 +8091,7 @@ pub fn getUnionType( | ... | @@ -7896,7 +8091,7 @@ pub fn getUnionType( |
| 7896 | // TODO: fmt bug | 8091 | // TODO: fmt bug |
| 7897 | // zig fmt: off | 8092 | // zig fmt: off |
| 7898 | switch (ini.key) { | 8093 | switch (ini.key) { |
| 7899 | .declared => |d| @intFromBool(d.captures.len != 0) + d.captures.len, | 8094 | inline .declared, .declared_owned_captures => |d| @intFromBool(d.captures.len != 0) + d.captures.len, |
| 7900 | .reified => 2, // type_hash: PackedU64 | 8095 | .reified => 2, // type_hash: PackedU64 |
| 7901 | } + | 8096 | } + |
| 7902 | // zig fmt: on | 8097 | // zig fmt: on |
| ... | @@ -7905,7 +8100,10 @@ pub fn getUnionType( | ... | @@ -7905,7 +8100,10 @@ pub fn getUnionType( |
| 7905 | 8100 | ||
| 7906 | const extra_index = addExtraAssumeCapacity(extra, Tag.TypeUnion{ | 8101 | const extra_index = addExtraAssumeCapacity(extra, Tag.TypeUnion{ |
| 7907 | .flags = .{ | 8102 | .flags = .{ |
| 7908 | .any_captures = ini.key == .declared and ini.key.declared.captures.len != 0, | 8103 | .any_captures = switch (ini.key) { |
| 8104 | inline .declared, .declared_owned_captures => |d| d.captures.len != 0, | ||
| 8105 | .reified => false, | ||
| 8106 | }, | ||
| 7909 | .runtime_tag = ini.flags.runtime_tag, | 8107 | .runtime_tag = ini.flags.runtime_tag, |
| 7910 | .any_aligned_fields = ini.flags.any_aligned_fields, | 8108 | .any_aligned_fields = ini.flags.any_aligned_fields, |
| 7911 | .layout = ini.flags.layout, | 8109 | .layout = ini.flags.layout, |
| ... | @@ -7914,7 +8112,10 @@ pub fn getUnionType( | ... | @@ -7914,7 +8112,10 @@ pub fn getUnionType( |
| 7914 | .assumed_runtime_bits = ini.flags.assumed_runtime_bits, | 8112 | .assumed_runtime_bits = ini.flags.assumed_runtime_bits, |
| 7915 | .assumed_pointer_aligned = ini.flags.assumed_pointer_aligned, | 8113 | .assumed_pointer_aligned = ini.flags.assumed_pointer_aligned, |
| 7916 | .alignment = ini.flags.alignment, | 8114 | .alignment = ini.flags.alignment, |
| 7917 | .is_reified = ini.key == .reified, | 8115 | .is_reified = switch (ini.key) { |
| 8116 | .declared, .declared_owned_captures => false, | ||
| 8117 | .reified => true, | ||
| 8118 | }, | ||
| 7918 | }, | 8119 | }, |
| 7919 | .fields_len = ini.fields_len, | 8120 | .fields_len = ini.fields_len, |
| 7920 | .size = std.math.maxInt(u32), | 8121 | .size = std.math.maxInt(u32), |
| ... | @@ -7938,6 +8139,10 @@ pub fn getUnionType( | ... | @@ -7938,6 +8139,10 @@ pub fn getUnionType( |
| 7938 | extra.appendAssumeCapacity(.{@intCast(d.captures.len)}); | 8139 | extra.appendAssumeCapacity(.{@intCast(d.captures.len)}); |
| 7939 | extra.appendSliceAssumeCapacity(.{@ptrCast(d.captures)}); | 8140 | extra.appendSliceAssumeCapacity(.{@ptrCast(d.captures)}); |
| 7940 | }, | 8141 | }, |
| 8142 | .declared_owned_captures => |d| if (d.captures.len != 0) { | ||
| 8143 | extra.appendAssumeCapacity(.{@intCast(d.captures.len)}); | ||
| 8144 | extra.appendSliceAssumeCapacity(.{@ptrCast(d.captures.get(ip))}); | ||
| 8145 | }, | ||
| 7941 | .reified => |r| _ = addExtraAssumeCapacity(extra, PackedU64.init(r.type_hash)), | 8146 | .reified => |r| _ = addExtraAssumeCapacity(extra, PackedU64.init(r.type_hash)), |
| 7942 | } | 8147 | } |
| 7943 | 8148 | ||
| ... | @@ -8035,6 +8240,10 @@ pub const StructTypeInit = struct { | ... | @@ -8035,6 +8240,10 @@ pub const StructTypeInit = struct { |
| 8035 | zir_index: TrackedInst.Index, | 8240 | zir_index: TrackedInst.Index, |
| 8036 | captures: []const CaptureValue, | 8241 | captures: []const CaptureValue, |
| 8037 | }, | 8242 | }, |
| 8243 | declared_owned_captures: struct { | ||
| 8244 | zir_index: TrackedInst.Index, | ||
| 8245 | captures: CaptureValue.Slice, | ||
| 8246 | }, | ||
| 8038 | reified: struct { | 8247 | reified: struct { |
| 8039 | zir_index: TrackedInst.Index, | 8248 | zir_index: TrackedInst.Index, |
| 8040 | type_hash: u64, | 8249 | type_hash: u64, |
| ... | @@ -8047,17 +8256,28 @@ pub fn getStructType( | ... | @@ -8047,17 +8256,28 @@ pub fn getStructType( |
| 8047 | gpa: Allocator, | 8256 | gpa: Allocator, |
| 8048 | tid: Zcu.PerThread.Id, | 8257 | tid: Zcu.PerThread.Id, |
| 8049 | ini: StructTypeInit, | 8258 | ini: StructTypeInit, |
| 8259 | /// If it is known that there is an existing type with this key which is outdated, | ||
| 8260 | /// this is passed as `true`, and the type is replaced with one at a fresh index. | ||
| 8261 | replace_existing: bool, | ||
| 8050 | ) Allocator.Error!WipNamespaceType.Result { | 8262 | ) Allocator.Error!WipNamespaceType.Result { |
| 8051 | var gop = try ip.getOrPutKey(gpa, tid, .{ .struct_type = switch (ini.key) { | 8263 | const key: Key = .{ .struct_type = switch (ini.key) { |
| 8052 | .declared => |d| .{ .declared = .{ | 8264 | .declared => |d| .{ .declared = .{ |
| 8053 | .zir_index = d.zir_index, | 8265 | .zir_index = d.zir_index, |
| 8054 | .captures = .{ .external = d.captures }, | 8266 | .captures = .{ .external = d.captures }, |
| 8055 | } }, | 8267 | } }, |
| 8268 | .declared_owned_captures => |d| .{ .declared = .{ | ||
| 8269 | .zir_index = d.zir_index, | ||
| 8270 | .captures = .{ .owned = d.captures }, | ||
| 8271 | } }, | ||
| 8056 | .reified => |r| .{ .reified = .{ | 8272 | .reified => |r| .{ .reified = .{ |
| 8057 | .zir_index = r.zir_index, | 8273 | .zir_index = r.zir_index, |
| 8058 | .type_hash = r.type_hash, | 8274 | .type_hash = r.type_hash, |
| 8059 | } }, | 8275 | } }, |
| 8060 | } }); | 8276 | } }; |
| 8277 | var gop = if (replace_existing) | ||
| 8278 | ip.putKeyReplace(tid, key) | ||
| 8279 | else | ||
| 8280 | try ip.getOrPutKey(gpa, tid, key); | ||
| 8061 | defer gop.deinit(); | 8281 | defer gop.deinit(); |
| 8062 | if (gop == .existing) return .{ .existing = gop.existing }; | 8282 | if (gop == .existing) return .{ .existing = gop.existing }; |
| 8063 | 8283 | ||
| ... | @@ -8080,7 +8300,7 @@ pub fn getStructType( | ... | @@ -8080,7 +8300,7 @@ pub fn getStructType( |
| 8080 | // TODO: fmt bug | 8300 | // TODO: fmt bug |
| 8081 | // zig fmt: off | 8301 | // zig fmt: off |
| 8082 | switch (ini.key) { | 8302 | switch (ini.key) { |
| 8083 | .declared => |d| @intFromBool(d.captures.len != 0) + d.captures.len, | 8303 | inline .declared, .declared_owned_captures => |d| @intFromBool(d.captures.len != 0) + d.captures.len, |
| 8084 | .reified => 2, // type_hash: PackedU64 | 8304 | .reified => 2, // type_hash: PackedU64 |
| 8085 | } + | 8305 | } + |
| 8086 | // zig fmt: on | 8306 | // zig fmt: on |
| ... | @@ -8096,10 +8316,16 @@ pub fn getStructType( | ... | @@ -8096,10 +8316,16 @@ pub fn getStructType( |
| 8096 | .backing_int_ty = .none, | 8316 | .backing_int_ty = .none, |
| 8097 | .names_map = names_map, | 8317 | .names_map = names_map, |
| 8098 | .flags = .{ | 8318 | .flags = .{ |
| 8099 | .any_captures = ini.key == .declared and ini.key.declared.captures.len != 0, | 8319 | .any_captures = switch (ini.key) { |
| 8320 | inline .declared, .declared_owned_captures => |d| d.captures.len != 0, | ||
| 8321 | .reified => false, | ||
| 8322 | }, | ||
| 8100 | .field_inits_wip = false, | 8323 | .field_inits_wip = false, |
| 8101 | .inits_resolved = ini.inits_resolved, | 8324 | .inits_resolved = ini.inits_resolved, |
| 8102 | .is_reified = ini.key == .reified, | 8325 | .is_reified = switch (ini.key) { |
| 8326 | .declared, .declared_owned_captures => false, | ||
| 8327 | .reified => true, | ||
| 8328 | }, | ||
| 8103 | }, | 8329 | }, |
| 8104 | }); | 8330 | }); |
| 8105 | try items.append(.{ | 8331 | try items.append(.{ |
| ... | @@ -8111,6 +8337,10 @@ pub fn getStructType( | ... | @@ -8111,6 +8337,10 @@ pub fn getStructType( |
| 8111 | extra.appendAssumeCapacity(.{@intCast(d.captures.len)}); | 8337 | extra.appendAssumeCapacity(.{@intCast(d.captures.len)}); |
| 8112 | extra.appendSliceAssumeCapacity(.{@ptrCast(d.captures)}); | 8338 | extra.appendSliceAssumeCapacity(.{@ptrCast(d.captures)}); |
| 8113 | }, | 8339 | }, |
| 8340 | .declared_owned_captures => |d| if (d.captures.len != 0) { | ||
| 8341 | extra.appendAssumeCapacity(.{@intCast(d.captures.len)}); | ||
| 8342 | extra.appendSliceAssumeCapacity(.{@ptrCast(d.captures.get(ip))}); | ||
| 8343 | }, | ||
| 8114 | .reified => |r| { | 8344 | .reified => |r| { |
| 8115 | _ = addExtraAssumeCapacity(extra, PackedU64.init(r.type_hash)); | 8345 | _ = addExtraAssumeCapacity(extra, PackedU64.init(r.type_hash)); |
| 8116 | }, | 8346 | }, |
| ... | @@ -8138,7 +8368,7 @@ pub fn getStructType( | ... | @@ -8138,7 +8368,7 @@ pub fn getStructType( |
| 8138 | // TODO: fmt bug | 8368 | // TODO: fmt bug |
| 8139 | // zig fmt: off | 8369 | // zig fmt: off |
| 8140 | switch (ini.key) { | 8370 | switch (ini.key) { |
| 8141 | .declared => |d| @intFromBool(d.captures.len != 0) + d.captures.len, | 8371 | inline .declared, .declared_owned_captures => |d| @intFromBool(d.captures.len != 0) + d.captures.len, |
| 8142 | .reified => 2, // type_hash: PackedU64 | 8372 | .reified => 2, // type_hash: PackedU64 |
| 8143 | } + | 8373 | } + |
| 8144 | // zig fmt: on | 8374 | // zig fmt: on |
| ... | @@ -8153,7 +8383,10 @@ pub fn getStructType( | ... | @@ -8153,7 +8383,10 @@ pub fn getStructType( |
| 8153 | .fields_len = ini.fields_len, | 8383 | .fields_len = ini.fields_len, |
| 8154 | .size = std.math.maxInt(u32), | 8384 | .size = std.math.maxInt(u32), |
| 8155 | .flags = .{ | 8385 | .flags = .{ |
| 8156 | .any_captures = ini.key == .declared and ini.key.declared.captures.len != 0, | 8386 | .any_captures = switch (ini.key) { |
| 8387 | inline .declared, .declared_owned_captures => |d| d.captures.len != 0, | ||
| 8388 | .reified => false, | ||
| 8389 | }, | ||
| 8157 | .is_extern = is_extern, | 8390 | .is_extern = is_extern, |
| 8158 | .known_non_opv = ini.known_non_opv, | 8391 | .known_non_opv = ini.known_non_opv, |
| 8159 | .requires_comptime = ini.requires_comptime, | 8392 | .requires_comptime = ini.requires_comptime, |
| ... | @@ -8171,7 +8404,10 @@ pub fn getStructType( | ... | @@ -8171,7 +8404,10 @@ pub fn getStructType( |
| 8171 | .field_inits_wip = false, | 8404 | .field_inits_wip = false, |
| 8172 | .inits_resolved = ini.inits_resolved, | 8405 | .inits_resolved = ini.inits_resolved, |
| 8173 | .fully_resolved = false, | 8406 | .fully_resolved = false, |
| 8174 | .is_reified = ini.key == .reified, | 8407 | .is_reified = switch (ini.key) { |
| 8408 | .declared, .declared_owned_captures => false, | ||
| 8409 | .reified => true, | ||
| 8410 | }, | ||
| 8175 | }, | 8411 | }, |
| 8176 | }); | 8412 | }); |
| 8177 | try items.append(.{ | 8413 | try items.append(.{ |
| ... | @@ -8183,6 +8419,10 @@ pub fn getStructType( | ... | @@ -8183,6 +8419,10 @@ pub fn getStructType( |
| 8183 | extra.appendAssumeCapacity(.{@intCast(d.captures.len)}); | 8419 | extra.appendAssumeCapacity(.{@intCast(d.captures.len)}); |
| 8184 | extra.appendSliceAssumeCapacity(.{@ptrCast(d.captures)}); | 8420 | extra.appendSliceAssumeCapacity(.{@ptrCast(d.captures)}); |
| 8185 | }, | 8421 | }, |
| 8422 | .declared_owned_captures => |d| if (d.captures.len != 0) { | ||
| 8423 | extra.appendAssumeCapacity(.{@intCast(d.captures.len)}); | ||
| 8424 | extra.appendSliceAssumeCapacity(.{@ptrCast(d.captures.get(ip))}); | ||
| 8425 | }, | ||
| 8186 | .reified => |r| { | 8426 | .reified => |r| { |
| 8187 | _ = addExtraAssumeCapacity(extra, PackedU64.init(r.type_hash)); | 8427 | _ = addExtraAssumeCapacity(extra, PackedU64.init(r.type_hash)); |
| 8188 | }, | 8428 | }, |
| ... | @@ -8986,6 +9226,10 @@ pub const EnumTypeInit = struct { | ... | @@ -8986,6 +9226,10 @@ pub const EnumTypeInit = struct { |
| 8986 | zir_index: TrackedInst.Index, | 9226 | zir_index: TrackedInst.Index, |
| 8987 | captures: []const CaptureValue, | 9227 | captures: []const CaptureValue, |
| 8988 | }, | 9228 | }, |
| 9229 | declared_owned_captures: struct { | ||
| 9230 | zir_index: TrackedInst.Index, | ||
| 9231 | captures: CaptureValue.Slice, | ||
| 9232 | }, | ||
| 8989 | reified: struct { | 9233 | reified: struct { |
| 8990 | zir_index: TrackedInst.Index, | 9234 | zir_index: TrackedInst.Index, |
| 8991 | type_hash: u64, | 9235 | type_hash: u64, |
| ... | @@ -9081,17 +9325,28 @@ pub fn getEnumType( | ... | @@ -9081,17 +9325,28 @@ pub fn getEnumType( |
| 9081 | gpa: Allocator, | 9325 | gpa: Allocator, |
| 9082 | tid: Zcu.PerThread.Id, | 9326 | tid: Zcu.PerThread.Id, |
| 9083 | ini: EnumTypeInit, | 9327 | ini: EnumTypeInit, |
| 9328 | /// If it is known that there is an existing type with this key which is outdated, | ||
| 9329 | /// this is passed as `true`, and the type is replaced with one at a fresh index. | ||
| 9330 | replace_existing: bool, | ||
| 9084 | ) Allocator.Error!WipEnumType.Result { | 9331 | ) Allocator.Error!WipEnumType.Result { |
| 9085 | var gop = try ip.getOrPutKey(gpa, tid, .{ .enum_type = switch (ini.key) { | 9332 | const key: Key = .{ .enum_type = switch (ini.key) { |
| 9086 | .declared => |d| .{ .declared = .{ | 9333 | .declared => |d| .{ .declared = .{ |
| 9087 | .zir_index = d.zir_index, | 9334 | .zir_index = d.zir_index, |
| 9088 | .captures = .{ .external = d.captures }, | 9335 | .captures = .{ .external = d.captures }, |
| 9089 | } }, | 9336 | } }, |
| 9337 | .declared_owned_captures => |d| .{ .declared = .{ | ||
| 9338 | .zir_index = d.zir_index, | ||
| 9339 | .captures = .{ .owned = d.captures }, | ||
| 9340 | } }, | ||
| 9090 | .reified => |r| .{ .reified = .{ | 9341 | .reified => |r| .{ .reified = .{ |
| 9091 | .zir_index = r.zir_index, | 9342 | .zir_index = r.zir_index, |
| 9092 | .type_hash = r.type_hash, | 9343 | .type_hash = r.type_hash, |
| 9093 | } }, | 9344 | } }, |
| 9094 | } }); | 9345 | } }; |
| 9346 | var gop = if (replace_existing) | ||
| 9347 | ip.putKeyReplace(tid, key) | ||
| 9348 | else | ||
| 9349 | try ip.getOrPutKey(gpa, tid, key); | ||
| 9095 | defer gop.deinit(); | 9350 | defer gop.deinit(); |
| 9096 | if (gop == .existing) return .{ .existing = gop.existing }; | 9351 | if (gop == .existing) return .{ .existing = gop.existing }; |
| 9097 | 9352 | ||
| ... | @@ -9110,7 +9365,7 @@ pub fn getEnumType( | ... | @@ -9110,7 +9365,7 @@ pub fn getEnumType( |
| 9110 | // TODO: fmt bug | 9365 | // TODO: fmt bug |
| 9111 | // zig fmt: off | 9366 | // zig fmt: off |
| 9112 | switch (ini.key) { | 9367 | switch (ini.key) { |
| 9113 | .declared => |d| d.captures.len, | 9368 | inline .declared, .declared_owned_captures => |d| d.captures.len, |
| 9114 | .reified => 2, // type_hash: PackedU64 | 9369 | .reified => 2, // type_hash: PackedU64 |
| 9115 | } + | 9370 | } + |
| 9116 | // zig fmt: on | 9371 | // zig fmt: on |
| ... | @@ -9120,7 +9375,7 @@ pub fn getEnumType( | ... | @@ -9120,7 +9375,7 @@ pub fn getEnumType( |
| 9120 | const extra_index = addExtraAssumeCapacity(extra, EnumAuto{ | 9375 | const extra_index = addExtraAssumeCapacity(extra, EnumAuto{ |
| 9121 | .name = undefined, // set by `prepare` | 9376 | .name = undefined, // set by `prepare` |
| 9122 | .captures_len = switch (ini.key) { | 9377 | .captures_len = switch (ini.key) { |
| 9123 | .declared => |d| @intCast(d.captures.len), | 9378 | inline .declared, .declared_owned_captures => |d| @intCast(d.captures.len), |
| 9124 | .reified => std.math.maxInt(u32), | 9379 | .reified => std.math.maxInt(u32), |
| 9125 | }, | 9380 | }, |
| 9126 | .namespace = undefined, // set by `prepare` | 9381 | .namespace = undefined, // set by `prepare` |
| ... | @@ -9139,6 +9394,7 @@ pub fn getEnumType( | ... | @@ -9139,6 +9394,7 @@ pub fn getEnumType( |
| 9139 | extra.appendAssumeCapacity(undefined); // `cau` will be set by `finish` | 9394 | extra.appendAssumeCapacity(undefined); // `cau` will be set by `finish` |
| 9140 | switch (ini.key) { | 9395 | switch (ini.key) { |
| 9141 | .declared => |d| extra.appendSliceAssumeCapacity(.{@ptrCast(d.captures)}), | 9396 | .declared => |d| extra.appendSliceAssumeCapacity(.{@ptrCast(d.captures)}), |
| 9397 | .declared_owned_captures => |d| extra.appendSliceAssumeCapacity(.{@ptrCast(d.captures.get(ip))}), | ||
| 9142 | .reified => |r| _ = addExtraAssumeCapacity(extra, PackedU64.init(r.type_hash)), | 9398 | .reified => |r| _ = addExtraAssumeCapacity(extra, PackedU64.init(r.type_hash)), |
| 9143 | } | 9399 | } |
| 9144 | const names_start = extra.mutate.len; | 9400 | const names_start = extra.mutate.len; |
| ... | @@ -9169,7 +9425,7 @@ pub fn getEnumType( | ... | @@ -9169,7 +9425,7 @@ pub fn getEnumType( |
| 9169 | // TODO: fmt bug | 9425 | // TODO: fmt bug |
| 9170 | // zig fmt: off | 9426 | // zig fmt: off |
| 9171 | switch (ini.key) { | 9427 | switch (ini.key) { |
| 9172 | .declared => |d| d.captures.len, | 9428 | inline .declared, .declared_owned_captures => |d| d.captures.len, |
| 9173 | .reified => 2, // type_hash: PackedU64 | 9429 | .reified => 2, // type_hash: PackedU64 |
| 9174 | } + | 9430 | } + |
| 9175 | // zig fmt: on | 9431 | // zig fmt: on |
| ... | @@ -9180,7 +9436,7 @@ pub fn getEnumType( | ... | @@ -9180,7 +9436,7 @@ pub fn getEnumType( |
| 9180 | const extra_index = addExtraAssumeCapacity(extra, EnumExplicit{ | 9436 | const extra_index = addExtraAssumeCapacity(extra, EnumExplicit{ |
| 9181 | .name = undefined, // set by `prepare` | 9437 | .name = undefined, // set by `prepare` |
| 9182 | .captures_len = switch (ini.key) { | 9438 | .captures_len = switch (ini.key) { |
| 9183 | .declared => |d| @intCast(d.captures.len), | 9439 | inline .declared, .declared_owned_captures => |d| @intCast(d.captures.len), |
| 9184 | .reified => std.math.maxInt(u32), | 9440 | .reified => std.math.maxInt(u32), |
| 9185 | }, | 9441 | }, |
| 9186 | .namespace = undefined, // set by `prepare` | 9442 | .namespace = undefined, // set by `prepare` |
| ... | @@ -9204,6 +9460,7 @@ pub fn getEnumType( | ... | @@ -9204,6 +9460,7 @@ pub fn getEnumType( |
| 9204 | extra.appendAssumeCapacity(undefined); // `cau` will be set by `finish` | 9460 | extra.appendAssumeCapacity(undefined); // `cau` will be set by `finish` |
| 9205 | switch (ini.key) { | 9461 | switch (ini.key) { |
| 9206 | .declared => |d| extra.appendSliceAssumeCapacity(.{@ptrCast(d.captures)}), | 9462 | .declared => |d| extra.appendSliceAssumeCapacity(.{@ptrCast(d.captures)}), |
| 9463 | .declared_owned_captures => |d| extra.appendSliceAssumeCapacity(.{@ptrCast(d.captures.get(ip))}), | ||
| 9207 | .reified => |r| _ = addExtraAssumeCapacity(extra, PackedU64.init(r.type_hash)), | 9464 | .reified => |r| _ = addExtraAssumeCapacity(extra, PackedU64.init(r.type_hash)), |
| 9208 | } | 9465 | } |
| 9209 | const names_start = extra.mutate.len; | 9466 | const names_start = extra.mutate.len; |
| ... | @@ -9267,10 +9524,12 @@ pub fn getGeneratedTagEnumType( | ... | @@ -9267,10 +9524,12 @@ pub fn getGeneratedTagEnumType( |
| 9267 | .tid = tid, | 9524 | .tid = tid, |
| 9268 | .index = items.mutate.len, | 9525 | .index = items.mutate.len, |
| 9269 | }, ip); | 9526 | }, ip); |
| 9527 | const parent_namespace = ip.namespacePtr(ini.parent_namespace); | ||
| 9270 | const namespace = try ip.createNamespace(gpa, tid, .{ | 9528 | const namespace = try ip.createNamespace(gpa, tid, .{ |
| 9271 | .parent = ini.parent_namespace.toOptional(), | 9529 | .parent = ini.parent_namespace.toOptional(), |
| 9272 | .owner_type = enum_index, | 9530 | .owner_type = enum_index, |
| 9273 | .file_scope = ip.namespacePtr(ini.parent_namespace).file_scope, | 9531 | .file_scope = parent_namespace.file_scope, |
| 9532 | .generation = parent_namespace.generation, | ||
| 9274 | }); | 9533 | }); |
| 9275 | errdefer ip.destroyNamespace(tid, namespace); | 9534 | errdefer ip.destroyNamespace(tid, namespace); |
| 9276 | 9535 | ||
| ... | @@ -10866,6 +11125,7 @@ pub fn destroyNamespace( | ... | @@ -10866,6 +11125,7 @@ pub fn destroyNamespace( |
| 10866 | .parent = undefined, | 11125 | .parent = undefined, |
| 10867 | .file_scope = undefined, | 11126 | .file_scope = undefined, |
| 10868 | .owner_type = undefined, | 11127 | .owner_type = undefined, |
| 11128 | .generation = undefined, | ||
| 10869 | }; | 11129 | }; |
| 10870 | @field(namespace, Local.namespace_next_free_field) = | 11130 | @field(namespace, Local.namespace_next_free_field) = |
| 10871 | @enumFromInt(local.mutate.namespaces.free_list); | 11131 | @enumFromInt(local.mutate.namespaces.free_list); |
| ... | @@ -11000,7 +11260,6 @@ pub fn getOrPutTrailingString( | ... | @@ -11000,7 +11260,6 @@ pub fn getOrPutTrailingString( |
| 11000 | shard.mutate.string_map.mutex.lock(); | 11260 | shard.mutate.string_map.mutex.lock(); |
| 11001 | defer shard.mutate.string_map.mutex.unlock(); | 11261 | defer shard.mutate.string_map.mutex.unlock(); |
| 11002 | if (map.entries != shard.shared.string_map.entries) { | 11262 | if (map.entries != shard.shared.string_map.entries) { |
| 11003 | shard.mutate.string_map.len += 1; | ||
| 11004 | map = shard.shared.string_map; | 11263 | map = shard.shared.string_map; |
| 11005 | map_mask = map.header().mask(); | 11264 | map_mask = map.header().mask(); |
| 11006 | map_index = hash; | 11265 | map_index = hash; |
src/Sema.zig+375-266| ... | @@ -110,6 +110,12 @@ exports: std.ArrayListUnmanaged(Zcu.Export) = .{}, | ... | @@ -110,6 +110,12 @@ exports: std.ArrayListUnmanaged(Zcu.Export) = .{}, |
| 110 | /// of data stored in `Zcu.all_references`. It exists to avoid adding references to | 110 | /// of data stored in `Zcu.all_references`. It exists to avoid adding references to |
| 111 | /// a given `AnalUnit` multiple times. | 111 | /// a given `AnalUnit` multiple times. |
| 112 | references: std.AutoArrayHashMapUnmanaged(AnalUnit, void) = .{}, | 112 | references: std.AutoArrayHashMapUnmanaged(AnalUnit, void) = .{}, |
| 113 | type_references: std.AutoArrayHashMapUnmanaged(InternPool.Index, void) = .{}, | ||
| 114 | |||
| 115 | /// All dependencies registered so far by this `Sema`. This is a temporary duplicate | ||
| 116 | /// of the main dependency data. It exists to avoid adding dependencies to a given | ||
| 117 | /// `AnalUnit` multiple times. | ||
| 118 | dependencies: std.AutoArrayHashMapUnmanaged(InternPool.Dependee, void) = .{}, | ||
| 113 | 119 | ||
| 114 | const MaybeComptimeAlloc = struct { | 120 | const MaybeComptimeAlloc = struct { |
| 115 | /// The runtime index of the `alloc` instruction. | 121 | /// The runtime index of the `alloc` instruction. |
| ... | @@ -877,6 +883,8 @@ pub fn deinit(sema: *Sema) void { | ... | @@ -877,6 +883,8 @@ pub fn deinit(sema: *Sema) void { |
| 877 | sema.comptime_allocs.deinit(gpa); | 883 | sema.comptime_allocs.deinit(gpa); |
| 878 | sema.exports.deinit(gpa); | 884 | sema.exports.deinit(gpa); |
| 879 | sema.references.deinit(gpa); | 885 | sema.references.deinit(gpa); |
| 886 | sema.type_references.deinit(gpa); | ||
| 887 | sema.dependencies.deinit(gpa); | ||
| 880 | sema.* = undefined; | 888 | sema.* = undefined; |
| 881 | } | 889 | } |
| 882 | 890 | ||
| ... | @@ -999,7 +1007,7 @@ fn analyzeBodyInner( | ... | @@ -999,7 +1007,7 @@ fn analyzeBodyInner( |
| 999 | // The hashmap lookup in here is a little expensive, and LLVM fails to optimize it away. | 1007 | // The hashmap lookup in here is a little expensive, and LLVM fails to optimize it away. |
| 1000 | if (build_options.enable_logging) { | 1008 | if (build_options.enable_logging) { |
| 1001 | std.log.scoped(.sema_zir).debug("sema ZIR {s} %{d}", .{ sub_file_path: { | 1009 | std.log.scoped(.sema_zir).debug("sema ZIR {s} %{d}", .{ sub_file_path: { |
| 1002 | const file_index = block.src_base_inst.resolveFull(&zcu.intern_pool).file; | 1010 | const file_index = block.src_base_inst.resolveFile(&zcu.intern_pool); |
| 1003 | const file = zcu.fileByIndex(file_index); | 1011 | const file = zcu.fileByIndex(file_index); |
| 1004 | break :sub_file_path file.sub_file_path; | 1012 | break :sub_file_path file.sub_file_path; |
| 1005 | }, inst }); | 1013 | }, inst }); |
| ... | @@ -2496,12 +2504,12 @@ pub fn failWithOwnedErrorMsg(sema: *Sema, block: ?*Block, err_msg: *Module.Error | ... | @@ -2496,12 +2504,12 @@ pub fn failWithOwnedErrorMsg(sema: *Sema, block: ?*Block, err_msg: *Module.Error |
| 2496 | const mod = sema.pt.zcu; | 2504 | const mod = sema.pt.zcu; |
| 2497 | 2505 | ||
| 2498 | if (build_options.enable_debug_extensions and mod.comp.debug_compile_errors) { | 2506 | if (build_options.enable_debug_extensions and mod.comp.debug_compile_errors) { |
| 2499 | var all_references = mod.resolveReferences() catch @panic("out of memory"); | 2507 | var all_references: ?std.AutoHashMapUnmanaged(AnalUnit, ?Zcu.ResolvedReference) = null; |
| 2500 | var wip_errors: std.zig.ErrorBundle.Wip = undefined; | 2508 | var wip_errors: std.zig.ErrorBundle.Wip = undefined; |
| 2501 | wip_errors.init(gpa) catch @panic("out of memory"); | 2509 | wip_errors.init(gpa) catch @panic("out of memory"); |
| 2502 | Compilation.addModuleErrorMsg(mod, &wip_errors, err_msg.*, &all_references) catch unreachable; | 2510 | Compilation.addModuleErrorMsg(mod, &wip_errors, err_msg.*, &all_references) catch @panic("out of memory"); |
| 2503 | std.debug.print("compile error during Sema:\n", .{}); | 2511 | std.debug.print("compile error during Sema:\n", .{}); |
| 2504 | var error_bundle = wip_errors.toOwnedBundle("") catch unreachable; | 2512 | var error_bundle = wip_errors.toOwnedBundle("") catch @panic("out of memory"); |
| 2505 | error_bundle.renderToStdErr(.{ .ttyconf = .no_color }); | 2513 | error_bundle.renderToStdErr(.{ .ttyconf = .no_color }); |
| 2506 | crash_report.compilerPanic("unexpected compile error occurred", null, null); | 2514 | crash_report.compilerPanic("unexpected compile error occurred", null, null); |
| 2507 | } | 2515 | } |
| ... | @@ -2715,33 +2723,6 @@ fn wrapWipTy(sema: *Sema, wip_ty: anytype) @TypeOf(wip_ty) { | ... | @@ -2715,33 +2723,6 @@ fn wrapWipTy(sema: *Sema, wip_ty: anytype) @TypeOf(wip_ty) { |
| 2715 | return new; | 2723 | return new; |
| 2716 | } | 2724 | } |
| 2717 | 2725 | ||
| 2718 | /// Given a type just looked up in the `InternPool`, check whether it is | ||
| 2719 | /// considered outdated on this update. If so, remove it from the pool | ||
| 2720 | /// and return `true`. | ||
| 2721 | fn maybeRemoveOutdatedType(sema: *Sema, ty: InternPool.Index) !bool { | ||
| 2722 | const pt = sema.pt; | ||
| 2723 | const zcu = pt.zcu; | ||
| 2724 | const ip = &zcu.intern_pool; | ||
| 2725 | |||
| 2726 | if (!zcu.comp.incremental) return false; | ||
| 2727 | |||
| 2728 | const cau_index = switch (ip.indexToKey(ty)) { | ||
| 2729 | .struct_type => ip.loadStructType(ty).cau.unwrap().?, | ||
| 2730 | .union_type => ip.loadUnionType(ty).cau, | ||
| 2731 | .enum_type => ip.loadEnumType(ty).cau.unwrap().?, | ||
| 2732 | else => unreachable, | ||
| 2733 | }; | ||
| 2734 | const cau_unit = AnalUnit.wrap(.{ .cau = cau_index }); | ||
| 2735 | const was_outdated = zcu.outdated.swapRemove(cau_unit) or | ||
| 2736 | zcu.potentially_outdated.swapRemove(cau_unit); | ||
| 2737 | if (!was_outdated) return false; | ||
| 2738 | _ = zcu.outdated_ready.swapRemove(cau_unit); | ||
| 2739 | zcu.intern_pool.removeDependenciesForDepender(zcu.gpa, cau_unit); | ||
| 2740 | zcu.intern_pool.remove(pt.tid, ty); | ||
| 2741 | try zcu.markDependeeOutdated(.{ .interned = ty }); | ||
| 2742 | return true; | ||
| 2743 | } | ||
| 2744 | |||
| 2745 | fn zirStructDecl( | 2726 | fn zirStructDecl( |
| 2746 | sema: *Sema, | 2727 | sema: *Sema, |
| 2747 | block: *Block, | 2728 | block: *Block, |
| ... | @@ -2807,10 +2788,17 @@ fn zirStructDecl( | ... | @@ -2807,10 +2788,17 @@ fn zirStructDecl( |
| 2807 | .captures = captures, | 2788 | .captures = captures, |
| 2808 | } }, | 2789 | } }, |
| 2809 | }; | 2790 | }; |
| 2810 | const wip_ty = sema.wrapWipTy(switch (try ip.getStructType(gpa, pt.tid, struct_init)) { | 2791 | const wip_ty = sema.wrapWipTy(switch (try ip.getStructType(gpa, pt.tid, struct_init, false)) { |
| 2811 | .existing => |ty| wip: { | 2792 | .existing => |ty| { |
| 2812 | if (!try sema.maybeRemoveOutdatedType(ty)) return Air.internedToRef(ty); | 2793 | const new_ty = try pt.ensureTypeUpToDate(ty, false); |
| 2813 | break :wip (try ip.getStructType(gpa, pt.tid, struct_init)).wip; | 2794 | |
| 2795 | // Make sure we update the namespace if the declaration is re-analyzed, to pick | ||
| 2796 | // up on e.g. changed comptime decls. | ||
| 2797 | try pt.ensureNamespaceUpToDate(Type.fromInterned(new_ty).getNamespaceIndex(mod)); | ||
| 2798 | |||
| 2799 | try sema.declareDependency(.{ .interned = new_ty }); | ||
| 2800 | try sema.addTypeReferenceEntry(src, new_ty); | ||
| 2801 | return Air.internedToRef(new_ty); | ||
| 2814 | }, | 2802 | }, |
| 2815 | .wip => |wip| wip, | 2803 | .wip => |wip| wip, |
| 2816 | }); | 2804 | }); |
| ... | @@ -2828,6 +2816,7 @@ fn zirStructDecl( | ... | @@ -2828,6 +2816,7 @@ fn zirStructDecl( |
| 2828 | .parent = block.namespace.toOptional(), | 2816 | .parent = block.namespace.toOptional(), |
| 2829 | .owner_type = wip_ty.index, | 2817 | .owner_type = wip_ty.index, |
| 2830 | .file_scope = block.getFileScopeIndex(mod), | 2818 | .file_scope = block.getFileScopeIndex(mod), |
| 2819 | .generation = mod.generation, | ||
| 2831 | }); | 2820 | }); |
| 2832 | errdefer pt.destroyNamespace(new_namespace_index); | 2821 | errdefer pt.destroyNamespace(new_namespace_index); |
| 2833 | 2822 | ||
| ... | @@ -2850,8 +2839,8 @@ fn zirStructDecl( | ... | @@ -2850,8 +2839,8 @@ fn zirStructDecl( |
| 2850 | if (block.ownerModule().strip) break :codegen_type; | 2839 | if (block.ownerModule().strip) break :codegen_type; |
| 2851 | try mod.comp.queueJob(.{ .codegen_type = wip_ty.index }); | 2840 | try mod.comp.queueJob(.{ .codegen_type = wip_ty.index }); |
| 2852 | } | 2841 | } |
| 2853 | try sema.addReferenceEntry(src, AnalUnit.wrap(.{ .cau = new_cau_index })); | ||
| 2854 | try sema.declareDependency(.{ .interned = wip_ty.index }); | 2842 | try sema.declareDependency(.{ .interned = wip_ty.index }); |
| 2843 | try sema.addTypeReferenceEntry(src, wip_ty.index); | ||
| 2855 | return Air.internedToRef(wip_ty.finish(ip, new_cau_index.toOptional(), new_namespace_index)); | 2844 | return Air.internedToRef(wip_ty.finish(ip, new_cau_index.toOptional(), new_namespace_index)); |
| 2856 | } | 2845 | } |
| 2857 | 2846 | ||
| ... | @@ -2873,7 +2862,7 @@ fn createTypeName( | ... | @@ -2873,7 +2862,7 @@ fn createTypeName( |
| 2873 | .anon => {}, // handled after switch | 2862 | .anon => {}, // handled after switch |
| 2874 | .parent => return block.type_name_ctx, | 2863 | .parent => return block.type_name_ctx, |
| 2875 | .func => func_strat: { | 2864 | .func => func_strat: { |
| 2876 | const fn_info = sema.code.getFnInfo(ip.funcZirBodyInst(sema.func_index).resolve(ip)); | 2865 | const fn_info = sema.code.getFnInfo(ip.funcZirBodyInst(sema.func_index).resolve(ip) orelse return error.AnalysisFail); |
| 2877 | const zir_tags = sema.code.instructions.items(.tag); | 2866 | const zir_tags = sema.code.instructions.items(.tag); |
| 2878 | 2867 | ||
| 2879 | var buf: std.ArrayListUnmanaged(u8) = .{}; | 2868 | var buf: std.ArrayListUnmanaged(u8) = .{}; |
| ... | @@ -2966,7 +2955,6 @@ fn zirEnumDecl( | ... | @@ -2966,7 +2955,6 @@ fn zirEnumDecl( |
| 2966 | 2955 | ||
| 2967 | const tracked_inst = try block.trackZir(inst); | 2956 | const tracked_inst = try block.trackZir(inst); |
| 2968 | const src: LazySrcLoc = .{ .base_node_inst = tracked_inst, .offset = LazySrcLoc.Offset.nodeOffset(0) }; | 2957 | const src: LazySrcLoc = .{ .base_node_inst = tracked_inst, .offset = LazySrcLoc.Offset.nodeOffset(0) }; |
| 2969 | const tag_ty_src: LazySrcLoc = .{ .base_node_inst = tracked_inst, .offset = .{ .node_offset_container_tag = 0 } }; | ||
| 2970 | 2958 | ||
| 2971 | const tag_type_ref = if (small.has_tag_type) blk: { | 2959 | const tag_type_ref = if (small.has_tag_type) blk: { |
| 2972 | const tag_type_ref: Zir.Inst.Ref = @enumFromInt(sema.code.extra[extra_index]); | 2960 | const tag_type_ref: Zir.Inst.Ref = @enumFromInt(sema.code.extra[extra_index]); |
| ... | @@ -3029,10 +3017,17 @@ fn zirEnumDecl( | ... | @@ -3029,10 +3017,17 @@ fn zirEnumDecl( |
| 3029 | .captures = captures, | 3017 | .captures = captures, |
| 3030 | } }, | 3018 | } }, |
| 3031 | }; | 3019 | }; |
| 3032 | const wip_ty = sema.wrapWipTy(switch (try ip.getEnumType(gpa, pt.tid, enum_init)) { | 3020 | const wip_ty = sema.wrapWipTy(switch (try ip.getEnumType(gpa, pt.tid, enum_init, false)) { |
| 3033 | .existing => |ty| wip: { | 3021 | .existing => |ty| { |
| 3034 | if (!try sema.maybeRemoveOutdatedType(ty)) return Air.internedToRef(ty); | 3022 | const new_ty = try pt.ensureTypeUpToDate(ty, false); |
| 3035 | break :wip (try ip.getEnumType(gpa, pt.tid, enum_init)).wip; | 3023 | |
| 3024 | // Make sure we update the namespace if the declaration is re-analyzed, to pick | ||
| 3025 | // up on e.g. changed comptime decls. | ||
| 3026 | try pt.ensureNamespaceUpToDate(Type.fromInterned(new_ty).getNamespaceIndex(mod)); | ||
| 3027 | |||
| 3028 | try sema.declareDependency(.{ .interned = new_ty }); | ||
| 3029 | try sema.addTypeReferenceEntry(src, new_ty); | ||
| 3030 | return Air.internedToRef(new_ty); | ||
| 3036 | }, | 3031 | }, |
| 3037 | .wip => |wip| wip, | 3032 | .wip => |wip| wip, |
| 3038 | }); | 3033 | }); |
| ... | @@ -3056,167 +3051,38 @@ fn zirEnumDecl( | ... | @@ -3056,167 +3051,38 @@ fn zirEnumDecl( |
| 3056 | .parent = block.namespace.toOptional(), | 3051 | .parent = block.namespace.toOptional(), |
| 3057 | .owner_type = wip_ty.index, | 3052 | .owner_type = wip_ty.index, |
| 3058 | .file_scope = block.getFileScopeIndex(mod), | 3053 | .file_scope = block.getFileScopeIndex(mod), |
| 3054 | .generation = mod.generation, | ||
| 3059 | }); | 3055 | }); |
| 3060 | errdefer if (!done) pt.destroyNamespace(new_namespace_index); | 3056 | errdefer if (!done) pt.destroyNamespace(new_namespace_index); |
| 3061 | 3057 | ||
| 3062 | const new_cau_index = try ip.createTypeCau(gpa, pt.tid, tracked_inst, new_namespace_index, wip_ty.index); | 3058 | const new_cau_index = try ip.createTypeCau(gpa, pt.tid, tracked_inst, new_namespace_index, wip_ty.index); |
| 3063 | 3059 | ||
| 3064 | if (pt.zcu.comp.incremental) { | ||
| 3065 | try mod.intern_pool.addDependency( | ||
| 3066 | gpa, | ||
| 3067 | AnalUnit.wrap(.{ .cau = new_cau_index }), | ||
| 3068 | .{ .src_hash = try block.trackZir(inst) }, | ||
| 3069 | ); | ||
| 3070 | } | ||
| 3071 | |||
| 3072 | try pt.scanNamespace(new_namespace_index, decls); | 3060 | try pt.scanNamespace(new_namespace_index, decls); |
| 3073 | 3061 | ||
| 3074 | try sema.addReferenceEntry(src, AnalUnit.wrap(.{ .cau = new_cau_index })); | ||
| 3075 | try sema.declareDependency(.{ .interned = wip_ty.index }); | 3062 | try sema.declareDependency(.{ .interned = wip_ty.index }); |
| 3063 | try sema.addTypeReferenceEntry(src, wip_ty.index); | ||
| 3076 | 3064 | ||
| 3077 | // We've finished the initial construction of this type, and are about to perform analysis. | 3065 | // We've finished the initial construction of this type, and are about to perform analysis. |
| 3078 | // Set the Cau and namespace appropriately, and don't destroy anything on failure. | 3066 | // Set the Cau and namespace appropriately, and don't destroy anything on failure. |
| 3079 | wip_ty.prepare(ip, new_cau_index, new_namespace_index); | 3067 | wip_ty.prepare(ip, new_cau_index, new_namespace_index); |
| 3080 | done = true; | 3068 | done = true; |
| 3081 | 3069 | ||
| 3082 | const int_tag_ty = ty: { | 3070 | try Sema.resolveDeclaredEnum( |
| 3083 | // We create a block for the field type instructions because they | 3071 | pt, |
| 3084 | // may need to reference Decls from inside the enum namespace. | 3072 | wip_ty, |
| 3085 | // Within the field type, default value, and alignment expressions, the owner should be the enum's `Cau`. | 3073 | inst, |
| 3086 | 3074 | tracked_inst, | |
| 3087 | const prev_owner = sema.owner; | 3075 | new_namespace_index, |
| 3088 | sema.owner = AnalUnit.wrap(.{ .cau = new_cau_index }); | 3076 | type_name, |
| 3089 | defer sema.owner = prev_owner; | 3077 | new_cau_index, |
| 3090 | 3078 | small, | |
| 3091 | const prev_func_index = sema.func_index; | 3079 | body, |
| 3092 | sema.func_index = .none; | 3080 | tag_type_ref, |
| 3093 | defer sema.func_index = prev_func_index; | 3081 | any_values, |
| 3094 | 3082 | fields_len, | |
| 3095 | var enum_block: Block = .{ | 3083 | sema.code, |
| 3096 | .parent = null, | 3084 | body_end, |
| 3097 | .sema = sema, | 3085 | ); |
| 3098 | .namespace = new_namespace_index, | ||
| 3099 | .instructions = .{}, | ||
| 3100 | .inlining = null, | ||
| 3101 | .is_comptime = true, | ||
| 3102 | .src_base_inst = tracked_inst, | ||
| 3103 | .type_name_ctx = type_name, | ||
| 3104 | }; | ||
| 3105 | defer enum_block.instructions.deinit(sema.gpa); | ||
| 3106 | |||
| 3107 | if (body.len != 0) { | ||
| 3108 | _ = try sema.analyzeInlineBody(&enum_block, body, inst); | ||
| 3109 | } | ||
| 3110 | |||
| 3111 | if (tag_type_ref != .none) { | ||
| 3112 | const ty = try sema.resolveType(&enum_block, tag_ty_src, tag_type_ref); | ||
| 3113 | if (ty.zigTypeTag(mod) != .Int and ty.zigTypeTag(mod) != .ComptimeInt) { | ||
| 3114 | return sema.fail(&enum_block, tag_ty_src, "expected integer tag type, found '{}'", .{ty.fmt(pt)}); | ||
| 3115 | } | ||
| 3116 | break :ty ty; | ||
| 3117 | } else if (fields_len == 0) { | ||
| 3118 | break :ty try pt.intType(.unsigned, 0); | ||
| 3119 | } else { | ||
| 3120 | const bits = std.math.log2_int_ceil(usize, fields_len); | ||
| 3121 | break :ty try pt.intType(.unsigned, bits); | ||
| 3122 | } | ||
| 3123 | }; | ||
| 3124 | |||
| 3125 | wip_ty.setTagTy(ip, int_tag_ty.toIntern()); | ||
| 3126 | |||
| 3127 | if (small.nonexhaustive and int_tag_ty.toIntern() != .comptime_int_type) { | ||
| 3128 | if (fields_len > 1 and std.math.log2_int(u64, fields_len) == int_tag_ty.bitSize(pt)) { | ||
| 3129 | return sema.fail(block, src, "non-exhaustive enum specifies every value", .{}); | ||
| 3130 | } | ||
| 3131 | } | ||
| 3132 | |||
| 3133 | var bit_bag_index: usize = body_end; | ||
| 3134 | var cur_bit_bag: u32 = undefined; | ||
| 3135 | var field_i: u32 = 0; | ||
| 3136 | var last_tag_val: ?Value = null; | ||
| 3137 | while (field_i < fields_len) : (field_i += 1) { | ||
| 3138 | if (field_i % 32 == 0) { | ||
| 3139 | cur_bit_bag = sema.code.extra[bit_bag_index]; | ||
| 3140 | bit_bag_index += 1; | ||
| 3141 | } | ||
| 3142 | const has_tag_value = @as(u1, @truncate(cur_bit_bag)) != 0; | ||
| 3143 | cur_bit_bag >>= 1; | ||
| 3144 | |||
| 3145 | const field_name_index: Zir.NullTerminatedString = @enumFromInt(sema.code.extra[extra_index]); | ||
| 3146 | const field_name_zir = sema.code.nullTerminatedString(field_name_index); | ||
| 3147 | extra_index += 2; // field name, doc comment | ||
| 3148 | |||
| 3149 | const field_name = try mod.intern_pool.getOrPutString(gpa, pt.tid, field_name_zir, .no_embedded_nulls); | ||
| 3150 | |||
| 3151 | const value_src: LazySrcLoc = .{ | ||
| 3152 | .base_node_inst = tracked_inst, | ||
| 3153 | .offset = .{ .container_field_value = field_i }, | ||
| 3154 | }; | ||
| 3155 | |||
| 3156 | const tag_overflow = if (has_tag_value) overflow: { | ||
| 3157 | const tag_val_ref: Zir.Inst.Ref = @enumFromInt(sema.code.extra[extra_index]); | ||
| 3158 | extra_index += 1; | ||
| 3159 | const tag_inst = try sema.resolveInst(tag_val_ref); | ||
| 3160 | last_tag_val = try sema.resolveConstDefinedValue(block, .{ | ||
| 3161 | .base_node_inst = tracked_inst, | ||
| 3162 | .offset = .{ .container_field_name = field_i }, | ||
| 3163 | }, tag_inst, .{ | ||
| 3164 | .needed_comptime_reason = "enum tag value must be comptime-known", | ||
| 3165 | }); | ||
| 3166 | if (!(try sema.intFitsInType(last_tag_val.?, int_tag_ty, null))) break :overflow true; | ||
| 3167 | last_tag_val = try pt.getCoerced(last_tag_val.?, int_tag_ty); | ||
| 3168 | if (wip_ty.nextField(&mod.intern_pool, field_name, last_tag_val.?.toIntern())) |conflict| { | ||
| 3169 | assert(conflict.kind == .value); // AstGen validated names are unique | ||
| 3170 | const other_field_src: LazySrcLoc = .{ | ||
| 3171 | .base_node_inst = tracked_inst, | ||
| 3172 | .offset = .{ .container_field_value = conflict.prev_field_idx }, | ||
| 3173 | }; | ||
| 3174 | const msg = msg: { | ||
| 3175 | const msg = try sema.errMsg(value_src, "enum tag value {} already taken", .{last_tag_val.?.fmtValueSema(pt, sema)}); | ||
| 3176 | errdefer msg.destroy(gpa); | ||
| 3177 | try sema.errNote(other_field_src, msg, "other occurrence here", .{}); | ||
| 3178 | break :msg msg; | ||
| 3179 | }; | ||
| 3180 | return sema.failWithOwnedErrorMsg(block, msg); | ||
| 3181 | } | ||
| 3182 | break :overflow false; | ||
| 3183 | } else if (any_values) overflow: { | ||
| 3184 | var overflow: ?usize = null; | ||
| 3185 | last_tag_val = if (last_tag_val) |val| | ||
| 3186 | try sema.intAdd(val, try pt.intValue(int_tag_ty, 1), int_tag_ty, &overflow) | ||
| 3187 | else | ||
| 3188 | try pt.intValue(int_tag_ty, 0); | ||
| 3189 | if (overflow != null) break :overflow true; | ||
| 3190 | if (wip_ty.nextField(&mod.intern_pool, field_name, last_tag_val.?.toIntern())) |conflict| { | ||
| 3191 | assert(conflict.kind == .value); // AstGen validated names are unique | ||
| 3192 | const other_field_src: LazySrcLoc = .{ | ||
| 3193 | .base_node_inst = tracked_inst, | ||
| 3194 | .offset = .{ .container_field_value = conflict.prev_field_idx }, | ||
| 3195 | }; | ||
| 3196 | const msg = msg: { | ||
| 3197 | const msg = try sema.errMsg(value_src, "enum tag value {} already taken", .{last_tag_val.?.fmtValueSema(pt, sema)}); | ||
| 3198 | errdefer msg.destroy(gpa); | ||
| 3199 | try sema.errNote(other_field_src, msg, "other occurrence here", .{}); | ||
| 3200 | break :msg msg; | ||
| 3201 | }; | ||
| 3202 | return sema.failWithOwnedErrorMsg(block, msg); | ||
| 3203 | } | ||
| 3204 | break :overflow false; | ||
| 3205 | } else overflow: { | ||
| 3206 | assert(wip_ty.nextField(&mod.intern_pool, field_name, .none) == null); | ||
| 3207 | last_tag_val = try pt.intValue(Type.comptime_int, field_i); | ||
| 3208 | if (!try sema.intFitsInType(last_tag_val.?, int_tag_ty, null)) break :overflow true; | ||
| 3209 | last_tag_val = try pt.getCoerced(last_tag_val.?, int_tag_ty); | ||
| 3210 | break :overflow false; | ||
| 3211 | }; | ||
| 3212 | |||
| 3213 | if (tag_overflow) { | ||
| 3214 | const msg = try sema.errMsg(value_src, "enumeration value '{}' too large for type '{}'", .{ | ||
| 3215 | last_tag_val.?.fmtValueSema(pt, sema), int_tag_ty.fmt(pt), | ||
| 3216 | }); | ||
| 3217 | return sema.failWithOwnedErrorMsg(block, msg); | ||
| 3218 | } | ||
| 3219 | } | ||
| 3220 | 3086 | ||
| 3221 | codegen_type: { | 3087 | codegen_type: { |
| 3222 | if (mod.comp.config.use_llvm) break :codegen_type; | 3088 | if (mod.comp.config.use_llvm) break :codegen_type; |
| ... | @@ -3295,10 +3161,17 @@ fn zirUnionDecl( | ... | @@ -3295,10 +3161,17 @@ fn zirUnionDecl( |
| 3295 | .captures = captures, | 3161 | .captures = captures, |
| 3296 | } }, | 3162 | } }, |
| 3297 | }; | 3163 | }; |
| 3298 | const wip_ty = sema.wrapWipTy(switch (try ip.getUnionType(gpa, pt.tid, union_init)) { | 3164 | const wip_ty = sema.wrapWipTy(switch (try ip.getUnionType(gpa, pt.tid, union_init, false)) { |
| 3299 | .existing => |ty| wip: { | 3165 | .existing => |ty| { |
| 3300 | if (!try sema.maybeRemoveOutdatedType(ty)) return Air.internedToRef(ty); | 3166 | const new_ty = try pt.ensureTypeUpToDate(ty, false); |
| 3301 | break :wip (try ip.getUnionType(gpa, pt.tid, union_init)).wip; | 3167 | |
| 3168 | // Make sure we update the namespace if the declaration is re-analyzed, to pick | ||
| 3169 | // up on e.g. changed comptime decls. | ||
| 3170 | try pt.ensureNamespaceUpToDate(Type.fromInterned(new_ty).getNamespaceIndex(mod)); | ||
| 3171 | |||
| 3172 | try sema.declareDependency(.{ .interned = new_ty }); | ||
| 3173 | try sema.addTypeReferenceEntry(src, new_ty); | ||
| 3174 | return Air.internedToRef(new_ty); | ||
| 3302 | }, | 3175 | }, |
| 3303 | .wip => |wip| wip, | 3176 | .wip => |wip| wip, |
| 3304 | }); | 3177 | }); |
| ... | @@ -3316,6 +3189,7 @@ fn zirUnionDecl( | ... | @@ -3316,6 +3189,7 @@ fn zirUnionDecl( |
| 3316 | .parent = block.namespace.toOptional(), | 3189 | .parent = block.namespace.toOptional(), |
| 3317 | .owner_type = wip_ty.index, | 3190 | .owner_type = wip_ty.index, |
| 3318 | .file_scope = block.getFileScopeIndex(mod), | 3191 | .file_scope = block.getFileScopeIndex(mod), |
| 3192 | .generation = mod.generation, | ||
| 3319 | }); | 3193 | }); |
| 3320 | errdefer pt.destroyNamespace(new_namespace_index); | 3194 | errdefer pt.destroyNamespace(new_namespace_index); |
| 3321 | 3195 | ||
| ... | @@ -3325,7 +3199,7 @@ fn zirUnionDecl( | ... | @@ -3325,7 +3199,7 @@ fn zirUnionDecl( |
| 3325 | try mod.intern_pool.addDependency( | 3199 | try mod.intern_pool.addDependency( |
| 3326 | gpa, | 3200 | gpa, |
| 3327 | AnalUnit.wrap(.{ .cau = new_cau_index }), | 3201 | AnalUnit.wrap(.{ .cau = new_cau_index }), |
| 3328 | .{ .src_hash = try block.trackZir(inst) }, | 3202 | .{ .src_hash = tracked_inst }, |
| 3329 | ); | 3203 | ); |
| 3330 | } | 3204 | } |
| 3331 | 3205 | ||
| ... | @@ -3338,8 +3212,8 @@ fn zirUnionDecl( | ... | @@ -3338,8 +3212,8 @@ fn zirUnionDecl( |
| 3338 | if (block.ownerModule().strip) break :codegen_type; | 3212 | if (block.ownerModule().strip) break :codegen_type; |
| 3339 | try mod.comp.queueJob(.{ .codegen_type = wip_ty.index }); | 3213 | try mod.comp.queueJob(.{ .codegen_type = wip_ty.index }); |
| 3340 | } | 3214 | } |
| 3341 | try sema.addReferenceEntry(src, AnalUnit.wrap(.{ .cau = new_cau_index })); | ||
| 3342 | try sema.declareDependency(.{ .interned = wip_ty.index }); | 3215 | try sema.declareDependency(.{ .interned = wip_ty.index }); |
| 3216 | try sema.addTypeReferenceEntry(src, wip_ty.index); | ||
| 3343 | return Air.internedToRef(wip_ty.finish(ip, new_cau_index.toOptional(), new_namespace_index)); | 3217 | return Air.internedToRef(wip_ty.finish(ip, new_cau_index.toOptional(), new_namespace_index)); |
| 3344 | } | 3218 | } |
| 3345 | 3219 | ||
| ... | @@ -3387,8 +3261,15 @@ fn zirOpaqueDecl( | ... | @@ -3387,8 +3261,15 @@ fn zirOpaqueDecl( |
| 3387 | }; | 3261 | }; |
| 3388 | // No `wrapWipTy` needed as no std.builtin types are opaque. | 3262 | // No `wrapWipTy` needed as no std.builtin types are opaque. |
| 3389 | const wip_ty = switch (try ip.getOpaqueType(gpa, pt.tid, opaque_init)) { | 3263 | const wip_ty = switch (try ip.getOpaqueType(gpa, pt.tid, opaque_init)) { |
| 3390 | // No `maybeRemoveOutdatedType` as opaque types are never outdated. | 3264 | .existing => |ty| { |
| 3391 | .existing => |ty| return Air.internedToRef(ty), | 3265 | // Make sure we update the namespace if the declaration is re-analyzed, to pick |
| 3266 | // up on e.g. changed comptime decls. | ||
| 3267 | try pt.ensureNamespaceUpToDate(Type.fromInterned(ty).getNamespaceIndex(mod)); | ||
| 3268 | |||
| 3269 | try sema.declareDependency(.{ .interned = ty }); | ||
| 3270 | try sema.addTypeReferenceEntry(src, ty); | ||
| 3271 | return Air.internedToRef(ty); | ||
| 3272 | }, | ||
| 3392 | .wip => |wip| wip, | 3273 | .wip => |wip| wip, |
| 3393 | }; | 3274 | }; |
| 3394 | errdefer wip_ty.cancel(ip, pt.tid); | 3275 | errdefer wip_ty.cancel(ip, pt.tid); |
| ... | @@ -3405,6 +3286,7 @@ fn zirOpaqueDecl( | ... | @@ -3405,6 +3286,7 @@ fn zirOpaqueDecl( |
| 3405 | .parent = block.namespace.toOptional(), | 3286 | .parent = block.namespace.toOptional(), |
| 3406 | .owner_type = wip_ty.index, | 3287 | .owner_type = wip_ty.index, |
| 3407 | .file_scope = block.getFileScopeIndex(mod), | 3288 | .file_scope = block.getFileScopeIndex(mod), |
| 3289 | .generation = mod.generation, | ||
| 3408 | }); | 3290 | }); |
| 3409 | errdefer pt.destroyNamespace(new_namespace_index); | 3291 | errdefer pt.destroyNamespace(new_namespace_index); |
| 3410 | 3292 | ||
| ... | @@ -3416,6 +3298,7 @@ fn zirOpaqueDecl( | ... | @@ -3416,6 +3298,7 @@ fn zirOpaqueDecl( |
| 3416 | if (block.ownerModule().strip) break :codegen_type; | 3298 | if (block.ownerModule().strip) break :codegen_type; |
| 3417 | try mod.comp.queueJob(.{ .codegen_type = wip_ty.index }); | 3299 | try mod.comp.queueJob(.{ .codegen_type = wip_ty.index }); |
| 3418 | } | 3300 | } |
| 3301 | try sema.addTypeReferenceEntry(src, wip_ty.index); | ||
| 3419 | return Air.internedToRef(wip_ty.finish(ip, .none, new_namespace_index)); | 3302 | return Air.internedToRef(wip_ty.finish(ip, .none, new_namespace_index)); |
| 3420 | } | 3303 | } |
| 3421 | 3304 | ||
| ... | @@ -5487,7 +5370,7 @@ fn failWithBadMemberAccess( | ... | @@ -5487,7 +5370,7 @@ fn failWithBadMemberAccess( |
| 5487 | .Enum => "enum", | 5370 | .Enum => "enum", |
| 5488 | else => unreachable, | 5371 | else => unreachable, |
| 5489 | }; | 5372 | }; |
| 5490 | if (agg_ty.typeDeclInst(zcu)) |inst| if (inst.resolve(ip) == .main_struct_inst) { | 5373 | if (agg_ty.typeDeclInst(zcu)) |inst| if ((inst.resolve(ip) orelse return error.AnalysisFail) == .main_struct_inst) { |
| 5491 | return sema.fail(block, field_src, "root struct of file '{}' has no member named '{}'", .{ | 5374 | return sema.fail(block, field_src, "root struct of file '{}' has no member named '{}'", .{ |
| 5492 | agg_ty.fmt(pt), field_name.fmt(ip), | 5375 | agg_ty.fmt(pt), field_name.fmt(ip), |
| 5493 | }); | 5376 | }); |
| ... | @@ -6041,15 +5924,17 @@ fn zirCImport(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileEr | ... | @@ -6041,15 +5924,17 @@ fn zirCImport(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileEr |
| 6041 | return sema.fail(&child_block, src, "C import failed: {s}", .{@errorName(err)}); | 5924 | return sema.fail(&child_block, src, "C import failed: {s}", .{@errorName(err)}); |
| 6042 | 5925 | ||
| 6043 | const path_digest = zcu.filePathDigest(result.file_index); | 5926 | const path_digest = zcu.filePathDigest(result.file_index); |
| 6044 | const old_root_type = zcu.fileRootType(result.file_index); | 5927 | pt.astGenFile(result.file, path_digest) catch |err| |
| 6045 | pt.astGenFile(result.file, path_digest, old_root_type) catch |err| | ||
| 6046 | return sema.fail(&child_block, src, "C import failed: {s}", .{@errorName(err)}); | 5928 | return sema.fail(&child_block, src, "C import failed: {s}", .{@errorName(err)}); |
| 6047 | 5929 | ||
| 6048 | // TODO: register some kind of dependency on the file. | 5930 | // TODO: register some kind of dependency on the file. |
| 6049 | // That way, if this returns `error.AnalysisFail`, we have the dependency banked ready to | 5931 | // That way, if this returns `error.AnalysisFail`, we have the dependency banked ready to |
| 6050 | // trigger re-analysis later. | 5932 | // trigger re-analysis later. |
| 6051 | try pt.ensureFileAnalyzed(result.file_index); | 5933 | try pt.ensureFileAnalyzed(result.file_index); |
| 6052 | return Air.internedToRef(zcu.fileRootType(result.file_index)); | 5934 | const ty = zcu.fileRootType(result.file_index); |
| 5935 | try sema.declareDependency(.{ .interned = ty }); | ||
| 5936 | try sema.addTypeReferenceEntry(src, ty); | ||
| 5937 | return Air.internedToRef(ty); | ||
| 6053 | } | 5938 | } |
| 6054 | 5939 | ||
| 6055 | fn zirSuspendBlock(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { | 5940 | fn zirSuspendBlock(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| ... | @@ -6797,12 +6682,21 @@ fn lookupInNamespace( | ... | @@ -6797,12 +6682,21 @@ fn lookupInNamespace( |
| 6797 | const zcu = pt.zcu; | 6682 | const zcu = pt.zcu; |
| 6798 | const ip = &zcu.intern_pool; | 6683 | const ip = &zcu.intern_pool; |
| 6799 | 6684 | ||
| 6685 | try pt.ensureNamespaceUpToDate(namespace_index); | ||
| 6686 | |||
| 6800 | const namespace = zcu.namespacePtr(namespace_index); | 6687 | const namespace = zcu.namespacePtr(namespace_index); |
| 6801 | 6688 | ||
| 6802 | const adapter: Zcu.Namespace.NameAdapter = .{ .zcu = zcu }; | 6689 | const adapter: Zcu.Namespace.NameAdapter = .{ .zcu = zcu }; |
| 6803 | 6690 | ||
| 6804 | const src_file = zcu.namespacePtr(block.namespace).file_scope; | 6691 | const src_file = zcu.namespacePtr(block.namespace).file_scope; |
| 6805 | 6692 | ||
| 6693 | if (Type.fromInterned(namespace.owner_type).typeDeclInst(zcu)) |type_decl_inst| { | ||
| 6694 | try sema.declareDependency(.{ .namespace_name = .{ | ||
| 6695 | .namespace = type_decl_inst, | ||
| 6696 | .name = ident_name, | ||
| 6697 | } }); | ||
| 6698 | } | ||
| 6699 | |||
| 6806 | if (observe_usingnamespace and (namespace.pub_usingnamespace.items.len != 0 or namespace.priv_usingnamespace.items.len != 0)) { | 6700 | if (observe_usingnamespace and (namespace.pub_usingnamespace.items.len != 0 or namespace.priv_usingnamespace.items.len != 0)) { |
| 6807 | const gpa = sema.gpa; | 6701 | const gpa = sema.gpa; |
| 6808 | var checked_namespaces: std.AutoArrayHashMapUnmanaged(*Namespace, void) = .{}; | 6702 | var checked_namespaces: std.AutoArrayHashMapUnmanaged(*Namespace, void) = .{}; |
| ... | @@ -7528,14 +7422,14 @@ fn analyzeCall( | ... | @@ -7528,14 +7422,14 @@ fn analyzeCall( |
| 7528 | operation: CallOperation, | 7422 | operation: CallOperation, |
| 7529 | ) CompileError!Air.Inst.Ref { | 7423 | ) CompileError!Air.Inst.Ref { |
| 7530 | const pt = sema.pt; | 7424 | const pt = sema.pt; |
| 7531 | const mod = pt.zcu; | 7425 | const zcu = pt.zcu; |
| 7532 | const ip = &mod.intern_pool; | 7426 | const ip = &zcu.intern_pool; |
| 7533 | 7427 | ||
| 7534 | const callee_ty = sema.typeOf(func); | 7428 | const callee_ty = sema.typeOf(func); |
| 7535 | const func_ty_info = mod.typeToFunc(func_ty).?; | 7429 | const func_ty_info = zcu.typeToFunc(func_ty).?; |
| 7536 | const cc = func_ty_info.cc; | 7430 | const cc = func_ty_info.cc; |
| 7537 | if (try sema.resolveValue(func)) |func_val| | 7431 | if (try sema.resolveValue(func)) |func_val| |
| 7538 | if (func_val.isUndef(mod)) | 7432 | if (func_val.isUndef(zcu)) |
| 7539 | return sema.failWithUseOfUndef(block, call_src); | 7433 | return sema.failWithUseOfUndef(block, call_src); |
| 7540 | if (cc == .Naked) { | 7434 | if (cc == .Naked) { |
| 7541 | const maybe_func_inst = try sema.funcDeclSrcInst(func); | 7435 | const maybe_func_inst = try sema.funcDeclSrcInst(func); |
| ... | @@ -7647,7 +7541,7 @@ fn analyzeCall( | ... | @@ -7647,7 +7541,7 @@ fn analyzeCall( |
| 7647 | .needed_comptime_reason = "function being called at comptime must be comptime-known", | 7541 | .needed_comptime_reason = "function being called at comptime must be comptime-known", |
| 7648 | .block_comptime_reason = comptime_reason, | 7542 | .block_comptime_reason = comptime_reason, |
| 7649 | }); | 7543 | }); |
| 7650 | const module_fn_index = switch (mod.intern_pool.indexToKey(func_val.toIntern())) { | 7544 | const module_fn_index = switch (zcu.intern_pool.indexToKey(func_val.toIntern())) { |
| 7651 | .@"extern" => return sema.fail(block, call_src, "{s} call of extern function", .{ | 7545 | .@"extern" => return sema.fail(block, call_src, "{s} call of extern function", .{ |
| 7652 | @as([]const u8, if (is_comptime_call) "comptime" else "inline"), | 7546 | @as([]const u8, if (is_comptime_call) "comptime" else "inline"), |
| 7653 | }), | 7547 | }), |
| ... | @@ -7664,7 +7558,7 @@ fn analyzeCall( | ... | @@ -7664,7 +7558,7 @@ fn analyzeCall( |
| 7664 | }, | 7558 | }, |
| 7665 | else => {}, | 7559 | else => {}, |
| 7666 | } | 7560 | } |
| 7667 | assert(callee_ty.isPtrAtRuntime(mod)); | 7561 | assert(callee_ty.isPtrAtRuntime(zcu)); |
| 7668 | return sema.fail(block, call_src, "{s} call of function pointer", .{ | 7562 | return sema.fail(block, call_src, "{s} call of function pointer", .{ |
| 7669 | if (is_comptime_call) "comptime" else "inline", | 7563 | if (is_comptime_call) "comptime" else "inline", |
| 7670 | }); | 7564 | }); |
| ... | @@ -7704,7 +7598,7 @@ fn analyzeCall( | ... | @@ -7704,7 +7598,7 @@ fn analyzeCall( |
| 7704 | }, | 7598 | }, |
| 7705 | }; | 7599 | }; |
| 7706 | 7600 | ||
| 7707 | const module_fn = mod.funcInfo(module_fn_index); | 7601 | const module_fn = zcu.funcInfo(module_fn_index); |
| 7708 | 7602 | ||
| 7709 | // This is not a function instance, so the function's `Nav` has a | 7603 | // This is not a function instance, so the function's `Nav` has a |
| 7710 | // `Cau` -- we don't need to check `generic_owner`. | 7604 | // `Cau` -- we don't need to check `generic_owner`. |
| ... | @@ -7718,7 +7612,7 @@ fn analyzeCall( | ... | @@ -7718,7 +7612,7 @@ fn analyzeCall( |
| 7718 | // whenever performing an operation where the difference matters. | 7612 | // whenever performing an operation where the difference matters. |
| 7719 | var ics = InlineCallSema.init( | 7613 | var ics = InlineCallSema.init( |
| 7720 | sema, | 7614 | sema, |
| 7721 | mod.cauFileScope(fn_cau_index).zir, | 7615 | zcu.cauFileScope(fn_cau_index).zir, |
| 7722 | module_fn_index, | 7616 | module_fn_index, |
| 7723 | block.error_return_trace_index, | 7617 | block.error_return_trace_index, |
| 7724 | ); | 7618 | ); |
| ... | @@ -7752,13 +7646,16 @@ fn analyzeCall( | ... | @@ -7752,13 +7646,16 @@ fn analyzeCall( |
| 7752 | 7646 | ||
| 7753 | // Whether this call should be memoized, set to false if the call can | 7647 | // Whether this call should be memoized, set to false if the call can |
| 7754 | // mutate comptime state. | 7648 | // mutate comptime state. |
| 7755 | var should_memoize = true; | 7649 | // TODO: comptime call memoization is currently not supported under incremental compilation |
| 7650 | // since dependencies are not marked on callers. If we want to keep this around (we should | ||
| 7651 | // check that it's worthwhile first!), each memoized call needs a `Cau`. | ||
| 7652 | var should_memoize = !zcu.comp.incremental; | ||
| 7756 | 7653 | ||
| 7757 | // If it's a comptime function call, we need to memoize it as long as no external | 7654 | // If it's a comptime function call, we need to memoize it as long as no external |
| 7758 | // comptime memory is mutated. | 7655 | // comptime memory is mutated. |
| 7759 | const memoized_arg_values = try sema.arena.alloc(InternPool.Index, func_ty_info.param_types.len); | 7656 | const memoized_arg_values = try sema.arena.alloc(InternPool.Index, func_ty_info.param_types.len); |
| 7760 | 7657 | ||
| 7761 | const owner_info = mod.typeToFunc(Type.fromInterned(module_fn.ty)).?; | 7658 | const owner_info = zcu.typeToFunc(Type.fromInterned(module_fn.ty)).?; |
| 7762 | const new_param_types = try sema.arena.alloc(InternPool.Index, owner_info.param_types.len); | 7659 | const new_param_types = try sema.arena.alloc(InternPool.Index, owner_info.param_types.len); |
| 7763 | var new_fn_info: InternPool.GetFuncTypeKey = .{ | 7660 | var new_fn_info: InternPool.GetFuncTypeKey = .{ |
| 7764 | .param_types = new_param_types, | 7661 | .param_types = new_param_types, |
| ... | @@ -7778,7 +7675,7 @@ fn analyzeCall( | ... | @@ -7778,7 +7675,7 @@ fn analyzeCall( |
| 7778 | // the AIR instructions of the callsite. The callee could be a generic function | 7675 | // the AIR instructions of the callsite. The callee could be a generic function |
| 7779 | // which means its parameter type expressions must be resolved in order and used | 7676 | // which means its parameter type expressions must be resolved in order and used |
| 7780 | // to successively coerce the arguments. | 7677 | // to successively coerce the arguments. |
| 7781 | const fn_info = ics.callee().code.getFnInfo(module_fn.zir_body_inst.resolve(ip)); | 7678 | const fn_info = ics.callee().code.getFnInfo(module_fn.zir_body_inst.resolve(ip) orelse return error.AnalysisFail); |
| 7782 | try ics.callee().inst_map.ensureSpaceForInstructions(gpa, fn_info.param_body); | 7679 | try ics.callee().inst_map.ensureSpaceForInstructions(gpa, fn_info.param_body); |
| 7783 | 7680 | ||
| 7784 | var arg_i: u32 = 0; | 7681 | var arg_i: u32 = 0; |
| ... | @@ -7823,7 +7720,7 @@ fn analyzeCall( | ... | @@ -7823,7 +7720,7 @@ fn analyzeCall( |
| 7823 | // each of the parameters, resolving the return type and providing it to the child | 7720 | // each of the parameters, resolving the return type and providing it to the child |
| 7824 | // `Sema` so that it can be used for the `ret_ptr` instruction. | 7721 | // `Sema` so that it can be used for the `ret_ptr` instruction. |
| 7825 | const ret_ty_inst = if (fn_info.ret_ty_body.len != 0) | 7722 | const ret_ty_inst = if (fn_info.ret_ty_body.len != 0) |
| 7826 | try sema.resolveInlineBody(&child_block, fn_info.ret_ty_body, module_fn.zir_body_inst.resolve(ip)) | 7723 | try sema.resolveInlineBody(&child_block, fn_info.ret_ty_body, module_fn.zir_body_inst.resolve(ip) orelse return error.AnalysisFail) |
| 7827 | else | 7724 | else |
| 7828 | try sema.resolveInst(fn_info.ret_ty_ref); | 7725 | try sema.resolveInst(fn_info.ret_ty_ref); |
| 7829 | const ret_ty_src: LazySrcLoc = .{ .base_node_inst = module_fn.zir_body_inst, .offset = .{ .node_offset_fn_type_ret_ty = 0 } }; | 7726 | const ret_ty_src: LazySrcLoc = .{ .base_node_inst = module_fn.zir_body_inst, .offset = .{ .node_offset_fn_type_ret_ty = 0 } }; |
| ... | @@ -7843,12 +7740,12 @@ fn analyzeCall( | ... | @@ -7843,12 +7740,12 @@ fn analyzeCall( |
| 7843 | // bug generating invalid LLVM IR. | 7740 | // bug generating invalid LLVM IR. |
| 7844 | const res2: Air.Inst.Ref = res2: { | 7741 | const res2: Air.Inst.Ref = res2: { |
| 7845 | if (should_memoize and is_comptime_call) { | 7742 | if (should_memoize and is_comptime_call) { |
| 7846 | if (mod.intern_pool.getIfExists(.{ .memoized_call = .{ | 7743 | if (zcu.intern_pool.getIfExists(.{ .memoized_call = .{ |
| 7847 | .func = module_fn_index, | 7744 | .func = module_fn_index, |
| 7848 | .arg_values = memoized_arg_values, | 7745 | .arg_values = memoized_arg_values, |
| 7849 | .result = .none, | 7746 | .result = .none, |
| 7850 | } })) |memoized_call_index| { | 7747 | } })) |memoized_call_index| { |
| 7851 | const memoized_call = mod.intern_pool.indexToKey(memoized_call_index).memoized_call; | 7748 | const memoized_call = zcu.intern_pool.indexToKey(memoized_call_index).memoized_call; |
| 7852 | break :res2 Air.internedToRef(memoized_call.result); | 7749 | break :res2 Air.internedToRef(memoized_call.result); |
| 7853 | } | 7750 | } |
| 7854 | } | 7751 | } |
| ... | @@ -7907,7 +7804,7 @@ fn analyzeCall( | ... | @@ -7907,7 +7804,7 @@ fn analyzeCall( |
| 7907 | // a reference to `comptime_allocs` so is not stable across instances of `Sema`. | 7804 | // a reference to `comptime_allocs` so is not stable across instances of `Sema`. |
| 7908 | // TODO: check whether any external comptime memory was mutated by the | 7805 | // TODO: check whether any external comptime memory was mutated by the |
| 7909 | // comptime function call. If so, then do not memoize the call here. | 7806 | // comptime function call. If so, then do not memoize the call here. |
| 7910 | if (should_memoize and !Value.fromInterned(result_interned).canMutateComptimeVarState(mod)) { | 7807 | if (should_memoize and !Value.fromInterned(result_interned).canMutateComptimeVarState(zcu)) { |
| 7911 | _ = try pt.intern(.{ .memoized_call = .{ | 7808 | _ = try pt.intern(.{ .memoized_call = .{ |
| 7912 | .func = module_fn_index, | 7809 | .func = module_fn_index, |
| 7913 | .arg_values = memoized_arg_values, | 7810 | .arg_values = memoized_arg_values, |
| ... | @@ -7946,7 +7843,7 @@ fn analyzeCall( | ... | @@ -7946,7 +7843,7 @@ fn analyzeCall( |
| 7946 | if (param_ty) |t| assert(!t.isGenericPoison()); | 7843 | if (param_ty) |t| assert(!t.isGenericPoison()); |
| 7947 | arg_out.* = try args_info.analyzeArg(sema, block, arg_idx, param_ty, func_ty_info, func); | 7844 | arg_out.* = try args_info.analyzeArg(sema, block, arg_idx, param_ty, func_ty_info, func); |
| 7948 | try sema.validateRuntimeValue(block, args_info.argSrc(block, arg_idx), arg_out.*); | 7845 | try sema.validateRuntimeValue(block, args_info.argSrc(block, arg_idx), arg_out.*); |
| 7949 | if (sema.typeOf(arg_out.*).zigTypeTag(mod) == .NoReturn) { | 7846 | if (sema.typeOf(arg_out.*).zigTypeTag(zcu) == .NoReturn) { |
| 7950 | return arg_out.*; | 7847 | return arg_out.*; |
| 7951 | } | 7848 | } |
| 7952 | } | 7849 | } |
| ... | @@ -7955,15 +7852,15 @@ fn analyzeCall( | ... | @@ -7955,15 +7852,15 @@ fn analyzeCall( |
| 7955 | 7852 | ||
| 7956 | switch (sema.owner.unwrap()) { | 7853 | switch (sema.owner.unwrap()) { |
| 7957 | .cau => {}, | 7854 | .cau => {}, |
| 7958 | .func => |owner_func| if (Type.fromInterned(func_ty_info.return_type).isError(mod)) { | 7855 | .func => |owner_func| if (Type.fromInterned(func_ty_info.return_type).isError(zcu)) { |
| 7959 | ip.funcSetCallsOrAwaitsErrorableFn(owner_func); | 7856 | ip.funcSetCallsOrAwaitsErrorableFn(owner_func); |
| 7960 | }, | 7857 | }, |
| 7961 | } | 7858 | } |
| 7962 | 7859 | ||
| 7963 | if (try sema.resolveValue(func)) |func_val| { | 7860 | if (try sema.resolveValue(func)) |func_val| { |
| 7964 | if (mod.intern_pool.isFuncBody(func_val.toIntern())) { | 7861 | if (zcu.intern_pool.isFuncBody(func_val.toIntern())) { |
| 7965 | try sema.addReferenceEntry(call_src, AnalUnit.wrap(.{ .func = func_val.toIntern() })); | 7862 | try sema.addReferenceEntry(call_src, AnalUnit.wrap(.{ .func = func_val.toIntern() })); |
| 7966 | try mod.ensureFuncBodyAnalysisQueued(func_val.toIntern()); | 7863 | try zcu.ensureFuncBodyAnalysisQueued(func_val.toIntern()); |
| 7967 | } | 7864 | } |
| 7968 | } | 7865 | } |
| 7969 | 7866 | ||
| ... | @@ -7990,7 +7887,7 @@ fn analyzeCall( | ... | @@ -7990,7 +7887,7 @@ fn analyzeCall( |
| 7990 | // Function pointers and extern functions aren't guaranteed to | 7887 | // Function pointers and extern functions aren't guaranteed to |
| 7991 | // actually be noreturn so we add a safety check for them. | 7888 | // actually be noreturn so we add a safety check for them. |
| 7992 | if (try sema.resolveValue(func)) |func_val| { | 7889 | if (try sema.resolveValue(func)) |func_val| { |
| 7993 | switch (mod.intern_pool.indexToKey(func_val.toIntern())) { | 7890 | switch (zcu.intern_pool.indexToKey(func_val.toIntern())) { |
| 7994 | .func => break :skip_safety, | 7891 | .func => break :skip_safety, |
| 7995 | .ptr => |ptr| if (ptr.byte_offset == 0) switch (ptr.base_addr) { | 7892 | .ptr => |ptr| if (ptr.byte_offset == 0) switch (ptr.base_addr) { |
| 7996 | .nav => |nav| if (!ip.getNav(nav).isExtern(ip)) break :skip_safety, | 7893 | .nav => |nav| if (!ip.getNav(nav).isExtern(ip)) break :skip_safety, |
| ... | @@ -8210,7 +8107,7 @@ fn instantiateGenericCall( | ... | @@ -8210,7 +8107,7 @@ fn instantiateGenericCall( |
| 8210 | const fn_nav = ip.getNav(generic_owner_func.owner_nav); | 8107 | const fn_nav = ip.getNav(generic_owner_func.owner_nav); |
| 8211 | const fn_cau = ip.getCau(fn_nav.analysis_owner.unwrap().?); | 8108 | const fn_cau = ip.getCau(fn_nav.analysis_owner.unwrap().?); |
| 8212 | const fn_zir = zcu.namespacePtr(fn_cau.namespace).fileScope(zcu).zir; | 8109 | const fn_zir = zcu.namespacePtr(fn_cau.namespace).fileScope(zcu).zir; |
| 8213 | const fn_info = fn_zir.getFnInfo(generic_owner_func.zir_body_inst.resolve(ip)); | 8110 | const fn_info = fn_zir.getFnInfo(generic_owner_func.zir_body_inst.resolve(ip) orelse return error.AnalysisFail); |
| 8214 | 8111 | ||
| 8215 | const comptime_args = try sema.arena.alloc(InternPool.Index, args_info.count()); | 8112 | const comptime_args = try sema.arena.alloc(InternPool.Index, args_info.count()); |
| 8216 | @memset(comptime_args, .none); | 8113 | @memset(comptime_args, .none); |
| ... | @@ -9416,7 +9313,7 @@ fn zirFunc( | ... | @@ -9416,7 +9313,7 @@ fn zirFunc( |
| 9416 | break :cau generic_owner_nav.analysis_owner.unwrap().?; | 9313 | break :cau generic_owner_nav.analysis_owner.unwrap().?; |
| 9417 | } else sema.owner.unwrap().cau; | 9314 | } else sema.owner.unwrap().cau; |
| 9418 | const fn_is_exported = exported: { | 9315 | const fn_is_exported = exported: { |
| 9419 | const decl_inst = ip.getCau(func_decl_cau).zir_index.resolve(ip); | 9316 | const decl_inst = ip.getCau(func_decl_cau).zir_index.resolve(ip) orelse return error.AnalysisFail; |
| 9420 | const zir_decl = sema.code.getDeclaration(decl_inst)[0]; | 9317 | const zir_decl = sema.code.getDeclaration(decl_inst)[0]; |
| 9421 | break :exported zir_decl.flags.is_export; | 9318 | break :exported zir_decl.flags.is_export; |
| 9422 | }; | 9319 | }; |
| ... | @@ -13964,12 +13861,6 @@ fn zirHasDecl(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air | ... | @@ -13964,12 +13861,6 @@ fn zirHasDecl(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air |
| 13964 | }); | 13861 | }); |
| 13965 | 13862 | ||
| 13966 | try sema.checkNamespaceType(block, lhs_src, container_type); | 13863 | try sema.checkNamespaceType(block, lhs_src, container_type); |
| 13967 | if (container_type.typeDeclInst(mod)) |type_decl_inst| { | ||
| 13968 | try sema.declareDependency(.{ .namespace_name = .{ | ||
| 13969 | .namespace = type_decl_inst, | ||
| 13970 | .name = decl_name, | ||
| 13971 | } }); | ||
| 13972 | } | ||
| 13973 | 13864 | ||
| 13974 | const namespace = container_type.getNamespace(mod).unwrap() orelse return .bool_false; | 13865 | const namespace = container_type.getNamespace(mod).unwrap() orelse return .bool_false; |
| 13975 | if (try sema.lookupInNamespace(block, src, namespace, decl_name, true)) |lookup| { | 13866 | if (try sema.lookupInNamespace(block, src, namespace, decl_name, true)) |lookup| { |
| ... | @@ -14009,7 +13900,10 @@ fn zirImport(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air. | ... | @@ -14009,7 +13900,10 @@ fn zirImport(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air. |
| 14009 | // That way, if this returns `error.AnalysisFail`, we have the dependency banked ready to | 13900 | // That way, if this returns `error.AnalysisFail`, we have the dependency banked ready to |
| 14010 | // trigger re-analysis later. | 13901 | // trigger re-analysis later. |
| 14011 | try pt.ensureFileAnalyzed(result.file_index); | 13902 | try pt.ensureFileAnalyzed(result.file_index); |
| 14012 | return Air.internedToRef(zcu.fileRootType(result.file_index)); | 13903 | const ty = zcu.fileRootType(result.file_index); |
| 13904 | try sema.declareDependency(.{ .interned = ty }); | ||
| 13905 | try sema.addTypeReferenceEntry(operand_src, ty); | ||
| 13906 | return Air.internedToRef(ty); | ||
| 14013 | } | 13907 | } |
| 14014 | 13908 | ||
| 14015 | fn zirEmbedFile(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { | 13909 | fn zirEmbedFile(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| ... | @@ -17673,7 +17567,13 @@ fn zirThis( | ... | @@ -17673,7 +17567,13 @@ fn zirThis( |
| 17673 | _ = extended; | 17567 | _ = extended; |
| 17674 | const pt = sema.pt; | 17568 | const pt = sema.pt; |
| 17675 | const namespace = pt.zcu.namespacePtr(block.namespace); | 17569 | const namespace = pt.zcu.namespacePtr(block.namespace); |
| 17676 | return Air.internedToRef(namespace.owner_type); | 17570 | const new_ty = try pt.ensureTypeUpToDate(namespace.owner_type, false); |
| 17571 | switch (pt.zcu.intern_pool.indexToKey(new_ty)) { | ||
| 17572 | .struct_type, .union_type, .enum_type => try sema.declareDependency(.{ .interned = new_ty }), | ||
| 17573 | .opaque_type => {}, | ||
| 17574 | else => unreachable, | ||
| 17575 | } | ||
| 17576 | return Air.internedToRef(new_ty); | ||
| 17677 | } | 17577 | } |
| 17678 | 17578 | ||
| 17679 | fn zirClosureGet(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!Air.Inst.Ref { | 17579 | fn zirClosureGet(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!Air.Inst.Ref { |
| ... | @@ -17698,7 +17598,7 @@ fn zirClosureGet(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstDat | ... | @@ -17698,7 +17598,7 @@ fn zirClosureGet(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstDat |
| 17698 | const msg = msg: { | 17598 | const msg = msg: { |
| 17699 | const name = name: { | 17599 | const name = name: { |
| 17700 | // TODO: we should probably store this name in the ZIR to avoid this complexity. | 17600 | // TODO: we should probably store this name in the ZIR to avoid this complexity. |
| 17701 | const file, const src_base_node = Module.LazySrcLoc.resolveBaseNode(block.src_base_inst, mod); | 17601 | const file, const src_base_node = Module.LazySrcLoc.resolveBaseNode(block.src_base_inst, mod).?; |
| 17702 | const tree = file.getTree(sema.gpa) catch |err| { | 17602 | const tree = file.getTree(sema.gpa) catch |err| { |
| 17703 | // In this case we emit a warning + a less precise source location. | 17603 | // In this case we emit a warning + a less precise source location. |
| 17704 | log.warn("unable to load {s}: {s}", .{ | 17604 | log.warn("unable to load {s}: {s}", .{ |
| ... | @@ -17726,7 +17626,7 @@ fn zirClosureGet(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstDat | ... | @@ -17726,7 +17626,7 @@ fn zirClosureGet(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstDat |
| 17726 | if (!block.is_typeof and !block.is_comptime and sema.func_index != .none) { | 17626 | if (!block.is_typeof and !block.is_comptime and sema.func_index != .none) { |
| 17727 | const msg = msg: { | 17627 | const msg = msg: { |
| 17728 | const name = name: { | 17628 | const name = name: { |
| 17729 | const file, const src_base_node = Module.LazySrcLoc.resolveBaseNode(block.src_base_inst, mod); | 17629 | const file, const src_base_node = Module.LazySrcLoc.resolveBaseNode(block.src_base_inst, mod).?; |
| 17730 | const tree = file.getTree(sema.gpa) catch |err| { | 17630 | const tree = file.getTree(sema.gpa) catch |err| { |
| 17731 | // In this case we emit a warning + a less precise source location. | 17631 | // In this case we emit a warning + a less precise source location. |
| 17732 | log.warn("unable to load {s}: {s}", .{ | 17632 | log.warn("unable to load {s}: {s}", .{ |
| ... | @@ -18975,6 +18875,7 @@ fn typeInfoNamespaceDecls( | ... | @@ -18975,6 +18875,7 @@ fn typeInfoNamespaceDecls( |
| 18975 | const ip = &zcu.intern_pool; | 18875 | const ip = &zcu.intern_pool; |
| 18976 | 18876 | ||
| 18977 | const namespace_index = opt_namespace_index.unwrap() orelse return; | 18877 | const namespace_index = opt_namespace_index.unwrap() orelse return; |
| 18878 | try pt.ensureNamespaceUpToDate(namespace_index); | ||
| 18978 | const namespace = zcu.namespacePtr(namespace_index); | 18879 | const namespace = zcu.namespacePtr(namespace_index); |
| 18979 | 18880 | ||
| 18980 | const gop = try seen_namespaces.getOrPut(namespace); | 18881 | const gop = try seen_namespaces.getOrPut(namespace); |
| ... | @@ -21821,7 +21722,10 @@ fn zirReify( | ... | @@ -21821,7 +21722,10 @@ fn zirReify( |
| 21821 | .zir_index = try block.trackZir(inst), | 21722 | .zir_index = try block.trackZir(inst), |
| 21822 | } }, | 21723 | } }, |
| 21823 | })) { | 21724 | })) { |
| 21824 | .existing => |ty| return Air.internedToRef(ty), | 21725 | .existing => |ty| { |
| 21726 | try sema.addTypeReferenceEntry(src, ty); | ||
| 21727 | return Air.internedToRef(ty); | ||
| 21728 | }, | ||
| 21825 | .wip => |wip| wip, | 21729 | .wip => |wip| wip, |
| 21826 | }; | 21730 | }; |
| 21827 | errdefer wip_ty.cancel(ip, pt.tid); | 21731 | errdefer wip_ty.cancel(ip, pt.tid); |
| ... | @@ -21838,8 +21742,10 @@ fn zirReify( | ... | @@ -21838,8 +21742,10 @@ fn zirReify( |
| 21838 | .parent = block.namespace.toOptional(), | 21742 | .parent = block.namespace.toOptional(), |
| 21839 | .owner_type = wip_ty.index, | 21743 | .owner_type = wip_ty.index, |
| 21840 | .file_scope = block.getFileScopeIndex(mod), | 21744 | .file_scope = block.getFileScopeIndex(mod), |
| 21745 | .generation = mod.generation, | ||
| 21841 | }); | 21746 | }); |
| 21842 | 21747 | ||
| 21748 | try sema.addTypeReferenceEntry(src, wip_ty.index); | ||
| 21843 | return Air.internedToRef(wip_ty.finish(ip, .none, new_namespace_index)); | 21749 | return Air.internedToRef(wip_ty.finish(ip, .none, new_namespace_index)); |
| 21844 | }, | 21750 | }, |
| 21845 | .Union => { | 21751 | .Union => { |
| ... | @@ -22019,11 +21925,16 @@ fn reifyEnum( | ... | @@ -22019,11 +21925,16 @@ fn reifyEnum( |
| 22019 | .zir_index = tracked_inst, | 21925 | .zir_index = tracked_inst, |
| 22020 | .type_hash = hasher.final(), | 21926 | .type_hash = hasher.final(), |
| 22021 | } }, | 21927 | } }, |
| 22022 | })) { | 21928 | }, false)) { |
| 22023 | .wip => |wip| wip, | 21929 | .wip => |wip| wip, |
| 22024 | .existing => |ty| return Air.internedToRef(ty), | 21930 | .existing => |ty| { |
| 21931 | try sema.declareDependency(.{ .interned = ty }); | ||
| 21932 | try sema.addTypeReferenceEntry(src, ty); | ||
| 21933 | return Air.internedToRef(ty); | ||
| 21934 | }, | ||
| 22025 | }; | 21935 | }; |
| 22026 | errdefer wip_ty.cancel(ip, pt.tid); | 21936 | var done = false; |
| 21937 | errdefer if (!done) wip_ty.cancel(ip, pt.tid); | ||
| 22027 | 21938 | ||
| 22028 | if (tag_ty.zigTypeTag(mod) != .Int) { | 21939 | if (tag_ty.zigTypeTag(mod) != .Int) { |
| 22029 | return sema.fail(block, src, "Type.Enum.tag_type must be an integer type", .{}); | 21940 | return sema.fail(block, src, "Type.Enum.tag_type must be an integer type", .{}); |
| ... | @@ -22041,12 +21952,16 @@ fn reifyEnum( | ... | @@ -22041,12 +21952,16 @@ fn reifyEnum( |
| 22041 | .parent = block.namespace.toOptional(), | 21952 | .parent = block.namespace.toOptional(), |
| 22042 | .owner_type = wip_ty.index, | 21953 | .owner_type = wip_ty.index, |
| 22043 | .file_scope = block.getFileScopeIndex(mod), | 21954 | .file_scope = block.getFileScopeIndex(mod), |
| 21955 | .generation = mod.generation, | ||
| 22044 | }); | 21956 | }); |
| 22045 | 21957 | ||
| 22046 | const new_cau_index = try ip.createTypeCau(gpa, pt.tid, tracked_inst, new_namespace_index, wip_ty.index); | 21958 | const new_cau_index = try ip.createTypeCau(gpa, pt.tid, tracked_inst, new_namespace_index, wip_ty.index); |
| 22047 | 21959 | ||
| 21960 | try sema.declareDependency(.{ .interned = wip_ty.index }); | ||
| 21961 | try sema.addTypeReferenceEntry(src, wip_ty.index); | ||
| 22048 | wip_ty.prepare(ip, new_cau_index, new_namespace_index); | 21962 | wip_ty.prepare(ip, new_cau_index, new_namespace_index); |
| 22049 | wip_ty.setTagTy(ip, tag_ty.toIntern()); | 21963 | wip_ty.setTagTy(ip, tag_ty.toIntern()); |
| 21964 | done = true; | ||
| 22050 | 21965 | ||
| 22051 | for (0..fields_len) |field_idx| { | 21966 | for (0..fields_len) |field_idx| { |
| 22052 | const field_info = try fields_val.elemValue(pt, field_idx); | 21967 | const field_info = try fields_val.elemValue(pt, field_idx); |
| ... | @@ -22181,9 +22096,13 @@ fn reifyUnion( | ... | @@ -22181,9 +22096,13 @@ fn reifyUnion( |
| 22181 | .zir_index = tracked_inst, | 22096 | .zir_index = tracked_inst, |
| 22182 | .type_hash = hasher.final(), | 22097 | .type_hash = hasher.final(), |
| 22183 | } }, | 22098 | } }, |
| 22184 | })) { | 22099 | }, false)) { |
| 22185 | .wip => |wip| wip, | 22100 | .wip => |wip| wip, |
| 22186 | .existing => |ty| return Air.internedToRef(ty), | 22101 | .existing => |ty| { |
| 22102 | try sema.declareDependency(.{ .interned = ty }); | ||
| 22103 | try sema.addTypeReferenceEntry(src, ty); | ||
| 22104 | return Air.internedToRef(ty); | ||
| 22105 | }, | ||
| 22187 | }; | 22106 | }; |
| 22188 | errdefer wip_ty.cancel(ip, pt.tid); | 22107 | errdefer wip_ty.cancel(ip, pt.tid); |
| 22189 | 22108 | ||
| ... | @@ -22338,6 +22257,7 @@ fn reifyUnion( | ... | @@ -22338,6 +22257,7 @@ fn reifyUnion( |
| 22338 | .parent = block.namespace.toOptional(), | 22257 | .parent = block.namespace.toOptional(), |
| 22339 | .owner_type = wip_ty.index, | 22258 | .owner_type = wip_ty.index, |
| 22340 | .file_scope = block.getFileScopeIndex(mod), | 22259 | .file_scope = block.getFileScopeIndex(mod), |
| 22260 | .generation = mod.generation, | ||
| 22341 | }); | 22261 | }); |
| 22342 | 22262 | ||
| 22343 | const new_cau_index = try ip.createTypeCau(gpa, pt.tid, tracked_inst, new_namespace_index, wip_ty.index); | 22263 | const new_cau_index = try ip.createTypeCau(gpa, pt.tid, tracked_inst, new_namespace_index, wip_ty.index); |
| ... | @@ -22348,7 +22268,8 @@ fn reifyUnion( | ... | @@ -22348,7 +22268,8 @@ fn reifyUnion( |
| 22348 | if (block.ownerModule().strip) break :codegen_type; | 22268 | if (block.ownerModule().strip) break :codegen_type; |
| 22349 | try mod.comp.queueJob(.{ .codegen_type = wip_ty.index }); | 22269 | try mod.comp.queueJob(.{ .codegen_type = wip_ty.index }); |
| 22350 | } | 22270 | } |
| 22351 | try sema.addReferenceEntry(src, AnalUnit.wrap(.{ .cau = new_cau_index })); | 22271 | try sema.declareDependency(.{ .interned = wip_ty.index }); |
| 22272 | try sema.addTypeReferenceEntry(src, wip_ty.index); | ||
| 22352 | return Air.internedToRef(wip_ty.finish(ip, new_cau_index.toOptional(), new_namespace_index)); | 22273 | return Air.internedToRef(wip_ty.finish(ip, new_cau_index.toOptional(), new_namespace_index)); |
| 22353 | } | 22274 | } |
| 22354 | 22275 | ||
| ... | @@ -22446,9 +22367,13 @@ fn reifyStruct( | ... | @@ -22446,9 +22367,13 @@ fn reifyStruct( |
| 22446 | .zir_index = tracked_inst, | 22367 | .zir_index = tracked_inst, |
| 22447 | .type_hash = hasher.final(), | 22368 | .type_hash = hasher.final(), |
| 22448 | } }, | 22369 | } }, |
| 22449 | })) { | 22370 | }, false)) { |
| 22450 | .wip => |wip| wip, | 22371 | .wip => |wip| wip, |
| 22451 | .existing => |ty| return Air.internedToRef(ty), | 22372 | .existing => |ty| { |
| 22373 | try sema.declareDependency(.{ .interned = ty }); | ||
| 22374 | try sema.addTypeReferenceEntry(src, ty); | ||
| 22375 | return Air.internedToRef(ty); | ||
| 22376 | }, | ||
| 22452 | }; | 22377 | }; |
| 22453 | errdefer wip_ty.cancel(ip, pt.tid); | 22378 | errdefer wip_ty.cancel(ip, pt.tid); |
| 22454 | 22379 | ||
| ... | @@ -22616,6 +22541,7 @@ fn reifyStruct( | ... | @@ -22616,6 +22541,7 @@ fn reifyStruct( |
| 22616 | .parent = block.namespace.toOptional(), | 22541 | .parent = block.namespace.toOptional(), |
| 22617 | .owner_type = wip_ty.index, | 22542 | .owner_type = wip_ty.index, |
| 22618 | .file_scope = block.getFileScopeIndex(mod), | 22543 | .file_scope = block.getFileScopeIndex(mod), |
| 22544 | .generation = mod.generation, | ||
| 22619 | }); | 22545 | }); |
| 22620 | 22546 | ||
| 22621 | const new_cau_index = try ip.createTypeCau(gpa, pt.tid, tracked_inst, new_namespace_index, wip_ty.index); | 22547 | const new_cau_index = try ip.createTypeCau(gpa, pt.tid, tracked_inst, new_namespace_index, wip_ty.index); |
| ... | @@ -22626,7 +22552,8 @@ fn reifyStruct( | ... | @@ -22626,7 +22552,8 @@ fn reifyStruct( |
| 22626 | if (block.ownerModule().strip) break :codegen_type; | 22552 | if (block.ownerModule().strip) break :codegen_type; |
| 22627 | try mod.comp.queueJob(.{ .codegen_type = wip_ty.index }); | 22553 | try mod.comp.queueJob(.{ .codegen_type = wip_ty.index }); |
| 22628 | } | 22554 | } |
| 22629 | try sema.addReferenceEntry(src, AnalUnit.wrap(.{ .cau = new_cau_index })); | 22555 | try sema.declareDependency(.{ .interned = wip_ty.index }); |
| 22556 | try sema.addTypeReferenceEntry(src, wip_ty.index); | ||
| 22630 | return Air.internedToRef(wip_ty.finish(ip, new_cau_index.toOptional(), new_namespace_index)); | 22557 | return Air.internedToRef(wip_ty.finish(ip, new_cau_index.toOptional(), new_namespace_index)); |
| 22631 | } | 22558 | } |
| 22632 | 22559 | ||
| ... | @@ -26125,7 +26052,7 @@ fn zirVarExtended( | ... | @@ -26125,7 +26052,7 @@ fn zirVarExtended( |
| 26125 | const addrspace_src = block.src(.{ .node_offset_var_decl_addrspace = 0 }); | 26052 | const addrspace_src = block.src(.{ .node_offset_var_decl_addrspace = 0 }); |
| 26126 | 26053 | ||
| 26127 | const decl_inst, const decl_bodies = decl: { | 26054 | const decl_inst, const decl_bodies = decl: { |
| 26128 | const decl_inst = sema.getOwnerCauDeclInst().resolve(ip); | 26055 | const decl_inst = sema.getOwnerCauDeclInst().resolve(ip) orelse return error.AnalysisFail; |
| 26129 | const zir_decl, const extra_end = sema.code.getDeclaration(decl_inst); | 26056 | const zir_decl, const extra_end = sema.code.getDeclaration(decl_inst); |
| 26130 | break :decl .{ decl_inst, zir_decl.getBodies(extra_end, sema.code) }; | 26057 | break :decl .{ decl_inst, zir_decl.getBodies(extra_end, sema.code) }; |
| 26131 | }; | 26058 | }; |
| ... | @@ -26354,7 +26281,7 @@ fn zirFuncFancy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A | ... | @@ -26354,7 +26281,7 @@ fn zirFuncFancy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A |
| 26354 | break :decl_inst cau.zir_index; | 26281 | break :decl_inst cau.zir_index; |
| 26355 | } else sema.getOwnerCauDeclInst(); // not an instantiation so we're analyzing a function declaration Cau | 26282 | } else sema.getOwnerCauDeclInst(); // not an instantiation so we're analyzing a function declaration Cau |
| 26356 | 26283 | ||
| 26357 | const zir_decl = sema.code.getDeclaration(decl_inst.resolve(&mod.intern_pool))[0]; | 26284 | const zir_decl = sema.code.getDeclaration(decl_inst.resolve(&mod.intern_pool) orelse return error.AnalysisFail)[0]; |
| 26358 | if (zir_decl.flags.is_export) { | 26285 | if (zir_decl.flags.is_export) { |
| 26359 | break :cc .C; | 26286 | break :cc .C; |
| 26360 | } | 26287 | } |
| ... | @@ -27659,13 +27586,6 @@ fn fieldVal( | ... | @@ -27659,13 +27586,6 @@ fn fieldVal( |
| 27659 | const val = (try sema.resolveDefinedValue(block, object_src, dereffed_type)).?; | 27586 | const val = (try sema.resolveDefinedValue(block, object_src, dereffed_type)).?; |
| 27660 | const child_type = val.toType(); | 27587 | const child_type = val.toType(); |
| 27661 | 27588 | ||
| 27662 | if (child_type.typeDeclInst(mod)) |type_decl_inst| { | ||
| 27663 | try sema.declareDependency(.{ .namespace_name = .{ | ||
| 27664 | .namespace = type_decl_inst, | ||
| 27665 | .name = field_name, | ||
| 27666 | } }); | ||
| 27667 | } | ||
| 27668 | |||
| 27669 | switch (try child_type.zigTypeTagOrPoison(mod)) { | 27589 | switch (try child_type.zigTypeTagOrPoison(mod)) { |
| 27670 | .ErrorSet => { | 27590 | .ErrorSet => { |
| 27671 | switch (ip.indexToKey(child_type.toIntern())) { | 27591 | switch (ip.indexToKey(child_type.toIntern())) { |
| ... | @@ -27897,13 +27817,6 @@ fn fieldPtr( | ... | @@ -27897,13 +27817,6 @@ fn fieldPtr( |
| 27897 | const val = (sema.resolveDefinedValue(block, src, inner) catch unreachable).?; | 27817 | const val = (sema.resolveDefinedValue(block, src, inner) catch unreachable).?; |
| 27898 | const child_type = val.toType(); | 27818 | const child_type = val.toType(); |
| 27899 | 27819 | ||
| 27900 | if (child_type.typeDeclInst(mod)) |type_decl_inst| { | ||
| 27901 | try sema.declareDependency(.{ .namespace_name = .{ | ||
| 27902 | .namespace = type_decl_inst, | ||
| 27903 | .name = field_name, | ||
| 27904 | } }); | ||
| 27905 | } | ||
| 27906 | |||
| 27907 | switch (child_type.zigTypeTag(mod)) { | 27820 | switch (child_type.zigTypeTag(mod)) { |
| 27908 | .ErrorSet => { | 27821 | .ErrorSet => { |
| 27909 | switch (ip.indexToKey(child_type.toIntern())) { | 27822 | switch (ip.indexToKey(child_type.toIntern())) { |
| ... | @@ -32223,7 +32136,7 @@ fn addReferenceEntry( | ... | @@ -32223,7 +32136,7 @@ fn addReferenceEntry( |
| 32223 | referenced_unit: AnalUnit, | 32136 | referenced_unit: AnalUnit, |
| 32224 | ) !void { | 32137 | ) !void { |
| 32225 | const zcu = sema.pt.zcu; | 32138 | const zcu = sema.pt.zcu; |
| 32226 | if (zcu.comp.reference_trace == 0) return; | 32139 | if (!zcu.comp.incremental and zcu.comp.reference_trace == 0) return; |
| 32227 | const gop = try sema.references.getOrPut(sema.gpa, referenced_unit); | 32140 | const gop = try sema.references.getOrPut(sema.gpa, referenced_unit); |
| 32228 | if (gop.found_existing) return; | 32141 | if (gop.found_existing) return; |
| 32229 | // TODO: we need to figure out how to model inline calls here. | 32142 | // TODO: we need to figure out how to model inline calls here. |
| ... | @@ -32232,6 +32145,18 @@ fn addReferenceEntry( | ... | @@ -32232,6 +32145,18 @@ fn addReferenceEntry( |
| 32232 | try zcu.addUnitReference(sema.owner, referenced_unit, src); | 32145 | try zcu.addUnitReference(sema.owner, referenced_unit, src); |
| 32233 | } | 32146 | } |
| 32234 | 32147 | ||
| 32148 | fn addTypeReferenceEntry( | ||
| 32149 | sema: *Sema, | ||
| 32150 | src: LazySrcLoc, | ||
| 32151 | referenced_type: InternPool.Index, | ||
| 32152 | ) !void { | ||
| 32153 | const zcu = sema.pt.zcu; | ||
| 32154 | if (!zcu.comp.incremental and zcu.comp.reference_trace == 0) return; | ||
| 32155 | const gop = try sema.type_references.getOrPut(sema.gpa, referenced_type); | ||
| 32156 | if (gop.found_existing) return; | ||
| 32157 | try zcu.addTypeReference(sema.owner, referenced_type, src); | ||
| 32158 | } | ||
| 32159 | |||
| 32235 | pub fn ensureNavResolved(sema: *Sema, src: LazySrcLoc, nav_index: InternPool.Nav.Index) CompileError!void { | 32160 | pub fn ensureNavResolved(sema: *Sema, src: LazySrcLoc, nav_index: InternPool.Nav.Index) CompileError!void { |
| 32236 | const pt = sema.pt; | 32161 | const pt = sema.pt; |
| 32237 | const zcu = pt.zcu; | 32162 | const zcu = pt.zcu; |
| ... | @@ -35323,7 +35248,7 @@ pub fn resolveStructLayout(sema: *Sema, ty: Type) SemaError!void { | ... | @@ -35323,7 +35248,7 @@ pub fn resolveStructLayout(sema: *Sema, ty: Type) SemaError!void { |
| 35323 | if (struct_type.haveLayout(ip)) | 35248 | if (struct_type.haveLayout(ip)) |
| 35324 | return; | 35249 | return; |
| 35325 | 35250 | ||
| 35326 | try ty.resolveFields(pt); | 35251 | try sema.resolveTypeFieldsStruct(ty.toIntern(), struct_type); |
| 35327 | 35252 | ||
| 35328 | if (struct_type.layout == .@"packed") { | 35253 | if (struct_type.layout == .@"packed") { |
| 35329 | semaBackingIntType(pt, struct_type) catch |err| switch (err) { | 35254 | semaBackingIntType(pt, struct_type) catch |err| switch (err) { |
| ... | @@ -35505,7 +35430,7 @@ fn semaBackingIntType(pt: Zcu.PerThread, struct_type: InternPool.LoadedStructTyp | ... | @@ -35505,7 +35430,7 @@ fn semaBackingIntType(pt: Zcu.PerThread, struct_type: InternPool.LoadedStructTyp |
| 35505 | break :blk accumulator; | 35430 | break :blk accumulator; |
| 35506 | }; | 35431 | }; |
| 35507 | 35432 | ||
| 35508 | const zir_index = struct_type.zir_index.unwrap().?.resolve(ip); | 35433 | const zir_index = struct_type.zir_index.unwrap().?.resolve(ip) orelse return error.AnalysisFail; |
| 35509 | const extended = zir.instructions.items(.data)[@intFromEnum(zir_index)].extended; | 35434 | const extended = zir.instructions.items(.data)[@intFromEnum(zir_index)].extended; |
| 35510 | assert(extended.opcode == .struct_decl); | 35435 | assert(extended.opcode == .struct_decl); |
| 35511 | const small: Zir.Inst.StructDecl.Small = @bitCast(extended.small); | 35436 | const small: Zir.Inst.StructDecl.Small = @bitCast(extended.small); |
| ... | @@ -36120,7 +36045,7 @@ fn semaStructFields( | ... | @@ -36120,7 +36045,7 @@ fn semaStructFields( |
| 36120 | const cau_index = struct_type.cau.unwrap().?; | 36045 | const cau_index = struct_type.cau.unwrap().?; |
| 36121 | const namespace_index = ip.getCau(cau_index).namespace; | 36046 | const namespace_index = ip.getCau(cau_index).namespace; |
| 36122 | const zir = zcu.namespacePtr(namespace_index).fileScope(zcu).zir; | 36047 | const zir = zcu.namespacePtr(namespace_index).fileScope(zcu).zir; |
| 36123 | const zir_index = struct_type.zir_index.unwrap().?.resolve(ip); | 36048 | const zir_index = struct_type.zir_index.unwrap().?.resolve(ip) orelse return error.AnalysisFail; |
| 36124 | 36049 | ||
| 36125 | const fields_len, const small, var extra_index = structZirInfo(zir, zir_index); | 36050 | const fields_len, const small, var extra_index = structZirInfo(zir, zir_index); |
| 36126 | 36051 | ||
| ... | @@ -36343,7 +36268,7 @@ fn semaStructFieldInits( | ... | @@ -36343,7 +36268,7 @@ fn semaStructFieldInits( |
| 36343 | const cau_index = struct_type.cau.unwrap().?; | 36268 | const cau_index = struct_type.cau.unwrap().?; |
| 36344 | const namespace_index = ip.getCau(cau_index).namespace; | 36269 | const namespace_index = ip.getCau(cau_index).namespace; |
| 36345 | const zir = zcu.namespacePtr(namespace_index).fileScope(zcu).zir; | 36270 | const zir = zcu.namespacePtr(namespace_index).fileScope(zcu).zir; |
| 36346 | const zir_index = struct_type.zir_index.unwrap().?.resolve(ip); | 36271 | const zir_index = struct_type.zir_index.unwrap().?.resolve(ip) orelse return error.AnalysisFail; |
| 36347 | const fields_len, const small, var extra_index = structZirInfo(zir, zir_index); | 36272 | const fields_len, const small, var extra_index = structZirInfo(zir, zir_index); |
| 36348 | 36273 | ||
| 36349 | var comptime_err_ret_trace = std.ArrayList(LazySrcLoc).init(gpa); | 36274 | var comptime_err_ret_trace = std.ArrayList(LazySrcLoc).init(gpa); |
| ... | @@ -36477,7 +36402,7 @@ fn semaUnionFields(pt: Zcu.PerThread, arena: Allocator, union_ty: InternPool.Ind | ... | @@ -36477,7 +36402,7 @@ fn semaUnionFields(pt: Zcu.PerThread, arena: Allocator, union_ty: InternPool.Ind |
| 36477 | const ip = &zcu.intern_pool; | 36402 | const ip = &zcu.intern_pool; |
| 36478 | const cau_index = union_type.cau; | 36403 | const cau_index = union_type.cau; |
| 36479 | const zir = zcu.namespacePtr(union_type.namespace).fileScope(zcu).zir; | 36404 | const zir = zcu.namespacePtr(union_type.namespace).fileScope(zcu).zir; |
| 36480 | const zir_index = union_type.zir_index.resolve(ip); | 36405 | const zir_index = union_type.zir_index.resolve(ip) orelse return error.AnalysisFail; |
| 36481 | const extended = zir.instructions.items(.data)[@intFromEnum(zir_index)].extended; | 36406 | const extended = zir.instructions.items(.data)[@intFromEnum(zir_index)].extended; |
| 36482 | assert(extended.opcode == .union_decl); | 36407 | assert(extended.opcode == .union_decl); |
| 36483 | const small: Zir.Inst.UnionDecl.Small = @bitCast(extended.small); | 36408 | const small: Zir.Inst.UnionDecl.Small = @bitCast(extended.small); |
| ... | @@ -36591,11 +36516,11 @@ fn semaUnionFields(pt: Zcu.PerThread, arena: Allocator, union_ty: InternPool.Ind | ... | @@ -36591,11 +36516,11 @@ fn semaUnionFields(pt: Zcu.PerThread, arena: Allocator, union_ty: InternPool.Ind |
| 36591 | } | 36516 | } |
| 36592 | } else { | 36517 | } else { |
| 36593 | // The provided type is the enum tag type. | 36518 | // The provided type is the enum tag type. |
| 36594 | union_type.setTagType(ip, provided_ty.toIntern()); | ||
| 36595 | const enum_type = switch (ip.indexToKey(provided_ty.toIntern())) { | 36519 | const enum_type = switch (ip.indexToKey(provided_ty.toIntern())) { |
| 36596 | .enum_type => ip.loadEnumType(provided_ty.toIntern()), | 36520 | .enum_type => ip.loadEnumType(provided_ty.toIntern()), |
| 36597 | else => return sema.fail(&block_scope, tag_ty_src, "expected enum tag type, found '{}'", .{provided_ty.fmt(pt)}), | 36521 | else => return sema.fail(&block_scope, tag_ty_src, "expected enum tag type, found '{}'", .{provided_ty.fmt(pt)}), |
| 36598 | }; | 36522 | }; |
| 36523 | union_type.setTagType(ip, provided_ty.toIntern()); | ||
| 36599 | // The fields of the union must match the enum exactly. | 36524 | // The fields of the union must match the enum exactly. |
| 36600 | // A flag per field is used to check for missing and extraneous fields. | 36525 | // A flag per field is used to check for missing and extraneous fields. |
| 36601 | explicit_tags_seen = try sema.arena.alloc(bool, enum_type.names.len); | 36526 | explicit_tags_seen = try sema.arena.alloc(bool, enum_type.names.len); |
| ... | @@ -38223,6 +38148,9 @@ pub fn declareDependency(sema: *Sema, dependee: InternPool.Dependee) !void { | ... | @@ -38223,6 +38148,9 @@ pub fn declareDependency(sema: *Sema, dependee: InternPool.Dependee) !void { |
| 38223 | const zcu = sema.pt.zcu; | 38148 | const zcu = sema.pt.zcu; |
| 38224 | if (!zcu.comp.incremental) return; | 38149 | if (!zcu.comp.incremental) return; |
| 38225 | 38150 | ||
| 38151 | const gop = try sema.dependencies.getOrPut(sema.gpa, dependee); | ||
| 38152 | if (gop.found_existing) return; | ||
| 38153 | |||
| 38226 | // Avoid creating dependencies on ourselves. This situation can arise when we analyze the fields | 38154 | // Avoid creating dependencies on ourselves. This situation can arise when we analyze the fields |
| 38227 | // of a type and they use `@This()`. This dependency would be unnecessary, and in fact would | 38155 | // of a type and they use `@This()`. This dependency would be unnecessary, and in fact would |
| 38228 | // just result in over-analysis since `Zcu.findOutdatedToAnalyze` would never be able to resolve | 38156 | // just result in over-analysis since `Zcu.findOutdatedToAnalyze` would never be able to resolve |
| ... | @@ -38446,6 +38374,187 @@ fn getOwnerFuncDeclInst(sema: *Sema) InternPool.TrackedInst.Index { | ... | @@ -38446,6 +38374,187 @@ fn getOwnerFuncDeclInst(sema: *Sema) InternPool.TrackedInst.Index { |
| 38446 | return ip.getCau(cau).zir_index; | 38374 | return ip.getCau(cau).zir_index; |
| 38447 | } | 38375 | } |
| 38448 | 38376 | ||
| 38377 | /// Called as soon as a `declared` enum type is created. | ||
| 38378 | /// Resolves the tag type and field inits. | ||
| 38379 | /// Marks the `src_inst` dependency on the enum's declaration, so call sites need not do this. | ||
| 38380 | pub fn resolveDeclaredEnum( | ||
| 38381 | pt: Zcu.PerThread, | ||
| 38382 | wip_ty: InternPool.WipEnumType, | ||
| 38383 | inst: Zir.Inst.Index, | ||
| 38384 | tracked_inst: InternPool.TrackedInst.Index, | ||
| 38385 | namespace: InternPool.NamespaceIndex, | ||
| 38386 | type_name: InternPool.NullTerminatedString, | ||
| 38387 | enum_cau: InternPool.Cau.Index, | ||
| 38388 | small: Zir.Inst.EnumDecl.Small, | ||
| 38389 | body: []const Zir.Inst.Index, | ||
| 38390 | tag_type_ref: Zir.Inst.Ref, | ||
| 38391 | any_values: bool, | ||
| 38392 | fields_len: u32, | ||
| 38393 | zir: Zir, | ||
| 38394 | body_end: usize, | ||
| 38395 | ) Zcu.CompileError!void { | ||
| 38396 | const zcu = pt.zcu; | ||
| 38397 | const gpa = zcu.gpa; | ||
| 38398 | const ip = &zcu.intern_pool; | ||
| 38399 | |||
| 38400 | const bit_bags_count = std.math.divCeil(usize, fields_len, 32) catch unreachable; | ||
| 38401 | |||
| 38402 | const src: LazySrcLoc = .{ .base_node_inst = tracked_inst, .offset = LazySrcLoc.Offset.nodeOffset(0) }; | ||
| 38403 | const tag_ty_src: LazySrcLoc = .{ .base_node_inst = tracked_inst, .offset = .{ .node_offset_container_tag = 0 } }; | ||
| 38404 | |||
| 38405 | const anal_unit = AnalUnit.wrap(.{ .cau = enum_cau }); | ||
| 38406 | |||
| 38407 | var arena = std.heap.ArenaAllocator.init(gpa); | ||
| 38408 | defer arena.deinit(); | ||
| 38409 | |||
| 38410 | var comptime_err_ret_trace = std.ArrayList(Zcu.LazySrcLoc).init(gpa); | ||
| 38411 | defer comptime_err_ret_trace.deinit(); | ||
| 38412 | |||
| 38413 | var sema: Sema = .{ | ||
| 38414 | .pt = pt, | ||
| 38415 | .gpa = gpa, | ||
| 38416 | .arena = arena.allocator(), | ||
| 38417 | .code = zir, | ||
| 38418 | .owner = anal_unit, | ||
| 38419 | .func_index = .none, | ||
| 38420 | .func_is_naked = false, | ||
| 38421 | .fn_ret_ty = Type.void, | ||
| 38422 | .fn_ret_ty_ies = null, | ||
| 38423 | .comptime_err_ret_trace = &comptime_err_ret_trace, | ||
| 38424 | }; | ||
| 38425 | defer sema.deinit(); | ||
| 38426 | |||
| 38427 | try sema.declareDependency(.{ .src_hash = tracked_inst }); | ||
| 38428 | |||
| 38429 | var block: Block = .{ | ||
| 38430 | .parent = null, | ||
| 38431 | .sema = &sema, | ||
| 38432 | .namespace = namespace, | ||
| 38433 | .instructions = .{}, | ||
| 38434 | .inlining = null, | ||
| 38435 | .is_comptime = true, | ||
| 38436 | .src_base_inst = tracked_inst, | ||
| 38437 | .type_name_ctx = type_name, | ||
| 38438 | }; | ||
| 38439 | defer block.instructions.deinit(gpa); | ||
| 38440 | |||
| 38441 | const int_tag_ty = ty: { | ||
| 38442 | if (body.len != 0) { | ||
| 38443 | _ = try sema.analyzeInlineBody(&block, body, inst); | ||
| 38444 | } | ||
| 38445 | |||
| 38446 | if (tag_type_ref != .none) { | ||
| 38447 | const ty = try sema.resolveType(&block, tag_ty_src, tag_type_ref); | ||
| 38448 | if (ty.zigTypeTag(zcu) != .Int and ty.zigTypeTag(zcu) != .ComptimeInt) { | ||
| 38449 | return sema.fail(&block, tag_ty_src, "expected integer tag type, found '{}'", .{ty.fmt(pt)}); | ||
| 38450 | } | ||
| 38451 | break :ty ty; | ||
| 38452 | } else if (fields_len == 0) { | ||
| 38453 | break :ty try pt.intType(.unsigned, 0); | ||
| 38454 | } else { | ||
| 38455 | const bits = std.math.log2_int_ceil(usize, fields_len); | ||
| 38456 | break :ty try pt.intType(.unsigned, bits); | ||
| 38457 | } | ||
| 38458 | }; | ||
| 38459 | |||
| 38460 | wip_ty.setTagTy(ip, int_tag_ty.toIntern()); | ||
| 38461 | |||
| 38462 | if (small.nonexhaustive and int_tag_ty.toIntern() != .comptime_int_type) { | ||
| 38463 | if (fields_len > 1 and std.math.log2_int(u64, fields_len) == int_tag_ty.bitSize(pt)) { | ||
| 38464 | return sema.fail(&block, src, "non-exhaustive enum specifies every value", .{}); | ||
| 38465 | } | ||
| 38466 | } | ||
| 38467 | |||
| 38468 | var extra_index = body_end + bit_bags_count; | ||
| 38469 | var bit_bag_index: usize = body_end; | ||
| 38470 | var cur_bit_bag: u32 = undefined; | ||
| 38471 | var last_tag_val: ?Value = null; | ||
| 38472 | for (0..fields_len) |field_i_usize| { | ||
| 38473 | const field_i: u32 = @intCast(field_i_usize); | ||
| 38474 | if (field_i % 32 == 0) { | ||
| 38475 | cur_bit_bag = zir.extra[bit_bag_index]; | ||
| 38476 | bit_bag_index += 1; | ||
| 38477 | } | ||
| 38478 | const has_tag_value = @as(u1, @truncate(cur_bit_bag)) != 0; | ||
| 38479 | cur_bit_bag >>= 1; | ||
| 38480 | |||
| 38481 | const field_name_index: Zir.NullTerminatedString = @enumFromInt(zir.extra[extra_index]); | ||
| 38482 | const field_name_zir = zir.nullTerminatedString(field_name_index); | ||
| 38483 | extra_index += 2; // field name, doc comment | ||
| 38484 | |||
| 38485 | const field_name = try ip.getOrPutString(gpa, pt.tid, field_name_zir, .no_embedded_nulls); | ||
| 38486 | |||
| 38487 | const value_src: LazySrcLoc = .{ | ||
| 38488 | .base_node_inst = tracked_inst, | ||
| 38489 | .offset = .{ .container_field_value = field_i }, | ||
| 38490 | }; | ||
| 38491 | |||
| 38492 | const tag_overflow = if (has_tag_value) overflow: { | ||
| 38493 | const tag_val_ref: Zir.Inst.Ref = @enumFromInt(zir.extra[extra_index]); | ||
| 38494 | extra_index += 1; | ||
| 38495 | const tag_inst = try sema.resolveInst(tag_val_ref); | ||
| 38496 | last_tag_val = try sema.resolveConstDefinedValue(&block, .{ | ||
| 38497 | .base_node_inst = tracked_inst, | ||
| 38498 | .offset = .{ .container_field_name = field_i }, | ||
| 38499 | }, tag_inst, .{ | ||
| 38500 | .needed_comptime_reason = "enum tag value must be comptime-known", | ||
| 38501 | }); | ||
| 38502 | if (!(try sema.intFitsInType(last_tag_val.?, int_tag_ty, null))) break :overflow true; | ||
| 38503 | last_tag_val = try pt.getCoerced(last_tag_val.?, int_tag_ty); | ||
| 38504 | if (wip_ty.nextField(ip, field_name, last_tag_val.?.toIntern())) |conflict| { | ||
| 38505 | assert(conflict.kind == .value); // AstGen validated names are unique | ||
| 38506 | const other_field_src: LazySrcLoc = .{ | ||
| 38507 | .base_node_inst = tracked_inst, | ||
| 38508 | .offset = .{ .container_field_value = conflict.prev_field_idx }, | ||
| 38509 | }; | ||
| 38510 | const msg = msg: { | ||
| 38511 | const msg = try sema.errMsg(value_src, "enum tag value {} already taken", .{last_tag_val.?.fmtValueSema(pt, &sema)}); | ||
| 38512 | errdefer msg.destroy(gpa); | ||
| 38513 | try sema.errNote(other_field_src, msg, "other occurrence here", .{}); | ||
| 38514 | break :msg msg; | ||
| 38515 | }; | ||
| 38516 | return sema.failWithOwnedErrorMsg(&block, msg); | ||
| 38517 | } | ||
| 38518 | break :overflow false; | ||
| 38519 | } else if (any_values) overflow: { | ||
| 38520 | var overflow: ?usize = null; | ||
| 38521 | last_tag_val = if (last_tag_val) |val| | ||
| 38522 | try sema.intAdd(val, try pt.intValue(int_tag_ty, 1), int_tag_ty, &overflow) | ||
| 38523 | else | ||
| 38524 | try pt.intValue(int_tag_ty, 0); | ||
| 38525 | if (overflow != null) break :overflow true; | ||
| 38526 | if (wip_ty.nextField(ip, field_name, last_tag_val.?.toIntern())) |conflict| { | ||
| 38527 | assert(conflict.kind == .value); // AstGen validated names are unique | ||
| 38528 | const other_field_src: LazySrcLoc = .{ | ||
| 38529 | .base_node_inst = tracked_inst, | ||
| 38530 | .offset = .{ .container_field_value = conflict.prev_field_idx }, | ||
| 38531 | }; | ||
| 38532 | const msg = msg: { | ||
| 38533 | const msg = try sema.errMsg(value_src, "enum tag value {} already taken", .{last_tag_val.?.fmtValueSema(pt, &sema)}); | ||
| 38534 | errdefer msg.destroy(gpa); | ||
| 38535 | try sema.errNote(other_field_src, msg, "other occurrence here", .{}); | ||
| 38536 | break :msg msg; | ||
| 38537 | }; | ||
| 38538 | return sema.failWithOwnedErrorMsg(&block, msg); | ||
| 38539 | } | ||
| 38540 | break :overflow false; | ||
| 38541 | } else overflow: { | ||
| 38542 | assert(wip_ty.nextField(ip, field_name, .none) == null); | ||
| 38543 | last_tag_val = try pt.intValue(Type.comptime_int, field_i); | ||
| 38544 | if (!try sema.intFitsInType(last_tag_val.?, int_tag_ty, null)) break :overflow true; | ||
| 38545 | last_tag_val = try pt.getCoerced(last_tag_val.?, int_tag_ty); | ||
| 38546 | break :overflow false; | ||
| 38547 | }; | ||
| 38548 | |||
| 38549 | if (tag_overflow) { | ||
| 38550 | const msg = try sema.errMsg(value_src, "enumeration value '{}' too large for type '{}'", .{ | ||
| 38551 | last_tag_val.?.fmtValueSema(pt, &sema), int_tag_ty.fmt(pt), | ||
| 38552 | }); | ||
| 38553 | return sema.failWithOwnedErrorMsg(&block, msg); | ||
| 38554 | } | ||
| 38555 | } | ||
| 38556 | } | ||
| 38557 | |||
| 38449 | pub const bitCastVal = @import("Sema/bitcast.zig").bitCast; | 38558 | pub const bitCastVal = @import("Sema/bitcast.zig").bitCast; |
| 38450 | pub const bitCastSpliceVal = @import("Sema/bitcast.zig").bitCastSplice; | 38559 | pub const bitCastSpliceVal = @import("Sema/bitcast.zig").bitCastSplice; |
| 38451 | 38560 |
src/Type.zig+1-1| ... | @@ -3437,7 +3437,7 @@ pub fn typeDeclSrcLine(ty: Type, zcu: *Zcu) ?u32 { | ... | @@ -3437,7 +3437,7 @@ pub fn typeDeclSrcLine(ty: Type, zcu: *Zcu) ?u32 { |
| 3437 | }, | 3437 | }, |
| 3438 | else => return null, | 3438 | else => return null, |
| 3439 | }; | 3439 | }; |
| 3440 | const info = tracked.resolveFull(&zcu.intern_pool); | 3440 | const info = tracked.resolveFull(&zcu.intern_pool) orelse return null; |
| 3441 | const file = zcu.fileByIndex(info.file); | 3441 | const file = zcu.fileByIndex(info.file); |
| 3442 | assert(file.zir_loaded); | 3442 | assert(file.zir_loaded); |
| 3443 | const zir = file.zir; | 3443 | const zir = file.zir; |
src/Zcu.zig+485-135| ... | @@ -10,7 +10,7 @@ const builtin = @import("builtin"); | ... | @@ -10,7 +10,7 @@ const builtin = @import("builtin"); |
| 10 | const mem = std.mem; | 10 | const mem = std.mem; |
| 11 | const Allocator = std.mem.Allocator; | 11 | const Allocator = std.mem.Allocator; |
| 12 | const assert = std.debug.assert; | 12 | const assert = std.debug.assert; |
| 13 | const log = std.log.scoped(.module); | 13 | const log = std.log.scoped(.zcu); |
| 14 | const BigIntConst = std.math.big.int.Const; | 14 | const BigIntConst = std.math.big.int.Const; |
| 15 | const BigIntMutable = std.math.big.int.Mutable; | 15 | const BigIntMutable = std.math.big.int.Mutable; |
| 16 | const Target = std.Target; | 16 | const Target = std.Target; |
| ... | @@ -153,27 +153,27 @@ cimport_errors: std.AutoArrayHashMapUnmanaged(AnalUnit, std.zig.ErrorBundle) = . | ... | @@ -153,27 +153,27 @@ cimport_errors: std.AutoArrayHashMapUnmanaged(AnalUnit, std.zig.ErrorBundle) = . |
| 153 | /// Maximum amount of distinct error values, set by --error-limit | 153 | /// Maximum amount of distinct error values, set by --error-limit |
| 154 | error_limit: ErrorInt, | 154 | error_limit: ErrorInt, |
| 155 | 155 | ||
| 156 | /// Value is the number of PO or outdated Decls which this AnalUnit depends on. | 156 | /// Value is the number of PO dependencies of this AnalUnit. |
| 157 | /// This value will decrease as we perform semantic analysis to learn what is outdated. | ||
| 158 | /// If any of these PO deps is outdated, this value will be moved to `outdated`. | ||
| 157 | potentially_outdated: std.AutoArrayHashMapUnmanaged(AnalUnit, u32) = .{}, | 159 | potentially_outdated: std.AutoArrayHashMapUnmanaged(AnalUnit, u32) = .{}, |
| 158 | /// Value is the number of PO or outdated Decls which this AnalUnit depends on. | 160 | /// Value is the number of PO dependencies of this AnalUnit. |
| 159 | /// Once this value drops to 0, the AnalUnit is a candidate for re-analysis. | 161 | /// Once this value drops to 0, the AnalUnit is a candidate for re-analysis. |
| 160 | outdated: std.AutoArrayHashMapUnmanaged(AnalUnit, u32) = .{}, | 162 | outdated: std.AutoArrayHashMapUnmanaged(AnalUnit, u32) = .{}, |
| 161 | /// This contains all `AnalUnit`s in `outdated` whose PO dependency count is 0. | 163 | /// This contains all `AnalUnit`s in `outdated` whose PO dependency count is 0. |
| 162 | /// Such `AnalUnit`s are ready for immediate re-analysis. | 164 | /// Such `AnalUnit`s are ready for immediate re-analysis. |
| 163 | /// See `findOutdatedToAnalyze` for details. | 165 | /// See `findOutdatedToAnalyze` for details. |
| 164 | outdated_ready: std.AutoArrayHashMapUnmanaged(AnalUnit, void) = .{}, | 166 | outdated_ready: std.AutoArrayHashMapUnmanaged(AnalUnit, void) = .{}, |
| 165 | /// This contains a set of struct types whose corresponding `Cau` may not be in | ||
| 166 | /// `outdated`, but are the root types of files which have updated source and | ||
| 167 | /// thus must be re-analyzed. If such a type is only in this set, the struct type | ||
| 168 | /// index may be preserved (only the namespace might change). If its owned `Cau` | ||
| 169 | /// is also outdated, the struct type index must be recreated. | ||
| 170 | outdated_file_root: std.AutoArrayHashMapUnmanaged(InternPool.Index, void) = .{}, | ||
| 171 | /// This contains a list of AnalUnit whose analysis or codegen failed, but the | 167 | /// This contains a list of AnalUnit whose analysis or codegen failed, but the |
| 172 | /// failure was something like running out of disk space, and trying again may | 168 | /// failure was something like running out of disk space, and trying again may |
| 173 | /// succeed. On the next update, we will flush this list, marking all members of | 169 | /// succeed. On the next update, we will flush this list, marking all members of |
| 174 | /// it as outdated. | 170 | /// it as outdated. |
| 175 | retryable_failures: std.ArrayListUnmanaged(AnalUnit) = .{}, | 171 | retryable_failures: std.ArrayListUnmanaged(AnalUnit) = .{}, |
| 176 | 172 | ||
| 173 | /// These are the modules which we initially queue for analysis in `Compilation.update`. | ||
| 174 | /// `resolveReferences` will use these as the root of its reachability traversal. | ||
| 175 | analysis_roots: std.BoundedArray(*Package.Module, 3) = .{}, | ||
| 176 | |||
| 177 | stage1_flags: packed struct { | 177 | stage1_flags: packed struct { |
| 178 | have_winmain: bool = false, | 178 | have_winmain: bool = false, |
| 179 | have_wwinmain: bool = false, | 179 | have_wwinmain: bool = false, |
| ... | @@ -192,7 +192,7 @@ global_assembly: std.AutoArrayHashMapUnmanaged(InternPool.Cau.Index, []u8) = .{} | ... | @@ -192,7 +192,7 @@ global_assembly: std.AutoArrayHashMapUnmanaged(InternPool.Cau.Index, []u8) = .{} |
| 192 | 192 | ||
| 193 | /// Key is the `AnalUnit` *performing* the reference. This representation allows | 193 | /// Key is the `AnalUnit` *performing* the reference. This representation allows |
| 194 | /// incremental updates to quickly delete references caused by a specific `AnalUnit`. | 194 | /// incremental updates to quickly delete references caused by a specific `AnalUnit`. |
| 195 | /// Value is index into `all_reference` of the first reference triggered by the unit. | 195 | /// Value is index into `all_references` of the first reference triggered by the unit. |
| 196 | /// The `next` field on the `Reference` forms a linked list of all references | 196 | /// The `next` field on the `Reference` forms a linked list of all references |
| 197 | /// triggered by the key `AnalUnit`. | 197 | /// triggered by the key `AnalUnit`. |
| 198 | reference_table: std.AutoArrayHashMapUnmanaged(AnalUnit, u32) = .{}, | 198 | reference_table: std.AutoArrayHashMapUnmanaged(AnalUnit, u32) = .{}, |
| ... | @@ -200,11 +200,23 @@ all_references: std.ArrayListUnmanaged(Reference) = .{}, | ... | @@ -200,11 +200,23 @@ all_references: std.ArrayListUnmanaged(Reference) = .{}, |
| 200 | /// Freelist of indices in `all_references`. | 200 | /// Freelist of indices in `all_references`. |
| 201 | free_references: std.ArrayListUnmanaged(u32) = .{}, | 201 | free_references: std.ArrayListUnmanaged(u32) = .{}, |
| 202 | 202 | ||
| 203 | /// Key is the `AnalUnit` *performing* the reference. This representation allows | ||
| 204 | /// incremental updates to quickly delete references caused by a specific `AnalUnit`. | ||
| 205 | /// Value is index into `all_type_reference` of the first reference triggered by the unit. | ||
| 206 | /// The `next` field on the `TypeReference` forms a linked list of all type references | ||
| 207 | /// triggered by the key `AnalUnit`. | ||
| 208 | type_reference_table: std.AutoArrayHashMapUnmanaged(AnalUnit, u32) = .{}, | ||
| 209 | all_type_references: std.ArrayListUnmanaged(TypeReference) = .{}, | ||
| 210 | /// Freelist of indices in `all_type_references`. | ||
| 211 | free_type_references: std.ArrayListUnmanaged(u32) = .{}, | ||
| 212 | |||
| 203 | panic_messages: [PanicId.len]InternPool.Nav.Index.Optional = .{.none} ** PanicId.len, | 213 | panic_messages: [PanicId.len]InternPool.Nav.Index.Optional = .{.none} ** PanicId.len, |
| 204 | /// The panic function body. | 214 | /// The panic function body. |
| 205 | panic_func_index: InternPool.Index = .none, | 215 | panic_func_index: InternPool.Index = .none, |
| 206 | null_stack_trace: InternPool.Index = .none, | 216 | null_stack_trace: InternPool.Index = .none, |
| 207 | 217 | ||
| 218 | generation: u32 = 0, | ||
| 219 | |||
| 208 | pub const PerThread = @import("Zcu/PerThread.zig"); | 220 | pub const PerThread = @import("Zcu/PerThread.zig"); |
| 209 | 221 | ||
| 210 | pub const PanicId = enum { | 222 | pub const PanicId = enum { |
| ... | @@ -308,10 +320,21 @@ pub const Reference = struct { | ... | @@ -308,10 +320,21 @@ pub const Reference = struct { |
| 308 | src: LazySrcLoc, | 320 | src: LazySrcLoc, |
| 309 | }; | 321 | }; |
| 310 | 322 | ||
| 323 | pub const TypeReference = struct { | ||
| 324 | /// The container type which was referenced. | ||
| 325 | referenced: InternPool.Index, | ||
| 326 | /// Index into `all_type_references` of the next `TypeReference` triggered by the same `AnalUnit`. | ||
| 327 | /// `std.math.maxInt(u32)` is the sentinel. | ||
| 328 | next: u32, | ||
| 329 | /// The source location of the reference. | ||
| 330 | src: LazySrcLoc, | ||
| 331 | }; | ||
| 332 | |||
| 311 | /// The container that structs, enums, unions, and opaques have. | 333 | /// The container that structs, enums, unions, and opaques have. |
| 312 | pub const Namespace = struct { | 334 | pub const Namespace = struct { |
| 313 | parent: OptionalIndex, | 335 | parent: OptionalIndex, |
| 314 | file_scope: File.Index, | 336 | file_scope: File.Index, |
| 337 | generation: u32, | ||
| 315 | /// Will be a struct, enum, union, or opaque. | 338 | /// Will be a struct, enum, union, or opaque. |
| 316 | owner_type: InternPool.Index, | 339 | owner_type: InternPool.Index, |
| 317 | /// Members of the namespace which are marked `pub`. | 340 | /// Members of the namespace which are marked `pub`. |
| ... | @@ -2022,10 +2045,11 @@ pub const LazySrcLoc = struct { | ... | @@ -2022,10 +2045,11 @@ pub const LazySrcLoc = struct { |
| 2022 | .offset = .unneeded, | 2045 | .offset = .unneeded, |
| 2023 | }; | 2046 | }; |
| 2024 | 2047 | ||
| 2025 | pub fn resolveBaseNode(base_node_inst: InternPool.TrackedInst.Index, zcu: *Zcu) struct { *File, Ast.Node.Index } { | 2048 | /// Returns `null` if the ZIR instruction has been lost across incremental updates. |
| 2049 | pub fn resolveBaseNode(base_node_inst: InternPool.TrackedInst.Index, zcu: *Zcu) ?struct { *File, Ast.Node.Index } { | ||
| 2026 | const ip = &zcu.intern_pool; | 2050 | const ip = &zcu.intern_pool; |
| 2027 | const file_index, const zir_inst = inst: { | 2051 | const file_index, const zir_inst = inst: { |
| 2028 | const info = base_node_inst.resolveFull(ip); | 2052 | const info = base_node_inst.resolveFull(ip) orelse return null; |
| 2029 | break :inst .{ info.file, info.inst }; | 2053 | break :inst .{ info.file, info.inst }; |
| 2030 | }; | 2054 | }; |
| 2031 | const file = zcu.fileByIndex(file_index); | 2055 | const file = zcu.fileByIndex(file_index); |
| ... | @@ -2051,7 +2075,15 @@ pub const LazySrcLoc = struct { | ... | @@ -2051,7 +2075,15 @@ pub const LazySrcLoc = struct { |
| 2051 | /// Resolve the file and AST node of `base_node_inst` to get a resolved `SrcLoc`. | 2075 | /// Resolve the file and AST node of `base_node_inst` to get a resolved `SrcLoc`. |
| 2052 | /// The resulting `SrcLoc` should only be used ephemerally, as it is not correct across incremental updates. | 2076 | /// The resulting `SrcLoc` should only be used ephemerally, as it is not correct across incremental updates. |
| 2053 | pub fn upgrade(lazy: LazySrcLoc, zcu: *Zcu) SrcLoc { | 2077 | pub fn upgrade(lazy: LazySrcLoc, zcu: *Zcu) SrcLoc { |
| 2054 | const file, const base_node = resolveBaseNode(lazy.base_node_inst, zcu); | 2078 | return lazy.upgradeOrLost(zcu).?; |
| 2079 | } | ||
| 2080 | |||
| 2081 | /// Like `upgrade`, but returns `null` if the source location has been lost across incremental updates. | ||
| 2082 | pub fn upgradeOrLost(lazy: LazySrcLoc, zcu: *Zcu) ?SrcLoc { | ||
| 2083 | const file, const base_node: Ast.Node.Index = if (lazy.offset == .entire_file) .{ | ||
| 2084 | zcu.fileByIndex(lazy.base_node_inst.resolveFile(&zcu.intern_pool)), | ||
| 2085 | 0, | ||
| 2086 | } else resolveBaseNode(lazy.base_node_inst, zcu) orelse return null; | ||
| 2055 | return .{ | 2087 | return .{ |
| 2056 | .file_scope = file, | 2088 | .file_scope = file, |
| 2057 | .base_node = base_node, | 2089 | .base_node = base_node, |
| ... | @@ -2148,7 +2180,6 @@ pub fn deinit(zcu: *Zcu) void { | ... | @@ -2148,7 +2180,6 @@ pub fn deinit(zcu: *Zcu) void { |
| 2148 | zcu.potentially_outdated.deinit(gpa); | 2180 | zcu.potentially_outdated.deinit(gpa); |
| 2149 | zcu.outdated.deinit(gpa); | 2181 | zcu.outdated.deinit(gpa); |
| 2150 | zcu.outdated_ready.deinit(gpa); | 2182 | zcu.outdated_ready.deinit(gpa); |
| 2151 | zcu.outdated_file_root.deinit(gpa); | ||
| 2152 | zcu.retryable_failures.deinit(gpa); | 2183 | zcu.retryable_failures.deinit(gpa); |
| 2153 | 2184 | ||
| 2154 | zcu.test_functions.deinit(gpa); | 2185 | zcu.test_functions.deinit(gpa); |
| ... | @@ -2162,6 +2193,10 @@ pub fn deinit(zcu: *Zcu) void { | ... | @@ -2162,6 +2193,10 @@ pub fn deinit(zcu: *Zcu) void { |
| 2162 | zcu.all_references.deinit(gpa); | 2193 | zcu.all_references.deinit(gpa); |
| 2163 | zcu.free_references.deinit(gpa); | 2194 | zcu.free_references.deinit(gpa); |
| 2164 | 2195 | ||
| 2196 | zcu.type_reference_table.deinit(gpa); | ||
| 2197 | zcu.all_type_references.deinit(gpa); | ||
| 2198 | zcu.free_type_references.deinit(gpa); | ||
| 2199 | |||
| 2165 | zcu.intern_pool.deinit(gpa); | 2200 | zcu.intern_pool.deinit(gpa); |
| 2166 | } | 2201 | } |
| 2167 | 2202 | ||
| ... | @@ -2255,55 +2290,89 @@ pub fn loadZirCacheBody(gpa: Allocator, header: Zir.Header, cache_file: std.fs.F | ... | @@ -2255,55 +2290,89 @@ pub fn loadZirCacheBody(gpa: Allocator, header: Zir.Header, cache_file: std.fs.F |
| 2255 | return zir; | 2290 | return zir; |
| 2256 | } | 2291 | } |
| 2257 | 2292 | ||
| 2258 | pub fn markDependeeOutdated(zcu: *Zcu, dependee: InternPool.Dependee) !void { | 2293 | pub fn markDependeeOutdated( |
| 2259 | log.debug("outdated dependee: {}", .{dependee}); | 2294 | zcu: *Zcu, |
| 2295 | /// When we are diffing ZIR and marking things as outdated, we won't yet have marked the dependencies as PO. | ||
| 2296 | /// However, when we discover during analysis that something was outdated, the `Dependee` was already | ||
| 2297 | /// marked as PO, so we need to decrement the PO dep count for each depender. | ||
| 2298 | marked_po: enum { not_marked_po, marked_po }, | ||
| 2299 | dependee: InternPool.Dependee, | ||
| 2300 | ) !void { | ||
| 2301 | log.debug("outdated dependee: {}", .{zcu.fmtDependee(dependee)}); | ||
| 2260 | var it = zcu.intern_pool.dependencyIterator(dependee); | 2302 | var it = zcu.intern_pool.dependencyIterator(dependee); |
| 2261 | while (it.next()) |depender| { | 2303 | while (it.next()) |depender| { |
| 2262 | if (zcu.outdated.contains(depender)) { | 2304 | if (zcu.outdated.getPtr(depender)) |po_dep_count| { |
| 2263 | // We do not need to increment the PO dep count, as if the outdated | 2305 | switch (marked_po) { |
| 2264 | // dependee is a Decl, we had already marked this as PO. | 2306 | .not_marked_po => {}, |
| 2307 | .marked_po => { | ||
| 2308 | po_dep_count.* -= 1; | ||
| 2309 | log.debug("outdated {} => already outdated {} po_deps={}", .{ zcu.fmtDependee(dependee), zcu.fmtAnalUnit(depender), po_dep_count.* }); | ||
| 2310 | if (po_dep_count.* == 0) { | ||
| 2311 | log.debug("outdated ready: {}", .{zcu.fmtAnalUnit(depender)}); | ||
| 2312 | try zcu.outdated_ready.put(zcu.gpa, depender, {}); | ||
| 2313 | } | ||
| 2314 | }, | ||
| 2315 | } | ||
| 2265 | continue; | 2316 | continue; |
| 2266 | } | 2317 | } |
| 2267 | const opt_po_entry = zcu.potentially_outdated.fetchSwapRemove(depender); | 2318 | const opt_po_entry = zcu.potentially_outdated.fetchSwapRemove(depender); |
| 2319 | const new_po_dep_count = switch (marked_po) { | ||
| 2320 | .not_marked_po => if (opt_po_entry) |e| e.value else 0, | ||
| 2321 | .marked_po => if (opt_po_entry) |e| e.value - 1 else { | ||
| 2322 | // This `AnalUnit` has already been re-analyzed this update, and registered a dependency | ||
| 2323 | // on this thing, but already has sufficiently up-to-date information. Nothing to do. | ||
| 2324 | continue; | ||
| 2325 | }, | ||
| 2326 | }; | ||
| 2268 | try zcu.outdated.putNoClobber( | 2327 | try zcu.outdated.putNoClobber( |
| 2269 | zcu.gpa, | 2328 | zcu.gpa, |
| 2270 | depender, | 2329 | depender, |
| 2271 | // We do not need to increment this count for the same reason as above. | 2330 | new_po_dep_count, |
| 2272 | if (opt_po_entry) |e| e.value else 0, | ||
| 2273 | ); | 2331 | ); |
| 2274 | log.debug("outdated: {}", .{depender}); | 2332 | log.debug("outdated {} => new outdated {} po_deps={}", .{ zcu.fmtDependee(dependee), zcu.fmtAnalUnit(depender), new_po_dep_count }); |
| 2275 | if (opt_po_entry == null) { | 2333 | if (new_po_dep_count == 0) { |
| 2276 | // This is a new entry with no PO dependencies. | 2334 | log.debug("outdated ready: {}", .{zcu.fmtAnalUnit(depender)}); |
| 2277 | try zcu.outdated_ready.put(zcu.gpa, depender, {}); | 2335 | try zcu.outdated_ready.put(zcu.gpa, depender, {}); |
| 2278 | } | 2336 | } |
| 2279 | // If this is a Decl and was not previously PO, we must recursively | 2337 | // If this is a Decl and was not previously PO, we must recursively |
| 2280 | // mark dependencies on its tyval as PO. | 2338 | // mark dependencies on its tyval as PO. |
| 2281 | if (opt_po_entry == null) { | 2339 | if (opt_po_entry == null) { |
| 2340 | assert(marked_po == .not_marked_po); | ||
| 2282 | try zcu.markTransitiveDependersPotentiallyOutdated(depender); | 2341 | try zcu.markTransitiveDependersPotentiallyOutdated(depender); |
| 2283 | } | 2342 | } |
| 2284 | } | 2343 | } |
| 2285 | } | 2344 | } |
| 2286 | 2345 | ||
| 2287 | pub fn markPoDependeeUpToDate(zcu: *Zcu, dependee: InternPool.Dependee) !void { | 2346 | pub fn markPoDependeeUpToDate(zcu: *Zcu, dependee: InternPool.Dependee) !void { |
| 2347 | log.debug("up-to-date dependee: {}", .{zcu.fmtDependee(dependee)}); | ||
| 2288 | var it = zcu.intern_pool.dependencyIterator(dependee); | 2348 | var it = zcu.intern_pool.dependencyIterator(dependee); |
| 2289 | while (it.next()) |depender| { | 2349 | while (it.next()) |depender| { |
| 2290 | if (zcu.outdated.getPtr(depender)) |po_dep_count| { | 2350 | if (zcu.outdated.getPtr(depender)) |po_dep_count| { |
| 2291 | // This depender is already outdated, but it now has one | 2351 | // This depender is already outdated, but it now has one |
| 2292 | // less PO dependency! | 2352 | // less PO dependency! |
| 2293 | po_dep_count.* -= 1; | 2353 | po_dep_count.* -= 1; |
| 2354 | log.debug("up-to-date {} => {} po_deps={}", .{ zcu.fmtDependee(dependee), zcu.fmtAnalUnit(depender), po_dep_count.* }); | ||
| 2294 | if (po_dep_count.* == 0) { | 2355 | if (po_dep_count.* == 0) { |
| 2356 | log.debug("outdated ready: {}", .{zcu.fmtAnalUnit(depender)}); | ||
| 2295 | try zcu.outdated_ready.put(zcu.gpa, depender, {}); | 2357 | try zcu.outdated_ready.put(zcu.gpa, depender, {}); |
| 2296 | } | 2358 | } |
| 2297 | continue; | 2359 | continue; |
| 2298 | } | 2360 | } |
| 2299 | // This depender is definitely at least PO, because this Decl was just analyzed | 2361 | // This depender is definitely at least PO, because this Decl was just analyzed |
| 2300 | // due to being outdated. | 2362 | // due to being outdated. |
| 2301 | const ptr = zcu.potentially_outdated.getPtr(depender).?; | 2363 | const ptr = zcu.potentially_outdated.getPtr(depender) orelse { |
| 2364 | // This dependency has been registered during in-progress analysis, but the unit is | ||
| 2365 | // not in `potentially_outdated` because analysis is in-progress. Nothing to do. | ||
| 2366 | continue; | ||
| 2367 | }; | ||
| 2302 | if (ptr.* > 1) { | 2368 | if (ptr.* > 1) { |
| 2303 | ptr.* -= 1; | 2369 | ptr.* -= 1; |
| 2370 | log.debug("up-to-date {} => {} po_deps={}", .{ zcu.fmtDependee(dependee), zcu.fmtAnalUnit(depender), ptr.* }); | ||
| 2304 | continue; | 2371 | continue; |
| 2305 | } | 2372 | } |
| 2306 | 2373 | ||
| 2374 | log.debug("up-to-date {} => {} po_deps=0 (up-to-date)", .{ zcu.fmtDependee(dependee), zcu.fmtAnalUnit(depender) }); | ||
| 2375 | |||
| 2307 | // This dependency is no longer PO, i.e. is known to be up-to-date. | 2376 | // This dependency is no longer PO, i.e. is known to be up-to-date. |
| 2308 | assert(zcu.potentially_outdated.swapRemove(depender)); | 2377 | assert(zcu.potentially_outdated.swapRemove(depender)); |
| 2309 | // If this is a Decl, we must recursively mark dependencies on its tyval | 2378 | // If this is a Decl, we must recursively mark dependencies on its tyval |
| ... | @@ -2323,14 +2392,16 @@ pub fn markPoDependeeUpToDate(zcu: *Zcu, dependee: InternPool.Dependee) !void { | ... | @@ -2323,14 +2392,16 @@ pub fn markPoDependeeUpToDate(zcu: *Zcu, dependee: InternPool.Dependee) !void { |
| 2323 | /// in turn be PO, due to a dependency on the original AnalUnit's tyval or IES. | 2392 | /// in turn be PO, due to a dependency on the original AnalUnit's tyval or IES. |
| 2324 | fn markTransitiveDependersPotentiallyOutdated(zcu: *Zcu, maybe_outdated: AnalUnit) !void { | 2393 | fn markTransitiveDependersPotentiallyOutdated(zcu: *Zcu, maybe_outdated: AnalUnit) !void { |
| 2325 | const ip = &zcu.intern_pool; | 2394 | const ip = &zcu.intern_pool; |
| 2326 | var it = ip.dependencyIterator(switch (maybe_outdated.unwrap()) { | 2395 | const dependee: InternPool.Dependee = switch (maybe_outdated.unwrap()) { |
| 2327 | .cau => |cau| switch (ip.getCau(cau).owner.unwrap()) { | 2396 | .cau => |cau| switch (ip.getCau(cau).owner.unwrap()) { |
| 2328 | .nav => |nav| .{ .nav_val = nav }, // TODO: also `nav_ref` deps when introduced | 2397 | .nav => |nav| .{ .nav_val = nav }, // TODO: also `nav_ref` deps when introduced |
| 2329 | .none, .type => return, // analysis of this `Cau` can't outdate any dependencies | 2398 | .type => |ty| .{ .interned = ty }, |
| 2399 | .none => return, // analysis of this `Cau` can't outdate any dependencies | ||
| 2330 | }, | 2400 | }, |
| 2331 | .func => |func_index| .{ .interned = func_index }, // IES | 2401 | .func => |func_index| .{ .interned = func_index }, // IES |
| 2332 | }); | 2402 | }; |
| 2333 | 2403 | log.debug("potentially outdated dependee: {}", .{zcu.fmtDependee(dependee)}); | |
| 2404 | var it = ip.dependencyIterator(dependee); | ||
| 2334 | while (it.next()) |po| { | 2405 | while (it.next()) |po| { |
| 2335 | if (zcu.outdated.getPtr(po)) |po_dep_count| { | 2406 | if (zcu.outdated.getPtr(po)) |po_dep_count| { |
| 2336 | // This dependency is already outdated, but it now has one more PO | 2407 | // This dependency is already outdated, but it now has one more PO |
| ... | @@ -2339,14 +2410,17 @@ fn markTransitiveDependersPotentiallyOutdated(zcu: *Zcu, maybe_outdated: AnalUni | ... | @@ -2339,14 +2410,17 @@ fn markTransitiveDependersPotentiallyOutdated(zcu: *Zcu, maybe_outdated: AnalUni |
| 2339 | _ = zcu.outdated_ready.swapRemove(po); | 2410 | _ = zcu.outdated_ready.swapRemove(po); |
| 2340 | } | 2411 | } |
| 2341 | po_dep_count.* += 1; | 2412 | po_dep_count.* += 1; |
| 2413 | log.debug("po {} => {} [outdated] po_deps={}", .{ zcu.fmtDependee(dependee), zcu.fmtAnalUnit(po), po_dep_count.* }); | ||
| 2342 | continue; | 2414 | continue; |
| 2343 | } | 2415 | } |
| 2344 | if (zcu.potentially_outdated.getPtr(po)) |n| { | 2416 | if (zcu.potentially_outdated.getPtr(po)) |n| { |
| 2345 | // There is now one more PO dependency. | 2417 | // There is now one more PO dependency. |
| 2346 | n.* += 1; | 2418 | n.* += 1; |
| 2419 | log.debug("po {} => {} po_deps={}", .{ zcu.fmtDependee(dependee), zcu.fmtAnalUnit(po), n.* }); | ||
| 2347 | continue; | 2420 | continue; |
| 2348 | } | 2421 | } |
| 2349 | try zcu.potentially_outdated.putNoClobber(zcu.gpa, po, 1); | 2422 | try zcu.potentially_outdated.putNoClobber(zcu.gpa, po, 1); |
| 2423 | log.debug("po {} => {} po_deps=1", .{ zcu.fmtDependee(dependee), zcu.fmtAnalUnit(po) }); | ||
| 2350 | // This AnalUnit was not already PO, so we must recursively mark its dependers as also PO. | 2424 | // This AnalUnit was not already PO, so we must recursively mark its dependers as also PO. |
| 2351 | try zcu.markTransitiveDependersPotentiallyOutdated(po); | 2425 | try zcu.markTransitiveDependersPotentiallyOutdated(po); |
| 2352 | } | 2426 | } |
| ... | @@ -2355,9 +2429,11 @@ fn markTransitiveDependersPotentiallyOutdated(zcu: *Zcu, maybe_outdated: AnalUni | ... | @@ -2355,9 +2429,11 @@ fn markTransitiveDependersPotentiallyOutdated(zcu: *Zcu, maybe_outdated: AnalUni |
| 2355 | pub fn findOutdatedToAnalyze(zcu: *Zcu) Allocator.Error!?AnalUnit { | 2429 | pub fn findOutdatedToAnalyze(zcu: *Zcu) Allocator.Error!?AnalUnit { |
| 2356 | if (!zcu.comp.incremental) return null; | 2430 | if (!zcu.comp.incremental) return null; |
| 2357 | 2431 | ||
| 2358 | if (true) @panic("TODO: findOutdatedToAnalyze"); | 2432 | if (zcu.outdated.count() == 0) { |
| 2359 | 2433 | // Any units in `potentially_outdated` must just be stuck in loops with one another: none of those | |
| 2360 | if (zcu.outdated.count() == 0 and zcu.potentially_outdated.count() == 0) { | 2434 | // units have had any outdated dependencies so far, and all of their remaining PO deps are triggered |
| 2435 | // by other units in `potentially_outdated`. So, we can safety assume those units up-to-date. | ||
| 2436 | zcu.potentially_outdated.clearRetainingCapacity(); | ||
| 2361 | log.debug("findOutdatedToAnalyze: no outdated depender", .{}); | 2437 | log.debug("findOutdatedToAnalyze: no outdated depender", .{}); |
| 2362 | return null; | 2438 | return null; |
| 2363 | } | 2439 | } |
| ... | @@ -2372,96 +2448,75 @@ pub fn findOutdatedToAnalyze(zcu: *Zcu) Allocator.Error!?AnalUnit { | ... | @@ -2372,96 +2448,75 @@ pub fn findOutdatedToAnalyze(zcu: *Zcu) Allocator.Error!?AnalUnit { |
| 2372 | // In this case, we must defer to more complex logic below. | 2448 | // In this case, we must defer to more complex logic below. |
| 2373 | 2449 | ||
| 2374 | if (zcu.outdated_ready.count() > 0) { | 2450 | if (zcu.outdated_ready.count() > 0) { |
| 2375 | log.debug("findOutdatedToAnalyze: trivial '{s} {d}'", .{ | 2451 | const unit = zcu.outdated_ready.keys()[0]; |
| 2376 | @tagName(zcu.outdated_ready.keys()[0].unwrap()), | 2452 | log.debug("findOutdatedToAnalyze: trivial {}", .{zcu.fmtAnalUnit(unit)}); |
| 2377 | switch (zcu.outdated_ready.keys()[0].unwrap()) { | 2453 | return unit; |
| 2378 | inline else => |x| @intFromEnum(x), | ||
| 2379 | }, | ||
| 2380 | }); | ||
| 2381 | return zcu.outdated_ready.keys()[0]; | ||
| 2382 | } | 2454 | } |
| 2383 | 2455 | ||
| 2384 | // Next, we will see if there is any outdated file root which was not in | 2456 | // There is no single AnalUnit which is ready for re-analysis. Instead, we must assume that some |
| 2385 | // `outdated`. This set will be small (number of files changed in this | 2457 | // Cau with PO dependencies is outdated -- e.g. in the above example we arbitrarily pick one of |
| 2386 | // update), so it's alright for us to just iterate here. | 2458 | // A or B. We should select a Cau, since a Cau is definitely responsible for the loop in the |
| 2387 | for (zcu.outdated_file_root.keys()) |file_decl| { | 2459 | // dependency graph (since IES dependencies can't have loops). We should also, of course, not |
| 2388 | const decl_depender = AnalUnit.wrap(.{ .decl = file_decl }); | 2460 | // select a Cau owned by a `comptime` declaration, since you can't depend on those! |
| 2389 | if (zcu.outdated.contains(decl_depender)) { | ||
| 2390 | // Since we didn't hit this in the first loop, this Decl must have | ||
| 2391 | // pending dependencies, so is ineligible. | ||
| 2392 | continue; | ||
| 2393 | } | ||
| 2394 | if (zcu.potentially_outdated.contains(decl_depender)) { | ||
| 2395 | // This Decl's struct may or may not need to be recreated depending | ||
| 2396 | // on whether it is outdated. If we analyzed it now, we would have | ||
| 2397 | // to assume it was outdated and recreate it! | ||
| 2398 | continue; | ||
| 2399 | } | ||
| 2400 | log.debug("findOutdatedToAnalyze: outdated file root decl '{d}'", .{file_decl}); | ||
| 2401 | return decl_depender; | ||
| 2402 | } | ||
| 2403 | |||
| 2404 | // There is no single AnalUnit which is ready for re-analysis. Instead, we | ||
| 2405 | // must assume that some Decl with PO dependencies is outdated - e.g. in the | ||
| 2406 | // above example we arbitrarily pick one of A or B. We should select a Decl, | ||
| 2407 | // since a Decl is definitely responsible for the loop in the dependency | ||
| 2408 | // graph (since you can't depend on a runtime function analysis!). | ||
| 2409 | 2461 | ||
| 2410 | // The choice of this Decl could have a big impact on how much total | 2462 | // The choice of this Cau could have a big impact on how much total analysis we perform, since |
| 2411 | // analysis we perform, since if analysis concludes its tyval is unchanged, | 2463 | // if analysis concludes any dependencies on its result are up-to-date, then other PO AnalUnit |
| 2412 | // then other PO AnalUnit may be resolved as up-to-date. To hopefully avoid | 2464 | // may be resolved as up-to-date. To hopefully avoid doing too much work, let's find a Decl |
| 2413 | // doing too much work, let's find a Decl which the most things depend on - | 2465 | // which the most things depend on - the idea is that this will resolve a lot of loops (but this |
| 2414 | // the idea is that this will resolve a lot of loops (but this is only a | 2466 | // is only a heuristic). |
| 2415 | // heuristic). | ||
| 2416 | 2467 | ||
| 2417 | log.debug("findOutdatedToAnalyze: no trivial ready, using heuristic; {d} outdated, {d} PO", .{ | 2468 | log.debug("findOutdatedToAnalyze: no trivial ready, using heuristic; {d} outdated, {d} PO", .{ |
| 2418 | zcu.outdated.count(), | 2469 | zcu.outdated.count(), |
| 2419 | zcu.potentially_outdated.count(), | 2470 | zcu.potentially_outdated.count(), |
| 2420 | }); | 2471 | }); |
| 2421 | 2472 | ||
| 2422 | const Decl = {}; | 2473 | const ip = &zcu.intern_pool; |
| 2423 | 2474 | ||
| 2424 | var chosen_decl_idx: ?Decl.Index = null; | 2475 | var chosen_cau: ?InternPool.Cau.Index = null; |
| 2425 | var chosen_decl_dependers: u32 = undefined; | 2476 | var chosen_cau_dependers: u32 = undefined; |
| 2426 | 2477 | ||
| 2427 | for (zcu.outdated.keys()) |depender| { | 2478 | inline for (.{ zcu.outdated.keys(), zcu.potentially_outdated.keys() }) |outdated_units| { |
| 2428 | const decl_index = switch (depender.unwrap()) { | 2479 | for (outdated_units) |unit| { |
| 2429 | .decl => |d| d, | 2480 | const cau = switch (unit.unwrap()) { |
| 2430 | .func => continue, | 2481 | .cau => |cau| cau, |
| 2431 | }; | 2482 | .func => continue, // a `func` definitely can't be causing the loop so it is a bad choice |
| 2483 | }; | ||
| 2484 | const cau_owner = ip.getCau(cau).owner; | ||
| 2432 | 2485 | ||
| 2433 | var n: u32 = 0; | 2486 | var n: u32 = 0; |
| 2434 | var it = zcu.intern_pool.dependencyIterator(.{ .decl_val = decl_index }); | 2487 | var it = ip.dependencyIterator(switch (cau_owner.unwrap()) { |
| 2435 | while (it.next()) |_| n += 1; | 2488 | .none => continue, // there can be no dependencies on this `Cau` so it is a terrible choice |
| 2489 | .type => |ty| .{ .interned = ty }, | ||
| 2490 | .nav => |nav| .{ .nav_val = nav }, | ||
| 2491 | }); | ||
| 2492 | while (it.next()) |_| n += 1; | ||
| 2436 | 2493 | ||
| 2437 | if (chosen_decl_idx == null or n > chosen_decl_dependers) { | 2494 | if (chosen_cau == null or n > chosen_cau_dependers) { |
| 2438 | chosen_decl_idx = decl_index; | 2495 | chosen_cau = cau; |
| 2439 | chosen_decl_dependers = n; | 2496 | chosen_cau_dependers = n; |
| 2497 | } | ||
| 2440 | } | 2498 | } |
| 2441 | } | 2499 | } |
| 2442 | 2500 | ||
| 2443 | for (zcu.potentially_outdated.keys()) |depender| { | 2501 | if (chosen_cau == null) { |
| 2444 | const decl_index = switch (depender.unwrap()) { | 2502 | for (zcu.outdated.keys(), zcu.outdated.values()) |o, opod| { |
| 2445 | .decl => |d| d, | 2503 | const func = o.unwrap().func; |
| 2446 | .func => continue, | 2504 | const nav = zcu.funcInfo(func).owner_nav; |
| 2447 | }; | 2505 | std.io.getStdErr().writer().print("outdated: func {}, nav {}, name '{}', [p]o deps {}\n", .{ func, nav, ip.getNav(nav).fqn.fmt(ip), opod }) catch {}; |
| 2448 | 2506 | } | |
| 2449 | var n: u32 = 0; | 2507 | for (zcu.potentially_outdated.keys(), zcu.potentially_outdated.values()) |o, opod| { |
| 2450 | var it = zcu.intern_pool.dependencyIterator(.{ .decl_val = decl_index }); | 2508 | const func = o.unwrap().func; |
| 2451 | while (it.next()) |_| n += 1; | 2509 | const nav = zcu.funcInfo(func).owner_nav; |
| 2452 | 2510 | std.io.getStdErr().writer().print("po: func {}, nav {}, name '{}', [p]o deps {}\n", .{ func, nav, ip.getNav(nav).fqn.fmt(ip), opod }) catch {}; | |
| 2453 | if (chosen_decl_idx == null or n > chosen_decl_dependers) { | ||
| 2454 | chosen_decl_idx = decl_index; | ||
| 2455 | chosen_decl_dependers = n; | ||
| 2456 | } | 2511 | } |
| 2457 | } | 2512 | } |
| 2458 | 2513 | ||
| 2459 | log.debug("findOutdatedToAnalyze: heuristic returned Decl {d} ({d} dependers)", .{ | 2514 | log.debug("findOutdatedToAnalyze: heuristic returned '{}' ({d} dependers)", .{ |
| 2460 | chosen_decl_idx.?, | 2515 | zcu.fmtAnalUnit(AnalUnit.wrap(.{ .cau = chosen_cau.? })), |
| 2461 | chosen_decl_dependers, | 2516 | chosen_cau_dependers, |
| 2462 | }); | 2517 | }); |
| 2463 | 2518 | ||
| 2464 | return AnalUnit.wrap(.{ .decl = chosen_decl_idx.? }); | 2519 | return AnalUnit.wrap(.{ .cau = chosen_cau.? }); |
| 2465 | } | 2520 | } |
| 2466 | 2521 | ||
| 2467 | /// During an incremental update, before semantic analysis, call this to flush all values from | 2522 | /// During an incremental update, before semantic analysis, call this to flush all values from |
| ... | @@ -2506,10 +2561,10 @@ pub fn mapOldZirToNew( | ... | @@ -2506,10 +2561,10 @@ pub fn mapOldZirToNew( |
| 2506 | }); | 2561 | }); |
| 2507 | 2562 | ||
| 2508 | // Used as temporary buffers for namespace declaration instructions | 2563 | // Used as temporary buffers for namespace declaration instructions |
| 2509 | var old_decls = std.ArrayList(Zir.Inst.Index).init(gpa); | 2564 | var old_decls: std.ArrayListUnmanaged(Zir.Inst.Index) = .{}; |
| 2510 | defer old_decls.deinit(); | 2565 | defer old_decls.deinit(gpa); |
| 2511 | var new_decls = std.ArrayList(Zir.Inst.Index).init(gpa); | 2566 | var new_decls: std.ArrayListUnmanaged(Zir.Inst.Index) = .{}; |
| 2512 | defer new_decls.deinit(); | 2567 | defer new_decls.deinit(gpa); |
| 2513 | 2568 | ||
| 2514 | while (match_stack.popOrNull()) |match_item| { | 2569 | while (match_stack.popOrNull()) |match_item| { |
| 2515 | // Match the namespace declaration itself | 2570 | // Match the namespace declaration itself |
| ... | @@ -2583,7 +2638,7 @@ pub fn mapOldZirToNew( | ... | @@ -2583,7 +2638,7 @@ pub fn mapOldZirToNew( |
| 2583 | break :inst unnamed_tests.items[unnamed_test_idx]; | 2638 | break :inst unnamed_tests.items[unnamed_test_idx]; |
| 2584 | }, | 2639 | }, |
| 2585 | _ => inst: { | 2640 | _ => inst: { |
| 2586 | const name_nts = new_decl.name.toString(old_zir).?; | 2641 | const name_nts = new_decl.name.toString(new_zir).?; |
| 2587 | const name = new_zir.nullTerminatedString(name_nts); | 2642 | const name = new_zir.nullTerminatedString(name_nts); |
| 2588 | if (new_decl.name.isNamedTest(new_zir)) { | 2643 | if (new_decl.name.isNamedTest(new_zir)) { |
| 2589 | break :inst named_tests.get(name) orelse continue; | 2644 | break :inst named_tests.get(name) orelse continue; |
| ... | @@ -2596,11 +2651,11 @@ pub fn mapOldZirToNew( | ... | @@ -2596,11 +2651,11 @@ pub fn mapOldZirToNew( |
| 2596 | // Match the `declaration` instruction | 2651 | // Match the `declaration` instruction |
| 2597 | try inst_map.put(gpa, old_decl_inst, new_decl_inst); | 2652 | try inst_map.put(gpa, old_decl_inst, new_decl_inst); |
| 2598 | 2653 | ||
| 2599 | // Find namespace declarations within this declaration | 2654 | // Find container type declarations within this declaration |
| 2600 | try old_zir.findDecls(&old_decls, old_decl_inst); | 2655 | try old_zir.findDecls(gpa, &old_decls, old_decl_inst); |
| 2601 | try new_zir.findDecls(&new_decls, new_decl_inst); | 2656 | try new_zir.findDecls(gpa, &new_decls, new_decl_inst); |
| 2602 | 2657 | ||
| 2603 | // We don't have any smart way of matching up these namespace declarations, so we always | 2658 | // We don't have any smart way of matching up these type declarations, so we always |
| 2604 | // correlate them based on source order. | 2659 | // correlate them based on source order. |
| 2605 | const n = @min(old_decls.items.len, new_decls.items.len); | 2660 | const n = @min(old_decls.items.len, new_decls.items.len); |
| 2606 | try match_stack.ensureUnusedCapacity(gpa, n); | 2661 | try match_stack.ensureUnusedCapacity(gpa, n); |
| ... | @@ -2699,16 +2754,32 @@ pub fn deleteUnitExports(zcu: *Zcu, anal_unit: AnalUnit) void { | ... | @@ -2699,16 +2754,32 @@ pub fn deleteUnitExports(zcu: *Zcu, anal_unit: AnalUnit) void { |
| 2699 | pub fn deleteUnitReferences(zcu: *Zcu, anal_unit: AnalUnit) void { | 2754 | pub fn deleteUnitReferences(zcu: *Zcu, anal_unit: AnalUnit) void { |
| 2700 | const gpa = zcu.gpa; | 2755 | const gpa = zcu.gpa; |
| 2701 | 2756 | ||
| 2702 | const kv = zcu.reference_table.fetchSwapRemove(anal_unit) orelse return; | 2757 | unit_refs: { |
| 2703 | var idx = kv.value; | 2758 | const kv = zcu.reference_table.fetchSwapRemove(anal_unit) orelse break :unit_refs; |
| 2759 | var idx = kv.value; | ||
| 2704 | 2760 | ||
| 2705 | while (idx != std.math.maxInt(u32)) { | 2761 | while (idx != std.math.maxInt(u32)) { |
| 2706 | zcu.free_references.append(gpa, idx) catch { | 2762 | zcu.free_references.append(gpa, idx) catch { |
| 2707 | // This space will be reused eventually, so we need not propagate this error. | 2763 | // This space will be reused eventually, so we need not propagate this error. |
| 2708 | // Just leak it for now, and let GC reclaim it later on. | 2764 | // Just leak it for now, and let GC reclaim it later on. |
| 2709 | return; | 2765 | break :unit_refs; |
| 2710 | }; | 2766 | }; |
| 2711 | idx = zcu.all_references.items[idx].next; | 2767 | idx = zcu.all_references.items[idx].next; |
| 2768 | } | ||
| 2769 | } | ||
| 2770 | |||
| 2771 | type_refs: { | ||
| 2772 | const kv = zcu.type_reference_table.fetchSwapRemove(anal_unit) orelse break :type_refs; | ||
| 2773 | var idx = kv.value; | ||
| 2774 | |||
| 2775 | while (idx != std.math.maxInt(u32)) { | ||
| 2776 | zcu.free_type_references.append(gpa, idx) catch { | ||
| 2777 | // This space will be reused eventually, so we need not propagate this error. | ||
| 2778 | // Just leak it for now, and let GC reclaim it later on. | ||
| 2779 | break :type_refs; | ||
| 2780 | }; | ||
| 2781 | idx = zcu.all_type_references.items[idx].next; | ||
| 2782 | } | ||
| 2712 | } | 2783 | } |
| 2713 | } | 2784 | } |
| 2714 | 2785 | ||
| ... | @@ -2735,6 +2806,29 @@ pub fn addUnitReference(zcu: *Zcu, src_unit: AnalUnit, referenced_unit: AnalUnit | ... | @@ -2735,6 +2806,29 @@ pub fn addUnitReference(zcu: *Zcu, src_unit: AnalUnit, referenced_unit: AnalUnit |
| 2735 | gop.value_ptr.* = @intCast(ref_idx); | 2806 | gop.value_ptr.* = @intCast(ref_idx); |
| 2736 | } | 2807 | } |
| 2737 | 2808 | ||
| 2809 | pub fn addTypeReference(zcu: *Zcu, src_unit: AnalUnit, referenced_type: InternPool.Index, ref_src: LazySrcLoc) Allocator.Error!void { | ||
| 2810 | const gpa = zcu.gpa; | ||
| 2811 | |||
| 2812 | try zcu.type_reference_table.ensureUnusedCapacity(gpa, 1); | ||
| 2813 | |||
| 2814 | const ref_idx = zcu.free_type_references.popOrNull() orelse idx: { | ||
| 2815 | _ = try zcu.all_type_references.addOne(gpa); | ||
| 2816 | break :idx zcu.all_type_references.items.len - 1; | ||
| 2817 | }; | ||
| 2818 | |||
| 2819 | errdefer comptime unreachable; | ||
| 2820 | |||
| 2821 | const gop = zcu.type_reference_table.getOrPutAssumeCapacity(src_unit); | ||
| 2822 | |||
| 2823 | zcu.all_type_references.items[ref_idx] = .{ | ||
| 2824 | .referenced = referenced_type, | ||
| 2825 | .next = if (gop.found_existing) gop.value_ptr.* else std.math.maxInt(u32), | ||
| 2826 | .src = ref_src, | ||
| 2827 | }; | ||
| 2828 | |||
| 2829 | gop.value_ptr.* = @intCast(ref_idx); | ||
| 2830 | } | ||
| 2831 | |||
| 2738 | pub fn errorSetBits(mod: *Zcu) u16 { | 2832 | pub fn errorSetBits(mod: *Zcu) u16 { |
| 2739 | if (mod.error_limit == 0) return 0; | 2833 | if (mod.error_limit == 0) return 0; |
| 2740 | return @as(u16, std.math.log2_int(ErrorInt, mod.error_limit)) + 1; | 2834 | return @as(u16, std.math.log2_int(ErrorInt, mod.error_limit)) + 1; |
| ... | @@ -3029,28 +3123,215 @@ pub const ResolvedReference = struct { | ... | @@ -3029,28 +3123,215 @@ pub const ResolvedReference = struct { |
| 3029 | }; | 3123 | }; |
| 3030 | 3124 | ||
| 3031 | /// Returns a mapping from an `AnalUnit` to where it is referenced. | 3125 | /// Returns a mapping from an `AnalUnit` to where it is referenced. |
| 3032 | /// TODO: in future, this must be adapted to traverse from roots of analysis. That way, we can | 3126 | /// If the value is `null`, the `AnalUnit` is a root of analysis. |
| 3033 | /// use the returned map to determine which units have become unreferenced in an incremental update. | 3127 | /// If an `AnalUnit` is not in the returned map, it is unreferenced. |
| 3034 | pub fn resolveReferences(zcu: *Zcu) !std.AutoHashMapUnmanaged(AnalUnit, ResolvedReference) { | 3128 | pub fn resolveReferences(zcu: *Zcu) !std.AutoHashMapUnmanaged(AnalUnit, ?ResolvedReference) { |
| 3035 | const gpa = zcu.gpa; | 3129 | const gpa = zcu.gpa; |
| 3130 | const comp = zcu.comp; | ||
| 3131 | const ip = &zcu.intern_pool; | ||
| 3036 | 3132 | ||
| 3037 | var result: std.AutoHashMapUnmanaged(AnalUnit, ResolvedReference) = .{}; | 3133 | var result: std.AutoHashMapUnmanaged(AnalUnit, ?ResolvedReference) = .{}; |
| 3038 | errdefer result.deinit(gpa); | 3134 | errdefer result.deinit(gpa); |
| 3039 | 3135 | ||
| 3136 | var checked_types: std.AutoArrayHashMapUnmanaged(InternPool.Index, void) = .{}; | ||
| 3137 | var type_queue: std.AutoArrayHashMapUnmanaged(InternPool.Index, ?ResolvedReference) = .{}; | ||
| 3138 | var unit_queue: std.AutoArrayHashMapUnmanaged(AnalUnit, ?ResolvedReference) = .{}; | ||
| 3139 | defer { | ||
| 3140 | checked_types.deinit(gpa); | ||
| 3141 | type_queue.deinit(gpa); | ||
| 3142 | unit_queue.deinit(gpa); | ||
| 3143 | } | ||
| 3144 | |||
| 3040 | // This is not a sufficient size, but a lower bound. | 3145 | // This is not a sufficient size, but a lower bound. |
| 3041 | try result.ensureTotalCapacity(gpa, @intCast(zcu.reference_table.count())); | 3146 | try result.ensureTotalCapacity(gpa, @intCast(zcu.reference_table.count())); |
| 3042 | 3147 | ||
| 3043 | for (zcu.reference_table.keys(), zcu.reference_table.values()) |referencer, first_ref_idx| { | 3148 | try type_queue.ensureTotalCapacity(gpa, zcu.analysis_roots.len); |
| 3044 | assert(first_ref_idx != std.math.maxInt(u32)); | 3149 | for (zcu.analysis_roots.slice()) |mod| { |
| 3045 | var ref_idx = first_ref_idx; | 3150 | // Logic ripped from `Zcu.PerThread.importPkg`. |
| 3046 | while (ref_idx != std.math.maxInt(u32)) { | 3151 | // TODO: this is silly, `Module` should just store a reference to its root `File`. |
| 3047 | const ref = zcu.all_references.items[ref_idx]; | 3152 | const resolved_path = try std.fs.path.resolve(gpa, &.{ |
| 3048 | const gop = try result.getOrPut(gpa, ref.referenced); | 3153 | mod.root.root_dir.path orelse ".", |
| 3049 | if (!gop.found_existing) { | 3154 | mod.root.sub_path, |
| 3050 | gop.value_ptr.* = .{ .referencer = referencer, .src = ref.src }; | 3155 | mod.root_src_path, |
| 3156 | }); | ||
| 3157 | defer gpa.free(resolved_path); | ||
| 3158 | const file = zcu.import_table.get(resolved_path).?; | ||
| 3159 | const root_ty = zcu.fileRootType(file); | ||
| 3160 | if (root_ty == .none) continue; | ||
| 3161 | type_queue.putAssumeCapacityNoClobber(root_ty, null); | ||
| 3162 | } | ||
| 3163 | |||
| 3164 | while (true) { | ||
| 3165 | if (type_queue.popOrNull()) |kv| { | ||
| 3166 | const ty = kv.key; | ||
| 3167 | const referencer = kv.value; | ||
| 3168 | try checked_types.putNoClobber(gpa, ty, {}); | ||
| 3169 | |||
| 3170 | log.debug("handle type '{}'", .{Type.fromInterned(ty).containerTypeName(ip).fmt(ip)}); | ||
| 3171 | |||
| 3172 | // If this type has a `Cau` for resolution, it's automatically referenced. | ||
| 3173 | const resolution_cau: InternPool.Cau.Index.Optional = switch (ip.indexToKey(ty)) { | ||
| 3174 | .struct_type => ip.loadStructType(ty).cau, | ||
| 3175 | .union_type => ip.loadUnionType(ty).cau.toOptional(), | ||
| 3176 | .enum_type => ip.loadEnumType(ty).cau, | ||
| 3177 | .opaque_type => .none, | ||
| 3178 | else => unreachable, | ||
| 3179 | }; | ||
| 3180 | if (resolution_cau.unwrap()) |cau| { | ||
| 3181 | // this should only be referenced by the type | ||
| 3182 | const unit = AnalUnit.wrap(.{ .cau = cau }); | ||
| 3183 | assert(!result.contains(unit)); | ||
| 3184 | try unit_queue.putNoClobber(gpa, unit, referencer); | ||
| 3185 | } | ||
| 3186 | |||
| 3187 | // If this is a union with a generated tag, its tag type is automatically referenced. | ||
| 3188 | // We don't add this reference for non-generated tags, as those will already be referenced via the union's `Cau`, with a better source location. | ||
| 3189 | if (zcu.typeToUnion(Type.fromInterned(ty))) |union_obj| { | ||
| 3190 | const tag_ty = union_obj.enum_tag_ty; | ||
| 3191 | if (tag_ty != .none) { | ||
| 3192 | if (ip.indexToKey(tag_ty).enum_type == .generated_tag) { | ||
| 3193 | if (!checked_types.contains(tag_ty)) { | ||
| 3194 | try type_queue.put(gpa, tag_ty, referencer); | ||
| 3195 | } | ||
| 3196 | } | ||
| 3197 | } | ||
| 3198 | } | ||
| 3199 | |||
| 3200 | // Queue any decls within this type which would be automatically analyzed. | ||
| 3201 | // Keep in sync with analysis queueing logic in `Zcu.PerThread.ScanDeclIter.scanDecl`. | ||
| 3202 | const ns = Type.fromInterned(ty).getNamespace(zcu).unwrap().?; | ||
| 3203 | for (zcu.namespacePtr(ns).other_decls.items) |cau| { | ||
| 3204 | // These are `comptime` and `test` declarations. | ||
| 3205 | // `comptime` decls are always analyzed; `test` declarations are analyzed depending on the test filter. | ||
| 3206 | const inst_info = ip.getCau(cau).zir_index.resolveFull(ip) orelse continue; | ||
| 3207 | const file = zcu.fileByIndex(inst_info.file); | ||
| 3208 | // If the file failed AstGen, the TrackedInst refers to the old ZIR. | ||
| 3209 | const zir = if (file.status == .success_zir) file.zir else file.prev_zir.?.*; | ||
| 3210 | const declaration = zir.getDeclaration(inst_info.inst)[0]; | ||
| 3211 | const want_analysis = switch (declaration.name) { | ||
| 3212 | .@"usingnamespace" => unreachable, | ||
| 3213 | .@"comptime" => true, | ||
| 3214 | else => a: { | ||
| 3215 | if (!comp.config.is_test) break :a false; | ||
| 3216 | if (file.mod != zcu.main_mod) break :a false; | ||
| 3217 | if (declaration.name.isNamedTest(zir) or declaration.name == .decltest) { | ||
| 3218 | const nav = ip.getCau(cau).owner.unwrap().nav; | ||
| 3219 | const fqn_slice = ip.getNav(nav).fqn.toSlice(ip); | ||
| 3220 | for (comp.test_filters) |test_filter| { | ||
| 3221 | if (std.mem.indexOf(u8, fqn_slice, test_filter) != null) break; | ||
| 3222 | } else break :a false; | ||
| 3223 | } | ||
| 3224 | break :a true; | ||
| 3225 | }, | ||
| 3226 | }; | ||
| 3227 | if (want_analysis) { | ||
| 3228 | const unit = AnalUnit.wrap(.{ .cau = cau }); | ||
| 3229 | if (!result.contains(unit)) { | ||
| 3230 | log.debug("type '{}': ref cau %{}", .{ | ||
| 3231 | Type.fromInterned(ty).containerTypeName(ip).fmt(ip), | ||
| 3232 | @intFromEnum(inst_info.inst), | ||
| 3233 | }); | ||
| 3234 | try unit_queue.put(gpa, unit, referencer); | ||
| 3235 | } | ||
| 3236 | } | ||
| 3237 | } | ||
| 3238 | for (zcu.namespacePtr(ns).pub_decls.keys()) |nav| { | ||
| 3239 | // These are named declarations. They are analyzed only if marked `export`. | ||
| 3240 | const cau = ip.getNav(nav).analysis_owner.unwrap().?; | ||
| 3241 | const inst_info = ip.getCau(cau).zir_index.resolveFull(ip) orelse continue; | ||
| 3242 | const file = zcu.fileByIndex(inst_info.file); | ||
| 3243 | // If the file failed AstGen, the TrackedInst refers to the old ZIR. | ||
| 3244 | const zir = if (file.status == .success_zir) file.zir else file.prev_zir.?.*; | ||
| 3245 | const declaration = zir.getDeclaration(inst_info.inst)[0]; | ||
| 3246 | if (declaration.flags.is_export) { | ||
| 3247 | const unit = AnalUnit.wrap(.{ .cau = cau }); | ||
| 3248 | if (!result.contains(unit)) { | ||
| 3249 | log.debug("type '{}': ref cau %{}", .{ | ||
| 3250 | Type.fromInterned(ty).containerTypeName(ip).fmt(ip), | ||
| 3251 | @intFromEnum(inst_info.inst), | ||
| 3252 | }); | ||
| 3253 | try unit_queue.put(gpa, unit, referencer); | ||
| 3254 | } | ||
| 3255 | } | ||
| 3256 | } | ||
| 3257 | for (zcu.namespacePtr(ns).priv_decls.keys()) |nav| { | ||
| 3258 | // These are named declarations. They are analyzed only if marked `export`. | ||
| 3259 | const cau = ip.getNav(nav).analysis_owner.unwrap().?; | ||
| 3260 | const inst_info = ip.getCau(cau).zir_index.resolveFull(ip) orelse continue; | ||
| 3261 | const file = zcu.fileByIndex(inst_info.file); | ||
| 3262 | // If the file failed AstGen, the TrackedInst refers to the old ZIR. | ||
| 3263 | const zir = if (file.status == .success_zir) file.zir else file.prev_zir.?.*; | ||
| 3264 | const declaration = zir.getDeclaration(inst_info.inst)[0]; | ||
| 3265 | if (declaration.flags.is_export) { | ||
| 3266 | const unit = AnalUnit.wrap(.{ .cau = cau }); | ||
| 3267 | if (!result.contains(unit)) { | ||
| 3268 | log.debug("type '{}': ref cau %{}", .{ | ||
| 3269 | Type.fromInterned(ty).containerTypeName(ip).fmt(ip), | ||
| 3270 | @intFromEnum(inst_info.inst), | ||
| 3271 | }); | ||
| 3272 | try unit_queue.put(gpa, unit, referencer); | ||
| 3273 | } | ||
| 3274 | } | ||
| 3275 | } | ||
| 3276 | // Incremental compilation does not support `usingnamespace`. | ||
| 3277 | // These are only included to keep good reference traces in non-incremental updates. | ||
| 3278 | for (zcu.namespacePtr(ns).pub_usingnamespace.items) |nav| { | ||
| 3279 | const cau = ip.getNav(nav).analysis_owner.unwrap().?; | ||
| 3280 | const unit = AnalUnit.wrap(.{ .cau = cau }); | ||
| 3281 | if (!result.contains(unit)) try unit_queue.put(gpa, unit, referencer); | ||
| 3282 | } | ||
| 3283 | for (zcu.namespacePtr(ns).priv_usingnamespace.items) |nav| { | ||
| 3284 | const cau = ip.getNav(nav).analysis_owner.unwrap().?; | ||
| 3285 | const unit = AnalUnit.wrap(.{ .cau = cau }); | ||
| 3286 | if (!result.contains(unit)) try unit_queue.put(gpa, unit, referencer); | ||
| 3051 | } | 3287 | } |
| 3052 | ref_idx = ref.next; | 3288 | continue; |
| 3289 | } | ||
| 3290 | if (unit_queue.popOrNull()) |kv| { | ||
| 3291 | const unit = kv.key; | ||
| 3292 | try result.putNoClobber(gpa, unit, kv.value); | ||
| 3293 | |||
| 3294 | log.debug("handle unit '{}'", .{zcu.fmtAnalUnit(unit)}); | ||
| 3295 | |||
| 3296 | if (zcu.reference_table.get(unit)) |first_ref_idx| { | ||
| 3297 | assert(first_ref_idx != std.math.maxInt(u32)); | ||
| 3298 | var ref_idx = first_ref_idx; | ||
| 3299 | while (ref_idx != std.math.maxInt(u32)) { | ||
| 3300 | const ref = zcu.all_references.items[ref_idx]; | ||
| 3301 | if (!result.contains(ref.referenced)) { | ||
| 3302 | log.debug("unit '{}': ref unit '{}'", .{ | ||
| 3303 | zcu.fmtAnalUnit(unit), | ||
| 3304 | zcu.fmtAnalUnit(ref.referenced), | ||
| 3305 | }); | ||
| 3306 | try unit_queue.put(gpa, ref.referenced, .{ | ||
| 3307 | .referencer = unit, | ||
| 3308 | .src = ref.src, | ||
| 3309 | }); | ||
| 3310 | } | ||
| 3311 | ref_idx = ref.next; | ||
| 3312 | } | ||
| 3313 | } | ||
| 3314 | if (zcu.type_reference_table.get(unit)) |first_ref_idx| { | ||
| 3315 | assert(first_ref_idx != std.math.maxInt(u32)); | ||
| 3316 | var ref_idx = first_ref_idx; | ||
| 3317 | while (ref_idx != std.math.maxInt(u32)) { | ||
| 3318 | const ref = zcu.all_type_references.items[ref_idx]; | ||
| 3319 | if (!checked_types.contains(ref.referenced)) { | ||
| 3320 | log.debug("unit '{}': ref type '{}'", .{ | ||
| 3321 | zcu.fmtAnalUnit(unit), | ||
| 3322 | Type.fromInterned(ref.referenced).containerTypeName(ip).fmt(ip), | ||
| 3323 | }); | ||
| 3324 | try type_queue.put(gpa, ref.referenced, .{ | ||
| 3325 | .referencer = unit, | ||
| 3326 | .src = ref.src, | ||
| 3327 | }); | ||
| 3328 | } | ||
| 3329 | ref_idx = ref.next; | ||
| 3330 | } | ||
| 3331 | } | ||
| 3332 | continue; | ||
| 3053 | } | 3333 | } |
| 3334 | break; | ||
| 3054 | } | 3335 | } |
| 3055 | 3336 | ||
| 3056 | return result; | 3337 | return result; |
| ... | @@ -3093,7 +3374,7 @@ pub fn navSrcLoc(zcu: *const Zcu, nav_index: InternPool.Nav.Index) LazySrcLoc { | ... | @@ -3093,7 +3374,7 @@ pub fn navSrcLoc(zcu: *const Zcu, nav_index: InternPool.Nav.Index) LazySrcLoc { |
| 3093 | 3374 | ||
| 3094 | pub fn navSrcLine(zcu: *Zcu, nav_index: InternPool.Nav.Index) u32 { | 3375 | pub fn navSrcLine(zcu: *Zcu, nav_index: InternPool.Nav.Index) u32 { |
| 3095 | const ip = &zcu.intern_pool; | 3376 | const ip = &zcu.intern_pool; |
| 3096 | const inst_info = ip.getNav(nav_index).srcInst(ip).resolveFull(ip); | 3377 | const inst_info = ip.getNav(nav_index).srcInst(ip).resolveFull(ip).?; |
| 3097 | const zir = zcu.fileByIndex(inst_info.file).zir; | 3378 | const zir = zcu.fileByIndex(inst_info.file).zir; |
| 3098 | const inst = zir.instructions.get(@intFromEnum(inst_info.inst)); | 3379 | const inst = zir.instructions.get(@intFromEnum(inst_info.inst)); |
| 3099 | assert(inst.tag == .declaration); | 3380 | assert(inst.tag == .declaration); |
| ... | @@ -3106,7 +3387,7 @@ pub fn navValue(zcu: *const Zcu, nav_index: InternPool.Nav.Index) Value { | ... | @@ -3106,7 +3387,7 @@ pub fn navValue(zcu: *const Zcu, nav_index: InternPool.Nav.Index) Value { |
| 3106 | 3387 | ||
| 3107 | pub fn navFileScopeIndex(zcu: *Zcu, nav: InternPool.Nav.Index) File.Index { | 3388 | pub fn navFileScopeIndex(zcu: *Zcu, nav: InternPool.Nav.Index) File.Index { |
| 3108 | const ip = &zcu.intern_pool; | 3389 | const ip = &zcu.intern_pool; |
| 3109 | return ip.getNav(nav).srcInst(ip).resolveFull(ip).file; | 3390 | return ip.getNav(nav).srcInst(ip).resolveFile(ip); |
| 3110 | } | 3391 | } |
| 3111 | 3392 | ||
| 3112 | pub fn navFileScope(zcu: *Zcu, nav: InternPool.Nav.Index) *File { | 3393 | pub fn navFileScope(zcu: *Zcu, nav: InternPool.Nav.Index) *File { |
| ... | @@ -3115,6 +3396,75 @@ pub fn navFileScope(zcu: *Zcu, nav: InternPool.Nav.Index) *File { | ... | @@ -3115,6 +3396,75 @@ pub fn navFileScope(zcu: *Zcu, nav: InternPool.Nav.Index) *File { |
| 3115 | 3396 | ||
| 3116 | pub fn cauFileScope(zcu: *Zcu, cau: InternPool.Cau.Index) *File { | 3397 | pub fn cauFileScope(zcu: *Zcu, cau: InternPool.Cau.Index) *File { |
| 3117 | const ip = &zcu.intern_pool; | 3398 | const ip = &zcu.intern_pool; |
| 3118 | const file_index = ip.getCau(cau).zir_index.resolveFull(ip).file; | 3399 | const file_index = ip.getCau(cau).zir_index.resolveFile(ip); |
| 3119 | return zcu.fileByIndex(file_index); | 3400 | return zcu.fileByIndex(file_index); |
| 3120 | } | 3401 | } |
| 3402 | |||
| 3403 | pub fn fmtAnalUnit(zcu: *Zcu, unit: AnalUnit) std.fmt.Formatter(formatAnalUnit) { | ||
| 3404 | return .{ .data = .{ .unit = unit, .zcu = zcu } }; | ||
| 3405 | } | ||
| 3406 | pub fn fmtDependee(zcu: *Zcu, d: InternPool.Dependee) std.fmt.Formatter(formatDependee) { | ||
| 3407 | return .{ .data = .{ .dependee = d, .zcu = zcu } }; | ||
| 3408 | } | ||
| 3409 | |||
| 3410 | fn formatAnalUnit(data: struct { unit: AnalUnit, zcu: *Zcu }, comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void { | ||
| 3411 | _ = .{ fmt, options }; | ||
| 3412 | const zcu = data.zcu; | ||
| 3413 | const ip = &zcu.intern_pool; | ||
| 3414 | switch (data.unit.unwrap()) { | ||
| 3415 | .cau => |cau_index| { | ||
| 3416 | const cau = ip.getCau(cau_index); | ||
| 3417 | switch (cau.owner.unwrap()) { | ||
| 3418 | .nav => |nav| return writer.print("cau(decl='{}')", .{ip.getNav(nav).fqn.fmt(ip)}), | ||
| 3419 | .type => |ty| return writer.print("cau(ty='{}')", .{Type.fromInterned(ty).containerTypeName(ip).fmt(ip)}), | ||
| 3420 | .none => if (cau.zir_index.resolveFull(ip)) |resolved| { | ||
| 3421 | const file_path = zcu.fileByIndex(resolved.file).sub_file_path; | ||
| 3422 | return writer.print("cau(inst=('{s}', %{}))", .{ file_path, @intFromEnum(resolved.inst) }); | ||
| 3423 | } else { | ||
| 3424 | return writer.writeAll("cau(inst=<lost>)"); | ||
| 3425 | }, | ||
| 3426 | } | ||
| 3427 | }, | ||
| 3428 | .func => |func| { | ||
| 3429 | const nav = zcu.funcInfo(func).owner_nav; | ||
| 3430 | return writer.print("func('{}')", .{ip.getNav(nav).fqn.fmt(ip)}); | ||
| 3431 | }, | ||
| 3432 | } | ||
| 3433 | } | ||
| 3434 | fn formatDependee(data: struct { dependee: InternPool.Dependee, zcu: *Zcu }, comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void { | ||
| 3435 | _ = .{ fmt, options }; | ||
| 3436 | const zcu = data.zcu; | ||
| 3437 | const ip = &zcu.intern_pool; | ||
| 3438 | switch (data.dependee) { | ||
| 3439 | .src_hash => |ti| { | ||
| 3440 | const info = ti.resolveFull(ip) orelse { | ||
| 3441 | return writer.writeAll("inst(<lost>)"); | ||
| 3442 | }; | ||
| 3443 | const file_path = zcu.fileByIndex(info.file).sub_file_path; | ||
| 3444 | return writer.print("inst('{s}', %{d})", .{ file_path, @intFromEnum(info.inst) }); | ||
| 3445 | }, | ||
| 3446 | .nav_val => |nav| { | ||
| 3447 | const fqn = ip.getNav(nav).fqn; | ||
| 3448 | return writer.print("nav('{}')", .{fqn.fmt(ip)}); | ||
| 3449 | }, | ||
| 3450 | .interned => |ip_index| switch (ip.indexToKey(ip_index)) { | ||
| 3451 | .struct_type, .union_type, .enum_type => return writer.print("type('{}')", .{Type.fromInterned(ip_index).containerTypeName(ip).fmt(ip)}), | ||
| 3452 | .func => |f| return writer.print("ies('{}')", .{ip.getNav(f.owner_nav).fqn.fmt(ip)}), | ||
| 3453 | else => unreachable, | ||
| 3454 | }, | ||
| 3455 | .namespace => |ti| { | ||
| 3456 | const info = ti.resolveFull(ip) orelse { | ||
| 3457 | return writer.writeAll("namespace(<lost>)"); | ||
| 3458 | }; | ||
| 3459 | const file_path = zcu.fileByIndex(info.file).sub_file_path; | ||
| 3460 | return writer.print("namespace('{s}', %{d})", .{ file_path, @intFromEnum(info.inst) }); | ||
| 3461 | }, | ||
| 3462 | .namespace_name => |k| { | ||
| 3463 | const info = k.namespace.resolveFull(ip) orelse { | ||
| 3464 | return writer.print("namespace(<lost>, '{}')", .{k.name.fmt(ip)}); | ||
| 3465 | }; | ||
| 3466 | const file_path = zcu.fileByIndex(info.file).sub_file_path; | ||
| 3467 | return writer.print("namespace('{s}', %{d}, '{}')", .{ file_path, @intFromEnum(info.inst), k.name.fmt(ip) }); | ||
| 3468 | }, | ||
| 3469 | } | ||
| 3470 | } |
src/Zcu/PerThread.zig+901-321| ... | @@ -1,3 +1,6 @@ | ... | @@ -1,3 +1,6 @@ |
| 1 | //! This type provides a wrapper around a `*Zcu` for uses which require a thread `Id`. | ||
| 2 | //! Any operation which mutates `InternPool` state lives here rather than on `Zcu`. | ||
| 3 | |||
| 1 | zcu: *Zcu, | 4 | zcu: *Zcu, |
| 2 | 5 | ||
| 3 | /// Dense, per-thread unique index. | 6 | /// Dense, per-thread unique index. |
| ... | @@ -39,7 +42,6 @@ pub fn astGenFile( | ... | @@ -39,7 +42,6 @@ pub fn astGenFile( |
| 39 | pt: Zcu.PerThread, | 42 | pt: Zcu.PerThread, |
| 40 | file: *Zcu.File, | 43 | file: *Zcu.File, |
| 41 | path_digest: Cache.BinDigest, | 44 | path_digest: Cache.BinDigest, |
| 42 | old_root_type: InternPool.Index, | ||
| 43 | ) !void { | 45 | ) !void { |
| 44 | dev.check(.ast_gen); | 46 | dev.check(.ast_gen); |
| 45 | assert(!file.mod.isBuiltin()); | 47 | assert(!file.mod.isBuiltin()); |
| ... | @@ -299,25 +301,15 @@ pub fn astGenFile( | ... | @@ -299,25 +301,15 @@ pub fn astGenFile( |
| 299 | file.status = .astgen_failure; | 301 | file.status = .astgen_failure; |
| 300 | return error.AnalysisFail; | 302 | return error.AnalysisFail; |
| 301 | } | 303 | } |
| 302 | |||
| 303 | if (old_root_type != .none) { | ||
| 304 | // The root of this file must be re-analyzed, since the file has changed. | ||
| 305 | comp.mutex.lock(); | ||
| 306 | defer comp.mutex.unlock(); | ||
| 307 | |||
| 308 | log.debug("outdated file root type: {}", .{old_root_type}); | ||
| 309 | try zcu.outdated_file_root.put(gpa, old_root_type, {}); | ||
| 310 | } | ||
| 311 | } | 304 | } |
| 312 | 305 | ||
| 313 | const UpdatedFile = struct { | 306 | const UpdatedFile = struct { |
| 314 | file_index: Zcu.File.Index, | ||
| 315 | file: *Zcu.File, | 307 | file: *Zcu.File, |
| 316 | inst_map: std.AutoHashMapUnmanaged(Zir.Inst.Index, Zir.Inst.Index), | 308 | inst_map: std.AutoHashMapUnmanaged(Zir.Inst.Index, Zir.Inst.Index), |
| 317 | }; | 309 | }; |
| 318 | 310 | ||
| 319 | fn cleanupUpdatedFiles(gpa: Allocator, updated_files: *std.ArrayListUnmanaged(UpdatedFile)) void { | 311 | fn cleanupUpdatedFiles(gpa: Allocator, updated_files: *std.AutoArrayHashMapUnmanaged(Zcu.File.Index, UpdatedFile)) void { |
| 320 | for (updated_files.items) |*elem| elem.inst_map.deinit(gpa); | 312 | for (updated_files.values()) |*elem| elem.inst_map.deinit(gpa); |
| 321 | updated_files.deinit(gpa); | 313 | updated_files.deinit(gpa); |
| 322 | } | 314 | } |
| 323 | 315 | ||
| ... | @@ -328,143 +320,166 @@ pub fn updateZirRefs(pt: Zcu.PerThread) Allocator.Error!void { | ... | @@ -328,143 +320,166 @@ pub fn updateZirRefs(pt: Zcu.PerThread) Allocator.Error!void { |
| 328 | const gpa = zcu.gpa; | 320 | const gpa = zcu.gpa; |
| 329 | 321 | ||
| 330 | // We need to visit every updated File for every TrackedInst in InternPool. | 322 | // We need to visit every updated File for every TrackedInst in InternPool. |
| 331 | var updated_files: std.ArrayListUnmanaged(UpdatedFile) = .{}; | 323 | var updated_files: std.AutoArrayHashMapUnmanaged(Zcu.File.Index, UpdatedFile) = .{}; |
| 332 | defer cleanupUpdatedFiles(gpa, &updated_files); | 324 | defer cleanupUpdatedFiles(gpa, &updated_files); |
| 333 | for (zcu.import_table.values()) |file_index| { | 325 | for (zcu.import_table.values()) |file_index| { |
| 334 | const file = zcu.fileByIndex(file_index); | 326 | const file = zcu.fileByIndex(file_index); |
| 335 | const old_zir = file.prev_zir orelse continue; | 327 | const old_zir = file.prev_zir orelse continue; |
| 336 | const new_zir = file.zir; | 328 | const new_zir = file.zir; |
| 337 | try updated_files.append(gpa, .{ | 329 | const gop = try updated_files.getOrPut(gpa, file_index); |
| 338 | .file_index = file_index, | 330 | assert(!gop.found_existing); |
| 331 | gop.value_ptr.* = .{ | ||
| 339 | .file = file, | 332 | .file = file, |
| 340 | .inst_map = .{}, | 333 | .inst_map = .{}, |
| 341 | }); | 334 | }; |
| 342 | const inst_map = &updated_files.items[updated_files.items.len - 1].inst_map; | 335 | if (!new_zir.hasCompileErrors()) { |
| 343 | try Zcu.mapOldZirToNew(gpa, old_zir.*, new_zir, inst_map); | 336 | try Zcu.mapOldZirToNew(gpa, old_zir.*, file.zir, &gop.value_ptr.inst_map); |
| 337 | } | ||
| 344 | } | 338 | } |
| 345 | 339 | ||
| 346 | if (updated_files.items.len == 0) | 340 | if (updated_files.count() == 0) |
| 347 | return; | 341 | return; |
| 348 | 342 | ||
| 349 | for (ip.locals, 0..) |*local, tid| { | 343 | for (ip.locals, 0..) |*local, tid| { |
| 350 | const tracked_insts_list = local.getMutableTrackedInsts(gpa); | 344 | const tracked_insts_list = local.getMutableTrackedInsts(gpa); |
| 351 | for (tracked_insts_list.view().items(.@"0"), 0..) |*tracked_inst, tracked_inst_unwrapped_index| { | 345 | for (tracked_insts_list.viewAllowEmpty().items(.@"0"), 0..) |*tracked_inst, tracked_inst_unwrapped_index| { |
| 352 | for (updated_files.items) |updated_file| { | 346 | const file_index = tracked_inst.file; |
| 353 | const file_index = updated_file.file_index; | 347 | const updated_file = updated_files.get(file_index) orelse continue; |
| 354 | if (tracked_inst.file != file_index) continue; | ||
| 355 | |||
| 356 | const file = updated_file.file; | ||
| 357 | const old_zir = file.prev_zir.?.*; | ||
| 358 | const new_zir = file.zir; | ||
| 359 | const old_tag = old_zir.instructions.items(.tag); | ||
| 360 | const old_data = old_zir.instructions.items(.data); | ||
| 361 | const inst_map = &updated_file.inst_map; | ||
| 362 | |||
| 363 | const old_inst = tracked_inst.inst; | ||
| 364 | const tracked_inst_index = (InternPool.TrackedInst.Index.Unwrapped{ | ||
| 365 | .tid = @enumFromInt(tid), | ||
| 366 | .index = @intCast(tracked_inst_unwrapped_index), | ||
| 367 | }).wrap(ip); | ||
| 368 | tracked_inst.inst = inst_map.get(old_inst) orelse { | ||
| 369 | // Tracking failed for this instruction. Invalidate associated `src_hash` deps. | ||
| 370 | log.debug("tracking failed for %{d}", .{old_inst}); | ||
| 371 | try zcu.markDependeeOutdated(.{ .src_hash = tracked_inst_index }); | ||
| 372 | continue; | ||
| 373 | }; | ||
| 374 | 348 | ||
| 375 | if (old_zir.getAssociatedSrcHash(old_inst)) |old_hash| hash_changed: { | 349 | const file = updated_file.file; |
| 376 | if (new_zir.getAssociatedSrcHash(tracked_inst.inst)) |new_hash| { | 350 | |
| 377 | if (std.zig.srcHashEql(old_hash, new_hash)) { | 351 | if (file.zir.hasCompileErrors()) { |
| 378 | break :hash_changed; | 352 | // If we mark this as outdated now, users of this inst will just get a transitive analysis failure. |
| 379 | } | 353 | // Ultimately, they would end up throwing out potentially useful analysis results. |
| 380 | log.debug("hash for (%{d} -> %{d}) changed: {} -> {}", .{ | 354 | // So, do nothing. We already have the file failure -- that's sufficient for now! |
| 381 | old_inst, | 355 | continue; |
| 382 | tracked_inst.inst, | 356 | } |
| 383 | std.fmt.fmtSliceHexLower(&old_hash), | 357 | const old_inst = tracked_inst.inst.unwrap() orelse continue; // we can't continue tracking lost insts |
| 384 | std.fmt.fmtSliceHexLower(&new_hash), | 358 | const tracked_inst_index = (InternPool.TrackedInst.Index.Unwrapped{ |
| 385 | }); | 359 | .tid = @enumFromInt(tid), |
| 360 | .index = @intCast(tracked_inst_unwrapped_index), | ||
| 361 | }).wrap(ip); | ||
| 362 | const new_inst = updated_file.inst_map.get(old_inst) orelse { | ||
| 363 | // Tracking failed for this instruction. Invalidate associated `src_hash` deps. | ||
| 364 | log.debug("tracking failed for %{d}", .{old_inst}); | ||
| 365 | tracked_inst.inst = .lost; | ||
| 366 | try zcu.markDependeeOutdated(.not_marked_po, .{ .src_hash = tracked_inst_index }); | ||
| 367 | continue; | ||
| 368 | }; | ||
| 369 | tracked_inst.inst = InternPool.TrackedInst.MaybeLost.ZirIndex.wrap(new_inst); | ||
| 370 | |||
| 371 | const old_zir = file.prev_zir.?.*; | ||
| 372 | const new_zir = file.zir; | ||
| 373 | const old_tag = old_zir.instructions.items(.tag); | ||
| 374 | const old_data = old_zir.instructions.items(.data); | ||
| 375 | |||
| 376 | if (old_zir.getAssociatedSrcHash(old_inst)) |old_hash| hash_changed: { | ||
| 377 | if (new_zir.getAssociatedSrcHash(new_inst)) |new_hash| { | ||
| 378 | if (std.zig.srcHashEql(old_hash, new_hash)) { | ||
| 379 | break :hash_changed; | ||
| 386 | } | 380 | } |
| 387 | // The source hash associated with this instruction changed - invalidate relevant dependencies. | 381 | log.debug("hash for (%{d} -> %{d}) changed: {} -> {}", .{ |
| 388 | try zcu.markDependeeOutdated(.{ .src_hash = tracked_inst_index }); | 382 | old_inst, |
| 383 | new_inst, | ||
| 384 | std.fmt.fmtSliceHexLower(&old_hash), | ||
| 385 | std.fmt.fmtSliceHexLower(&new_hash), | ||
| 386 | }); | ||
| 389 | } | 387 | } |
| 388 | // The source hash associated with this instruction changed - invalidate relevant dependencies. | ||
| 389 | try zcu.markDependeeOutdated(.not_marked_po, .{ .src_hash = tracked_inst_index }); | ||
| 390 | } | ||
| 390 | 391 | ||
| 391 | // If this is a `struct_decl` etc, we must invalidate any outdated namespace dependencies. | 392 | // If this is a `struct_decl` etc, we must invalidate any outdated namespace dependencies. |
| 392 | const has_namespace = switch (old_tag[@intFromEnum(old_inst)]) { | 393 | const has_namespace = switch (old_tag[@intFromEnum(old_inst)]) { |
| 393 | .extended => switch (old_data[@intFromEnum(old_inst)].extended.opcode) { | 394 | .extended => switch (old_data[@intFromEnum(old_inst)].extended.opcode) { |
| 394 | .struct_decl, .union_decl, .opaque_decl, .enum_decl => true, | 395 | .struct_decl, .union_decl, .opaque_decl, .enum_decl => true, |
| 395 | else => false, | ||
| 396 | }, | ||
| 397 | else => false, | 396 | else => false, |
| 398 | }; | 397 | }, |
| 399 | if (!has_namespace) continue; | 398 | else => false, |
| 400 | 399 | }; | |
| 401 | var old_names: std.AutoArrayHashMapUnmanaged(InternPool.NullTerminatedString, void) = .{}; | 400 | if (!has_namespace) continue; |
| 402 | defer old_names.deinit(zcu.gpa); | 401 | |
| 403 | { | 402 | var old_names: std.AutoArrayHashMapUnmanaged(InternPool.NullTerminatedString, void) = .{}; |
| 404 | var it = old_zir.declIterator(old_inst); | 403 | defer old_names.deinit(zcu.gpa); |
| 405 | while (it.next()) |decl_inst| { | 404 | { |
| 406 | const decl_name = old_zir.getDeclaration(decl_inst)[0].name; | 405 | var it = old_zir.declIterator(old_inst); |
| 407 | switch (decl_name) { | 406 | while (it.next()) |decl_inst| { |
| 408 | .@"comptime", .@"usingnamespace", .unnamed_test, .decltest => continue, | 407 | const decl_name = old_zir.getDeclaration(decl_inst)[0].name; |
| 409 | _ => if (decl_name.isNamedTest(old_zir)) continue, | 408 | switch (decl_name) { |
| 410 | } | 409 | .@"comptime", .@"usingnamespace", .unnamed_test, .decltest => continue, |
| 411 | const name_zir = decl_name.toString(old_zir).?; | 410 | _ => if (decl_name.isNamedTest(old_zir)) continue, |
| 412 | const name_ip = try zcu.intern_pool.getOrPutString( | ||
| 413 | zcu.gpa, | ||
| 414 | pt.tid, | ||
| 415 | old_zir.nullTerminatedString(name_zir), | ||
| 416 | .no_embedded_nulls, | ||
| 417 | ); | ||
| 418 | try old_names.put(zcu.gpa, name_ip, {}); | ||
| 419 | } | 411 | } |
| 412 | const name_zir = decl_name.toString(old_zir).?; | ||
| 413 | const name_ip = try zcu.intern_pool.getOrPutString( | ||
| 414 | zcu.gpa, | ||
| 415 | pt.tid, | ||
| 416 | old_zir.nullTerminatedString(name_zir), | ||
| 417 | .no_embedded_nulls, | ||
| 418 | ); | ||
| 419 | try old_names.put(zcu.gpa, name_ip, {}); | ||
| 420 | } | 420 | } |
| 421 | var any_change = false; | 421 | } |
| 422 | { | 422 | var any_change = false; |
| 423 | var it = new_zir.declIterator(tracked_inst.inst); | 423 | { |
| 424 | while (it.next()) |decl_inst| { | 424 | var it = new_zir.declIterator(new_inst); |
| 425 | const decl_name = new_zir.getDeclaration(decl_inst)[0].name; | 425 | while (it.next()) |decl_inst| { |
| 426 | switch (decl_name) { | 426 | const decl_name = new_zir.getDeclaration(decl_inst)[0].name; |
| 427 | .@"comptime", .@"usingnamespace", .unnamed_test, .decltest => continue, | 427 | switch (decl_name) { |
| 428 | _ => if (decl_name.isNamedTest(new_zir)) continue, | 428 | .@"comptime", .@"usingnamespace", .unnamed_test, .decltest => continue, |
| 429 | } | 429 | _ => if (decl_name.isNamedTest(new_zir)) continue, |
| 430 | const name_zir = decl_name.toString(new_zir).?; | ||
| 431 | const name_ip = try zcu.intern_pool.getOrPutString( | ||
| 432 | zcu.gpa, | ||
| 433 | pt.tid, | ||
| 434 | new_zir.nullTerminatedString(name_zir), | ||
| 435 | .no_embedded_nulls, | ||
| 436 | ); | ||
| 437 | if (!old_names.swapRemove(name_ip)) continue; | ||
| 438 | // Name added | ||
| 439 | any_change = true; | ||
| 440 | try zcu.markDependeeOutdated(.{ .namespace_name = .{ | ||
| 441 | .namespace = tracked_inst_index, | ||
| 442 | .name = name_ip, | ||
| 443 | } }); | ||
| 444 | } | 430 | } |
| 445 | } | 431 | const name_zir = decl_name.toString(new_zir).?; |
| 446 | // The only elements remaining in `old_names` now are any names which were removed. | 432 | const name_ip = try zcu.intern_pool.getOrPutString( |
| 447 | for (old_names.keys()) |name_ip| { | 433 | zcu.gpa, |
| 434 | pt.tid, | ||
| 435 | new_zir.nullTerminatedString(name_zir), | ||
| 436 | .no_embedded_nulls, | ||
| 437 | ); | ||
| 438 | if (old_names.swapRemove(name_ip)) continue; | ||
| 439 | // Name added | ||
| 448 | any_change = true; | 440 | any_change = true; |
| 449 | try zcu.markDependeeOutdated(.{ .namespace_name = .{ | 441 | try zcu.markDependeeOutdated(.not_marked_po, .{ .namespace_name = .{ |
| 450 | .namespace = tracked_inst_index, | 442 | .namespace = tracked_inst_index, |
| 451 | .name = name_ip, | 443 | .name = name_ip, |
| 452 | } }); | 444 | } }); |
| 453 | } | 445 | } |
| 446 | } | ||
| 447 | // The only elements remaining in `old_names` now are any names which were removed. | ||
| 448 | for (old_names.keys()) |name_ip| { | ||
| 449 | any_change = true; | ||
| 450 | try zcu.markDependeeOutdated(.not_marked_po, .{ .namespace_name = .{ | ||
| 451 | .namespace = tracked_inst_index, | ||
| 452 | .name = name_ip, | ||
| 453 | } }); | ||
| 454 | } | ||
| 454 | 455 | ||
| 455 | if (any_change) { | 456 | if (any_change) { |
| 456 | try zcu.markDependeeOutdated(.{ .namespace = tracked_inst_index }); | 457 | try zcu.markDependeeOutdated(.not_marked_po, .{ .namespace = tracked_inst_index }); |
| 457 | } | ||
| 458 | } | 458 | } |
| 459 | } | 459 | } |
| 460 | } | 460 | } |
| 461 | 461 | ||
| 462 | for (updated_files.items) |updated_file| { | 462 | try ip.rehashTrackedInsts(gpa, pt.tid); |
| 463 | |||
| 464 | for (updated_files.keys(), updated_files.values()) |file_index, updated_file| { | ||
| 463 | const file = updated_file.file; | 465 | const file = updated_file.file; |
| 464 | const prev_zir = file.prev_zir.?; | 466 | if (file.zir.hasCompileErrors()) { |
| 465 | file.prev_zir = null; | 467 | // Keep `prev_zir` around: it's the last non-error ZIR. |
| 466 | prev_zir.deinit(gpa); | 468 | // Don't update the namespace, as we have no new data to update *to*. |
| 467 | gpa.destroy(prev_zir); | 469 | } else { |
| 470 | const prev_zir = file.prev_zir.?; | ||
| 471 | file.prev_zir = null; | ||
| 472 | prev_zir.deinit(gpa); | ||
| 473 | gpa.destroy(prev_zir); | ||
| 474 | |||
| 475 | // For every file which has changed, re-scan the namespace of the file's root struct type. | ||
| 476 | // These types are special-cased because they don't have an enclosing declaration which will | ||
| 477 | // be re-analyzed (causing the struct's namespace to be re-scanned). It's fine to do this | ||
| 478 | // now because this work is fast (no actual Sema work is happening, we're just updating the | ||
| 479 | // namespace contents). We must do this after updating ZIR refs above, since `scanNamespace` | ||
| 480 | // will track some instructions. | ||
| 481 | try pt.updateFileNamespace(file_index); | ||
| 482 | } | ||
| 468 | } | 483 | } |
| 469 | } | 484 | } |
| 470 | 485 | ||
| ... | @@ -473,8 +488,7 @@ pub fn updateZirRefs(pt: Zcu.PerThread) Allocator.Error!void { | ... | @@ -473,8 +488,7 @@ pub fn updateZirRefs(pt: Zcu.PerThread) Allocator.Error!void { |
| 473 | pub fn ensureFileAnalyzed(pt: Zcu.PerThread, file_index: Zcu.File.Index) Zcu.SemaError!void { | 488 | pub fn ensureFileAnalyzed(pt: Zcu.PerThread, file_index: Zcu.File.Index) Zcu.SemaError!void { |
| 474 | const file_root_type = pt.zcu.fileRootType(file_index); | 489 | const file_root_type = pt.zcu.fileRootType(file_index); |
| 475 | if (file_root_type != .none) { | 490 | if (file_root_type != .none) { |
| 476 | const file_root_type_cau = pt.zcu.intern_pool.loadStructType(file_root_type).cau.unwrap().?; | 491 | _ = try pt.ensureTypeUpToDate(file_root_type, false); |
| 477 | return pt.ensureCauAnalyzed(file_root_type_cau); | ||
| 478 | } else { | 492 | } else { |
| 479 | return pt.semaFile(file_index); | 493 | return pt.semaFile(file_index); |
| 480 | } | 494 | } |
| ... | @@ -491,9 +505,8 @@ pub fn ensureCauAnalyzed(pt: Zcu.PerThread, cau_index: InternPool.Cau.Index) Zcu | ... | @@ -491,9 +505,8 @@ pub fn ensureCauAnalyzed(pt: Zcu.PerThread, cau_index: InternPool.Cau.Index) Zcu |
| 491 | const gpa = zcu.gpa; | 505 | const gpa = zcu.gpa; |
| 492 | const ip = &zcu.intern_pool; | 506 | const ip = &zcu.intern_pool; |
| 493 | 507 | ||
| 494 | const anal_unit = InternPool.AnalUnit.wrap(.{ .cau = cau_index }); | 508 | const anal_unit = AnalUnit.wrap(.{ .cau = cau_index }); |
| 495 | const cau = ip.getCau(cau_index); | 509 | const cau = ip.getCau(cau_index); |
| 496 | const inst_info = cau.zir_index.resolveFull(ip); | ||
| 497 | 510 | ||
| 498 | log.debug("ensureCauAnalyzed {d}", .{@intFromEnum(cau_index)}); | 511 | log.debug("ensureCauAnalyzed {d}", .{@intFromEnum(cau_index)}); |
| 499 | 512 | ||
| ... | @@ -514,14 +527,96 @@ pub fn ensureCauAnalyzed(pt: Zcu.PerThread, cau_index: InternPool.Cau.Index) Zcu | ... | @@ -514,14 +527,96 @@ pub fn ensureCauAnalyzed(pt: Zcu.PerThread, cau_index: InternPool.Cau.Index) Zcu |
| 514 | 527 | ||
| 515 | if (cau_outdated) { | 528 | if (cau_outdated) { |
| 516 | _ = zcu.outdated_ready.swapRemove(anal_unit); | 529 | _ = zcu.outdated_ready.swapRemove(anal_unit); |
| 530 | } else { | ||
| 531 | // We can trust the current information about this `Cau`. | ||
| 532 | if (zcu.failed_analysis.contains(anal_unit) or zcu.transitive_failed_analysis.contains(anal_unit)) { | ||
| 533 | return error.AnalysisFail; | ||
| 534 | } | ||
| 535 | // If it wasn't failed and wasn't marked outdated, then either... | ||
| 536 | // * it is a type and is up-to-date, or | ||
| 537 | // * it is a `comptime` decl and is up-to-date, or | ||
| 538 | // * it is another decl and is EITHER up-to-date OR never-referenced (so unresolved) | ||
| 539 | // We just need to check for that last case. | ||
| 540 | switch (cau.owner.unwrap()) { | ||
| 541 | .type, .none => return, | ||
| 542 | .nav => |nav| if (ip.getNav(nav).status == .resolved) return, | ||
| 543 | } | ||
| 517 | } | 544 | } |
| 518 | 545 | ||
| 519 | // TODO: this only works if namespace lookups in Sema trigger `ensureCauAnalyzed`, because | 546 | const sema_result: SemaCauResult, const analysis_fail = if (pt.ensureCauAnalyzedInner(cau_index, cau_outdated)) |result| |
| 520 | // `outdated_file_root` information is not "viral", so we need that a namespace lookup first | 547 | .{ result, false } |
| 521 | // handles the case where the file root is not an outdated *type* but does have an outdated | 548 | else |err| switch (err) { |
| 522 | // *namespace*. A more logically simple alternative may be for a file's root struct to register | 549 | error.AnalysisFail => res: { |
| 523 | // a dependency on the file's entire source code (hash). Alternatively, we could make sure that | 550 | if (!zcu.failed_analysis.contains(anal_unit)) { |
| 524 | // these are always handled first in an update. Actually, that's probably the best option. | 551 | // If this `Cau` caused the error, it would have an entry in `failed_analysis`. |
| 552 | // Since it does not, this must be a transitive failure. | ||
| 553 | try zcu.transitive_failed_analysis.put(gpa, anal_unit, {}); | ||
| 554 | } | ||
| 555 | // We treat errors as up-to-date, since those uses would just trigger a transitive error. | ||
| 556 | // The exception is types, since type declarations may require re-analysis if the type, e.g. its captures, changed. | ||
| 557 | const outdated = cau.owner.unwrap() == .type; | ||
| 558 | break :res .{ .{ | ||
| 559 | .invalidate_decl_val = outdated, | ||
| 560 | .invalidate_decl_ref = outdated, | ||
| 561 | }, true }; | ||
| 562 | }, | ||
| 563 | error.OutOfMemory => res: { | ||
| 564 | try zcu.failed_analysis.ensureUnusedCapacity(gpa, 1); | ||
| 565 | try zcu.retryable_failures.ensureUnusedCapacity(gpa, 1); | ||
| 566 | const msg = try Zcu.ErrorMsg.create( | ||
| 567 | gpa, | ||
| 568 | .{ .base_node_inst = cau.zir_index, .offset = Zcu.LazySrcLoc.Offset.nodeOffset(0) }, | ||
| 569 | "unable to analyze: OutOfMemory", | ||
| 570 | .{}, | ||
| 571 | ); | ||
| 572 | zcu.retryable_failures.appendAssumeCapacity(anal_unit); | ||
| 573 | zcu.failed_analysis.putAssumeCapacityNoClobber(anal_unit, msg); | ||
| 574 | // We treat errors as up-to-date, since those uses would just trigger a transitive error | ||
| 575 | break :res .{ .{ | ||
| 576 | .invalidate_decl_val = false, | ||
| 577 | .invalidate_decl_ref = false, | ||
| 578 | }, true }; | ||
| 579 | }, | ||
| 580 | }; | ||
| 581 | |||
| 582 | if (cau_outdated) { | ||
| 583 | // TODO: we do not yet have separate dependencies for decl values vs types. | ||
| 584 | const invalidate = sema_result.invalidate_decl_val or sema_result.invalidate_decl_ref; | ||
| 585 | const dependee: InternPool.Dependee = switch (cau.owner.unwrap()) { | ||
| 586 | .none => return, // there are no dependencies on a `comptime` decl! | ||
| 587 | .nav => |nav_index| .{ .nav_val = nav_index }, | ||
| 588 | .type => |ty| .{ .interned = ty }, | ||
| 589 | }; | ||
| 590 | |||
| 591 | if (invalidate) { | ||
| 592 | // This dependency was marked as PO, meaning dependees were waiting | ||
| 593 | // on its analysis result, and it has turned out to be outdated. | ||
| 594 | // Update dependees accordingly. | ||
| 595 | try zcu.markDependeeOutdated(.marked_po, dependee); | ||
| 596 | } else { | ||
| 597 | // This dependency was previously PO, but turned out to be up-to-date. | ||
| 598 | // We do not need to queue successive analysis. | ||
| 599 | try zcu.markPoDependeeUpToDate(dependee); | ||
| 600 | } | ||
| 601 | } | ||
| 602 | |||
| 603 | if (analysis_fail) return error.AnalysisFail; | ||
| 604 | } | ||
| 605 | |||
| 606 | fn ensureCauAnalyzedInner( | ||
| 607 | pt: Zcu.PerThread, | ||
| 608 | cau_index: InternPool.Cau.Index, | ||
| 609 | cau_outdated: bool, | ||
| 610 | ) Zcu.SemaError!SemaCauResult { | ||
| 611 | const zcu = pt.zcu; | ||
| 612 | const ip = &zcu.intern_pool; | ||
| 613 | |||
| 614 | const cau = ip.getCau(cau_index); | ||
| 615 | const anal_unit = AnalUnit.wrap(.{ .cau = cau_index }); | ||
| 616 | |||
| 617 | const inst_info = cau.zir_index.resolveFull(ip) orelse return error.AnalysisFail; | ||
| 618 | |||
| 619 | // TODO: document this elsewhere mlugg! | ||
| 525 | // For my own benefit, here's how a namespace update for a normal (non-file-root) type works: | 620 | // For my own benefit, here's how a namespace update for a normal (non-file-root) type works: |
| 526 | // `const S = struct { ... };` | 621 | // `const S = struct { ... };` |
| 527 | // We are adding or removing a declaration within this `struct`. | 622 | // We are adding or removing a declaration within this `struct`. |
| ... | @@ -533,33 +628,12 @@ pub fn ensureCauAnalyzed(pt: Zcu.PerThread, cau_index: InternPool.Cau.Index) Zcu | ... | @@ -533,33 +628,12 @@ pub fn ensureCauAnalyzed(pt: Zcu.PerThread, cau_index: InternPool.Cau.Index) Zcu |
| 533 | // * so, it uses the same `struct` | 628 | // * so, it uses the same `struct` |
| 534 | // * but this doesn't stop it from updating the namespace! | 629 | // * but this doesn't stop it from updating the namespace! |
| 535 | // * we basically do `scanDecls`, updating the namespace as needed | 630 | // * we basically do `scanDecls`, updating the namespace as needed |
| 536 | // * TODO: optimize this to make sure we only do it once a generation i guess? | ||
| 537 | // * so everyone lived happily ever after | 631 | // * so everyone lived happily ever after |
| 538 | const file_root_outdated = switch (cau.owner.unwrap()) { | ||
| 539 | .type => |ty| zcu.outdated_file_root.swapRemove(ty), | ||
| 540 | .nav, .none => false, | ||
| 541 | }; | ||
| 542 | 632 | ||
| 543 | if (zcu.fileByIndex(inst_info.file).status != .success_zir) { | 633 | if (zcu.fileByIndex(inst_info.file).status != .success_zir) { |
| 544 | return error.AnalysisFail; | 634 | return error.AnalysisFail; |
| 545 | } | 635 | } |
| 546 | 636 | ||
| 547 | if (!cau_outdated and !file_root_outdated) { | ||
| 548 | // We can trust the current information about this `Cau`. | ||
| 549 | if (zcu.failed_analysis.contains(anal_unit) or zcu.transitive_failed_analysis.contains(anal_unit)) { | ||
| 550 | return error.AnalysisFail; | ||
| 551 | } | ||
| 552 | // If it wasn't failed and wasn't marked outdated, then either... | ||
| 553 | // * it is a type and is up-to-date, or | ||
| 554 | // * it is a `comptime` decl and is up-to-date, or | ||
| 555 | // * it is another decl and is EITHER up-to-date OR never-referenced (so unresolved) | ||
| 556 | // We just need to check for that last case. | ||
| 557 | switch (cau.owner.unwrap()) { | ||
| 558 | .type, .none => return, | ||
| 559 | .nav => |nav| if (ip.getNav(nav).status == .resolved) return, | ||
| 560 | } | ||
| 561 | } | ||
| 562 | |||
| 563 | // `cau_outdated` can be true in the initial update for `comptime` declarations, | 637 | // `cau_outdated` can be true in the initial update for `comptime` declarations, |
| 564 | // so this isn't a `dev.check`. | 638 | // so this isn't a `dev.check`. |
| 565 | if (cau_outdated and dev.env.supports(.incremental)) { | 639 | if (cau_outdated and dev.env.supports(.incremental)) { |
| ... | @@ -567,73 +641,23 @@ pub fn ensureCauAnalyzed(pt: Zcu.PerThread, cau_index: InternPool.Cau.Index) Zcu | ... | @@ -567,73 +641,23 @@ pub fn ensureCauAnalyzed(pt: Zcu.PerThread, cau_index: InternPool.Cau.Index) Zcu |
| 567 | // prior to re-analysis. | 641 | // prior to re-analysis. |
| 568 | zcu.deleteUnitExports(anal_unit); | 642 | zcu.deleteUnitExports(anal_unit); |
| 569 | zcu.deleteUnitReferences(anal_unit); | 643 | zcu.deleteUnitReferences(anal_unit); |
| 570 | } | 644 | if (zcu.failed_analysis.fetchSwapRemove(anal_unit)) |kv| { |
| 571 | 645 | kv.value.destroy(zcu.gpa); | |
| 572 | const sema_result: SemaCauResult = res: { | ||
| 573 | if (inst_info.inst == .main_struct_inst) { | ||
| 574 | const changed = try pt.semaFileUpdate(inst_info.file, cau_outdated); | ||
| 575 | break :res .{ | ||
| 576 | .invalidate_decl_val = changed, | ||
| 577 | .invalidate_decl_ref = changed, | ||
| 578 | }; | ||
| 579 | } | 646 | } |
| 580 | 647 | _ = zcu.transitive_failed_analysis.swapRemove(anal_unit); | |
| 581 | const decl_prog_node = zcu.sema_prog_node.start(switch (cau.owner.unwrap()) { | ||
| 582 | .nav => |nav| ip.getNav(nav).fqn.toSlice(ip), | ||
| 583 | .type => |ty| Type.fromInterned(ty).containerTypeName(ip).toSlice(ip), | ||
| 584 | .none => "comptime", | ||
| 585 | }, 0); | ||
| 586 | defer decl_prog_node.end(); | ||
| 587 | |||
| 588 | break :res pt.semaCau(cau_index) catch |err| switch (err) { | ||
| 589 | error.AnalysisFail => { | ||
| 590 | if (!zcu.failed_analysis.contains(anal_unit)) { | ||
| 591 | // If this `Cau` caused the error, it would have an entry in `failed_analysis`. | ||
| 592 | // Since it does not, this must be a transitive failure. | ||
| 593 | try zcu.transitive_failed_analysis.put(gpa, anal_unit, {}); | ||
| 594 | } | ||
| 595 | return error.AnalysisFail; | ||
| 596 | }, | ||
| 597 | error.GenericPoison => unreachable, | ||
| 598 | error.ComptimeBreak => unreachable, | ||
| 599 | error.ComptimeReturn => unreachable, | ||
| 600 | error.OutOfMemory => { | ||
| 601 | try zcu.failed_analysis.ensureUnusedCapacity(gpa, 1); | ||
| 602 | try zcu.retryable_failures.append(gpa, anal_unit); | ||
| 603 | zcu.failed_analysis.putAssumeCapacityNoClobber(anal_unit, try Zcu.ErrorMsg.create( | ||
| 604 | gpa, | ||
| 605 | .{ .base_node_inst = cau.zir_index, .offset = Zcu.LazySrcLoc.Offset.nodeOffset(0) }, | ||
| 606 | "unable to analyze: OutOfMemory", | ||
| 607 | .{}, | ||
| 608 | )); | ||
| 609 | return error.AnalysisFail; | ||
| 610 | }, | ||
| 611 | }; | ||
| 612 | }; | ||
| 613 | |||
| 614 | if (!cau_outdated) { | ||
| 615 | // We definitely don't need to do any dependency tracking, so our work is done. | ||
| 616 | return; | ||
| 617 | } | 648 | } |
| 618 | 649 | ||
| 619 | // TODO: we do not yet have separate dependencies for decl values vs types. | 650 | const decl_prog_node = zcu.sema_prog_node.start(switch (cau.owner.unwrap()) { |
| 620 | const invalidate = sema_result.invalidate_decl_val or sema_result.invalidate_decl_ref; | 651 | .nav => |nav| ip.getNav(nav).fqn.toSlice(ip), |
| 621 | const dependee: InternPool.Dependee = switch (cau.owner.unwrap()) { | 652 | .type => |ty| Type.fromInterned(ty).containerTypeName(ip).toSlice(ip), |
| 622 | .none => return, // there are no dependencies on a `comptime` decl! | 653 | .none => "comptime", |
| 623 | .nav => |nav_index| .{ .nav_val = nav_index }, | 654 | }, 0); |
| 624 | .type => |ty| .{ .interned = ty }, | 655 | defer decl_prog_node.end(); |
| 625 | }; | ||
| 626 | 656 | ||
| 627 | if (invalidate) { | 657 | return pt.semaCau(cau_index) catch |err| switch (err) { |
| 628 | // This dependency was marked as PO, meaning dependees were waiting | 658 | error.GenericPoison, error.ComptimeBreak, error.ComptimeReturn => unreachable, |
| 629 | // on its analysis result, and it has turned out to be outdated. | 659 | error.AnalysisFail, error.OutOfMemory => |e| return e, |
| 630 | // Update dependees accordingly. | 660 | }; |
| 631 | try zcu.markDependeeOutdated(dependee); | ||
| 632 | } else { | ||
| 633 | // This dependency was previously PO, but turned out to be up-to-date. | ||
| 634 | // We do not need to queue successive analysis. | ||
| 635 | try zcu.markPoDependeeUpToDate(dependee); | ||
| 636 | } | ||
| 637 | } | 661 | } |
| 638 | 662 | ||
| 639 | pub fn ensureFuncBodyAnalyzed(pt: Zcu.PerThread, maybe_coerced_func_index: InternPool.Index) Zcu.SemaError!void { | 663 | pub fn ensureFuncBodyAnalyzed(pt: Zcu.PerThread, maybe_coerced_func_index: InternPool.Index) Zcu.SemaError!void { |
| ... | @@ -653,6 +677,63 @@ pub fn ensureFuncBodyAnalyzed(pt: Zcu.PerThread, maybe_coerced_func_index: Inter | ... | @@ -653,6 +677,63 @@ pub fn ensureFuncBodyAnalyzed(pt: Zcu.PerThread, maybe_coerced_func_index: Inter |
| 653 | 677 | ||
| 654 | log.debug("ensureFuncBodyAnalyzed {d}", .{@intFromEnum(func_index)}); | 678 | log.debug("ensureFuncBodyAnalyzed {d}", .{@intFromEnum(func_index)}); |
| 655 | 679 | ||
| 680 | const anal_unit = AnalUnit.wrap(.{ .func = func_index }); | ||
| 681 | const func_outdated = zcu.outdated.swapRemove(anal_unit) or | ||
| 682 | zcu.potentially_outdated.swapRemove(anal_unit); | ||
| 683 | |||
| 684 | if (func_outdated) { | ||
| 685 | _ = zcu.outdated_ready.swapRemove(anal_unit); | ||
| 686 | } else { | ||
| 687 | // We can trust the current information about this function. | ||
| 688 | if (zcu.failed_analysis.contains(anal_unit) or zcu.transitive_failed_analysis.contains(anal_unit)) { | ||
| 689 | return error.AnalysisFail; | ||
| 690 | } | ||
| 691 | switch (func.analysisUnordered(ip).state) { | ||
| 692 | .unreferenced => {}, // this is the first reference | ||
| 693 | .queued => {}, // we're waiting on first-time analysis | ||
| 694 | .analyzed => return, // up-to-date | ||
| 695 | } | ||
| 696 | } | ||
| 697 | |||
| 698 | const ies_outdated, const analysis_fail = if (pt.ensureFuncBodyAnalyzedInner(func_index, func_outdated)) |result| | ||
| 699 | .{ result.ies_outdated, false } | ||
| 700 | else |err| switch (err) { | ||
| 701 | error.AnalysisFail => res: { | ||
| 702 | if (!zcu.failed_analysis.contains(anal_unit)) { | ||
| 703 | // If this function caused the error, it would have an entry in `failed_analysis`. | ||
| 704 | // Since it does not, this must be a transitive failure. | ||
| 705 | try zcu.transitive_failed_analysis.put(gpa, anal_unit, {}); | ||
| 706 | } | ||
| 707 | break :res .{ false, true }; // we treat errors as up-to-date IES, since those uses would just trigger a transitive error | ||
| 708 | }, | ||
| 709 | error.OutOfMemory => return error.OutOfMemory, // TODO: graceful handling like `ensureCauAnalyzed` | ||
| 710 | }; | ||
| 711 | |||
| 712 | if (func_outdated) { | ||
| 713 | if (ies_outdated) { | ||
| 714 | log.debug("func IES invalidated ('{d}')", .{@intFromEnum(func_index)}); | ||
| 715 | try zcu.markDependeeOutdated(.marked_po, .{ .interned = func_index }); | ||
| 716 | } else { | ||
| 717 | log.debug("func IES up-to-date ('{d}')", .{@intFromEnum(func_index)}); | ||
| 718 | try zcu.markPoDependeeUpToDate(.{ .interned = func_index }); | ||
| 719 | } | ||
| 720 | } | ||
| 721 | |||
| 722 | if (analysis_fail) return error.AnalysisFail; | ||
| 723 | } | ||
| 724 | |||
| 725 | fn ensureFuncBodyAnalyzedInner( | ||
| 726 | pt: Zcu.PerThread, | ||
| 727 | func_index: InternPool.Index, | ||
| 728 | func_outdated: bool, | ||
| 729 | ) Zcu.SemaError!struct { ies_outdated: bool } { | ||
| 730 | const zcu = pt.zcu; | ||
| 731 | const gpa = zcu.gpa; | ||
| 732 | const ip = &zcu.intern_pool; | ||
| 733 | |||
| 734 | const func = zcu.funcInfo(func_index); | ||
| 735 | const anal_unit = AnalUnit.wrap(.{ .func = func_index }); | ||
| 736 | |||
| 656 | // Here's an interesting question: is this function actually valid? | 737 | // Here's an interesting question: is this function actually valid? |
| 657 | // Maybe the signature changed, so we'll end up creating a whole different `func` | 738 | // Maybe the signature changed, so we'll end up creating a whole different `func` |
| 658 | // in the InternPool, and this one is a waste of time to analyze. Worse, we'd be | 739 | // in the InternPool, and this one is a waste of time to analyze. Worse, we'd be |
| ... | @@ -672,8 +753,10 @@ pub fn ensureFuncBodyAnalyzed(pt: Zcu.PerThread, maybe_coerced_func_index: Inter | ... | @@ -672,8 +753,10 @@ pub fn ensureFuncBodyAnalyzed(pt: Zcu.PerThread, maybe_coerced_func_index: Inter |
| 672 | }); | 753 | }); |
| 673 | 754 | ||
| 674 | if (ip.isRemoved(func_index) or (func.generic_owner != .none and ip.isRemoved(func.generic_owner))) { | 755 | if (ip.isRemoved(func_index) or (func.generic_owner != .none and ip.isRemoved(func.generic_owner))) { |
| 675 | try zcu.markDependeeOutdated(.{ .interned = func_index }); // IES | 756 | if (func_outdated) { |
| 676 | ip.removeDependenciesForDepender(gpa, InternPool.AnalUnit.wrap(.{ .func = func_index })); | 757 | try zcu.markDependeeOutdated(.marked_po, .{ .interned = func_index }); // IES |
| 758 | } | ||
| 759 | ip.removeDependenciesForDepender(gpa, AnalUnit.wrap(.{ .func = func_index })); | ||
| 677 | ip.remove(pt.tid, func_index); | 760 | ip.remove(pt.tid, func_index); |
| 678 | @panic("TODO: remove orphaned function from binary"); | 761 | @panic("TODO: remove orphaned function from binary"); |
| 679 | } | 762 | } |
| ... | @@ -685,15 +768,14 @@ pub fn ensureFuncBodyAnalyzed(pt: Zcu.PerThread, maybe_coerced_func_index: Inter | ... | @@ -685,15 +768,14 @@ pub fn ensureFuncBodyAnalyzed(pt: Zcu.PerThread, maybe_coerced_func_index: Inter |
| 685 | else | 768 | else |
| 686 | .none; | 769 | .none; |
| 687 | 770 | ||
| 688 | const anal_unit = InternPool.AnalUnit.wrap(.{ .func = func_index }); | ||
| 689 | const func_outdated = zcu.outdated.swapRemove(anal_unit) or | ||
| 690 | zcu.potentially_outdated.swapRemove(anal_unit); | ||
| 691 | |||
| 692 | if (func_outdated) { | 771 | if (func_outdated) { |
| 693 | dev.check(.incremental); | 772 | dev.check(.incremental); |
| 694 | _ = zcu.outdated_ready.swapRemove(anal_unit); | ||
| 695 | zcu.deleteUnitExports(anal_unit); | 773 | zcu.deleteUnitExports(anal_unit); |
| 696 | zcu.deleteUnitReferences(anal_unit); | 774 | zcu.deleteUnitReferences(anal_unit); |
| 775 | if (zcu.failed_analysis.fetchSwapRemove(anal_unit)) |kv| { | ||
| 776 | kv.value.destroy(gpa); | ||
| 777 | } | ||
| 778 | _ = zcu.transitive_failed_analysis.swapRemove(anal_unit); | ||
| 697 | } | 779 | } |
| 698 | 780 | ||
| 699 | if (!func_outdated) { | 781 | if (!func_outdated) { |
| ... | @@ -704,7 +786,7 @@ pub fn ensureFuncBodyAnalyzed(pt: Zcu.PerThread, maybe_coerced_func_index: Inter | ... | @@ -704,7 +786,7 @@ pub fn ensureFuncBodyAnalyzed(pt: Zcu.PerThread, maybe_coerced_func_index: Inter |
| 704 | switch (func.analysisUnordered(ip).state) { | 786 | switch (func.analysisUnordered(ip).state) { |
| 705 | .unreferenced => {}, // this is the first reference | 787 | .unreferenced => {}, // this is the first reference |
| 706 | .queued => {}, // we're waiting on first-time analysis | 788 | .queued => {}, // we're waiting on first-time analysis |
| 707 | .analyzed => return, // up-to-date | 789 | .analyzed => return .{ .ies_outdated = false }, // up-to-date |
| 708 | } | 790 | } |
| 709 | } | 791 | } |
| 710 | 792 | ||
| ... | @@ -713,28 +795,11 @@ pub fn ensureFuncBodyAnalyzed(pt: Zcu.PerThread, maybe_coerced_func_index: Inter | ... | @@ -713,28 +795,11 @@ pub fn ensureFuncBodyAnalyzed(pt: Zcu.PerThread, maybe_coerced_func_index: Inter |
| 713 | if (func_outdated) "outdated" else "never analyzed", | 795 | if (func_outdated) "outdated" else "never analyzed", |
| 714 | }); | 796 | }); |
| 715 | 797 | ||
| 716 | var air = pt.analyzeFnBody(func_index) catch |err| switch (err) { | 798 | var air = try pt.analyzeFnBody(func_index); |
| 717 | error.AnalysisFail => { | ||
| 718 | if (!zcu.failed_analysis.contains(anal_unit)) { | ||
| 719 | // If this function caused the error, it would have an entry in `failed_analysis`. | ||
| 720 | // Since it does not, this must be a transitive failure. | ||
| 721 | try zcu.transitive_failed_analysis.put(gpa, anal_unit, {}); | ||
| 722 | } | ||
| 723 | return error.AnalysisFail; | ||
| 724 | }, | ||
| 725 | error.OutOfMemory => return error.OutOfMemory, | ||
| 726 | }; | ||
| 727 | errdefer air.deinit(gpa); | 799 | errdefer air.deinit(gpa); |
| 728 | 800 | ||
| 729 | if (func_outdated) { | 801 | const ies_outdated = func_outdated and |
| 730 | if (!func.analysisUnordered(ip).inferred_error_set or func.resolvedErrorSetUnordered(ip) != old_resolved_ies) { | 802 | (!func.analysisUnordered(ip).inferred_error_set or func.resolvedErrorSetUnordered(ip) != old_resolved_ies); |
| 731 | log.debug("func IES invalidated ('{d}')", .{@intFromEnum(func_index)}); | ||
| 732 | try zcu.markDependeeOutdated(.{ .interned = func_index }); | ||
| 733 | } else { | ||
| 734 | log.debug("func IES up-to-date ('{d}')", .{@intFromEnum(func_index)}); | ||
| 735 | try zcu.markPoDependeeUpToDate(.{ .interned = func_index }); | ||
| 736 | } | ||
| 737 | } | ||
| 738 | 803 | ||
| 739 | const comp = zcu.comp; | 804 | const comp = zcu.comp; |
| 740 | 805 | ||
| ... | @@ -743,13 +808,15 @@ pub fn ensureFuncBodyAnalyzed(pt: Zcu.PerThread, maybe_coerced_func_index: Inter | ... | @@ -743,13 +808,15 @@ pub fn ensureFuncBodyAnalyzed(pt: Zcu.PerThread, maybe_coerced_func_index: Inter |
| 743 | 808 | ||
| 744 | if (comp.bin_file == null and zcu.llvm_object == null and !dump_air and !dump_llvm_ir) { | 809 | if (comp.bin_file == null and zcu.llvm_object == null and !dump_air and !dump_llvm_ir) { |
| 745 | air.deinit(gpa); | 810 | air.deinit(gpa); |
| 746 | return; | 811 | return .{ .ies_outdated = ies_outdated }; |
| 747 | } | 812 | } |
| 748 | 813 | ||
| 749 | try comp.queueJob(.{ .codegen_func = .{ | 814 | try comp.queueJob(.{ .codegen_func = .{ |
| 750 | .func = func_index, | 815 | .func = func_index, |
| 751 | .air = air, | 816 | .air = air, |
| 752 | } }); | 817 | } }); |
| 818 | |||
| 819 | return .{ .ies_outdated = ies_outdated }; | ||
| 753 | } | 820 | } |
| 754 | 821 | ||
| 755 | /// Takes ownership of `air`, even on error. | 822 | /// Takes ownership of `air`, even on error. |
| ... | @@ -824,7 +891,7 @@ pub fn linkerUpdateFunc(pt: Zcu.PerThread, func_index: InternPool.Index, air: Ai | ... | @@ -824,7 +891,7 @@ pub fn linkerUpdateFunc(pt: Zcu.PerThread, func_index: InternPool.Index, air: Ai |
| 824 | "unable to codegen: {s}", | 891 | "unable to codegen: {s}", |
| 825 | .{@errorName(err)}, | 892 | .{@errorName(err)}, |
| 826 | )); | 893 | )); |
| 827 | try zcu.retryable_failures.append(zcu.gpa, InternPool.AnalUnit.wrap(.{ .func = func_index })); | 894 | try zcu.retryable_failures.append(zcu.gpa, AnalUnit.wrap(.{ .func = func_index })); |
| 828 | }, | 895 | }, |
| 829 | }; | 896 | }; |
| 830 | } else if (zcu.llvm_object) |llvm_object| { | 897 | } else if (zcu.llvm_object) |llvm_object| { |
| ... | @@ -848,6 +915,7 @@ fn createFileRootStruct( | ... | @@ -848,6 +915,7 @@ fn createFileRootStruct( |
| 848 | pt: Zcu.PerThread, | 915 | pt: Zcu.PerThread, |
| 849 | file_index: Zcu.File.Index, | 916 | file_index: Zcu.File.Index, |
| 850 | namespace_index: Zcu.Namespace.Index, | 917 | namespace_index: Zcu.Namespace.Index, |
| 918 | replace_existing: bool, | ||
| 851 | ) Allocator.Error!InternPool.Index { | 919 | ) Allocator.Error!InternPool.Index { |
| 852 | const zcu = pt.zcu; | 920 | const zcu = pt.zcu; |
| 853 | const gpa = zcu.gpa; | 921 | const gpa = zcu.gpa; |
| ... | @@ -891,7 +959,7 @@ fn createFileRootStruct( | ... | @@ -891,7 +959,7 @@ fn createFileRootStruct( |
| 891 | .zir_index = tracked_inst, | 959 | .zir_index = tracked_inst, |
| 892 | .captures = &.{}, | 960 | .captures = &.{}, |
| 893 | } }, | 961 | } }, |
| 894 | })) { | 962 | }, replace_existing)) { |
| 895 | .existing => unreachable, // we wouldn't be analysing the file root if this type existed | 963 | .existing => unreachable, // we wouldn't be analysing the file root if this type existed |
| 896 | .wip => |wip| wip, | 964 | .wip => |wip| wip, |
| 897 | }; | 965 | }; |
| ... | @@ -904,7 +972,7 @@ fn createFileRootStruct( | ... | @@ -904,7 +972,7 @@ fn createFileRootStruct( |
| 904 | if (zcu.comp.incremental) { | 972 | if (zcu.comp.incremental) { |
| 905 | try ip.addDependency( | 973 | try ip.addDependency( |
| 906 | gpa, | 974 | gpa, |
| 907 | InternPool.AnalUnit.wrap(.{ .cau = new_cau_index }), | 975 | AnalUnit.wrap(.{ .cau = new_cau_index }), |
| 908 | .{ .src_hash = tracked_inst }, | 976 | .{ .src_hash = tracked_inst }, |
| 909 | ); | 977 | ); |
| 910 | } | 978 | } |
| ... | @@ -920,66 +988,42 @@ fn createFileRootStruct( | ... | @@ -920,66 +988,42 @@ fn createFileRootStruct( |
| 920 | return wip_ty.finish(ip, new_cau_index.toOptional(), namespace_index); | 988 | return wip_ty.finish(ip, new_cau_index.toOptional(), namespace_index); |
| 921 | } | 989 | } |
| 922 | 990 | ||
| 923 | /// Re-analyze the root type of a file on an incremental update. | 991 | /// Re-scan the namespace of a file's root struct type on an incremental update. |
| 924 | /// If `type_outdated`, the struct type itself is considered outdated and is | 992 | /// The file must have successfully populated ZIR. |
| 925 | /// reconstructed at a new InternPool index. Otherwise, the namespace is just | 993 | /// If the file's root struct type is not populated (the file is unreferenced), nothing is done. |
| 926 | /// re-analyzed. Returns whether the decl's tyval was invalidated. | 994 | /// This is called by `updateZirRefs` for all updated files before the main work loop. |
| 927 | /// Returns `error.AnalysisFail` if the file has an error. | 995 | /// This function does not perform any semantic analysis. |
| 928 | fn semaFileUpdate(pt: Zcu.PerThread, file_index: Zcu.File.Index, type_outdated: bool) Zcu.SemaError!bool { | 996 | fn updateFileNamespace(pt: Zcu.PerThread, file_index: Zcu.File.Index) Allocator.Error!void { |
| 929 | const zcu = pt.zcu; | 997 | const zcu = pt.zcu; |
| 930 | const ip = &zcu.intern_pool; | 998 | |
| 931 | const file = zcu.fileByIndex(file_index); | 999 | const file = zcu.fileByIndex(file_index); |
| 1000 | assert(file.status == .success_zir); | ||
| 932 | const file_root_type = zcu.fileRootType(file_index); | 1001 | const file_root_type = zcu.fileRootType(file_index); |
| 933 | const namespace_index = Type.fromInterned(file_root_type).getNamespaceIndex(zcu); | 1002 | if (file_root_type == .none) return; |
| 934 | 1003 | ||
| 935 | assert(file_root_type != .none); | 1004 | log.debug("updateFileNamespace mod={s} sub_file_path={s}", .{ |
| 936 | |||
| 937 | log.debug("semaFileUpdate mod={s} sub_file_path={s} type_outdated={}", .{ | ||
| 938 | file.mod.fully_qualified_name, | 1005 | file.mod.fully_qualified_name, |
| 939 | file.sub_file_path, | 1006 | file.sub_file_path, |
| 940 | type_outdated, | ||
| 941 | }); | 1007 | }); |
| 942 | 1008 | ||
| 943 | if (file.status != .success_zir) { | 1009 | const namespace_index = Type.fromInterned(file_root_type).getNamespaceIndex(zcu); |
| 944 | return error.AnalysisFail; | 1010 | const decls = decls: { |
| 945 | } | 1011 | const extended = file.zir.instructions.items(.data)[@intFromEnum(Zir.Inst.Index.main_struct_inst)].extended; |
| 946 | 1012 | const small: Zir.Inst.StructDecl.Small = @bitCast(extended.small); | |
| 947 | if (type_outdated) { | 1013 | |
| 948 | // Invalidate the existing type, reusing its namespace. | 1014 | var extra_index: usize = extended.operand + @typeInfo(Zir.Inst.StructDecl).Struct.fields.len; |
| 949 | const file_root_type_cau = ip.loadStructType(file_root_type).cau.unwrap().?; | 1015 | extra_index += @intFromBool(small.has_fields_len); |
| 950 | ip.removeDependenciesForDepender( | 1016 | const decls_len = if (small.has_decls_len) blk: { |
| 951 | zcu.gpa, | 1017 | const decls_len = file.zir.extra[extra_index]; |
| 952 | InternPool.AnalUnit.wrap(.{ .cau = file_root_type_cau }), | 1018 | extra_index += 1; |
| 953 | ); | 1019 | break :blk decls_len; |
| 954 | ip.remove(pt.tid, file_root_type); | 1020 | } else 0; |
| 955 | _ = try pt.createFileRootStruct(file_index, namespace_index); | 1021 | break :decls file.zir.bodySlice(extra_index, decls_len); |
| 956 | return true; | 1022 | }; |
| 957 | } | 1023 | try pt.scanNamespace(namespace_index, decls); |
| 958 | 1024 | zcu.namespacePtr(namespace_index).generation = zcu.generation; | |
| 959 | // Only the struct's namespace is outdated. | ||
| 960 | // Preserve the type - just scan the namespace again. | ||
| 961 | |||
| 962 | const extended = file.zir.instructions.items(.data)[@intFromEnum(Zir.Inst.Index.main_struct_inst)].extended; | ||
| 963 | const small: Zir.Inst.StructDecl.Small = @bitCast(extended.small); | ||
| 964 | |||
| 965 | var extra_index: usize = extended.operand + @typeInfo(Zir.Inst.StructDecl).Struct.fields.len; | ||
| 966 | extra_index += @intFromBool(small.has_fields_len); | ||
| 967 | const decls_len = if (small.has_decls_len) blk: { | ||
| 968 | const decls_len = file.zir.extra[extra_index]; | ||
| 969 | extra_index += 1; | ||
| 970 | break :blk decls_len; | ||
| 971 | } else 0; | ||
| 972 | const decls = file.zir.bodySlice(extra_index, decls_len); | ||
| 973 | |||
| 974 | if (!type_outdated) { | ||
| 975 | try pt.scanNamespace(namespace_index, decls); | ||
| 976 | } | ||
| 977 | |||
| 978 | return false; | ||
| 979 | } | 1025 | } |
| 980 | 1026 | ||
| 981 | /// Regardless of the file status, will create a `Decl` if none exists so that we can track | ||
| 982 | /// dependencies and re-analyze when the file becomes outdated. | ||
| 983 | fn semaFile(pt: Zcu.PerThread, file_index: Zcu.File.Index) Zcu.SemaError!void { | 1027 | fn semaFile(pt: Zcu.PerThread, file_index: Zcu.File.Index) Zcu.SemaError!void { |
| 984 | const tracy = trace(@src()); | 1028 | const tracy = trace(@src()); |
| 985 | defer tracy.end(); | 1029 | defer tracy.end(); |
| ... | @@ -998,8 +1042,9 @@ fn semaFile(pt: Zcu.PerThread, file_index: Zcu.File.Index) Zcu.SemaError!void { | ... | @@ -998,8 +1042,9 @@ fn semaFile(pt: Zcu.PerThread, file_index: Zcu.File.Index) Zcu.SemaError!void { |
| 998 | .parent = .none, | 1042 | .parent = .none, |
| 999 | .owner_type = undefined, // set in `createFileRootStruct` | 1043 | .owner_type = undefined, // set in `createFileRootStruct` |
| 1000 | .file_scope = file_index, | 1044 | .file_scope = file_index, |
| 1045 | .generation = zcu.generation, | ||
| 1001 | }); | 1046 | }); |
| 1002 | const struct_ty = try pt.createFileRootStruct(file_index, new_namespace_index); | 1047 | const struct_ty = try pt.createFileRootStruct(file_index, new_namespace_index, false); |
| 1003 | errdefer zcu.intern_pool.remove(pt.tid, struct_ty); | 1048 | errdefer zcu.intern_pool.remove(pt.tid, struct_ty); |
| 1004 | 1049 | ||
| 1005 | switch (zcu.comp.cache_use) { | 1050 | switch (zcu.comp.cache_use) { |
| ... | @@ -1049,10 +1094,10 @@ fn semaCau(pt: Zcu.PerThread, cau_index: InternPool.Cau.Index) !SemaCauResult { | ... | @@ -1049,10 +1094,10 @@ fn semaCau(pt: Zcu.PerThread, cau_index: InternPool.Cau.Index) !SemaCauResult { |
| 1049 | const gpa = zcu.gpa; | 1094 | const gpa = zcu.gpa; |
| 1050 | const ip = &zcu.intern_pool; | 1095 | const ip = &zcu.intern_pool; |
| 1051 | 1096 | ||
| 1052 | const anal_unit = InternPool.AnalUnit.wrap(.{ .cau = cau_index }); | 1097 | const anal_unit = AnalUnit.wrap(.{ .cau = cau_index }); |
| 1053 | 1098 | ||
| 1054 | const cau = ip.getCau(cau_index); | 1099 | const cau = ip.getCau(cau_index); |
| 1055 | const inst_info = cau.zir_index.resolveFull(ip); | 1100 | const inst_info = cau.zir_index.resolveFull(ip) orelse return error.AnalysisFail; |
| 1056 | const file = zcu.fileByIndex(inst_info.file); | 1101 | const file = zcu.fileByIndex(inst_info.file); |
| 1057 | const zir = file.zir; | 1102 | const zir = file.zir; |
| 1058 | 1103 | ||
| ... | @@ -1071,9 +1116,10 @@ fn semaCau(pt: Zcu.PerThread, cau_index: InternPool.Cau.Index) !SemaCauResult { | ... | @@ -1071,9 +1116,10 @@ fn semaCau(pt: Zcu.PerThread, cau_index: InternPool.Cau.Index) !SemaCauResult { |
| 1071 | }, | 1116 | }, |
| 1072 | .type => |ty| { | 1117 | .type => |ty| { |
| 1073 | // This is an incremental update, and this type is being re-analyzed because it is outdated. | 1118 | // This is an incremental update, and this type is being re-analyzed because it is outdated. |
| 1074 | // The type must be recreated at a new `InternPool.Index`. | 1119 | // Create a new type in its place, and mark the old one as outdated so that use sites will |
| 1075 | // Remove it from the InternPool and mark it outdated so that creation sites are re-analyzed. | 1120 | // be re-analyzed and discover an up-to-date type. |
| 1076 | ip.remove(pt.tid, ty); | 1121 | const new_ty = try pt.ensureTypeUpToDate(ty, true); |
| 1122 | assert(new_ty != ty); | ||
| 1077 | return .{ | 1123 | return .{ |
| 1078 | .invalidate_decl_val = true, | 1124 | .invalidate_decl_val = true, |
| 1079 | .invalidate_decl_ref = true, | 1125 | .invalidate_decl_ref = true, |
| ... | @@ -1919,21 +1965,25 @@ const ScanDeclIter = struct { | ... | @@ -1919,21 +1965,25 @@ const ScanDeclIter = struct { |
| 1919 | .@"comptime" => cau: { | 1965 | .@"comptime" => cau: { |
| 1920 | const cau = existing_cau orelse try ip.createComptimeCau(gpa, pt.tid, tracked_inst, namespace_index); | 1966 | const cau = existing_cau orelse try ip.createComptimeCau(gpa, pt.tid, tracked_inst, namespace_index); |
| 1921 | 1967 | ||
| 1922 | // For a `comptime` declaration, whether to re-analyze is based solely on whether the | 1968 | try namespace.other_decls.append(gpa, cau); |
| 1923 | // `Cau` is outdated. So, add this one to `outdated` and `outdated_ready` if not already. | 1969 | |
| 1924 | const unit = InternPool.AnalUnit.wrap(.{ .cau = cau }); | 1970 | if (existing_cau == null) { |
| 1925 | if (zcu.potentially_outdated.fetchSwapRemove(unit)) |kv| { | 1971 | // For a `comptime` declaration, whether to analyze is based solely on whether the |
| 1926 | try zcu.outdated.ensureUnusedCapacity(gpa, 1); | 1972 | // `Cau` is outdated. So, add this one to `outdated` and `outdated_ready` if not already. |
| 1927 | try zcu.outdated_ready.ensureUnusedCapacity(gpa, 1); | 1973 | const unit = AnalUnit.wrap(.{ .cau = cau }); |
| 1928 | zcu.outdated.putAssumeCapacityNoClobber(unit, kv.value); | 1974 | if (zcu.potentially_outdated.fetchSwapRemove(unit)) |kv| { |
| 1929 | if (kv.value == 0) { // no PO deps | 1975 | try zcu.outdated.ensureUnusedCapacity(gpa, 1); |
| 1976 | try zcu.outdated_ready.ensureUnusedCapacity(gpa, 1); | ||
| 1977 | zcu.outdated.putAssumeCapacityNoClobber(unit, kv.value); | ||
| 1978 | if (kv.value == 0) { // no PO deps | ||
| 1979 | zcu.outdated_ready.putAssumeCapacityNoClobber(unit, {}); | ||
| 1980 | } | ||
| 1981 | } else if (!zcu.outdated.contains(unit)) { | ||
| 1982 | try zcu.outdated.ensureUnusedCapacity(gpa, 1); | ||
| 1983 | try zcu.outdated_ready.ensureUnusedCapacity(gpa, 1); | ||
| 1984 | zcu.outdated.putAssumeCapacityNoClobber(unit, 0); | ||
| 1930 | zcu.outdated_ready.putAssumeCapacityNoClobber(unit, {}); | 1985 | zcu.outdated_ready.putAssumeCapacityNoClobber(unit, {}); |
| 1931 | } | 1986 | } |
| 1932 | } else if (!zcu.outdated.contains(unit)) { | ||
| 1933 | try zcu.outdated.ensureUnusedCapacity(gpa, 1); | ||
| 1934 | try zcu.outdated_ready.ensureUnusedCapacity(gpa, 1); | ||
| 1935 | zcu.outdated.putAssumeCapacityNoClobber(unit, 0); | ||
| 1936 | zcu.outdated_ready.putAssumeCapacityNoClobber(unit, {}); | ||
| 1937 | } | 1987 | } |
| 1938 | 1988 | ||
| 1939 | break :cau .{ cau, true }; | 1989 | break :cau .{ cau, true }; |
| ... | @@ -1951,6 +2001,9 @@ const ScanDeclIter = struct { | ... | @@ -1951,6 +2001,9 @@ const ScanDeclIter = struct { |
| 1951 | const want_analysis = switch (kind) { | 2001 | const want_analysis = switch (kind) { |
| 1952 | .@"comptime" => unreachable, | 2002 | .@"comptime" => unreachable, |
| 1953 | .@"usingnamespace" => a: { | 2003 | .@"usingnamespace" => a: { |
| 2004 | if (comp.incremental) { | ||
| 2005 | @panic("'usingnamespace' is not supported by incremental compilation"); | ||
| 2006 | } | ||
| 1954 | if (declaration.flags.is_pub) { | 2007 | if (declaration.flags.is_pub) { |
| 1955 | try namespace.pub_usingnamespace.append(gpa, nav); | 2008 | try namespace.pub_usingnamespace.append(gpa, nav); |
| 1956 | } else { | 2009 | } else { |
| ... | @@ -1989,7 +2042,7 @@ const ScanDeclIter = struct { | ... | @@ -1989,7 +2042,7 @@ const ScanDeclIter = struct { |
| 1989 | }, | 2042 | }, |
| 1990 | }; | 2043 | }; |
| 1991 | 2044 | ||
| 1992 | if (want_analysis or declaration.flags.is_export) { | 2045 | if (existing_cau == null and (want_analysis or declaration.flags.is_export)) { |
| 1993 | log.debug( | 2046 | log.debug( |
| 1994 | "scanDecl queue analyze_cau file='{s}' cau_index={d}", | 2047 | "scanDecl queue analyze_cau file='{s}' cau_index={d}", |
| 1995 | .{ namespace.fileScope(zcu).sub_file_path, cau }, | 2048 | .{ namespace.fileScope(zcu).sub_file_path, cau }, |
| ... | @@ -2009,9 +2062,9 @@ fn analyzeFnBody(pt: Zcu.PerThread, func_index: InternPool.Index) Zcu.SemaError! | ... | @@ -2009,9 +2062,9 @@ fn analyzeFnBody(pt: Zcu.PerThread, func_index: InternPool.Index) Zcu.SemaError! |
| 2009 | const gpa = zcu.gpa; | 2062 | const gpa = zcu.gpa; |
| 2010 | const ip = &zcu.intern_pool; | 2063 | const ip = &zcu.intern_pool; |
| 2011 | 2064 | ||
| 2012 | const anal_unit = InternPool.AnalUnit.wrap(.{ .func = func_index }); | 2065 | const anal_unit = AnalUnit.wrap(.{ .func = func_index }); |
| 2013 | const func = zcu.funcInfo(func_index); | 2066 | const func = zcu.funcInfo(func_index); |
| 2014 | const inst_info = func.zir_body_inst.resolveFull(ip); | 2067 | const inst_info = func.zir_body_inst.resolveFull(ip) orelse return error.AnalysisFail; |
| 2015 | const file = zcu.fileByIndex(inst_info.file); | 2068 | const file = zcu.fileByIndex(inst_info.file); |
| 2016 | const zir = file.zir; | 2069 | const zir = file.zir; |
| 2017 | 2070 | ||
| ... | @@ -2097,7 +2150,7 @@ fn analyzeFnBody(pt: Zcu.PerThread, func_index: InternPool.Index) Zcu.SemaError! | ... | @@ -2097,7 +2150,7 @@ fn analyzeFnBody(pt: Zcu.PerThread, func_index: InternPool.Index) Zcu.SemaError! |
| 2097 | }; | 2150 | }; |
| 2098 | defer inner_block.instructions.deinit(gpa); | 2151 | defer inner_block.instructions.deinit(gpa); |
| 2099 | 2152 | ||
| 2100 | const fn_info = sema.code.getFnInfo(func.zirBodyInstUnordered(ip).resolve(ip)); | 2153 | const fn_info = sema.code.getFnInfo(func.zirBodyInstUnordered(ip).resolve(ip) orelse return error.AnalysisFail); |
| 2101 | 2154 | ||
| 2102 | // Here we are performing "runtime semantic analysis" for a function body, which means | 2155 | // Here we are performing "runtime semantic analysis" for a function body, which means |
| 2103 | // we must map the parameter ZIR instructions to `arg` AIR instructions. | 2156 | // we must map the parameter ZIR instructions to `arg` AIR instructions. |
| ... | @@ -2395,7 +2448,7 @@ fn processExportsInner( | ... | @@ -2395,7 +2448,7 @@ fn processExportsInner( |
| 2395 | const nav = ip.getNav(nav_index); | 2448 | const nav = ip.getNav(nav_index); |
| 2396 | if (zcu.failed_codegen.contains(nav_index)) break :failed true; | 2449 | if (zcu.failed_codegen.contains(nav_index)) break :failed true; |
| 2397 | if (nav.analysis_owner.unwrap()) |cau| { | 2450 | if (nav.analysis_owner.unwrap()) |cau| { |
| 2398 | const cau_unit = InternPool.AnalUnit.wrap(.{ .cau = cau }); | 2451 | const cau_unit = AnalUnit.wrap(.{ .cau = cau }); |
| 2399 | if (zcu.failed_analysis.contains(cau_unit)) break :failed true; | 2452 | if (zcu.failed_analysis.contains(cau_unit)) break :failed true; |
| 2400 | if (zcu.transitive_failed_analysis.contains(cau_unit)) break :failed true; | 2453 | if (zcu.transitive_failed_analysis.contains(cau_unit)) break :failed true; |
| 2401 | } | 2454 | } |
| ... | @@ -2405,7 +2458,7 @@ fn processExportsInner( | ... | @@ -2405,7 +2458,7 @@ fn processExportsInner( |
| 2405 | }; | 2458 | }; |
| 2406 | // If the value is a function, we also need to check if that function succeeded analysis. | 2459 | // If the value is a function, we also need to check if that function succeeded analysis. |
| 2407 | if (val.typeOf(zcu).zigTypeTag(zcu) == .Fn) { | 2460 | if (val.typeOf(zcu).zigTypeTag(zcu) == .Fn) { |
| 2408 | const func_unit = InternPool.AnalUnit.wrap(.{ .func = val.toIntern() }); | 2461 | const func_unit = AnalUnit.wrap(.{ .func = val.toIntern() }); |
| 2409 | if (zcu.failed_analysis.contains(func_unit)) break :failed true; | 2462 | if (zcu.failed_analysis.contains(func_unit)) break :failed true; |
| 2410 | if (zcu.transitive_failed_analysis.contains(func_unit)) break :failed true; | 2463 | if (zcu.transitive_failed_analysis.contains(func_unit)) break :failed true; |
| 2411 | } | 2464 | } |
| ... | @@ -2580,7 +2633,7 @@ pub fn linkerUpdateNav(pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) !void | ... | @@ -2580,7 +2633,7 @@ pub fn linkerUpdateNav(pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) !void |
| 2580 | .{@errorName(err)}, | 2633 | .{@errorName(err)}, |
| 2581 | )); | 2634 | )); |
| 2582 | if (nav.analysis_owner.unwrap()) |cau| { | 2635 | if (nav.analysis_owner.unwrap()) |cau| { |
| 2583 | try zcu.retryable_failures.append(zcu.gpa, InternPool.AnalUnit.wrap(.{ .cau = cau })); | 2636 | try zcu.retryable_failures.append(zcu.gpa, AnalUnit.wrap(.{ .cau = cau })); |
| 2584 | } else { | 2637 | } else { |
| 2585 | // TODO: we don't have a way to indicate that this failure is retryable! | 2638 | // TODO: we don't have a way to indicate that this failure is retryable! |
| 2586 | // Since these are really rare, we could as a cop-out retry the whole build next update. | 2639 | // Since these are really rare, we could as a cop-out retry the whole build next update. |
| ... | @@ -2693,7 +2746,7 @@ pub fn reportRetryableFileError( | ... | @@ -2693,7 +2746,7 @@ pub fn reportRetryableFileError( |
| 2693 | gop.value_ptr.* = err_msg; | 2746 | gop.value_ptr.* = err_msg; |
| 2694 | } | 2747 | } |
| 2695 | 2748 | ||
| 2696 | /// Shortcut for calling `intern_pool.get`. | 2749 | ///Shortcut for calling `intern_pool.get`. |
| 2697 | pub fn intern(pt: Zcu.PerThread, key: InternPool.Key) Allocator.Error!InternPool.Index { | 2750 | pub fn intern(pt: Zcu.PerThread, key: InternPool.Key) Allocator.Error!InternPool.Index { |
| 2698 | return pt.zcu.intern_pool.get(pt.zcu.gpa, pt.tid, key); | 2751 | return pt.zcu.intern_pool.get(pt.zcu.gpa, pt.tid, key); |
| 2699 | } | 2752 | } |
| ... | @@ -3278,6 +3331,532 @@ pub fn navAlignment(pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) InternPo | ... | @@ -3278,6 +3331,532 @@ pub fn navAlignment(pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) InternPo |
| 3278 | return Value.fromInterned(r.val).typeOf(zcu).abiAlignment(pt); | 3331 | return Value.fromInterned(r.val).typeOf(zcu).abiAlignment(pt); |
| 3279 | } | 3332 | } |
| 3280 | 3333 | ||
| 3334 | /// Given a container type requiring resolution, ensures that it is up-to-date. | ||
| 3335 | /// If not, the type is recreated at a new `InternPool.Index`. | ||
| 3336 | /// The new index is returned. This is the same as the old index if the fields were up-to-date. | ||
| 3337 | /// If `already_updating` is set, assumes the type is already outdated and undergoing re-analysis rather than checking `zcu.outdated`. | ||
| 3338 | pub fn ensureTypeUpToDate(pt: Zcu.PerThread, ty: InternPool.Index, already_updating: bool) Zcu.SemaError!InternPool.Index { | ||
| 3339 | const zcu = pt.zcu; | ||
| 3340 | const ip = &zcu.intern_pool; | ||
| 3341 | switch (ip.indexToKey(ty)) { | ||
| 3342 | .struct_type => |key| { | ||
| 3343 | const struct_obj = ip.loadStructType(ty); | ||
| 3344 | const outdated = already_updating or o: { | ||
| 3345 | const anal_unit = AnalUnit.wrap(.{ .cau = struct_obj.cau.unwrap().? }); | ||
| 3346 | const o = zcu.outdated.swapRemove(anal_unit) or | ||
| 3347 | zcu.potentially_outdated.swapRemove(anal_unit); | ||
| 3348 | if (o) { | ||
| 3349 | _ = zcu.outdated_ready.swapRemove(anal_unit); | ||
| 3350 | try zcu.markDependeeOutdated(.marked_po, .{ .interned = ty }); | ||
| 3351 | } | ||
| 3352 | break :o o; | ||
| 3353 | }; | ||
| 3354 | if (!outdated) return ty; | ||
| 3355 | return pt.recreateStructType(ty, key, struct_obj); | ||
| 3356 | }, | ||
| 3357 | .union_type => |key| { | ||
| 3358 | const union_obj = ip.loadUnionType(ty); | ||
| 3359 | const outdated = already_updating or o: { | ||
| 3360 | const anal_unit = AnalUnit.wrap(.{ .cau = union_obj.cau }); | ||
| 3361 | const o = zcu.outdated.swapRemove(anal_unit) or | ||
| 3362 | zcu.potentially_outdated.swapRemove(anal_unit); | ||
| 3363 | if (o) { | ||
| 3364 | _ = zcu.outdated_ready.swapRemove(anal_unit); | ||
| 3365 | try zcu.markDependeeOutdated(.marked_po, .{ .interned = ty }); | ||
| 3366 | } | ||
| 3367 | break :o o; | ||
| 3368 | }; | ||
| 3369 | if (!outdated) return ty; | ||
| 3370 | return pt.recreateUnionType(ty, key, union_obj); | ||
| 3371 | }, | ||
| 3372 | .enum_type => |key| { | ||
| 3373 | const enum_obj = ip.loadEnumType(ty); | ||
| 3374 | const outdated = already_updating or o: { | ||
| 3375 | const anal_unit = AnalUnit.wrap(.{ .cau = enum_obj.cau.unwrap().? }); | ||
| 3376 | const o = zcu.outdated.swapRemove(anal_unit) or | ||
| 3377 | zcu.potentially_outdated.swapRemove(anal_unit); | ||
| 3378 | if (o) { | ||
| 3379 | _ = zcu.outdated_ready.swapRemove(anal_unit); | ||
| 3380 | try zcu.markDependeeOutdated(.marked_po, .{ .interned = ty }); | ||
| 3381 | } | ||
| 3382 | break :o o; | ||
| 3383 | }; | ||
| 3384 | if (!outdated) return ty; | ||
| 3385 | return pt.recreateEnumType(ty, key, enum_obj); | ||
| 3386 | }, | ||
| 3387 | .opaque_type => { | ||
| 3388 | assert(!already_updating); | ||
| 3389 | return ty; | ||
| 3390 | }, | ||
| 3391 | else => unreachable, | ||
| 3392 | } | ||
| 3393 | } | ||
| 3394 | |||
| 3395 | fn recreateStructType( | ||
| 3396 | pt: Zcu.PerThread, | ||
| 3397 | ty: InternPool.Index, | ||
| 3398 | full_key: InternPool.Key.NamespaceType, | ||
| 3399 | struct_obj: InternPool.LoadedStructType, | ||
| 3400 | ) Zcu.SemaError!InternPool.Index { | ||
| 3401 | const zcu = pt.zcu; | ||
| 3402 | const gpa = zcu.gpa; | ||
| 3403 | const ip = &zcu.intern_pool; | ||
| 3404 | |||
| 3405 | const key = switch (full_key) { | ||
| 3406 | .reified => unreachable, // never outdated | ||
| 3407 | .empty_struct => unreachable, // never outdated | ||
| 3408 | .generated_tag => unreachable, // not a struct | ||
| 3409 | .declared => |d| d, | ||
| 3410 | }; | ||
| 3411 | |||
| 3412 | if (@intFromEnum(ty) <= InternPool.static_len) { | ||
| 3413 | @panic("TODO: recreate resolved builtin type"); | ||
| 3414 | } | ||
| 3415 | |||
| 3416 | const inst_info = key.zir_index.resolveFull(ip) orelse return error.AnalysisFail; | ||
| 3417 | const file = zcu.fileByIndex(inst_info.file); | ||
| 3418 | if (file.status != .success_zir) return error.AnalysisFail; | ||
| 3419 | const zir = file.zir; | ||
| 3420 | |||
| 3421 | assert(zir.instructions.items(.tag)[@intFromEnum(inst_info.inst)] == .extended); | ||
| 3422 | const extended = zir.instructions.items(.data)[@intFromEnum(inst_info.inst)].extended; | ||
| 3423 | assert(extended.opcode == .struct_decl); | ||
| 3424 | const small: Zir.Inst.StructDecl.Small = @bitCast(extended.small); | ||
| 3425 | const extra = zir.extraData(Zir.Inst.StructDecl, extended.operand); | ||
| 3426 | var extra_index = extra.end; | ||
| 3427 | |||
| 3428 | const captures_len = if (small.has_captures_len) blk: { | ||
| 3429 | const captures_len = zir.extra[extra_index]; | ||
| 3430 | extra_index += 1; | ||
| 3431 | break :blk captures_len; | ||
| 3432 | } else 0; | ||
| 3433 | const fields_len = if (small.has_fields_len) blk: { | ||
| 3434 | const fields_len = zir.extra[extra_index]; | ||
| 3435 | extra_index += 1; | ||
| 3436 | break :blk fields_len; | ||
| 3437 | } else 0; | ||
| 3438 | |||
| 3439 | if (captures_len != key.captures.owned.len) return error.AnalysisFail; | ||
| 3440 | if (fields_len != struct_obj.field_types.len) return error.AnalysisFail; | ||
| 3441 | |||
| 3442 | // The old type will be unused, so drop its dependency information. | ||
| 3443 | ip.removeDependenciesForDepender(gpa, AnalUnit.wrap(.{ .cau = struct_obj.cau.unwrap().? })); | ||
| 3444 | |||
| 3445 | const namespace_index = struct_obj.namespace.unwrap().?; | ||
| 3446 | |||
| 3447 | const wip_ty = switch (try ip.getStructType(gpa, pt.tid, .{ | ||
| 3448 | .layout = small.layout, | ||
| 3449 | .fields_len = fields_len, | ||
| 3450 | .known_non_opv = small.known_non_opv, | ||
| 3451 | .requires_comptime = if (small.known_comptime_only) .yes else .unknown, | ||
| 3452 | .is_tuple = small.is_tuple, | ||
| 3453 | .any_comptime_fields = small.any_comptime_fields, | ||
| 3454 | .any_default_inits = small.any_default_inits, | ||
| 3455 | .inits_resolved = false, | ||
| 3456 | .any_aligned_fields = small.any_aligned_fields, | ||
| 3457 | .key = .{ .declared_owned_captures = .{ | ||
| 3458 | .zir_index = key.zir_index, | ||
| 3459 | .captures = key.captures.owned, | ||
| 3460 | } }, | ||
| 3461 | }, true)) { | ||
| 3462 | .wip => |wip| wip, | ||
| 3463 | .existing => unreachable, // we passed `replace_existing` | ||
| 3464 | }; | ||
| 3465 | errdefer wip_ty.cancel(ip, pt.tid); | ||
| 3466 | |||
| 3467 | wip_ty.setName(ip, struct_obj.name); | ||
| 3468 | const new_cau_index = try ip.createTypeCau(gpa, pt.tid, key.zir_index, namespace_index, wip_ty.index); | ||
| 3469 | try ip.addDependency( | ||
| 3470 | gpa, | ||
| 3471 | AnalUnit.wrap(.{ .cau = new_cau_index }), | ||
| 3472 | .{ .src_hash = key.zir_index }, | ||
| 3473 | ); | ||
| 3474 | zcu.namespacePtr(namespace_index).owner_type = wip_ty.index; | ||
| 3475 | // No need to re-scan the namespace -- `zirStructDecl` will ultimately do that if the type is still alive. | ||
| 3476 | try zcu.comp.queueJob(.{ .resolve_type_fully = wip_ty.index }); | ||
| 3477 | |||
| 3478 | const new_ty = wip_ty.finish(ip, new_cau_index.toOptional(), namespace_index); | ||
| 3479 | if (inst_info.inst == .main_struct_inst) { | ||
| 3480 | // This is the root type of a file! Update the reference. | ||
| 3481 | zcu.setFileRootType(inst_info.file, new_ty); | ||
| 3482 | } | ||
| 3483 | return new_ty; | ||
| 3484 | } | ||
| 3485 | |||
| 3486 | fn recreateUnionType( | ||
| 3487 | pt: Zcu.PerThread, | ||
| 3488 | ty: InternPool.Index, | ||
| 3489 | full_key: InternPool.Key.NamespaceType, | ||
| 3490 | union_obj: InternPool.LoadedUnionType, | ||
| 3491 | ) Zcu.SemaError!InternPool.Index { | ||
| 3492 | const zcu = pt.zcu; | ||
| 3493 | const gpa = zcu.gpa; | ||
| 3494 | const ip = &zcu.intern_pool; | ||
| 3495 | |||
| 3496 | const key = switch (full_key) { | ||
| 3497 | .reified => unreachable, // never outdated | ||
| 3498 | .empty_struct => unreachable, // never outdated | ||
| 3499 | .generated_tag => unreachable, // not a union | ||
| 3500 | .declared => |d| d, | ||
| 3501 | }; | ||
| 3502 | |||
| 3503 | if (@intFromEnum(ty) <= InternPool.static_len) { | ||
| 3504 | @panic("TODO: recreate resolved builtin type"); | ||
| 3505 | } | ||
| 3506 | |||
| 3507 | const inst_info = key.zir_index.resolveFull(ip) orelse return error.AnalysisFail; | ||
| 3508 | const file = zcu.fileByIndex(inst_info.file); | ||
| 3509 | if (file.status != .success_zir) return error.AnalysisFail; | ||
| 3510 | const zir = file.zir; | ||
| 3511 | |||
| 3512 | assert(zir.instructions.items(.tag)[@intFromEnum(inst_info.inst)] == .extended); | ||
| 3513 | const extended = zir.instructions.items(.data)[@intFromEnum(inst_info.inst)].extended; | ||
| 3514 | assert(extended.opcode == .union_decl); | ||
| 3515 | const small: Zir.Inst.UnionDecl.Small = @bitCast(extended.small); | ||
| 3516 | const extra = zir.extraData(Zir.Inst.UnionDecl, extended.operand); | ||
| 3517 | var extra_index = extra.end; | ||
| 3518 | |||
| 3519 | extra_index += @intFromBool(small.has_tag_type); | ||
| 3520 | const captures_len = if (small.has_captures_len) blk: { | ||
| 3521 | const captures_len = zir.extra[extra_index]; | ||
| 3522 | extra_index += 1; | ||
| 3523 | break :blk captures_len; | ||
| 3524 | } else 0; | ||
| 3525 | extra_index += @intFromBool(small.has_body_len); | ||
| 3526 | const fields_len = if (small.has_fields_len) blk: { | ||
| 3527 | const fields_len = zir.extra[extra_index]; | ||
| 3528 | extra_index += 1; | ||
| 3529 | break :blk fields_len; | ||
| 3530 | } else 0; | ||
| 3531 | |||
| 3532 | if (captures_len != key.captures.owned.len) return error.AnalysisFail; | ||
| 3533 | if (fields_len != union_obj.field_types.len) return error.AnalysisFail; | ||
| 3534 | |||
| 3535 | // The old type will be unused, so drop its dependency information. | ||
| 3536 | ip.removeDependenciesForDepender(gpa, AnalUnit.wrap(.{ .cau = union_obj.cau })); | ||
| 3537 | |||
| 3538 | const namespace_index = union_obj.namespace; | ||
| 3539 | |||
| 3540 | const wip_ty = switch (try ip.getUnionType(gpa, pt.tid, .{ | ||
| 3541 | .flags = .{ | ||
| 3542 | .layout = small.layout, | ||
| 3543 | .status = .none, | ||
| 3544 | .runtime_tag = if (small.has_tag_type or small.auto_enum_tag) | ||
| 3545 | .tagged | ||
| 3546 | else if (small.layout != .auto) | ||
| 3547 | .none | ||
| 3548 | else switch (true) { // TODO | ||
| 3549 | true => .safety, | ||
| 3550 | false => .none, | ||
| 3551 | }, | ||
| 3552 | .any_aligned_fields = small.any_aligned_fields, | ||
| 3553 | .requires_comptime = .unknown, | ||
| 3554 | .assumed_runtime_bits = false, | ||
| 3555 | .assumed_pointer_aligned = false, | ||
| 3556 | .alignment = .none, | ||
| 3557 | }, | ||
| 3558 | .fields_len = fields_len, | ||
| 3559 | .enum_tag_ty = .none, // set later | ||
| 3560 | .field_types = &.{}, // set later | ||
| 3561 | .field_aligns = &.{}, // set later | ||
| 3562 | .key = .{ .declared_owned_captures = .{ | ||
| 3563 | .zir_index = key.zir_index, | ||
| 3564 | .captures = key.captures.owned, | ||
| 3565 | } }, | ||
| 3566 | }, true)) { | ||
| 3567 | .wip => |wip| wip, | ||
| 3568 | .existing => unreachable, // we passed `replace_existing` | ||
| 3569 | }; | ||
| 3570 | errdefer wip_ty.cancel(ip, pt.tid); | ||
| 3571 | |||
| 3572 | wip_ty.setName(ip, union_obj.name); | ||
| 3573 | const new_cau_index = try ip.createTypeCau(gpa, pt.tid, key.zir_index, namespace_index, wip_ty.index); | ||
| 3574 | try ip.addDependency( | ||
| 3575 | gpa, | ||
| 3576 | AnalUnit.wrap(.{ .cau = new_cau_index }), | ||
| 3577 | .{ .src_hash = key.zir_index }, | ||
| 3578 | ); | ||
| 3579 | zcu.namespacePtr(namespace_index).owner_type = wip_ty.index; | ||
| 3580 | // No need to re-scan the namespace -- `zirUnionDecl` will ultimately do that if the type is still alive. | ||
| 3581 | try zcu.comp.queueJob(.{ .resolve_type_fully = wip_ty.index }); | ||
| 3582 | return wip_ty.finish(ip, new_cau_index.toOptional(), namespace_index); | ||
| 3583 | } | ||
| 3584 | |||
| 3585 | fn recreateEnumType( | ||
| 3586 | pt: Zcu.PerThread, | ||
| 3587 | ty: InternPool.Index, | ||
| 3588 | full_key: InternPool.Key.NamespaceType, | ||
| 3589 | enum_obj: InternPool.LoadedEnumType, | ||
| 3590 | ) Zcu.SemaError!InternPool.Index { | ||
| 3591 | const zcu = pt.zcu; | ||
| 3592 | const gpa = zcu.gpa; | ||
| 3593 | const ip = &zcu.intern_pool; | ||
| 3594 | |||
| 3595 | const key = switch (full_key) { | ||
| 3596 | .reified => unreachable, // never outdated | ||
| 3597 | .empty_struct => unreachable, // never outdated | ||
| 3598 | .generated_tag => unreachable, // never outdated | ||
| 3599 | .declared => |d| d, | ||
| 3600 | }; | ||
| 3601 | |||
| 3602 | if (@intFromEnum(ty) <= InternPool.static_len) { | ||
| 3603 | @panic("TODO: recreate resolved builtin type"); | ||
| 3604 | } | ||
| 3605 | |||
| 3606 | const inst_info = key.zir_index.resolveFull(ip) orelse return error.AnalysisFail; | ||
| 3607 | const file = zcu.fileByIndex(inst_info.file); | ||
| 3608 | if (file.status != .success_zir) return error.AnalysisFail; | ||
| 3609 | const zir = file.zir; | ||
| 3610 | |||
| 3611 | assert(zir.instructions.items(.tag)[@intFromEnum(inst_info.inst)] == .extended); | ||
| 3612 | const extended = zir.instructions.items(.data)[@intFromEnum(inst_info.inst)].extended; | ||
| 3613 | assert(extended.opcode == .enum_decl); | ||
| 3614 | const small: Zir.Inst.EnumDecl.Small = @bitCast(extended.small); | ||
| 3615 | const extra = zir.extraData(Zir.Inst.EnumDecl, extended.operand); | ||
| 3616 | var extra_index = extra.end; | ||
| 3617 | |||
| 3618 | const tag_type_ref = if (small.has_tag_type) blk: { | ||
| 3619 | const tag_type_ref: Zir.Inst.Ref = @enumFromInt(zir.extra[extra_index]); | ||
| 3620 | extra_index += 1; | ||
| 3621 | break :blk tag_type_ref; | ||
| 3622 | } else .none; | ||
| 3623 | |||
| 3624 | const captures_len = if (small.has_captures_len) blk: { | ||
| 3625 | const captures_len = zir.extra[extra_index]; | ||
| 3626 | extra_index += 1; | ||
| 3627 | break :blk captures_len; | ||
| 3628 | } else 0; | ||
| 3629 | |||
| 3630 | const body_len = if (small.has_body_len) blk: { | ||
| 3631 | const body_len = zir.extra[extra_index]; | ||
| 3632 | extra_index += 1; | ||
| 3633 | break :blk body_len; | ||
| 3634 | } else 0; | ||
| 3635 | |||
| 3636 | const fields_len = if (small.has_fields_len) blk: { | ||
| 3637 | const fields_len = zir.extra[extra_index]; | ||
| 3638 | extra_index += 1; | ||
| 3639 | break :blk fields_len; | ||
| 3640 | } else 0; | ||
| 3641 | |||
| 3642 | const decls_len = if (small.has_decls_len) blk: { | ||
| 3643 | const decls_len = zir.extra[extra_index]; | ||
| 3644 | extra_index += 1; | ||
| 3645 | break :blk decls_len; | ||
| 3646 | } else 0; | ||
| 3647 | |||
| 3648 | if (captures_len != key.captures.owned.len) return error.AnalysisFail; | ||
| 3649 | if (fields_len != enum_obj.names.len) return error.AnalysisFail; | ||
| 3650 | |||
| 3651 | extra_index += captures_len; | ||
| 3652 | extra_index += decls_len; | ||
| 3653 | |||
| 3654 | const body = zir.bodySlice(extra_index, body_len); | ||
| 3655 | extra_index += body.len; | ||
| 3656 | |||
| 3657 | const bit_bags_count = std.math.divCeil(usize, fields_len, 32) catch unreachable; | ||
| 3658 | const body_end = extra_index; | ||
| 3659 | extra_index += bit_bags_count; | ||
| 3660 | |||
| 3661 | const any_values = for (zir.extra[body_end..][0..bit_bags_count]) |bag| { | ||
| 3662 | if (bag != 0) break true; | ||
| 3663 | } else false; | ||
| 3664 | |||
| 3665 | // The old type will be unused, so drop its dependency information. | ||
| 3666 | ip.removeDependenciesForDepender(gpa, AnalUnit.wrap(.{ .cau = enum_obj.cau.unwrap().? })); | ||
| 3667 | |||
| 3668 | const namespace_index = enum_obj.namespace; | ||
| 3669 | |||
| 3670 | const wip_ty = switch (try ip.getEnumType(gpa, pt.tid, .{ | ||
| 3671 | .has_values = any_values, | ||
| 3672 | .tag_mode = if (small.nonexhaustive) | ||
| 3673 | .nonexhaustive | ||
| 3674 | else if (tag_type_ref == .none) | ||
| 3675 | .auto | ||
| 3676 | else | ||
| 3677 | .explicit, | ||
| 3678 | .fields_len = fields_len, | ||
| 3679 | .key = .{ .declared_owned_captures = .{ | ||
| 3680 | .zir_index = key.zir_index, | ||
| 3681 | .captures = key.captures.owned, | ||
| 3682 | } }, | ||
| 3683 | }, true)) { | ||
| 3684 | .wip => |wip| wip, | ||
| 3685 | .existing => unreachable, // we passed `replace_existing` | ||
| 3686 | }; | ||
| 3687 | var done = true; | ||
| 3688 | errdefer if (!done) wip_ty.cancel(ip, pt.tid); | ||
| 3689 | |||
| 3690 | wip_ty.setName(ip, enum_obj.name); | ||
| 3691 | |||
| 3692 | const new_cau_index = try ip.createTypeCau(gpa, pt.tid, key.zir_index, namespace_index, wip_ty.index); | ||
| 3693 | |||
| 3694 | zcu.namespacePtr(namespace_index).owner_type = wip_ty.index; | ||
| 3695 | // No need to re-scan the namespace -- `zirEnumDecl` will ultimately do that if the type is still alive. | ||
| 3696 | |||
| 3697 | wip_ty.prepare(ip, new_cau_index, namespace_index); | ||
| 3698 | done = true; | ||
| 3699 | |||
| 3700 | Sema.resolveDeclaredEnum( | ||
| 3701 | pt, | ||
| 3702 | wip_ty, | ||
| 3703 | inst_info.inst, | ||
| 3704 | key.zir_index, | ||
| 3705 | namespace_index, | ||
| 3706 | enum_obj.name, | ||
| 3707 | new_cau_index, | ||
| 3708 | small, | ||
| 3709 | body, | ||
| 3710 | tag_type_ref, | ||
| 3711 | any_values, | ||
| 3712 | fields_len, | ||
| 3713 | zir, | ||
| 3714 | body_end, | ||
| 3715 | ) catch |err| switch (err) { | ||
| 3716 | error.GenericPoison => unreachable, | ||
| 3717 | error.ComptimeBreak => unreachable, | ||
| 3718 | error.ComptimeReturn => unreachable, | ||
| 3719 | error.AnalysisFail, error.OutOfMemory => |e| return e, | ||
| 3720 | }; | ||
| 3721 | |||
| 3722 | return wip_ty.index; | ||
| 3723 | } | ||
| 3724 | |||
| 3725 | /// Given a namespace, re-scan its declarations from the type definition if they have not | ||
| 3726 | /// yet been re-scanned on this update. | ||
| 3727 | /// If the type declaration instruction has been lost, returns `error.AnalysisFail`. | ||
| 3728 | /// This will effectively short-circuit the caller, which will be semantic analysis of a | ||
| 3729 | /// guaranteed-unreferenced `AnalUnit`, to trigger a transitive analysis error. | ||
| 3730 | pub fn ensureNamespaceUpToDate(pt: Zcu.PerThread, namespace_index: Zcu.Namespace.Index) Zcu.SemaError!void { | ||
| 3731 | const zcu = pt.zcu; | ||
| 3732 | const ip = &zcu.intern_pool; | ||
| 3733 | const namespace = zcu.namespacePtr(namespace_index); | ||
| 3734 | |||
| 3735 | if (namespace.generation == zcu.generation) return; | ||
| 3736 | |||
| 3737 | const Container = enum { @"struct", @"union", @"enum", @"opaque" }; | ||
| 3738 | const container: Container, const full_key = switch (ip.indexToKey(namespace.owner_type)) { | ||
| 3739 | .struct_type => |k| .{ .@"struct", k }, | ||
| 3740 | .union_type => |k| .{ .@"union", k }, | ||
| 3741 | .enum_type => |k| .{ .@"enum", k }, | ||
| 3742 | .opaque_type => |k| .{ .@"opaque", k }, | ||
| 3743 | else => unreachable, // namespaces are owned by a container type | ||
| 3744 | }; | ||
| 3745 | |||
| 3746 | const key = switch (full_key) { | ||
| 3747 | .reified, .empty_struct, .generated_tag => { | ||
| 3748 | // Namespace always empty, so up-to-date. | ||
| 3749 | namespace.generation = zcu.generation; | ||
| 3750 | return; | ||
| 3751 | }, | ||
| 3752 | .declared => |d| d, | ||
| 3753 | }; | ||
| 3754 | |||
| 3755 | // Namespace outdated -- re-scan the type if necessary. | ||
| 3756 | |||
| 3757 | const inst_info = key.zir_index.resolveFull(ip) orelse return error.AnalysisFail; | ||
| 3758 | const file = zcu.fileByIndex(inst_info.file); | ||
| 3759 | if (file.status != .success_zir) return error.AnalysisFail; | ||
| 3760 | const zir = file.zir; | ||
| 3761 | |||
| 3762 | assert(zir.instructions.items(.tag)[@intFromEnum(inst_info.inst)] == .extended); | ||
| 3763 | const extended = zir.instructions.items(.data)[@intFromEnum(inst_info.inst)].extended; | ||
| 3764 | |||
| 3765 | const decls = switch (container) { | ||
| 3766 | .@"struct" => decls: { | ||
| 3767 | assert(extended.opcode == .struct_decl); | ||
| 3768 | const small: Zir.Inst.StructDecl.Small = @bitCast(extended.small); | ||
| 3769 | const extra = zir.extraData(Zir.Inst.StructDecl, extended.operand); | ||
| 3770 | var extra_index = extra.end; | ||
| 3771 | const captures_len = if (small.has_captures_len) blk: { | ||
| 3772 | const captures_len = zir.extra[extra_index]; | ||
| 3773 | extra_index += 1; | ||
| 3774 | break :blk captures_len; | ||
| 3775 | } else 0; | ||
| 3776 | extra_index += @intFromBool(small.has_fields_len); | ||
| 3777 | const decls_len = if (small.has_decls_len) blk: { | ||
| 3778 | const decls_len = zir.extra[extra_index]; | ||
| 3779 | extra_index += 1; | ||
| 3780 | break :blk decls_len; | ||
| 3781 | } else 0; | ||
| 3782 | extra_index += captures_len; | ||
| 3783 | if (small.has_backing_int) { | ||
| 3784 | const backing_int_body_len = zir.extra[extra_index]; | ||
| 3785 | extra_index += 1; // backing_int_body_len | ||
| 3786 | if (backing_int_body_len == 0) { | ||
| 3787 | extra_index += 1; // backing_int_ref | ||
| 3788 | } else { | ||
| 3789 | extra_index += backing_int_body_len; // backing_int_body_inst | ||
| 3790 | } | ||
| 3791 | } | ||
| 3792 | break :decls zir.bodySlice(extra_index, decls_len); | ||
| 3793 | }, | ||
| 3794 | .@"union" => decls: { | ||
| 3795 | assert(extended.opcode == .union_decl); | ||
| 3796 | const small: Zir.Inst.UnionDecl.Small = @bitCast(extended.small); | ||
| 3797 | const extra = zir.extraData(Zir.Inst.UnionDecl, extended.operand); | ||
| 3798 | var extra_index = extra.end; | ||
| 3799 | extra_index += @intFromBool(small.has_tag_type); | ||
| 3800 | const captures_len = if (small.has_captures_len) blk: { | ||
| 3801 | const captures_len = zir.extra[extra_index]; | ||
| 3802 | extra_index += 1; | ||
| 3803 | break :blk captures_len; | ||
| 3804 | } else 0; | ||
| 3805 | extra_index += @intFromBool(small.has_body_len); | ||
| 3806 | extra_index += @intFromBool(small.has_fields_len); | ||
| 3807 | const decls_len = if (small.has_decls_len) blk: { | ||
| 3808 | const decls_len = zir.extra[extra_index]; | ||
| 3809 | extra_index += 1; | ||
| 3810 | break :blk decls_len; | ||
| 3811 | } else 0; | ||
| 3812 | extra_index += captures_len; | ||
| 3813 | break :decls zir.bodySlice(extra_index, decls_len); | ||
| 3814 | }, | ||
| 3815 | .@"enum" => decls: { | ||
| 3816 | assert(extended.opcode == .enum_decl); | ||
| 3817 | const small: Zir.Inst.EnumDecl.Small = @bitCast(extended.small); | ||
| 3818 | const extra = zir.extraData(Zir.Inst.EnumDecl, extended.operand); | ||
| 3819 | var extra_index = extra.end; | ||
| 3820 | extra_index += @intFromBool(small.has_tag_type); | ||
| 3821 | const captures_len = if (small.has_captures_len) blk: { | ||
| 3822 | const captures_len = zir.extra[extra_index]; | ||
| 3823 | extra_index += 1; | ||
| 3824 | break :blk captures_len; | ||
| 3825 | } else 0; | ||
| 3826 | extra_index += @intFromBool(small.has_body_len); | ||
| 3827 | extra_index += @intFromBool(small.has_fields_len); | ||
| 3828 | const decls_len = if (small.has_decls_len) blk: { | ||
| 3829 | const decls_len = zir.extra[extra_index]; | ||
| 3830 | extra_index += 1; | ||
| 3831 | break :blk decls_len; | ||
| 3832 | } else 0; | ||
| 3833 | extra_index += captures_len; | ||
| 3834 | break :decls zir.bodySlice(extra_index, decls_len); | ||
| 3835 | }, | ||
| 3836 | .@"opaque" => decls: { | ||
| 3837 | assert(extended.opcode == .opaque_decl); | ||
| 3838 | const small: Zir.Inst.OpaqueDecl.Small = @bitCast(extended.small); | ||
| 3839 | const extra = zir.extraData(Zir.Inst.OpaqueDecl, extended.operand); | ||
| 3840 | var extra_index = extra.end; | ||
| 3841 | const captures_len = if (small.has_captures_len) blk: { | ||
| 3842 | const captures_len = zir.extra[extra_index]; | ||
| 3843 | extra_index += 1; | ||
| 3844 | break :blk captures_len; | ||
| 3845 | } else 0; | ||
| 3846 | const decls_len = if (small.has_decls_len) blk: { | ||
| 3847 | const decls_len = zir.extra[extra_index]; | ||
| 3848 | extra_index += 1; | ||
| 3849 | break :blk decls_len; | ||
| 3850 | } else 0; | ||
| 3851 | extra_index += captures_len; | ||
| 3852 | break :decls zir.bodySlice(extra_index, decls_len); | ||
| 3853 | }, | ||
| 3854 | }; | ||
| 3855 | |||
| 3856 | try pt.scanNamespace(namespace_index, decls); | ||
| 3857 | namespace.generation = zcu.generation; | ||
| 3858 | } | ||
| 3859 | |||
| 3281 | const Air = @import("../Air.zig"); | 3860 | const Air = @import("../Air.zig"); |
| 3282 | const Allocator = std.mem.Allocator; | 3861 | const Allocator = std.mem.Allocator; |
| 3283 | const assert = std.debug.assert; | 3862 | const assert = std.debug.assert; |
| ... | @@ -3290,6 +3869,7 @@ const builtin = @import("builtin"); | ... | @@ -3290,6 +3869,7 @@ const builtin = @import("builtin"); |
| 3290 | const Cache = std.Build.Cache; | 3869 | const Cache = std.Build.Cache; |
| 3291 | const dev = @import("../dev.zig"); | 3870 | const dev = @import("../dev.zig"); |
| 3292 | const InternPool = @import("../InternPool.zig"); | 3871 | const InternPool = @import("../InternPool.zig"); |
| 3872 | const AnalUnit = InternPool.AnalUnit; | ||
| 3293 | const isUpDir = @import("../introspect.zig").isUpDir; | 3873 | const isUpDir = @import("../introspect.zig").isUpDir; |
| 3294 | const Liveness = @import("../Liveness.zig"); | 3874 | const Liveness = @import("../Liveness.zig"); |
| 3295 | const log = std.log.scoped(.zcu); | 3875 | const log = std.log.scoped(.zcu); |
src/codegen.zig+1-1| ... | @@ -98,7 +98,7 @@ pub fn generateLazyFunction( | ... | @@ -98,7 +98,7 @@ pub fn generateLazyFunction( |
| 98 | debug_output: DebugInfoOutput, | 98 | debug_output: DebugInfoOutput, |
| 99 | ) CodeGenError!Result { | 99 | ) CodeGenError!Result { |
| 100 | const zcu = pt.zcu; | 100 | const zcu = pt.zcu; |
| 101 | const file = Type.fromInterned(lazy_sym.ty).typeDeclInstAllowGeneratedTag(zcu).?.resolveFull(&zcu.intern_pool).file; | 101 | const file = Type.fromInterned(lazy_sym.ty).typeDeclInstAllowGeneratedTag(zcu).?.resolveFile(&zcu.intern_pool); |
| 102 | const target = zcu.fileByIndex(file).mod.resolved_target.result; | 102 | const target = zcu.fileByIndex(file).mod.resolved_target.result; |
| 103 | switch (target_util.zigBackend(target, false)) { | 103 | switch (target_util.zigBackend(target, false)) { |
| 104 | else => unreachable, | 104 | else => unreachable, |
src/codegen/c.zig+1-1| ... | @@ -2585,7 +2585,7 @@ pub fn genTypeDecl( | ... | @@ -2585,7 +2585,7 @@ pub fn genTypeDecl( |
| 2585 | const ty = Type.fromInterned(index); | 2585 | const ty = Type.fromInterned(index); |
| 2586 | _ = try renderTypePrefix(.flush, global_ctype_pool, zcu, writer, global_ctype, .suffix, .{}); | 2586 | _ = try renderTypePrefix(.flush, global_ctype_pool, zcu, writer, global_ctype, .suffix, .{}); |
| 2587 | try writer.writeByte(';'); | 2587 | try writer.writeByte(';'); |
| 2588 | const file_scope = ty.typeDeclInstAllowGeneratedTag(zcu).?.resolveFull(ip).file; | 2588 | const file_scope = ty.typeDeclInstAllowGeneratedTag(zcu).?.resolveFile(ip); |
| 2589 | if (!zcu.fileByIndex(file_scope).mod.strip) try writer.print(" /* {} */", .{ | 2589 | if (!zcu.fileByIndex(file_scope).mod.strip) try writer.print(" /* {} */", .{ |
| 2590 | ty.containerTypeName(ip).fmt(ip), | 2590 | ty.containerTypeName(ip).fmt(ip), |
| 2591 | }); | 2591 | }); |
src/codegen/llvm.zig+3-3| ... | @@ -1959,7 +1959,7 @@ pub const Object = struct { | ... | @@ -1959,7 +1959,7 @@ pub const Object = struct { |
| 1959 | ); | 1959 | ); |
| 1960 | } | 1960 | } |
| 1961 | 1961 | ||
| 1962 | const file = try o.getDebugFile(ty.typeDeclInstAllowGeneratedTag(zcu).?.resolveFull(ip).file); | 1962 | const file = try o.getDebugFile(ty.typeDeclInstAllowGeneratedTag(zcu).?.resolveFile(ip)); |
| 1963 | const scope = if (ty.getParentNamespace(zcu).unwrap()) |parent_namespace| | 1963 | const scope = if (ty.getParentNamespace(zcu).unwrap()) |parent_namespace| |
| 1964 | try o.namespaceToDebugScope(parent_namespace) | 1964 | try o.namespaceToDebugScope(parent_namespace) |
| 1965 | else | 1965 | else |
| ... | @@ -2137,7 +2137,7 @@ pub const Object = struct { | ... | @@ -2137,7 +2137,7 @@ pub const Object = struct { |
| 2137 | const name = try o.allocTypeName(ty); | 2137 | const name = try o.allocTypeName(ty); |
| 2138 | defer gpa.free(name); | 2138 | defer gpa.free(name); |
| 2139 | 2139 | ||
| 2140 | const file = try o.getDebugFile(ty.typeDeclInstAllowGeneratedTag(zcu).?.resolveFull(ip).file); | 2140 | const file = try o.getDebugFile(ty.typeDeclInstAllowGeneratedTag(zcu).?.resolveFile(ip)); |
| 2141 | const scope = if (ty.getParentNamespace(zcu).unwrap()) |parent_namespace| | 2141 | const scope = if (ty.getParentNamespace(zcu).unwrap()) |parent_namespace| |
| 2142 | try o.namespaceToDebugScope(parent_namespace) | 2142 | try o.namespaceToDebugScope(parent_namespace) |
| 2143 | else | 2143 | else |
| ... | @@ -2772,7 +2772,7 @@ pub const Object = struct { | ... | @@ -2772,7 +2772,7 @@ pub const Object = struct { |
| 2772 | fn makeEmptyNamespaceDebugType(o: *Object, ty: Type) !Builder.Metadata { | 2772 | fn makeEmptyNamespaceDebugType(o: *Object, ty: Type) !Builder.Metadata { |
| 2773 | const zcu = o.pt.zcu; | 2773 | const zcu = o.pt.zcu; |
| 2774 | const ip = &zcu.intern_pool; | 2774 | const ip = &zcu.intern_pool; |
| 2775 | const file = try o.getDebugFile(ty.typeDeclInstAllowGeneratedTag(zcu).?.resolveFull(ip).file); | 2775 | const file = try o.getDebugFile(ty.typeDeclInstAllowGeneratedTag(zcu).?.resolveFile(ip)); |
| 2776 | const scope = if (ty.getParentNamespace(zcu).unwrap()) |parent_namespace| | 2776 | const scope = if (ty.getParentNamespace(zcu).unwrap()) |parent_namespace| |
| 2777 | try o.namespaceToDebugScope(parent_namespace) | 2777 | try o.namespaceToDebugScope(parent_namespace) |
| 2778 | else | 2778 | else |
src/crash_report.zig+14-2| ... | @@ -78,7 +78,13 @@ fn dumpStatusReport() !void { | ... | @@ -78,7 +78,13 @@ fn dumpStatusReport() !void { |
| 78 | const block: *Sema.Block = anal.block; | 78 | const block: *Sema.Block = anal.block; |
| 79 | const zcu = anal.sema.pt.zcu; | 79 | const zcu = anal.sema.pt.zcu; |
| 80 | 80 | ||
| 81 | const file, const src_base_node = Zcu.LazySrcLoc.resolveBaseNode(block.src_base_inst, zcu); | 81 | const file, const src_base_node = Zcu.LazySrcLoc.resolveBaseNode(block.src_base_inst, zcu) orelse { |
| 82 | const file = zcu.fileByIndex(block.src_base_inst.resolveFile(&zcu.intern_pool)); | ||
| 83 | try stderr.writeAll("Analyzing lost instruction in file '"); | ||
| 84 | try writeFilePath(file, stderr); | ||
| 85 | try stderr.writeAll("'. This should not happen!\n\n"); | ||
| 86 | return; | ||
| 87 | }; | ||
| 82 | 88 | ||
| 83 | try stderr.writeAll("Analyzing "); | 89 | try stderr.writeAll("Analyzing "); |
| 84 | try writeFilePath(file, stderr); | 90 | try writeFilePath(file, stderr); |
| ... | @@ -104,7 +110,13 @@ fn dumpStatusReport() !void { | ... | @@ -104,7 +110,13 @@ fn dumpStatusReport() !void { |
| 104 | while (parent) |curr| { | 110 | while (parent) |curr| { |
| 105 | fba.reset(); | 111 | fba.reset(); |
| 106 | try stderr.writeAll(" in "); | 112 | try stderr.writeAll(" in "); |
| 107 | const cur_block_file, const cur_block_src_base_node = Zcu.LazySrcLoc.resolveBaseNode(curr.block.src_base_inst, zcu); | 113 | const cur_block_file, const cur_block_src_base_node = Zcu.LazySrcLoc.resolveBaseNode(curr.block.src_base_inst, zcu) orelse { |
| 114 | const cur_block_file = zcu.fileByIndex(curr.block.src_base_inst.resolveFile(&zcu.intern_pool)); | ||
| 115 | try writeFilePath(cur_block_file, stderr); | ||
| 116 | try stderr.writeAll("\n > [lost instruction; this should not happen]\n"); | ||
| 117 | parent = curr.parent; | ||
| 118 | continue; | ||
| 119 | }; | ||
| 108 | try writeFilePath(cur_block_file, stderr); | 120 | try writeFilePath(cur_block_file, stderr); |
| 109 | try stderr.writeAll("\n > "); | 121 | try stderr.writeAll("\n > "); |
| 110 | print_zir.renderSingleInstruction( | 122 | print_zir.renderSingleInstruction( |
src/link/Dwarf.zig+11-11| ... | @@ -786,7 +786,7 @@ const Entry = struct { | ... | @@ -786,7 +786,7 @@ const Entry = struct { |
| 786 | const ip = &zcu.intern_pool; | 786 | const ip = &zcu.intern_pool; |
| 787 | for (dwarf.types.keys(), dwarf.types.values()) |ty, other_entry| { | 787 | for (dwarf.types.keys(), dwarf.types.values()) |ty, other_entry| { |
| 788 | const ty_unit: Unit.Index = if (Type.fromInterned(ty).typeDeclInst(zcu)) |inst_index| | 788 | const ty_unit: Unit.Index = if (Type.fromInterned(ty).typeDeclInst(zcu)) |inst_index| |
| 789 | dwarf.getUnit(zcu.fileByIndex(inst_index.resolveFull(ip).file).mod) catch unreachable | 789 | dwarf.getUnit(zcu.fileByIndex(inst_index.resolveFile(ip)).mod) catch unreachable |
| 790 | else | 790 | else |
| 791 | .main; | 791 | .main; |
| 792 | if (sec.getUnit(ty_unit) == unit and unit.getEntry(other_entry) == entry) | 792 | if (sec.getUnit(ty_unit) == unit and unit.getEntry(other_entry) == entry) |
| ... | @@ -796,7 +796,7 @@ const Entry = struct { | ... | @@ -796,7 +796,7 @@ const Entry = struct { |
| 796 | }); | 796 | }); |
| 797 | } | 797 | } |
| 798 | for (dwarf.navs.keys(), dwarf.navs.values()) |nav, other_entry| { | 798 | for (dwarf.navs.keys(), dwarf.navs.values()) |nav, other_entry| { |
| 799 | const nav_unit = dwarf.getUnit(zcu.fileByIndex(ip.getNav(nav).srcInst(ip).resolveFull(ip).file).mod) catch unreachable; | 799 | const nav_unit = dwarf.getUnit(zcu.fileByIndex(ip.getNav(nav).srcInst(ip).resolveFile(ip)).mod) catch unreachable; |
| 800 | if (sec.getUnit(nav_unit) == unit and unit.getEntry(other_entry) == entry) | 800 | if (sec.getUnit(nav_unit) == unit and unit.getEntry(other_entry) == entry) |
| 801 | log.err("missing Nav({}({d}))", .{ ip.getNav(nav).fqn.fmt(ip), @intFromEnum(nav) }); | 801 | log.err("missing Nav({}({d}))", .{ ip.getNav(nav).fqn.fmt(ip), @intFromEnum(nav) }); |
| 802 | } | 802 | } |
| ... | @@ -1201,7 +1201,7 @@ pub const WipNav = struct { | ... | @@ -1201,7 +1201,7 @@ pub const WipNav = struct { |
| 1201 | const ip = &zcu.intern_pool; | 1201 | const ip = &zcu.intern_pool; |
| 1202 | const maybe_inst_index = ty.typeDeclInst(zcu); | 1202 | const maybe_inst_index = ty.typeDeclInst(zcu); |
| 1203 | const unit = if (maybe_inst_index) |inst_index| | 1203 | const unit = if (maybe_inst_index) |inst_index| |
| 1204 | try wip_nav.dwarf.getUnit(zcu.fileByIndex(inst_index.resolveFull(ip).file).mod) | 1204 | try wip_nav.dwarf.getUnit(zcu.fileByIndex(inst_index.resolveFile(ip)).mod) |
| 1205 | else | 1205 | else |
| 1206 | .main; | 1206 | .main; |
| 1207 | const gop = try wip_nav.dwarf.types.getOrPut(wip_nav.dwarf.gpa, ty.toIntern()); | 1207 | const gop = try wip_nav.dwarf.types.getOrPut(wip_nav.dwarf.gpa, ty.toIntern()); |
| ... | @@ -1539,7 +1539,7 @@ pub fn initWipNav(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool.Nav.In | ... | @@ -1539,7 +1539,7 @@ pub fn initWipNav(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool.Nav.In |
| 1539 | const nav = ip.getNav(nav_index); | 1539 | const nav = ip.getNav(nav_index); |
| 1540 | log.debug("initWipNav({})", .{nav.fqn.fmt(ip)}); | 1540 | log.debug("initWipNav({})", .{nav.fqn.fmt(ip)}); |
| 1541 | 1541 | ||
| 1542 | const inst_info = nav.srcInst(ip).resolveFull(ip); | 1542 | const inst_info = nav.srcInst(ip).resolveFull(ip).?; |
| 1543 | const file = zcu.fileByIndex(inst_info.file); | 1543 | const file = zcu.fileByIndex(inst_info.file); |
| 1544 | 1544 | ||
| 1545 | const unit = try dwarf.getUnit(file.mod); | 1545 | const unit = try dwarf.getUnit(file.mod); |
| ... | @@ -1874,7 +1874,7 @@ pub fn updateComptimeNav(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool | ... | @@ -1874,7 +1874,7 @@ pub fn updateComptimeNav(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool |
| 1874 | const nav = ip.getNav(nav_index); | 1874 | const nav = ip.getNav(nav_index); |
| 1875 | log.debug("updateComptimeNav({})", .{nav.fqn.fmt(ip)}); | 1875 | log.debug("updateComptimeNav({})", .{nav.fqn.fmt(ip)}); |
| 1876 | 1876 | ||
| 1877 | const inst_info = nav.srcInst(ip).resolveFull(ip); | 1877 | const inst_info = nav.srcInst(ip).resolveFull(ip).?; |
| 1878 | const file = zcu.fileByIndex(inst_info.file); | 1878 | const file = zcu.fileByIndex(inst_info.file); |
| 1879 | assert(file.zir_loaded); | 1879 | assert(file.zir_loaded); |
| 1880 | const decl_inst = file.zir.instructions.get(@intFromEnum(inst_info.inst)); | 1880 | const decl_inst = file.zir.instructions.get(@intFromEnum(inst_info.inst)); |
| ... | @@ -1937,7 +1937,7 @@ pub fn updateComptimeNav(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool | ... | @@ -1937,7 +1937,7 @@ pub fn updateComptimeNav(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool |
| 1937 | }; | 1937 | }; |
| 1938 | break :value_inst value_inst; | 1938 | break :value_inst value_inst; |
| 1939 | }; | 1939 | }; |
| 1940 | const type_inst_info = loaded_struct.zir_index.unwrap().?.resolveFull(ip); | 1940 | const type_inst_info = loaded_struct.zir_index.unwrap().?.resolveFull(ip).?; |
| 1941 | if (type_inst_info.inst != value_inst) break :decl_struct; | 1941 | if (type_inst_info.inst != value_inst) break :decl_struct; |
| 1942 | 1942 | ||
| 1943 | const type_gop = try dwarf.types.getOrPut(dwarf.gpa, nav_val.toIntern()); | 1943 | const type_gop = try dwarf.types.getOrPut(dwarf.gpa, nav_val.toIntern()); |
| ... | @@ -2053,7 +2053,7 @@ pub fn updateComptimeNav(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool | ... | @@ -2053,7 +2053,7 @@ pub fn updateComptimeNav(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool |
| 2053 | }; | 2053 | }; |
| 2054 | break :value_inst value_inst; | 2054 | break :value_inst value_inst; |
| 2055 | }; | 2055 | }; |
| 2056 | const type_inst_info = loaded_enum.zir_index.unwrap().?.resolveFull(ip); | 2056 | const type_inst_info = loaded_enum.zir_index.unwrap().?.resolveFull(ip).?; |
| 2057 | if (type_inst_info.inst != value_inst) break :decl_enum; | 2057 | if (type_inst_info.inst != value_inst) break :decl_enum; |
| 2058 | 2058 | ||
| 2059 | const type_gop = try dwarf.types.getOrPut(dwarf.gpa, nav_val.toIntern()); | 2059 | const type_gop = try dwarf.types.getOrPut(dwarf.gpa, nav_val.toIntern()); |
| ... | @@ -2127,7 +2127,7 @@ pub fn updateComptimeNav(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool | ... | @@ -2127,7 +2127,7 @@ pub fn updateComptimeNav(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool |
| 2127 | }; | 2127 | }; |
| 2128 | break :value_inst value_inst; | 2128 | break :value_inst value_inst; |
| 2129 | }; | 2129 | }; |
| 2130 | const type_inst_info = loaded_union.zir_index.resolveFull(ip); | 2130 | const type_inst_info = loaded_union.zir_index.resolveFull(ip).?; |
| 2131 | if (type_inst_info.inst != value_inst) break :decl_union; | 2131 | if (type_inst_info.inst != value_inst) break :decl_union; |
| 2132 | 2132 | ||
| 2133 | const type_gop = try dwarf.types.getOrPut(dwarf.gpa, nav_val.toIntern()); | 2133 | const type_gop = try dwarf.types.getOrPut(dwarf.gpa, nav_val.toIntern()); |
| ... | @@ -2240,7 +2240,7 @@ pub fn updateComptimeNav(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool | ... | @@ -2240,7 +2240,7 @@ pub fn updateComptimeNav(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool |
| 2240 | }; | 2240 | }; |
| 2241 | break :value_inst value_inst; | 2241 | break :value_inst value_inst; |
| 2242 | }; | 2242 | }; |
| 2243 | const type_inst_info = loaded_opaque.zir_index.resolveFull(ip); | 2243 | const type_inst_info = loaded_opaque.zir_index.resolveFull(ip).?; |
| 2244 | if (type_inst_info.inst != value_inst) break :decl_opaque; | 2244 | if (type_inst_info.inst != value_inst) break :decl_opaque; |
| 2245 | 2245 | ||
| 2246 | const type_gop = try dwarf.types.getOrPut(dwarf.gpa, nav_val.toIntern()); | 2246 | const type_gop = try dwarf.types.getOrPut(dwarf.gpa, nav_val.toIntern()); |
| ... | @@ -2704,7 +2704,7 @@ pub fn updateContainerType(dwarf: *Dwarf, pt: Zcu.PerThread, type_index: InternP | ... | @@ -2704,7 +2704,7 @@ pub fn updateContainerType(dwarf: *Dwarf, pt: Zcu.PerThread, type_index: InternP |
| 2704 | const ty = Type.fromInterned(type_index); | 2704 | const ty = Type.fromInterned(type_index); |
| 2705 | log.debug("updateContainerType({}({d}))", .{ ty.fmt(pt), @intFromEnum(type_index) }); | 2705 | log.debug("updateContainerType({}({d}))", .{ ty.fmt(pt), @intFromEnum(type_index) }); |
| 2706 | 2706 | ||
| 2707 | const inst_info = ty.typeDeclInst(zcu).?.resolveFull(ip); | 2707 | const inst_info = ty.typeDeclInst(zcu).?.resolveFull(ip).?; |
| 2708 | const file = zcu.fileByIndex(inst_info.file); | 2708 | const file = zcu.fileByIndex(inst_info.file); |
| 2709 | if (inst_info.inst == .main_struct_inst) { | 2709 | if (inst_info.inst == .main_struct_inst) { |
| 2710 | const unit = try dwarf.getUnit(file.mod); | 2710 | const unit = try dwarf.getUnit(file.mod); |
| ... | @@ -2922,7 +2922,7 @@ pub fn updateNavLineNumber(dwarf: *Dwarf, zcu: *Zcu, nav_index: InternPool.Nav.I | ... | @@ -2922,7 +2922,7 @@ pub fn updateNavLineNumber(dwarf: *Dwarf, zcu: *Zcu, nav_index: InternPool.Nav.I |
| 2922 | const ip = &zcu.intern_pool; | 2922 | const ip = &zcu.intern_pool; |
| 2923 | 2923 | ||
| 2924 | const zir_index = ip.getCau(ip.getNav(nav_index).analysis_owner.unwrap() orelse return).zir_index; | 2924 | const zir_index = ip.getCau(ip.getNav(nav_index).analysis_owner.unwrap() orelse return).zir_index; |
| 2925 | const inst_info = zir_index.resolveFull(ip); | 2925 | const inst_info = zir_index.resolveFull(ip).?; |
| 2926 | assert(inst_info.inst != .main_struct_inst); | 2926 | assert(inst_info.inst != .main_struct_inst); |
| 2927 | const file = zcu.fileByIndex(inst_info.file); | 2927 | const file = zcu.fileByIndex(inst_info.file); |
| 2928 | 2928 |
src/main.zig+3-2| ... | @@ -3257,9 +3257,12 @@ fn buildOutputType( | ... | @@ -3257,9 +3257,12 @@ fn buildOutputType( |
| 3257 | else => false, | 3257 | else => false, |
| 3258 | }; | 3258 | }; |
| 3259 | 3259 | ||
| 3260 | const incremental = opt_incremental orelse false; | ||
| 3261 | |||
| 3260 | const disable_lld_caching = !output_to_cache; | 3262 | const disable_lld_caching = !output_to_cache; |
| 3261 | 3263 | ||
| 3262 | const cache_mode: Compilation.CacheMode = b: { | 3264 | const cache_mode: Compilation.CacheMode = b: { |
| 3265 | if (incremental) break :b .incremental; | ||
| 3263 | if (disable_lld_caching) break :b .incremental; | 3266 | if (disable_lld_caching) break :b .incremental; |
| 3264 | if (!create_module.resolved_options.have_zcu) break :b .whole; | 3267 | if (!create_module.resolved_options.have_zcu) break :b .whole; |
| 3265 | 3268 | ||
| ... | @@ -3272,8 +3275,6 @@ fn buildOutputType( | ... | @@ -3272,8 +3275,6 @@ fn buildOutputType( |
| 3272 | break :b .incremental; | 3275 | break :b .incremental; |
| 3273 | }; | 3276 | }; |
| 3274 | 3277 | ||
| 3275 | const incremental = opt_incremental orelse false; | ||
| 3276 | |||
| 3277 | process.raiseFileDescriptorLimit(); | 3278 | process.raiseFileDescriptorLimit(); |
| 3278 | 3279 | ||
| 3279 | var file_system_inputs: std.ArrayListUnmanaged(u8) = .{}; | 3280 | var file_system_inputs: std.ArrayListUnmanaged(u8) = .{}; |
test/incremental/add_decl created+59| ... | @@ -0,0 +1,59 @@ | ||
| 1 | #target=x86_64-linux | ||
| 2 | #update=initial version | ||
| 3 | #file=main.zig | ||
| 4 | const std = @import("std"); | ||
| 5 | pub fn main() !void { | ||
| 6 | try std.io.getStdOut().writeAll(foo); | ||
| 7 | } | ||
| 8 | const foo = "good morning\n"; | ||
| 9 | #expect_stdout="good morning\n" | ||
| 10 | |||
| 11 | #update=add new declaration | ||
| 12 | #file=main.zig | ||
| 13 | const std = @import("std"); | ||
| 14 | pub fn main() !void { | ||
| 15 | try std.io.getStdOut().writeAll(foo); | ||
| 16 | } | ||
| 17 | const foo = "good morning\n"; | ||
| 18 | const bar = "good evening\n"; | ||
| 19 | #expect_stdout="good morning\n" | ||
| 20 | |||
| 21 | #update=reference new declaration | ||
| 22 | #file=main.zig | ||
| 23 | const std = @import("std"); | ||
| 24 | pub fn main() !void { | ||
| 25 | try std.io.getStdOut().writeAll(bar); | ||
| 26 | } | ||
| 27 | const foo = "good morning\n"; | ||
| 28 | const bar = "good evening\n"; | ||
| 29 | #expect_stdout="good evening\n" | ||
| 30 | |||
| 31 | #update=reference missing declaration | ||
| 32 | #file=main.zig | ||
| 33 | const std = @import("std"); | ||
| 34 | pub fn main() !void { | ||
| 35 | try std.io.getStdOut().writeAll(qux); | ||
| 36 | } | ||
| 37 | const foo = "good morning\n"; | ||
| 38 | const bar = "good evening\n"; | ||
| 39 | #expect_error=ignored | ||
| 40 | |||
| 41 | #update=add missing declaration | ||
| 42 | #file=main.zig | ||
| 43 | const std = @import("std"); | ||
| 44 | pub fn main() !void { | ||
| 45 | try std.io.getStdOut().writeAll(qux); | ||
| 46 | } | ||
| 47 | const foo = "good morning\n"; | ||
| 48 | const bar = "good evening\n"; | ||
| 49 | const qux = "good night\n"; | ||
| 50 | #expect_stdout="good night\n" | ||
| 51 | |||
| 52 | #update=remove unused declarations | ||
| 53 | #file=main.zig | ||
| 54 | const std = @import("std"); | ||
| 55 | pub fn main() !void { | ||
| 56 | try std.io.getStdOut().writeAll(qux); | ||
| 57 | } | ||
| 58 | const qux = "good night\n"; | ||
| 59 | #expect_stdout="good night\n" | ||
test/incremental/add_decl_namespaced created+59| ... | @@ -0,0 +1,59 @@ | ||
| 1 | #target=x86_64-linux | ||
| 2 | #update=initial version | ||
| 3 | #file=main.zig | ||
| 4 | const std = @import("std"); | ||
| 5 | pub fn main() !void { | ||
| 6 | try std.io.getStdOut().writeAll(@This().foo); | ||
| 7 | } | ||
| 8 | const foo = "good morning\n"; | ||
| 9 | #expect_stdout="good morning\n" | ||
| 10 | |||
| 11 | #update=add new declaration | ||
| 12 | #file=main.zig | ||
| 13 | const std = @import("std"); | ||
| 14 | pub fn main() !void { | ||
| 15 | try std.io.getStdOut().writeAll(@This().foo); | ||
| 16 | } | ||
| 17 | const foo = "good morning\n"; | ||
| 18 | const bar = "good evening\n"; | ||
| 19 | #expect_stdout="good morning\n" | ||
| 20 | |||
| 21 | #update=reference new declaration | ||
| 22 | #file=main.zig | ||
| 23 | const std = @import("std"); | ||
| 24 | pub fn main() !void { | ||
| 25 | try std.io.getStdOut().writeAll(@This().bar); | ||
| 26 | } | ||
| 27 | const foo = "good morning\n"; | ||
| 28 | const bar = "good evening\n"; | ||
| 29 | #expect_stdout="good evening\n" | ||
| 30 | |||
| 31 | #update=reference missing declaration | ||
| 32 | #file=main.zig | ||
| 33 | const std = @import("std"); | ||
| 34 | pub fn main() !void { | ||
| 35 | try std.io.getStdOut().writeAll(@This().qux); | ||
| 36 | } | ||
| 37 | const foo = "good morning\n"; | ||
| 38 | const bar = "good evening\n"; | ||
| 39 | #expect_error=ignored | ||
| 40 | |||
| 41 | #update=add missing declaration | ||
| 42 | #file=main.zig | ||
| 43 | const std = @import("std"); | ||
| 44 | pub fn main() !void { | ||
| 45 | try std.io.getStdOut().writeAll(@This().qux); | ||
| 46 | } | ||
| 47 | const foo = "good morning\n"; | ||
| 48 | const bar = "good evening\n"; | ||
| 49 | const qux = "good night\n"; | ||
| 50 | #expect_stdout="good night\n" | ||
| 51 | |||
| 52 | #update=remove unused declarations | ||
| 53 | #file=main.zig | ||
| 54 | const std = @import("std"); | ||
| 55 | pub fn main() !void { | ||
| 56 | try std.io.getStdOut().writeAll(@This().qux); | ||
| 57 | } | ||
| 58 | const qux = "good night\n"; | ||
| 59 | #expect_stdout="good night\n" | ||
test/incremental/delete_comptime_decls created+38| ... | @@ -0,0 +1,38 @@ | ||
| 1 | #target=x86_64-linux | ||
| 2 | #update=initial version | ||
| 3 | #file=main.zig | ||
| 4 | pub fn main() void {} | ||
| 5 | comptime { | ||
| 6 | var array = [_:0]u8{ 1, 2, 3, 4 }; | ||
| 7 | const src_slice: [:0]u8 = &array; | ||
| 8 | const slice = src_slice[2..6]; | ||
| 9 | _ = slice; | ||
| 10 | } | ||
| 11 | comptime { | ||
| 12 | var array = [_:0]u8{ 1, 2, 3, 4 }; | ||
| 13 | const slice = array[2..6]; | ||
| 14 | _ = slice; | ||
| 15 | } | ||
| 16 | comptime { | ||
| 17 | var array = [_]u8{ 1, 2, 3, 4 }; | ||
| 18 | const slice = array[2..5]; | ||
| 19 | _ = slice; | ||
| 20 | } | ||
| 21 | comptime { | ||
| 22 | var array = [_:0]u8{ 1, 2, 3, 4 }; | ||
| 23 | const slice = array[3..2]; | ||
| 24 | _ = slice; | ||
| 25 | } | ||
| 26 | #expect_error=ignored | ||
| 27 | |||
| 28 | #update=delete and modify comptime decls | ||
| 29 | #file=main.zig | ||
| 30 | pub fn main() void {} | ||
| 31 | comptime { | ||
| 32 | const x: [*c]u8 = null; | ||
| 33 | var runtime_len: usize = undefined; | ||
| 34 | 		runtime_len = 0; | ||
| 35 | const y = x[0..runtime_len]; | ||
| 36 | _ = y; | ||
| 37 | } | ||
| 38 | #expect_error=ignored | ||
test/incremental/unreferenced_error created+38| ... | @@ -0,0 +1,38 @@ | ||
| 1 | #target=x86_64-linux | ||
| 2 | #update=initial version | ||
| 3 | #file=main.zig | ||
| 4 | const std = @import("std"); | ||
| 5 | pub fn main() !void { | ||
| 6 | try std.io.getStdOut().writeAll(a); | ||
| 7 | } | ||
| 8 | const a = "Hello, World!\n"; | ||
| 9 | #expect_stdout="Hello, World!\n" | ||
| 10 | |||
| 11 | #update=introduce compile error | ||
| 12 | #file=main.zig | ||
| 13 | const std = @import("std"); | ||
| 14 | pub fn main() !void { | ||
| 15 | try std.io.getStdOut().writeAll(a); | ||
| 16 | } | ||
| 17 | const a = @compileError("bad a"); | ||
| 18 | #expect_error=ignored | ||
| 19 | |||
| 20 | #update=remove error reference | ||
| 21 | #file=main.zig | ||
| 22 | const std = @import("std"); | ||
| 23 | pub fn main() !void { | ||
| 24 | try std.io.getStdOut().writeAll(b); | ||
| 25 | } | ||
| 26 | const a = @compileError("bad a"); | ||
| 27 | const b = "Hi there!\n"; | ||
| 28 | #expect_stdout="Hi there!\n" | ||
| 29 | |||
| 30 | #update=introduce and remove reference to error | ||
| 31 | #file=main.zig | ||
| 32 | const std = @import("std"); | ||
| 33 | pub fn main() !void { | ||
| 34 | try std.io.getStdOut().writeAll(a); | ||
| 35 | } | ||
| 36 | const a = "Back to a\n"; | ||
| 37 | const b = @compileError("bad b"); | ||
| 38 | #expect_stdout="Back to a\n" | ||
tools/incr-check.zig+190-17| ... | @@ -2,14 +2,55 @@ const std = @import("std"); | ... | @@ -2,14 +2,55 @@ const std = @import("std"); |
| 2 | const fatal = std.process.fatal; | 2 | const fatal = std.process.fatal; |
| 3 | const Allocator = std.mem.Allocator; | 3 | const Allocator = std.mem.Allocator; |
| 4 | 4 | ||
| 5 | const usage = "usage: incr-check <zig binary path> <input file> [--zig-lib-dir lib] [--debug-zcu] [--emit none|bin|c] [--zig-cc-binary /path/to/zig]"; | ||
| 6 | |||
| 7 | const EmitMode = enum { | ||
| 8 | none, | ||
| 9 | bin, | ||
| 10 | c, | ||
| 11 | }; | ||
| 12 | |||
| 5 | pub fn main() !void { | 13 | pub fn main() !void { |
| 6 | var arena_instance = std.heap.ArenaAllocator.init(std.heap.page_allocator); | 14 | var arena_instance = std.heap.ArenaAllocator.init(std.heap.page_allocator); |
| 7 | defer arena_instance.deinit(); | 15 | defer arena_instance.deinit(); |
| 8 | const arena = arena_instance.allocator(); | 16 | const arena = arena_instance.allocator(); |
| 9 | 17 | ||
| 10 | const args = try std.process.argsAlloc(arena); | 18 | var opt_zig_exe: ?[]const u8 = null; |
| 11 | const zig_exe = args[1]; | 19 | var opt_input_file_name: ?[]const u8 = null; |
| 12 | const input_file_name = args[2]; | 20 | var opt_lib_dir: ?[]const u8 = null; |
| 21 | var opt_cc_zig: ?[]const u8 = null; | ||
| 22 | var emit: EmitMode = .bin; | ||
| 23 | var debug_zcu = false; | ||
| 24 | |||
| 25 | var arg_it = try std.process.argsWithAllocator(arena); | ||
| 26 | _ = arg_it.skip(); | ||
| 27 | while (arg_it.next()) |arg| { | ||
| 28 | if (arg.len > 0 and arg[0] == '-') { | ||
| 29 | if (std.mem.eql(u8, arg, "--emit")) { | ||
| 30 | const emit_str = arg_it.next() orelse fatal("expected arg after '--emit'\n{s}", .{usage}); | ||
| 31 | emit = std.meta.stringToEnum(EmitMode, emit_str) orelse | ||
| 32 | fatal("invalid emit mode '{s}'\n{s}", .{ emit_str, usage }); | ||
| 33 | } else if (std.mem.eql(u8, arg, "--zig-lib-dir")) { | ||
| 34 | opt_lib_dir = arg_it.next() orelse fatal("expected arg after '--zig-lib-dir'\n{s}", .{usage}); | ||
| 35 | } else if (std.mem.eql(u8, arg, "--debug-zcu")) { | ||
| 36 | debug_zcu = true; | ||
| 37 | } else if (std.mem.eql(u8, arg, "--zig-cc-binary")) { | ||
| 38 | opt_cc_zig = arg_it.next() orelse fatal("expect arg after '--zig-cc-binary'\n{s}", .{usage}); | ||
| 39 | } else { | ||
| 40 | fatal("unknown option '{s}'\n{s}", .{ arg, usage }); | ||
| 41 | } | ||
| 42 | continue; | ||
| 43 | } | ||
| 44 | if (opt_zig_exe == null) { | ||
| 45 | opt_zig_exe = arg; | ||
| 46 | } else if (opt_input_file_name == null) { | ||
| 47 | opt_input_file_name = arg; | ||
| 48 | } else { | ||
| 49 | fatal("unknown argument '{s}'\n{s}", .{ arg, usage }); | ||
| 50 | } | ||
| 51 | } | ||
| 52 | const zig_exe = opt_zig_exe orelse fatal("missing path to zig\n{s}", .{usage}); | ||
| 53 | const input_file_name = opt_input_file_name orelse fatal("missing input file\n{s}", .{usage}); | ||
| 13 | 54 | ||
| 14 | const input_file_bytes = try std.fs.cwd().readFileAlloc(arena, input_file_name, std.math.maxInt(u32)); | 55 | const input_file_bytes = try std.fs.cwd().readFileAlloc(arena, input_file_name, std.math.maxInt(u32)); |
| 15 | const case = try Case.parse(arena, input_file_bytes); | 56 | const case = try Case.parse(arena, input_file_bytes); |
| ... | @@ -24,13 +65,18 @@ pub fn main() !void { | ... | @@ -24,13 +65,18 @@ pub fn main() !void { |
| 24 | const child_prog_node = prog_node.start("zig build-exe", 0); | 65 | const child_prog_node = prog_node.start("zig build-exe", 0); |
| 25 | defer child_prog_node.end(); | 66 | defer child_prog_node.end(); |
| 26 | 67 | ||
| 27 | var child = std.process.Child.init(&.{ | 68 | // Convert paths to be relative to the cwd of the subprocess. |
| 28 | // Convert incr-check-relative path to subprocess-relative path. | 69 | const resolved_zig_exe = try std.fs.path.relative(arena, tmp_dir_path, zig_exe); |
| 29 | try std.fs.path.relative(arena, tmp_dir_path, zig_exe), | 70 | const opt_resolved_lib_dir = if (opt_lib_dir) |lib_dir| |
| 71 | try std.fs.path.relative(arena, tmp_dir_path, lib_dir) | ||
| 72 | else | ||
| 73 | null; | ||
| 74 | |||
| 75 | var child_args: std.ArrayListUnmanaged([]const u8) = .{}; | ||
| 76 | try child_args.appendSlice(arena, &.{ | ||
| 77 | resolved_zig_exe, | ||
| 30 | "build-exe", | 78 | "build-exe", |
| 31 | case.root_source_file, | 79 | case.root_source_file, |
| 32 | "-fno-llvm", | ||
| 33 | "-fno-lld", | ||
| 34 | "-fincremental", | 80 | "-fincremental", |
| 35 | "-target", | 81 | "-target", |
| 36 | case.target_query, | 82 | case.target_query, |
| ... | @@ -39,8 +85,20 @@ pub fn main() !void { | ... | @@ -39,8 +85,20 @@ pub fn main() !void { |
| 39 | "--global-cache-dir", | 85 | "--global-cache-dir", |
| 40 | ".global_cache", | 86 | ".global_cache", |
| 41 | "--listen=-", | 87 | "--listen=-", |
| 42 | }, arena); | 88 | }); |
| 89 | if (opt_resolved_lib_dir) |resolved_lib_dir| { | ||
| 90 | try child_args.appendSlice(arena, &.{ "--zig-lib-dir", resolved_lib_dir }); | ||
| 91 | } | ||
| 92 | switch (emit) { | ||
| 93 | .bin => try child_args.appendSlice(arena, &.{ "-fno-llvm", "-fno-lld" }), | ||
| 94 | .none => try child_args.append(arena, "-fno-emit-bin"), | ||
| 95 | .c => try child_args.appendSlice(arena, &.{ "-ofmt=c", "-lc" }), | ||
| 96 | } | ||
| 97 | if (debug_zcu) { | ||
| 98 | try child_args.appendSlice(arena, &.{ "--debug-log", "zcu" }); | ||
| 99 | } | ||
| 43 | 100 | ||
| 101 | var child = std.process.Child.init(child_args.items, arena); | ||
| 44 | child.stdin_behavior = .Pipe; | 102 | child.stdin_behavior = .Pipe; |
| 45 | child.stdout_behavior = .Pipe; | 103 | child.stdout_behavior = .Pipe; |
| 46 | child.stderr_behavior = .Pipe; | 104 | child.stderr_behavior = .Pipe; |
| ... | @@ -48,12 +106,33 @@ pub fn main() !void { | ... | @@ -48,12 +106,33 @@ pub fn main() !void { |
| 48 | child.cwd_dir = tmp_dir; | 106 | child.cwd_dir = tmp_dir; |
| 49 | child.cwd = tmp_dir_path; | 107 | child.cwd = tmp_dir_path; |
| 50 | 108 | ||
| 109 | var cc_child_args: std.ArrayListUnmanaged([]const u8) = .{}; | ||
| 110 | if (emit == .c) { | ||
| 111 | const resolved_cc_zig_exe = if (opt_cc_zig) |cc_zig_exe| | ||
| 112 | try std.fs.path.relative(arena, tmp_dir_path, cc_zig_exe) | ||
| 113 | else | ||
| 114 | resolved_zig_exe; | ||
| 115 | |||
| 116 | try cc_child_args.appendSlice(arena, &.{ | ||
| 117 | resolved_cc_zig_exe, | ||
| 118 | "cc", | ||
| 119 | "-target", | ||
| 120 | case.target_query, | ||
| 121 | "-I", | ||
| 122 | opt_resolved_lib_dir orelse fatal("'--zig-lib-dir' required when using '--emit c'", .{}), | ||
| 123 | "-o", | ||
| 124 | }); | ||
| 125 | } | ||
| 126 | |||
| 51 | var eval: Eval = .{ | 127 | var eval: Eval = .{ |
| 52 | .arena = arena, | 128 | .arena = arena, |
| 53 | .case = case, | 129 | .case = case, |
| 54 | .tmp_dir = tmp_dir, | 130 | .tmp_dir = tmp_dir, |
| 55 | .tmp_dir_path = tmp_dir_path, | 131 | .tmp_dir_path = tmp_dir_path, |
| 56 | .child = &child, | 132 | .child = &child, |
| 133 | .allow_stderr = debug_zcu, | ||
| 134 | .emit = emit, | ||
| 135 | .cc_child_args = &cc_child_args, | ||
| 57 | }; | 136 | }; |
| 58 | 137 | ||
| 59 | try child.spawn(); | 138 | try child.spawn(); |
| ... | @@ -65,9 +144,16 @@ pub fn main() !void { | ... | @@ -65,9 +144,16 @@ pub fn main() !void { |
| 65 | defer poller.deinit(); | 144 | defer poller.deinit(); |
| 66 | 145 | ||
| 67 | for (case.updates) |update| { | 146 | for (case.updates) |update| { |
| 147 | var update_node = prog_node.start(update.name, 0); | ||
| 148 | defer update_node.end(); | ||
| 149 | |||
| 150 | if (debug_zcu) { | ||
| 151 | std.log.info("=== START UPDATE '{s}' ===", .{update.name}); | ||
| 152 | } | ||
| 153 | |||
| 68 | eval.write(update); | 154 | eval.write(update); |
| 69 | try eval.requestUpdate(); | 155 | try eval.requestUpdate(); |
| 70 | try eval.check(&poller, update); | 156 | try eval.check(&poller, update, update_node); |
| 71 | } | 157 | } |
| 72 | 158 | ||
| 73 | try eval.end(&poller); | 159 | try eval.end(&poller); |
| ... | @@ -81,6 +167,11 @@ const Eval = struct { | ... | @@ -81,6 +167,11 @@ const Eval = struct { |
| 81 | tmp_dir: std.fs.Dir, | 167 | tmp_dir: std.fs.Dir, |
| 82 | tmp_dir_path: []const u8, | 168 | tmp_dir_path: []const u8, |
| 83 | child: *std.process.Child, | 169 | child: *std.process.Child, |
| 170 | allow_stderr: bool, | ||
| 171 | emit: EmitMode, | ||
| 172 | /// When `emit == .c`, this contains the first few arguments to `zig cc` to build the generated binary. | ||
| 173 | /// The arguments `out.c in.c` must be appended before spawning the subprocess. | ||
| 174 | cc_child_args: *std.ArrayListUnmanaged([]const u8), | ||
| 84 | 175 | ||
| 85 | const StreamEnum = enum { stdout, stderr }; | 176 | const StreamEnum = enum { stdout, stderr }; |
| 86 | const Poller = std.io.Poller(StreamEnum); | 177 | const Poller = std.io.Poller(StreamEnum); |
| ... | @@ -102,7 +193,7 @@ const Eval = struct { | ... | @@ -102,7 +193,7 @@ const Eval = struct { |
| 102 | } | 193 | } |
| 103 | } | 194 | } |
| 104 | 195 | ||
| 105 | fn check(eval: *Eval, poller: *Poller, update: Case.Update) !void { | 196 | fn check(eval: *Eval, poller: *Poller, update: Case.Update, prog_node: std.Progress.Node) !void { |
| 106 | const arena = eval.arena; | 197 | const arena = eval.arena; |
| 107 | const Header = std.zig.Server.Message.Header; | 198 | const Header = std.zig.Server.Message.Header; |
| 108 | const stdout = poller.fifo(.stdout); | 199 | const stdout = poller.fifo(.stdout); |
| ... | @@ -136,9 +227,18 @@ const Eval = struct { | ... | @@ -136,9 +227,18 @@ const Eval = struct { |
| 136 | }; | 227 | }; |
| 137 | if (stderr.readableLength() > 0) { | 228 | if (stderr.readableLength() > 0) { |
| 138 | const stderr_data = try stderr.toOwnedSlice(); | 229 | const stderr_data = try stderr.toOwnedSlice(); |
| 139 | fatal("error_bundle included unexpected stderr:\n{s}", .{stderr_data}); | 230 | if (eval.allow_stderr) { |
| 231 | std.log.info("error_bundle included stderr:\n{s}", .{stderr_data}); | ||
| 232 | } else { | ||
| 233 | fatal("error_bundle included unexpected stderr:\n{s}", .{stderr_data}); | ||
| 234 | } | ||
| 235 | } | ||
| 236 | if (result_error_bundle.errorMessageCount() == 0) { | ||
| 237 | // Empty bundle indicates successful update in a `-fno-emit-bin` build. | ||
| 238 | try eval.checkSuccessOutcome(update, null, prog_node); | ||
| 239 | } else { | ||
| 240 | try eval.checkErrorOutcome(update, result_error_bundle); | ||
| 140 | } | 241 | } |
| 141 | try eval.checkErrorOutcome(update, result_error_bundle); | ||
| 142 | // This message indicates the end of the update. | 242 | // This message indicates the end of the update. |
| 143 | stdout.discard(body.len); | 243 | stdout.discard(body.len); |
| 144 | return; | 244 | return; |
| ... | @@ -150,9 +250,13 @@ const Eval = struct { | ... | @@ -150,9 +250,13 @@ const Eval = struct { |
| 150 | const result_binary = try arena.dupe(u8, body[@sizeOf(EbpHdr)..]); | 250 | const result_binary = try arena.dupe(u8, body[@sizeOf(EbpHdr)..]); |
| 151 | if (stderr.readableLength() > 0) { | 251 | if (stderr.readableLength() > 0) { |
| 152 | const stderr_data = try stderr.toOwnedSlice(); | 252 | const stderr_data = try stderr.toOwnedSlice(); |
| 153 | fatal("emit_bin_path included unexpected stderr:\n{s}", .{stderr_data}); | 253 | if (eval.allow_stderr) { |
| 254 | std.log.info("emit_bin_path included stderr:\n{s}", .{stderr_data}); | ||
| 255 | } else { | ||
| 256 | fatal("emit_bin_path included unexpected stderr:\n{s}", .{stderr_data}); | ||
| 257 | } | ||
| 154 | } | 258 | } |
| 155 | try eval.checkSuccessOutcome(update, result_binary); | 259 | try eval.checkSuccessOutcome(update, result_binary, prog_node); |
| 156 | // This message indicates the end of the update. | 260 | // This message indicates the end of the update. |
| 157 | stdout.discard(body.len); | 261 | stdout.discard(body.len); |
| 158 | return; | 262 | return; |
| ... | @@ -166,7 +270,11 @@ const Eval = struct { | ... | @@ -166,7 +270,11 @@ const Eval = struct { |
| 166 | 270 | ||
| 167 | if (stderr.readableLength() > 0) { | 271 | if (stderr.readableLength() > 0) { |
| 168 | const stderr_data = try stderr.toOwnedSlice(); | 272 | const stderr_data = try stderr.toOwnedSlice(); |
| 169 | fatal("update '{s}' failed:\n{s}", .{ update.name, stderr_data }); | 273 | if (eval.allow_stderr) { |
| 274 | std.log.info("update '{s}' included stderr:\n{s}", .{ update.name, stderr_data }); | ||
| 275 | } else { | ||
| 276 | fatal("update '{s}' failed:\n{s}", .{ update.name, stderr_data }); | ||
| 277 | } | ||
| 170 | } | 278 | } |
| 171 | 279 | ||
| 172 | waitChild(eval.child); | 280 | waitChild(eval.child); |
| ... | @@ -191,12 +299,28 @@ const Eval = struct { | ... | @@ -191,12 +299,28 @@ const Eval = struct { |
| 191 | } | 299 | } |
| 192 | } | 300 | } |
| 193 | 301 | ||
| 194 | fn checkSuccessOutcome(eval: *Eval, update: Case.Update, binary_path: []const u8) !void { | 302 | fn checkSuccessOutcome(eval: *Eval, update: Case.Update, opt_emitted_path: ?[]const u8, prog_node: std.Progress.Node) !void { |
| 195 | switch (update.outcome) { | 303 | switch (update.outcome) { |
| 196 | .unknown => return, | 304 | .unknown => return, |
| 197 | .compile_errors => fatal("expected compile errors but compilation incorrectly succeeded", .{}), | 305 | .compile_errors => fatal("expected compile errors but compilation incorrectly succeeded", .{}), |
| 198 | .stdout, .exit_code => {}, | 306 | .stdout, .exit_code => {}, |
| 199 | } | 307 | } |
| 308 | const emitted_path = opt_emitted_path orelse { | ||
| 309 | std.debug.assert(eval.emit == .none); | ||
| 310 | return; | ||
| 311 | }; | ||
| 312 | |||
| 313 | const binary_path = switch (eval.emit) { | ||
| 314 | .none => unreachable, | ||
| 315 | .bin => emitted_path, | ||
| 316 | .c => bin: { | ||
| 317 | const rand_int = std.crypto.random.int(u64); | ||
| 318 | const out_bin_name = "./out_" ++ std.fmt.hex(rand_int); | ||
| 319 | try eval.buildCOutput(update, emitted_path, out_bin_name, prog_node); | ||
| 320 | break :bin out_bin_name; | ||
| 321 | }, | ||
| 322 | }; | ||
| 323 | |||
| 200 | const result = std.process.Child.run(.{ | 324 | const result = std.process.Child.run(.{ |
| 201 | .allocator = eval.arena, | 325 | .allocator = eval.arena, |
| 202 | .argv = &.{binary_path}, | 326 | .argv = &.{binary_path}, |
| ... | @@ -266,6 +390,50 @@ const Eval = struct { | ... | @@ -266,6 +390,50 @@ const Eval = struct { |
| 266 | fatal("unexpected stderr:\n{s}", .{stderr_data}); | 390 | fatal("unexpected stderr:\n{s}", .{stderr_data}); |
| 267 | } | 391 | } |
| 268 | } | 392 | } |
| 393 | |||
| 394 | fn buildCOutput(eval: *Eval, update: Case.Update, c_path: []const u8, out_path: []const u8, prog_node: std.Progress.Node) !void { | ||
| 395 | std.debug.assert(eval.cc_child_args.items.len > 0); | ||
| 396 | |||
| 397 | const child_prog_node = prog_node.start("build cbe output", 0); | ||
| 398 | defer child_prog_node.end(); | ||
| 399 | |||
| 400 | try eval.cc_child_args.appendSlice(eval.arena, &.{ out_path, c_path }); | ||
| 401 | defer eval.cc_child_args.items.len -= 2; | ||
| 402 | |||
| 403 | const result = std.process.Child.run(.{ | ||
| 404 | .allocator = eval.arena, | ||
| 405 | .argv = eval.cc_child_args.items, | ||
| 406 | .cwd_dir = eval.tmp_dir, | ||
| 407 | .cwd = eval.tmp_dir_path, | ||
| 408 | .progress_node = child_prog_node, | ||
| 409 | }) catch |err| { | ||
| 410 | fatal("update '{s}': failed to spawn zig cc for '{s}': {s}", .{ | ||
| 411 | update.name, c_path, @errorName(err), | ||
| 412 | }); | ||
| 413 | }; | ||
| 414 | switch (result.term) { | ||
| 415 | .Exited => |code| if (code != 0) { | ||
| 416 | if (result.stderr.len != 0) { | ||
| 417 | std.log.err("update '{s}': zig cc stderr:\n{s}", .{ | ||
| 418 | update.name, result.stderr, | ||
| 419 | }); | ||
| 420 | } | ||
| 421 | fatal("update '{s}': zig cc for '{s}' failed with code {d}", .{ | ||
| 422 | update.name, c_path, code, | ||
| 423 | }); | ||
| 424 | }, | ||
| 425 | .Signal, .Stopped, .Unknown => { | ||
| 426 | if (result.stderr.len != 0) { | ||
| 427 | std.log.err("update '{s}': zig cc stderr:\n{s}", .{ | ||
| 428 | update.name, result.stderr, | ||
| 429 | }); | ||
| 430 | } | ||
| 431 | fatal("update '{s}': zig cc for '{s}' terminated unexpectedly", .{ | ||
| 432 | update.name, c_path, | ||
| 433 | }); | ||
| 434 | }, | ||
| 435 | } | ||
| 436 | } | ||
| 269 | }; | 437 | }; |
| 270 | 438 | ||
| 271 | const Case = struct { | 439 | const Case = struct { |
| ... | @@ -357,6 +525,11 @@ const Case = struct { | ... | @@ -357,6 +525,11 @@ const Case = struct { |
| 357 | fatal("line {d}: bad string literal: {s}", .{ line_n, @errorName(err) }); | 525 | fatal("line {d}: bad string literal: {s}", .{ line_n, @errorName(err) }); |
| 358 | }, | 526 | }, |
| 359 | }; | 527 | }; |
| 528 | } else if (std.mem.eql(u8, key, "expect_error")) { | ||
| 529 | if (updates.items.len == 0) fatal("line {d}: expect directive before update", .{line_n}); | ||
| 530 | const last_update = &updates.items[updates.items.len - 1]; | ||
| 531 | if (last_update.outcome != .unknown) fatal("line {d}: conflicting expect directive", .{line_n}); | ||
| 532 | last_update.outcome = .{ .compile_errors = &.{} }; | ||
| 360 | } else { | 533 | } else { |
| 361 | fatal("line {d}: unrecognized key '{s}'", .{ line_n, key }); | 534 | fatal("line {d}: unrecognized key '{s}'", .{ line_n, key }); |
| 362 | } | 535 | } |