authorgravatar for techatrix@mailbox.orgTechatrix <techatrix@mailbox.org> 2024-01-16 05:51:26+01:00
committergravatar for techatrix@mailbox.orgTechatrix <techatrix@mailbox.org> 2024-01-16 05:55:26+01:00
log06410f58bd5378d5544f34dc3e87e3309cbdd332
tree950d43fe3789619373ddc8b47236b43829a6c2a4
parent8b9425c248a36afc9cd4f76707b61553b577ce14

AstGen: properly handle ill-formed switch on error


2 files changed, 45 insertions(+), 15 deletions(-)

src/AstGen.zig+23-15
......@@ -841,13 +841,16 @@ fn expr(gz: *GenZir, scope: *Scope, ri: ResultInfo, node: Ast.Node.Index) InnerE
841841 .@"if",
842842 => {
843843 const if_full = tree.fullIf(node).?;
844 if (if_full.error_token) |error_token| {
845 const tag = node_tags[if_full.ast.else_expr];
846 if ((tag == .@"switch" or tag == .switch_comma) and
847 std.mem.eql(u8, tree.tokenSlice(error_token), tree.tokenSlice(error_token + 4)))
848 {
849 return switchExprErrUnion(gz, scope, ri.br(), node, .@"if");
844 no_switch_on_err: {
845 const error_token = if_full.error_token orelse break :no_switch_on_err;
846 switch (node_tags[if_full.ast.else_expr]) {
847 .@"switch", .switch_comma => {},
848 else => break :no_switch_on_err,
850849 }
850 const switch_operand = node_datas[if_full.ast.else_expr].lhs;
851 if (node_tags[switch_operand] != .identifier) break :no_switch_on_err;
852 if (!mem.eql(u8, tree.tokenSlice(error_token), tree.tokenSlice(main_tokens[switch_operand]))) break :no_switch_on_err;
853 return switchExprErrUnion(gz, scope, ri.br(), node, .@"if");
851854 }
852855 return ifExpr(gz, scope, ri.br(), node, if_full);
853856 },
......@@ -1026,16 +1029,21 @@ fn expr(gz: *GenZir, scope: *Scope, ri: ResultInfo, node: Ast.Node.Index) InnerE
10261029 },
10271030 .@"catch" => {
10281031 const catch_token = main_tokens[node];
1029 const payload_token: ?Ast.TokenIndex = if (token_tags[catch_token + 1] == .pipe) blk: {
1030 if (token_tags.len > catch_token + 6 and
1031 token_tags[catch_token + 4] == .keyword_switch)
1032 {
1033 if (std.mem.eql(u8, tree.tokenSlice(catch_token + 2), tree.tokenSlice(catch_token + 6))) {
1034 return switchExprErrUnion(gz, scope, ri.br(), node, .@"catch");
1035 }
1032 const payload_token: ?Ast.TokenIndex = if (token_tags[catch_token + 1] == .pipe)
1033 catch_token + 2
1034 else
1035 null;
1036 no_switch_on_err: {
1037 const capture_token = payload_token orelse break :no_switch_on_err;
1038 switch (node_tags[node_datas[node].rhs]) {
1039 .@"switch", .switch_comma => {},
1040 else => break :no_switch_on_err,
10361041 }
1037 break :blk catch_token + 2;
1038 } else null;
1042 const switch_operand = node_datas[node_datas[node].rhs].lhs;
1043 if (node_tags[switch_operand] != .identifier) break :no_switch_on_err;
1044 if (!mem.eql(u8, tree.tokenSlice(capture_token), tree.tokenSlice(main_tokens[switch_operand]))) break :no_switch_on_err;
1045 return switchExprErrUnion(gz, scope, ri.br(), node, .@"catch");
1046 }
10391047 switch (ri.rl) {
10401048 .ref, .ref_coerced_ty => return orelseCatchExpr(
10411049 gz,
test/cases/compile_errors/switch_on_error_with_non_trivial_switch_operand.zig created+22
......@@ -0,0 +1,22 @@
1export fn entry1() void {
2 var x: error{Foo}!u32 = 0;
3 _ = &x;
4 if (x) |_| {} else |err| switch (err + 1) {
5 else => {},
6 }
7}
8
9export fn entry2() void {
10 var x: error{Foo}!u32 = 0;
11 _ = &x;
12 _ = x catch |err| switch (err + 1) {
13 else => {},
14 };
15}
16
17// error
18// backend=stage2
19// target=native
20//
21// :4:42: error: invalid operands to binary expression: 'ErrorSet' and 'ComptimeInt'
22// :12:35: error: invalid operands to binary expression: 'ErrorSet' and 'ComptimeInt'