diff options
| author | Andrew Kelley <andrew@ziglang.org> | 2020-12-31 01:54:02 -0700 |
|---|---|---|
| committer | Andrew Kelley <andrew@ziglang.org> | 2020-12-31 01:54:02 -0700 |
| commit | a46d24af1cf2885991c67bf39a2e639891c16121 (patch) | |
| tree | d4f3c81b798cbae420819434c810a52b6817a85b /src/type.zig | |
| parent | 3f7d9b5fc19e4081236b3b63aebbc80e1b17f5b5 (diff) | |
| download | zig-a46d24af1cf2885991c67bf39a2e639891c16121.tar.gz zig-a46d24af1cf2885991c67bf39a2e639891c16121.zip | |
stage2: inferred local variables
This patch introduces the following new things:
Types:
- inferred_alloc
- This is a special value that tracks a set of types that have been stored
to an inferred allocation. It does not support most of the normal type queries.
However it does respond to `isConstPtr`, `ptrSize`, `zigTypeTag`, etc.
- The payload for this type simply points to the corresponding Value
payload.
Values:
- inferred_alloc
- This is a special value that tracks a set of types that have been stored
to an inferred allocation. It does not support any of the normal value queries.
ZIR instructions:
- store_to_inferred_ptr,
- Same as `store` but the type of the value being stored will be used to infer
the pointer type.
- resolve_inferred_alloc
- Each `store_to_inferred_ptr` puts the type of the stored value into a set,
and then `resolve_inferred_alloc` triggers peer type resolution on the set.
The operand is a `alloc_inferred` or `alloc_inferred_mut` instruction, which
is the allocation that needs to have its type inferred.
Changes to the C backend:
* Implements the bitcast instruction. If the source and dest types
are both pointers, uses a cast, otherwise uses memcpy.
* Tests are run with -Wno-declaration-after-statement. Someday we can
conform to this but not today.
In ZIR form it looks like this:
```zir
fn_body main { // unanalyzed
%0 = dbg_stmt()
=>%1 = alloc_inferred()
%2 = declval_in_module(Decl(add))
%3 = deref(%2)
%4 = param_type(%3, 0)
%5 = const(TypedValue{ .ty = comptime_int, .val = 1})
%6 = as(%4, %5)
%7 = param_type(%3, 1)
%8 = const(TypedValue{ .ty = comptime_int, .val = 2})
%9 = as(%7, %8)
%10 = call(%3, [%6, %9], modifier=auto)
=>%11 = store_to_inferred_ptr(%1, %10)
=>%12 = resolve_inferred_alloc(%1)
%13 = dbg_stmt()
%14 = ret_type()
%15 = const(TypedValue{ .ty = comptime_int, .val = 3})
%16 = sub(%10, %15)
%17 = as(%14, %16)
%18 = return(%17)
} // fn_body main
```
I have not played around with very many test cases yet. Some interesting
ones that I want to look at before merging:
```zig
var x = blk: {
var y = foo();
y.a = 1;
break :blk y;
};
```
In the above test case, x and y are supposed to alias.
```zig
var x = if (bar()) blk: {
var y = foo();
y.a = 1;
break :blk y;
} else blk: {
var z = baz();
z.b = 1;
break :blk z;
};
```
In the above test case, x, y, and z are supposed to alias.
I also haven't tested with `var` instead of `const` yet.
Diffstat (limited to 'src/type.zig')
| -rw-r--r-- | src/type.zig | 148 |
1 files changed, 96 insertions, 52 deletions
diff --git a/src/type.zig b/src/type.zig index 9d834a19f2..ea21be0e68 100644 --- a/src/type.zig +++ b/src/type.zig @@ -78,6 +78,7 @@ pub const Type = extern union { .const_slice, .mut_slice, .pointer, + .inferred_alloc, => return .Pointer, .optional, @@ -158,6 +159,8 @@ pub const Type = extern union { .optional_single_mut_pointer, => self.cast(Payload.ElemType), + .inferred_alloc => unreachable, + else => null, }; } @@ -384,6 +387,7 @@ pub const Type = extern union { .enum_literal, .anyerror_void_error_union, .@"anyframe", + .inferred_alloc, => unreachable, .array_u8, @@ -686,6 +690,7 @@ pub const Type = extern union { const name = ty.castTag(.error_set_single).?.data; return out_stream.print("error{{{s}}}", .{name}); }, + .inferred_alloc => return out_stream.writeAll("(inferred allocation type)"), } unreachable; } @@ -733,6 +738,7 @@ pub const Type = extern union { .single_const_pointer_to_comptime_int => return Value.initTag(.single_const_pointer_to_comptime_int_type), .const_slice_u8 => return Value.initTag(.const_slice_u8_type), .enum_literal => return Value.initTag(.enum_literal_type), + .inferred_alloc => unreachable, else => return Value.Tag.ty.create(allocator, self), } } @@ -803,6 +809,8 @@ pub const Type = extern union { .enum_literal, .empty_struct, => false, + + .inferred_alloc => unreachable, }; } @@ -920,6 +928,7 @@ pub const Type = extern union { .@"undefined", .enum_literal, .empty_struct, + .inferred_alloc, => unreachable, }; } @@ -943,6 +952,7 @@ pub const Type = extern union { .enum_literal => unreachable, .single_const_pointer_to_comptime_int => unreachable, .empty_struct => unreachable, + .inferred_alloc => unreachable, .u8, .i8, @@ -1121,6 +1131,7 @@ pub const Type = extern union { .single_const_pointer, .single_mut_pointer, .single_const_pointer_to_comptime_int, + .inferred_alloc, => true, .pointer => self.castTag(.pointer).?.data.size == .One, @@ -1203,6 +1214,7 @@ pub const Type = extern union { .single_const_pointer, .single_mut_pointer, .single_const_pointer_to_comptime_int, + .inferred_alloc, => .One, .pointer => self.castTag(.pointer).?.data.size, @@ -1273,6 +1285,7 @@ pub const Type = extern union { .error_set, .error_set_single, .empty_struct, + .inferred_alloc, => false, .const_slice, @@ -1345,6 +1358,7 @@ pub const Type = extern union { .error_set, .error_set_single, .empty_struct, + .inferred_alloc, => false, .single_const_pointer, @@ -1426,6 +1440,7 @@ pub const Type = extern union { .error_set, .error_set_single, .empty_struct, + .inferred_alloc, => false, .pointer => { @@ -1502,6 +1517,7 @@ pub const Type = extern union { .error_set, .error_set_single, .empty_struct, + .inferred_alloc, => false, .pointer => { @@ -1569,58 +1585,58 @@ pub const Type = extern union { /// Asserts the type is a pointer or array type. pub fn elemType(self: Type) Type { return switch (self.tag()) { - .u8, - .i8, - .u16, - .i16, - .u32, - .i32, - .u64, - .i64, - .usize, - .isize, - .c_short, - .c_ushort, - .c_int, - .c_uint, - .c_long, - .c_ulong, - .c_longlong, - .c_ulonglong, - .c_longdouble, - .f16, - .f32, - .f64, - .f128, - .c_void, - .bool, - .void, - .type, - .anyerror, - .comptime_int, - .comptime_float, - .noreturn, - .@"null", - .@"undefined", - .fn_noreturn_no_args, - .fn_void_no_args, - .fn_naked_noreturn_no_args, - .fn_ccc_void_no_args, - .function, - .int_unsigned, - .int_signed, - .optional, - .optional_single_const_pointer, - .optional_single_mut_pointer, - .enum_literal, - .error_union, - .@"anyframe", - .anyframe_T, - .anyerror_void_error_union, - .error_set, - .error_set_single, - .empty_struct, - => unreachable, + .u8 => unreachable, + .i8 => unreachable, + .u16 => unreachable, + .i16 => unreachable, + .u32 => unreachable, + .i32 => unreachable, + .u64 => unreachable, + .i64 => unreachable, + .usize => unreachable, + .isize => unreachable, + .c_short => unreachable, + .c_ushort => unreachable, + .c_int => unreachable, + .c_uint => unreachable, + .c_long => unreachable, + .c_ulong => unreachable, + .c_longlong => unreachable, + .c_ulonglong => unreachable, + .c_longdouble => unreachable, + .f16 => unreachable, + .f32 => unreachable, + .f64 => unreachable, + .f128 => unreachable, + .c_void => unreachable, + .bool => unreachable, + .void => unreachable, + .type => unreachable, + .anyerror => unreachable, + .comptime_int => unreachable, + .comptime_float => unreachable, + .noreturn => unreachable, + .@"null" => unreachable, + .@"undefined" => unreachable, + .fn_noreturn_no_args => unreachable, + .fn_void_no_args => unreachable, + .fn_naked_noreturn_no_args => unreachable, + .fn_ccc_void_no_args => unreachable, + .function => unreachable, + .int_unsigned => unreachable, + .int_signed => unreachable, + .optional => unreachable, + .optional_single_const_pointer => unreachable, + .optional_single_mut_pointer => unreachable, + .enum_literal => unreachable, + .error_union => unreachable, + .@"anyframe" => unreachable, + .anyframe_T => unreachable, + .anyerror_void_error_union => unreachable, + .error_set => unreachable, + .error_set_single => unreachable, + .empty_struct => unreachable, + .inferred_alloc => unreachable, .array => self.castTag(.array).?.data.elem_type, .array_sentinel => self.castTag(.array_sentinel).?.data.elem_type, @@ -1742,6 +1758,7 @@ pub const Type = extern union { .error_set, .error_set_single, .empty_struct, + .inferred_alloc, => unreachable, .array => self.castTag(.array).?.data.len, @@ -1808,6 +1825,7 @@ pub const Type = extern union { .error_set, .error_set_single, .empty_struct, + .inferred_alloc, => unreachable, .single_const_pointer, @@ -1891,6 +1909,7 @@ pub const Type = extern union { .error_set, .error_set_single, .empty_struct, + .inferred_alloc, => false, .int_signed, @@ -1966,6 +1985,7 @@ pub const Type = extern union { .error_set, .error_set_single, .empty_struct, + .inferred_alloc, => false, .int_unsigned, @@ -2031,6 +2051,7 @@ pub const Type = extern union { .error_set, .error_set_single, .empty_struct, + .inferred_alloc, => unreachable, .int_unsigned => .{ @@ -2120,6 +2141,7 @@ pub const Type = extern union { .error_set, .error_set_single, .empty_struct, + .inferred_alloc, => false, .usize, @@ -2232,6 +2254,7 @@ pub const Type = extern union { .error_set, .error_set_single, .empty_struct, + .inferred_alloc, => unreachable, }; } @@ -2310,6 +2333,7 @@ pub const Type = extern union { .error_set, .error_set_single, .empty_struct, + .inferred_alloc, => unreachable, } } @@ -2387,6 +2411,7 @@ pub const Type = extern union { .error_set, .error_set_single, .empty_struct, + .inferred_alloc, => unreachable, } } @@ -2464,6 +2489,7 @@ pub const Type = extern union { .error_set, .error_set_single, .empty_struct, + .inferred_alloc, => unreachable, }; } @@ -2538,6 +2564,7 @@ pub const Type = extern union { .error_set, .error_set_single, .empty_struct, + .inferred_alloc, => unreachable, }; } @@ -2612,6 +2639,7 @@ pub const Type = extern union { .error_set, .error_set_single, .empty_struct, + .inferred_alloc, => unreachable, }; } @@ -2686,6 +2714,7 @@ pub const Type = extern union { .error_set, .error_set_single, .empty_struct, + .inferred_alloc, => false, }; } @@ -2778,6 +2807,7 @@ pub const Type = extern union { ty = ty.castTag(.pointer).?.data.pointee_type; continue; }, + .inferred_alloc => unreachable, }; } @@ -2846,6 +2876,7 @@ pub const Type = extern union { .error_set, .error_set_single, .empty_struct, + .inferred_alloc, => return false, .c_const_pointer, @@ -2931,6 +2962,7 @@ pub const Type = extern union { .c_const_pointer, .c_mut_pointer, .pointer, + .inferred_alloc, => unreachable, .empty_struct => self.castTag(.empty_struct).?.data, @@ -3068,6 +3100,10 @@ pub const Type = extern union { error_set, error_set_single, empty_struct, + /// This is a special value that tracks a set of types that have been stored + /// to an inferred allocation. It does not support most of the normal type queries. + /// However it does respond to `isConstPtr`, `ptrSize`, `zigTypeTag`, etc. + inferred_alloc, pub const last_no_payload_tag = Tag.const_slice_u8; pub const no_payload_count = @enumToInt(last_no_payload_tag) + 1; @@ -3148,6 +3184,7 @@ pub const Type = extern union { .error_set => Payload.Decl, .error_set_single => Payload.Name, .empty_struct => Payload.ContainerScope, + .inferred_alloc => Payload.InferredAlloc, }; } @@ -3261,6 +3298,13 @@ pub const Type = extern union { base: Payload, data: *Module.Scope.Container, }; + + pub const InferredAlloc = struct { + pub const base_tag = Tag.inferred_alloc; + + base: Payload = .{ .tag = base_tag }, + data: *Value.Payload.InferredAlloc, + }; }; }; |
