diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs index 9f15f41955d86..ebc06ef0f741d 100644 --- a/compiler/rustc_lint/src/unused.rs +++ b/compiler/rustc_lint/src/unused.rs @@ -628,6 +628,13 @@ impl UnusedDelimLint for UnusedParens { } impl UnusedParens { + fn pin_ergonomics_rustfix_allowed(cx: &EarlyContext<'_>) -> bool { + // FIXME(pin_ergonomics): Once `pin_ergonomics` is stabilized, + // remove this feature gate and allow the pinned-pattern rustfix + // suggestion unconditionally. + cx.builder.features().pin_ergonomics() + } + fn check_unused_parens_pat( &self, cx: &EarlyContext<'_>, @@ -636,7 +643,7 @@ impl UnusedParens { avoid_mut: bool, keep_space: (bool, bool), ) { - use ast::{BindingMode, PatKind}; + use ast::{BindingMode, ByRef, Mutability, PatKind, Pinnedness}; if let PatKind::Paren(inner) = &value.kind { match inner.kind { @@ -649,8 +656,15 @@ impl UnusedParens { PatKind::Guard(..) => return, // Avoid `p0 | .. | pn` if we should. PatKind::Or(..) if avoid_or => return, - // Avoid `mut x` and `mut x @ p` if we should: - PatKind::Ident(BindingMode::MUT, ..) if avoid_mut => { + // Avoid bindings that start with `mut`, like `mut x`, `mut x @ p`, + // and `mut ref pin const x`, if we should. + PatKind::Ident(BindingMode(_, Mutability::Mut), ..) if avoid_mut => { + return; + } + PatKind::Ref(_, Pinnedness::Pinned, _) + | PatKind::Ident(BindingMode(ByRef::Yes(Pinnedness::Pinned, _), _), ..) + if !Self::pin_ergonomics_rustfix_allowed(cx) => + { return; } // Otherwise proceed with linting. @@ -756,8 +770,8 @@ impl EarlyLintPass for UnusedParens { } fn check_pat(&mut self, cx: &EarlyContext<'_>, p: &ast::Pat) { - use ast::Mutability; use ast::PatKind::*; + use ast::{Mutability, Pinnedness}; let keep_space = (false, false); match &p.kind { // Do not lint on `(..)` as that will result in the other arms being useless. @@ -775,9 +789,22 @@ impl EarlyLintPass for UnusedParens { // Avoid linting on `i @ (p0 | .. | pn)` and `box (p0 | .. | pn)`, #64106. Ident(.., Some(p)) | Box(p) | Deref(p) | Guard(p, _) => self.check_unused_parens_pat(cx, p, true, false, keep_space), // Avoid linting on `&(mut x)` as `&mut x` has a different meaning, #55342. + // This only applies to plain shared reference patterns. In `&pin const (mut x)`, + // `pin const` is consumed before parsing the subpattern, so removing the + // parentheses preserves `mut x` as a binding pattern. // Also avoid linting on `& mut? (p0 | .. | pn)`, #64106. - // FIXME(pin_ergonomics): check pinned patterns - Ref(p, _, m) => self.check_unused_parens_pat(cx, p, true, *m == Mutability::Not, keep_space), + Ref(p, pinned, m) => { + if *pinned == Pinnedness::Pinned && !Self::pin_ergonomics_rustfix_allowed(cx) { + return; + } + self.check_unused_parens_pat( + cx, + p, + true, + *pinned == Pinnedness::Not && *m == Mutability::Not, + keep_space, + ); + } } } diff --git a/tests/ui/lint/unused-parens-pinned-reference-patterns.fixed b/tests/ui/lint/unused-parens-pinned-reference-patterns.fixed new file mode 100644 index 0000000000000..88c30d4696736 --- /dev/null +++ b/tests/ui/lint/unused-parens-pinned-reference-patterns.fixed @@ -0,0 +1,56 @@ +//@ run-rustfix +//@ check-pass +//@ normalize-stderr: "warning: 9 warnings emitted\n\n" -> "warning: 9 warnings emitted\n" +#![feature(pin_ergonomics, mut_ref)] +#![allow(dead_code)] +#![warn(unused_parens)] + +fn pinned_reference_patterns( + pin_const: &pin const i32, + pin_mut: &pin mut i32, + nested_pin_const: &pin const &pin const i32, +) { + let &pin const _x = pin_const; + //~^ WARN unnecessary parentheses around pattern + + let &pin const mut _x = pin_const; + //~^ WARN unnecessary parentheses around pattern + + let &pin const mut _x @ _ = pin_const; + //~^ WARN unnecessary parentheses around pattern + + let &pin mut mut _x = pin_mut; + //~^ WARN unnecessary parentheses around pattern + + let &pin const &pin const _x = nested_pin_const; + //~^ WARN unnecessary parentheses around pattern + + let &pin const ref pin const _x = pin_const; + //~^ WARN unnecessary parentheses around pattern + + let &pin mut ref pin mut _x = pin_mut; + //~^ WARN unnecessary parentheses around pattern + + let &pin const mut ref pin const _x = pin_const; + //~^ WARN unnecessary parentheses around pattern + + let &pin mut mut ref pin mut _x = pin_mut; + //~^ WARN unnecessary parentheses around pattern +} + +fn pinned_or_patterns_are_still_ambiguous(pin_const: &pin const i32) { + match pin_const { + &pin const (0 | 1) => {} + _ => {} + } +} + +fn plain_shared_reference_patterns_still_need_parens(shared: &i32) { + let &(mut _x) = shared; + + let &(mut ref _x) = shared; + + let &(mut ref pin const _x) = shared; +} + +fn main() {} diff --git a/tests/ui/lint/unused-parens-pinned-reference-patterns.rs b/tests/ui/lint/unused-parens-pinned-reference-patterns.rs new file mode 100644 index 0000000000000..040ba3e45bf45 --- /dev/null +++ b/tests/ui/lint/unused-parens-pinned-reference-patterns.rs @@ -0,0 +1,56 @@ +//@ run-rustfix +//@ check-pass +//@ normalize-stderr: "warning: 9 warnings emitted\n\n" -> "warning: 9 warnings emitted\n" +#![feature(pin_ergonomics, mut_ref)] +#![allow(dead_code)] +#![warn(unused_parens)] + +fn pinned_reference_patterns( + pin_const: &pin const i32, + pin_mut: &pin mut i32, + nested_pin_const: &pin const &pin const i32, +) { + let &pin const (_x) = pin_const; + //~^ WARN unnecessary parentheses around pattern + + let &pin const (mut _x) = pin_const; + //~^ WARN unnecessary parentheses around pattern + + let &pin const (mut _x @ _) = pin_const; + //~^ WARN unnecessary parentheses around pattern + + let &pin mut (mut _x) = pin_mut; + //~^ WARN unnecessary parentheses around pattern + + let &pin const (&pin const _x) = nested_pin_const; + //~^ WARN unnecessary parentheses around pattern + + let &pin const (ref pin const _x) = pin_const; + //~^ WARN unnecessary parentheses around pattern + + let &pin mut (ref pin mut _x) = pin_mut; + //~^ WARN unnecessary parentheses around pattern + + let &pin const (mut ref pin const _x) = pin_const; + //~^ WARN unnecessary parentheses around pattern + + let &pin mut (mut ref pin mut _x) = pin_mut; + //~^ WARN unnecessary parentheses around pattern +} + +fn pinned_or_patterns_are_still_ambiguous(pin_const: &pin const i32) { + match pin_const { + &pin const (0 | 1) => {} + _ => {} + } +} + +fn plain_shared_reference_patterns_still_need_parens(shared: &i32) { + let &(mut _x) = shared; + + let &(mut ref _x) = shared; + + let &(mut ref pin const _x) = shared; +} + +fn main() {} diff --git a/tests/ui/lint/unused-parens-pinned-reference-patterns.stderr b/tests/ui/lint/unused-parens-pinned-reference-patterns.stderr new file mode 100644 index 0000000000000..15921b6864d7d --- /dev/null +++ b/tests/ui/lint/unused-parens-pinned-reference-patterns.stderr @@ -0,0 +1,114 @@ +warning: unnecessary parentheses around pattern + --> $DIR/unused-parens-pinned-reference-patterns.rs:13:20 + | +LL | let &pin const (_x) = pin_const; + | ^ ^ + | +note: the lint level is defined here + --> $DIR/unused-parens-pinned-reference-patterns.rs:6:9 + | +LL | #![warn(unused_parens)] + | ^^^^^^^^^^^^^ +help: remove these parentheses + | +LL - let &pin const (_x) = pin_const; +LL + let &pin const _x = pin_const; + | + +warning: unnecessary parentheses around pattern + --> $DIR/unused-parens-pinned-reference-patterns.rs:16:20 + | +LL | let &pin const (mut _x) = pin_const; + | ^ ^ + | +help: remove these parentheses + | +LL - let &pin const (mut _x) = pin_const; +LL + let &pin const mut _x = pin_const; + | + +warning: unnecessary parentheses around pattern + --> $DIR/unused-parens-pinned-reference-patterns.rs:19:20 + | +LL | let &pin const (mut _x @ _) = pin_const; + | ^ ^ + | +help: remove these parentheses + | +LL - let &pin const (mut _x @ _) = pin_const; +LL + let &pin const mut _x @ _ = pin_const; + | + +warning: unnecessary parentheses around pattern + --> $DIR/unused-parens-pinned-reference-patterns.rs:22:18 + | +LL | let &pin mut (mut _x) = pin_mut; + | ^ ^ + | +help: remove these parentheses + | +LL - let &pin mut (mut _x) = pin_mut; +LL + let &pin mut mut _x = pin_mut; + | + +warning: unnecessary parentheses around pattern + --> $DIR/unused-parens-pinned-reference-patterns.rs:25:20 + | +LL | let &pin const (&pin const _x) = nested_pin_const; + | ^ ^ + | +help: remove these parentheses + | +LL - let &pin const (&pin const _x) = nested_pin_const; +LL + let &pin const &pin const _x = nested_pin_const; + | + +warning: unnecessary parentheses around pattern + --> $DIR/unused-parens-pinned-reference-patterns.rs:28:20 + | +LL | let &pin const (ref pin const _x) = pin_const; + | ^ ^ + | +help: remove these parentheses + | +LL - let &pin const (ref pin const _x) = pin_const; +LL + let &pin const ref pin const _x = pin_const; + | + +warning: unnecessary parentheses around pattern + --> $DIR/unused-parens-pinned-reference-patterns.rs:31:18 + | +LL | let &pin mut (ref pin mut _x) = pin_mut; + | ^ ^ + | +help: remove these parentheses + | +LL - let &pin mut (ref pin mut _x) = pin_mut; +LL + let &pin mut ref pin mut _x = pin_mut; + | + +warning: unnecessary parentheses around pattern + --> $DIR/unused-parens-pinned-reference-patterns.rs:34:20 + | +LL | let &pin const (mut ref pin const _x) = pin_const; + | ^ ^ + | +help: remove these parentheses + | +LL - let &pin const (mut ref pin const _x) = pin_const; +LL + let &pin const mut ref pin const _x = pin_const; + | + +warning: unnecessary parentheses around pattern + --> $DIR/unused-parens-pinned-reference-patterns.rs:37:18 + | +LL | let &pin mut (mut ref pin mut _x) = pin_mut; + | ^ ^ + | +help: remove these parentheses + | +LL - let &pin mut (mut ref pin mut _x) = pin_mut; +LL + let &pin mut mut ref pin mut _x = pin_mut; + | + +warning: 9 warnings emitted