From 15f11dce4ab52ef41e7ffb2e5c1328f918962344 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Sat, 17 Jul 2021 22:41:04 +0300 Subject: [PATCH] feat: improve parser error recovery for function parameters --- .../src/completions/fn_param.rs | 14 +++++ crates/parser/src/grammar/items/consts.rs | 7 ++- crates/parser/src/grammar/params.rs | 14 ++++- crates/parser/src/grammar/type_params.rs | 6 ++- crates/parser/src/grammar/types.rs | 3 +- .../parser/err/0018_incomplete_fn.rast | 3 +- .../parser/err/0021_incomplete_param.rast | 3 +- .../parser/err/0045_item_modifiers.rast | 24 +++++---- .../err/0015_missing_fn_param_type.rast | 52 +++++++++++++++++++ .../inline/err/0015_missing_fn_param_type.rs | 1 + 10 files changed, 106 insertions(+), 21 deletions(-) create mode 100644 crates/syntax/test_data/parser/inline/err/0015_missing_fn_param_type.rast create mode 100644 crates/syntax/test_data/parser/inline/err/0015_missing_fn_param_type.rs diff --git a/crates/ide_completion/src/completions/fn_param.rs b/crates/ide_completion/src/completions/fn_param.rs index 7805da24abd..d299f2e2634 100644 --- a/crates/ide_completion/src/completions/fn_param.rs +++ b/crates/ide_completion/src/completions/fn_param.rs @@ -101,6 +101,20 @@ fn baz(file$0) {} ); } + #[test] + fn test_param_completion_first_param() { + check( + r#" +fn foo(file_id: FileId) {} +fn bar(file_id: FileId) {} +fn baz(file$0 id: u32) {} +"#, + expect![[r#" + bn file_id: FileId + "#]], + ); + } + #[test] fn test_param_completion_nth_param() { check( diff --git a/crates/parser/src/grammar/items/consts.rs b/crates/parser/src/grammar/items/consts.rs index ed3bee4a468..1b317dd84a9 100644 --- a/crates/parser/src/grammar/items/consts.rs +++ b/crates/parser/src/grammar/items/consts.rs @@ -21,8 +21,11 @@ fn const_or_static(p: &mut Parser, m: Marker, kw: SyntaxKind, def: SyntaxKind) { // test_err static_underscore // static _: i32 = 5; - - types::ascription(p); + if p.at(T![:]) { + types::ascription(p); + } else { + p.error("missing type for `const` or `static`") + } if p.eat(T![=]) { expressions::expr(p); } diff --git a/crates/parser/src/grammar/params.rs b/crates/parser/src/grammar/params.rs index 5a78675fb4f..8f028c61941 100644 --- a/crates/parser/src/grammar/params.rs +++ b/crates/parser/src/grammar/params.rs @@ -106,7 +106,13 @@ fn param(p: &mut Parser, m: Marker, flavor: Flavor) -> Variadic { if variadic_param(p) { res = Variadic(true) } else { - types::ascription(p); + if p.at(T![:]) { + types::ascription(p) + } else { + // test_err missing_fn_param_type + // fn f(x y: i32, z, t: i32) {} + p.error("missing type for function parameter") + } } } // test value_parameters_no_patterns @@ -126,7 +132,11 @@ fn param(p: &mut Parser, m: Marker, flavor: Flavor) -> Variadic { if variadic_param(p) { res = Variadic(true) } else { - types::ascription(p); + if p.at(T![:]) { + types::ascription(p) + } else { + p.error("missing type for function parameter") + } } } else { types::type_(p); diff --git a/crates/parser/src/grammar/type_params.rs b/crates/parser/src/grammar/type_params.rs index 49d6fa6d0b6..a7a0109fd1b 100644 --- a/crates/parser/src/grammar/type_params.rs +++ b/crates/parser/src/grammar/type_params.rs @@ -67,7 +67,11 @@ fn const_param(p: &mut Parser, m: Marker) { assert!(p.at(T![const])); p.bump(T![const]); name(p); - types::ascription(p); + if p.at(T![:]) { + types::ascription(p); + } else { + p.error("missing type for const parameter"); + } // test const_param_defaults // struct A; diff --git a/crates/parser/src/grammar/types.rs b/crates/parser/src/grammar/types.rs index 72476c19070..e0b3c1bf0cb 100644 --- a/crates/parser/src/grammar/types.rs +++ b/crates/parser/src/grammar/types.rs @@ -55,7 +55,8 @@ fn type_with_bounds_cond(p: &mut Parser, allow_bounds: bool) { } pub(super) fn ascription(p: &mut Parser) { - p.expect(T![:]); + assert!(p.at(T![:])); + p.bump(T![:]); type_(p) } diff --git a/crates/syntax/test_data/parser/err/0018_incomplete_fn.rast b/crates/syntax/test_data/parser/err/0018_incomplete_fn.rast index 060f47dc440..5b180ce3375 100644 --- a/crates/syntax/test_data/parser/err/0018_incomplete_fn.rast +++ b/crates/syntax/test_data/parser/err/0018_incomplete_fn.rast @@ -127,7 +127,6 @@ SOURCE_FILE@0..183 R_CURLY@181..182 "}" WHITESPACE@182..183 "\n" error 34..34: expected pattern -error 34..34: expected COLON -error 34..34: expected type +error 34..34: missing type for function parameter error 180..180: expected function arguments error 180..180: expected a block diff --git a/crates/syntax/test_data/parser/err/0021_incomplete_param.rast b/crates/syntax/test_data/parser/err/0021_incomplete_param.rast index b3284553770..901490fa2fe 100644 --- a/crates/syntax/test_data/parser/err/0021_incomplete_param.rast +++ b/crates/syntax/test_data/parser/err/0021_incomplete_param.rast @@ -30,5 +30,4 @@ SOURCE_FILE@0..22 WHITESPACE@19..20 "\n" R_CURLY@20..21 "}" WHITESPACE@21..22 "\n" -error 16..16: expected COLON -error 16..16: expected type +error 16..16: missing type for function parameter diff --git a/crates/syntax/test_data/parser/err/0045_item_modifiers.rast b/crates/syntax/test_data/parser/err/0045_item_modifiers.rast index a6e6552a99e..e9dad0b7a03 100644 --- a/crates/syntax/test_data/parser/err/0045_item_modifiers.rast +++ b/crates/syntax/test_data/parser/err/0045_item_modifiers.rast @@ -17,22 +17,22 @@ SOURCE_FILE@0..50 L_CURLY@22..23 "{" R_CURLY@23..24 "}" WHITESPACE@24..25 "\n" - CONST@25..46 + CONST@25..40 UNSAFE_KW@25..31 "unsafe" WHITESPACE@31..32 " " CONST_KW@32..37 "const" WHITESPACE@37..38 " " ERROR@38..40 FN_KW@38..40 "fn" - WHITESPACE@40..41 " " - PATH_TYPE@41..46 - PATH@41..46 - PATH_SEGMENT@41..46 - NAME_REF@41..44 - IDENT@41..44 "bar" - PARAM_LIST@44..46 - L_PAREN@44..45 "(" - R_PAREN@45..46 ")" + WHITESPACE@40..41 " " + MACRO_CALL@41..46 + PATH@41..44 + PATH_SEGMENT@41..44 + NAME_REF@41..44 + IDENT@41..44 "bar" + TOKEN_TREE@44..46 + L_PAREN@44..45 "(" + R_PAREN@45..46 ")" WHITESPACE@46..47 " " ERROR@47..49 L_CURLY@47..48 "{" @@ -40,6 +40,8 @@ SOURCE_FILE@0..50 WHITESPACE@49..50 "\n" error 6..6: expected existential, fn, trait or impl error 38..38: expected a name -error 40..40: expected COLON +error 40..40: missing type for `const` or `static` +error 40..40: expected SEMICOLON +error 44..44: expected BANG error 46..46: expected SEMICOLON error 47..47: expected an item diff --git a/crates/syntax/test_data/parser/inline/err/0015_missing_fn_param_type.rast b/crates/syntax/test_data/parser/inline/err/0015_missing_fn_param_type.rast new file mode 100644 index 00000000000..99391c266ab --- /dev/null +++ b/crates/syntax/test_data/parser/inline/err/0015_missing_fn_param_type.rast @@ -0,0 +1,52 @@ +SOURCE_FILE@0..29 + FN@0..28 + FN_KW@0..2 "fn" + WHITESPACE@2..3 " " + NAME@3..4 + IDENT@3..4 "f" + PARAM_LIST@4..25 + L_PAREN@4..5 "(" + PARAM@5..6 + IDENT_PAT@5..6 + NAME@5..6 + IDENT@5..6 "x" + WHITESPACE@6..7 " " + PARAM@7..13 + IDENT_PAT@7..8 + NAME@7..8 + IDENT@7..8 "y" + COLON@8..9 ":" + WHITESPACE@9..10 " " + PATH_TYPE@10..13 + PATH@10..13 + PATH_SEGMENT@10..13 + NAME_REF@10..13 + IDENT@10..13 "i32" + COMMA@13..14 "," + WHITESPACE@14..15 " " + PARAM@15..16 + IDENT_PAT@15..16 + NAME@15..16 + IDENT@15..16 "z" + COMMA@16..17 "," + WHITESPACE@17..18 " " + PARAM@18..24 + IDENT_PAT@18..19 + NAME@18..19 + IDENT@18..19 "t" + COLON@19..20 ":" + WHITESPACE@20..21 " " + PATH_TYPE@21..24 + PATH@21..24 + PATH_SEGMENT@21..24 + NAME_REF@21..24 + IDENT@21..24 "i32" + R_PAREN@24..25 ")" + WHITESPACE@25..26 " " + BLOCK_EXPR@26..28 + L_CURLY@26..27 "{" + R_CURLY@27..28 "}" + WHITESPACE@28..29 "\n" +error 6..6: missing type for function parameter +error 6..6: expected COMMA +error 16..16: missing type for function parameter diff --git a/crates/syntax/test_data/parser/inline/err/0015_missing_fn_param_type.rs b/crates/syntax/test_data/parser/inline/err/0015_missing_fn_param_type.rs new file mode 100644 index 00000000000..4a95b908435 --- /dev/null +++ b/crates/syntax/test_data/parser/inline/err/0015_missing_fn_param_type.rs @@ -0,0 +1 @@ +fn f(x y: i32, z, t: i32) {} -- 2.44.0