Commit 1033d71017
src/Sema.zig
@@ -35301,7 +35301,7 @@ fn resolveSimpleType(sema: *Sema, simple_type: InternPool.SimpleType) CompileErr
_ = try sema.getBuiltinType(builtin_type_name);
}
-fn resolveTypeFieldsStruct(
+pub fn resolveTypeFieldsStruct(
sema: *Sema,
ty: InternPool.Index,
struct_type: InternPool.Key.StructType,
@@ -35340,7 +35340,7 @@ fn resolveTypeFieldsStruct(
try semaStructFields(mod, sema.arena, struct_type);
}
-fn resolveTypeFieldsUnion(sema: *Sema, ty: Type, union_type: InternPool.Key.UnionType) CompileError!void {
+pub fn resolveTypeFieldsUnion(sema: *Sema, ty: Type, union_type: InternPool.Key.UnionType) CompileError!void {
const mod = sema.mod;
const ip = &mod.intern_pool;
const owner_decl = mod.declPtr(union_type.decl);
@@ -37083,185 +37083,9 @@ fn typePtrOrOptionalPtrTy(sema: *Sema, ty: Type) !?Type {
}
/// `generic_poison` will return false.
-/// This function returns false negatives when structs and unions are having their
-/// field types resolved.
-/// TODO assert the return value matches `ty.comptimeOnly`
-/// TODO merge these implementations together with the "advanced"/opt_sema pattern seen
-/// elsewhere in value.zig
+/// May return false negatives when structs and unions are having their field types resolved.
pub fn typeRequiresComptime(sema: *Sema, ty: Type) CompileError!bool {
- const mod = sema.mod;
- const ip = &mod.intern_pool;
- return switch (ty.toIntern()) {
- .empty_struct_type => false,
-
- else => switch (ip.indexToKey(ty.toIntern())) {
- .int_type => return false,
- .ptr_type => |ptr_type| {
- const child_ty = ptr_type.child.toType();
- switch (child_ty.zigTypeTag(mod)) {
- .Fn => return !try sema.fnHasRuntimeBits(child_ty),
- .Opaque => return false,
- else => return sema.typeRequiresComptime(child_ty),
- }
- },
- .anyframe_type => |child| {
- if (child == .none) return false;
- return sema.typeRequiresComptime(child.toType());
- },
- .array_type => |array_type| return sema.typeRequiresComptime(array_type.child.toType()),
- .vector_type => |vector_type| return sema.typeRequiresComptime(vector_type.child.toType()),
- .opt_type => |child| return sema.typeRequiresComptime(child.toType()),
-
- .error_union_type => |error_union_type| {
- return sema.typeRequiresComptime(error_union_type.payload_type.toType());
- },
-
- .error_set_type, .inferred_error_set_type => false,
-
- .func_type => true,
-
- .simple_type => |t| switch (t) {
- .f16,
- .f32,
- .f64,
- .f80,
- .f128,
- .usize,
- .isize,
- .c_char,
- .c_short,
- .c_ushort,
- .c_int,
- .c_uint,
- .c_long,
- .c_ulong,
- .c_longlong,
- .c_ulonglong,
- .c_longdouble,
- .anyopaque,
- .bool,
- .void,
- .anyerror,
- .adhoc_inferred_error_set,
- .noreturn,
- .generic_poison,
- .atomic_order,
- .atomic_rmw_op,
- .calling_convention,
- .address_space,
- .float_mode,
- .reduce_op,
- .call_modifier,
- .prefetch_options,
- .export_options,
- .extern_options,
- => false,
-
- .type,
- .comptime_int,
- .comptime_float,
- .null,
- .undefined,
- .enum_literal,
- .type_info,
- => true,
- },
- .struct_type => |struct_type| {
- if (struct_type.layout == .Packed) {
- // packed structs cannot be comptime-only because they have a well-defined
- // memory layout and every field has a well-defined bit pattern.
- return false;
- }
- switch (struct_type.flagsPtr(ip).requires_comptime) {
- .no, .wip => return false,
- .yes => return true,
- .unknown => {
- if (struct_type.flagsPtr(ip).field_types_wip)
- return false;
-
- try sema.resolveTypeFieldsStruct(ty.toIntern(), struct_type);
-
- struct_type.flagsPtr(ip).requires_comptime = .wip;
-
- for (0..struct_type.field_types.len) |i_usize| {
- const i: u32 = @intCast(i_usize);
- if (struct_type.fieldIsComptime(ip, i)) continue;
- const field_ty = struct_type.field_types.get(ip)[i];
- if (try sema.typeRequiresComptime(field_ty.toType())) {
- // Note that this does not cause the layout to
- // be considered resolved. Comptime-only types
- // still maintain a layout of their
- // runtime-known fields.
- struct_type.flagsPtr(ip).requires_comptime = .yes;
- return true;
- }
- }
- struct_type.flagsPtr(ip).requires_comptime = .no;
- return false;
- },
- }
- },
- .anon_struct_type => |tuple| {
- for (tuple.types.get(ip), tuple.values.get(ip)) |field_ty, val| {
- const have_comptime_val = val != .none;
- if (!have_comptime_val and try sema.typeRequiresComptime(field_ty.toType())) {
- return true;
- }
- }
- return false;
- },
-
- .union_type => |union_type| {
- switch (union_type.flagsPtr(ip).requires_comptime) {
- .no, .wip => return false,
- .yes => return true,
- .unknown => {
- if (union_type.flagsPtr(ip).status == .field_types_wip)
- return false;
-
- try sema.resolveTypeFieldsUnion(ty, union_type);
- const union_obj = ip.loadUnionType(union_type);
-
- union_obj.flagsPtr(ip).requires_comptime = .wip;
- for (0..union_obj.field_types.len) |field_index| {
- const field_ty = union_obj.field_types.get(ip)[field_index];
- if (try sema.typeRequiresComptime(field_ty.toType())) {
- union_obj.flagsPtr(ip).requires_comptime = .yes;
- return true;
- }
- }
- union_obj.flagsPtr(ip).requires_comptime = .no;
- return false;
- },
- }
- },
-
- .opaque_type => false,
- .enum_type => |enum_type| try sema.typeRequiresComptime(enum_type.tag_ty.toType()),
-
- // values, not types
- .undef,
- .runtime_value,
- .simple_value,
- .variable,
- .extern_func,
- .func,
- .int,
- .err,
- .error_union,
- .enum_literal,
- .enum_tag,
- .empty_enum_value,
- .float,
- .ptr,
- .opt,
- .aggregate,
- .un,
- // memoization, not types
- .memoized_call,
- => unreachable,
- },
- };
+ return ty.comptimeOnlyAdvanced(sema.mod, sema);
}
pub fn typeHasRuntimeBits(sema: *Sema, ty: Type) CompileError!bool {
@@ -37316,21 +37140,8 @@ fn structFieldAlignment(
return ty_abi_align;
}
-/// Synchronize logic with `Type.isFnOrHasRuntimeBits`.
pub fn fnHasRuntimeBits(sema: *Sema, ty: Type) CompileError!bool {
- const mod = sema.mod;
- const fn_info = mod.typeToFunc(ty).?;
- if (fn_info.is_generic) return false;
- if (fn_info.is_var_args) return true;
- switch (fn_info.cc) {
- // If there was a comptime calling convention, it should also return false here.
- .Inline => return false,
- else => {},
- }
- if (try sema.typeRequiresComptime(fn_info.return_type.toType())) {
- return false;
- }
- return true;
+ return ty.fnHasRuntimeBitsAdvanced(sema.mod, sema);
}
fn unionFieldIndex(
src/type.zig
@@ -771,21 +771,25 @@ pub const Type = struct {
return hasRuntimeBitsAdvanced(ty, mod, true, .eager) catch unreachable;
}
+ pub fn fnHasRuntimeBits(ty: Type, mod: *Module) bool {
+ return ty.fnHasRuntimeBitsAdvanced(mod, null) catch unreachable;
+ }
+
+ /// Determines whether a function type has runtime bits, i.e. whether a
+ /// function with this type can exist at runtime.
+ /// Asserts that `ty` is a function type.
+ /// If `opt_sema` is not provided, asserts that the return type is sufficiently resolved.
+ pub fn fnHasRuntimeBitsAdvanced(ty: Type, mod: *Module, opt_sema: ?*Sema) Module.CompileError!bool {
+ const fn_info = mod.typeToFunc(ty).?;
+ if (fn_info.is_generic) return false;
+ if (fn_info.is_var_args) return true;
+ if (fn_info.cc == .Inline) return false;
+ return !try fn_info.return_type.toType().comptimeOnlyAdvanced(mod, opt_sema);
+ }
+
pub fn isFnOrHasRuntimeBits(ty: Type, mod: *Module) bool {
switch (ty.zigTypeTag(mod)) {
- .Fn => {
- const fn_info = mod.typeToFunc(ty).?;
- if (fn_info.is_generic) return false;
- if (fn_info.is_var_args) return true;
- switch (fn_info.cc) {
- // If there was a comptime calling convention,
- // it should also return false here.
- .Inline => return false,
- else => {},
- }
- if (fn_info.return_type.toType().comptimeOnly(mod)) return false;
- return true;
- },
+ .Fn => return ty.fnHasRuntimeBits(mod),
else => return ty.hasRuntimeBits(mod),
}
}
@@ -2575,9 +2579,14 @@ pub const Type = struct {
/// During semantic analysis, instead call `Sema.typeRequiresComptime` which
/// resolves field types rather than asserting they are already resolved.
- /// TODO merge these implementations together with the "advanced" pattern seen
- /// elsewhere in this file.
pub fn comptimeOnly(ty: Type, mod: *Module) bool {
+ return ty.comptimeOnlyAdvanced(mod, null) catch unreachable;
+ }
+
+ /// `generic_poison` will return false.
+ /// May return false negatives when structs and unions are having their field types resolved.
+ /// If `opt_sema` is not provided, asserts that the type is sufficiently resolved.
+ pub fn comptimeOnlyAdvanced(ty: Type, mod: *Module, opt_sema: ?*Sema) Module.CompileError!bool {
const ip = &mod.intern_pool;
return switch (ty.toIntern()) {
.empty_struct_type => false,
@@ -2587,19 +2596,19 @@ pub const Type = struct {
.ptr_type => |ptr_type| {
const child_ty = ptr_type.child.toType();
switch (child_ty.zigTypeTag(mod)) {
- .Fn => return !child_ty.isFnOrHasRuntimeBits(mod),
+ .Fn => return !try child_ty.fnHasRuntimeBitsAdvanced(mod, opt_sema),
.Opaque => return false,
- else => return child_ty.comptimeOnly(mod),
+ else => return child_ty.comptimeOnlyAdvanced(mod, opt_sema),
}
},
.anyframe_type => |child| {
if (child == .none) return false;
- return child.toType().comptimeOnly(mod);
+ return child.toType().comptimeOnlyAdvanced(mod, opt_sema);
},
- .array_type => |array_type| array_type.child.toType().comptimeOnly(mod),
- .vector_type => |vector_type| vector_type.child.toType().comptimeOnly(mod),
- .opt_type => |child| child.toType().comptimeOnly(mod),
- .error_union_type => |error_union_type| error_union_type.payload_type.toType().comptimeOnly(mod),
+ .array_type => |array_type| return array_type.child.toType().comptimeOnlyAdvanced(mod, opt_sema),
+ .vector_type => |vector_type| return vector_type.child.toType().comptimeOnlyAdvanced(mod, opt_sema),
+ .opt_type => |child| return child.toType().comptimeOnlyAdvanced(mod, opt_sema),
+ .error_union_type => |error_union_type| return error_union_type.payload_type.toType().comptimeOnlyAdvanced(mod, opt_sema),
.error_set_type,
.inferred_error_set_type,
@@ -2662,39 +2671,80 @@ pub const Type = struct {
// A struct with no fields is not comptime-only.
return switch (struct_type.flagsPtr(ip).requires_comptime) {
- // Return false to avoid incorrect dependency loops.
- // This will be handled correctly once merged with
- // `Sema.typeRequiresComptime`.
- .wip, .unknown => false,
- .no => false,
+ .no, .wip => false,
.yes => true,
+ .unknown => {
+ // The type is not resolved; assert that we have a Sema.
+ const sema = opt_sema.?;
+
+ if (struct_type.flagsPtr(ip).field_types_wip)
+ return false;
+
+ try sema.resolveTypeFieldsStruct(ty.toIntern(), struct_type);
+
+ struct_type.flagsPtr(ip).requires_comptime = .wip;
+ errdefer struct_type.flagsPtr(ip).requires_comptime = .unknown;
+
+ for (0..struct_type.field_types.len) |i_usize| {
+ const i: u32 = @intCast(i_usize);
+ if (struct_type.fieldIsComptime(ip, i)) continue;
+ const field_ty = struct_type.field_types.get(ip)[i];
+ if (try field_ty.toType().comptimeOnlyAdvanced(mod, opt_sema)) {
+ // Note that this does not cause the layout to
+ // be considered resolved. Comptime-only types
+ // still maintain a layout of their
+ // runtime-known fields.
+ struct_type.flagsPtr(ip).requires_comptime = .yes;
+ return true;
+ }
+ }
+
+ struct_type.flagsPtr(ip).requires_comptime = .no;
+ return false;
+ },
};
},
.anon_struct_type => |tuple| {
for (tuple.types.get(ip), tuple.values.get(ip)) |field_ty, val| {
const have_comptime_val = val != .none;
- if (!have_comptime_val and field_ty.toType().comptimeOnly(mod)) return true;
+ if (!have_comptime_val and try field_ty.toType().comptimeOnlyAdvanced(mod, opt_sema)) return true;
}
return false;
},
- .union_type => |union_type| {
- switch (union_type.flagsPtr(ip).requires_comptime) {
- .wip, .unknown => {
- // Return false to avoid incorrect dependency loops.
- // This will be handled correctly once merged with
- // `Sema.typeRequiresComptime`.
+ .union_type => |union_type| switch (union_type.flagsPtr(ip).requires_comptime) {
+ .no, .wip => false,
+ .yes => true,
+ .unknown => {
+ // The type is not resolved; assert that we have a Sema.
+ const sema = opt_sema.?;
+
+ if (union_type.flagsPtr(ip).status == .field_types_wip)
return false;
- },
- .no => return false,
- .yes => return true,
- }
+
+ try sema.resolveTypeFieldsUnion(ty, union_type);
+ const union_obj = ip.loadUnionType(union_type);
+
+ union_obj.flagsPtr(ip).requires_comptime = .wip;
+ errdefer union_obj.flagsPtr(ip).requires_comptime = .unknown;
+
+ for (0..union_obj.field_types.len) |field_idx| {
+ const field_ty = union_obj.field_types.get(ip)[field_idx];
+ if (try field_ty.toType().comptimeOnlyAdvanced(mod, opt_sema)) {
+ union_obj.flagsPtr(ip).requires_comptime = .yes;
+ return true;
+ }
+ }
+
+ union_obj.flagsPtr(ip).requires_comptime = .no;
+ return false;
+ },
},
.opaque_type => false,
- .enum_type => |enum_type| enum_type.tag_ty.toType().comptimeOnly(mod),
+ .enum_type => |enum_type| return enum_type.tag_ty.toType().comptimeOnlyAdvanced(mod, opt_sema),
// values, not types
.undef,