Skip to content

Commit f8f7c27

Browse files
committed
Clean up parsers related to generic bounds
1 parent eb3e0d4 commit f8f7c27

File tree

8 files changed

+85
-103
lines changed

8 files changed

+85
-103
lines changed

compiler/rustc_parse/messages.ftl

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -748,9 +748,6 @@ parse_parentheses_with_struct_fields = invalid `struct` delimiters or `fn` call
748748
.suggestion_braces_for_struct = if `{$type}` is a struct, use braces as delimiters
749749
.suggestion_no_fields_for_fn = if `{$type}` is a function, use the arguments directly
750750
751-
parse_parenthesized_lifetime = parenthesized lifetime bounds are not supported
752-
parse_parenthesized_lifetime_suggestion = remove the parentheses
753-
754751
parse_path_double_colon = path separator must be a double colon
755752
.suggestion = use a double colon instead
756753

compiler/rustc_parse/src/errors.rs

Lines changed: 0 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -3136,27 +3136,6 @@ pub(crate) struct ModifierLifetime {
31363136
pub modifier: &'static str,
31373137
}
31383138

3139-
#[derive(Subdiagnostic)]
3140-
#[multipart_suggestion(
3141-
parse_parenthesized_lifetime_suggestion,
3142-
applicability = "machine-applicable"
3143-
)]
3144-
pub(crate) struct RemoveParens {
3145-
#[suggestion_part(code = "")]
3146-
pub lo: Span,
3147-
#[suggestion_part(code = "")]
3148-
pub hi: Span,
3149-
}
3150-
3151-
#[derive(Diagnostic)]
3152-
#[diag(parse_parenthesized_lifetime)]
3153-
pub(crate) struct ParenthesizedLifetime {
3154-
#[primary_span]
3155-
pub span: Span,
3156-
#[subdiagnostic]
3157-
pub sugg: RemoveParens,
3158-
}
3159-
31603139
#[derive(Diagnostic)]
31613140
#[diag(parse_underscore_literal_suffix)]
31623141
pub(crate) struct UnderscoreLiteralSuffix {

compiler/rustc_parse/src/parser/expr.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2397,12 +2397,12 @@ impl<'a> Parser<'a> {
23972397
let before = self.prev_token;
23982398
let binder = if self.check_keyword(exp!(For)) {
23992399
let lo = self.token.span;
2400-
let (lifetime_defs, _) = self.parse_late_bound_lifetime_defs()?;
2400+
let (bound_vars, _) = self.parse_higher_ranked_binder()?;
24012401
let span = lo.to(self.prev_token.span);
24022402

24032403
self.psess.gated_spans.gate(sym::closure_lifetime_binder, span);
24042404

2405-
ClosureBinder::For { span, generic_params: lifetime_defs }
2405+
ClosureBinder::For { span, generic_params: bound_vars }
24062406
} else {
24072407
ClosureBinder::NotPresent
24082408
};

compiler/rustc_parse/src/parser/generics.rs

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -172,8 +172,11 @@ impl<'a> Parser<'a> {
172172
})
173173
}
174174

175-
/// Parses a (possibly empty) list of lifetime and type parameters, possibly including
176-
/// a trailing comma and erroneous trailing attributes.
175+
/// Parse a (possibly empty) list of generic (lifetime, type, const) parameters.
176+
///
177+
/// ```ebnf
178+
/// GenericParams = (GenericParam ("," GenericParam)* ","?)?
179+
/// ```
177180
pub(super) fn parse_generic_params(&mut self) -> PResult<'a, ThinVec<ast::GenericParam>> {
178181
let mut params = ThinVec::new();
179182
let mut done = false;
@@ -520,15 +523,15 @@ impl<'a> Parser<'a> {
520523
// * `for<'a> Trait1<'a>: Trait2<'a /* ok */>`
521524
// * `(for<'a> Trait1<'a>): Trait2<'a /* not ok */>`
522525
// * `for<'a> for<'b> Trait1<'a, 'b>: Trait2<'a /* ok */, 'b /* not ok */>`
523-
let (lifetime_defs, _) = self.parse_late_bound_lifetime_defs()?;
526+
let (bound_vars, _) = self.parse_higher_ranked_binder()?;
524527

525528
// Parse type with mandatory colon and (possibly empty) bounds,
526529
// or with mandatory equality sign and the second type.
527530
let ty = self.parse_ty_for_where_clause()?;
528531
if self.eat(exp!(Colon)) {
529532
let bounds = self.parse_generic_bounds()?;
530533
Ok(ast::WherePredicateKind::BoundPredicate(ast::WhereBoundPredicate {
531-
bound_generic_params: lifetime_defs,
534+
bound_generic_params: bound_vars,
532535
bounded_ty: ty,
533536
bounds,
534537
}))

compiler/rustc_parse/src/parser/ty.rs

Lines changed: 70 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -307,11 +307,11 @@ impl<'a> Parser<'a> {
307307
// Function pointer type or bound list (trait object type) starting with a poly-trait.
308308
// `for<'lt> [unsafe] [extern "ABI"] fn (&'lt S) -> T`
309309
// `for<'lt> Trait1<'lt> + Trait2 + 'a`
310-
let (lifetime_defs, _) = self.parse_late_bound_lifetime_defs()?;
310+
let (bound_vars, _) = self.parse_higher_ranked_binder()?;
311311
if self.check_fn_front_matter(false, Case::Sensitive) {
312312
self.parse_ty_fn_ptr(
313313
lo,
314-
lifetime_defs,
314+
bound_vars,
315315
Some(self.prev_token.span.shrink_to_lo()),
316316
recover_return_sign,
317317
)?
@@ -325,7 +325,7 @@ impl<'a> Parser<'a> {
325325
let path = self.parse_path(PathStyle::Type)?;
326326
let parse_plus = allow_plus == AllowPlus::Yes && self.check_plus();
327327
let kind = self.parse_remaining_bounds_path(
328-
lifetime_defs,
328+
bound_vars,
329329
path,
330330
lo,
331331
parse_plus,
@@ -358,7 +358,7 @@ impl<'a> Parser<'a> {
358358
let path = self.parse_path(PathStyle::Type)?;
359359
let parse_plus = allow_plus == AllowPlus::Yes && self.check_plus();
360360
self.parse_remaining_bounds_path(
361-
lifetime_defs,
361+
bound_vars,
362362
path,
363363
lo,
364364
parse_plus,
@@ -442,7 +442,7 @@ impl<'a> Parser<'a> {
442442
let ty = ts.into_iter().next().unwrap();
443443
let maybe_bounds = allow_plus == AllowPlus::Yes && self.token.is_like_plus();
444444
match ty.kind {
445-
// `(TY_BOUND_NOPAREN) + BOUND + ...`.
445+
// `"(" BareTraitBound ")" "+" Bound "+" ...`.
446446
TyKind::Path(None, path) if maybe_bounds => self.parse_remaining_bounds_path(
447447
ThinVec::new(),
448448
path,
@@ -847,11 +847,13 @@ impl<'a> Parser<'a> {
847847
Ok(TyKind::ImplTrait(ast::DUMMY_NODE_ID, bounds))
848848
}
849849

850-
fn parse_precise_capturing_args(
851-
&mut self,
852-
lo: Span,
853-
parens: ast::Parens,
854-
) -> PResult<'a, GenericBound> {
850+
/// Parse a use-bound aka precise capturing list.
851+
///
852+
/// ```ebnf
853+
/// UseBound = "use" "<" (PreciseCapture ("," PreciseCapture)* ","?)? ">"
854+
/// PreciseCapture = "Self" | Ident | Lifetime
855+
/// ```
856+
fn parse_use_bound(&mut self, lo: Span, parens: ast::Parens) -> PResult<'a, GenericBound> {
855857
self.expect_lt()?;
856858
let (args, _, _) = self.parse_seq_to_before_tokens(
857859
&[exp!(Gt)],
@@ -880,16 +882,7 @@ impl<'a> Parser<'a> {
880882

881883
if let ast::Parens::Yes = parens {
882884
self.expect(exp!(CloseParen))?;
883-
let hi = self.prev_token.span;
884-
let mut diag = self
885-
.dcx()
886-
.struct_span_err(lo.to(hi), "precise capturing lists may not be parenthesized");
887-
diag.multipart_suggestion(
888-
"remove the parentheses",
889-
vec![(lo, String::new()), (hi, String::new())],
890-
Applicability::MachineApplicable,
891-
);
892-
diag.emit();
885+
self.report_parenthesized_bound(lo, self.prev_token.span, "precise capturing lists");
893886
}
894887

895888
Ok(GenericBound::Use(args, lo.to(self.prev_token.span)))
@@ -950,9 +943,10 @@ impl<'a> Parser<'a> {
950943
self.parse_generic_bounds_common(AllowPlus::Yes)
951944
}
952945

953-
/// Parses bounds of a type parameter `BOUND + BOUND + ...`, possibly with trailing `+`.
946+
/// Parse generic bounds.
954947
///
955-
/// See `parse_generic_bound` for the `BOUND` grammar.
948+
/// Only if `allow_plus` this parses a `+`-separated list of bounds (trailing `+` is admitted).
949+
/// Otherwise, this only parses a single bound or none.
956950
fn parse_generic_bounds_common(&mut self, allow_plus: AllowPlus) -> PResult<'a, GenericBounds> {
957951
let mut bounds = Vec::new();
958952

@@ -998,42 +992,56 @@ impl<'a> Parser<'a> {
998992
|| self.check_keyword(exp!(Use))
999993
}
1000994

1001-
/// Parses a bound according to the grammar:
995+
/// Parse a bound.
996+
///
1002997
/// ```ebnf
1003-
/// BOUND = TY_BOUND | LT_BOUND
998+
/// Bound = LifetimeBound | UseBound | TraitBound
1004999
/// ```
10051000
fn parse_generic_bound(&mut self) -> PResult<'a, GenericBound> {
10061001
let leading_token = self.prev_token;
10071002
let lo = self.token.span;
10081003

1004+
// We only admit parenthesized *trait* bounds. However, we want to gracefully recover from
1005+
// other kinds of parenthesized bounds, so parse the opening parenthesis *here*.
1006+
//
1007+
// In the future we might want to lift this syntactic restriction and
1008+
// introduce "`GenericBound::Paren(Box<GenericBound>)`".
10091009
let parens = if self.eat(exp!(OpenParen)) { ast::Parens::Yes } else { ast::Parens::No };
10101010

10111011
if self.token.is_lifetime() {
1012-
self.parse_generic_lt_bound(lo, parens)
1012+
self.parse_lifetime_bound(lo, parens)
10131013
} else if self.eat_keyword(exp!(Use)) {
1014-
self.parse_precise_capturing_args(lo, parens)
1014+
self.parse_use_bound(lo, parens)
10151015
} else {
1016-
self.parse_generic_ty_bound(lo, parens, &leading_token)
1016+
self.parse_trait_bound(lo, parens, &leading_token)
10171017
}
10181018
}
10191019

1020-
/// Parses a lifetime ("outlives") bound, e.g. `'a`, according to:
1020+
/// Parse a lifetime-bound aka outlives-bound.
1021+
///
10211022
/// ```ebnf
1022-
/// LT_BOUND = LIFETIME
1023+
/// LifetimeBound = Lifetime
10231024
/// ```
1024-
fn parse_generic_lt_bound(
1025-
&mut self,
1026-
lo: Span,
1027-
parens: ast::Parens,
1028-
) -> PResult<'a, GenericBound> {
1025+
fn parse_lifetime_bound(&mut self, lo: Span, parens: ast::Parens) -> PResult<'a, GenericBound> {
10291026
let lt = self.expect_lifetime();
1030-
let bound = GenericBound::Outlives(lt);
1027+
10311028
if let ast::Parens::Yes = parens {
1032-
// FIXME(Centril): Consider not erroring here and accepting `('lt)` instead,
1033-
// possibly introducing `GenericBound::Paren(Box<GenericBound>)`?
1034-
self.recover_paren_lifetime(lo)?;
1029+
self.expect(exp!(CloseParen))?;
1030+
self.report_parenthesized_bound(lo, self.prev_token.span, "lifetime bounds");
10351031
}
1036-
Ok(bound)
1032+
1033+
Ok(GenericBound::Outlives(lt))
1034+
}
1035+
1036+
fn report_parenthesized_bound(&self, lo: Span, hi: Span, kind: &str) -> ErrorGuaranteed {
1037+
let mut diag =
1038+
self.dcx().struct_span_err(lo.to(hi), format!("{kind} may not be parenthesized"));
1039+
diag.multipart_suggestion(
1040+
"remove the parentheses",
1041+
vec![(lo, String::new()), (hi, String::new())],
1042+
Applicability::MachineApplicable,
1043+
);
1044+
diag.emit()
10371045
}
10381046

10391047
/// Emits an error if any trait bound modifiers were present.
@@ -1078,27 +1086,17 @@ impl<'a> Parser<'a> {
10781086
unreachable!("lifetime bound intercepted in `parse_generic_ty_bound` but no modifiers?")
10791087
}
10801088

1081-
/// Recover on `('lifetime)` with `(` already eaten.
1082-
fn recover_paren_lifetime(&mut self, lo: Span) -> PResult<'a, ()> {
1083-
self.expect(exp!(CloseParen))?;
1084-
let span = lo.to(self.prev_token.span);
1085-
let sugg = errors::RemoveParens { lo, hi: self.prev_token.span };
1086-
1087-
self.dcx().emit_err(errors::ParenthesizedLifetime { span, sugg });
1088-
Ok(())
1089-
}
1090-
10911089
/// Parses the modifiers that may precede a trait in a bound, e.g. `?Trait` or `[const] Trait`.
10921090
///
10931091
/// If no modifiers are present, this does not consume any tokens.
10941092
///
10951093
/// ```ebnf
1096-
/// CONSTNESS = [["["] "const" ["]"]]
1097-
/// ASYNCNESS = ["async"]
1098-
/// POLARITY = ["?" | "!"]
1094+
/// Constness = ("const" | "[" "const" "]")?
1095+
/// Asyncness = "async"?
1096+
/// Polarity = ("?" | "!")?
10991097
/// ```
11001098
///
1101-
/// See `parse_generic_ty_bound` for the complete grammar of trait bound modifiers.
1099+
/// See `parse_trait_bound` for more context.
11021100
fn parse_trait_bound_modifiers(&mut self) -> PResult<'a, TraitBoundModifiers> {
11031101
let modifier_lo = self.token.span;
11041102
let constness = self.parse_bound_constness()?;
@@ -1191,20 +1189,21 @@ impl<'a> Parser<'a> {
11911189
})
11921190
}
11931191

1194-
/// Parses a type bound according to:
1192+
/// Parse a trait bound.
1193+
///
11951194
/// ```ebnf
1196-
/// TY_BOUND = TY_BOUND_NOPAREN | (TY_BOUND_NOPAREN)
1197-
/// TY_BOUND_NOPAREN = [for<GENERIC_PARAMS> CONSTNESS ASYNCNESS | POLARITY] SIMPLE_PATH
1195+
/// TraitBound = BareTraitBound | "(" BareTraitBound ")"
1196+
/// BareTraitBound =
1197+
/// (HigherRankedBinder Constness Asyncness | Polarity)
1198+
/// TypePath
11981199
/// ```
1199-
///
1200-
/// For example, this grammar accepts `for<'a: 'b> [const] ?m::Trait<'a>`.
1201-
fn parse_generic_ty_bound(
1200+
fn parse_trait_bound(
12021201
&mut self,
12031202
lo: Span,
12041203
parens: ast::Parens,
12051204
leading_token: &Token,
12061205
) -> PResult<'a, GenericBound> {
1207-
let (mut lifetime_defs, binder_span) = self.parse_late_bound_lifetime_defs()?;
1206+
let (mut bound_vars, binder_span) = self.parse_higher_ranked_binder()?;
12081207

12091208
let modifiers_lo = self.token.span;
12101209
let modifiers = self.parse_trait_bound_modifiers()?;
@@ -1227,11 +1226,11 @@ impl<'a> Parser<'a> {
12271226
// e.g. `T: for<'a> 'a` or `T: [const] 'a`.
12281227
if self.token.is_lifetime() {
12291228
let _: ErrorGuaranteed = self.error_lt_bound_with_modifiers(modifiers, binder_span);
1230-
return self.parse_generic_lt_bound(lo, parens);
1229+
return self.parse_lifetime_bound(lo, parens);
12311230
}
12321231

1233-
if let (more_lifetime_defs, Some(binder_span)) = self.parse_late_bound_lifetime_defs()? {
1234-
lifetime_defs.extend(more_lifetime_defs);
1232+
if let (more_bound_vars, Some(binder_span)) = self.parse_higher_ranked_binder()? {
1233+
bound_vars.extend(more_bound_vars);
12351234
self.dcx().emit_err(errors::BinderBeforeModifiers { binder_span, modifiers_span });
12361235
}
12371236

@@ -1291,7 +1290,7 @@ impl<'a> Parser<'a> {
12911290
};
12921291

12931292
if self.may_recover() && self.token == TokenKind::OpenParen {
1294-
self.recover_fn_trait_with_lifetime_params(&mut path, &mut lifetime_defs)?;
1293+
self.recover_fn_trait_with_lifetime_params(&mut path, &mut bound_vars)?;
12951294
}
12961295

12971296
if let ast::Parens::Yes = parens {
@@ -1314,7 +1313,7 @@ impl<'a> Parser<'a> {
13141313
}
13151314

13161315
let poly_trait =
1317-
PolyTraitRef::new(lifetime_defs, path, modifiers, lo.to(self.prev_token.span), parens);
1316+
PolyTraitRef::new(bound_vars, path, modifiers, lo.to(self.prev_token.span), parens);
13181317
Ok(GenericBound::Trait(poly_trait))
13191318
}
13201319

@@ -1352,8 +1351,12 @@ impl<'a> Parser<'a> {
13521351
}
13531352
}
13541353

1355-
/// Optionally parses `for<$generic_params>`.
1356-
pub(super) fn parse_late_bound_lifetime_defs(
1354+
/// Parse an optional higher-ranked binder.
1355+
///
1356+
/// ```ebnf
1357+
/// HigherRankedBinder = ("for" "<" GenericParams ">")?
1358+
/// ```
1359+
pub(super) fn parse_higher_ranked_binder(
13571360
&mut self,
13581361
) -> PResult<'a, (ThinVec<GenericParam>, Option<Span>)> {
13591362
if self.eat_keyword(exp!(For)) {

tests/ui/parser/trait-object-lifetime-parens.e2015.stderr

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
error: parenthesized lifetime bounds are not supported
1+
error: lifetime bounds may not be parenthesized
22
--> $DIR/trait-object-lifetime-parens.rs:9:21
33
|
44
LL | fn f<'a, T: Trait + ('a)>() {}
@@ -10,7 +10,7 @@ LL - fn f<'a, T: Trait + ('a)>() {}
1010
LL + fn f<'a, T: Trait + 'a>() {}
1111
|
1212

13-
error: parenthesized lifetime bounds are not supported
13+
error: lifetime bounds may not be parenthesized
1414
--> $DIR/trait-object-lifetime-parens.rs:12:24
1515
|
1616
LL | let _: Box<Trait + ('a)>;

tests/ui/parser/trait-object-lifetime-parens.e2021.stderr

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
error: parenthesized lifetime bounds are not supported
1+
error: lifetime bounds may not be parenthesized
22
--> $DIR/trait-object-lifetime-parens.rs:9:21
33
|
44
LL | fn f<'a, T: Trait + ('a)>() {}
@@ -10,7 +10,7 @@ LL - fn f<'a, T: Trait + ('a)>() {}
1010
LL + fn f<'a, T: Trait + 'a>() {}
1111
|
1212

13-
error: parenthesized lifetime bounds are not supported
13+
error: lifetime bounds may not be parenthesized
1414
--> $DIR/trait-object-lifetime-parens.rs:12:24
1515
|
1616
LL | let _: Box<Trait + ('a)>;

0 commit comments

Comments
 (0)