Commit 06410f58bd

Techatrix <19954306+Techatrix@users.noreply.github.com>
2024-01-16 05:51:26
AstGen: properly handle ill-formed switch on error
1 parent 8b9425c
Changed files (2)
src/AstGen.zig
@@ -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);
         },
@@ -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,
test/cases/compile_errors/switch_on_error_with_non_trivial_switch_operand.zig
@@ -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'