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