Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 26 additions & 16 deletions src/AstGen.zig
Original file line number Diff line number Diff line change
Expand Up @@ -841,13 +841,16 @@ fn expr(gz: *GenZir, scope: *Scope, ri: ResultInfo, node: Ast.Node.Index) InnerE
.@"if",
=> {
const if_full = tree.fullIf(node).?;
if (if_full.error_token) |error_token| {
const tag = node_tags[if_full.ast.else_expr];
if ((tag == .@"switch" or tag == .switch_comma) and
std.mem.eql(u8, tree.tokenSlice(error_token), tree.tokenSlice(error_token + 4)))
{
return switchExprErrUnion(gz, scope, ri.br(), node, .@"if");
no_switch_on_err: {
const error_token = if_full.error_token orelse break :no_switch_on_err;
switch (node_tags[if_full.ast.else_expr]) {
.@"switch", .switch_comma => {},
else => break :no_switch_on_err,
}
const switch_operand = node_datas[if_full.ast.else_expr].lhs;
if (node_tags[switch_operand] != .identifier) break :no_switch_on_err;
if (!mem.eql(u8, tree.tokenSlice(error_token), tree.tokenSlice(main_tokens[switch_operand]))) break :no_switch_on_err;
return switchExprErrUnion(gz, scope, ri.br(), node, .@"if");
}
return ifExpr(gz, scope, ri.br(), node, if_full);
},
Expand Down Expand Up @@ -1026,16 +1029,21 @@ fn expr(gz: *GenZir, scope: *Scope, ri: ResultInfo, node: Ast.Node.Index) InnerE
},
.@"catch" => {
const catch_token = main_tokens[node];
const payload_token: ?Ast.TokenIndex = if (token_tags[catch_token + 1] == .pipe) blk: {
if (token_tags.len > catch_token + 6 and
token_tags[catch_token + 4] == .keyword_switch)
{
if (std.mem.eql(u8, tree.tokenSlice(catch_token + 2), tree.tokenSlice(catch_token + 6))) {
return switchExprErrUnion(gz, scope, ri.br(), node, .@"catch");
}
const payload_token: ?Ast.TokenIndex = if (token_tags[catch_token + 1] == .pipe)
catch_token + 2
else
null;
no_switch_on_err: {
const capture_token = payload_token orelse break :no_switch_on_err;
switch (node_tags[node_datas[node].rhs]) {
.@"switch", .switch_comma => {},
else => break :no_switch_on_err,
}
break :blk catch_token + 2;
} else null;
const switch_operand = node_datas[node_datas[node].rhs].lhs;
if (node_tags[switch_operand] != .identifier) break :no_switch_on_err;
if (!mem.eql(u8, tree.tokenSlice(capture_token), tree.tokenSlice(main_tokens[switch_operand]))) break :no_switch_on_err;
return switchExprErrUnion(gz, scope, ri.br(), node, .@"catch");
}
switch (ri.rl) {
.ref, .ref_coerced_ty => return orelseCatchExpr(
gz,
Expand Down Expand Up @@ -7219,7 +7227,9 @@ fn switchExprErrUnion(
};

const capture_token = case.payload_token orelse break :blk &err_scope.base;
assert(token_tags[capture_token] == .identifier);
if (token_tags[capture_token] != .identifier) {
return astgen.failTok(capture_token + 1, "error set cannot be captured by reference", .{});
}

const capture_slice = tree.tokenSlice(capture_token);
if (mem.eql(u8, capture_slice, "_")) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
export fn entry() void {
const err: error{Foo} = error.Foo;

switch (err) {
error.Foo => |*foo| {
foo catch {};
},
}
}

// error
// backend=stage2
// target=native
//
// :5:23: error: error set cannot be captured by reference
4 changes: 1 addition & 3 deletions test/cases/compile_errors/switch_on_error_union_discard.zig
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
export fn entry() void {
const x: error{}!u32 = 0;
if (x) |v| v else |_| switch (_) {
}
if (x) |v| v else |_| switch (_) {}
}


// error
// backend=stage2
// target=native
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
comptime {
const e: error{Foo}!u32 = error.Foo;
e catch |err| switch (err) {
error.Foo => |*foo| {
foo catch {};
},
};
}

comptime {
const e: error{Foo}!u32 = error.Foo;
if (e) {} else |err| switch (err) {
error.Foo => |*foo| {
foo catch {};
},
}
}

// error
// backend=stage2
// target=native
//
// :4:24: error: error set cannot be captured by reference
// :13:24: error: error set cannot be captured by reference
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
export fn entry1() void {
var x: error{Foo}!u32 = 0;
_ = &x;
if (x) |_| {} else |err| switch (err + 1) {
else => {},
}
}

export fn entry2() void {
var x: error{Foo}!u32 = 0;
_ = &x;
_ = x catch |err| switch (err + 1) {
else => {},
};
}

// error
// backend=stage2
// target=native
//
// :4:42: error: invalid operands to binary expression: 'ErrorSet' and 'ComptimeInt'
// :12:35: error: invalid operands to binary expression: 'ErrorSet' and 'ComptimeInt'