authorgravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2023-10-10 12:30:44+01:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-10-10 21:40:23-07:00
log1033d71017c9c40bd55f1743cd7990024c892af7
tree542fed262152767a305316cd5c71a5f4c7328965
parent7edba14d7cba465a2ffe12a45f96424849bbaf11

Sema,type: unify type query functions

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,7 +35301,7 @@ fn resolveSimpleType(sema: *Sema, simple_type: InternPool.SimpleType) CompileErr
35301 _ = try sema.getBuiltinType(builtin_type_name);35301 _ = try sema.getBuiltinType(builtin_type_name);
35302}35302}
3530335303
35304fn resolveTypeFieldsStruct(35304pub fn resolveTypeFieldsStruct(
35305 sema: *Sema,35305 sema: *Sema,
35306 ty: InternPool.Index,35306 ty: InternPool.Index,
35307 struct_type: InternPool.Key.StructType,35307 struct_type: InternPool.Key.StructType,
...@@ -35340,7 +35340,7 @@ fn resolveTypeFieldsStruct(...@@ -35340,7 +35340,7 @@ fn resolveTypeFieldsStruct(
35340 try semaStructFields(mod, sema.arena, struct_type);35340 try semaStructFields(mod, sema.arena, struct_type);
35341}35341}
3534235342
35343fn resolveTypeFieldsUnion(sema: *Sema, ty: Type, union_type: InternPool.Key.UnionType) CompileError!void {35343pub fn resolveTypeFieldsUnion(sema: *Sema, ty: Type, union_type: InternPool.Key.UnionType) CompileError!void {
35344 const mod = sema.mod;35344 const mod = sema.mod;
35345 const ip = &mod.intern_pool;35345 const ip = &mod.intern_pool;
35346 const owner_decl = mod.declPtr(union_type.decl);35346 const owner_decl = mod.declPtr(union_type.decl);
...@@ -37083,185 +37083,9 @@ fn typePtrOrOptionalPtrTy(sema: *Sema, ty: Type) !?Type {...@@ -37083,185 +37083,9 @@ fn typePtrOrOptionalPtrTy(sema: *Sema, ty: Type) !?Type {
37083}37083}
3708437084
37085/// `generic_poison` will return false.37085/// `generic_poison` will return false.
37086/// This function returns false negatives when structs and unions are having their37086/// May return false negatives when structs and unions are having their field types resolved.
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
37091pub fn typeRequiresComptime(sema: *Sema, ty: Type) CompileError!bool {37087pub fn typeRequiresComptime(sema: *Sema, ty: Type) CompileError!bool {
37092 const mod = sema.mod;37088 return ty.comptimeOnlyAdvanced(sema.mod, sema);
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 };
37265}37089}
3726637090
37267pub fn typeHasRuntimeBits(sema: *Sema, ty: Type) CompileError!bool {37091pub fn typeHasRuntimeBits(sema: *Sema, ty: Type) CompileError!bool {
...@@ -37316,21 +37140,8 @@ fn structFieldAlignment(...@@ -37316,21 +37140,8 @@ fn structFieldAlignment(
37316 return ty_abi_align;37140 return ty_abi_align;
37317}37141}
3731837142
37319/// Synchronize logic with `Type.isFnOrHasRuntimeBits`.
37320pub fn fnHasRuntimeBits(sema: *Sema, ty: Type) CompileError!bool {37143pub fn fnHasRuntimeBits(sema: *Sema, ty: Type) CompileError!bool {
37321 const mod = sema.mod;37144 return ty.fnHasRuntimeBitsAdvanced(sema.mod, sema);
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;
37334}37145}
3733537146
37336fn unionFieldIndex(37147fn unionFieldIndex(
src/type.zig+89-39
...@@ -771,21 +771,25 @@ pub const Type = struct {...@@ -771,21 +771,25 @@ pub const Type = struct {
771 return hasRuntimeBitsAdvanced(ty, mod, true, .eager) catch unreachable;771 return hasRuntimeBitsAdvanced(ty, mod, true, .eager) catch unreachable;
772 }772 }
773773
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 pub fn isFnOrHasRuntimeBits(ty: Type, mod: *Module) bool {790 pub fn isFnOrHasRuntimeBits(ty: Type, mod: *Module) bool {
775 switch (ty.zigTypeTag(mod)) {791 switch (ty.zigTypeTag(mod)) {
776 .Fn => {792 .Fn => return ty.fnHasRuntimeBits(mod),
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 },
789 else => return ty.hasRuntimeBits(mod),793 else => return ty.hasRuntimeBits(mod),
790 }794 }
791 }795 }
...@@ -2575,9 +2579,14 @@ pub const Type = struct {...@@ -2575,9 +2579,14 @@ pub const Type = struct {
25752579
2576 /// During semantic analysis, instead call `Sema.typeRequiresComptime` which2580 /// During semantic analysis, instead call `Sema.typeRequiresComptime` which
2577 /// resolves field types rather than asserting they are already resolved.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 pub fn comptimeOnly(ty: Type, mod: *Module) bool {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 const ip = &mod.intern_pool;2590 const ip = &mod.intern_pool;
2582 return switch (ty.toIntern()) {2591 return switch (ty.toIntern()) {
2583 .empty_struct_type => false,2592 .empty_struct_type => false,
...@@ -2587,19 +2596,19 @@ pub const Type = struct {...@@ -2587,19 +2596,19 @@ pub const Type = struct {
2587 .ptr_type => |ptr_type| {2596 .ptr_type => |ptr_type| {
2588 const child_ty = ptr_type.child.toType();2597 const child_ty = ptr_type.child.toType();
2589 switch (child_ty.zigTypeTag(mod)) {2598 switch (child_ty.zigTypeTag(mod)) {
2590 .Fn => return !child_ty.isFnOrHasRuntimeBits(mod),2599 .Fn => return !try child_ty.fnHasRuntimeBitsAdvanced(mod, opt_sema),
2591 .Opaque => return false,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 .anyframe_type => |child| {2604 .anyframe_type => |child| {
2596 if (child == .none) return false;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),2608 .array_type => |array_type| return array_type.child.toType().comptimeOnlyAdvanced(mod, opt_sema),
2600 .vector_type => |vector_type| vector_type.child.toType().comptimeOnly(mod),2609 .vector_type => |vector_type| return vector_type.child.toType().comptimeOnlyAdvanced(mod, opt_sema),
2601 .opt_type => |child| child.toType().comptimeOnly(mod),2610 .opt_type => |child| return child.toType().comptimeOnlyAdvanced(mod, opt_sema),
2602 .error_union_type => |error_union_type| error_union_type.payload_type.toType().comptimeOnly(mod),2611 .error_union_type => |error_union_type| return error_union_type.payload_type.toType().comptimeOnlyAdvanced(mod, opt_sema),
26032612
2604 .error_set_type,2613 .error_set_type,
2605 .inferred_error_set_type,2614 .inferred_error_set_type,
...@@ -2662,39 +2671,80 @@ pub const Type = struct {...@@ -2662,39 +2671,80 @@ pub const Type = struct {
26622671
2663 // A struct with no fields is not comptime-only.2672 // A struct with no fields is not comptime-only.
2664 return switch (struct_type.flagsPtr(ip).requires_comptime) {2673 return switch (struct_type.flagsPtr(ip).requires_comptime) {
2665 // Return false to avoid incorrect dependency loops.2674 .no, .wip => false,
2666 // This will be handled correctly once merged with
2667 // `Sema.typeRequiresComptime`.
2668 .wip, .unknown => false,
2669 .no => false,
2670 .yes => true,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 },
26732707
2674 .anon_struct_type => |tuple| {2708 .anon_struct_type => |tuple| {
2675 for (tuple.types.get(ip), tuple.values.get(ip)) |field_ty, val| {2709 for (tuple.types.get(ip), tuple.values.get(ip)) |field_ty, val| {
2676 const have_comptime_val = val != .none;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 return false;2713 return false;
2680 },2714 },
26812715
2682 .union_type => |union_type| {2716 .union_type => |union_type| switch (union_type.flagsPtr(ip).requires_comptime) {
2683 switch (union_type.flagsPtr(ip).requires_comptime) {2717 .no, .wip => false,
2684 .wip, .unknown => {2718 .yes => true,
2685 // Return false to avoid incorrect dependency loops.2719 .unknown => {
2686 // This will be handled correctly once merged with2720 // The type is not resolved; assert that we have a Sema.
2687 // `Sema.typeRequiresComptime`.2721 const sema = opt_sema.?;
2722
2723 if (union_type.flagsPtr(ip).status == .field_types_wip)
2688 return false;2724 return false;
2689 },2725
2690 .no => return false,2726 try sema.resolveTypeFieldsUnion(ty, union_type);
2691 .yes => return true,2727 const union_obj = ip.loadUnionType(union_type);
2692 }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 },
26942744
2695 .opaque_type => false,2745 .opaque_type => false,
26962746
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),
26982748
2699 // values, not types2749 // values, not types
2700 .undef,2750 .undef,