| author | |
| committer | |
| log | c98b020ce29467e80217718e0a1856b7fccd6b53 |
| tree | a8b4385bc6d9403d8762f63329d423a2789487f3 |
| parent | fb9fcf5632468b2aa8af73f4e3269a01535076f5 |
4 files changed, 20 insertions(+), 9 deletions(-)
lib/std/zig/Ast.zig+4| ... | ... | @@ -136,6 +136,9 @@ pub fn renderError(tree: Tree, parse_error: Error, stream: anytype) !void { |
| 136 | 136 | // location would point to the `*` after the `.*`. |
| 137 | 137 | return stream.writeAll("'.*' cannot be followed by '*'. Are you missing a space?"); |
| 138 | 138 | }, |
| 139 | .chained_comparison_operators => { | |
| 140 | return stream.writeAll("comparison operators cannot be chained"); | |
| 141 | }, | |
| 139 | 142 | .decl_between_fields => { |
| 140 | 143 | return stream.writeAll("declarations are not allowed between container fields"); |
| 141 | 144 | }, |
| ... | ... | @@ -2424,6 +2427,7 @@ pub const Error = struct { |
| 2424 | 2427 | |
| 2425 | 2428 | pub const Tag = enum { |
| 2426 | 2429 | asterisk_after_ptr_deref, |
| 2430 | chained_comparison_operators, | |
| 2427 | 2431 | decl_between_fields, |
| 2428 | 2432 | expected_block, |
| 2429 | 2433 | expected_block_or_assignment, |
lib/std/zig/parse.zig+5-1| ... | ... | @@ -1374,6 +1374,7 @@ const Parser = struct { |
| 1374 | 1374 | }); |
| 1375 | 1375 | |
| 1376 | 1376 | fn parseExprPrecedence(p: *Parser, min_prec: i32) Error!Node.Index { |
| 1377 | assert(min_prec >= 0); | |
| 1377 | 1378 | var node = try p.parsePrefixExpr(); |
| 1378 | 1379 | if (node == 0) { |
| 1379 | 1380 | return null_node; |
| ... | ... | @@ -1384,9 +1385,12 @@ const Parser = struct { |
| 1384 | 1385 | while (true) { |
| 1385 | 1386 | const tok_tag = p.token_tags[p.tok_i]; |
| 1386 | 1387 | const info = operTable[@intCast(usize, @enumToInt(tok_tag))]; |
| 1387 | if (info.prec < min_prec or info.prec == banned_prec) { | |
| 1388 | if (info.prec < min_prec) { | |
| 1388 | 1389 | break; |
| 1389 | 1390 | } |
| 1391 | if (info.prec == banned_prec) { | |
| 1392 | return p.fail(.chained_comparison_operators); | |
| 1393 | } | |
| 1390 | 1394 | const oper_token = p.nextToken(); |
| 1391 | 1395 | // Special-case handling for "catch" and "&&". |
| 1392 | 1396 | switch (tok_tag) { |
lib/std/zig/parser_test.zig+2-2| ... | ... | @@ -5056,8 +5056,8 @@ test "recovery: non-associative operators" { |
| 5056 | 5056 | \\const x = a == b == c; |
| 5057 | 5057 | \\const x = a == b != c; |
| 5058 | 5058 | , &[_]Error{ |
| 5059 | .expected_token, | |
| 5060 | .expected_token, | |
| 5059 | .chained_comparison_operators, | |
| 5060 | .chained_comparison_operators, | |
| 5061 | 5061 | }); |
| 5062 | 5062 | } |
| 5063 | 5063 |
test/compile_errors.zig+9-6| ... | ... | @@ -5033,18 +5033,21 @@ pub fn addCases(ctx: *TestContext) !void { |
| 5033 | 5033 | "tmp.zig:2:5: note: control flow is diverted here", |
| 5034 | 5034 | }); |
| 5035 | 5035 | |
| 5036 | ctx.objErrStage1("unreachable code - multiple things", | |
| 5036 | ctx.objErrStage1("unreachable code - nested returns", | |
| 5037 | 5037 | \\export fn a() i32 { |
| 5038 | 5038 | \\ return return 1; |
| 5039 | 5039 | \\} |
| 5040 | \\export fn b(value: u32) bool { | |
| 5041 | \\ return 1 < value < 1000; | |
| 5042 | \\} | |
| 5043 | 5040 | , &[_][]const u8{ |
| 5044 | 5041 | "tmp.zig:2:5: error: unreachable code", |
| 5045 | 5042 | "tmp.zig:2:12: note: control flow is diverted here", |
| 5046 | "tmp.zig:5:22: error: unreachable code", | |
| 5047 | "tmp.zig:5:5: note: control flow is diverted here", | |
| 5043 | }); | |
| 5044 | ||
| 5045 | ctx.objErrStage1("chained comparison operators", | |
| 5046 | \\export fn a(value: u32) bool { | |
| 5047 | \\ return 1 < value < 1000; | |
| 5048 | \\} | |
| 5049 | , &[_][]const u8{ | |
| 5050 | "tmp.zig:2:22: error: comparison operators cannot be chained", | |
| 5048 | 5051 | }); |
| 5049 | 5052 | |
| 5050 | 5053 | ctx.objErrStage1("bad import", |