Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/parser/src/grammar/generic_params.rs')
| -rw-r--r-- | crates/parser/src/grammar/generic_params.rs | 89 |
1 files changed, 49 insertions, 40 deletions
diff --git a/crates/parser/src/grammar/generic_params.rs b/crates/parser/src/grammar/generic_params.rs index 55c5dc400b..cb1b59f649 100644 --- a/crates/parser/src/grammar/generic_params.rs +++ b/crates/parser/src/grammar/generic_params.rs @@ -13,7 +13,7 @@ pub(super) fn opt_generic_param_list(p: &mut Parser<'_>) { // test_err generic_param_list_recover // fn f<T: Clone,, U:, V>() {} -fn generic_param_list(p: &mut Parser<'_>) { +pub(super) fn generic_param_list(p: &mut Parser<'_>) { assert!(p.at(T![<])); let m = p.start(); delimited( @@ -147,7 +147,15 @@ fn type_bound(p: &mut Parser<'_>) -> bool { let has_paren = p.eat(T!['(']); match p.current() { LIFETIME_IDENT => lifetime(p), - T![for] => types::for_type(p, false), + // test for_binder_bound + // fn foo<T: for<'a> [const] async Trait>() {} + T![for] => { + types::for_binder(p); + if path_type_bound(p).is_err() { + m.abandon(p); + return false; + } + } // test precise_capturing // fn captures<'a: 'a, 'b: 'b, T>() -> impl Sized + use<'b, T, Self> {} @@ -180,44 +188,8 @@ fn type_bound(p: &mut Parser<'_>) -> bool { p.bump_any(); types::for_type(p, false) } - current => { - match current { - T![?] => p.bump_any(), - T![~] => { - p.bump_any(); - p.expect(T![const]); - } - T!['['] => { - p.bump_any(); - p.expect(T![const]); - p.expect(T![']']); - } - // test const_trait_bound - // const fn foo(_: impl const Trait) {} - T![const] => { - p.bump_any(); - } - // test async_trait_bound - // fn async_foo(_: impl async Fn(&i32)) {} - T![async] => { - p.bump_any(); - } - _ => (), - } - if paths::is_use_path_start(p) { - types::path_type_bounds(p, false); - // test_err type_bounds_macro_call_recovery - // fn foo<T: T![], T: T!, T: T!{}>() -> Box<T! + T!{}> {} - if p.at(T![!]) { - let m = p.start(); - p.bump(T![!]); - p.error("unexpected `!` in type path, macro calls are not allowed here"); - if p.at_ts(TokenSet::new(&[T!['{'], T!['['], T!['(']])) { - items::token_tree(p); - } - m.complete(p, ERROR); - } - } else { + _ => { + if path_type_bound(p).is_err() { m.abandon(p); return false; } @@ -231,6 +203,43 @@ fn type_bound(p: &mut Parser<'_>) -> bool { true } +fn path_type_bound(p: &mut Parser<'_>) -> Result<(), ()> { + if p.eat(T![~]) { + p.expect(T![const]); + } else if p.eat(T!['[']) { + // test maybe_const_trait_bound + // const fn foo(_: impl [const] Trait) {} + p.expect(T![const]); + p.expect(T![']']); + } else { + // test const_trait_bound + // const fn foo(_: impl const Trait) {} + p.eat(T![const]); + } + // test async_trait_bound + // fn async_foo(_: impl async Fn(&i32)) {} + p.eat(T![async]); + p.eat(T![?]); + + if paths::is_use_path_start(p) { + types::path_type_bounds(p, false); + // test_err type_bounds_macro_call_recovery + // fn foo<T: T![], T: T!, T: T!{}>() -> Box<T! + T!{}> {} + if p.at(T![!]) { + let m = p.start(); + p.bump(T![!]); + p.error("unexpected `!` in type path, macro calls are not allowed here"); + if p.at_ts(TokenSet::new(&[T!['{'], T!['['], T!['(']])) { + items::token_tree(p); + } + m.complete(p, ERROR); + } + Ok(()) + } else { + Err(()) + } +} + // test where_clause // fn foo() // where |