| author | |
| committer | |
| log | 1033d71017c9c40bd55f1743cd7990024c892af7 |
| tree | 542fed262152767a305316cd5c71a5f4c7328965 |
| parent | 7edba14d7cba465a2ffe12a45f96424849bbaf11 |
The following pairs of functions have been combined using the "advanced"
pattern used for other type queries:
* `Sema.fnHasRuntimeBits`, `Type.isFnOrHasRuntimeBits`
* `Sema.typeRequiresComptime`, `Type.comptimeOnly`2 files changed, 94 insertions(+), 233 deletions(-)
src/Sema.zig+5-194| ... | ... | @@ -35301,7 +35301,7 @@ fn resolveSimpleType(sema: *Sema, simple_type: InternPool.SimpleType) CompileErr |
| 35301 | 35301 | _ = try sema.getBuiltinType(builtin_type_name); |
| 35302 | 35302 | } |
| 35303 | 35303 | |
| 35304 | fn resolveTypeFieldsStruct( | |
| 35304 | pub fn resolveTypeFieldsStruct( | |
| 35305 | 35305 | sema: *Sema, |
| 35306 | 35306 | ty: InternPool.Index, |
| 35307 | 35307 | struct_type: InternPool.Key.StructType, |
| ... | ... | @@ -35340,7 +35340,7 @@ fn resolveTypeFieldsStruct( |
| 35340 | 35340 | try semaStructFields(mod, sema.arena, struct_type); |
| 35341 | 35341 | } |
| 35342 | 35342 | |
| 35343 | fn resolveTypeFieldsUnion(sema: *Sema, ty: Type, union_type: InternPool.Key.UnionType) CompileError!void { | |
| 35343 | pub fn resolveTypeFieldsUnion(sema: *Sema, ty: Type, union_type: InternPool.Key.UnionType) CompileError!void { | |
| 35344 | 35344 | const mod = sema.mod; |
| 35345 | 35345 | const ip = &mod.intern_pool; |
| 35346 | 35346 | const owner_decl = mod.declPtr(union_type.decl); |
| ... | ... | @@ -37083,185 +37083,9 @@ fn typePtrOrOptionalPtrTy(sema: *Sema, ty: Type) !?Type { |
| 37083 | 37083 | } |
| 37084 | 37084 | |
| 37085 | 37085 | /// `generic_poison` will return false. |
| 37086 | /// This function returns false negatives when structs and unions are having their | |
| 37087 | /// field types resolved. | |
| 37088 | /// TODO assert the return value matches `ty.comptimeOnly` | |
| 37089 | /// TODO merge these implementations together with the "advanced"/opt_sema pattern seen | |
| 37090 | /// elsewhere in value.zig | |
| 37086 | /// May return false negatives when structs and unions are having their field types resolved. | |
| 37091 | 37087 | pub fn typeRequiresComptime(sema: *Sema, ty: Type) CompileError!bool { |
| 37092 | const mod = sema.mod; | |
| 37093 | const ip = &mod.intern_pool; | |
| 37094 | return switch (ty.toIntern()) { | |
| 37095 | .empty_struct_type => false, | |
| 37096 | ||
| 37097 | else => switch (ip.indexToKey(ty.toIntern())) { | |
| 37098 | .int_type => return false, | |
| 37099 | .ptr_type => |ptr_type| { | |
| 37100 | const child_ty = ptr_type.child.toType(); | |
| 37101 | switch (child_ty.zigTypeTag(mod)) { | |
| 37102 | .Fn => return !try sema.fnHasRuntimeBits(child_ty), | |
| 37103 | .Opaque => return false, | |
| 37104 | else => return sema.typeRequiresComptime(child_ty), | |
| 37105 | } | |
| 37106 | }, | |
| 37107 | .anyframe_type => |child| { | |
| 37108 | if (child == .none) return false; | |
| 37109 | return sema.typeRequiresComptime(child.toType()); | |
| 37110 | }, | |
| 37111 | .array_type => |array_type| return sema.typeRequiresComptime(array_type.child.toType()), | |
| 37112 | .vector_type => |vector_type| return sema.typeRequiresComptime(vector_type.child.toType()), | |
| 37113 | .opt_type => |child| return sema.typeRequiresComptime(child.toType()), | |
| 37114 | ||
| 37115 | .error_union_type => |error_union_type| { | |
| 37116 | return sema.typeRequiresComptime(error_union_type.payload_type.toType()); | |
| 37117 | }, | |
| 37118 | ||
| 37119 | .error_set_type, .inferred_error_set_type => false, | |
| 37120 | ||
| 37121 | .func_type => true, | |
| 37122 | ||
| 37123 | .simple_type => |t| switch (t) { | |
| 37124 | .f16, | |
| 37125 | .f32, | |
| 37126 | .f64, | |
| 37127 | .f80, | |
| 37128 | .f128, | |
| 37129 | .usize, | |
| 37130 | .isize, | |
| 37131 | .c_char, | |
| 37132 | .c_short, | |
| 37133 | .c_ushort, | |
| 37134 | .c_int, | |
| 37135 | .c_uint, | |
| 37136 | .c_long, | |
| 37137 | .c_ulong, | |
| 37138 | .c_longlong, | |
| 37139 | .c_ulonglong, | |
| 37140 | .c_longdouble, | |
| 37141 | .anyopaque, | |
| 37142 | .bool, | |
| 37143 | .void, | |
| 37144 | .anyerror, | |
| 37145 | .adhoc_inferred_error_set, | |
| 37146 | .noreturn, | |
| 37147 | .generic_poison, | |
| 37148 | .atomic_order, | |
| 37149 | .atomic_rmw_op, | |
| 37150 | .calling_convention, | |
| 37151 | .address_space, | |
| 37152 | .float_mode, | |
| 37153 | .reduce_op, | |
| 37154 | .call_modifier, | |
| 37155 | .prefetch_options, | |
| 37156 | .export_options, | |
| 37157 | .extern_options, | |
| 37158 | => false, | |
| 37159 | ||
| 37160 | .type, | |
| 37161 | .comptime_int, | |
| 37162 | .comptime_float, | |
| 37163 | .null, | |
| 37164 | .undefined, | |
| 37165 | .enum_literal, | |
| 37166 | .type_info, | |
| 37167 | => true, | |
| 37168 | }, | |
| 37169 | .struct_type => |struct_type| { | |
| 37170 | if (struct_type.layout == .Packed) { | |
| 37171 | // packed structs cannot be comptime-only because they have a well-defined | |
| 37172 | // memory layout and every field has a well-defined bit pattern. | |
| 37173 | return false; | |
| 37174 | } | |
| 37175 | switch (struct_type.flagsPtr(ip).requires_comptime) { | |
| 37176 | .no, .wip => return false, | |
| 37177 | .yes => return true, | |
| 37178 | .unknown => { | |
| 37179 | if (struct_type.flagsPtr(ip).field_types_wip) | |
| 37180 | return false; | |
| 37181 | ||
| 37182 | try sema.resolveTypeFieldsStruct(ty.toIntern(), struct_type); | |
| 37183 | ||
| 37184 | struct_type.flagsPtr(ip).requires_comptime = .wip; | |
| 37185 | ||
| 37186 | for (0..struct_type.field_types.len) |i_usize| { | |
| 37187 | const i: u32 = @intCast(i_usize); | |
| 37188 | if (struct_type.fieldIsComptime(ip, i)) continue; | |
| 37189 | const field_ty = struct_type.field_types.get(ip)[i]; | |
| 37190 | if (try sema.typeRequiresComptime(field_ty.toType())) { | |
| 37191 | // Note that this does not cause the layout to | |
| 37192 | // be considered resolved. Comptime-only types | |
| 37193 | // still maintain a layout of their | |
| 37194 | // runtime-known fields. | |
| 37195 | struct_type.flagsPtr(ip).requires_comptime = .yes; | |
| 37196 | return true; | |
| 37197 | } | |
| 37198 | } | |
| 37199 | struct_type.flagsPtr(ip).requires_comptime = .no; | |
| 37200 | return false; | |
| 37201 | }, | |
| 37202 | } | |
| 37203 | }, | |
| 37204 | .anon_struct_type => |tuple| { | |
| 37205 | for (tuple.types.get(ip), tuple.values.get(ip)) |field_ty, val| { | |
| 37206 | const have_comptime_val = val != .none; | |
| 37207 | if (!have_comptime_val and try sema.typeRequiresComptime(field_ty.toType())) { | |
| 37208 | return true; | |
| 37209 | } | |
| 37210 | } | |
| 37211 | return false; | |
| 37212 | }, | |
| 37213 | ||
| 37214 | .union_type => |union_type| { | |
| 37215 | switch (union_type.flagsPtr(ip).requires_comptime) { | |
| 37216 | .no, .wip => return false, | |
| 37217 | .yes => return true, | |
| 37218 | .unknown => { | |
| 37219 | if (union_type.flagsPtr(ip).status == .field_types_wip) | |
| 37220 | return false; | |
| 37221 | ||
| 37222 | try sema.resolveTypeFieldsUnion(ty, union_type); | |
| 37223 | const union_obj = ip.loadUnionType(union_type); | |
| 37224 | ||
| 37225 | union_obj.flagsPtr(ip).requires_comptime = .wip; | |
| 37226 | for (0..union_obj.field_types.len) |field_index| { | |
| 37227 | const field_ty = union_obj.field_types.get(ip)[field_index]; | |
| 37228 | if (try sema.typeRequiresComptime(field_ty.toType())) { | |
| 37229 | union_obj.flagsPtr(ip).requires_comptime = .yes; | |
| 37230 | return true; | |
| 37231 | } | |
| 37232 | } | |
| 37233 | union_obj.flagsPtr(ip).requires_comptime = .no; | |
| 37234 | return false; | |
| 37235 | }, | |
| 37236 | } | |
| 37237 | }, | |
| 37238 | ||
| 37239 | .opaque_type => false, | |
| 37240 | .enum_type => |enum_type| try sema.typeRequiresComptime(enum_type.tag_ty.toType()), | |
| 37241 | ||
| 37242 | // values, not types | |
| 37243 | .undef, | |
| 37244 | .runtime_value, | |
| 37245 | .simple_value, | |
| 37246 | .variable, | |
| 37247 | .extern_func, | |
| 37248 | .func, | |
| 37249 | .int, | |
| 37250 | .err, | |
| 37251 | .error_union, | |
| 37252 | .enum_literal, | |
| 37253 | .enum_tag, | |
| 37254 | .empty_enum_value, | |
| 37255 | .float, | |
| 37256 | .ptr, | |
| 37257 | .opt, | |
| 37258 | .aggregate, | |
| 37259 | .un, | |
| 37260 | // memoization, not types | |
| 37261 | .memoized_call, | |
| 37262 | => unreachable, | |
| 37263 | }, | |
| 37264 | }; | |
| 37088 | return ty.comptimeOnlyAdvanced(sema.mod, sema); | |
| 37265 | 37089 | } |
| 37266 | 37090 | |
| 37267 | 37091 | pub fn typeHasRuntimeBits(sema: *Sema, ty: Type) CompileError!bool { |
| ... | ... | @@ -37316,21 +37140,8 @@ fn structFieldAlignment( |
| 37316 | 37140 | return ty_abi_align; |
| 37317 | 37141 | } |
| 37318 | 37142 | |
| 37319 | /// Synchronize logic with `Type.isFnOrHasRuntimeBits`. | |
| 37320 | 37143 | pub fn fnHasRuntimeBits(sema: *Sema, ty: Type) CompileError!bool { |
| 37321 | const mod = sema.mod; | |
| 37322 | const fn_info = mod.typeToFunc(ty).?; | |
| 37323 | if (fn_info.is_generic) return false; | |
| 37324 | if (fn_info.is_var_args) return true; | |
| 37325 | switch (fn_info.cc) { | |
| 37326 | // If there was a comptime calling convention, it should also return false here. | |
| 37327 | .Inline => return false, | |
| 37328 | else => {}, | |
| 37329 | } | |
| 37330 | if (try sema.typeRequiresComptime(fn_info.return_type.toType())) { | |
| 37331 | return false; | |
| 37332 | } | |
| 37333 | return true; | |
| 37144 | return ty.fnHasRuntimeBitsAdvanced(sema.mod, sema); | |
| 37334 | 37145 | } |
| 37335 | 37146 | |
| 37336 | 37147 | fn unionFieldIndex( |
src/type.zig+89-39| ... | ... | @@ -771,21 +771,25 @@ pub const Type = struct { |
| 771 | 771 | return hasRuntimeBitsAdvanced(ty, mod, true, .eager) catch unreachable; |
| 772 | 772 | } |
| 773 | 773 | |
| 774 | pub fn fnHasRuntimeBits(ty: Type, mod: *Module) bool { | |
| 775 | return ty.fnHasRuntimeBitsAdvanced(mod, null) catch unreachable; | |
| 776 | } | |
| 777 | ||
| 778 | /// Determines whether a function type has runtime bits, i.e. whether a | |
| 779 | /// function with this type can exist at runtime. | |
| 780 | /// Asserts that `ty` is a function type. | |
| 781 | /// If `opt_sema` is not provided, asserts that the return type is sufficiently resolved. | |
| 782 | pub fn fnHasRuntimeBitsAdvanced(ty: Type, mod: *Module, opt_sema: ?*Sema) Module.CompileError!bool { | |
| 783 | const fn_info = mod.typeToFunc(ty).?; | |
| 784 | if (fn_info.is_generic) return false; | |
| 785 | if (fn_info.is_var_args) return true; | |
| 786 | if (fn_info.cc == .Inline) return false; | |
| 787 | return !try fn_info.return_type.toType().comptimeOnlyAdvanced(mod, opt_sema); | |
| 788 | } | |
| 789 | ||
| 774 | 790 | pub fn isFnOrHasRuntimeBits(ty: Type, mod: *Module) bool { |
| 775 | 791 | switch (ty.zigTypeTag(mod)) { |
| 776 | .Fn => { | |
| 777 | const fn_info = mod.typeToFunc(ty).?; | |
| 778 | if (fn_info.is_generic) return false; | |
| 779 | if (fn_info.is_var_args) return true; | |
| 780 | switch (fn_info.cc) { | |
| 781 | // If there was a comptime calling convention, | |
| 782 | // it should also return false here. | |
| 783 | .Inline => return false, | |
| 784 | else => {}, | |
| 785 | } | |
| 786 | if (fn_info.return_type.toType().comptimeOnly(mod)) return false; | |
| 787 | return true; | |
| 788 | }, | |
| 792 | .Fn => return ty.fnHasRuntimeBits(mod), | |
| 789 | 793 | else => return ty.hasRuntimeBits(mod), |
| 790 | 794 | } |
| 791 | 795 | } |
| ... | ... | @@ -2575,9 +2579,14 @@ pub const Type = struct { |
| 2575 | 2579 | |
| 2576 | 2580 | /// During semantic analysis, instead call `Sema.typeRequiresComptime` which |
| 2577 | 2581 | /// resolves field types rather than asserting they are already resolved. |
| 2578 | /// TODO merge these implementations together with the "advanced" pattern seen | |
| 2579 | /// elsewhere in this file. | |
| 2580 | 2582 | pub fn comptimeOnly(ty: Type, mod: *Module) bool { |
| 2583 | return ty.comptimeOnlyAdvanced(mod, null) catch unreachable; | |
| 2584 | } | |
| 2585 | ||
| 2586 | /// `generic_poison` will return false. | |
| 2587 | /// May return false negatives when structs and unions are having their field types resolved. | |
| 2588 | /// If `opt_sema` is not provided, asserts that the type is sufficiently resolved. | |
| 2589 | pub fn comptimeOnlyAdvanced(ty: Type, mod: *Module, opt_sema: ?*Sema) Module.CompileError!bool { | |
| 2581 | 2590 | const ip = &mod.intern_pool; |
| 2582 | 2591 | return switch (ty.toIntern()) { |
| 2583 | 2592 | .empty_struct_type => false, |
| ... | ... | @@ -2587,19 +2596,19 @@ pub const Type = struct { |
| 2587 | 2596 | .ptr_type => |ptr_type| { |
| 2588 | 2597 | const child_ty = ptr_type.child.toType(); |
| 2589 | 2598 | switch (child_ty.zigTypeTag(mod)) { |
| 2590 | .Fn => return !child_ty.isFnOrHasRuntimeBits(mod), | |
| 2599 | .Fn => return !try child_ty.fnHasRuntimeBitsAdvanced(mod, opt_sema), | |
| 2591 | 2600 | .Opaque => return false, |
| 2592 | else => return child_ty.comptimeOnly(mod), | |
| 2601 | else => return child_ty.comptimeOnlyAdvanced(mod, opt_sema), | |
| 2593 | 2602 | } |
| 2594 | 2603 | }, |
| 2595 | 2604 | .anyframe_type => |child| { |
| 2596 | 2605 | if (child == .none) return false; |
| 2597 | return child.toType().comptimeOnly(mod); | |
| 2606 | return child.toType().comptimeOnlyAdvanced(mod, opt_sema); | |
| 2598 | 2607 | }, |
| 2599 | .array_type => |array_type| array_type.child.toType().comptimeOnly(mod), | |
| 2600 | .vector_type => |vector_type| vector_type.child.toType().comptimeOnly(mod), | |
| 2601 | .opt_type => |child| child.toType().comptimeOnly(mod), | |
| 2602 | .error_union_type => |error_union_type| error_union_type.payload_type.toType().comptimeOnly(mod), | |
| 2608 | .array_type => |array_type| return array_type.child.toType().comptimeOnlyAdvanced(mod, opt_sema), | |
| 2609 | .vector_type => |vector_type| return vector_type.child.toType().comptimeOnlyAdvanced(mod, opt_sema), | |
| 2610 | .opt_type => |child| return child.toType().comptimeOnlyAdvanced(mod, opt_sema), | |
| 2611 | .error_union_type => |error_union_type| return error_union_type.payload_type.toType().comptimeOnlyAdvanced(mod, opt_sema), | |
| 2603 | 2612 | |
| 2604 | 2613 | .error_set_type, |
| 2605 | 2614 | .inferred_error_set_type, |
| ... | ... | @@ -2662,39 +2671,80 @@ pub const Type = struct { |
| 2662 | 2671 | |
| 2663 | 2672 | // A struct with no fields is not comptime-only. |
| 2664 | 2673 | return switch (struct_type.flagsPtr(ip).requires_comptime) { |
| 2665 | // Return false to avoid incorrect dependency loops. | |
| 2666 | // This will be handled correctly once merged with | |
| 2667 | // `Sema.typeRequiresComptime`. | |
| 2668 | .wip, .unknown => false, | |
| 2669 | .no => false, | |
| 2674 | .no, .wip => false, | |
| 2670 | 2675 | .yes => true, |
| 2676 | .unknown => { | |
| 2677 | // The type is not resolved; assert that we have a Sema. | |
| 2678 | const sema = opt_sema.?; | |
| 2679 | ||
| 2680 | if (struct_type.flagsPtr(ip).field_types_wip) | |
| 2681 | return false; | |
| 2682 | ||
| 2683 | try sema.resolveTypeFieldsStruct(ty.toIntern(), struct_type); | |
| 2684 | ||
| 2685 | struct_type.flagsPtr(ip).requires_comptime = .wip; | |
| 2686 | errdefer struct_type.flagsPtr(ip).requires_comptime = .unknown; | |
| 2687 | ||
| 2688 | for (0..struct_type.field_types.len) |i_usize| { | |
| 2689 | const i: u32 = @intCast(i_usize); | |
| 2690 | if (struct_type.fieldIsComptime(ip, i)) continue; | |
| 2691 | const field_ty = struct_type.field_types.get(ip)[i]; | |
| 2692 | if (try field_ty.toType().comptimeOnlyAdvanced(mod, opt_sema)) { | |
| 2693 | // Note that this does not cause the layout to | |
| 2694 | // be considered resolved. Comptime-only types | |
| 2695 | // still maintain a layout of their | |
| 2696 | // runtime-known fields. | |
| 2697 | struct_type.flagsPtr(ip).requires_comptime = .yes; | |
| 2698 | return true; | |
| 2699 | } | |
| 2700 | } | |
| 2701 | ||
| 2702 | struct_type.flagsPtr(ip).requires_comptime = .no; | |
| 2703 | return false; | |
| 2704 | }, | |
| 2671 | 2705 | }; |
| 2672 | 2706 | }, |
| 2673 | 2707 | |
| 2674 | 2708 | .anon_struct_type => |tuple| { |
| 2675 | 2709 | for (tuple.types.get(ip), tuple.values.get(ip)) |field_ty, val| { |
| 2676 | 2710 | const have_comptime_val = val != .none; |
| 2677 | if (!have_comptime_val and field_ty.toType().comptimeOnly(mod)) return true; | |
| 2711 | if (!have_comptime_val and try field_ty.toType().comptimeOnlyAdvanced(mod, opt_sema)) return true; | |
| 2678 | 2712 | } |
| 2679 | 2713 | return false; |
| 2680 | 2714 | }, |
| 2681 | 2715 | |
| 2682 | .union_type => |union_type| { | |
| 2683 | switch (union_type.flagsPtr(ip).requires_comptime) { | |
| 2684 | .wip, .unknown => { | |
| 2685 | // Return false to avoid incorrect dependency loops. | |
| 2686 | // This will be handled correctly once merged with | |
| 2687 | // `Sema.typeRequiresComptime`. | |
| 2716 | .union_type => |union_type| switch (union_type.flagsPtr(ip).requires_comptime) { | |
| 2717 | .no, .wip => false, | |
| 2718 | .yes => true, | |
| 2719 | .unknown => { | |
| 2720 | // The type is not resolved; assert that we have a Sema. | |
| 2721 | const sema = opt_sema.?; | |
| 2722 | ||
| 2723 | if (union_type.flagsPtr(ip).status == .field_types_wip) | |
| 2688 | 2724 | return false; |
| 2689 | }, | |
| 2690 | .no => return false, | |
| 2691 | .yes => return true, | |
| 2692 | } | |
| 2725 | ||
| 2726 | try sema.resolveTypeFieldsUnion(ty, union_type); | |
| 2727 | const union_obj = ip.loadUnionType(union_type); | |
| 2728 | ||
| 2729 | union_obj.flagsPtr(ip).requires_comptime = .wip; | |
| 2730 | errdefer union_obj.flagsPtr(ip).requires_comptime = .unknown; | |
| 2731 | ||
| 2732 | for (0..union_obj.field_types.len) |field_idx| { | |
| 2733 | const field_ty = union_obj.field_types.get(ip)[field_idx]; | |
| 2734 | if (try field_ty.toType().comptimeOnlyAdvanced(mod, opt_sema)) { | |
| 2735 | union_obj.flagsPtr(ip).requires_comptime = .yes; | |
| 2736 | return true; | |
| 2737 | } | |
| 2738 | } | |
| 2739 | ||
| 2740 | union_obj.flagsPtr(ip).requires_comptime = .no; | |
| 2741 | return false; | |
| 2742 | }, | |
| 2693 | 2743 | }, |
| 2694 | 2744 | |
| 2695 | 2745 | .opaque_type => false, |
| 2696 | 2746 | |
| 2697 | .enum_type => |enum_type| enum_type.tag_ty.toType().comptimeOnly(mod), | |
| 2747 | .enum_type => |enum_type| return enum_type.tag_ty.toType().comptimeOnlyAdvanced(mod, opt_sema), | |
| 2698 | 2748 | |
| 2699 | 2749 | // values, not types |
| 2700 | 2750 | .undef, |