Skip to content

Commit fd5ff82

Browse files
authored
Rollup merge of #103468 - chenyukang:yukang/fix-103435-extra-parentheses, r=estebank
Fix unused lint and parser caring about spaces to won't produce invalid code Fixes #103435
2 parents 9553fea + a46af18 commit fd5ff82

File tree

6 files changed

+149
-20
lines changed

6 files changed

+149
-20
lines changed

compiler/rustc_lint/src/unused.rs

+29-13
Original file line numberDiff line numberDiff line change
@@ -565,10 +565,24 @@ trait UnusedDelimLint {
565565
lint.set_arg("delim", Self::DELIM_STR);
566566
lint.set_arg("item", msg);
567567
if let Some((lo, hi)) = spans {
568-
let replacement = vec![
569-
(lo, if keep_space.0 { " ".into() } else { "".into() }),
570-
(hi, if keep_space.1 { " ".into() } else { "".into() }),
571-
];
568+
let sm = cx.sess().source_map();
569+
let lo_replace =
570+
if keep_space.0 &&
571+
let Ok(snip) = sm.span_to_prev_source(lo) && !snip.ends_with(" ") {
572+
" ".to_string()
573+
} else {
574+
"".to_string()
575+
};
576+
577+
let hi_replace =
578+
if keep_space.1 &&
579+
let Ok(snip) = sm.span_to_next_source(hi) && !snip.starts_with(" ") {
580+
" ".to_string()
581+
} else {
582+
"".to_string()
583+
};
584+
585+
let replacement = vec![(lo, lo_replace), (hi, hi_replace)];
572586
lint.multipart_suggestion(
573587
fluent::suggestion,
574588
replacement,
@@ -765,6 +779,7 @@ impl UnusedParens {
765779
value: &ast::Pat,
766780
avoid_or: bool,
767781
avoid_mut: bool,
782+
keep_space: (bool, bool),
768783
) {
769784
use ast::{BindingAnnotation, PatKind};
770785

@@ -789,7 +804,7 @@ impl UnusedParens {
789804
} else {
790805
None
791806
};
792-
self.emit_unused_delims(cx, value.span, spans, "pattern", (false, false));
807+
self.emit_unused_delims(cx, value.span, spans, "pattern", keep_space);
793808
}
794809
}
795810
}
@@ -798,7 +813,7 @@ impl EarlyLintPass for UnusedParens {
798813
fn check_expr(&mut self, cx: &EarlyContext<'_>, e: &ast::Expr) {
799814
match e.kind {
800815
ExprKind::Let(ref pat, _, _) | ExprKind::ForLoop(ref pat, ..) => {
801-
self.check_unused_parens_pat(cx, pat, false, false);
816+
self.check_unused_parens_pat(cx, pat, false, false, (true, true));
802817
}
803818
// We ignore parens in cases like `if (((let Some(0) = Some(1))))` because we already
804819
// handle a hard error for them during AST lowering in `lower_expr_mut`, but we still
@@ -842,40 +857,41 @@ impl EarlyLintPass for UnusedParens {
842857

843858
fn check_pat(&mut self, cx: &EarlyContext<'_>, p: &ast::Pat) {
844859
use ast::{Mutability, PatKind::*};
860+
let keep_space = (false, false);
845861
match &p.kind {
846862
// Do not lint on `(..)` as that will result in the other arms being useless.
847863
Paren(_)
848864
// The other cases do not contain sub-patterns.
849865
| Wild | Rest | Lit(..) | MacCall(..) | Range(..) | Ident(.., None) | Path(..) => {},
850866
// These are list-like patterns; parens can always be removed.
851867
TupleStruct(_, _, ps) | Tuple(ps) | Slice(ps) | Or(ps) => for p in ps {
852-
self.check_unused_parens_pat(cx, p, false, false);
868+
self.check_unused_parens_pat(cx, p, false, false, keep_space);
853869
},
854870
Struct(_, _, fps, _) => for f in fps {
855-
self.check_unused_parens_pat(cx, &f.pat, false, false);
871+
self.check_unused_parens_pat(cx, &f.pat, false, false, keep_space);
856872
},
857873
// Avoid linting on `i @ (p0 | .. | pn)` and `box (p0 | .. | pn)`, #64106.
858-
Ident(.., Some(p)) | Box(p) => self.check_unused_parens_pat(cx, p, true, false),
874+
Ident(.., Some(p)) | Box(p) => self.check_unused_parens_pat(cx, p, true, false, keep_space),
859875
// Avoid linting on `&(mut x)` as `&mut x` has a different meaning, #55342.
860876
// Also avoid linting on `& mut? (p0 | .. | pn)`, #64106.
861-
Ref(p, m) => self.check_unused_parens_pat(cx, p, true, *m == Mutability::Not),
877+
Ref(p, m) => self.check_unused_parens_pat(cx, p, true, *m == Mutability::Not, keep_space),
862878
}
863879
}
864880

865881
fn check_stmt(&mut self, cx: &EarlyContext<'_>, s: &ast::Stmt) {
866882
if let StmtKind::Local(ref local) = s.kind {
867-
self.check_unused_parens_pat(cx, &local.pat, true, false);
883+
self.check_unused_parens_pat(cx, &local.pat, true, false, (false, false));
868884
}
869885

870886
<Self as UnusedDelimLint>::check_stmt(self, cx, s)
871887
}
872888

873889
fn check_param(&mut self, cx: &EarlyContext<'_>, param: &ast::Param) {
874-
self.check_unused_parens_pat(cx, &param.pat, true, false);
890+
self.check_unused_parens_pat(cx, &param.pat, true, false, (false, false));
875891
}
876892

877893
fn check_arm(&mut self, cx: &EarlyContext<'_>, arm: &ast::Arm) {
878-
self.check_unused_parens_pat(cx, &arm.pat, false, false);
894+
self.check_unused_parens_pat(cx, &arm.pat, false, false, (false, false));
879895
}
880896

881897
fn check_ty(&mut self, cx: &EarlyContext<'_>, ty: &ast::Ty) {

compiler/rustc_parse/src/errors.rs

+4-2
Original file line numberDiff line numberDiff line change
@@ -1165,10 +1165,12 @@ pub(crate) struct ParenthesesInForHead {
11651165
#[derive(Subdiagnostic)]
11661166
#[multipart_suggestion(suggestion, applicability = "machine-applicable")]
11671167
pub(crate) struct ParenthesesInForHeadSugg {
1168-
#[suggestion_part(code = "")]
1168+
#[suggestion_part(code = "{left_snippet}")]
11691169
pub left: Span,
1170-
#[suggestion_part(code = "")]
1170+
pub left_snippet: String,
1171+
#[suggestion_part(code = "{right_snippet}")]
11711172
pub right: Span,
1173+
pub right_snippet: String,
11721174
}
11731175

11741176
#[derive(Diagnostic)]

compiler/rustc_parse/src/parser/diagnostics.rs

+19-5
Original file line numberDiff line numberDiff line change
@@ -1653,15 +1653,29 @@ impl<'a> Parser<'a> {
16531653
(token::CloseDelim(Delimiter::Parenthesis), Some(begin_par_sp)) => {
16541654
self.bump();
16551655

1656+
let sm = self.sess.source_map();
1657+
let left = begin_par_sp;
1658+
let right = self.prev_token.span;
1659+
let left_snippet = if let Ok(snip) = sm.span_to_prev_source(left) &&
1660+
!snip.ends_with(" ") {
1661+
" ".to_string()
1662+
} else {
1663+
"".to_string()
1664+
};
1665+
1666+
let right_snippet = if let Ok(snip) = sm.span_to_next_source(right) &&
1667+
!snip.starts_with(" ") {
1668+
" ".to_string()
1669+
} else {
1670+
"".to_string()
1671+
};
1672+
16561673
self.sess.emit_err(ParenthesesInForHead {
1657-
span: vec![begin_par_sp, self.prev_token.span],
1674+
span: vec![left, right],
16581675
// With e.g. `for (x) in y)` this would replace `(x) in y)`
16591676
// with `x) in y)` which is syntactically invalid.
16601677
// However, this is prevented before we get here.
1661-
sugg: ParenthesesInForHeadSugg {
1662-
left: begin_par_sp,
1663-
right: self.prev_token.span,
1664-
},
1678+
sugg: ParenthesesInForHeadSugg { left, right, left_snippet, right_snippet },
16651679
});
16661680

16671681
// Unwrap `(pat)` into `pat` to avoid the `unused_parens` lint.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// run-rustfix
2+
#![deny(unused_parens)]
3+
4+
fn main() {
5+
if let Some(_) = Some(1) {}
6+
//~^ ERROR unnecessary parentheses around pattern
7+
8+
for _x in 1..10 {}
9+
//~^ ERROR unnecessary parentheses around pattern
10+
11+
if 2 == 1 {}
12+
//~^ ERROR unnecessary parentheses around `if` condition
13+
14+
// reported by parser
15+
for _x in 1..10 {}
16+
//~^ ERROR expected one of
17+
//~| ERROR unexpected parentheses surrounding
18+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// run-rustfix
2+
#![deny(unused_parens)]
3+
4+
fn main() {
5+
if let(Some(_))= Some(1) {}
6+
//~^ ERROR unnecessary parentheses around pattern
7+
8+
for(_x)in 1..10 {}
9+
//~^ ERROR unnecessary parentheses around pattern
10+
11+
if(2 == 1){}
12+
//~^ ERROR unnecessary parentheses around `if` condition
13+
14+
// reported by parser
15+
for(_x in 1..10){}
16+
//~^ ERROR expected one of
17+
//~| ERROR unexpected parentheses surrounding
18+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
error: expected one of `)`, `,`, `@`, or `|`, found keyword `in`
2+
--> $DIR/issue-103435-extra-parentheses.rs:15:12
3+
|
4+
LL | for(_x in 1..10){}
5+
| ^^ expected one of `)`, `,`, `@`, or `|`
6+
7+
error: unexpected parentheses surrounding `for` loop head
8+
--> $DIR/issue-103435-extra-parentheses.rs:15:8
9+
|
10+
LL | for(_x in 1..10){}
11+
| ^ ^
12+
|
13+
help: remove parentheses in `for` loop
14+
|
15+
LL - for(_x in 1..10){}
16+
LL + for _x in 1..10 {}
17+
|
18+
19+
error: unnecessary parentheses around pattern
20+
--> $DIR/issue-103435-extra-parentheses.rs:5:11
21+
|
22+
LL | if let(Some(_))= Some(1) {}
23+
| ^ ^
24+
|
25+
note: the lint level is defined here
26+
--> $DIR/issue-103435-extra-parentheses.rs:2:9
27+
|
28+
LL | #![deny(unused_parens)]
29+
| ^^^^^^^^^^^^^
30+
help: remove these parentheses
31+
|
32+
LL - if let(Some(_))= Some(1) {}
33+
LL + if let Some(_) = Some(1) {}
34+
|
35+
36+
error: unnecessary parentheses around pattern
37+
--> $DIR/issue-103435-extra-parentheses.rs:8:8
38+
|
39+
LL | for(_x)in 1..10 {}
40+
| ^ ^
41+
|
42+
help: remove these parentheses
43+
|
44+
LL - for(_x)in 1..10 {}
45+
LL + for _x in 1..10 {}
46+
|
47+
48+
error: unnecessary parentheses around `if` condition
49+
--> $DIR/issue-103435-extra-parentheses.rs:11:7
50+
|
51+
LL | if(2 == 1){}
52+
| ^ ^
53+
|
54+
help: remove these parentheses
55+
|
56+
LL - if(2 == 1){}
57+
LL + if 2 == 1 {}
58+
|
59+
60+
error: aborting due to 5 previous errors
61+

0 commit comments

Comments
 (0)