From c98b020ce29467e80217718e0a1856b7fccd6b53 Mon Sep 17 00:00:00 2001 From: Matthew Borkowski Date: Thu, 2 Dec 2021 03:50:23 -0500 Subject: [PATCH] parse.zig: make chained comparison operators a parse error --- lib/std/zig/Ast.zig | 4 ++++ lib/std/zig/parse.zig | 6 +++++- lib/std/zig/parser_test.zig | 4 ++-- test/compile_errors.zig | 15 +++++++++------ 4 files changed, 20 insertions(+), 9 deletions(-) diff --git a/lib/std/zig/Ast.zig b/lib/std/zig/Ast.zig index 7729805c88..da8616ed9e 100644 --- a/lib/std/zig/Ast.zig +++ b/lib/std/zig/Ast.zig @@ -136,6 +136,9 @@ pub fn renderError(tree: Tree, parse_error: Error, stream: anytype) !void { // location would point to the `*` after the `.*`. return stream.writeAll("'.*' cannot be followed by '*'. Are you missing a space?"); }, + .chained_comparison_operators => { + return stream.writeAll("comparison operators cannot be chained"); + }, .decl_between_fields => { return stream.writeAll("declarations are not allowed between container fields"); }, @@ -2424,6 +2427,7 @@ pub const Error = struct { pub const Tag = enum { asterisk_after_ptr_deref, + chained_comparison_operators, decl_between_fields, expected_block, expected_block_or_assignment, diff --git a/lib/std/zig/parse.zig b/lib/std/zig/parse.zig index 89abb35006..28219fa085 100644 --- a/lib/std/zig/parse.zig +++ b/lib/std/zig/parse.zig @@ -1374,6 +1374,7 @@ const Parser = struct { }); fn parseExprPrecedence(p: *Parser, min_prec: i32) Error!Node.Index { + assert(min_prec >= 0); var node = try p.parsePrefixExpr(); if (node == 0) { return null_node; @@ -1384,9 +1385,12 @@ const Parser = struct { while (true) { const tok_tag = p.token_tags[p.tok_i]; const info = operTable[@intCast(usize, @enumToInt(tok_tag))]; - if (info.prec < min_prec or info.prec == banned_prec) { + if (info.prec < min_prec) { break; } + if (info.prec == banned_prec) { + return p.fail(.chained_comparison_operators); + } const oper_token = p.nextToken(); // Special-case handling for "catch" and "&&". switch (tok_tag) { diff --git a/lib/std/zig/parser_test.zig b/lib/std/zig/parser_test.zig index ef716ffb32..b4cc67de28 100644 --- a/lib/std/zig/parser_test.zig +++ b/lib/std/zig/parser_test.zig @@ -5056,8 +5056,8 @@ test "recovery: non-associative operators" { \\const x = a == b == c; \\const x = a == b != c; , &[_]Error{ - .expected_token, - .expected_token, + .chained_comparison_operators, + .chained_comparison_operators, }); } diff --git a/test/compile_errors.zig b/test/compile_errors.zig index 8dfb44cf80..7df818a708 100644 --- a/test/compile_errors.zig +++ b/test/compile_errors.zig @@ -5033,18 +5033,21 @@ pub fn addCases(ctx: *TestContext) !void { "tmp.zig:2:5: note: control flow is diverted here", }); - ctx.objErrStage1("unreachable code - multiple things", + ctx.objErrStage1("unreachable code - nested returns", \\export fn a() i32 { \\ return return 1; \\} - \\export fn b(value: u32) bool { - \\ return 1 < value < 1000; - \\} , &[_][]const u8{ "tmp.zig:2:5: error: unreachable code", "tmp.zig:2:12: note: control flow is diverted here", - "tmp.zig:5:22: error: unreachable code", - "tmp.zig:5:5: note: control flow is diverted here", + }); + + ctx.objErrStage1("chained comparison operators", + \\export fn a(value: u32) bool { + \\ return 1 < value < 1000; + \\} + , &[_][]const u8{ + "tmp.zig:2:22: error: comparison operators cannot be chained", }); ctx.objErrStage1("bad import",