Skip to content

Commit 6c35e1a

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

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
@@ -581,10 +581,24 @@ trait UnusedDelimLint {
581581
lint.set_arg("delim", Self::DELIM_STR);
582582
lint.set_arg("item", msg);
583583
if let Some((lo, hi)) = spans {
584-
let replacement = vec![
585-
(lo, if keep_space.0 { " ".into() } else { "".into() }),
586-
(hi, if keep_space.1 { " ".into() } else { "".into() }),
587-
];
584+
let sm = cx.sess().source_map();
585+
let lo_replace =
586+
if keep_space.0 &&
587+
let Ok(snip) = sm.span_to_prev_source(lo) && !snip.ends_with(" ") {
588+
" ".to_string()
589+
} else {
590+
"".to_string()
591+
};
592+
593+
let hi_replace =
594+
if keep_space.1 &&
595+
let Ok(snip) = sm.span_to_next_source(hi) && !snip.starts_with(" ") {
596+
" ".to_string()
597+
} else {
598+
"".to_string()
599+
};
600+
601+
let replacement = vec![(lo, lo_replace), (hi, hi_replace)];
588602
lint.multipart_suggestion(
589603
fluent::suggestion,
590604
replacement,
@@ -781,6 +795,7 @@ impl UnusedParens {
781795
value: &ast::Pat,
782796
avoid_or: bool,
783797
avoid_mut: bool,
798+
keep_space: (bool, bool),
784799
) {
785800
use ast::{BindingAnnotation, PatKind};
786801

@@ -805,7 +820,7 @@ impl UnusedParens {
805820
} else {
806821
None
807822
};
808-
self.emit_unused_delims(cx, value.span, spans, "pattern", (false, false));
823+
self.emit_unused_delims(cx, value.span, spans, "pattern", keep_space);
809824
}
810825
}
811826
}
@@ -814,7 +829,7 @@ impl EarlyLintPass for UnusedParens {
814829
fn check_expr(&mut self, cx: &EarlyContext<'_>, e: &ast::Expr) {
815830
match e.kind {
816831
ExprKind::Let(ref pat, _, _) | ExprKind::ForLoop(ref pat, ..) => {
817-
self.check_unused_parens_pat(cx, pat, false, false);
832+
self.check_unused_parens_pat(cx, pat, false, false, (true, true));
818833
}
819834
// We ignore parens in cases like `if (((let Some(0) = Some(1))))` because we already
820835
// handle a hard error for them during AST lowering in `lower_expr_mut`, but we still
@@ -858,40 +873,41 @@ impl EarlyLintPass for UnusedParens {
858873

859874
fn check_pat(&mut self, cx: &EarlyContext<'_>, p: &ast::Pat) {
860875
use ast::{Mutability, PatKind::*};
876+
let keep_space = (false, false);
861877
match &p.kind {
862878
// Do not lint on `(..)` as that will result in the other arms being useless.
863879
Paren(_)
864880
// The other cases do not contain sub-patterns.
865881
| Wild | Rest | Lit(..) | MacCall(..) | Range(..) | Ident(.., None) | Path(..) => {},
866882
// These are list-like patterns; parens can always be removed.
867883
TupleStruct(_, _, ps) | Tuple(ps) | Slice(ps) | Or(ps) => for p in ps {
868-
self.check_unused_parens_pat(cx, p, false, false);
884+
self.check_unused_parens_pat(cx, p, false, false, keep_space);
869885
},
870886
Struct(_, _, fps, _) => for f in fps {
871-
self.check_unused_parens_pat(cx, &f.pat, false, false);
887+
self.check_unused_parens_pat(cx, &f.pat, false, false, keep_space);
872888
},
873889
// Avoid linting on `i @ (p0 | .. | pn)` and `box (p0 | .. | pn)`, #64106.
874-
Ident(.., Some(p)) | Box(p) => self.check_unused_parens_pat(cx, p, true, false),
890+
Ident(.., Some(p)) | Box(p) => self.check_unused_parens_pat(cx, p, true, false, keep_space),
875891
// Avoid linting on `&(mut x)` as `&mut x` has a different meaning, #55342.
876892
// Also avoid linting on `& mut? (p0 | .. | pn)`, #64106.
877-
Ref(p, m) => self.check_unused_parens_pat(cx, p, true, *m == Mutability::Not),
893+
Ref(p, m) => self.check_unused_parens_pat(cx, p, true, *m == Mutability::Not, keep_space),
878894
}
879895
}
880896

881897
fn check_stmt(&mut self, cx: &EarlyContext<'_>, s: &ast::Stmt) {
882898
if let StmtKind::Local(ref local) = s.kind {
883-
self.check_unused_parens_pat(cx, &local.pat, true, false);
899+
self.check_unused_parens_pat(cx, &local.pat, true, false, (false, false));
884900
}
885901

886902
<Self as UnusedDelimLint>::check_stmt(self, cx, s)
887903
}
888904

889905
fn check_param(&mut self, cx: &EarlyContext<'_>, param: &ast::Param) {
890-
self.check_unused_parens_pat(cx, &param.pat, true, false);
906+
self.check_unused_parens_pat(cx, &param.pat, true, false, (false, false));
891907
}
892908

893909
fn check_arm(&mut self, cx: &EarlyContext<'_>, arm: &ast::Arm) {
894-
self.check_unused_parens_pat(cx, &arm.pat, false, false);
910+
self.check_unused_parens_pat(cx, &arm.pat, false, false, (false, false));
895911
}
896912

897913
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)