From d0f1334226fc25a8c00ecccd64c0021e4aef9ca5 Mon Sep 17 00:00:00 2001 From: Roland Ruckerbauer Date: Mon, 17 Dec 2018 17:10:05 +0100 Subject: [PATCH] Fixed cast expression parsing in ra_syntax. The cast expression expected any type via types::type_() function, but the language spec does only allow TypeNoBounds (types without direct extra bounds via `+`). **Example:** ```rust fn test() { 6i8 as i32 + 5; } ``` This fails, because the types::type_() function which should parse the type after the as keyword is greedy, and takes all plus sign after path types as extra. My proposed fix is to replace the not implemented `type_no_plus()` just calls (`type_()`) function, which is used at several places. The replacement is `type_with_bounds_cond(p: &mut Parser, allow_bounds: bool)`, which passes the condition to relevant sub-parsers. This function is then called by `type_()` and the new public `type_no_bounds()`. --- crates/ra_syntax/src/grammar/expressions.rs | 6 ++- crates/ra_syntax/src/grammar/types.rs | 21 +++++--- .../data/parser/inline/0079_cast_expr.rs | 2 + .../data/parser/inline/0079_cast_expr.txt | 52 ++++++++++++++++--- 4 files changed, 66 insertions(+), 15 deletions(-) diff --git a/crates/ra_syntax/src/grammar/expressions.rs b/crates/ra_syntax/src/grammar/expressions.rs index 60c8602f9f..a9449c7bf8 100644 --- a/crates/ra_syntax/src/grammar/expressions.rs +++ b/crates/ra_syntax/src/grammar/expressions.rs @@ -368,12 +368,16 @@ fn try_expr(p: &mut Parser, lhs: CompletedMarker) -> CompletedMarker { // test cast_expr // fn foo() { // 82 as i32; +// 81 as i8 + 1; +// 79 as i16 - 1; // } fn cast_expr(p: &mut Parser, lhs: CompletedMarker) -> CompletedMarker { assert!(p.at(AS_KW)); let m = lhs.precede(p); p.bump(); - types::type_(p); + // Use type_no_bounds(), because cast expressions are not + // allowed to have bounds. + types::type_no_bounds(p); m.complete(p, CAST_EXPR) } diff --git a/crates/ra_syntax/src/grammar/types.rs b/crates/ra_syntax/src/grammar/types.rs index ed2718e739..811d399d4e 100644 --- a/crates/ra_syntax/src/grammar/types.rs +++ b/crates/ra_syntax/src/grammar/types.rs @@ -11,6 +11,14 @@ pub(super) const TYPE_FIRST: TokenSet = token_set_union![ const TYPE_RECOVERY_SET: TokenSet = token_set![R_PAREN, COMMA]; pub(super) fn type_(p: &mut Parser) { + type_with_bounds_cond(p, true); +} + +pub(super) fn type_no_bounds(p: &mut Parser) { + type_with_bounds_cond(p, false); +} + +fn type_with_bounds_cond(p: &mut Parser, allow_bounds: bool) { match p.current() { L_PAREN => paren_or_tuple_type(p), EXCL => never_type(p), @@ -22,8 +30,9 @@ pub(super) fn type_(p: &mut Parser) { FOR_KW => for_type(p), IMPL_KW => impl_trait_type(p), DYN_KW => dyn_trait_type(p), - L_ANGLE => path_type(p), - _ if paths::is_path_start(p) => path_type(p), + // Some path types are not allowed to have bounds (no plus) + L_ANGLE => path_type_(p, allow_bounds), + _ if paths::is_path_start(p) => path_type_(p, allow_bounds), _ => { p.err_recover("expected type", TYPE_RECOVERY_SET); } @@ -35,10 +44,6 @@ pub(super) fn ascription(p: &mut Parser) { type_(p) } -fn type_no_plus(p: &mut Parser) { - type_(p); -} - fn paren_or_tuple_type(p: &mut Parser) { assert!(p.at(L_PAREN)); let m = p.start(); @@ -101,7 +106,7 @@ fn pointer_type(p: &mut Parser) { } }; - type_no_plus(p); + type_no_bounds(p); m.complete(p, POINTER_TYPE); } @@ -147,7 +152,7 @@ fn reference_type(p: &mut Parser) { p.bump(); p.eat(LIFETIME); p.eat(MUT_KW); - type_no_plus(p); + type_no_bounds(p); m.complete(p, REFERENCE_TYPE); } diff --git a/crates/ra_syntax/tests/data/parser/inline/0079_cast_expr.rs b/crates/ra_syntax/tests/data/parser/inline/0079_cast_expr.rs index 3e53d56d64..b571a58608 100644 --- a/crates/ra_syntax/tests/data/parser/inline/0079_cast_expr.rs +++ b/crates/ra_syntax/tests/data/parser/inline/0079_cast_expr.rs @@ -1,3 +1,5 @@ fn foo() { 82 as i32; + 81 as i8 + 1; + 79 as i16 - 1; } diff --git a/crates/ra_syntax/tests/data/parser/inline/0079_cast_expr.txt b/crates/ra_syntax/tests/data/parser/inline/0079_cast_expr.txt index a804399134..cb56aef0ba 100644 --- a/crates/ra_syntax/tests/data/parser/inline/0079_cast_expr.txt +++ b/crates/ra_syntax/tests/data/parser/inline/0079_cast_expr.txt @@ -1,5 +1,5 @@ -SOURCE_FILE@[0; 28) - FN_DEF@[0; 27) +SOURCE_FILE@[0; 65) + FN_DEF@[0; 64) FN_KW@[0; 2) WHITESPACE@[2; 3) NAME@[3; 6) @@ -8,7 +8,7 @@ SOURCE_FILE@[0; 28) L_PAREN@[6; 7) R_PAREN@[7; 8) WHITESPACE@[8; 9) - BLOCK@[9; 27) + BLOCK@[9; 64) L_CURLY@[9; 10) WHITESPACE@[10; 15) EXPR_STMT@[15; 25) @@ -24,6 +24,46 @@ SOURCE_FILE@[0; 28) NAME_REF@[21; 24) IDENT@[21; 24) "i32" SEMI@[24; 25) - WHITESPACE@[25; 26) - R_CURLY@[26; 27) - WHITESPACE@[27; 28) + WHITESPACE@[25; 30) + EXPR_STMT@[30; 43) + BIN_EXPR@[30; 42) + CAST_EXPR@[30; 38) + LITERAL@[30; 32) + INT_NUMBER@[30; 32) "81" + WHITESPACE@[32; 33) + AS_KW@[33; 35) + WHITESPACE@[35; 36) + PATH_TYPE@[36; 38) + PATH@[36; 38) + PATH_SEGMENT@[36; 38) + NAME_REF@[36; 38) + IDENT@[36; 38) "i8" + WHITESPACE@[38; 39) + PLUS@[39; 40) + WHITESPACE@[40; 41) + LITERAL@[41; 42) + INT_NUMBER@[41; 42) "1" + SEMI@[42; 43) + WHITESPACE@[43; 48) + EXPR_STMT@[48; 62) + BIN_EXPR@[48; 61) + CAST_EXPR@[48; 57) + LITERAL@[48; 50) + INT_NUMBER@[48; 50) "79" + WHITESPACE@[50; 51) + AS_KW@[51; 53) + WHITESPACE@[53; 54) + PATH_TYPE@[54; 57) + PATH@[54; 57) + PATH_SEGMENT@[54; 57) + NAME_REF@[54; 57) + IDENT@[54; 57) "i16" + WHITESPACE@[57; 58) + MINUS@[58; 59) + WHITESPACE@[59; 60) + LITERAL@[60; 61) + INT_NUMBER@[60; 61) "1" + SEMI@[61; 62) + WHITESPACE@[62; 63) + R_CURLY@[63; 64) + WHITESPACE@[64; 65)