Commit c11b6adf13
Changed files (8)
lib
compiler
reduce
docs
wasm
test
behavior
lib/compiler/reduce/Walk.zig
@@ -345,12 +345,8 @@ fn walkExpression(w: *Walk, node: Ast.Node.Index) Error!void {
},
.assign_destructure => {
- const lhs_count = ast.extra_data[datas[node].lhs];
- assert(lhs_count > 1);
- const lhs_exprs = ast.extra_data[datas[node].lhs + 1 ..][0..lhs_count];
- const rhs = datas[node].rhs;
-
- for (lhs_exprs) |lhs_node| {
+ const full = tree.assignDestructure(node);
+ for (full.ast.variables) |variable_node| {
switch (node_tags[lhs_node]) {
.global_var_decl,
.local_var_decl,
@@ -358,10 +354,10 @@ fn walkExpression(w: *Walk, node: Ast.Node.Index) Error!void {
.aligned_var_decl,
=> try walkLocalVarDecl(w, ast.fullVarDecl(lhs_node).?),
- else => try walkExpression(w, lhs_node),
+ else => try walkExpression(w, variable_node),
}
}
- return walkExpression(w, rhs);
+ return walkExpression(w, full.ast.assign_expr);
},
.bit_not,
lib/docs/wasm/Walk.zig
@@ -699,12 +699,9 @@ fn expr(w: *Walk, scope: *Scope, parent_decl: Decl.Index, node: Ast.Node.Index)
},
.assign_destructure => {
- const extra_index = node_datas[node].lhs;
- const lhs_count = ast.extra_data[extra_index];
- const lhs_nodes: []const Ast.Node.Index = @ptrCast(ast.extra_data[extra_index + 1 ..][0..lhs_count]);
- const rhs = node_datas[node].rhs;
- for (lhs_nodes) |lhs_node| try expr(w, scope, parent_decl, lhs_node);
- _ = try expr(w, scope, parent_decl, rhs);
+ const full = ast.assignDestructure(node);
+ for (full.ast.variables) |variable_node| try expr(w, scope, parent_decl, variable_node);
+ _ = try expr(w, scope, parent_decl, full.ast.value_expr);
},
.bool_not,
lib/std/zig/Ast.zig
@@ -1406,6 +1406,16 @@ pub fn alignedVarDecl(tree: Ast, node: Node.Index) full.VarDecl {
});
}
+pub fn assignDestructure(tree: Ast, node: Node.Index) full.AssignDestructure {
+ const data = tree.nodes.items(.data)[node];
+ const variable_count = tree.extra_data[data.lhs];
+ return tree.fullAssignDestructureComponents(.{
+ .variables = tree.extra_data[data.lhs + 1 ..][0..variable_count],
+ .equal_token = tree.nodes.items(.main_token)[node],
+ .value_expr = data.rhs,
+ });
+}
+
pub fn ifSimple(tree: Ast, node: Node.Index) full.If {
assert(tree.nodes.items(.tag)[node] == .if_simple);
const data = tree.nodes.items(.data)[node];
@@ -2045,6 +2055,28 @@ fn fullVarDeclComponents(tree: Ast, info: full.VarDecl.Components) full.VarDecl
return result;
}
+fn fullAssignDestructureComponents(tree: Ast, info: full.AssignDestructure.Components) full.AssignDestructure {
+ const token_tags = tree.tokens.items(.tag);
+ const node_tags = tree.nodes.items(.tag);
+ var result: full.AssignDestructure = .{
+ .comptime_token = null,
+ .ast = info,
+ };
+ const first_variable_token = tree.firstToken(info.variables[0]);
+ const maybe_comptime_token = switch (node_tags[info.variables[0]]) {
+ .global_var_decl,
+ .local_var_decl,
+ .aligned_var_decl,
+ .simple_var_decl,
+ => first_variable_token,
+ else => first_variable_token - 1,
+ };
+ if (token_tags[maybe_comptime_token] == .keyword_comptime) {
+ result.comptime_token = maybe_comptime_token;
+ }
+ return result;
+}
+
fn fullIfComponents(tree: Ast, info: full.If.Components) full.If {
const token_tags = tree.tokens.items(.tag);
var result: full.If = .{
@@ -2508,6 +2540,17 @@ pub const full = struct {
}
};
+ pub const AssignDestructure = struct {
+ comptime_token: ?TokenIndex,
+ ast: Components,
+
+ pub const Components = struct {
+ variables: []const Node.Index,
+ equal_token: TokenIndex,
+ value_expr: Node.Index,
+ };
+ };
+
pub const If = struct {
/// Points to the first token after the `|`. Will either be an identifier or
/// a `*` (with an identifier immediately after it).
lib/std/zig/AstGen.zig
@@ -3406,45 +3406,36 @@ fn assignDestructure(gz: *GenZir, scope: *Scope, node: Ast.Node.Index) InnerErro
try emitDbgNode(gz, node);
const astgen = gz.astgen;
const tree = astgen.tree;
- const token_tags = tree.tokens.items(.tag);
- const node_datas = tree.nodes.items(.data);
const main_tokens = tree.nodes.items(.main_token);
const node_tags = tree.nodes.items(.tag);
- const extra_index = node_datas[node].lhs;
- const lhs_count = tree.extra_data[extra_index];
- const lhs_nodes: []const Ast.Node.Index = @ptrCast(tree.extra_data[extra_index + 1 ..][0..lhs_count]);
- const rhs = node_datas[node].rhs;
-
- const maybe_comptime_token = tree.firstToken(node) - 1;
- const declared_comptime = token_tags[maybe_comptime_token] == .keyword_comptime;
-
- if (declared_comptime and gz.is_comptime) {
+ const full = tree.assignDestructure(node);
+ if (full.comptime_token != null and gz.is_comptime) {
return astgen.failNode(node, "redundant comptime keyword in already comptime scope", .{});
}
// If this expression is marked comptime, we must wrap the whole thing in a comptime block.
var gz_buf: GenZir = undefined;
- const inner_gz = if (declared_comptime) bs: {
+ const inner_gz = if (full.comptime_token) |_| bs: {
gz_buf = gz.makeSubBlock(scope);
gz_buf.is_comptime = true;
break :bs &gz_buf;
} else gz;
- defer if (declared_comptime) inner_gz.unstack();
+ defer if (full.comptime_token) |_| inner_gz.unstack();
- const rl_components = try astgen.arena.alloc(ResultInfo.Loc.DestructureComponent, lhs_nodes.len);
- for (rl_components, lhs_nodes) |*lhs_rl, lhs_node| {
- if (node_tags[lhs_node] == .identifier) {
+ const rl_components = try astgen.arena.alloc(ResultInfo.Loc.DestructureComponent, full.ast.variables.len);
+ for (rl_components, full.ast.variables) |*variable_rl, variable_node| {
+ if (node_tags[variable_node] == .identifier) {
// This intentionally does not support `@"_"` syntax.
- const ident_name = tree.tokenSlice(main_tokens[lhs_node]);
+ const ident_name = tree.tokenSlice(main_tokens[variable_node]);
if (mem.eql(u8, ident_name, "_")) {
- lhs_rl.* = .discard;
+ variable_rl.* = .discard;
continue;
}
}
- lhs_rl.* = .{ .typed_ptr = .{
- .inst = try lvalExpr(inner_gz, scope, lhs_node),
- .src_node = lhs_node,
+ variable_rl.* = .{ .typed_ptr = .{
+ .inst = try lvalExpr(inner_gz, scope, variable_node),
+ .src_node = variable_node,
} };
}
@@ -3453,9 +3444,9 @@ fn assignDestructure(gz: *GenZir, scope: *Scope, node: Ast.Node.Index) InnerErro
.components = rl_components,
} } };
- _ = try expr(inner_gz, scope, ri, rhs);
+ _ = try expr(inner_gz, scope, ri, full.ast.value_expr);
- if (declared_comptime) {
+ if (full.comptime_token) |_| {
const comptime_block_inst = try gz.makeBlockInst(.block_comptime, node);
_ = try inner_gz.addBreak(.@"break", comptime_block_inst, .void_value);
try inner_gz.setBlockBody(comptime_block_inst);
@@ -3474,23 +3465,16 @@ fn assignDestructureMaybeDecls(
const astgen = gz.astgen;
const tree = astgen.tree;
const token_tags = tree.tokens.items(.tag);
- const node_datas = tree.nodes.items(.data);
const main_tokens = tree.nodes.items(.main_token);
const node_tags = tree.nodes.items(.tag);
- const extra_index = node_datas[node].lhs;
- const lhs_count = tree.extra_data[extra_index];
- const lhs_nodes: []const Ast.Node.Index = @ptrCast(tree.extra_data[extra_index + 1 ..][0..lhs_count]);
- const rhs = node_datas[node].rhs;
-
- const maybe_comptime_token = tree.firstToken(node) - 1;
- const declared_comptime = token_tags[maybe_comptime_token] == .keyword_comptime;
- if (declared_comptime and gz.is_comptime) {
+ const full = tree.assignDestructure(node);
+ if (full.comptime_token != null and gz.is_comptime) {
return astgen.failNode(node, "redundant comptime keyword in already comptime scope", .{});
}
- const is_comptime = declared_comptime or gz.is_comptime;
- const rhs_is_comptime = tree.nodes.items(.tag)[rhs] == .@"comptime";
+ const is_comptime = full.comptime_token != null or gz.is_comptime;
+ const value_is_comptime = node_tags[full.ast.value_expr] == .@"comptime";
// When declaring consts via a destructure, we always use a result pointer.
// This avoids the need to create tuple types, and is also likely easier to
@@ -3499,24 +3483,24 @@ fn assignDestructureMaybeDecls(
// We know this rl information won't live past the evaluation of this
// expression, so it may as well go in the block arena.
- const rl_components = try block_arena.alloc(ResultInfo.Loc.DestructureComponent, lhs_nodes.len);
- var any_non_const_lhs = false;
+ const rl_components = try block_arena.alloc(ResultInfo.Loc.DestructureComponent, full.ast.variables.len);
+ var any_non_const_variables = false;
var any_lvalue_expr = false;
- for (rl_components, lhs_nodes) |*lhs_rl, lhs_node| {
- switch (node_tags[lhs_node]) {
+ for (rl_components, full.ast.variables) |*variable_rl, variable_node| {
+ switch (node_tags[variable_node]) {
.identifier => {
// This intentionally does not support `@"_"` syntax.
- const ident_name = tree.tokenSlice(main_tokens[lhs_node]);
+ const ident_name = tree.tokenSlice(main_tokens[variable_node]);
if (mem.eql(u8, ident_name, "_")) {
- any_non_const_lhs = true;
- lhs_rl.* = .discard;
+ any_non_const_variables = true;
+ variable_rl.* = .discard;
continue;
}
},
.global_var_decl, .local_var_decl, .simple_var_decl, .aligned_var_decl => {
- const full = tree.fullVarDecl(lhs_node).?;
+ const full_var_decl = tree.fullVarDecl(variable_node).?;
- const name_token = full.ast.mut_token + 1;
+ const name_token = full_var_decl.ast.mut_token + 1;
const ident_name_raw = tree.tokenSlice(name_token);
if (mem.eql(u8, ident_name_raw, "_")) {
return astgen.failTok(name_token, "'_' used as an identifier without @\"_\" syntax", .{});
@@ -3524,35 +3508,35 @@ fn assignDestructureMaybeDecls(
// We detect shadowing in the second pass over these, while we're creating scopes.
- if (full.ast.addrspace_node != 0) {
- return astgen.failTok(main_tokens[full.ast.addrspace_node], "cannot set address space of local variable '{s}'", .{ident_name_raw});
+ if (full_var_decl.ast.addrspace_node != 0) {
+ return astgen.failTok(main_tokens[full_var_decl.ast.addrspace_node], "cannot set address space of local variable '{s}'", .{ident_name_raw});
}
- if (full.ast.section_node != 0) {
- return astgen.failTok(main_tokens[full.ast.section_node], "cannot set section of local variable '{s}'", .{ident_name_raw});
+ if (full_var_decl.ast.section_node != 0) {
+ return astgen.failTok(main_tokens[full_var_decl.ast.section_node], "cannot set section of local variable '{s}'", .{ident_name_raw});
}
- const is_const = switch (token_tags[full.ast.mut_token]) {
+ const is_const = switch (token_tags[full_var_decl.ast.mut_token]) {
.keyword_var => false,
.keyword_const => true,
else => unreachable,
};
- if (!is_const) any_non_const_lhs = true;
+ if (!is_const) any_non_const_variables = true;
// We also mark `const`s as comptime if the RHS is definitely comptime-known.
- const this_lhs_comptime = is_comptime or (is_const and rhs_is_comptime);
+ const this_variable_comptime = is_comptime or (is_const and value_is_comptime);
- const align_inst: Zir.Inst.Ref = if (full.ast.align_node != 0)
- try expr(gz, scope, coerced_align_ri, full.ast.align_node)
+ const align_inst: Zir.Inst.Ref = if (full_var_decl.ast.align_node != 0)
+ try expr(gz, scope, coerced_align_ri, full_var_decl.ast.align_node)
else
.none;
- if (full.ast.type_node != 0) {
+ if (full_var_decl.ast.type_node != 0) {
// Typed alloc
- const type_inst = try typeExpr(gz, scope, full.ast.type_node);
+ const type_inst = try typeExpr(gz, scope, full_var_decl.ast.type_node);
const ptr = if (align_inst == .none) ptr: {
const tag: Zir.Inst.Tag = if (is_const)
.alloc
- else if (this_lhs_comptime)
+ else if (this_variable_comptime)
.alloc_comptime_mut
else
.alloc_mut;
@@ -3562,16 +3546,16 @@ fn assignDestructureMaybeDecls(
.type_inst = type_inst,
.align_inst = align_inst,
.is_const = is_const,
- .is_comptime = this_lhs_comptime,
+ .is_comptime = this_variable_comptime,
});
- lhs_rl.* = .{ .typed_ptr = .{ .inst = ptr } };
+ variable_rl.* = .{ .typed_ptr = .{ .inst = ptr } };
} else {
// Inferred alloc
const ptr = if (align_inst == .none) ptr: {
const tag: Zir.Inst.Tag = if (is_const) tag: {
- break :tag if (this_lhs_comptime) .alloc_inferred_comptime else .alloc_inferred;
+ break :tag if (this_variable_comptime) .alloc_inferred_comptime else .alloc_inferred;
} else tag: {
- break :tag if (this_lhs_comptime) .alloc_inferred_comptime_mut else .alloc_inferred_mut;
+ break :tag if (this_variable_comptime) .alloc_inferred_comptime_mut else .alloc_inferred_mut;
};
break :ptr try gz.addNode(tag, node);
} else try gz.addAllocExtended(.{
@@ -3579,48 +3563,48 @@ fn assignDestructureMaybeDecls(
.type_inst = .none,
.align_inst = align_inst,
.is_const = is_const,
- .is_comptime = this_lhs_comptime,
+ .is_comptime = this_variable_comptime,
});
- lhs_rl.* = .{ .inferred_ptr = ptr };
+ variable_rl.* = .{ .inferred_ptr = ptr };
}
continue;
},
else => {},
}
- // This LHS is just an lvalue expression.
+ // This variable is just an lvalue expression.
// We will fill in its result pointer later, inside a comptime block.
- any_non_const_lhs = true;
+ any_non_const_variables = true;
any_lvalue_expr = true;
- lhs_rl.* = .{ .typed_ptr = .{
+ variable_rl.* = .{ .typed_ptr = .{
.inst = undefined,
- .src_node = lhs_node,
+ .src_node = variable_node,
} };
}
- if (declared_comptime and !any_non_const_lhs) {
- try astgen.appendErrorTok(maybe_comptime_token, "'comptime const' is redundant; instead wrap the initialization expression with 'comptime'", .{});
+ if (full.comptime_token != null and !any_non_const_variables) {
+ try astgen.appendErrorTok(full.comptime_token.?, "'comptime const' is redundant; instead wrap the initialization expression with 'comptime'", .{});
}
// If this expression is marked comptime, we must wrap it in a comptime block.
var gz_buf: GenZir = undefined;
- const inner_gz = if (declared_comptime) bs: {
+ const inner_gz = if (full.comptime_token) |_| bs: {
gz_buf = gz.makeSubBlock(scope);
gz_buf.is_comptime = true;
break :bs &gz_buf;
} else gz;
- defer if (declared_comptime) inner_gz.unstack();
+ defer if (full.comptime_token) |_| inner_gz.unstack();
if (any_lvalue_expr) {
- // At least one LHS was an lvalue expr. Iterate again in order to
+ // At least one variable was an lvalue expr. Iterate again in order to
// evaluate the lvalues from within the possible block_comptime.
- for (rl_components, lhs_nodes) |*lhs_rl, lhs_node| {
- if (lhs_rl.* != .typed_ptr) continue;
- switch (node_tags[lhs_node]) {
+ for (rl_components, full.ast.variables) |*variable_rl, variable_node| {
+ if (variable_rl.* != .typed_ptr) continue;
+ switch (node_tags[variable_node]) {
.global_var_decl, .local_var_decl, .simple_var_decl, .aligned_var_decl => continue,
else => {},
}
- lhs_rl.typed_ptr.inst = try lvalExpr(inner_gz, scope, lhs_node);
+ variable_rl.typed_ptr.inst = try lvalExpr(inner_gz, scope, variable_node);
}
}
@@ -3629,9 +3613,9 @@ fn assignDestructureMaybeDecls(
_ = try reachableExpr(inner_gz, scope, .{ .rl = .{ .destructure = .{
.src_node = node,
.components = rl_components,
- } } }, rhs, node);
+ } } }, full.ast.value_expr, node);
- if (declared_comptime) {
+ if (full.comptime_token) |_| {
// Finish the block_comptime. Inferred alloc resolution etc will occur
// in the parent block.
const comptime_block_inst = try gz.makeBlockInst(.block_comptime, node);
@@ -3640,37 +3624,37 @@ fn assignDestructureMaybeDecls(
try gz.instructions.append(gz.astgen.gpa, comptime_block_inst);
}
- // Now, iterate over the LHS exprs to construct any new scopes.
+ // Now, iterate over the variable exprs to construct any new scopes.
// If there were any inferred allocations, resolve them.
// If there were any `const` decls, make the pointer constant.
var cur_scope = scope;
- for (rl_components, lhs_nodes) |lhs_rl, lhs_node| {
- switch (node_tags[lhs_node]) {
+ for (rl_components, full.ast.variables) |variable_rl, variable_node| {
+ switch (node_tags[variable_node]) {
.local_var_decl, .simple_var_decl, .aligned_var_decl => {},
else => continue, // We were mutating an existing lvalue - nothing to do
}
- const full = tree.fullVarDecl(lhs_node).?;
- const raw_ptr = switch (lhs_rl) {
+ const full_var_decl = tree.fullVarDecl(variable_node).?;
+ const raw_ptr = switch (variable_rl) {
.discard => unreachable,
.typed_ptr => |typed_ptr| typed_ptr.inst,
.inferred_ptr => |ptr_inst| ptr_inst,
};
// If the alloc was inferred, resolve it.
- if (full.ast.type_node == 0) {
- _ = try gz.addUnNode(.resolve_inferred_alloc, raw_ptr, lhs_node);
+ if (full_var_decl.ast.type_node == 0) {
+ _ = try gz.addUnNode(.resolve_inferred_alloc, raw_ptr, variable_node);
}
- const is_const = switch (token_tags[full.ast.mut_token]) {
+ const is_const = switch (token_tags[full_var_decl.ast.mut_token]) {
.keyword_var => false,
.keyword_const => true,
else => unreachable,
};
// If the alloc was const, make it const.
- const var_ptr = if (is_const and full.ast.type_node != 0) make_const: {
+ const var_ptr = if (is_const and full_var_decl.ast.type_node != 0) make_const: {
// Note that we don't do this if type_node == 0 since `resolve_inferred_alloc`
// handles it for us.
break :make_const try gz.addUnNode(.make_ptr_const, raw_ptr, node);
} else raw_ptr;
- const name_token = full.ast.mut_token + 1;
+ const name_token = full_var_decl.ast.mut_token + 1;
const ident_name_raw = tree.tokenSlice(name_token);
const ident_name = try astgen.identAsString(name_token);
try astgen.detectLocalShadowing(
lib/std/zig/AstRlAnnotate.zig
@@ -204,13 +204,12 @@ fn expr(astrl: *AstRlAnnotate, node: Ast.Node.Index, block: ?*Block, ri: ResultI
}
},
.assign_destructure => {
- const lhs_count = tree.extra_data[node_datas[node].lhs];
- const all_lhs = tree.extra_data[node_datas[node].lhs + 1 ..][0..lhs_count];
- for (all_lhs) |lhs| {
- _ = try astrl.expr(lhs, block, ResultInfo.none);
+ const full = tree.assignDestructure(node);
+ for (full.ast.variables) |variable_node| {
+ _ = try astrl.expr(variable_node, block, ResultInfo.none);
}
// We don't need to gather any meaningful data here, because destructures always use RLS
- _ = try astrl.expr(node_datas[node].rhs, block, ResultInfo.none);
+ _ = try astrl.expr(full.ast.value_expr, block, ResultInfo.none);
return false;
},
.assign => {
lib/std/zig/parser_test.zig
@@ -2914,6 +2914,25 @@ test "zig fmt: test declaration" {
);
}
+test "zig fmt: destructure" {
+ try testCanonical(
+ \\comptime {
+ \\ var w: u8, var x: u8 = .{ 1, 2 };
+ \\ w, var y: u8 = .{ 3, 4 };
+ \\ var z: u8, x = .{ 5, 6 };
+ \\ y, z = .{ 7, 8 };
+ \\}
+ \\
+ \\comptime {
+ \\ comptime var w, var x = .{ 1, 2 };
+ \\ comptime w, var y = .{ 3, 4 };
+ \\ comptime var z, x = .{ 5, 6 };
+ \\ comptime y, z = .{ 7, 8 };
+ \\}
+ \\
+ );
+}
+
test "zig fmt: infix operators" {
try testCanonical(
\\test {
lib/std/zig/render.zig
@@ -569,39 +569,33 @@ fn renderExpression(r: *Render, node: Ast.Node.Index, space: Space) Error!void {
},
.assign_destructure => {
- const lhs_count = tree.extra_data[datas[node].lhs];
- assert(lhs_count > 1);
- const lhs_exprs = tree.extra_data[datas[node].lhs + 1 ..][0..lhs_count];
- const rhs = datas[node].rhs;
-
- const maybe_comptime_token = tree.firstToken(node) - 1;
- if (token_tags[maybe_comptime_token] == .keyword_comptime) {
- try renderToken(r, maybe_comptime_token, .space);
+ const full = tree.assignDestructure(node);
+ if (full.comptime_token) |comptime_token| {
+ try renderToken(r, comptime_token, .space);
}
- for (lhs_exprs, 0..) |lhs_node, i| {
- const lhs_space: Space = if (i == lhs_exprs.len - 1) .space else .comma_space;
- switch (node_tags[lhs_node]) {
+ for (full.ast.variables, 0..) |variable_node, i| {
+ const variable_space: Space = if (i == full.ast.variables.len - 1) .space else .comma_space;
+ switch (node_tags[variable_node]) {
.global_var_decl,
.local_var_decl,
.simple_var_decl,
.aligned_var_decl,
=> {
- try renderVarDecl(r, tree.fullVarDecl(lhs_node).?, true, lhs_space);
+ try renderVarDecl(r, tree.fullVarDecl(variable_node).?, true, variable_space);
},
- else => try renderExpression(r, lhs_node, lhs_space),
+ else => try renderExpression(r, variable_node, variable_space),
}
}
- const equal_token = main_tokens[node];
- if (tree.tokensOnSameLine(equal_token, equal_token + 1)) {
- try renderToken(r, equal_token, .space);
+ if (tree.tokensOnSameLine(full.ast.equal_token, full.ast.equal_token + 1)) {
+ try renderToken(r, full.ast.equal_token, .space);
} else {
ais.pushIndent();
- try renderToken(r, equal_token, .newline);
+ try renderToken(r, full.ast.equal_token, .newline);
ais.popIndent();
}
ais.pushIndentOneShot();
- return renderExpression(r, rhs, space);
+ return renderExpression(r, full.ast.value_expr, space);
},
.bit_not,
test/behavior/destructure.zig
@@ -24,21 +24,55 @@ test "simple destructure" {
test "destructure with comptime syntax" {
const S = struct {
- fn doTheTest() void {
- comptime var x: f32 = undefined;
- comptime x, const y, var z = .{ 0.5, 123, 456 }; // z is a comptime var
- _ = &z;
-
- comptime assert(@TypeOf(y) == comptime_int);
- comptime assert(@TypeOf(z) == comptime_int);
- comptime assert(x == 0.5);
- comptime assert(y == 123);
- comptime assert(z == 456);
+ fn doTheTest() !void {
+ {
+ comptime var x: f32 = undefined;
+ comptime x, const y, var z = .{ 0.5, 123, 456 }; // z is a comptime var
+ _ = &z;
+
+ comptime assert(@TypeOf(y) == comptime_int);
+ comptime assert(@TypeOf(z) == comptime_int);
+ comptime assert(x == 0.5);
+ comptime assert(y == 123);
+ comptime assert(z == 456);
+ }
+ {
+ var w: u8, var x: u8 = .{ 1, 2 };
+ w, var y: u8 = .{ 3, 4 };
+ var z: u8, x = .{ 5, 6 };
+ y, z = .{ 7, 8 };
+ {
+ w += 1;
+ x -= 2;
+ y *= 3;
+ z /= 4;
+ }
+ try expect(w == 4);
+ try expect(x == 4);
+ try expect(y == 21);
+ try expect(z == 2);
+ }
+ {
+ comptime var w, var x = .{ 1, 2 };
+ comptime w, var y = .{ 3, 4 };
+ comptime var z, x = .{ 5, 6 };
+ comptime y, z = .{ 7, 8 };
+ comptime {
+ w += 1;
+ x -= 2;
+ y *= 3;
+ z /= 4;
+ }
+ comptime assert(w == 4);
+ comptime assert(x == 4);
+ comptime assert(y == 21);
+ comptime assert(z == 2);
+ }
}
};
- S.doTheTest();
- comptime S.doTheTest();
+ try S.doTheTest();
+ try comptime S.doTheTest();
}
test "destructure from labeled block" {