Skip to content

Commit 57ffc83

Browse files
authored
Rollup merge of #64128 - Centril:unused-parens-pat, r=davidtwco
unused_parens: account for or-patterns and `&(mut x)` Fixes #55342. Fixes #64106. cc #54883 cc #64111 r? @oli-obk
2 parents c195145 + e85b181 commit 57ffc83

File tree

3 files changed

+256
-64
lines changed

3 files changed

+256
-64
lines changed

src/librustc_lint/unused.rs

+64-17
Original file line numberDiff line numberDiff line change
@@ -398,18 +398,37 @@ impl UnusedParens {
398398
}
399399
}
400400

401-
fn check_unused_parens_pat(&self,
402-
cx: &EarlyContext<'_>,
403-
value: &ast::Pat,
404-
msg: &str) {
405-
if let ast::PatKind::Paren(_) = value.node {
401+
fn check_unused_parens_pat(
402+
&self,
403+
cx: &EarlyContext<'_>,
404+
value: &ast::Pat,
405+
avoid_or: bool,
406+
avoid_mut: bool,
407+
) {
408+
use ast::{PatKind, BindingMode::ByValue, Mutability::Mutable};
409+
410+
if let PatKind::Paren(inner) = &value.node {
411+
match inner.node {
412+
// The lint visitor will visit each subpattern of `p`. We do not want to lint
413+
// any range pattern no matter where it occurs in the pattern. For something like
414+
// `&(a..=b)`, there is a recursive `check_pat` on `a` and `b`, but we will assume
415+
// that if there are unnecessary parens they serve a purpose of readability.
416+
PatKind::Range(..) => return,
417+
// Avoid `p0 | .. | pn` if we should.
418+
PatKind::Or(..) if avoid_or => return,
419+
// Avoid `mut x` and `mut x @ p` if we should:
420+
PatKind::Ident(ByValue(Mutable), ..) if avoid_mut => return,
421+
// Otherwise proceed with linting.
422+
_ => {}
423+
}
424+
406425
let pattern_text = if let Ok(snippet) = cx.sess().source_map()
407426
.span_to_snippet(value.span) {
408427
snippet
409428
} else {
410429
pprust::pat_to_string(value)
411430
};
412-
Self::remove_outer_parens(cx, value.span, &pattern_text, msg, (false, false));
431+
Self::remove_outer_parens(cx, value.span, &pattern_text, "pattern", (false, false));
413432
}
414433
}
415434

@@ -474,6 +493,13 @@ impl EarlyLintPass for UnusedParens {
474493
fn check_expr(&mut self, cx: &EarlyContext<'_>, e: &ast::Expr) {
475494
use syntax::ast::ExprKind::*;
476495
let (value, msg, followed_by_block, left_pos, right_pos) = match e.node {
496+
Let(ref pats, ..) => {
497+
for p in pats {
498+
self.check_unused_parens_pat(cx, p, false, false);
499+
}
500+
return;
501+
}
502+
477503
If(ref cond, ref block, ..) => {
478504
let left = e.span.lo() + syntax_pos::BytePos(2);
479505
let right = block.span.lo();
@@ -486,7 +512,8 @@ impl EarlyLintPass for UnusedParens {
486512
(cond, "`while` condition", true, Some(left), Some(right))
487513
},
488514

489-
ForLoop(_, ref cond, ref block, ..) => {
515+
ForLoop(ref pat, ref cond, ref block, ..) => {
516+
self.check_unused_parens_pat(cx, pat, false, false);
490517
(cond, "`for` head expression", true, None, Some(block.span.lo()))
491518
}
492519

@@ -531,26 +558,46 @@ impl EarlyLintPass for UnusedParens {
531558
}
532559

533560
fn check_pat(&mut self, cx: &EarlyContext<'_>, p: &ast::Pat) {
534-
use ast::PatKind::{Paren, Range};
535-
// The lint visitor will visit each subpattern of `p`. We do not want to lint any range
536-
// pattern no matter where it occurs in the pattern. For something like `&(a..=b)`, there
537-
// is a recursive `check_pat` on `a` and `b`, but we will assume that if there are
538-
// unnecessary parens they serve a purpose of readability.
539-
if let Paren(ref pat) = p.node {
540-
match pat.node {
541-
Range(..) => {}
542-
_ => self.check_unused_parens_pat(cx, &p, "pattern")
543-
}
561+
use ast::{PatKind::*, Mutability};
562+
match &p.node {
563+
// Do not lint on `(..)` as that will result in the other arms being useless.
564+
Paren(_)
565+
// The other cases do not contain sub-patterns.
566+
| Wild | Rest | Lit(..) | Mac(..) | Range(..) | Ident(.., None) | Path(..) => return,
567+
// These are list-like patterns; parens can always be removed.
568+
TupleStruct(_, ps) | Tuple(ps) | Slice(ps) | Or(ps) => for p in ps {
569+
self.check_unused_parens_pat(cx, p, false, false);
570+
},
571+
Struct(_, fps, _) => for f in fps {
572+
self.check_unused_parens_pat(cx, &f.pat, false, false);
573+
},
574+
// Avoid linting on `i @ (p0 | .. | pn)` and `box (p0 | .. | pn)`, #64106.
575+
Ident(.., Some(p)) | Box(p) => self.check_unused_parens_pat(cx, p, true, false),
576+
// Avoid linting on `&(mut x)` as `&mut x` has a different meaning, #55342.
577+
// Also avoid linting on `& mut? (p0 | .. | pn)`, #64106.
578+
Ref(p, m) => self.check_unused_parens_pat(cx, p, true, *m == Mutability::Immutable),
544579
}
545580
}
546581

547582
fn check_stmt(&mut self, cx: &EarlyContext<'_>, s: &ast::Stmt) {
548583
if let ast::StmtKind::Local(ref local) = s.node {
584+
self.check_unused_parens_pat(cx, &local.pat, false, false);
585+
549586
if let Some(ref value) = local.init {
550587
self.check_unused_parens_expr(cx, &value, "assigned value", false, None, None);
551588
}
552589
}
553590
}
591+
592+
fn check_param(&mut self, cx: &EarlyContext<'_>, param: &ast::Param) {
593+
self.check_unused_parens_pat(cx, &param.pat, true, false);
594+
}
595+
596+
fn check_arm(&mut self, cx: &EarlyContext<'_>, arm: &ast::Arm) {
597+
for p in &arm.pats {
598+
self.check_unused_parens_pat(cx, p, false, false);
599+
}
600+
}
554601
}
555602

556603
declare_lint! {

src/test/ui/lint/issue-54538-unused-parens-lint.rs

+70-20
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,75 @@
1-
// build-pass (FIXME(62277): could be check-pass?)
1+
#![feature(box_patterns)]
2+
3+
#![feature(or_patterns)]
4+
//~^ WARN the feature `or_patterns` is incomplete
25

36
#![allow(ellipsis_inclusive_range_patterns)]
47
#![allow(unreachable_patterns)]
58
#![allow(unused_variables)]
6-
#![warn(unused_parens)]
9+
#![deny(unused_parens)]
10+
11+
fn lint_on_top_level() {
12+
let (a) = 0; //~ ERROR unnecessary parentheses around pattern
13+
for (a) in 0..1 {} //~ ERROR unnecessary parentheses around pattern
14+
if let (a) = 0 {} //~ ERROR unnecessary parentheses around pattern
15+
while let (a) = 0 {} //~ ERROR unnecessary parentheses around pattern
16+
fn foo((a): u8) {} //~ ERROR unnecessary parentheses around pattern
17+
let _ = |(a): u8| 0; //~ ERROR unnecessary parentheses around pattern
18+
}
19+
20+
// Don't lint in these cases (#64106).
21+
fn or_patterns_no_lint() {
22+
match Box::new(0) {
23+
box (0 | 1) => {} // Should not lint as `box 0 | 1` binds as `(box 0) | 1`.
24+
_ => {}
25+
}
26+
27+
match 0 {
28+
x @ (0 | 1) => {} // Should not lint as `x @ 0 | 1` binds as `(x @ 0) | 1`.
29+
_ => {}
30+
}
31+
32+
if let &(0 | 1) = &0 {} // Should also not lint.
33+
if let &mut (0 | 1) = &mut 0 {} // Same.
34+
35+
fn foo((Ok(a) | Err(a)): Result<u8, u8>) {} // Doesn't parse if we remove parens for now.
36+
//~^ ERROR identifier `a` is bound more than once
37+
38+
let _ = |(Ok(a) | Err(a)): Result<u8, u8>| 1; // `|Ok(a) | Err(a)| 1` parses as bit-or.
39+
//~^ ERROR identifier `a` is bound more than once
40+
}
41+
42+
fn or_patterns_will_lint() {
43+
if let (0 | 1) = 0 {} //~ ERROR unnecessary parentheses around pattern
44+
if let ((0 | 1),) = (0,) {} //~ ERROR unnecessary parentheses around pattern
45+
if let [(0 | 1)] = [0] {} //~ ERROR unnecessary parentheses around pattern
46+
if let 0 | (1 | 2) = 0 {} //~ ERROR unnecessary parentheses around pattern
47+
struct TS(u8);
48+
if let TS((0 | 1)) = TS(0) {} //~ ERROR unnecessary parentheses around pattern
49+
struct NS { f: u8 }
50+
if let NS { f: (0 | 1) } = (NS { f: 0 }) {} //~ ERROR unnecessary parentheses around pattern
51+
}
52+
53+
// Don't lint on `&(mut x)` because `&mut x` means something else (#55342).
54+
fn deref_mut_binding_no_lint() {
55+
let &(mut x) = &0;
56+
}
757

858
fn main() {
959
match 1 {
10-
(_) => {} //~ WARNING: unnecessary parentheses around pattern
11-
(y) => {} //~ WARNING: unnecessary parentheses around pattern
12-
(ref r) => {} //~ WARNING: unnecessary parentheses around pattern
13-
(e @ 1...2) => {} //~ WARNING: unnecessary parentheses around outer pattern
14-
(1...2) => {} // Non ambiguous range pattern should not warn
60+
(_) => {} //~ ERROR unnecessary parentheses around pattern
61+
(y) => {} //~ ERROR unnecessary parentheses around pattern
62+
(ref r) => {} //~ ERROR unnecessary parentheses around pattern
63+
(e @ 1...2) => {} //~ ERROR unnecessary parentheses around pattern
64+
(1...2) => {} // Non ambiguous range pattern should not warn
1565
e @ (3...4) => {} // Non ambiguous range pattern should not warn
1666
}
1767

1868
match &1 {
19-
(e @ &(1...2)) => {} //~ WARNING: unnecessary parentheses around outer pattern
20-
&(_) => {} //~ WARNING: unnecessary parentheses around pattern
21-
e @ &(1...2) => {} // Ambiguous range pattern should not warn
22-
&(1...2) => {} // Ambiguous range pattern should not warn
69+
(e @ &(1...2)) => {} //~ ERROR unnecessary parentheses around pattern
70+
&(_) => {} //~ ERROR unnecessary parentheses around pattern
71+
e @ &(1...2) => {} // Ambiguous range pattern should not warn
72+
&(1...2) => {} // Ambiguous range pattern should not warn
2373
}
2474

2575
match &1 {
@@ -28,19 +78,19 @@ fn main() {
2878
}
2979

3080
match 1 {
31-
(_) => {} //~ WARNING: unnecessary parentheses around pattern
32-
(y) => {} //~ WARNING: unnecessary parentheses around pattern
33-
(ref r) => {} //~ WARNING: unnecessary parentheses around pattern
34-
(e @ 1..=2) => {} //~ WARNING: unnecessary parentheses around outer pattern
35-
(1..=2) => {} // Non ambiguous range pattern should not warn
81+
(_) => {} //~ ERROR unnecessary parentheses around pattern
82+
(y) => {} //~ ERROR unnecessary parentheses around pattern
83+
(ref r) => {} //~ ERROR unnecessary parentheses around pattern
84+
(e @ 1..=2) => {} //~ ERROR unnecessary parentheses around pattern
85+
(1..=2) => {} // Non ambiguous range pattern should not warn
3686
e @ (3..=4) => {} // Non ambiguous range pattern should not warn
3787
}
3888

3989
match &1 {
40-
(e @ &(1..=2)) => {} //~ WARNING: unnecessary parentheses around outer pattern
41-
&(_) => {} //~ WARNING: unnecessary parentheses around pattern
42-
e @ &(1..=2) => {} // Ambiguous range pattern should not warn
43-
&(1..=2) => {} // Ambiguous range pattern should not warn
90+
(e @ &(1..=2)) => {} //~ ERROR unnecessary parentheses around pattern
91+
&(_) => {} //~ ERROR unnecessary parentheses around pattern
92+
e @ &(1..=2) => {} // Ambiguous range pattern should not warn
93+
&(1..=2) => {} // Ambiguous range pattern should not warn
4494
}
4595

4696
match &1 {

0 commit comments

Comments
 (0)