diff options
| author | mlugg <mlugg@mlugg.co.uk> | 2023-08-31 14:30:58 +0100 |
|---|---|---|
| committer | Andrew Kelley <andrew@ziglang.org> | 2023-09-15 11:33:53 -0700 |
| commit | 88f5315ddfc6eaf3e28433504ec046fb3252db7c (patch) | |
| tree | 5cd6e8e16b285d136a1fbaa98d12739aeab34feb /test/cases/compile_errors | |
| parent | 50ef10eb4963167225f7153dc5165292dbac0046 (diff) | |
| download | zig-88f5315ddfc6eaf3e28433504ec046fb3252db7c.tar.gz zig-88f5315ddfc6eaf3e28433504ec046fb3252db7c.zip | |
compiler: implement destructuring syntax
This change implements the following syntax into the compiler:
```zig
const x: u32, var y, foo.bar = .{ 1, 2, 3 };
```
A destructure expression may only appear within a block (i.e. not at
comtainer scope). The LHS consists of a sequence of comma-separated var
decls and/or lvalue expressions. The RHS is a normal expression.
A new result location type, `destructure`, is used, which contains
result pointers for each component of the destructure. This means that
when the RHS is a more complicated expression, peer type resolution is
not used: each result value is individually destructured and written to
the result pointers. RLS is always used for destructure expressions,
meaning every `const` on the LHS of such an expression creates a true
stack allocation.
Aside from anonymous array literals, Sema is capable of destructuring
the following types:
* Tuples
* Arrays
* Vectors
A destructure may be prefixed with the `comptime` keyword, in which case
the entire destructure is evaluated at comptime: this means all `var`s
in the LHS are `comptime var`s, every lvalue expression is evaluated at
comptime, and the RHS is evaluated at comptime. If every LHS is a
`const`, this is not allowed: as with single declarations, the user
should instead mark the RHS as `comptime`.
There are a few subtleties in the grammar changes here. For one thing,
if every LHS is an lvalue expression (rather than a var decl), a
destructure is considered an expression. This makes, for instance,
`if (cond) x, y = .{ 1, 2 };` valid Zig code. A destructure is allowed
in almost every context where a standard assignment expression is
permitted. The exception is `switch` prongs, which cannot be
destructures as the comma is ambiguous with the end of the prong.
A follow-up commit will begin utilizing this syntax in the Zig compiler.
Resolves: #498
Diffstat (limited to 'test/cases/compile_errors')
4 files changed, 62 insertions, 0 deletions
diff --git a/test/cases/compile_errors/cast_without_result_type.zig b/test/cases/compile_errors/cast_without_result_type.zig index 3d8a3d5412..1eaabef474 100644 --- a/test/cases/compile_errors/cast_without_result_type.zig +++ b/test/cases/compile_errors/cast_without_result_type.zig @@ -13,6 +13,10 @@ export fn d() void { var x: f32 = 0; _ = x + @floatFromInt(123); } +export fn e() void { + const x: u32, const y: u64 = @intCast(123); + _ = x + y; +} // error // backend=stage2 @@ -26,3 +30,6 @@ export fn d() void { // :9:10: note: use @as to provide explicit result type // :14:13: error: @floatFromInt must have a known result type // :14:13: note: use @as to provide explicit result type +// :17:34: error: @intCast must have a known result type +// :17:32: note: destructure expressions do not provide a single result type +// :17:34: note: use @as to provide explicit result type diff --git a/test/cases/compile_errors/extra_comma_in_destructure.zig b/test/cases/compile_errors/extra_comma_in_destructure.zig new file mode 100644 index 0000000000..bc848c2ddb --- /dev/null +++ b/test/cases/compile_errors/extra_comma_in_destructure.zig @@ -0,0 +1,10 @@ +export fn foo() void { + const x, const y, = .{ 1, 2 }; + _ = .{ x, y }; +} + +// error +// backend=stage2 +// target=native +// +// :2:23: error: expected expression or var decl, found '=' diff --git a/test/cases/compile_errors/invalid_destructure_astgen.zig b/test/cases/compile_errors/invalid_destructure_astgen.zig new file mode 100644 index 0000000000..b560661176 --- /dev/null +++ b/test/cases/compile_errors/invalid_destructure_astgen.zig @@ -0,0 +1,22 @@ +export fn foo() void { + const x, const y = .{ 1, 2, 3 }; + _ = .{ x, y }; +} + +export fn bar() void { + var x: u32 = undefined; + x, const y: u64 = blk: { + if (true) break :blk .{ 1, 2 }; + break :blk .{ .x = 123, .y = 456 }; + }; + _ = y; +} + +// error +// backend=stage2 +// target=native +// +// :2:25: error: expected 2 elements for destructure, found 3 +// :2:22: note: result destructured here +// :10:21: error: struct value cannot be destructured +// :8:21: note: result destructured here diff --git a/test/cases/compile_errors/invalid_destructure_sema.zig b/test/cases/compile_errors/invalid_destructure_sema.zig new file mode 100644 index 0000000000..7d2d94598d --- /dev/null +++ b/test/cases/compile_errors/invalid_destructure_sema.zig @@ -0,0 +1,23 @@ +export fn foo() void { + const x, const y = 123; + _ = .{ x, y }; +} + +export fn bar() void { + var x: u32 = undefined; + x, const y: u64 = blk: { + if (false) break :blk .{ 1, 2 }; + const val = .{ 3, 4, 5 }; + break :blk val; + }; + _ = y; +} + +// error +// backend=stage2 +// target=native +// +// :2:24: error: type 'comptime_int' cannot be destructured +// :2:22: note: result destructured here +// :11:20: error: expected 2 elements for destructure, found 3 +// :8:21: note: result destructured here |
