about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2021-06-10 20:32:43 +0000
committerbors <bors@rust-lang.org>2021-06-10 20:32:43 +0000
commit16e18395ce33ca1ebfe60a591fb2f9317a75d822 (patch)
tree166a43159b96252a1054b698186e2c55b21d541e /src
parentc622840b909428bc77ab67f4f4fb61d03abb65eb (diff)
parent69363492337fa5280d8242f8b68de9a4b60a8b55 (diff)
downloadrust-16e18395ce33ca1ebfe60a591fb2f9317a75d822.tar.gz
rust-16e18395ce33ca1ebfe60a591fb2f9317a75d822.zip
Auto merge of #80080 - rylev:qpath-on-struct, r=petrochenkov
Allow qualified paths in struct construction (both expressions and patterns)

Fixes #79658
Diffstat (limited to 'src')
-rw-r--r--src/doc/unstable-book/src/language-features/more-qualified-paths.md29
-rw-r--r--src/test/ui-fulldeps/pprust-expr-roundtrip.rs127
-rw-r--r--src/test/ui/associated-types/associated-type-destructuring-assignment.rs11
-rw-r--r--src/test/ui/associated-types/associated-type-macro.rs4
-rw-r--r--src/test/ui/associated-types/associated-type-macro.stderr8
-rw-r--r--src/test/ui/associated-types/associated-type-struct-construction.rs24
-rw-r--r--src/test/ui/associated-types/associated-type-tuple-struct-construction.rs24
-rw-r--r--src/test/ui/associated-types/associated-type-tuple-struct-construction.stderr19
-rw-r--r--src/test/ui/feature-gates/feature-gate-more-qualified-paths.rs27
-rw-r--r--src/test/ui/feature-gates/feature-gate-more-qualified-paths.stderr30
-rw-r--r--src/test/ui/parser/brace-after-qualified-path-in-match.rs7
-rw-r--r--src/test/ui/parser/brace-after-qualified-path-in-match.stderr10
-rw-r--r--src/test/ui/parser/paren-after-qualified-path-in-match.rs7
-rw-r--r--src/test/ui/parser/paren-after-qualified-path-in-match.stderr10
-rw-r--r--src/tools/clippy/clippy_lints/src/misc_early/unneeded_field_pattern.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/misc_early/unneeded_wildcard_pattern.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/non_expressive_names.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs16
-rw-r--r--src/tools/clippy/clippy_utils/src/ast_utils.rs17
-rw-r--r--src/tools/rustfmt/src/expr.rs4
-rw-r--r--src/tools/rustfmt/src/patterns.rs6
21 files changed, 267 insertions, 119 deletions
diff --git a/src/doc/unstable-book/src/language-features/more-qualified-paths.md b/src/doc/unstable-book/src/language-features/more-qualified-paths.md
new file mode 100644
index 00000000000..857af577a6c
--- /dev/null
+++ b/src/doc/unstable-book/src/language-features/more-qualified-paths.md
@@ -0,0 +1,29 @@
+# `more_qualified_paths`
+
+The `more_qualified_paths` feature can be used in order to enable the
+use of qualified paths in patterns.
+
+## Example
+
+```rust
+#![feature(more_qualified_paths)]
+
+fn main() {
+    // destructure through a qualified path
+    let <Foo as A>::Assoc { br } = StructStruct { br: 2 };
+}
+
+struct StructStruct {
+    br: i8,
+}
+
+struct Foo;
+
+trait A {
+    type Assoc;
+}
+
+impl A for Foo {
+    type Assoc = StructStruct;
+}
+```
diff --git a/src/test/ui-fulldeps/pprust-expr-roundtrip.rs b/src/test/ui-fulldeps/pprust-expr-roundtrip.rs
index ac2d29c9caf..091c834eccf 100644
--- a/src/test/ui-fulldeps/pprust-expr-roundtrip.rs
+++ b/src/test/ui-fulldeps/pprust-expr-roundtrip.rs
@@ -19,45 +19,35 @@
 
 #![feature(rustc_private)]
 
+extern crate rustc_ast;
 extern crate rustc_ast_pretty;
 extern crate rustc_data_structures;
-extern crate rustc_ast;
 extern crate rustc_parse;
 extern crate rustc_session;
 extern crate rustc_span;
 
+use rustc_ast::mut_visit::{self, visit_clobber, MutVisitor};
+use rustc_ast::ptr::P;
+use rustc_ast::*;
 use rustc_ast_pretty::pprust;
 use rustc_data_structures::thin_vec::ThinVec;
 use rustc_parse::new_parser_from_source_str;
 use rustc_session::parse::ParseSess;
-use rustc_span::source_map::{Spanned, DUMMY_SP, FileName};
 use rustc_span::source_map::FilePathMapping;
+use rustc_span::source_map::{FileName, Spanned, DUMMY_SP};
 use rustc_span::symbol::Ident;
-use rustc_ast::*;
-use rustc_ast::mut_visit::{self, MutVisitor, visit_clobber};
-use rustc_ast::ptr::P;
 
 fn parse_expr(ps: &ParseSess, src: &str) -> Option<P<Expr>> {
     let src_as_string = src.to_string();
 
-    let mut p = new_parser_from_source_str(
-        ps,
-        FileName::Custom(src_as_string.clone()),
-        src_as_string,
-    );
+    let mut p =
+        new_parser_from_source_str(ps, FileName::Custom(src_as_string.clone()), src_as_string);
     p.parse_expr().map_err(|mut e| e.cancel()).ok()
 }
 
-
 // Helper functions for building exprs
 fn expr(kind: ExprKind) -> P<Expr> {
-    P(Expr {
-        id: DUMMY_NODE_ID,
-        kind,
-        span: DUMMY_SP,
-        attrs: ThinVec::new(),
-        tokens: None
-    })
+    P(Expr { id: DUMMY_NODE_ID, kind, span: DUMMY_SP, attrs: ThinVec::new(), tokens: None })
 }
 
 fn make_x() -> P<Expr> {
@@ -83,11 +73,13 @@ fn iter_exprs(depth: usize, f: &mut dyn FnMut(P<Expr>)) {
             1 => iter_exprs(depth - 1, &mut |e| g(ExprKind::Call(e, vec![]))),
             2 => {
                 let seg = PathSegment::from_ident(Ident::from_str("x"));
-                iter_exprs(depth - 1, &mut |e| g(ExprKind::MethodCall(
-                            seg.clone(), vec![e, make_x()], DUMMY_SP)));
-                iter_exprs(depth - 1, &mut |e| g(ExprKind::MethodCall(
-                            seg.clone(), vec![make_x(), e], DUMMY_SP)));
-            },
+                iter_exprs(depth - 1, &mut |e| {
+                    g(ExprKind::MethodCall(seg.clone(), vec![e, make_x()], DUMMY_SP))
+                });
+                iter_exprs(depth - 1, &mut |e| {
+                    g(ExprKind::MethodCall(seg.clone(), vec![make_x(), e], DUMMY_SP))
+                });
+            }
             3..=8 => {
                 let op = Spanned {
                     span: DUMMY_SP,
@@ -99,14 +91,14 @@ fn iter_exprs(depth: usize, f: &mut dyn FnMut(P<Expr>)) {
                         7 => BinOpKind::Or,
                         8 => BinOpKind::Lt,
                         _ => unreachable!(),
-                    }
+                    },
                 };
                 iter_exprs(depth - 1, &mut |e| g(ExprKind::Binary(op, e, make_x())));
                 iter_exprs(depth - 1, &mut |e| g(ExprKind::Binary(op, make_x(), e)));
-            },
+            }
             9 => {
                 iter_exprs(depth - 1, &mut |e| g(ExprKind::Unary(UnOp::Deref, e)));
-            },
+            }
             10 => {
                 let block = P(Block {
                     stmts: Vec::new(),
@@ -116,67 +108,66 @@ fn iter_exprs(depth: usize, f: &mut dyn FnMut(P<Expr>)) {
                     tokens: None,
                 });
                 iter_exprs(depth - 1, &mut |e| g(ExprKind::If(e, block.clone(), None)));
-            },
+            }
             11 => {
-                let decl = P(FnDecl {
-                    inputs: vec![],
-                    output: FnRetTy::Default(DUMMY_SP),
+                let decl = P(FnDecl { inputs: vec![], output: FnRetTy::Default(DUMMY_SP) });
+                iter_exprs(depth - 1, &mut |e| {
+                    g(ExprKind::Closure(
+                        CaptureBy::Value,
+                        Async::No,
+                        Movability::Movable,
+                        decl.clone(),
+                        e,
+                        DUMMY_SP,
+                    ))
                 });
-                iter_exprs(depth - 1, &mut |e| g(
-                        ExprKind::Closure(CaptureBy::Value,
-                                          Async::No,
-                                          Movability::Movable,
-                                          decl.clone(),
-                                          e,
-                                          DUMMY_SP)));
-            },
+            }
             12 => {
                 iter_exprs(depth - 1, &mut |e| g(ExprKind::Assign(e, make_x(), DUMMY_SP)));
                 iter_exprs(depth - 1, &mut |e| g(ExprKind::Assign(make_x(), e, DUMMY_SP)));
-            },
+            }
             13 => {
                 iter_exprs(depth - 1, &mut |e| g(ExprKind::Field(e, Ident::from_str("f"))));
-            },
+            }
             14 => {
-                iter_exprs(depth - 1, &mut |e| g(ExprKind::Range(
-                            Some(e), Some(make_x()), RangeLimits::HalfOpen)));
-                iter_exprs(depth - 1, &mut |e| g(ExprKind::Range(
-                            Some(make_x()), Some(e), RangeLimits::HalfOpen)));
-            },
+                iter_exprs(depth - 1, &mut |e| {
+                    g(ExprKind::Range(Some(e), Some(make_x()), RangeLimits::HalfOpen))
+                });
+                iter_exprs(depth - 1, &mut |e| {
+                    g(ExprKind::Range(Some(make_x()), Some(e), RangeLimits::HalfOpen))
+                });
+            }
             15 => {
-                iter_exprs(
-                    depth - 1,
-                    &mut |e| g(ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, e)),
-                );
-            },
+                iter_exprs(depth - 1, &mut |e| {
+                    g(ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, e))
+                });
+            }
             16 => {
                 g(ExprKind::Ret(None));
                 iter_exprs(depth - 1, &mut |e| g(ExprKind::Ret(Some(e))));
-            },
+            }
             17 => {
                 let path = Path::from_ident(Ident::from_str("S"));
                 g(ExprKind::Struct(P(StructExpr {
-                    path, fields: vec![], rest: StructRest::Base(make_x())
+                    qself: None,
+                    path,
+                    fields: vec![],
+                    rest: StructRest::Base(make_x()),
                 })));
-            },
+            }
             18 => {
                 iter_exprs(depth - 1, &mut |e| g(ExprKind::Try(e)));
-            },
+            }
             19 => {
-                let pat = P(Pat {
-                    id: DUMMY_NODE_ID,
-                    kind: PatKind::Wild,
-                    span: DUMMY_SP,
-                    tokens: None,
-                });
+                let pat =
+                    P(Pat { id: DUMMY_NODE_ID, kind: PatKind::Wild, span: DUMMY_SP, tokens: None });
                 iter_exprs(depth - 1, &mut |e| g(ExprKind::Let(pat.clone(), e)))
-            },
+            }
             _ => panic!("bad counter value in iter_exprs"),
         }
     }
 }
 
-
 // Folders for manipulating the placement of `Paren` nodes. See below for why this is needed.
 
 /// `MutVisitor` that removes all `ExprKind::Paren` nodes.
@@ -192,7 +183,6 @@ impl MutVisitor for RemoveParens {
     }
 }
 
-
 /// `MutVisitor` that inserts `ExprKind::Paren` nodes around every `Expr`.
 struct AddParens;
 
@@ -205,7 +195,7 @@ impl MutVisitor for AddParens {
                 kind: ExprKind::Paren(e),
                 span: DUMMY_SP,
                 attrs: ThinVec::new(),
-                tokens: None
+                tokens: None,
             })
         });
     }
@@ -238,9 +228,12 @@ fn run() {
             RemoveParens.visit_expr(&mut parsed);
             AddParens.visit_expr(&mut parsed);
             let text2 = pprust::expr_to_string(&parsed);
-            assert!(text1 == text2,
-                    "exprs are not equal:\n  e =      {:?}\n  parsed = {:?}",
-                    text1, text2);
+            assert!(
+                text1 == text2,
+                "exprs are not equal:\n  e =      {:?}\n  parsed = {:?}",
+                text1,
+                text2
+            );
         }
     });
 }
diff --git a/src/test/ui/associated-types/associated-type-destructuring-assignment.rs b/src/test/ui/associated-types/associated-type-destructuring-assignment.rs
new file mode 100644
index 00000000000..fea7c7a383f
--- /dev/null
+++ b/src/test/ui/associated-types/associated-type-destructuring-assignment.rs
@@ -0,0 +1,11 @@
+// check-pass
+
+#![feature(destructuring_assignment)]
+#![feature(more_qualified_paths)]
+
+enum E { V() }
+
+fn main() {
+    <E>::V() = E::V(); // OK, destructuring assignment
+    <E>::V {} = E::V(); // OK, destructuring assignment
+}
diff --git a/src/test/ui/associated-types/associated-type-macro.rs b/src/test/ui/associated-types/associated-type-macro.rs
new file mode 100644
index 00000000000..22b5bca4010
--- /dev/null
+++ b/src/test/ui/associated-types/associated-type-macro.rs
@@ -0,0 +1,4 @@
+fn main() {
+    #[cfg(FALSE)]
+    <() as module>::mac!(); //~ ERROR macros cannot use qualified paths
+}
diff --git a/src/test/ui/associated-types/associated-type-macro.stderr b/src/test/ui/associated-types/associated-type-macro.stderr
new file mode 100644
index 00000000000..6a4cf99c474
--- /dev/null
+++ b/src/test/ui/associated-types/associated-type-macro.stderr
@@ -0,0 +1,8 @@
+error: macros cannot use qualified paths
+  --> $DIR/associated-type-macro.rs:3:5
+   |
+LL |     <() as module>::mac!();
+   |     ^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/associated-types/associated-type-struct-construction.rs b/src/test/ui/associated-types/associated-type-struct-construction.rs
new file mode 100644
index 00000000000..f8f8048fb71
--- /dev/null
+++ b/src/test/ui/associated-types/associated-type-struct-construction.rs
@@ -0,0 +1,24 @@
+// Make sure that users can construct structs through associated types
+// in both expressions and patterns
+
+#![feature(more_qualified_paths)]
+
+// check-pass
+fn main() {
+    let <Foo as A>::Assoc { br } = <Foo as A>::Assoc { br: 2 };
+    assert!(br == 2);
+}
+
+struct StructStruct {
+    br: i8,
+}
+
+struct Foo;
+
+trait A {
+    type Assoc;
+}
+
+impl A for Foo {
+    type Assoc = StructStruct;
+}
diff --git a/src/test/ui/associated-types/associated-type-tuple-struct-construction.rs b/src/test/ui/associated-types/associated-type-tuple-struct-construction.rs
new file mode 100644
index 00000000000..d5809ecd55d
--- /dev/null
+++ b/src/test/ui/associated-types/associated-type-tuple-struct-construction.rs
@@ -0,0 +1,24 @@
+// Users cannot yet construct structs through associated types
+// in both expressions and patterns
+
+#![feature(more_qualified_paths)]
+
+fn main() {
+    let <Foo as A>::Assoc(n) = <Foo as A>::Assoc(2);
+    //~^ ERROR expected method or associated constant, found associated type
+    //~| ERROR expected method or associated constant, found associated type
+    assert!(n == 2);
+}
+
+struct TupleStruct(i8);
+
+struct Foo;
+
+
+trait A {
+    type Assoc;
+}
+
+impl A for Foo {
+    type Assoc = TupleStruct;
+}
diff --git a/src/test/ui/associated-types/associated-type-tuple-struct-construction.stderr b/src/test/ui/associated-types/associated-type-tuple-struct-construction.stderr
new file mode 100644
index 00000000000..bca7deeb512
--- /dev/null
+++ b/src/test/ui/associated-types/associated-type-tuple-struct-construction.stderr
@@ -0,0 +1,19 @@
+error[E0575]: expected method or associated constant, found associated type `A::Assoc`
+  --> $DIR/associated-type-tuple-struct-construction.rs:7:32
+   |
+LL |     let <Foo as A>::Assoc(n) = <Foo as A>::Assoc(2);
+   |                                ^^^^^^^^^^^^^^^^^
+   |
+   = note: can't use a type alias as a constructor
+
+error[E0575]: expected method or associated constant, found associated type `A::Assoc`
+  --> $DIR/associated-type-tuple-struct-construction.rs:7:9
+   |
+LL |     let <Foo as A>::Assoc(n) = <Foo as A>::Assoc(2);
+   |         ^^^^^^^^^^^^^^^^^
+   |
+   = note: can't use a type alias as a constructor
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0575`.
diff --git a/src/test/ui/feature-gates/feature-gate-more-qualified-paths.rs b/src/test/ui/feature-gates/feature-gate-more-qualified-paths.rs
new file mode 100644
index 00000000000..2e05acbfa17
--- /dev/null
+++ b/src/test/ui/feature-gates/feature-gate-more-qualified-paths.rs
@@ -0,0 +1,27 @@
+fn main() {
+    // destructure through a qualified path
+    let <Foo as A>::Assoc { br } = StructStruct { br: 2 };
+    //~^ ERROR usage of qualified paths in this context is experimental
+    let _ = <Foo as A>::Assoc { br: 2 };
+    //~^ ERROR usage of qualified paths in this context is experimental
+    let <E>::V(..) = E::V(0);
+    //~^ ERROR usage of qualified paths in this context is experimental
+}
+
+struct StructStruct {
+    br: i8,
+}
+
+struct Foo;
+
+trait A {
+    type Assoc;
+}
+
+impl A for Foo {
+    type Assoc = StructStruct;
+}
+
+enum E {
+    V(u8)
+}
diff --git a/src/test/ui/feature-gates/feature-gate-more-qualified-paths.stderr b/src/test/ui/feature-gates/feature-gate-more-qualified-paths.stderr
new file mode 100644
index 00000000000..b49cc40800f
--- /dev/null
+++ b/src/test/ui/feature-gates/feature-gate-more-qualified-paths.stderr
@@ -0,0 +1,30 @@
+error[E0658]: usage of qualified paths in this context is experimental
+  --> $DIR/feature-gate-more-qualified-paths.rs:3:9
+   |
+LL |     let <Foo as A>::Assoc { br } = StructStruct { br: 2 };
+   |         ^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #80080 <https://github.com/rust-lang/rust/issues/80080> for more information
+   = help: add `#![feature(more_qualified_paths)]` to the crate attributes to enable
+
+error[E0658]: usage of qualified paths in this context is experimental
+  --> $DIR/feature-gate-more-qualified-paths.rs:5:13
+   |
+LL |     let _ = <Foo as A>::Assoc { br: 2 };
+   |             ^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #80080 <https://github.com/rust-lang/rust/issues/80080> for more information
+   = help: add `#![feature(more_qualified_paths)]` to the crate attributes to enable
+
+error[E0658]: usage of qualified paths in this context is experimental
+  --> $DIR/feature-gate-more-qualified-paths.rs:7:9
+   |
+LL |     let <E>::V(..) = E::V(0);
+   |         ^^^^^^
+   |
+   = note: see issue #80080 <https://github.com/rust-lang/rust/issues/80080> for more information
+   = help: add `#![feature(more_qualified_paths)]` to the crate attributes to enable
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/parser/brace-after-qualified-path-in-match.rs b/src/test/ui/parser/brace-after-qualified-path-in-match.rs
deleted file mode 100644
index f4152086162..00000000000
--- a/src/test/ui/parser/brace-after-qualified-path-in-match.rs
+++ /dev/null
@@ -1,7 +0,0 @@
-fn main() {
-    match 10 {
-        <T as Trait>::Type{key: value} => (),
-        //~^ ERROR unexpected `{` after qualified path
-        _ => (),
-    }
-}
diff --git a/src/test/ui/parser/brace-after-qualified-path-in-match.stderr b/src/test/ui/parser/brace-after-qualified-path-in-match.stderr
deleted file mode 100644
index d6fdf353f07..00000000000
--- a/src/test/ui/parser/brace-after-qualified-path-in-match.stderr
+++ /dev/null
@@ -1,10 +0,0 @@
-error: unexpected `{` after qualified path
-  --> $DIR/brace-after-qualified-path-in-match.rs:3:27
-   |
-LL |         <T as Trait>::Type{key: value} => (),
-   |         ------------------^ unexpected `{` after qualified path
-   |         |
-   |         the qualified path
-
-error: aborting due to previous error
-
diff --git a/src/test/ui/parser/paren-after-qualified-path-in-match.rs b/src/test/ui/parser/paren-after-qualified-path-in-match.rs
deleted file mode 100644
index 68b1c2baf10..00000000000
--- a/src/test/ui/parser/paren-after-qualified-path-in-match.rs
+++ /dev/null
@@ -1,7 +0,0 @@
-fn main() {
-    match 10 {
-        <T as Trait>::Type(2) => (),
-        //~^ ERROR unexpected `(` after qualified path
-        _ => (),
-    }
-}
diff --git a/src/test/ui/parser/paren-after-qualified-path-in-match.stderr b/src/test/ui/parser/paren-after-qualified-path-in-match.stderr
deleted file mode 100644
index af21f919546..00000000000
--- a/src/test/ui/parser/paren-after-qualified-path-in-match.stderr
+++ /dev/null
@@ -1,10 +0,0 @@
-error: unexpected `(` after qualified path
-  --> $DIR/paren-after-qualified-path-in-match.rs:3:27
-   |
-LL |         <T as Trait>::Type(2) => (),
-   |         ------------------^ unexpected `(` after qualified path
-   |         |
-   |         the qualified path
-
-error: aborting due to previous error
-
diff --git a/src/tools/clippy/clippy_lints/src/misc_early/unneeded_field_pattern.rs b/src/tools/clippy/clippy_lints/src/misc_early/unneeded_field_pattern.rs
index 329a0009a3e..2201cf56d52 100644
--- a/src/tools/clippy/clippy_lints/src/misc_early/unneeded_field_pattern.rs
+++ b/src/tools/clippy/clippy_lints/src/misc_early/unneeded_field_pattern.rs
@@ -5,7 +5,7 @@ use rustc_lint::{EarlyContext, LintContext};
 use super::UNNEEDED_FIELD_PATTERN;
 
 pub(super) fn check(cx: &EarlyContext<'_>, pat: &Pat) {
-    if let PatKind::Struct(ref npat, ref pfields, _) = pat.kind {
+    if let PatKind::Struct(_, ref npat, ref pfields, _) = pat.kind {
         let mut wilds = 0;
         let type_name = npat
             .segments
diff --git a/src/tools/clippy/clippy_lints/src/misc_early/unneeded_wildcard_pattern.rs b/src/tools/clippy/clippy_lints/src/misc_early/unneeded_wildcard_pattern.rs
index 4dd032d78f1..df044538fe1 100644
--- a/src/tools/clippy/clippy_lints/src/misc_early/unneeded_wildcard_pattern.rs
+++ b/src/tools/clippy/clippy_lints/src/misc_early/unneeded_wildcard_pattern.rs
@@ -7,7 +7,7 @@ use rustc_span::source_map::Span;
 use super::UNNEEDED_WILDCARD_PATTERN;
 
 pub(super) fn check(cx: &EarlyContext<'_>, pat: &Pat) {
-    if let PatKind::TupleStruct(_, ref patterns) | PatKind::Tuple(ref patterns) = pat.kind {
+    if let PatKind::TupleStruct(_, _, ref patterns) | PatKind::Tuple(ref patterns) = pat.kind {
         if let Some(rest_index) = patterns.iter().position(|pat| pat.is_rest()) {
             if let Some((left_index, left_pat)) = patterns[..rest_index]
                 .iter()
diff --git a/src/tools/clippy/clippy_lints/src/non_expressive_names.rs b/src/tools/clippy/clippy_lints/src/non_expressive_names.rs
index 5292af5f076..1a23e6afe28 100644
--- a/src/tools/clippy/clippy_lints/src/non_expressive_names.rs
+++ b/src/tools/clippy/clippy_lints/src/non_expressive_names.rs
@@ -139,7 +139,7 @@ impl<'a, 'tcx, 'b> Visitor<'tcx> for SimilarNamesNameVisitor<'a, 'tcx, 'b> {
                     self.check_ident(ident);
                 }
             },
-            PatKind::Struct(_, ref fields, _) => {
+            PatKind::Struct(_, _, ref fields, _) => {
                 for field in fields {
                     if !field.is_shorthand {
                         self.visit_pat(&field.pat);
diff --git a/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs b/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs
index 3e985fa72b8..1b3c457b01a 100644
--- a/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs
+++ b/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs
@@ -1,6 +1,6 @@
 #![allow(clippy::wildcard_imports, clippy::enum_glob_use)]
 
-use clippy_utils::ast_utils::{eq_field_pat, eq_id, eq_pat, eq_path};
+use clippy_utils::ast_utils::{eq_field_pat, eq_id, eq_pat, eq_path, eq_maybe_qself};
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::{meets_msrv, msrvs, over};
 use rustc_ast::mut_visit::*;
@@ -273,16 +273,16 @@ fn transform_with_focus_on_idx(alternatives: &mut Vec<P<Pat>>, focus_idx: usize)
             |k| always_pat!(k, Tuple(ps) => ps),
         ),
         // Transform `S(pre, x, post) | ... | S(pre, y, post)` into `S(pre, x | y, post)`.
-        TupleStruct(path1, ps1) => extend_with_matching_product(
+        TupleStruct(qself1, path1, ps1) => extend_with_matching_product(
             ps1, start, alternatives,
             |k, ps1, idx| matches!(
                 k,
-                TupleStruct(path2, ps2) if eq_path(path1, path2) && eq_pre_post(ps1, ps2, idx)
+                TupleStruct(qself2, path2, ps2) if eq_maybe_qself(qself1, qself2) && eq_path(path1, path2) && eq_pre_post(ps1, ps2, idx)
             ),
-            |k| always_pat!(k, TupleStruct(_, ps) => ps),
+            |k| always_pat!(k, TupleStruct(_, _, ps) => ps),
         ),
         // Transform a record pattern `S { fp_0, ..., fp_n }`.
-        Struct(path1, fps1, rest1) => extend_with_struct_pat(path1, fps1, *rest1, start, alternatives),
+        Struct(qself1, path1, fps1, rest1) => extend_with_struct_pat(qself1, path1, fps1, *rest1, start, alternatives),
     };
 
     alternatives[focus_idx].kind = focus_kind;
@@ -294,6 +294,7 @@ fn transform_with_focus_on_idx(alternatives: &mut Vec<P<Pat>>, focus_idx: usize)
 /// So when we fixate on some `ident_k: pat_k`, we try to find `ident_k` in the other pattern
 /// and check that all `fp_i` where `i ∈ ((0...n) \ k)` between two patterns are equal.
 fn extend_with_struct_pat(
+    qself1: &Option<ast::QSelf>,
     path1: &ast::Path,
     fps1: &mut Vec<ast::PatField>,
     rest1: bool,
@@ -306,8 +307,9 @@ fn extend_with_struct_pat(
             start,
             alternatives,
             |k| {
-                matches!(k, Struct(path2, fps2, rest2)
+                matches!(k, Struct(qself2, path2, fps2, rest2)
                 if rest1 == *rest2 // If one struct pattern has `..` so must the other.
+                && eq_maybe_qself(qself1, qself2)
                 && eq_path(path1, path2)
                 && fps1.len() == fps2.len()
                 && fps1.iter().enumerate().all(|(idx_1, fp1)| {
@@ -323,7 +325,7 @@ fn extend_with_struct_pat(
                 }))
             },
             // Extract `p2_k`.
-            |k| always_pat!(k, Struct(_, mut fps, _) => fps.swap_remove(pos_in_2.take().unwrap()).pat),
+            |k| always_pat!(k, Struct(_, _, mut fps, _) => fps.swap_remove(pos_in_2.take().unwrap()).pat),
         );
         extend_with_tail_or(&mut fps1[idx].pat, tail_or)
     })
diff --git a/src/tools/clippy/clippy_utils/src/ast_utils.rs b/src/tools/clippy/clippy_utils/src/ast_utils.rs
index 93e10c836cc..e6d84bc7560 100644
--- a/src/tools/clippy/clippy_utils/src/ast_utils.rs
+++ b/src/tools/clippy/clippy_utils/src/ast_utils.rs
@@ -47,9 +47,9 @@ pub fn eq_pat(l: &Pat, r: &Pat) -> bool {
         | (Ref(l, Mutability::Mut), Ref(r, Mutability::Mut)) => eq_pat(l, r),
         (Tuple(l), Tuple(r)) | (Slice(l), Slice(r)) => over(l, r, |l, r| eq_pat(l, r)),
         (Path(lq, lp), Path(rq, rp)) => both(lq, rq, |l, r| eq_qself(l, r)) && eq_path(lp, rp),
-        (TupleStruct(lp, lfs), TupleStruct(rp, rfs)) => eq_path(lp, rp) && over(lfs, rfs, |l, r| eq_pat(l, r)),
-        (Struct(lp, lfs, lr), Struct(rp, rfs, rr)) => {
-            lr == rr && eq_path(lp, rp) && unordered_over(lfs, rfs, |lf, rf| eq_field_pat(lf, rf))
+        (TupleStruct(lqself, lp, lfs), TupleStruct(rqself, rp, rfs)) => eq_maybe_qself(lqself, rqself) && eq_path(lp, rp) && over(lfs, rfs, |l, r| eq_pat(l, r)),
+        (Struct(lqself, lp, lfs, lr), Struct(rqself, rp, rfs, rr)) => {
+            lr == rr && eq_maybe_qself(lqself, rqself) &&eq_path(lp, rp) && unordered_over(lfs, rfs, |lf, rf| eq_field_pat(lf, rf))
         },
         (Or(ls), Or(rs)) => unordered_over(ls, rs, |l, r| eq_pat(l, r)),
         (MacCall(l), MacCall(r)) => eq_mac_call(l, r),
@@ -78,6 +78,14 @@ pub fn eq_qself(l: &QSelf, r: &QSelf) -> bool {
     l.position == r.position && eq_ty(&l.ty, &r.ty)
 }
 
+pub fn eq_maybe_qself(l: &Option<QSelf>, r: &Option<QSelf>) -> bool {
+    match (l, r) {
+        (Some(l), Some(r)) => eq_qself(l, r),
+        (None, None) => true,
+        _ => false
+    }
+}
+
 pub fn eq_path(l: &Path, r: &Path) -> bool {
     over(&l.segments, &r.segments, |l, r| eq_path_seg(l, r))
 }
@@ -170,7 +178,8 @@ pub fn eq_expr(l: &Expr, r: &Expr) -> bool {
         (Path(lq, lp), Path(rq, rp)) => both(lq, rq, |l, r| eq_qself(l, r)) && eq_path(lp, rp),
         (MacCall(l), MacCall(r)) => eq_mac_call(l, r),
         (Struct(lse), Struct(rse)) => {
-            eq_path(&lse.path, &rse.path)
+            eq_maybe_qself(&lse.qself, &rse.qself) 
+                && eq_path(&lse.path, &rse.path)
                 && eq_struct_rest(&lse.rest, &rse.rest)
                 && unordered_over(&lse.fields, &rse.fields, |l, r| eq_field(l, r))
         },
diff --git a/src/tools/rustfmt/src/expr.rs b/src/tools/rustfmt/src/expr.rs
index ced382c4915..bca9f77f959 100644
--- a/src/tools/rustfmt/src/expr.rs
+++ b/src/tools/rustfmt/src/expr.rs
@@ -107,7 +107,9 @@ pub(crate) fn format_expr(
         }
         ast::ExprKind::Unary(op, ref subexpr) => rewrite_unary_op(context, op, subexpr, shape),
         ast::ExprKind::Struct(ref struct_expr) => {
-            let ast::StructExpr { fields, path, rest } = &**struct_expr;
+            let ast::StructExpr {
+                fields, path, rest, ..
+            } = &**struct_expr;
             rewrite_struct_lit(context, path, fields, rest, &expr.attrs, expr.span, shape)
         }
         ast::ExprKind::Tup(ref items) => {
diff --git a/src/tools/rustfmt/src/patterns.rs b/src/tools/rustfmt/src/patterns.rs
index 6824fc661ba..fa0ef260991 100644
--- a/src/tools/rustfmt/src/patterns.rs
+++ b/src/tools/rustfmt/src/patterns.rs
@@ -45,7 +45,7 @@ fn is_short_pattern_inner(pat: &ast::Pat) -> bool {
         | ast::PatKind::Path(..)
         | ast::PatKind::Range(..) => false,
         ast::PatKind::Tuple(ref subpats) => subpats.len() <= 1,
-        ast::PatKind::TupleStruct(ref path, ref subpats) => {
+        ast::PatKind::TupleStruct(_, ref path, ref subpats) => {
             path.segments.len() <= 1 && subpats.len() <= 1
         }
         ast::PatKind::Box(ref p) | ast::PatKind::Ref(ref p, _) | ast::PatKind::Paren(ref p) => {
@@ -226,7 +226,7 @@ impl Rewrite for Pat {
             PatKind::Path(ref q_self, ref path) => {
                 rewrite_path(context, PathContext::Expr, q_self.as_ref(), path, shape)
             }
-            PatKind::TupleStruct(ref path, ref pat_vec) => {
+            PatKind::TupleStruct(_, ref path, ref pat_vec) => {
                 let path_str = rewrite_path(context, PathContext::Expr, None, path, shape)?;
                 rewrite_tuple_pat(pat_vec, Some(path_str), self.span, context, shape)
             }
@@ -244,7 +244,7 @@ impl Rewrite for Pat {
                     .collect();
                 Some(format!("[{}]", rw.join(", ")))
             }
-            PatKind::Struct(ref path, ref fields, ellipsis) => {
+            PatKind::Struct(_, ref path, ref fields, ellipsis) => {
                 rewrite_struct_pat(path, fields, ellipsis, self.span, context, shape)
             }
             PatKind::MacCall(ref mac) => {