Detect more cases of unused_parens around types

This commit is contained in:
Benjamin Schulz 2025-06-04 19:03:18 +02:00 committed by Ben Schulz
parent e61dd437f3
commit 7d6764a45b
19 changed files with 596 additions and 83 deletions

View file

@ -1391,6 +1391,7 @@ impl Expr {
path.clone(),
TraitBoundModifiers::NONE,
self.span,
Parens::No,
))),
_ => None,
}
@ -3360,6 +3361,13 @@ pub struct TraitRef {
pub ref_id: NodeId,
}
/// Whether enclosing parentheses are present or not.
#[derive(Clone, Encodable, Decodable, Debug)]
pub enum Parens {
Yes,
No,
}
#[derive(Clone, Encodable, Decodable, Debug)]
pub struct PolyTraitRef {
/// The `'a` in `for<'a> Foo<&'a T>`.
@ -3372,6 +3380,10 @@ pub struct PolyTraitRef {
pub trait_ref: TraitRef,
pub span: Span,
/// When `Yes`, the first and last character of `span` are an opening
/// and a closing paren respectively.
pub parens: Parens,
}
impl PolyTraitRef {
@ -3380,12 +3392,14 @@ impl PolyTraitRef {
path: Path,
modifiers: TraitBoundModifiers,
span: Span,
parens: Parens,
) -> Self {
PolyTraitRef {
bound_generic_params: generic_params,
modifiers,
trait_ref: TraitRef { path, ref_id: DUMMY_NODE_ID },
span,
parens,
}
}
}

View file

@ -1142,7 +1142,7 @@ macro_rules! common_visitor_and_walkers {
vis: &mut V,
p: &$($lt)? $($mut)? PolyTraitRef,
) -> V::Result {
let PolyTraitRef { bound_generic_params, modifiers, trait_ref, span } = p;
let PolyTraitRef { bound_generic_params, modifiers, trait_ref, span, parens: _ } = p;
try_visit!(visit_modifiers(vis, modifiers));
try_visit!(visit_generic_params(vis, bound_generic_params));
try_visit!(vis.visit_trait_ref(trait_ref));

View file

@ -1209,6 +1209,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
modifiers: TraitBoundModifiers::NONE,
trait_ref: TraitRef { path: path.clone(), ref_id: t.id },
span: t.span,
parens: ast::Parens::No,
},
itctx,
);

View file

@ -195,6 +195,7 @@ impl<'a> ExtCtxt<'a> {
},
trait_ref: self.trait_ref(path),
span,
parens: ast::Parens::No,
}
}

View file

@ -3,6 +3,7 @@ use std::iter;
use rustc_ast::util::{classify, parser};
use rustc_ast::{self as ast, ExprKind, HasAttrs as _, StmtKind};
use rustc_attr_data_structures::{AttributeKind, find_attr};
use rustc_data_structures::fx::FxHashMap;
use rustc_errors::{MultiSpan, pluralize};
use rustc_hir::def::{DefKind, Res};
use rustc_hir::def_id::DefId;
@ -10,6 +11,7 @@ use rustc_hir::{self as hir, LangItem};
use rustc_infer::traits::util::elaborate;
use rustc_middle::ty::{self, Ty, adjustment};
use rustc_session::{declare_lint, declare_lint_pass, impl_lint_pass};
use rustc_span::edition::Edition::Edition2015;
use rustc_span::{BytePos, Span, Symbol, kw, sym};
use tracing::instrument;
@ -1032,6 +1034,31 @@ pub(crate) struct UnusedParens {
/// `1 as (i32) < 2` parses to ExprKind::Lt
/// `1 as i32 < 2` parses to i32::<2[missing angle bracket]
parens_in_cast_in_lt: Vec<ast::NodeId>,
/// Ty nodes in this map are in TypeNoBounds position. Any bounds they
/// contain may be ambiguous w/r/t trailing `+` operators.
in_no_bounds_pos: FxHashMap<ast::NodeId, NoBoundsException>,
}
/// Whether parentheses may be omitted from a type without resulting in ambiguity.
///
/// ```
/// type Example = Box<dyn Fn() -> &'static (dyn Send) + Sync>;
/// ```
///
/// Here, `&'static (dyn Send) + Sync` is a `TypeNoBounds`. As such, it may not directly
/// contain `ImplTraitType` or `TraitObjectType` which is why `(dyn Send)` is parenthesized.
/// However, an exception is made for `ImplTraitTypeOneBound` and `TraitObjectTypeOneBound`.
/// The following is accepted because there is no `+`.
///
/// ```
/// type Example = Box<dyn Fn() -> &'static dyn Send>;
/// ```
enum NoBoundsException {
/// The type must be parenthesized.
None,
/// The type is the last bound of the containing type expression. If it has exactly one bound,
/// parentheses around the type are unnecessary.
OneBound,
}
impl_lint_pass!(UnusedParens => [UNUSED_PARENS]);
@ -1275,23 +1302,100 @@ impl EarlyLintPass for UnusedParens {
);
}
ast::TyKind::Paren(r) => {
match &r.kind {
ast::TyKind::TraitObject(..) => {}
ast::TyKind::BareFn(b)
if self.with_self_ty_parens && b.generic_params.len() > 0 => {}
ast::TyKind::ImplTrait(_, bounds) if bounds.len() > 1 => {}
_ => {
let spans = if !ty.span.from_expansion() {
let unused_parens = match &r.kind {
ast::TyKind::ImplTrait(_, bounds) | ast::TyKind::TraitObject(bounds, _) => {
match self.in_no_bounds_pos.get(&ty.id) {
Some(NoBoundsException::None) => false,
Some(NoBoundsException::OneBound) => bounds.len() <= 1,
None => true,
}
}
ast::TyKind::BareFn(b) => {
!self.with_self_ty_parens || b.generic_params.is_empty()
}
_ => true,
};
if unused_parens {
let spans = (!ty.span.from_expansion())
.then(|| {
r.span
.find_ancestor_inside(ty.span)
.map(|r| (ty.span.with_hi(r.lo()), ty.span.with_lo(r.hi())))
})
.flatten();
self.emit_unused_delims(cx, ty.span, spans, "type", (false, false), false);
}
self.with_self_ty_parens = false;
}
ast::TyKind::Ref(_, mut_ty) | ast::TyKind::Ptr(mut_ty) => {
self.in_no_bounds_pos.insert(mut_ty.ty.id, NoBoundsException::OneBound);
}
ast::TyKind::TraitObject(bounds, _) | ast::TyKind::ImplTrait(_, bounds) => {
for i in 0..bounds.len() {
let is_last = i == bounds.len() - 1;
if let ast::GenericBound::Trait(poly_trait_ref) = &bounds[i] {
let fn_with_explicit_ret_ty = if let [.., segment] =
&*poly_trait_ref.trait_ref.path.segments
&& let Some(args) = segment.args.as_ref()
&& let ast::GenericArgs::Parenthesized(paren_args) = &**args
&& let ast::FnRetTy::Ty(ret_ty) = &paren_args.output
{
self.in_no_bounds_pos.insert(
ret_ty.id,
if is_last {
NoBoundsException::OneBound
} else {
NoBoundsException::None
},
);
true
} else {
None
false
};
self.emit_unused_delims(cx, ty.span, spans, "type", (false, false), false);
// In edition 2015, dyn is a contextual keyword and `dyn::foo::Bar` is
// parsed as a path, so parens are necessary to disambiguate. See
// - tests/ui/lint/unused/unused-parens-trait-obj-e2015.rs and
// - https://doc.rust-lang.org/reference/types/trait-object.html#r-type.trait-object.syntax-edition2018
let dyn2015_exception = cx.sess().psess.edition == Edition2015
&& matches!(ty.kind, ast::TyKind::TraitObject(..))
&& i == 0
&& poly_trait_ref
.trait_ref
.path
.segments
.first()
.map(|s| s.ident.name == kw::PathRoot)
.unwrap_or(false);
if let ast::Parens::Yes = poly_trait_ref.parens
&& (is_last || !fn_with_explicit_ret_ty)
&& !dyn2015_exception
{
let s = poly_trait_ref.span;
let spans = (!s.from_expansion()).then(|| {
(
s.with_hi(s.lo() + rustc_span::BytePos(1)),
s.with_lo(s.hi() - rustc_span::BytePos(1)),
)
});
self.emit_unused_delims(
cx,
poly_trait_ref.span,
spans,
"type",
(false, false),
false,
);
}
}
}
self.with_self_ty_parens = false;
}
_ => {}
}
@ -1301,6 +1405,10 @@ impl EarlyLintPass for UnusedParens {
<Self as UnusedDelimLint>::check_item(self, cx, item)
}
fn check_item_post(&mut self, _: &EarlyContext<'_>, _: &rustc_ast::Item) {
self.in_no_bounds_pos.clear();
}
fn enter_where_predicate(&mut self, _: &EarlyContext<'_>, pred: &ast::WherePredicate) {
use rustc_ast::{WhereBoundPredicate, WherePredicateKind};
if let WherePredicateKind::BoundPredicate(WhereBoundPredicate {

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)
@ -832,7 +849,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))
@ -897,10 +914,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
@ -909,7 +926,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)
@ -919,10 +936,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)?;
@ -1078,7 +1099,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()?;
@ -1104,7 +1125,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()? {
@ -1171,7 +1192,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) {
@ -1191,7 +1212,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))
}

View file

@ -3832,6 +3832,7 @@ fn mk_where_bound_predicate(
ref_id: DUMMY_NODE_ID,
},
span: DUMMY_SP,
parens: ast::Parens::No,
})],
};

View file

@ -347,7 +347,7 @@ impl dyn Error {
/// let b = B(Some(Box::new(A)));
///
/// // let err : Box<Error> = b.into(); // or
/// let err = &b as &(dyn Error);
/// let err = &b as &dyn Error;
///
/// let mut iter = err.sources();
///

View file

@ -1,5 +1,6 @@
//@ run-rustfix
#![feature(impl_trait_in_fn_trait_return)]
#![deny(unused_parens)]
#![allow(while_true)] // for rustfix
@ -16,11 +17,11 @@ fn bar(y: bool) -> X {
return X { y }; //~ ERROR unnecessary parentheses around `return` value
}
pub fn unused_parens_around_return_type() -> u32 { //~ ERROR unnecessary parentheses around type
pub fn around_return_type() -> u32 { //~ ERROR unnecessary parentheses around type
panic!()
}
pub fn unused_parens_around_block_return() -> u32 {
pub fn around_block_return() -> u32 {
let _foo = {
5 //~ ERROR unnecessary parentheses around block return value
};
@ -31,10 +32,90 @@ pub trait Trait {
fn test(&self);
}
pub fn passes_unused_parens_lint() -> &'static (dyn Trait) {
pub fn around_multi_bound_ref() -> &'static (dyn Trait + Send) {
panic!()
}
//~v ERROR unnecessary parentheses around type
pub fn around_single_bound_ref() -> &'static dyn Trait {
panic!()
}
pub fn around_multi_bound_ptr() -> *const (dyn Trait + Send) {
panic!()
}
//~v ERROR unnecessary parentheses around type
pub fn around_single_bound_ptr() -> *const dyn Trait {
panic!()
}
pub fn around_multi_bound_dyn_fn_output() -> &'static dyn FnOnce() -> (impl Send + Sync) {
&|| ()
}
//~v ERROR unnecessary parentheses around type
pub fn around_single_bound_dyn_fn_output() -> &'static dyn FnOnce() -> impl Send {
&|| ()
}
pub fn around_dyn_fn_output_given_more_bounds() -> &'static (dyn FnOnce() -> (impl Send) + Sync) {
&|| ()
}
pub fn around_multi_bound_impl_fn_output() -> impl FnOnce() -> (impl Send + Sync) {
|| ()
}
//~v ERROR unnecessary parentheses around type
pub fn around_single_bound_impl_fn_output() -> impl FnOnce() -> impl Send {
|| ()
}
pub fn around_impl_fn_output_given_more_bounds() -> impl FnOnce() -> (impl Send) + Sync {
|| ()
}
//~v ERROR unnecessary parentheses around type
pub fn around_dyn_bound() -> &'static dyn FnOnce() {
&|| ()
}
//~v ERROR unnecessary parentheses around type
pub fn around_impl_trait_bound() -> impl FnOnce() {
|| ()
}
// these parens aren't strictly required but they help disambiguate => no lint
pub fn around_fn_bound_with_explicit_ret_ty() -> impl (Fn() -> ()) + Send {
|| ()
}
//~v ERROR unnecessary parentheses around type
pub fn around_fn_bound_with_implicit_ret_ty() -> impl Fn() + Send {
|| ()
}
//~v ERROR unnecessary parentheses around type
pub fn around_last_fn_bound_with_explicit_ret_ty() -> impl Send + Fn() -> () {
|| ()
}
//~v ERROR unnecessary parentheses around type
pub fn around_regular_bound1() -> &'static (dyn Send + Sync) {
&|| ()
}
//~v ERROR unnecessary parentheses around type
pub fn around_regular_bound2() -> &'static (dyn Send + Sync) {
&|| ()
}
//~v ERROR unnecessary parentheses around type
pub fn around_regular_bound3() -> &'static (dyn Send + ::std::marker::Sync) {
&|| ()
}
pub fn parens_with_keyword(e: &[()]) -> i32 {
if true {} //~ ERROR unnecessary parentheses around `if`
while true {} //~ ERROR unnecessary parentheses around `while`

View file

@ -1,5 +1,6 @@
//@ run-rustfix
#![feature(impl_trait_in_fn_trait_return)]
#![deny(unused_parens)]
#![allow(while_true)] // for rustfix
@ -16,11 +17,11 @@ fn bar(y: bool) -> X {
return (X { y }); //~ ERROR unnecessary parentheses around `return` value
}
pub fn unused_parens_around_return_type() -> (u32) { //~ ERROR unnecessary parentheses around type
pub fn around_return_type() -> (u32) { //~ ERROR unnecessary parentheses around type
panic!()
}
pub fn unused_parens_around_block_return() -> u32 {
pub fn around_block_return() -> u32 {
let _foo = {
(5) //~ ERROR unnecessary parentheses around block return value
};
@ -31,10 +32,90 @@ pub trait Trait {
fn test(&self);
}
pub fn passes_unused_parens_lint() -> &'static (dyn Trait) {
pub fn around_multi_bound_ref() -> &'static (dyn Trait + Send) {
panic!()
}
//~v ERROR unnecessary parentheses around type
pub fn around_single_bound_ref() -> &'static (dyn Trait) {
panic!()
}
pub fn around_multi_bound_ptr() -> *const (dyn Trait + Send) {
panic!()
}
//~v ERROR unnecessary parentheses around type
pub fn around_single_bound_ptr() -> *const (dyn Trait) {
panic!()
}
pub fn around_multi_bound_dyn_fn_output() -> &'static dyn FnOnce() -> (impl Send + Sync) {
&|| ()
}
//~v ERROR unnecessary parentheses around type
pub fn around_single_bound_dyn_fn_output() -> &'static dyn FnOnce() -> (impl Send) {
&|| ()
}
pub fn around_dyn_fn_output_given_more_bounds() -> &'static (dyn FnOnce() -> (impl Send) + Sync) {
&|| ()
}
pub fn around_multi_bound_impl_fn_output() -> impl FnOnce() -> (impl Send + Sync) {
|| ()
}
//~v ERROR unnecessary parentheses around type
pub fn around_single_bound_impl_fn_output() -> impl FnOnce() -> (impl Send) {
|| ()
}
pub fn around_impl_fn_output_given_more_bounds() -> impl FnOnce() -> (impl Send) + Sync {
|| ()
}
//~v ERROR unnecessary parentheses around type
pub fn around_dyn_bound() -> &'static dyn (FnOnce()) {
&|| ()
}
//~v ERROR unnecessary parentheses around type
pub fn around_impl_trait_bound() -> impl (FnOnce()) {
|| ()
}
// these parens aren't strictly required but they help disambiguate => no lint
pub fn around_fn_bound_with_explicit_ret_ty() -> impl (Fn() -> ()) + Send {
|| ()
}
//~v ERROR unnecessary parentheses around type
pub fn around_fn_bound_with_implicit_ret_ty() -> impl (Fn()) + Send {
|| ()
}
//~v ERROR unnecessary parentheses around type
pub fn around_last_fn_bound_with_explicit_ret_ty() -> impl Send + (Fn() -> ()) {
|| ()
}
//~v ERROR unnecessary parentheses around type
pub fn around_regular_bound1() -> &'static (dyn (Send) + Sync) {
&|| ()
}
//~v ERROR unnecessary parentheses around type
pub fn around_regular_bound2() -> &'static (dyn Send + (Sync)) {
&|| ()
}
//~v ERROR unnecessary parentheses around type
pub fn around_regular_bound3() -> &'static (dyn Send + (::std::marker::Sync)) {
&|| ()
}
pub fn parens_with_keyword(e: &[()]) -> i32 {
if(true) {} //~ ERROR unnecessary parentheses around `if`
while(true) {} //~ ERROR unnecessary parentheses around `while`

View file

@ -1,11 +1,11 @@
error: unnecessary parentheses around `return` value
--> $DIR/lint-unnecessary-parens.rs:13:12
--> $DIR/lint-unnecessary-parens.rs:14:12
|
LL | return (1);
| ^ ^
|
note: the lint level is defined here
--> $DIR/lint-unnecessary-parens.rs:3:9
--> $DIR/lint-unnecessary-parens.rs:4:9
|
LL | #![deny(unused_parens)]
| ^^^^^^^^^^^^^
@ -16,7 +16,7 @@ LL + return 1;
|
error: unnecessary parentheses around `return` value
--> $DIR/lint-unnecessary-parens.rs:16:12
--> $DIR/lint-unnecessary-parens.rs:17:12
|
LL | return (X { y });
| ^ ^
@ -28,19 +28,19 @@ LL + return X { y };
|
error: unnecessary parentheses around type
--> $DIR/lint-unnecessary-parens.rs:19:46
--> $DIR/lint-unnecessary-parens.rs:20:32
|
LL | pub fn unused_parens_around_return_type() -> (u32) {
| ^ ^
LL | pub fn around_return_type() -> (u32) {
| ^ ^
|
help: remove these parentheses
|
LL - pub fn unused_parens_around_return_type() -> (u32) {
LL + pub fn unused_parens_around_return_type() -> u32 {
LL - pub fn around_return_type() -> (u32) {
LL + pub fn around_return_type() -> u32 {
|
error: unnecessary parentheses around block return value
--> $DIR/lint-unnecessary-parens.rs:25:9
--> $DIR/lint-unnecessary-parens.rs:26:9
|
LL | (5)
| ^ ^
@ -52,7 +52,7 @@ LL + 5
|
error: unnecessary parentheses around block return value
--> $DIR/lint-unnecessary-parens.rs:27:5
--> $DIR/lint-unnecessary-parens.rs:28:5
|
LL | (5)
| ^ ^
@ -63,8 +63,140 @@ LL - (5)
LL + 5
|
error: unnecessary parentheses around type
--> $DIR/lint-unnecessary-parens.rs:40:46
|
LL | pub fn around_single_bound_ref() -> &'static (dyn Trait) {
| ^ ^
|
help: remove these parentheses
|
LL - pub fn around_single_bound_ref() -> &'static (dyn Trait) {
LL + pub fn around_single_bound_ref() -> &'static dyn Trait {
|
error: unnecessary parentheses around type
--> $DIR/lint-unnecessary-parens.rs:49:44
|
LL | pub fn around_single_bound_ptr() -> *const (dyn Trait) {
| ^ ^
|
help: remove these parentheses
|
LL - pub fn around_single_bound_ptr() -> *const (dyn Trait) {
LL + pub fn around_single_bound_ptr() -> *const dyn Trait {
|
error: unnecessary parentheses around type
--> $DIR/lint-unnecessary-parens.rs:58:72
|
LL | pub fn around_single_bound_dyn_fn_output() -> &'static dyn FnOnce() -> (impl Send) {
| ^ ^
|
help: remove these parentheses
|
LL - pub fn around_single_bound_dyn_fn_output() -> &'static dyn FnOnce() -> (impl Send) {
LL + pub fn around_single_bound_dyn_fn_output() -> &'static dyn FnOnce() -> impl Send {
|
error: unnecessary parentheses around type
--> $DIR/lint-unnecessary-parens.rs:71:65
|
LL | pub fn around_single_bound_impl_fn_output() -> impl FnOnce() -> (impl Send) {
| ^ ^
|
help: remove these parentheses
|
LL - pub fn around_single_bound_impl_fn_output() -> impl FnOnce() -> (impl Send) {
LL + pub fn around_single_bound_impl_fn_output() -> impl FnOnce() -> impl Send {
|
error: unnecessary parentheses around type
--> $DIR/lint-unnecessary-parens.rs:80:43
|
LL | pub fn around_dyn_bound() -> &'static dyn (FnOnce()) {
| ^ ^
|
help: remove these parentheses
|
LL - pub fn around_dyn_bound() -> &'static dyn (FnOnce()) {
LL + pub fn around_dyn_bound() -> &'static dyn FnOnce() {
|
error: unnecessary parentheses around type
--> $DIR/lint-unnecessary-parens.rs:85:42
|
LL | pub fn around_impl_trait_bound() -> impl (FnOnce()) {
| ^ ^
|
help: remove these parentheses
|
LL - pub fn around_impl_trait_bound() -> impl (FnOnce()) {
LL + pub fn around_impl_trait_bound() -> impl FnOnce() {
|
error: unnecessary parentheses around type
--> $DIR/lint-unnecessary-parens.rs:95:55
|
LL | pub fn around_fn_bound_with_implicit_ret_ty() -> impl (Fn()) + Send {
| ^ ^
|
help: remove these parentheses
|
LL - pub fn around_fn_bound_with_implicit_ret_ty() -> impl (Fn()) + Send {
LL + pub fn around_fn_bound_with_implicit_ret_ty() -> impl Fn() + Send {
|
error: unnecessary parentheses around type
--> $DIR/lint-unnecessary-parens.rs:100:67
|
LL | pub fn around_last_fn_bound_with_explicit_ret_ty() -> impl Send + (Fn() -> ()) {
| ^ ^
|
help: remove these parentheses
|
LL - pub fn around_last_fn_bound_with_explicit_ret_ty() -> impl Send + (Fn() -> ()) {
LL + pub fn around_last_fn_bound_with_explicit_ret_ty() -> impl Send + Fn() -> () {
|
error: unnecessary parentheses around type
--> $DIR/lint-unnecessary-parens.rs:105:49
|
LL | pub fn around_regular_bound1() -> &'static (dyn (Send) + Sync) {
| ^ ^
|
help: remove these parentheses
|
LL - pub fn around_regular_bound1() -> &'static (dyn (Send) + Sync) {
LL + pub fn around_regular_bound1() -> &'static (dyn Send + Sync) {
|
error: unnecessary parentheses around type
--> $DIR/lint-unnecessary-parens.rs:110:56
|
LL | pub fn around_regular_bound2() -> &'static (dyn Send + (Sync)) {
| ^ ^
|
help: remove these parentheses
|
LL - pub fn around_regular_bound2() -> &'static (dyn Send + (Sync)) {
LL + pub fn around_regular_bound2() -> &'static (dyn Send + Sync) {
|
error: unnecessary parentheses around type
--> $DIR/lint-unnecessary-parens.rs:115:56
|
LL | pub fn around_regular_bound3() -> &'static (dyn Send + (::std::marker::Sync)) {
| ^ ^
|
help: remove these parentheses
|
LL - pub fn around_regular_bound3() -> &'static (dyn Send + (::std::marker::Sync)) {
LL + pub fn around_regular_bound3() -> &'static (dyn Send + ::std::marker::Sync) {
|
error: unnecessary parentheses around `if` condition
--> $DIR/lint-unnecessary-parens.rs:39:7
--> $DIR/lint-unnecessary-parens.rs:120:7
|
LL | if(true) {}
| ^ ^
@ -76,7 +208,7 @@ LL + if true {}
|
error: unnecessary parentheses around `while` condition
--> $DIR/lint-unnecessary-parens.rs:40:10
--> $DIR/lint-unnecessary-parens.rs:121:10
|
LL | while(true) {}
| ^ ^
@ -88,7 +220,7 @@ LL + while true {}
|
error: unnecessary parentheses around `for` iterator expression
--> $DIR/lint-unnecessary-parens.rs:41:13
--> $DIR/lint-unnecessary-parens.rs:122:13
|
LL | for _ in(e) {}
| ^ ^
@ -100,7 +232,7 @@ LL + for _ in e {}
|
error: unnecessary parentheses around `match` scrutinee expression
--> $DIR/lint-unnecessary-parens.rs:42:10
--> $DIR/lint-unnecessary-parens.rs:123:10
|
LL | match(1) { _ => ()}
| ^ ^
@ -112,7 +244,7 @@ LL + match 1 { _ => ()}
|
error: unnecessary parentheses around `return` value
--> $DIR/lint-unnecessary-parens.rs:43:11
--> $DIR/lint-unnecessary-parens.rs:124:11
|
LL | return(1);
| ^ ^
@ -124,7 +256,7 @@ LL + return 1;
|
error: unnecessary parentheses around assigned value
--> $DIR/lint-unnecessary-parens.rs:74:31
--> $DIR/lint-unnecessary-parens.rs:155:31
|
LL | pub const CONST_ITEM: usize = (10);
| ^ ^
@ -136,7 +268,7 @@ LL + pub const CONST_ITEM: usize = 10;
|
error: unnecessary parentheses around assigned value
--> $DIR/lint-unnecessary-parens.rs:75:33
--> $DIR/lint-unnecessary-parens.rs:156:33
|
LL | pub static STATIC_ITEM: usize = (10);
| ^ ^
@ -148,7 +280,7 @@ LL + pub static STATIC_ITEM: usize = 10;
|
error: unnecessary parentheses around function argument
--> $DIR/lint-unnecessary-parens.rs:79:9
--> $DIR/lint-unnecessary-parens.rs:160:9
|
LL | bar((true));
| ^ ^
@ -160,7 +292,7 @@ LL + bar(true);
|
error: unnecessary parentheses around `if` condition
--> $DIR/lint-unnecessary-parens.rs:81:8
--> $DIR/lint-unnecessary-parens.rs:162:8
|
LL | if (true) {}
| ^ ^
@ -172,7 +304,7 @@ LL + if true {}
|
error: unnecessary parentheses around `while` condition
--> $DIR/lint-unnecessary-parens.rs:82:11
--> $DIR/lint-unnecessary-parens.rs:163:11
|
LL | while (true) {}
| ^ ^
@ -184,7 +316,7 @@ LL + while true {}
|
error: unnecessary parentheses around `match` scrutinee expression
--> $DIR/lint-unnecessary-parens.rs:83:11
--> $DIR/lint-unnecessary-parens.rs:164:11
|
LL | match (true) {
| ^ ^
@ -196,7 +328,7 @@ LL + match true {
|
error: unnecessary parentheses around `let` scrutinee expression
--> $DIR/lint-unnecessary-parens.rs:86:16
--> $DIR/lint-unnecessary-parens.rs:167:16
|
LL | if let 1 = (1) {}
| ^ ^
@ -208,7 +340,7 @@ LL + if let 1 = 1 {}
|
error: unnecessary parentheses around `let` scrutinee expression
--> $DIR/lint-unnecessary-parens.rs:87:19
--> $DIR/lint-unnecessary-parens.rs:168:19
|
LL | while let 1 = (2) {}
| ^ ^
@ -220,7 +352,7 @@ LL + while let 1 = 2 {}
|
error: unnecessary parentheses around method argument
--> $DIR/lint-unnecessary-parens.rs:103:24
--> $DIR/lint-unnecessary-parens.rs:184:24
|
LL | X { y: false }.foo((true));
| ^ ^
@ -232,7 +364,7 @@ LL + X { y: false }.foo(true);
|
error: unnecessary parentheses around assigned value
--> $DIR/lint-unnecessary-parens.rs:105:18
--> $DIR/lint-unnecessary-parens.rs:186:18
|
LL | let mut _a = (0);
| ^ ^
@ -244,7 +376,7 @@ LL + let mut _a = 0;
|
error: unnecessary parentheses around assigned value
--> $DIR/lint-unnecessary-parens.rs:106:10
--> $DIR/lint-unnecessary-parens.rs:187:10
|
LL | _a = (0);
| ^ ^
@ -256,7 +388,7 @@ LL + _a = 0;
|
error: unnecessary parentheses around assigned value
--> $DIR/lint-unnecessary-parens.rs:107:11
--> $DIR/lint-unnecessary-parens.rs:188:11
|
LL | _a += (1);
| ^ ^
@ -268,7 +400,7 @@ LL + _a += 1;
|
error: unnecessary parentheses around pattern
--> $DIR/lint-unnecessary-parens.rs:109:8
--> $DIR/lint-unnecessary-parens.rs:190:8
|
LL | let(mut _a) = 3;
| ^ ^
@ -280,7 +412,7 @@ LL + let mut _a = 3;
|
error: unnecessary parentheses around pattern
--> $DIR/lint-unnecessary-parens.rs:110:9
--> $DIR/lint-unnecessary-parens.rs:191:9
|
LL | let (mut _a) = 3;
| ^ ^
@ -292,7 +424,7 @@ LL + let mut _a = 3;
|
error: unnecessary parentheses around pattern
--> $DIR/lint-unnecessary-parens.rs:111:8
--> $DIR/lint-unnecessary-parens.rs:192:8
|
LL | let( mut _a) = 3;
| ^^ ^
@ -304,7 +436,7 @@ LL + let mut _a = 3;
|
error: unnecessary parentheses around pattern
--> $DIR/lint-unnecessary-parens.rs:113:8
--> $DIR/lint-unnecessary-parens.rs:194:8
|
LL | let(_a) = 3;
| ^ ^
@ -316,7 +448,7 @@ LL + let _a = 3;
|
error: unnecessary parentheses around pattern
--> $DIR/lint-unnecessary-parens.rs:114:9
--> $DIR/lint-unnecessary-parens.rs:195:9
|
LL | let (_a) = 3;
| ^ ^
@ -328,7 +460,7 @@ LL + let _a = 3;
|
error: unnecessary parentheses around pattern
--> $DIR/lint-unnecessary-parens.rs:115:8
--> $DIR/lint-unnecessary-parens.rs:196:8
|
LL | let( _a) = 3;
| ^^ ^
@ -340,7 +472,7 @@ LL + let _a = 3;
|
error: unnecessary parentheses around block return value
--> $DIR/lint-unnecessary-parens.rs:121:9
--> $DIR/lint-unnecessary-parens.rs:202:9
|
LL | (unit!() - One)
| ^ ^
@ -352,7 +484,7 @@ LL + unit!() - One
|
error: unnecessary parentheses around block return value
--> $DIR/lint-unnecessary-parens.rs:123:9
--> $DIR/lint-unnecessary-parens.rs:204:9
|
LL | (unit![] - One)
| ^ ^
@ -364,7 +496,7 @@ LL + unit![] - One
|
error: unnecessary parentheses around block return value
--> $DIR/lint-unnecessary-parens.rs:126:9
--> $DIR/lint-unnecessary-parens.rs:207:9
|
LL | (unit! {} - One)
| ^ ^
@ -376,7 +508,7 @@ LL + unit! {} - One
|
error: unnecessary parentheses around assigned value
--> $DIR/lint-unnecessary-parens.rs:131:14
--> $DIR/lint-unnecessary-parens.rs:212:14
|
LL | let _r = (&x);
| ^ ^
@ -388,7 +520,7 @@ LL + let _r = &x;
|
error: unnecessary parentheses around assigned value
--> $DIR/lint-unnecessary-parens.rs:132:14
--> $DIR/lint-unnecessary-parens.rs:213:14
|
LL | let _r = (&mut x);
| ^ ^
@ -399,5 +531,5 @@ LL - let _r = (&mut x);
LL + let _r = &mut x;
|
error: aborting due to 33 previous errors
error: aborting due to 44 previous errors

View file

@ -14,7 +14,7 @@ where
trait Hello<T> {}
fn with_dyn_bound<T>()
where
(dyn Hello<(for<'b> fn(&'b ()))>): Hello<T> //~ ERROR unnecessary parentheses around type
dyn Hello<(for<'b> fn(&'b ()))>: Hello<T> //~ ERROR unnecessary parentheses around type
{}
fn main() {

View file

@ -17,15 +17,15 @@ LL + for<'b> for<'a> fn(Inv<'a>): Trait<'b>,
|
error: unnecessary parentheses around type
--> $DIR/issue-105061-should-lint.rs:17:16
--> $DIR/issue-105061-should-lint.rs:17:15
|
LL | (dyn Hello<(for<'b> fn(&'b ()))>): Hello<T>
| ^ ^
LL | dyn Hello<(for<'b> fn(&'b ()))>: Hello<T>
| ^ ^
|
help: remove these parentheses
|
LL - (dyn Hello<(for<'b> fn(&'b ()))>): Hello<T>
LL + (dyn Hello<for<'b> fn(&'b ())>): Hello<T>
LL - dyn Hello<(for<'b> fn(&'b ()))>: Hello<T>
LL + dyn Hello<for<'b> fn(&'b ())>: Hello<T>
|
error: aborting due to 2 previous errors

View file

@ -0,0 +1,27 @@
//@ revisions: edition2015 edition2018
//@[edition2015] check-pass
//@[edition2015] edition: 2015
//@[edition2018] run-rustfix
//@[edition2018] edition: 2018
#![deny(unused_parens)]
#[allow(unused)]
macro_rules! edition2015_only {
() => {
mod dyn {
pub type IsAContextualKeywordIn2015 = ();
}
pub type DynIsAContextualKeywordIn2015A = dyn::IsAContextualKeywordIn2015;
}
}
#[cfg(edition2015)]
edition2015_only!();
// there's a lint for 2018 and later only because of how dyn is parsed in edition 2015
//[edition2018]~v ERROR unnecessary parentheses around type
pub type DynIsAContextualKeywordIn2015B = Box<dyn ::std::ops::Fn()>;
fn main() {}

View file

@ -0,0 +1,19 @@
error: unnecessary parentheses around type
--> $DIR/unused-parens-trait-obj.rs:25:51
|
LL | pub type DynIsAContextualKeywordIn2015B = Box<dyn (::std::ops::Fn())>;
| ^ ^
|
note: the lint level is defined here
--> $DIR/unused-parens-trait-obj.rs:7:9
|
LL | #![deny(unused_parens)]
| ^^^^^^^^^^^^^
help: remove these parentheses
|
LL - pub type DynIsAContextualKeywordIn2015B = Box<dyn (::std::ops::Fn())>;
LL + pub type DynIsAContextualKeywordIn2015B = Box<dyn ::std::ops::Fn()>;
|
error: aborting due to 1 previous error

View file

@ -0,0 +1,27 @@
//@ revisions: edition2015 edition2018
//@[edition2015] check-pass
//@[edition2015] edition: 2015
//@[edition2018] run-rustfix
//@[edition2018] edition: 2018
#![deny(unused_parens)]
#[allow(unused)]
macro_rules! edition2015_only {
() => {
mod dyn {
pub type IsAContextualKeywordIn2015 = ();
}
pub type DynIsAContextualKeywordIn2015A = dyn::IsAContextualKeywordIn2015;
}
}
#[cfg(edition2015)]
edition2015_only!();
// there's a lint for 2018 and later only because of how dyn is parsed in edition 2015
//[edition2018]~v ERROR unnecessary parentheses around type
pub type DynIsAContextualKeywordIn2015B = Box<dyn (::std::ops::Fn())>;
fn main() {}

View file

@ -31,7 +31,7 @@ fn dyn_fn_with_params() {
#[test]
fn call_fn_trait() {
let f: &(dyn Fn()) = &(|| {}) as _;
let f: &dyn Fn() = &(|| {}) as _;
f.call(());
}
@ -47,7 +47,7 @@ fn use_fnmut<F: FnMut()>(mut f: F) {
#[test]
fn fn_to_fnmut() {
let f: &(dyn Fn()) = &(|| {}) as _;
let f: &dyn Fn() = &(|| {}) as _;
use_fnmut(f);
}

View file

@ -7,7 +7,7 @@ static BYTE: u8 = 33;
fn main() {
let x: &(dyn 'static + Display) = &BYTE;
let y: Box<dyn Display + 'static> = Box::new(BYTE);
let _: &dyn (Display) = &BYTE;
let _: &dyn Display = &BYTE;
let _: &dyn (::std::fmt::Display) = &BYTE;
let xstr = format!("{}", x);
let ystr = format!("{}", y);

View file

@ -10,7 +10,7 @@ pub mod Foo {
}
mod Bar {
impl<'a> dyn (crate::Foo::Trait) + 'a {
impl<'a> dyn crate::Foo::Trait + 'a {
fn bar(&self) { self.foo() }
}
}