aboutsummaryrefslogtreecommitdiff
path: root/src/type.zig
diff options
context:
space:
mode:
authorAndrew Kelley <andrew@ziglang.org>2023-05-15 20:09:54 -0700
committerAndrew Kelley <andrew@ziglang.org>2023-06-10 20:47:53 -0700
commit17882162b3be5542b4e289e5ddc6535a4bb4c6b1 (patch)
tree678a9762bd5894e487ff808562eba690918c23ba /src/type.zig
parent6a9a918fbe4adc23dd7d7573c6f1e499f4be074e (diff)
downloadzig-17882162b3be5542b4e289e5ddc6535a4bb4c6b1.tar.gz
zig-17882162b3be5542b4e289e5ddc6535a4bb4c6b1.zip
stage2: move function types to InternPool
Diffstat (limited to 'src/type.zig')
-rw-r--r--src/type.zig392
1 files changed, 110 insertions, 282 deletions
diff --git a/src/type.zig b/src/type.zig
index 32fa64a1ac..daf8b305cc 100644
--- a/src/type.zig
+++ b/src/type.zig
@@ -42,8 +42,6 @@ pub const Type = struct {
.error_set_merged,
=> return .ErrorSet,
- .function => return .Fn,
-
.pointer,
.inferred_alloc_const,
.inferred_alloc_mut,
@@ -66,6 +64,7 @@ pub const Type = struct {
.union_type => return .Union,
.opaque_type => return .Opaque,
.enum_type => return .Enum,
+ .func_type => return .Fn,
.simple_type => |s| switch (s) {
.f16,
.f32,
@@ -344,53 +343,6 @@ pub const Type = struct {
return true;
},
- .function => {
- if (b.zigTypeTag(mod) != .Fn) return false;
-
- const a_info = a.fnInfo();
- const b_info = b.fnInfo();
-
- if (!a_info.return_type.isGenericPoison() and
- !b_info.return_type.isGenericPoison() and
- !eql(a_info.return_type, b_info.return_type, mod))
- return false;
-
- if (a_info.is_var_args != b_info.is_var_args)
- return false;
-
- if (a_info.is_generic != b_info.is_generic)
- return false;
-
- if (a_info.is_noinline != b_info.is_noinline)
- return false;
-
- if (a_info.noalias_bits != b_info.noalias_bits)
- return false;
-
- if (!a_info.cc_is_generic and a_info.cc != b_info.cc)
- return false;
-
- if (!a_info.align_is_generic and a_info.alignment != b_info.alignment)
- return false;
-
- if (a_info.param_types.len != b_info.param_types.len)
- return false;
-
- for (a_info.param_types, 0..) |a_param_ty, i| {
- const b_param_ty = b_info.param_types[i];
- if (a_info.comptime_params[i] != b_info.comptime_params[i])
- return false;
-
- if (a_param_ty.isGenericPoison()) continue;
- if (b_param_ty.isGenericPoison()) continue;
-
- if (!eql(a_param_ty, b_param_ty, mod))
- return false;
- }
-
- return true;
- },
-
.pointer,
.inferred_alloc_const,
.inferred_alloc_mut,
@@ -501,32 +453,6 @@ pub const Type = struct {
std.hash.autoHash(hasher, ies);
},
- .function => {
- std.hash.autoHash(hasher, std.builtin.TypeId.Fn);
-
- const fn_info = ty.fnInfo();
- if (!fn_info.return_type.isGenericPoison()) {
- hashWithHasher(fn_info.return_type, hasher, mod);
- }
- if (!fn_info.align_is_generic) {
- std.hash.autoHash(hasher, fn_info.alignment);
- }
- if (!fn_info.cc_is_generic) {
- std.hash.autoHash(hasher, fn_info.cc);
- }
- std.hash.autoHash(hasher, fn_info.is_var_args);
- std.hash.autoHash(hasher, fn_info.is_generic);
- std.hash.autoHash(hasher, fn_info.is_noinline);
- std.hash.autoHash(hasher, fn_info.noalias_bits);
-
- std.hash.autoHash(hasher, fn_info.param_types.len);
- for (fn_info.param_types, 0..) |param_ty, i| {
- std.hash.autoHash(hasher, fn_info.paramIsComptime(i));
- if (param_ty.isGenericPoison()) continue;
- hashWithHasher(param_ty, hasher, mod);
- }
- },
-
.pointer,
.inferred_alloc_const,
.inferred_alloc_mut,
@@ -631,30 +557,6 @@ pub const Type = struct {
};
},
- .function => {
- const payload = self.castTag(.function).?.data;
- const param_types = try allocator.alloc(Type, payload.param_types.len);
- for (payload.param_types, 0..) |param_ty, i| {
- param_types[i] = try param_ty.copy(allocator);
- }
- const other_comptime_params = payload.comptime_params[0..payload.param_types.len];
- const comptime_params = try allocator.dupe(bool, other_comptime_params);
- return Tag.function.create(allocator, .{
- .return_type = try payload.return_type.copy(allocator),
- .param_types = param_types,
- .cc = payload.cc,
- .alignment = payload.alignment,
- .is_var_args = payload.is_var_args,
- .is_generic = payload.is_generic,
- .is_noinline = payload.is_noinline,
- .comptime_params = comptime_params.ptr,
- .align_is_generic = payload.align_is_generic,
- .cc_is_generic = payload.cc_is_generic,
- .section_is_generic = payload.section_is_generic,
- .addrspace_is_generic = payload.addrspace_is_generic,
- .noalias_bits = payload.noalias_bits,
- });
- },
.pointer => {
const payload = self.castTag(.pointer).?.data;
const sent: ?Value = if (payload.sentinel) |some|
@@ -766,32 +668,6 @@ pub const Type = struct {
while (true) {
const t = ty.tag();
switch (t) {
- .function => {
- const payload = ty.castTag(.function).?.data;
- try writer.writeAll("fn(");
- for (payload.param_types, 0..) |param_type, i| {
- if (i != 0) try writer.writeAll(", ");
- try param_type.dump("", .{}, writer);
- }
- if (payload.is_var_args) {
- if (payload.param_types.len != 0) {
- try writer.writeAll(", ");
- }
- try writer.writeAll("...");
- }
- try writer.writeAll(") ");
- if (payload.alignment != 0) {
- try writer.print("align({d}) ", .{payload.alignment});
- }
- if (payload.cc != .Unspecified) {
- try writer.writeAll("callconv(.");
- try writer.writeAll(@tagName(payload.cc));
- try writer.writeAll(") ");
- }
- ty = payload.return_type;
- continue;
- },
-
.anyframe_T => {
const return_type = ty.castTag(.anyframe_T).?.data;
try writer.print("anyframe->", .{});
@@ -909,48 +785,6 @@ pub const Type = struct {
try writer.writeAll(")).Fn.return_type.?).ErrorUnion.error_set");
},
- .function => {
- const fn_info = ty.fnInfo();
- if (fn_info.is_noinline) {
- try writer.writeAll("noinline ");
- }
- try writer.writeAll("fn(");
- for (fn_info.param_types, 0..) |param_ty, i| {
- if (i != 0) try writer.writeAll(", ");
- if (fn_info.paramIsComptime(i)) {
- try writer.writeAll("comptime ");
- }
- if (std.math.cast(u5, i)) |index| if (@truncate(u1, fn_info.noalias_bits >> index) != 0) {
- try writer.writeAll("noalias ");
- };
- if (param_ty.isGenericPoison()) {
- try writer.writeAll("anytype");
- } else {
- try print(param_ty, writer, mod);
- }
- }
- if (fn_info.is_var_args) {
- if (fn_info.param_types.len != 0) {
- try writer.writeAll(", ");
- }
- try writer.writeAll("...");
- }
- try writer.writeAll(") ");
- if (fn_info.alignment != 0) {
- try writer.print("align({d}) ", .{fn_info.alignment});
- }
- if (fn_info.cc != .Unspecified) {
- try writer.writeAll("callconv(.");
- try writer.writeAll(@tagName(fn_info.cc));
- try writer.writeAll(") ");
- }
- if (fn_info.return_type.isGenericPoison()) {
- try writer.writeAll("anytype");
- } else {
- try print(fn_info.return_type, writer, mod);
- }
- },
-
.error_union => {
const error_union = ty.castTag(.error_union).?.data;
try print(error_union.error_set, writer, mod);
@@ -1158,6 +992,48 @@ pub const Type = struct {
const decl = mod.declPtr(enum_type.decl);
try decl.renderFullyQualifiedName(mod, writer);
},
+ .func_type => |fn_info| {
+ if (fn_info.is_noinline) {
+ try writer.writeAll("noinline ");
+ }
+ try writer.writeAll("fn(");
+ for (fn_info.param_types, 0..) |param_ty, i| {
+ if (i != 0) try writer.writeAll(", ");
+ if (std.math.cast(u5, i)) |index| {
+ if (fn_info.paramIsComptime(index)) {
+ try writer.writeAll("comptime ");
+ }
+ if (fn_info.paramIsNoalias(index)) {
+ try writer.writeAll("noalias ");
+ }
+ }
+ if (param_ty == .generic_poison_type) {
+ try writer.writeAll("anytype");
+ } else {
+ try print(param_ty.toType(), writer, mod);
+ }
+ }
+ if (fn_info.is_var_args) {
+ if (fn_info.param_types.len != 0) {
+ try writer.writeAll(", ");
+ }
+ try writer.writeAll("...");
+ }
+ try writer.writeAll(") ");
+ if (fn_info.alignment != 0) {
+ try writer.print("align({d}) ", .{fn_info.alignment});
+ }
+ if (fn_info.cc != .Unspecified) {
+ try writer.writeAll("callconv(.");
+ try writer.writeAll(@tagName(fn_info.cc));
+ try writer.writeAll(") ");
+ }
+ if (fn_info.return_type == .generic_poison_type) {
+ try writer.writeAll("anytype");
+ } else {
+ try print(fn_info.return_type.toType(), writer, mod);
+ }
+ },
// values, not types
.undef => unreachable,
@@ -1174,6 +1050,11 @@ pub const Type = struct {
}
}
+ pub fn toIntern(ty: Type) InternPool.Index {
+ assert(ty.ip_index != .none);
+ return ty.ip_index;
+ }
+
pub fn toValue(self: Type, allocator: Allocator) Allocator.Error!Value {
if (self.ip_index != .none) return self.ip_index.toValue();
switch (self.tag()) {
@@ -1223,7 +1104,7 @@ pub const Type = struct {
if (ignore_comptime_only) {
return true;
} else if (ty.childType(mod).zigTypeTag(mod) == .Fn) {
- return !ty.childType(mod).fnInfo().is_generic;
+ return !mod.typeToFunc(ty.childType(mod)).?.is_generic;
} else if (strat == .sema) {
return !(try strat.sema.typeRequiresComptime(ty));
} else {
@@ -1231,12 +1112,6 @@ pub const Type = struct {
}
},
- // These are false because they are comptime-only types.
- // These are function *bodies*, not pointers.
- // Special exceptions have to be made when emitting functions due to
- // this returning false.
- .function => return false,
-
.optional => {
const child_ty = ty.optionalChild(mod);
if (child_ty.isNoReturn()) {
@@ -1262,7 +1137,7 @@ pub const Type = struct {
// to comptime-only types do not, with the exception of function pointers.
if (ignore_comptime_only) return true;
const child_ty = ptr_type.elem_type.toType();
- if (child_ty.zigTypeTag(mod) == .Fn) return !child_ty.fnInfo().is_generic;
+ if (child_ty.zigTypeTag(mod) == .Fn) return !mod.typeToFunc(child_ty).?.is_generic;
if (strat == .sema) return !(try strat.sema.typeRequiresComptime(ty));
return !comptimeOnly(ty, mod);
},
@@ -1293,6 +1168,13 @@ pub const Type = struct {
}
},
.error_union_type => @panic("TODO"),
+
+ // These are function *bodies*, not pointers.
+ // They return false here because they are comptime-only types.
+ // Special exceptions have to be made when emitting functions due to
+ // this returning false.
+ .func_type => false,
+
.simple_type => |t| switch (t) {
.f16,
.f32,
@@ -1436,8 +1318,6 @@ pub const Type = struct {
.error_set_single,
.error_set_inferred,
.error_set_merged,
- // These are function bodies, not function pointers.
- .function,
.error_union,
.anyframe_T,
=> false,
@@ -1448,12 +1328,21 @@ pub const Type = struct {
.optional => ty.isPtrLikeOptional(mod),
},
else => switch (mod.intern_pool.indexToKey(ty.ip_index)) {
- .int_type => true,
- .ptr_type => true,
+ .int_type,
+ .ptr_type,
+ .vector_type,
+ => true,
+
+ .error_union_type,
+ .anon_struct_type,
+ .opaque_type,
+ // These are function bodies, not function pointers.
+ .func_type,
+ => false,
+
.array_type => |array_type| array_type.child.toType().hasWellDefinedLayout(mod),
- .vector_type => true,
.opt_type => |child| child.toType().isPtrLikeOptional(mod),
- .error_union_type => false,
+
.simple_type => |t| switch (t) {
.f16,
.f32,
@@ -1509,12 +1398,10 @@ pub const Type = struct {
};
return struct_obj.layout != .Auto;
},
- .anon_struct_type => false,
.union_type => |union_type| switch (union_type.runtime_tag) {
.none, .safety => mod.unionPtr(union_type.index).layout != .Auto,
.tagged => false,
},
- .opaque_type => false,
.enum_type => |enum_type| switch (enum_type.tag_mode) {
.auto => false,
.explicit, .nonexhaustive => true,
@@ -1546,7 +1433,7 @@ pub const Type = struct {
pub fn isFnOrHasRuntimeBits(ty: Type, mod: *Module) bool {
switch (ty.zigTypeTag(mod)) {
.Fn => {
- const fn_info = ty.fnInfo();
+ 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) {
@@ -1555,7 +1442,7 @@ pub const Type = struct {
.Inline => return false,
else => {},
}
- if (fn_info.return_type.comptimeOnly(mod)) return false;
+ if (fn_info.return_type.toType().comptimeOnly(mod)) return false;
return true;
},
else => return ty.hasRuntimeBits(mod),
@@ -1707,13 +1594,6 @@ pub const Type = struct {
switch (ty.ip_index) {
.empty_struct_type => return AbiAlignmentAdvanced{ .scalar = 0 },
.none => switch (ty.tag()) {
- // represents machine code; not a pointer
- .function => {
- const alignment = ty.castTag(.function).?.data.alignment;
- if (alignment != 0) return AbiAlignmentAdvanced{ .scalar = alignment };
- return AbiAlignmentAdvanced{ .scalar = target_util.defaultFunctionAlignment(target) };
- },
-
.pointer,
.anyframe_T,
=> return AbiAlignmentAdvanced{ .scalar = @divExact(target.ptrBitWidth(), 8) },
@@ -1753,6 +1633,13 @@ pub const Type = struct {
.opt_type => return abiAlignmentAdvancedOptional(ty, mod, strat),
.error_union_type => return abiAlignmentAdvancedErrorUnion(ty, mod, strat),
+ // represents machine code; not a pointer
+ .func_type => |func_type| {
+ const alignment = @intCast(u32, func_type.alignment);
+ if (alignment != 0) return AbiAlignmentAdvanced{ .scalar = alignment };
+ return AbiAlignmentAdvanced{ .scalar = target_util.defaultFunctionAlignment(target) };
+ },
+
.simple_type => |t| switch (t) {
.bool,
.atomic_order,
@@ -2086,7 +1973,6 @@ pub const Type = struct {
.empty_struct_type => return AbiSizeAdvanced{ .scalar = 0 },
.none => switch (ty.tag()) {
- .function => unreachable, // represents machine code; not a pointer
.inferred_alloc_const => unreachable,
.inferred_alloc_mut => unreachable,
@@ -2187,6 +2073,7 @@ pub const Type = struct {
.opt_type => return ty.abiSizeAdvancedOptional(mod, strat),
.error_union_type => @panic("TODO"),
+ .func_type => unreachable, // represents machine code; not a pointer
.simple_type => |t| switch (t) {
.bool,
.atomic_order,
@@ -2408,7 +2295,6 @@ pub const Type = struct {
switch (ty.ip_index) {
.none => switch (ty.tag()) {
- .function => unreachable, // represents machine code; not a pointer
.inferred_alloc_const => unreachable,
.inferred_alloc_mut => unreachable,
@@ -2453,6 +2339,7 @@ pub const Type = struct {
},
.opt_type => @panic("TODO"),
.error_union_type => @panic("TODO"),
+ .func_type => unreachable, // represents machine code; not a pointer
.simple_type => |t| switch (t) {
.f16 => return 16,
.f32 => return 32,
@@ -3271,6 +3158,7 @@ pub const Type = struct {
.opt_type => unreachable,
.error_union_type => unreachable,
+ .func_type => unreachable,
.simple_type => unreachable, // handled via Index enum tag above
.union_type => unreachable,
@@ -3356,54 +3244,22 @@ pub const Type = struct {
};
}
- /// Asserts the type is a function.
- pub fn fnParamLen(self: Type) usize {
- return self.castTag(.function).?.data.param_types.len;
- }
-
- /// Asserts the type is a function. The length of the slice must be at least the length
- /// given by `fnParamLen`.
- pub fn fnParamTypes(self: Type, types: []Type) void {
- const payload = self.castTag(.function).?.data;
- @memcpy(types[0..payload.param_types.len], payload.param_types);
- }
-
- /// Asserts the type is a function.
- pub fn fnParamType(self: Type, index: usize) Type {
- switch (self.tag()) {
- .function => {
- const payload = self.castTag(.function).?.data;
- return payload.param_types[index];
- },
-
- else => unreachable,
- }
- }
-
/// Asserts the type is a function or a function pointer.
- pub fn fnReturnType(ty: Type) Type {
- const fn_ty = switch (ty.tag()) {
- .pointer => ty.castTag(.pointer).?.data.pointee_type,
- .function => ty,
- else => unreachable,
- };
- return fn_ty.castTag(.function).?.data.return_type;
+ pub fn fnReturnType(ty: Type, mod: *Module) Type {
+ return fnReturnTypeIp(ty, mod.intern_pool);
}
- /// Asserts the type is a function.
- pub fn fnCallingConvention(self: Type) std.builtin.CallingConvention {
- return self.castTag(.function).?.data.cc;
+ pub fn fnReturnTypeIp(ty: Type, ip: InternPool) Type {
+ return switch (ip.indexToKey(ty.ip_index)) {
+ .ptr_type => |ptr_type| ip.indexToKey(ptr_type.elem_type).func_type.return_type,
+ .func_type => |func_type| func_type.return_type,
+ else => unreachable,
+ }.toType();
}
/// Asserts the type is a function.
- pub fn fnCallingConventionAllowsZigTypes(target: Target, cc: std.builtin.CallingConvention) bool {
- return switch (cc) {
- .Unspecified, .Async, .Inline => true,
- // For now we want to authorize PTX kernel to use zig objects, even if we end up exposing the ABI.
- // The goal is to experiment with more integrated CPU/GPU code.
- .Kernel => target.cpu.arch == .nvptx or target.cpu.arch == .nvptx64,
- else => false,
- };
+ pub fn fnCallingConvention(ty: Type, mod: *Module) std.builtin.CallingConvention {
+ return mod.intern_pool.indexToKey(ty.ip_index).func_type.cc;
}
pub fn isValidParamType(self: Type, mod: *const Module) bool {
@@ -3421,12 +3277,8 @@ pub const Type = struct {
}
/// Asserts the type is a function.
- pub fn fnIsVarArgs(self: Type) bool {
- return self.castTag(.function).?.data.is_var_args;
- }
-
- pub fn fnInfo(ty: Type) Payload.Function.Data {
- return ty.castTag(.function).?.data;
+ pub fn fnIsVarArgs(ty: Type, mod: *Module) bool {
+ return mod.intern_pool.indexToKey(ty.ip_index).func_type.is_var_args;
}
pub fn isNumeric(ty: Type, mod: *const Module) bool {
@@ -3474,7 +3326,6 @@ pub const Type = struct {
.error_set_single,
.error_set,
.error_set_merged,
- .function,
.error_set_inferred,
.anyframe_T,
.pointer,
@@ -3500,7 +3351,12 @@ pub const Type = struct {
return null;
}
},
- .ptr_type => return null,
+
+ .ptr_type,
+ .error_union_type,
+ .func_type,
+ => return null,
+
.array_type => |array_type| {
if (array_type.len == 0)
return Value.initTag(.empty_array);
@@ -3514,13 +3370,13 @@ pub const Type = struct {
return null;
},
.opt_type => |child| {
- if (child.toType().isNoReturn()) {
- return Value.null;
+ if (child == .noreturn_type) {
+ return try mod.nullValue(ty);
} else {
return null;
}
},
- .error_union_type => return null,
+
.simple_type => |t| switch (t) {
.f16,
.f32,
@@ -3682,9 +3538,6 @@ pub const Type = struct {
.error_set_merged,
=> false,
- // These are function bodies, not function pointers.
- .function => true,
-
.inferred_alloc_mut => unreachable,
.inferred_alloc_const => unreachable,
@@ -3721,6 +3574,9 @@ pub const Type = struct {
.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),
+ // These are function bodies, not function pointers.
+ .func_type => true,
+
.simple_type => |t| switch (t) {
.f16,
.f32,
@@ -4367,6 +4223,10 @@ pub const Type = struct {
return ty.ip_index == .generic_poison_type;
}
+ pub fn isBoundFn(ty: Type) bool {
+ return ty.ip_index == .none and ty.tag() == .bound_fn;
+ }
+
/// This enum does not directly correspond to `std.builtin.TypeId` because
/// it has extra enum tags in it, as a way of using less memory. For example,
/// even though Zig recognizes `*align(10) i32` and `*i32` both as Pointer types
@@ -4383,7 +4243,6 @@ pub const Type = struct {
// After this, the tag requires a payload.
pointer,
- function,
optional,
error_union,
anyframe_T,
@@ -4411,7 +4270,6 @@ pub const Type = struct {
.error_set_merged => Payload.ErrorSetMerged,
.pointer => Payload.Pointer,
- .function => Payload.Function,
.error_union => Payload.ErrorUnion,
.error_set_single => Payload.Name,
};
@@ -4508,36 +4366,6 @@ pub const Type = struct {
data: u16,
};
- pub const Function = struct {
- pub const base_tag = Tag.function;
-
- base: Payload = Payload{ .tag = base_tag },
- data: Data,
-
- // TODO look into optimizing this memory to take fewer bytes
- pub const Data = struct {
- param_types: []Type,
- comptime_params: [*]bool,
- return_type: Type,
- /// If zero use default target function code alignment.
- alignment: u32,
- noalias_bits: u32,
- cc: std.builtin.CallingConvention,
- is_var_args: bool,
- is_generic: bool,
- is_noinline: bool,
- align_is_generic: bool,
- cc_is_generic: bool,
- section_is_generic: bool,
- addrspace_is_generic: bool,
-
- pub fn paramIsComptime(self: @This(), i: usize) bool {
- assert(i < self.param_types.len);
- return self.comptime_params[i];
- }
- };
- };
-
pub const ErrorSet = struct {
pub const base_tag = Tag.error_set;