aboutsummaryrefslogtreecommitdiff
path: root/src/type.zig
diff options
context:
space:
mode:
authorAndrew Kelley <andrew@ziglang.org>2021-08-02 20:35:55 -0700
committerAndrew Kelley <andrew@ziglang.org>2021-08-02 21:56:10 -0700
commit1472dc3ddb6fd7932ff530e7a2fd3f0185c7353f (patch)
tree77c6cae8dbc822e9fc5ec069b9d61d6e769694f8 /src/type.zig
parentb465037a65dd6a31c5865086ec4392a1d3a372bc (diff)
downloadzig-1472dc3ddb6fd7932ff530e7a2fd3f0185c7353f.tar.gz
zig-1472dc3ddb6fd7932ff530e7a2fd3f0185c7353f.zip
stage2: update ZIR for generic functions
ZIR encoding for functions is changed in preparation for generic function support. As an example: ```zig const std = @import("std"); const expect = std.testing.expect; test "example" { var x: usize = 0; x += checkSize(i32, 1); x += checkSize(bool, true); try expect(x == 5); } fn checkSize(comptime T: type, x: T) usize { _ = x; return @sizeOf(T); } ``` Previous ZIR for the `checkSize` function: ```zir [165] checkSize line(10) hash(0226f62e189fd0b1c5fca02cf4617562): %55 = block_inline({ %56 = decl_val("T") token_offset:11:35 %57 = as_node(@Ref.type_type, %56) node_offset:11:35 %69 = extended(func([comptime @Ref.type_type, %57], @Ref.usize_type, { %58 = arg("T") token_offset:11:23 %59 = as_node(@Ref.type_type, %58) node_offset:11:35 %60 = arg("x") token_offset:11:32 %61 = dbg_stmt(11, 4) ``` ZIR for the `checkSize` function after this commit: ```zir [157] checkSize line(10) hash(0226f62e189fd0b1c5fca02cf4617562): %55 = block_inline({ %56 = param_comptime("T", @Ref.type_type) token_offset:11:23 %57 = as_node(@Ref.type_type, %56) node_offset:11:35 %58 = param("x", %57) token_offset:11:32 %67 = func(@Ref.usize_type, { %59 = dbg_stmt(11, 4) ``` Noted differences: * Previously the type expression was redundantly repeated. * Previously the parameter names were redundantly stored in the ZIR extra array. * Instead of `arg` ZIR instructions as the first instructions within a function body, they are now outside the function body, in the same block as the `func` instruction. There are variants: - param - param_comptime - param_anytype - param_anytype_comptime * The param instructions additionally encode the type. * Because of the param instructions, the `func` instruction no longer encodes the list of parameter types or the comptime bits. It's implied that Sema will collect the parameters so that when a `func` instruction is encountered, they will be implicitly used to construct the function's type. This is so that we can satisfy all 3 ways of performing semantic analysis on a function: 1. runtime: Sema will insert AIR arg instructions for each parameter, and insert into the Sema inst_map ZIR param => AIR arg. 2. comptime/inline: Sema will insert into the inst_map ZIR param => callsite arguments. 3. generic: Sema will map *only the comptime* ZIR param instructions to the AIR instructions for the comptime arguments at the callsite, and then re-run Sema for the function's Decl. This will produce a new function which is the monomorphized function. Additionally: * AstGen: Update usage of deprecated `ensureCapacity` to `ensureUnusedCapacity` or `ensureTotalCapacity`. * Introduce `Type.fnInfo` for getting a bunch of data about a function type at once, and use it in `analyzeCall`. This commit starts a branch to implement generic functions in stage2. Test regressions have not been addressed yet.
Diffstat (limited to 'src/type.zig')
-rw-r--r--src/type.zig60
1 files changed, 50 insertions, 10 deletions
diff --git a/src/type.zig b/src/type.zig
index a8c3d77bbb..feb16fd47c 100644
--- a/src/type.zig
+++ b/src/type.zig
@@ -759,12 +759,15 @@ pub const Type = extern union {
for (payload.param_types) |param_type, i| {
param_types[i] = try param_type.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,
.is_var_args = payload.is_var_args,
.is_generic = payload.is_generic,
+ .comptime_params = comptime_params.ptr,
});
},
.pointer => {
@@ -2408,14 +2411,41 @@ pub const Type = extern union {
};
}
- /// Asserts the type is a function.
- pub fn fnIsGeneric(self: Type) bool {
- return switch (self.tag()) {
- .fn_noreturn_no_args => false,
- .fn_void_no_args => false,
- .fn_naked_noreturn_no_args => false,
- .fn_ccc_void_no_args => false,
- .function => self.castTag(.function).?.data.is_generic,
+ pub fn fnInfo(ty: Type) Payload.Function.Data {
+ return switch (ty.tag()) {
+ .fn_noreturn_no_args => .{
+ .param_types = &.{},
+ .comptime_params = undefined,
+ .return_type = initTag(.noreturn),
+ .cc = .Unspecified,
+ .is_var_args = false,
+ .is_generic = false,
+ },
+ .fn_void_no_args => .{
+ .param_types = &.{},
+ .comptime_params = undefined,
+ .return_type = initTag(.void),
+ .cc = .Unspecified,
+ .is_var_args = false,
+ .is_generic = false,
+ },
+ .fn_naked_noreturn_no_args => .{
+ .param_types = &.{},
+ .comptime_params = undefined,
+ .return_type = initTag(.noreturn),
+ .cc = .Naked,
+ .is_var_args = false,
+ .is_generic = false,
+ },
+ .fn_ccc_void_no_args => .{
+ .param_types = &.{},
+ .comptime_params = undefined,
+ .return_type = initTag(.void),
+ .cc = .C,
+ .is_var_args = false,
+ .is_generic = false,
+ },
+ .function => ty.castTag(.function).?.data,
else => unreachable,
};
@@ -3223,13 +3253,23 @@ pub const Type = extern union {
pub const base_tag = Tag.function;
base: Payload = Payload{ .tag = base_tag },
- data: struct {
+ data: Data,
+
+ // TODO look into optimizing this memory to take fewer bytes
+ const Data = struct {
param_types: []Type,
+ comptime_params: [*]bool,
return_type: Type,
cc: std.builtin.CallingConvention,
is_var_args: bool,
is_generic: bool,
- },
+
+ fn paramIsComptime(self: @This(), i: usize) bool {
+ if (!self.is_generic) return false;
+ assert(i < self.param_types.len);
+ return self.comptime_params[i];
+ }
+ };
};
pub const ErrorSet = struct {