Skip to content

Commit cf463de

Browse files
Benjamin Schulzbenschulz
authored andcommitted
Detect more cases of unused_parens around types
1 parent e61dd43 commit cf463de

12 files changed

+476
-57
lines changed

compiler/rustc_lint/src/unused.rs

Lines changed: 86 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,15 @@ use std::iter;
33
use rustc_ast::util::{classify, parser};
44
use rustc_ast::{self as ast, ExprKind, HasAttrs as _, StmtKind};
55
use rustc_attr_data_structures::{AttributeKind, find_attr};
6+
use rustc_data_structures::fx::FxHashMap;
67
use rustc_errors::{MultiSpan, pluralize};
78
use rustc_hir::def::{DefKind, Res};
89
use rustc_hir::def_id::DefId;
910
use rustc_hir::{self as hir, LangItem};
1011
use rustc_infer::traits::util::elaborate;
1112
use rustc_middle::ty::{self, Ty, adjustment};
1213
use rustc_session::{declare_lint, declare_lint_pass, impl_lint_pass};
14+
use rustc_span::edition::Edition::Edition2015;
1315
use rustc_span::{BytePos, Span, Symbol, kw, sym};
1416
use tracing::instrument;
1517

@@ -1032,6 +1034,14 @@ pub(crate) struct UnusedParens {
10321034
/// `1 as (i32) < 2` parses to ExprKind::Lt
10331035
/// `1 as i32 < 2` parses to i32::<2[missing angle bracket]
10341036
parens_in_cast_in_lt: Vec<ast::NodeId>,
1037+
/// Ty nodes in this map are in TypeNoBounds position. Any bounds they
1038+
/// contain may be ambiguous w/r/t trailing `+` operators.
1039+
in_no_bounds_pos: FxHashMap<ast::NodeId, NoBoundsException>,
1040+
}
1041+
1042+
enum NoBoundsException {
1043+
None,
1044+
OneBound,
10351045
}
10361046

10371047
impl_lint_pass!(UnusedParens => [UNUSED_PARENS]);
@@ -1276,10 +1286,12 @@ impl EarlyLintPass for UnusedParens {
12761286
}
12771287
ast::TyKind::Paren(r) => {
12781288
match &r.kind {
1279-
ast::TyKind::TraitObject(..) => {}
1289+
ast::TyKind::ImplTrait(_, bounds) | ast::TyKind::TraitObject(bounds, _)
1290+
if self.in_no_bounds_pos.get(&ty.id).is_some_and(|exception| {
1291+
matches!(exception, NoBoundsException::None) || bounds.len() > 1
1292+
}) => {}
12801293
ast::TyKind::BareFn(b)
12811294
if self.with_self_ty_parens && b.generic_params.len() > 0 => {}
1282-
ast::TyKind::ImplTrait(_, bounds) if bounds.len() > 1 => {}
12831295
_ => {
12841296
let spans = if !ty.span.from_expansion() {
12851297
r.span
@@ -1293,6 +1305,74 @@ impl EarlyLintPass for UnusedParens {
12931305
}
12941306
self.with_self_ty_parens = false;
12951307
}
1308+
ast::TyKind::Ref(_, mut_ty) | ast::TyKind::Ptr(mut_ty) => {
1309+
self.in_no_bounds_pos.insert(mut_ty.ty.id, NoBoundsException::OneBound);
1310+
}
1311+
ast::TyKind::TraitObject(bounds, _) | ast::TyKind::ImplTrait(_, bounds) => {
1312+
for i in 0..bounds.len() {
1313+
let last = i == bounds.len() - 1;
1314+
1315+
if let ast::GenericBound::Trait(poly_trait_ref) = &bounds[i] {
1316+
let parenthesized = cx
1317+
.sess()
1318+
.source_map()
1319+
.span_to_snippet(poly_trait_ref.span)
1320+
.map(|snip| snip.starts_with('(') && snip.ends_with(')'))
1321+
.unwrap_or(false);
1322+
1323+
let fn_with_explicit_ret_ty = if let [.., segment] =
1324+
&*poly_trait_ref.trait_ref.path.segments
1325+
&& let Some(args) = segment.args.as_ref()
1326+
&& let ast::GenericArgs::Parenthesized(paren_args) = &**args
1327+
&& let ast::FnRetTy::Ty(ret_ty) = &paren_args.output
1328+
{
1329+
self.in_no_bounds_pos.insert(
1330+
ret_ty.id,
1331+
if last {
1332+
NoBoundsException::OneBound
1333+
} else {
1334+
NoBoundsException::None
1335+
},
1336+
);
1337+
1338+
true
1339+
} else {
1340+
false
1341+
};
1342+
1343+
let dyn2015_exception = cx.sess().psess.edition == Edition2015
1344+
&& matches!(ty.kind, ast::TyKind::TraitObject(..))
1345+
&& i == 0
1346+
&& poly_trait_ref
1347+
.trait_ref
1348+
.path
1349+
.segments
1350+
.first()
1351+
.map(|s| s.ident.name == kw::PathRoot)
1352+
.unwrap_or(false);
1353+
1354+
if parenthesized && (last || !fn_with_explicit_ret_ty) && !dyn2015_exception
1355+
{
1356+
let s = poly_trait_ref.span;
1357+
let spans = (!s.from_expansion()).then(|| {
1358+
(
1359+
s.with_hi(s.lo() + rustc_span::BytePos(1)),
1360+
s.with_lo(s.hi() - rustc_span::BytePos(1)),
1361+
)
1362+
});
1363+
1364+
self.emit_unused_delims(
1365+
cx,
1366+
poly_trait_ref.span,
1367+
spans,
1368+
"type",
1369+
(false, false),
1370+
false,
1371+
);
1372+
}
1373+
}
1374+
}
1375+
}
12961376
_ => {}
12971377
}
12981378
}
@@ -1301,6 +1381,10 @@ impl EarlyLintPass for UnusedParens {
13011381
<Self as UnusedDelimLint>::check_item(self, cx, item)
13021382
}
13031383

1384+
fn check_item_post(&mut self, _: &EarlyContext<'_>, _: &rustc_ast::Item) {
1385+
self.in_no_bounds_pos.clear();
1386+
}
1387+
13041388
fn enter_where_predicate(&mut self, _: &EarlyContext<'_>, pred: &ast::WherePredicate) {
13051389
use rustc_ast::{WhereBoundPredicate, WherePredicateKind};
13061390
if let WherePredicateKind::BoundPredicate(WhereBoundPredicate {

library/core/src/error.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -347,7 +347,7 @@ impl dyn Error {
347347
/// let b = B(Some(Box::new(A)));
348348
///
349349
/// // let err : Box<Error> = b.into(); // or
350-
/// let err = &b as &(dyn Error);
350+
/// let err = &b as &dyn Error;
351351
///
352352
/// let mut iter = err.sources();
353353
///

tests/ui/lint/lint-unnecessary-parens.fixed

Lines changed: 84 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
//@ run-rustfix
22

3+
#![feature(impl_trait_in_fn_trait_return)]
34
#![deny(unused_parens)]
45
#![allow(while_true)] // for rustfix
56

@@ -16,11 +17,11 @@ fn bar(y: bool) -> X {
1617
return X { y }; //~ ERROR unnecessary parentheses around `return` value
1718
}
1819

19-
pub fn unused_parens_around_return_type() -> u32 { //~ ERROR unnecessary parentheses around type
20+
pub fn around_return_type() -> u32 { //~ ERROR unnecessary parentheses around type
2021
panic!()
2122
}
2223

23-
pub fn unused_parens_around_block_return() -> u32 {
24+
pub fn around_block_return() -> u32 {
2425
let _foo = {
2526
5 //~ ERROR unnecessary parentheses around block return value
2627
};
@@ -31,10 +32,90 @@ pub trait Trait {
3132
fn test(&self);
3233
}
3334

34-
pub fn passes_unused_parens_lint() -> &'static (dyn Trait) {
35+
pub fn around_multi_bound_ref() -> &'static (dyn Trait + Send) {
3536
panic!()
3637
}
3738

39+
//~v ERROR unnecessary parentheses around type
40+
pub fn around_single_bound_ref() -> &'static dyn Trait {
41+
panic!()
42+
}
43+
44+
pub fn around_multi_bound_ptr() -> *const (dyn Trait + Send) {
45+
panic!()
46+
}
47+
48+
//~v ERROR unnecessary parentheses around type
49+
pub fn around_single_bound_ptr() -> *const dyn Trait {
50+
panic!()
51+
}
52+
53+
pub fn around_multi_bound_dyn_fn_output() -> &'static dyn FnOnce() -> (impl Send + Sync) {
54+
&|| ()
55+
}
56+
57+
//~v ERROR unnecessary parentheses around type
58+
pub fn around_single_bound_dyn_fn_output() -> &'static dyn FnOnce() -> impl Send {
59+
&|| ()
60+
}
61+
62+
pub fn around_dyn_fn_output_given_more_bounds() -> &'static (dyn FnOnce() -> (impl Send) + Sync) {
63+
&|| ()
64+
}
65+
66+
pub fn around_multi_bound_impl_fn_output() -> impl FnOnce() -> (impl Send + Sync) {
67+
|| ()
68+
}
69+
70+
//~v ERROR unnecessary parentheses around type
71+
pub fn around_single_bound_impl_fn_output() -> impl FnOnce() -> impl Send {
72+
|| ()
73+
}
74+
75+
pub fn around_impl_fn_output_given_more_bounds() -> impl FnOnce() -> (impl Send) + Sync {
76+
|| ()
77+
}
78+
79+
//~v ERROR unnecessary parentheses around type
80+
pub fn around_dyn_bound() -> &'static dyn FnOnce() {
81+
&|| ()
82+
}
83+
84+
//~v ERROR unnecessary parentheses around type
85+
pub fn around_impl_trait_bound() -> impl FnOnce() {
86+
|| ()
87+
}
88+
89+
// these parens aren't strictly required but they help disambiguate => no lint
90+
pub fn around_fn_bound_with_explicit_ret_ty() -> impl (Fn() -> ()) + Send {
91+
|| ()
92+
}
93+
94+
//~v ERROR unnecessary parentheses around type
95+
pub fn around_fn_bound_with_implicit_ret_ty() -> impl Fn() + Send {
96+
|| ()
97+
}
98+
99+
//~v ERROR unnecessary parentheses around type
100+
pub fn around_last_fn_bound_with_explicit_ret_ty() -> impl Send + Fn() -> () {
101+
|| ()
102+
}
103+
104+
//~v ERROR unnecessary parentheses around type
105+
pub fn around_regular_bound1() -> &'static (dyn Send + Sync) {
106+
&|| ()
107+
}
108+
109+
//~v ERROR unnecessary parentheses around type
110+
pub fn around_regular_bound2() -> &'static (dyn Send + Sync) {
111+
&|| ()
112+
}
113+
114+
//~v ERROR unnecessary parentheses around type
115+
pub fn around_regular_bound3() -> &'static (dyn Send + ::std::marker::Sync) {
116+
&|| ()
117+
}
118+
38119
pub fn parens_with_keyword(e: &[()]) -> i32 {
39120
if true {} //~ ERROR unnecessary parentheses around `if`
40121
while true {} //~ ERROR unnecessary parentheses around `while`

tests/ui/lint/lint-unnecessary-parens.rs

Lines changed: 84 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
//@ run-rustfix
22

3+
#![feature(impl_trait_in_fn_trait_return)]
34
#![deny(unused_parens)]
45
#![allow(while_true)] // for rustfix
56

@@ -16,11 +17,11 @@ fn bar(y: bool) -> X {
1617
return (X { y }); //~ ERROR unnecessary parentheses around `return` value
1718
}
1819

19-
pub fn unused_parens_around_return_type() -> (u32) { //~ ERROR unnecessary parentheses around type
20+
pub fn around_return_type() -> (u32) { //~ ERROR unnecessary parentheses around type
2021
panic!()
2122
}
2223

23-
pub fn unused_parens_around_block_return() -> u32 {
24+
pub fn around_block_return() -> u32 {
2425
let _foo = {
2526
(5) //~ ERROR unnecessary parentheses around block return value
2627
};
@@ -31,10 +32,90 @@ pub trait Trait {
3132
fn test(&self);
3233
}
3334

34-
pub fn passes_unused_parens_lint() -> &'static (dyn Trait) {
35+
pub fn around_multi_bound_ref() -> &'static (dyn Trait + Send) {
3536
panic!()
3637
}
3738

39+
//~v ERROR unnecessary parentheses around type
40+
pub fn around_single_bound_ref() -> &'static (dyn Trait) {
41+
panic!()
42+
}
43+
44+
pub fn around_multi_bound_ptr() -> *const (dyn Trait + Send) {
45+
panic!()
46+
}
47+
48+
//~v ERROR unnecessary parentheses around type
49+
pub fn around_single_bound_ptr() -> *const (dyn Trait) {
50+
panic!()
51+
}
52+
53+
pub fn around_multi_bound_dyn_fn_output() -> &'static dyn FnOnce() -> (impl Send + Sync) {
54+
&|| ()
55+
}
56+
57+
//~v ERROR unnecessary parentheses around type
58+
pub fn around_single_bound_dyn_fn_output() -> &'static dyn FnOnce() -> (impl Send) {
59+
&|| ()
60+
}
61+
62+
pub fn around_dyn_fn_output_given_more_bounds() -> &'static (dyn FnOnce() -> (impl Send) + Sync) {
63+
&|| ()
64+
}
65+
66+
pub fn around_multi_bound_impl_fn_output() -> impl FnOnce() -> (impl Send + Sync) {
67+
|| ()
68+
}
69+
70+
//~v ERROR unnecessary parentheses around type
71+
pub fn around_single_bound_impl_fn_output() -> impl FnOnce() -> (impl Send) {
72+
|| ()
73+
}
74+
75+
pub fn around_impl_fn_output_given_more_bounds() -> impl FnOnce() -> (impl Send) + Sync {
76+
|| ()
77+
}
78+
79+
//~v ERROR unnecessary parentheses around type
80+
pub fn around_dyn_bound() -> &'static dyn (FnOnce()) {
81+
&|| ()
82+
}
83+
84+
//~v ERROR unnecessary parentheses around type
85+
pub fn around_impl_trait_bound() -> impl (FnOnce()) {
86+
|| ()
87+
}
88+
89+
// these parens aren't strictly required but they help disambiguate => no lint
90+
pub fn around_fn_bound_with_explicit_ret_ty() -> impl (Fn() -> ()) + Send {
91+
|| ()
92+
}
93+
94+
//~v ERROR unnecessary parentheses around type
95+
pub fn around_fn_bound_with_implicit_ret_ty() -> impl (Fn()) + Send {
96+
|| ()
97+
}
98+
99+
//~v ERROR unnecessary parentheses around type
100+
pub fn around_last_fn_bound_with_explicit_ret_ty() -> impl Send + (Fn() -> ()) {
101+
|| ()
102+
}
103+
104+
//~v ERROR unnecessary parentheses around type
105+
pub fn around_regular_bound1() -> &'static (dyn (Send) + Sync) {
106+
&|| ()
107+
}
108+
109+
//~v ERROR unnecessary parentheses around type
110+
pub fn around_regular_bound2() -> &'static (dyn Send + (Sync)) {
111+
&|| ()
112+
}
113+
114+
//~v ERROR unnecessary parentheses around type
115+
pub fn around_regular_bound3() -> &'static (dyn Send + (::std::marker::Sync)) {
116+
&|| ()
117+
}
118+
38119
pub fn parens_with_keyword(e: &[()]) -> i32 {
39120
if(true) {} //~ ERROR unnecessary parentheses around `if`
40121
while(true) {} //~ ERROR unnecessary parentheses around `while`

0 commit comments

Comments
 (0)