mirror of
https://github.com/rust-lang/rust.git
synced 2026-04-27 18:57:42 +03:00
Clean up parsers related to generic bounds
This commit is contained in:
@@ -748,9 +748,6 @@ parse_parentheses_with_struct_fields = invalid `struct` delimiters or `fn` call
|
||||
.suggestion_braces_for_struct = if `{$type}` is a struct, use braces as delimiters
|
||||
.suggestion_no_fields_for_fn = if `{$type}` is a function, use the arguments directly
|
||||
|
||||
parse_parenthesized_lifetime = parenthesized lifetime bounds are not supported
|
||||
parse_parenthesized_lifetime_suggestion = remove the parentheses
|
||||
|
||||
parse_path_double_colon = path separator must be a double colon
|
||||
.suggestion = use a double colon instead
|
||||
|
||||
|
||||
@@ -3136,27 +3136,6 @@ pub(crate) struct ModifierLifetime {
|
||||
pub modifier: &'static str,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
#[multipart_suggestion(
|
||||
parse_parenthesized_lifetime_suggestion,
|
||||
applicability = "machine-applicable"
|
||||
)]
|
||||
pub(crate) struct RemoveParens {
|
||||
#[suggestion_part(code = "")]
|
||||
pub lo: Span,
|
||||
#[suggestion_part(code = "")]
|
||||
pub hi: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(parse_parenthesized_lifetime)]
|
||||
pub(crate) struct ParenthesizedLifetime {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
#[subdiagnostic]
|
||||
pub sugg: RemoveParens,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(parse_underscore_literal_suffix)]
|
||||
pub(crate) struct UnderscoreLiteralSuffix {
|
||||
|
||||
@@ -2397,12 +2397,12 @@ fn parse_expr_closure(&mut self) -> PResult<'a, Box<Expr>> {
|
||||
let before = self.prev_token;
|
||||
let binder = if self.check_keyword(exp!(For)) {
|
||||
let lo = self.token.span;
|
||||
let (lifetime_defs, _) = self.parse_late_bound_lifetime_defs()?;
|
||||
let (bound_vars, _) = self.parse_higher_ranked_binder()?;
|
||||
let span = lo.to(self.prev_token.span);
|
||||
|
||||
self.psess.gated_spans.gate(sym::closure_lifetime_binder, span);
|
||||
|
||||
ClosureBinder::For { span, generic_params: lifetime_defs }
|
||||
ClosureBinder::For { span, generic_params: bound_vars }
|
||||
} else {
|
||||
ClosureBinder::NotPresent
|
||||
};
|
||||
|
||||
@@ -172,8 +172,11 @@ pub(crate) fn recover_const_param_with_mistyped_const(
|
||||
})
|
||||
}
|
||||
|
||||
/// Parses a (possibly empty) list of lifetime and type parameters, possibly including
|
||||
/// a trailing comma and erroneous trailing attributes.
|
||||
/// Parse a (possibly empty) list of generic (lifetime, type, const) parameters.
|
||||
///
|
||||
/// ```ebnf
|
||||
/// GenericParams = (GenericParam ("," GenericParam)* ","?)?
|
||||
/// ```
|
||||
pub(super) fn parse_generic_params(&mut self) -> PResult<'a, ThinVec<ast::GenericParam>> {
|
||||
let mut params = ThinVec::new();
|
||||
let mut done = false;
|
||||
@@ -520,7 +523,7 @@ fn parse_ty_where_predicate_kind(&mut self) -> PResult<'a, ast::WherePredicateKi
|
||||
// * `for<'a> Trait1<'a>: Trait2<'a /* ok */>`
|
||||
// * `(for<'a> Trait1<'a>): Trait2<'a /* not ok */>`
|
||||
// * `for<'a> for<'b> Trait1<'a, 'b>: Trait2<'a /* ok */, 'b /* not ok */>`
|
||||
let (lifetime_defs, _) = self.parse_late_bound_lifetime_defs()?;
|
||||
let (bound_vars, _) = self.parse_higher_ranked_binder()?;
|
||||
|
||||
// Parse type with mandatory colon and (possibly empty) bounds,
|
||||
// or with mandatory equality sign and the second type.
|
||||
@@ -528,7 +531,7 @@ fn parse_ty_where_predicate_kind(&mut self) -> PResult<'a, ast::WherePredicateKi
|
||||
if self.eat(exp!(Colon)) {
|
||||
let bounds = self.parse_generic_bounds()?;
|
||||
Ok(ast::WherePredicateKind::BoundPredicate(ast::WhereBoundPredicate {
|
||||
bound_generic_params: lifetime_defs,
|
||||
bound_generic_params: bound_vars,
|
||||
bounded_ty: ty,
|
||||
bounds,
|
||||
}))
|
||||
|
||||
@@ -307,11 +307,11 @@ fn parse_ty_common(
|
||||
// Function pointer type or bound list (trait object type) starting with a poly-trait.
|
||||
// `for<'lt> [unsafe] [extern "ABI"] fn (&'lt S) -> T`
|
||||
// `for<'lt> Trait1<'lt> + Trait2 + 'a`
|
||||
let (lifetime_defs, _) = self.parse_late_bound_lifetime_defs()?;
|
||||
let (bound_vars, _) = self.parse_higher_ranked_binder()?;
|
||||
if self.check_fn_front_matter(false, Case::Sensitive) {
|
||||
self.parse_ty_fn_ptr(
|
||||
lo,
|
||||
lifetime_defs,
|
||||
bound_vars,
|
||||
Some(self.prev_token.span.shrink_to_lo()),
|
||||
recover_return_sign,
|
||||
)?
|
||||
@@ -325,7 +325,7 @@ fn parse_ty_common(
|
||||
let path = self.parse_path(PathStyle::Type)?;
|
||||
let parse_plus = allow_plus == AllowPlus::Yes && self.check_plus();
|
||||
let kind = self.parse_remaining_bounds_path(
|
||||
lifetime_defs,
|
||||
bound_vars,
|
||||
path,
|
||||
lo,
|
||||
parse_plus,
|
||||
@@ -358,7 +358,7 @@ fn parse_ty_common(
|
||||
let path = self.parse_path(PathStyle::Type)?;
|
||||
let parse_plus = allow_plus == AllowPlus::Yes && self.check_plus();
|
||||
self.parse_remaining_bounds_path(
|
||||
lifetime_defs,
|
||||
bound_vars,
|
||||
path,
|
||||
lo,
|
||||
parse_plus,
|
||||
@@ -442,7 +442,7 @@ fn parse_ty_tuple_or_parens(&mut self, lo: Span, allow_plus: AllowPlus) -> PResu
|
||||
let ty = ts.into_iter().next().unwrap();
|
||||
let maybe_bounds = allow_plus == AllowPlus::Yes && self.token.is_like_plus();
|
||||
match ty.kind {
|
||||
// `(TY_BOUND_NOPAREN) + BOUND + ...`.
|
||||
// `"(" BareTraitBound ")" "+" Bound "+" ...`.
|
||||
TyKind::Path(None, path) if maybe_bounds => self.parse_remaining_bounds_path(
|
||||
ThinVec::new(),
|
||||
path,
|
||||
@@ -847,11 +847,13 @@ fn parse_impl_ty(&mut self, impl_dyn_multi: &mut bool) -> PResult<'a, TyKind> {
|
||||
Ok(TyKind::ImplTrait(ast::DUMMY_NODE_ID, bounds))
|
||||
}
|
||||
|
||||
fn parse_precise_capturing_args(
|
||||
&mut self,
|
||||
lo: Span,
|
||||
parens: ast::Parens,
|
||||
) -> PResult<'a, GenericBound> {
|
||||
/// Parse a use-bound aka precise capturing list.
|
||||
///
|
||||
/// ```ebnf
|
||||
/// UseBound = "use" "<" (PreciseCapture ("," PreciseCapture)* ","?)? ">"
|
||||
/// PreciseCapture = "Self" | Ident | Lifetime
|
||||
/// ```
|
||||
fn parse_use_bound(&mut self, lo: Span, parens: ast::Parens) -> PResult<'a, GenericBound> {
|
||||
self.expect_lt()?;
|
||||
let (args, _, _) = self.parse_seq_to_before_tokens(
|
||||
&[exp!(Gt)],
|
||||
@@ -880,16 +882,7 @@ fn parse_precise_capturing_args(
|
||||
|
||||
if let ast::Parens::Yes = parens {
|
||||
self.expect(exp!(CloseParen))?;
|
||||
let hi = self.prev_token.span;
|
||||
let mut diag = self
|
||||
.dcx()
|
||||
.struct_span_err(lo.to(hi), "precise capturing lists may not be parenthesized");
|
||||
diag.multipart_suggestion(
|
||||
"remove the parentheses",
|
||||
vec![(lo, String::new()), (hi, String::new())],
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
diag.emit();
|
||||
self.report_parenthesized_bound(lo, self.prev_token.span, "precise capturing lists");
|
||||
}
|
||||
|
||||
Ok(GenericBound::Use(args, lo.to(self.prev_token.span)))
|
||||
@@ -950,9 +943,10 @@ pub(super) fn parse_generic_bounds(&mut self) -> PResult<'a, GenericBounds> {
|
||||
self.parse_generic_bounds_common(AllowPlus::Yes)
|
||||
}
|
||||
|
||||
/// Parses bounds of a type parameter `BOUND + BOUND + ...`, possibly with trailing `+`.
|
||||
/// Parse generic bounds.
|
||||
///
|
||||
/// See `parse_generic_bound` for the `BOUND` grammar.
|
||||
/// Only if `allow_plus` this parses a `+`-separated list of bounds (trailing `+` is admitted).
|
||||
/// Otherwise, this only parses a single bound or none.
|
||||
fn parse_generic_bounds_common(&mut self, allow_plus: AllowPlus) -> PResult<'a, GenericBounds> {
|
||||
let mut bounds = Vec::new();
|
||||
|
||||
@@ -998,42 +992,56 @@ fn can_begin_bound(&mut self) -> bool {
|
||||
|| self.check_keyword(exp!(Use))
|
||||
}
|
||||
|
||||
/// Parses a bound according to the grammar:
|
||||
/// Parse a bound.
|
||||
///
|
||||
/// ```ebnf
|
||||
/// BOUND = TY_BOUND | LT_BOUND
|
||||
/// Bound = LifetimeBound | UseBound | TraitBound
|
||||
/// ```
|
||||
fn parse_generic_bound(&mut self) -> PResult<'a, GenericBound> {
|
||||
let leading_token = self.prev_token;
|
||||
let lo = self.token.span;
|
||||
|
||||
// We only admit parenthesized *trait* bounds. However, we want to gracefully recover from
|
||||
// other kinds of parenthesized bounds, so parse the opening parenthesis *here*.
|
||||
//
|
||||
// In the future we might want to lift this syntactic restriction and
|
||||
// introduce "`GenericBound::Paren(Box<GenericBound>)`".
|
||||
let parens = if self.eat(exp!(OpenParen)) { ast::Parens::Yes } else { ast::Parens::No };
|
||||
|
||||
if self.token.is_lifetime() {
|
||||
self.parse_generic_lt_bound(lo, parens)
|
||||
self.parse_lifetime_bound(lo, parens)
|
||||
} else if self.eat_keyword(exp!(Use)) {
|
||||
self.parse_precise_capturing_args(lo, parens)
|
||||
self.parse_use_bound(lo, parens)
|
||||
} else {
|
||||
self.parse_generic_ty_bound(lo, parens, &leading_token)
|
||||
self.parse_trait_bound(lo, parens, &leading_token)
|
||||
}
|
||||
}
|
||||
|
||||
/// Parses a lifetime ("outlives") bound, e.g. `'a`, according to:
|
||||
/// Parse a lifetime-bound aka outlives-bound.
|
||||
///
|
||||
/// ```ebnf
|
||||
/// LT_BOUND = LIFETIME
|
||||
/// LifetimeBound = Lifetime
|
||||
/// ```
|
||||
fn parse_generic_lt_bound(
|
||||
&mut self,
|
||||
lo: Span,
|
||||
parens: ast::Parens,
|
||||
) -> PResult<'a, GenericBound> {
|
||||
fn parse_lifetime_bound(&mut self, lo: Span, parens: ast::Parens) -> PResult<'a, GenericBound> {
|
||||
let lt = self.expect_lifetime();
|
||||
let bound = GenericBound::Outlives(lt);
|
||||
|
||||
if let ast::Parens::Yes = parens {
|
||||
// FIXME(Centril): Consider not erroring here and accepting `('lt)` instead,
|
||||
// possibly introducing `GenericBound::Paren(Box<GenericBound>)`?
|
||||
self.recover_paren_lifetime(lo)?;
|
||||
self.expect(exp!(CloseParen))?;
|
||||
self.report_parenthesized_bound(lo, self.prev_token.span, "lifetime bounds");
|
||||
}
|
||||
Ok(bound)
|
||||
|
||||
Ok(GenericBound::Outlives(lt))
|
||||
}
|
||||
|
||||
fn report_parenthesized_bound(&self, lo: Span, hi: Span, kind: &str) -> ErrorGuaranteed {
|
||||
let mut diag =
|
||||
self.dcx().struct_span_err(lo.to(hi), format!("{kind} may not be parenthesized"));
|
||||
diag.multipart_suggestion(
|
||||
"remove the parentheses",
|
||||
vec![(lo, String::new()), (hi, String::new())],
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
diag.emit()
|
||||
}
|
||||
|
||||
/// Emits an error if any trait bound modifiers were present.
|
||||
@@ -1078,27 +1086,17 @@ fn error_lt_bound_with_modifiers(
|
||||
unreachable!("lifetime bound intercepted in `parse_generic_ty_bound` but no modifiers?")
|
||||
}
|
||||
|
||||
/// Recover on `('lifetime)` with `(` already eaten.
|
||||
fn recover_paren_lifetime(&mut self, lo: Span) -> PResult<'a, ()> {
|
||||
self.expect(exp!(CloseParen))?;
|
||||
let span = lo.to(self.prev_token.span);
|
||||
let sugg = errors::RemoveParens { lo, hi: self.prev_token.span };
|
||||
|
||||
self.dcx().emit_err(errors::ParenthesizedLifetime { span, sugg });
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Parses the modifiers that may precede a trait in a bound, e.g. `?Trait` or `[const] Trait`.
|
||||
///
|
||||
/// If no modifiers are present, this does not consume any tokens.
|
||||
///
|
||||
/// ```ebnf
|
||||
/// CONSTNESS = [["["] "const" ["]"]]
|
||||
/// ASYNCNESS = ["async"]
|
||||
/// POLARITY = ["?" | "!"]
|
||||
/// Constness = ("const" | "[" "const" "]")?
|
||||
/// Asyncness = "async"?
|
||||
/// Polarity = ("?" | "!")?
|
||||
/// ```
|
||||
///
|
||||
/// See `parse_generic_ty_bound` for the complete grammar of trait bound modifiers.
|
||||
/// See `parse_trait_bound` for more context.
|
||||
fn parse_trait_bound_modifiers(&mut self) -> PResult<'a, TraitBoundModifiers> {
|
||||
let modifier_lo = self.token.span;
|
||||
let constness = self.parse_bound_constness()?;
|
||||
@@ -1191,20 +1189,21 @@ pub fn parse_bound_constness(&mut self) -> PResult<'a, BoundConstness> {
|
||||
})
|
||||
}
|
||||
|
||||
/// Parses a type bound according to:
|
||||
/// ```ebnf
|
||||
/// TY_BOUND = TY_BOUND_NOPAREN | (TY_BOUND_NOPAREN)
|
||||
/// TY_BOUND_NOPAREN = [for<GENERIC_PARAMS> CONSTNESS ASYNCNESS | POLARITY] SIMPLE_PATH
|
||||
/// ```
|
||||
/// Parse a trait bound.
|
||||
///
|
||||
/// For example, this grammar accepts `for<'a: 'b> [const] ?m::Trait<'a>`.
|
||||
fn parse_generic_ty_bound(
|
||||
/// ```ebnf
|
||||
/// TraitBound = BareTraitBound | "(" BareTraitBound ")"
|
||||
/// BareTraitBound =
|
||||
/// (HigherRankedBinder Constness Asyncness | Polarity)
|
||||
/// TypePath
|
||||
/// ```
|
||||
fn parse_trait_bound(
|
||||
&mut self,
|
||||
lo: Span,
|
||||
parens: ast::Parens,
|
||||
leading_token: &Token,
|
||||
) -> PResult<'a, GenericBound> {
|
||||
let (mut lifetime_defs, binder_span) = self.parse_late_bound_lifetime_defs()?;
|
||||
let (mut bound_vars, binder_span) = self.parse_higher_ranked_binder()?;
|
||||
|
||||
let modifiers_lo = self.token.span;
|
||||
let modifiers = self.parse_trait_bound_modifiers()?;
|
||||
@@ -1227,11 +1226,11 @@ fn parse_generic_ty_bound(
|
||||
// e.g. `T: for<'a> 'a` or `T: [const] 'a`.
|
||||
if self.token.is_lifetime() {
|
||||
let _: ErrorGuaranteed = self.error_lt_bound_with_modifiers(modifiers, binder_span);
|
||||
return self.parse_generic_lt_bound(lo, parens);
|
||||
return self.parse_lifetime_bound(lo, parens);
|
||||
}
|
||||
|
||||
if let (more_lifetime_defs, Some(binder_span)) = self.parse_late_bound_lifetime_defs()? {
|
||||
lifetime_defs.extend(more_lifetime_defs);
|
||||
if let (more_bound_vars, Some(binder_span)) = self.parse_higher_ranked_binder()? {
|
||||
bound_vars.extend(more_bound_vars);
|
||||
self.dcx().emit_err(errors::BinderBeforeModifiers { binder_span, modifiers_span });
|
||||
}
|
||||
|
||||
@@ -1291,7 +1290,7 @@ fn parse_generic_ty_bound(
|
||||
};
|
||||
|
||||
if self.may_recover() && self.token == TokenKind::OpenParen {
|
||||
self.recover_fn_trait_with_lifetime_params(&mut path, &mut lifetime_defs)?;
|
||||
self.recover_fn_trait_with_lifetime_params(&mut path, &mut bound_vars)?;
|
||||
}
|
||||
|
||||
if let ast::Parens::Yes = parens {
|
||||
@@ -1314,7 +1313,7 @@ fn parse_generic_ty_bound(
|
||||
}
|
||||
|
||||
let poly_trait =
|
||||
PolyTraitRef::new(lifetime_defs, path, modifiers, lo.to(self.prev_token.span), parens);
|
||||
PolyTraitRef::new(bound_vars, path, modifiers, lo.to(self.prev_token.span), parens);
|
||||
Ok(GenericBound::Trait(poly_trait))
|
||||
}
|
||||
|
||||
@@ -1352,8 +1351,12 @@ fn recover_path_from_fn(&mut self) -> Option<ast::Path> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Optionally parses `for<$generic_params>`.
|
||||
pub(super) fn parse_late_bound_lifetime_defs(
|
||||
/// Parse an optional higher-ranked binder.
|
||||
///
|
||||
/// ```ebnf
|
||||
/// HigherRankedBinder = ("for" "<" GenericParams ">")?
|
||||
/// ```
|
||||
pub(super) fn parse_higher_ranked_binder(
|
||||
&mut self,
|
||||
) -> PResult<'a, (ThinVec<GenericParam>, Option<Span>)> {
|
||||
if self.eat_keyword(exp!(For)) {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
error: parenthesized lifetime bounds are not supported
|
||||
error: lifetime bounds may not be parenthesized
|
||||
--> $DIR/trait-object-lifetime-parens.rs:9:21
|
||||
|
|
||||
LL | fn f<'a, T: Trait + ('a)>() {}
|
||||
@@ -10,7 +10,7 @@ LL - fn f<'a, T: Trait + ('a)>() {}
|
||||
LL + fn f<'a, T: Trait + 'a>() {}
|
||||
|
|
||||
|
||||
error: parenthesized lifetime bounds are not supported
|
||||
error: lifetime bounds may not be parenthesized
|
||||
--> $DIR/trait-object-lifetime-parens.rs:12:24
|
||||
|
|
||||
LL | let _: Box<Trait + ('a)>;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
error: parenthesized lifetime bounds are not supported
|
||||
error: lifetime bounds may not be parenthesized
|
||||
--> $DIR/trait-object-lifetime-parens.rs:9:21
|
||||
|
|
||||
LL | fn f<'a, T: Trait + ('a)>() {}
|
||||
@@ -10,7 +10,7 @@ LL - fn f<'a, T: Trait + ('a)>() {}
|
||||
LL + fn f<'a, T: Trait + 'a>() {}
|
||||
|
|
||||
|
||||
error: parenthesized lifetime bounds are not supported
|
||||
error: lifetime bounds may not be parenthesized
|
||||
--> $DIR/trait-object-lifetime-parens.rs:12:24
|
||||
|
|
||||
LL | let _: Box<Trait + ('a)>;
|
||||
|
||||
@@ -6,10 +6,10 @@
|
||||
|
||||
trait Trait {}
|
||||
|
||||
fn f<'a, T: Trait + ('a)>() {} //~ ERROR parenthesized lifetime bounds are not supported
|
||||
fn f<'a, T: Trait + ('a)>() {} //~ ERROR lifetime bounds may not be parenthesized
|
||||
|
||||
fn check<'a>() {
|
||||
let _: Box<Trait + ('a)>; //~ ERROR parenthesized lifetime bounds are not supported
|
||||
let _: Box<Trait + ('a)>; //~ ERROR lifetime bounds may not be parenthesized
|
||||
//[e2021]~^ ERROR expected a type, found a trait
|
||||
// FIXME: It'd be great if we could suggest removing the parentheses here too.
|
||||
//[e2015]~v ERROR lifetimes must be followed by `+` to form a trait object type
|
||||
|
||||
Reference in New Issue
Block a user