diff options
| author | Andrew Kelley <andrew@ziglang.org> | 2021-08-02 20:35:55 -0700 |
|---|---|---|
| committer | Andrew Kelley <andrew@ziglang.org> | 2021-08-02 21:56:10 -0700 |
| commit | 1472dc3ddb6fd7932ff530e7a2fd3f0185c7353f (patch) | |
| tree | 77c6cae8dbc822e9fc5ec069b9d61d6e769694f8 /src/type.zig | |
| parent | b465037a65dd6a31c5865086ec4392a1d3a372bc (diff) | |
| download | zig-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.zig | 60 |
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 { |
