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 | 26 |
1 files changed, 15 insertions, 11 deletions
diff --git a/crates/parser/src/grammar/generic_params.rs b/crates/parser/src/grammar/generic_params.rs index 92311238c2..9d4fdbfaf2 100644 --- a/crates/parser/src/grammar/generic_params.rs +++ b/crates/parser/src/grammar/generic_params.rs @@ -56,7 +56,7 @@ fn generic_param(p: &mut Parser<'_>, m: Marker) -> bool { fn lifetime_param(p: &mut Parser<'_>, m: Marker) { assert!(p.at(LIFETIME_IDENT)); lifetime(p); - if p.at(T![:]) { + if p.eat(T![:]) { lifetime_bounds(p); } m.complete(p, LIFETIME_PARAM); @@ -106,14 +106,19 @@ fn const_param(p: &mut Parser<'_>, m: Marker) { } fn lifetime_bounds(p: &mut Parser<'_>) { - assert!(p.at(T![:])); - p.bump(T![:]); - while p.at(LIFETIME_IDENT) { - lifetime(p); + let marker = p.start(); + while { + if !matches!(p.current(), LIFETIME_IDENT | T![>] | T![,]) { + p.error("expected lifetime"); + } + + type_bound(p) + } { if !p.eat(T![+]) { break; } } + marker.complete(p, TYPE_BOUND_LIST); } // test type_param_bounds @@ -145,6 +150,9 @@ fn type_bound(p: &mut Parser<'_>) -> bool { T![for] => types::for_type(p, false), // test precise_capturing // fn captures<'a: 'a, 'b: 'b, T>() -> impl Sized + use<'b, T, Self> {} + + // test_err precise_capturing_invalid + // type T = impl use<self, 1>; T![use] if p.nth_at(1, T![<]) => { p.bump_any(); let m = p.start(); @@ -156,14 +164,10 @@ fn type_bound(p: &mut Parser<'_>) -> bool { || "expected identifier or lifetime".into(), TokenSet::new(&[T![Self], IDENT, LIFETIME_IDENT]), |p| { - if p.at(T![Self]) { - let m = p.start(); - p.bump(T![Self]); - m.complete(p, NAME_REF); - } else if p.at(LIFETIME_IDENT) { + if p.at(LIFETIME_IDENT) { lifetime(p); } else { - name_ref(p); + name_ref_or_upper_self(p); } true }, |