Skip to content

Commit

Permalink
compiler: preserve result type information through address-of operator
Browse files Browse the repository at this point in the history
This commit introduces the new `ref_coerced_ty` result type into AstGen.
This represents a expression which we want to treat as an lvalue, and
the pointer will be coerced to a given type.

This change gives known result types to many expressions, in particular
struct and array initializations. This allows certain casts to work
which previously required explicitly specifying types via `@as`. It also
eliminates our dependence on anonymous struct types for expressions of
the form `&.{ ... }` - this paves the way for ziglang#16865, and also results
in less Sema magic happening for such initializations, also leading to
potentially better runtime code.

As part of these changes, this commit also implements ziglang#17194 by
disallowing RLS on explicitly-typed struct and array initializations.
Apologies for linking these changes - it seemed rather pointless to try
and separate them, since they both make big changes to struct and array
initializations in AstGen. The rationale for this change can be found in
the proposal - in essence, performing RLS whilst maintaining the
semantics of the intermediary type is a very difficult problem to solve.

This allowed the problematic `coerce_result_ptr` ZIR instruction to be
completely eliminated, which in turn also simplified the logic for
inferred allocations in Sema - thanks to this, we almost break even on
line count!

In doing this, the ZIR instructions surrounding these initializations
have been restructured - some have been added and removed, and others
renamed for clarity (and their semantics changed slightly). In order to
optimize ZIR tag count, the `struct_init_anon_ref` and
`array_init_anon_ref` instructions have been removed in favour of using
`ref` on a standard anonymous value initialization, since these
instructions are now virtually never used.

Lastly, it's worth noting that this commit introduces a slightly strange
source of generic poison types: in the expression `@as(*anyopaque, &x)`,
the sub-expression `x` has a generic poison result type, despite no
generic code being involved. This turns out to be a logical choice,
because we don't know the result type for `x`, and the generic poison
type represents precisely this case, providing the semantics we need.

Resolves: ziglang#16512
Resolves: ziglang#17194
  • Loading branch information
mlugg committed Sep 23, 2023
1 parent 78946a1 commit 0dd18c1
Show file tree
Hide file tree
Showing 22 changed files with 82 additions and 43 deletions.
6 changes: 2 additions & 4 deletions compile_errors/anytype_param_requires_comptime.zig
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,5 @@ pub export fn entry() void {
// backend=stage2
// target=native
//
// :7:14: error: runtime-known argument passed to parameter of comptime-only type
// :9:12: note: declared here
// :4:16: note: struct requires comptime because of this field
// :4:16: note: types are not available at runtime
// :7:25: error: unable to resolve comptime value
// :7:25: note: initializer of comptime only struct must be comptime-known
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,6 @@ export fn entry() void {
// backend=stage2
// target=native
//
// :11:27: error: expected type 'u8', found '?u8'
// :11:27: note: cannot convert optional to payload type
// :11:27: note: consider using '.?', 'orelse', or 'if'
// :11:20: error: expected type 'u8', found '?u8'
// :11:20: note: cannot convert optional to payload type
// :11:20: note: consider using '.?', 'orelse', or 'if'
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
export fn foo() void {
const x: *const anyopaque = &@intCast(123);
_ = x;
}
export fn bar() void {
const x: *const anyopaque = &.{
.x = @intCast(123),
};
_ = x;
}

// error
// backend=stage2
// target=native
//
// :2:34: error: @intCast must have a known result type
// :2:34: note: result type is unknown due to opaque pointer type
// :2:34: note: use @as to provide explicit result type
// :7:14: error: @intCast must have a known result type
// :6:35: note: result type is unknown due to opaque pointer type
// :7:14: note: use @as to provide explicit result type
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,11 @@ export fn c() void {
export fn d() void {
bar(@floatFromInt(123));
}
export fn f() void {
bar(.{
.x = @intCast(123),
});
}

fn bar(_: anytype) void {}

Expand All @@ -18,14 +23,17 @@ fn bar(_: anytype) void {}
// target=native
//
// :2:9: error: @ptrFromInt must have a known result type
// :2:9: note: result type is unknown due to anytype parameter
// :2:8: note: result type is unknown due to anytype parameter
// :2:9: note: use @as to provide explicit result type
// :5:9: error: @ptrCast must have a known result type
// :5:9: note: result type is unknown due to anytype parameter
// :5:8: note: result type is unknown due to anytype parameter
// :5:9: note: use @as to provide explicit result type
// :8:9: error: @intCast must have a known result type
// :8:9: note: result type is unknown due to anytype parameter
// :8:8: note: result type is unknown due to anytype parameter
// :8:9: note: use @as to provide explicit result type
// :11:9: error: @floatFromInt must have a known result type
// :11:9: note: result type is unknown due to anytype parameter
// :11:8: note: result type is unknown due to anytype parameter
// :11:9: note: use @as to provide explicit result type
// :15:14: error: @intCast must have a known result type
// :14:8: note: result type is unknown due to anytype parameter
// :15:14: note: use @as to provide explicit result type
3 changes: 2 additions & 1 deletion compile_errors/for_invalid_ranges.zig
Original file line number Diff line number Diff line change
Expand Up @@ -31,5 +31,6 @@ export fn e() void {
// :2:13: error: expected type 'usize', found '*const [5:0]u8'
// :7:10: error: type 'usize' cannot represent integer value '-1'
// :12:10: error: expected type 'usize', found '*const [5:0]u8'
// :17:13: error: expected type 'usize', found '*const struct{comptime comptime_int = 97, comptime comptime_int = 98, comptime comptime_int = 99}'
// :17:13: error: expected type 'usize', found pointer
// :17:13: note: address-of operator always returns a pointer
// :22:20: error: overflow of integer type 'usize' with value '-1'
9 changes: 5 additions & 4 deletions compile_errors/invalid_store_to_comptime_field.zig
Original file line number Diff line number Diff line change
Expand Up @@ -71,14 +71,15 @@ pub export fn entry8() void {
// target=native
// backend=stage2
//
// :6:19: error: value stored in comptime field does not match the default value of the field
// :14:19: error: value stored in comptime field does not match the default value of the field
// :6:9: error: value stored in comptime field does not match the default value of the field
// :14:9: error: value stored in comptime field does not match the default value of the field
// :19:38: error: value stored in comptime field does not match the default value of the field
// :31:19: error: value stored in comptime field does not match the default value of the field
// :25:29: note: default value set here
// :41:19: error: value stored in comptime field does not match the default value of the field
// :35:29: note: default value set here
// :45:12: error: value stored in comptime field does not match the default value of the field
// :53:25: error: value stored in comptime field does not match the default value of the field
// :66:43: error: value stored in comptime field does not match the default value of the field
// :59:35: error: value stored in comptime field does not match the default value of the field
// :66:36: error: value stored in comptime field does not match the default value of the field
// :59:30: error: value stored in comptime field does not match the default value of the field
// :57:29: note: default value set here
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,4 @@ export fn entry() void {
// backend=llvm
// target=native
//
// :4:30: error: array literal requires address-of operator (&) to coerce to slice type '[][2]f32'
// :4:26: error: array literal requires address-of operator (&) to coerce to slice type '[][2]f32'
4 changes: 3 additions & 1 deletion compile_errors/missing_else_clause.zig
Original file line number Diff line number Diff line change
Expand Up @@ -39,4 +39,6 @@ export fn entry() void {
// :8:25: note: type 'i32' here
// :16:16: error: expected type 'tmp.h.T', found 'void'
// :15:15: note: struct declared here
// :22:9: error: incompatible types: 'void' and 'tmp.k.T'
// :22:13: error: incompatible types: 'void' and 'tmp.k.T'
// :22:25: note: type 'void' here
// :24:13: note: type 'tmp.k.T' here
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,9 @@ comptime {
// backend=stage2
// target=native
//
// :2:29: error: expected type '[][]const u8', found '*const struct{comptime *const [5:0]u8 = "hello", comptime *const [5:0]u8 = "world"}'
// :2:29: error: expected type '[][]const u8', found '*const [2][]const u8'
// :2:29: note: cast discards const qualifier
// :6:31: error: expected type '*[2][]const u8', found '*const struct{comptime *const [5:0]u8 = "hello", comptime *const [5:0]u8 = "world"}'
// :6:31: error: expected type '*[2][]const u8', found '*const [2][]const u8'
// :6:31: note: cast discards const qualifier
// :11:19: error: expected type '*tmp.S', found '*const struct{comptime a: comptime_int = 2}'
// :11:19: error: expected type '*tmp.S', found '*const tmp.S'
// :11:19: note: cast discards const qualifier
2 changes: 1 addition & 1 deletion compile_errors/reassign_to_array_parameter.zig
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,4 @@ export fn entry() void {
// backend=llvm
// target=native
//
// :2:15: error: cannot assign to constant
// :2:5: error: cannot assign to constant
2 changes: 1 addition & 1 deletion compile_errors/reassign_to_struct_parameter.zig
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,4 @@ export fn entry() void {
// backend=stage2
// target=native
//
// :5:10: error: cannot assign to constant
// :5:5: error: cannot assign to constant
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,6 @@ export fn entry() void {
// backend=stage2
// target=native
//
// :12:25: error: expected type 'u32', found '@typeInfo(@typeInfo(@TypeOf(tmp.get_uval)).Fn.return_type.?).ErrorUnion.error_set!u32'
// :12:25: note: cannot convert error union to payload type
// :12:25: note: consider using 'try', 'catch', or 'if'
// :12:15: error: expected type 'u32', found '@typeInfo(@typeInfo(@TypeOf(tmp.get_uval)).Fn.return_type.?).ErrorUnion.error_set!u32'
// :12:15: note: cannot convert error union to payload type
// :12:15: note: consider using 'try', 'catch', or 'if'
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,6 @@ pub const Container = struct {
// backend=stage2
// target=native
//
// :3:36: error: expected type 'i32', found '?i32'
// :3:36: note: cannot convert optional to payload type
// :3:36: note: consider using '.?', 'orelse', or 'if'
// :3:23: error: expected type 'i32', found '?i32'
// :3:23: note: cannot convert optional to payload type
// :3:23: note: consider using '.?', 'orelse', or 'if'
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,6 @@ pub const Container = struct {
// backend=stage2
// target=native
//
// :3:36: error: expected type 'i32', found '?i32'
// :3:36: note: cannot convert optional to payload type
// :3:36: note: consider using '.?', 'orelse', or 'if'
// :3:23: error: expected type 'i32', found '?i32'
// :3:23: note: cannot convert optional to payload type
// :3:23: note: consider using '.?', 'orelse', or 'if'
1 change: 1 addition & 0 deletions compile_errors/return_incompatible_generic_struct.zig
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,4 @@ export fn entry() void {
// :8:18: error: expected type 'tmp.A(u32)', found 'tmp.B(u32)'
// :5:12: note: struct declared here
// :2:12: note: struct declared here
// :7:11: note: function return type declared here
4 changes: 2 additions & 2 deletions compile_errors/runtime_assignment_to_comptime_struct_type.zig
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,5 @@ export fn f() void {
// backend=stage2
// target=native
//
// :7:29: error: unable to resolve comptime value
// :7:29: note: initializer of comptime only struct must be comptime-known
// :7:23: error: unable to resolve comptime value
// :7:23: note: initializer of comptime only struct must be comptime-known
4 changes: 2 additions & 2 deletions compile_errors/runtime_assignment_to_comptime_union_type.zig
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,5 @@ export fn f() void {
// backend=stage2
// target=native
//
// :7:29: error: unable to resolve comptime value
// :7:29: note: initializer of comptime only union must be comptime-known
// :7:23: error: unable to resolve comptime value
// :7:23: note: initializer of comptime only union must be comptime-known
3 changes: 2 additions & 1 deletion compile_errors/shift_amount_has_to_be_an_integer_type.zig
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,5 @@ export fn entry() void {
// backend=stage2
// target=native
//
// :2:20: error: expected type 'comptime_int', found '*const u8'
// :2:20: error: expected type 'comptime_int', found pointer
// :2:20: note: address-of operator always returns a pointer
13 changes: 10 additions & 3 deletions compile_errors/slice_sentinel_mismatch-1.zig
Original file line number Diff line number Diff line change
@@ -1,11 +1,18 @@
export fn entry() void {
export fn entry1() void {
const y: [:1]const u8 = &[_:2]u8{ 1, 2 };
_ = y;
}
export fn entry2() void {
const x: [:2]const u8 = &.{ 1, 2 };
const y: [:1]const u8 = x;
_ = y;
}

// error
// backend=stage2
// target=native
//
// :2:29: error: expected type '[:1]const u8', found '*const [2:2]u8'
// :2:29: note: pointer sentinel '2' cannot cast into pointer sentinel '1'
// :2:37: error: expected type '[2:1]u8', found '[2:2]u8'
// :2:37: note: array sentinel '2' cannot cast into array sentinel '1'
// :7:29: error: expected type '[:1]const u8', found '[:2]const u8'
// :7:29: note: pointer sentinel '2' cannot cast into pointer sentinel '1'
1 change: 0 additions & 1 deletion compile_errors/union_init_with_none_or_multiple_fields.zig
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@ export fn u2m() void {
// target=native
//
// :10:20: error: union initializer must initialize one field
// :1:12: note: union declared here
// :14:20: error: cannot initialize multiple union fields at once; unions can only have one active field
// :14:31: note: additional initializer here
// :1:12: note: union declared here
Expand Down
2 changes: 1 addition & 1 deletion compile_errors/union_noreturn_field_initialized.zig
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ pub export fn entry3() void {
// backend=stage2
// target=native
//
// :11:21: error: cannot initialize 'noreturn' field of union
// :11:14: error: cannot initialize 'noreturn' field of union
// :4:9: note: field 'b' declared here
// :2:15: note: union declared here
// :19:10: error: cannot initialize 'noreturn' field of union
Expand Down
2 changes: 1 addition & 1 deletion compile_errors/wrong_types_given_to_export.zig
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,5 @@ comptime {
// backend=stage2
// target=native
//
// :3:51: error: expected type 'builtin.GlobalLinkage', found 'u32'
// :3:41: error: expected type 'builtin.GlobalLinkage', found 'u32'
// :?:?: note: enum declared here

0 comments on commit 0dd18c1

Please sign in to comment.