From 3ea4d4385053bb4b0da87de57aac3563e085a0e3 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Sun, 20 Dec 2020 21:53:55 +0100 Subject: Properly parse legacy trait objects with leading ForType --- crates/parser/src/grammar/type_params.rs | 2 +- crates/parser/src/grammar/types.rs | 26 +++++++++---- .../inline/ok/0154_no_dyn_trait_leading_for.rast | 43 ++++++++++++++++++++++ .../inline/ok/0154_no_dyn_trait_leading_for.rs | 1 + 4 files changed, 63 insertions(+), 9 deletions(-) create mode 100644 crates/syntax/test_data/parser/inline/ok/0154_no_dyn_trait_leading_for.rast create mode 100644 crates/syntax/test_data/parser/inline/ok/0154_no_dyn_trait_leading_for.rs diff --git a/crates/parser/src/grammar/type_params.rs b/crates/parser/src/grammar/type_params.rs index 9c3f7c28a..4aeccd193 100644 --- a/crates/parser/src/grammar/type_params.rs +++ b/crates/parser/src/grammar/type_params.rs @@ -113,7 +113,7 @@ fn type_bound(p: &mut Parser) -> bool { p.eat(T![?]); match p.current() { LIFETIME_IDENT => lifetime(p), - T![for] => types::for_type(p), + T![for] => types::for_type(p, false), _ if paths::is_use_path_start(p) => types::path_type_(p, false), _ => { m.abandon(p); diff --git a/crates/parser/src/grammar/types.rs b/crates/parser/src/grammar/types.rs index 36a15eace..94cbf7d85 100644 --- a/crates/parser/src/grammar/types.rs +++ b/crates/parser/src/grammar/types.rs @@ -44,7 +44,7 @@ fn type_with_bounds_cond(p: &mut Parser, allow_bounds: bool) { T![&] => ref_type(p), T![_] => infer_type(p), T![fn] | T![unsafe] | T![extern] => fn_ptr_type(p), - T![for] => for_type(p), + T![for] => for_type(p, allow_bounds), T![impl] => impl_trait_type(p), T![dyn] => dyn_trait_type(p), // Some path types are not allowed to have bounds (no plus) @@ -227,7 +227,7 @@ pub(super) fn for_binder(p: &mut Parser) { // type A = for<'a> fn() -> (); // type B = for<'a> unsafe extern "C" fn(&'a ()) -> (); // type Obj = for<'a> PartialEq<&'a i32>; -pub(super) fn for_type(p: &mut Parser) { +pub(super) fn for_type(p: &mut Parser, allow_bounds: bool) { assert!(p.at(T![for])); let m = p.start(); for_binder(p); @@ -240,7 +240,13 @@ pub(super) fn for_type(p: &mut Parser) { } } type_no_bounds(p); - m.complete(p, FOR_TYPE); + let completed = m.complete(p, FOR_TYPE); + + // test no_dyn_trait_leading_for + // type A = for<'a> Test<'a> + Send; + if allow_bounds { + opt_type_bounds_as_dyn_trait_type(p, completed); + } } // test impl_trait_type @@ -290,7 +296,7 @@ fn path_or_macro_type_(p: &mut Parser, allow_bounds: bool) { let path = m.complete(p, kind); if allow_bounds { - opt_path_type_bounds_as_dyn_trait_type(p, path); + opt_type_bounds_as_dyn_trait_type(p, path); } } @@ -304,19 +310,23 @@ pub(super) fn path_type_(p: &mut Parser, allow_bounds: bool) { // fn foo() -> Box {} let path = m.complete(p, PATH_TYPE); if allow_bounds { - opt_path_type_bounds_as_dyn_trait_type(p, path); + opt_type_bounds_as_dyn_trait_type(p, path); } } -/// This turns a parsed PATH_TYPE optionally into a DYN_TRAIT_TYPE +/// This turns a parsed PATH_TYPE or FOR_TYPE optionally into a DYN_TRAIT_TYPE /// with a TYPE_BOUND_LIST -fn opt_path_type_bounds_as_dyn_trait_type(p: &mut Parser, path_type_marker: CompletedMarker) { +fn opt_type_bounds_as_dyn_trait_type(p: &mut Parser, type_marker: CompletedMarker) { + assert!(matches!( + type_marker.kind(), + SyntaxKind::PATH_TYPE | SyntaxKind::FOR_TYPE | SyntaxKind::MACRO_CALL + )); if !p.at(T![+]) { return; } // First create a TYPE_BOUND from the completed PATH_TYPE - let m = path_type_marker.precede(p).complete(p, TYPE_BOUND); + let m = type_marker.precede(p).complete(p, TYPE_BOUND); // Next setup a marker for the TYPE_BOUND_LIST let m = m.precede(p); diff --git a/crates/syntax/test_data/parser/inline/ok/0154_no_dyn_trait_leading_for.rast b/crates/syntax/test_data/parser/inline/ok/0154_no_dyn_trait_leading_for.rast new file mode 100644 index 000000000..edfcb288c --- /dev/null +++ b/crates/syntax/test_data/parser/inline/ok/0154_no_dyn_trait_leading_for.rast @@ -0,0 +1,43 @@ +SOURCE_FILE@0..34 + TYPE_ALIAS@0..33 + TYPE_KW@0..4 "type" + WHITESPACE@4..5 " " + NAME@5..6 + IDENT@5..6 "A" + WHITESPACE@6..7 " " + EQ@7..8 "=" + WHITESPACE@8..9 " " + DYN_TRAIT_TYPE@9..32 + TYPE_BOUND_LIST@9..32 + TYPE_BOUND@9..25 + FOR_TYPE@9..25 + FOR_KW@9..12 "for" + GENERIC_PARAM_LIST@12..16 + L_ANGLE@12..13 "<" + LIFETIME_PARAM@13..15 + LIFETIME@13..15 + LIFETIME_IDENT@13..15 "\'a" + R_ANGLE@15..16 ">" + WHITESPACE@16..17 " " + PATH_TYPE@17..25 + PATH@17..25 + PATH_SEGMENT@17..25 + NAME_REF@17..21 + IDENT@17..21 "Test" + GENERIC_ARG_LIST@21..25 + L_ANGLE@21..22 "<" + LIFETIME_ARG@22..24 + LIFETIME@22..24 + LIFETIME_IDENT@22..24 "\'a" + R_ANGLE@24..25 ">" + WHITESPACE@25..26 " " + PLUS@26..27 "+" + WHITESPACE@27..28 " " + TYPE_BOUND@28..32 + PATH_TYPE@28..32 + PATH@28..32 + PATH_SEGMENT@28..32 + NAME_REF@28..32 + IDENT@28..32 "Send" + SEMICOLON@32..33 ";" + WHITESPACE@33..34 "\n" diff --git a/crates/syntax/test_data/parser/inline/ok/0154_no_dyn_trait_leading_for.rs b/crates/syntax/test_data/parser/inline/ok/0154_no_dyn_trait_leading_for.rs new file mode 100644 index 000000000..47a71fd19 --- /dev/null +++ b/crates/syntax/test_data/parser/inline/ok/0154_no_dyn_trait_leading_for.rs @@ -0,0 +1 @@ +type A = for<'a> Test<'a> + Send; -- cgit v1.2.3