Skip to content

Commit be07f84

Browse files
author
Benjamin Schulz
committed
Detect more cases of unused_parens around types
1 parent b6685d7 commit be07f84

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
@@ -2,13 +2,15 @@ use std::iter;
22

33
use rustc_ast::util::{classify, parser};
44
use rustc_ast::{self as ast, ExprKind, HasAttrs as _, StmtKind};
5+
use rustc_data_structures::fx::FxHashMap;
56
use rustc_errors::{MultiSpan, pluralize};
67
use rustc_hir::def::{DefKind, Res};
78
use rustc_hir::def_id::DefId;
89
use rustc_hir::{self as hir, LangItem};
910
use rustc_infer::traits::util::elaborate;
1011
use rustc_middle::ty::{self, Ty, adjustment};
1112
use rustc_session::{declare_lint, declare_lint_pass, impl_lint_pass};
13+
use rustc_span::edition::Edition::Edition2015;
1214
use rustc_span::{BytePos, Span, Symbol, kw, sym};
1315
use tracing::instrument;
1416

@@ -1029,6 +1031,14 @@ pub(crate) struct UnusedParens {
10291031
/// `1 as (i32) < 2` parses to ExprKind::Lt
10301032
/// `1 as i32 < 2` parses to i32::<2[missing angle bracket]
10311033
parens_in_cast_in_lt: Vec<ast::NodeId>,
1034+
/// Ty nodes in this map are in TypeNoBounds position. Any bounds they
1035+
/// contain may be ambiguous w/r/t trailing `+` operators.
1036+
in_no_bounds_pos: FxHashMap<ast::NodeId, NoBoundsException>,
1037+
}
1038+
1039+
enum NoBoundsException {
1040+
None,
1041+
OneBound,
10321042
}
10331043

10341044
impl_lint_pass!(UnusedParens => [UNUSED_PARENS]);
@@ -1273,10 +1283,12 @@ impl EarlyLintPass for UnusedParens {
12731283
}
12741284
ast::TyKind::Paren(r) => {
12751285
match &r.kind {
1276-
ast::TyKind::TraitObject(..) => {}
1286+
ast::TyKind::ImplTrait(_, bounds) | ast::TyKind::TraitObject(bounds, _)
1287+
if self.in_no_bounds_pos.get(&ty.id).is_some_and(|exception| {
1288+
matches!(exception, NoBoundsException::None) || bounds.len() > 1
1289+
}) => {}
12771290
ast::TyKind::BareFn(b)
12781291
if self.with_self_ty_parens && b.generic_params.len() > 0 => {}
1279-
ast::TyKind::ImplTrait(_, bounds) if bounds.len() > 1 => {}
12801292
_ => {
12811293
let spans = if !ty.span.from_expansion() {
12821294
r.span
@@ -1290,6 +1302,74 @@ impl EarlyLintPass for UnusedParens {
12901302
}
12911303
self.with_self_ty_parens = false;
12921304
}
1305+
ast::TyKind::Ref(_, mut_ty) | ast::TyKind::Ptr(mut_ty) => {
1306+
self.in_no_bounds_pos.insert(mut_ty.ty.id, NoBoundsException::OneBound);
1307+
}
1308+
ast::TyKind::TraitObject(bounds, _) | ast::TyKind::ImplTrait(_, bounds) => {
1309+
for i in 0..bounds.len() {
1310+
let last = i == bounds.len() - 1;
1311+
1312+
if let ast::GenericBound::Trait(poly_trait_ref) = &bounds[i] {
1313+
let parenthesized = cx
1314+
.sess()
1315+
.source_map()
1316+
.span_to_snippet(poly_trait_ref.span)
1317+
.map(|snip| snip.starts_with('(') && snip.ends_with(')'))
1318+
.unwrap_or(false);
1319+
1320+
let fn_with_explicit_ret_ty = if let [.., segment] =
1321+
&*poly_trait_ref.trait_ref.path.segments
1322+
&& let Some(args) = segment.args.as_ref()
1323+
&& let ast::GenericArgs::Parenthesized(paren_args) = &**args
1324+
&& let ast::FnRetTy::Ty(ret_ty) = &paren_args.output
1325+
{
1326+
self.in_no_bounds_pos.insert(
1327+
ret_ty.id,
1328+
if last {
1329+
NoBoundsException::OneBound
1330+
} else {
1331+
NoBoundsException::None
1332+
},
1333+
);
1334+
1335+
true
1336+
} else {
1337+
false
1338+
};
1339+
1340+
let dyn2015_exception = cx.sess().psess.edition == Edition2015
1341+
&& matches!(ty.kind, ast::TyKind::TraitObject(..))
1342+
&& i == 0
1343+
&& poly_trait_ref
1344+
.trait_ref
1345+
.path
1346+
.segments
1347+
.first()
1348+
.map(|s| s.ident.name == kw::PathRoot)
1349+
.unwrap_or(false);
1350+
1351+
if parenthesized && (last || !fn_with_explicit_ret_ty) && !dyn2015_exception
1352+
{
1353+
let s = poly_trait_ref.span;
1354+
let spans = (!s.from_expansion()).then(|| {
1355+
(
1356+
s.with_hi(s.lo() + rustc_span::BytePos(1)),
1357+
s.with_lo(s.hi() - rustc_span::BytePos(1)),
1358+
)
1359+
});
1360+
1361+
self.emit_unused_delims(
1362+
cx,
1363+
poly_trait_ref.span,
1364+
spans,
1365+
"type",
1366+
(false, false),
1367+
false,
1368+
);
1369+
}
1370+
}
1371+
}
1372+
}
12931373
_ => {}
12941374
}
12951375
}
@@ -1298,6 +1378,10 @@ impl EarlyLintPass for UnusedParens {
12981378
<Self as UnusedDelimLint>::check_item(self, cx, item)
12991379
}
13001380

1381+
fn check_item_post(&mut self, _: &EarlyContext<'_>, _: &rustc_ast::Item) {
1382+
self.in_no_bounds_pos.clear();
1383+
}
1384+
13011385
fn enter_where_predicate(&mut self, _: &EarlyContext<'_>, pred: &ast::WherePredicate) {
13021386
use rustc_ast::{WhereBoundPredicate, WherePredicateKind};
13031387
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)