Rollup merge of #142237 - benschulz:unused-parens-fn, r=fee1-dead

Detect more cases of unused_parens around types

With this change, more unused parentheses around bounds and types nested within bounds are detected.
This commit is contained in:
Matthias Krüger
2025-07-02 19:29:35 +02:00
committed by GitHub
19 changed files with 596 additions and 83 deletions

View File

@@ -305,8 +305,13 @@ impl<'a> Parser<'a> {
let removal_span = kw.span.with_hi(self.token.span.lo());
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, path, lo, parse_plus)?;
let kind = self.parse_remaining_bounds_path(
lifetime_defs,
path,
lo,
parse_plus,
ast::Parens::No,
)?;
let err = self.dcx().create_err(errors::TransposeDynOrImpl {
span: kw.span,
kw: kw.name.as_str(),
@@ -333,7 +338,13 @@ impl<'a> Parser<'a> {
} else {
let path = self.parse_path(PathStyle::Type)?;
let parse_plus = allow_plus == AllowPlus::Yes && self.check_plus();
self.parse_remaining_bounds_path(lifetime_defs, path, lo, parse_plus)?
self.parse_remaining_bounds_path(
lifetime_defs,
path,
lo,
parse_plus,
ast::Parens::No,
)?
}
}
} else if self.eat_keyword(exp!(Impl)) {
@@ -413,9 +424,13 @@ impl<'a> Parser<'a> {
let maybe_bounds = allow_plus == AllowPlus::Yes && self.token.is_like_plus();
match ty.kind {
// `(TY_BOUND_NOPAREN) + BOUND + ...`.
TyKind::Path(None, path) if maybe_bounds => {
self.parse_remaining_bounds_path(ThinVec::new(), path, lo, true)
}
TyKind::Path(None, path) if maybe_bounds => self.parse_remaining_bounds_path(
ThinVec::new(),
path,
lo,
true,
ast::Parens::Yes,
),
// For `('a) + …`, we know that `'a` in type position already lead to an error being
// emitted. To reduce output, let's indirectly suppress E0178 (bad `+` in type) and
// other irrelevant consequential errors.
@@ -495,12 +510,14 @@ impl<'a> Parser<'a> {
path: ast::Path,
lo: Span,
parse_plus: bool,
parens: ast::Parens,
) -> PResult<'a, TyKind> {
let poly_trait_ref = PolyTraitRef::new(
generic_params,
path,
TraitBoundModifiers::NONE,
lo.to(self.prev_token.span),
parens,
);
let bounds = vec![GenericBound::Trait(poly_trait_ref)];
self.parse_remaining_bounds(bounds, parse_plus)
@@ -826,7 +843,7 @@ impl<'a> Parser<'a> {
Ok(TyKind::MacCall(P(MacCall { path, args: self.parse_delim_args()? })))
} else if allow_plus == AllowPlus::Yes && self.check_plus() {
// `Trait1 + Trait2 + 'a`
self.parse_remaining_bounds_path(ThinVec::new(), path, lo, true)
self.parse_remaining_bounds_path(ThinVec::new(), path, lo, true, ast::Parens::No)
} else {
// Just a type path.
Ok(TyKind::Path(None, path))
@@ -892,10 +909,10 @@ impl<'a> Parser<'a> {
fn parse_generic_bound(&mut self) -> PResult<'a, GenericBound> {
let lo = self.token.span;
let leading_token = self.prev_token;
let has_parens = self.eat(exp!(OpenParen));
let parens = if self.eat(exp!(OpenParen)) { ast::Parens::Yes } else { ast::Parens::No };
let bound = if self.token.is_lifetime() {
self.parse_generic_lt_bound(lo, has_parens)?
self.parse_generic_lt_bound(lo, parens)?
} else if self.eat_keyword(exp!(Use)) {
// parse precise captures, if any. This is `use<'lt, 'lt, P, P>`; a list of
// lifetimes and ident params (including SelfUpper). These are validated later
@@ -904,7 +921,7 @@ impl<'a> Parser<'a> {
let (args, args_span) = self.parse_precise_capturing_args()?;
GenericBound::Use(args, use_span.to(args_span))
} else {
self.parse_generic_ty_bound(lo, has_parens, &leading_token)?
self.parse_generic_ty_bound(lo, parens, &leading_token)?
};
Ok(bound)
@@ -914,10 +931,14 @@ impl<'a> Parser<'a> {
/// ```ebnf
/// LT_BOUND = LIFETIME
/// ```
fn parse_generic_lt_bound(&mut self, lo: Span, has_parens: bool) -> PResult<'a, GenericBound> {
fn parse_generic_lt_bound(
&mut self,
lo: Span,
parens: ast::Parens,
) -> PResult<'a, GenericBound> {
let lt = self.expect_lifetime();
let bound = GenericBound::Outlives(lt);
if has_parens {
if let ast::Parens::Yes = parens {
// FIXME(Centril): Consider not erroring here and accepting `('lt)` instead,
// possibly introducing `GenericBound::Paren(P<GenericBound>)`?
self.recover_paren_lifetime(lo)?;
@@ -1090,7 +1111,7 @@ impl<'a> Parser<'a> {
fn parse_generic_ty_bound(
&mut self,
lo: Span,
has_parens: bool,
parens: ast::Parens,
leading_token: &Token,
) -> PResult<'a, GenericBound> {
let (mut lifetime_defs, binder_span) = self.parse_late_bound_lifetime_defs()?;
@@ -1116,7 +1137,7 @@ impl<'a> Parser<'a> {
// 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, has_parens);
return self.parse_generic_lt_bound(lo, parens);
}
if let (more_lifetime_defs, Some(binder_span)) = self.parse_late_bound_lifetime_defs()? {
@@ -1183,7 +1204,7 @@ impl<'a> Parser<'a> {
self.recover_fn_trait_with_lifetime_params(&mut path, &mut lifetime_defs)?;
}
if has_parens {
if let ast::Parens::Yes = parens {
// Someone has written something like `&dyn (Trait + Other)`. The correct code
// would be `&(dyn Trait + Other)`
if self.token.is_like_plus() && leading_token.is_keyword(kw::Dyn) {
@@ -1203,7 +1224,7 @@ impl<'a> Parser<'a> {
}
let poly_trait =
PolyTraitRef::new(lifetime_defs, path, modifiers, lo.to(self.prev_token.span));
PolyTraitRef::new(lifetime_defs, path, modifiers, lo.to(self.prev_token.span), parens);
Ok(GenericBound::Trait(poly_trait))
}