about summary refs log tree commit diff
diff options
context:
space:
mode:
authorWaffle Lapkin <waffle.lapkin@gmail.com>2025-04-27 16:05:44 +0200
committerWaffle Lapkin <waffle.lapkin@gmail.com>2025-04-27 18:10:08 +0200
commitbce7fe1818111ed9124412369ff1b36ffe5fdbe1 (patch)
tree1b4479fb73d8764b135f1a313e921dca2f24202d
parent5f294f099a4461fc965d9109a79b8da3f96380b9 (diff)
downloadrust-bce7fe1818111ed9124412369ff1b36ffe5fdbe1.tar.gz
rust-bce7fe1818111ed9124412369ff1b36ffe5fdbe1.zip
Make error for tuple struct pat/expr w/ FQS clearer
1. Fix "expected" and the note for the pattern case
2. Add suggestions
-rw-r--r--compiler/rustc_resolve/src/late.rs31
-rw-r--r--compiler/rustc_resolve/src/late/diagnostics.rs124
-rw-r--r--tests/ui/associated-types/tuple-struct-expr-pat.fixed48
-rw-r--r--tests/ui/associated-types/tuple-struct-expr-pat.rs10
-rw-r--r--tests/ui/associated-types/tuple-struct-expr-pat.stderr66
5 files changed, 222 insertions, 57 deletions
diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs
index bae2fdeecaf..88818ad1280 100644
--- a/compiler/rustc_resolve/src/late.rs
+++ b/compiler/rustc_resolve/src/late.rs
@@ -402,7 +402,7 @@ pub(crate) enum AliasPossibility {
 }
 
 #[derive(Copy, Clone, Debug)]
-pub(crate) enum PathSource<'a> {
+pub(crate) enum PathSource<'a, 'c> {
     /// Type paths `Path`.
     Type,
     /// Trait paths in bounds or impls.
@@ -416,7 +416,10 @@ pub(crate) enum PathSource<'a> {
     /// Paths in tuple struct patterns `Path(..)`.
     TupleStruct(Span, &'a [Span]),
     /// `m::A::B` in `<T as m::A>::B::C`.
-    TraitItem(Namespace),
+    ///
+    /// Second field holds the "cause" of this one, i.e. the context within
+    /// which the trait item is resolved. Used for diagnostics.
+    TraitItem(Namespace, &'c PathSource<'a, 'c>),
     /// Paths in delegation item
     Delegation,
     /// An arg in a `use<'a, N>` precise-capturing bound.
@@ -427,7 +430,7 @@ pub(crate) enum PathSource<'a> {
     DefineOpaques,
 }
 
-impl<'a> PathSource<'a> {
+impl<'a> PathSource<'a, '_> {
     fn namespace(self) -> Namespace {
         match self {
             PathSource::Type
@@ -439,7 +442,7 @@ impl<'a> PathSource<'a> {
             | PathSource::TupleStruct(..)
             | PathSource::Delegation
             | PathSource::ReturnTypeNotation => ValueNS,
-            PathSource::TraitItem(ns) => ns,
+            PathSource::TraitItem(ns, _) => ns,
             PathSource::PreciseCapturingArg(ns) => ns,
         }
     }
@@ -467,8 +470,9 @@ impl<'a> PathSource<'a> {
             PathSource::Trait(_) => "trait",
             PathSource::Pat => "unit struct, unit variant or constant",
             PathSource::Struct => "struct, variant or union type",
-            PathSource::TupleStruct(..) => "tuple struct or tuple variant",
-            PathSource::TraitItem(ns) => match ns {
+            PathSource::TraitItem(ValueNS, PathSource::TupleStruct(..))
+            | PathSource::TupleStruct(..) => "tuple struct or tuple variant",
+            PathSource::TraitItem(ns, _) => match ns {
                 TypeNS => "associated type",
                 ValueNS => "method or associated constant",
                 MacroNS => bug!("associated macro"),
@@ -572,7 +576,7 @@ impl<'a> PathSource<'a> {
                 ) | Res::SelfTyParam { .. }
                     | Res::SelfTyAlias { .. }
             ),
-            PathSource::TraitItem(ns) => match res {
+            PathSource::TraitItem(ns, _) => match res {
                 Res::Def(DefKind::AssocConst | DefKind::AssocFn, _) if ns == ValueNS => true,
                 Res::Def(DefKind::AssocTy, _) if ns == TypeNS => true,
                 _ => false,
@@ -1983,7 +1987,7 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
         &mut self,
         partial_res: PartialRes,
         path: &[Segment],
-        source: PathSource<'_>,
+        source: PathSource<'_, '_>,
         path_span: Span,
     ) {
         let proj_start = path.len() - partial_res.unresolved_segments();
@@ -4135,7 +4139,7 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
         id: NodeId,
         qself: &Option<P<QSelf>>,
         path: &Path,
-        source: PathSource<'ast>,
+        source: PathSource<'ast, '_>,
     ) {
         self.smart_resolve_path_fragment(
             qself,
@@ -4152,7 +4156,7 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
         &mut self,
         qself: &Option<P<QSelf>>,
         path: &[Segment],
-        source: PathSource<'ast>,
+        source: PathSource<'ast, '_>,
         finalize: Finalize,
         record_partial_res: RecordPartialRes,
         parent_qself: Option<&QSelf>,
@@ -4333,6 +4337,7 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
             path_span,
             source.defer_to_typeck(),
             finalize,
+            source,
         ) {
             Ok(Some(partial_res)) if let Some(res) = partial_res.full_res() => {
                 // if we also have an associated type that matches the ident, stash a suggestion
@@ -4455,12 +4460,13 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
         span: Span,
         defer_to_typeck: bool,
         finalize: Finalize,
+        source: PathSource<'ast, '_>,
     ) -> Result<Option<PartialRes>, Spanned<ResolutionError<'ra>>> {
         let mut fin_res = None;
 
         for (i, &ns) in [primary_ns, TypeNS, ValueNS].iter().enumerate() {
             if i == 0 || ns != primary_ns {
-                match self.resolve_qpath(qself, path, ns, finalize)? {
+                match self.resolve_qpath(qself, path, ns, finalize, source)? {
                     Some(partial_res)
                         if partial_res.unresolved_segments() == 0 || defer_to_typeck =>
                     {
@@ -4497,6 +4503,7 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
         path: &[Segment],
         ns: Namespace,
         finalize: Finalize,
+        source: PathSource<'ast, '_>,
     ) -> Result<Option<PartialRes>, Spanned<ResolutionError<'ra>>> {
         debug!(
             "resolve_qpath(qself={:?}, path={:?}, ns={:?}, finalize={:?})",
@@ -4544,7 +4551,7 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
             let partial_res = self.smart_resolve_path_fragment(
                 &None,
                 &path[..=qself.position],
-                PathSource::TraitItem(ns),
+                PathSource::TraitItem(ns, &source),
                 Finalize::with_root_span(finalize.node_id, finalize.path_span, qself.path_span),
                 RecordPartialRes::No,
                 Some(&qself),
diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs
index d4fe446cc9f..ac1479b152d 100644
--- a/compiler/rustc_resolve/src/late/diagnostics.rs
+++ b/compiler/rustc_resolve/src/late/diagnostics.rs
@@ -174,7 +174,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
         &mut self,
         path: &[Segment],
         span: Span,
-        source: PathSource<'_>,
+        source: PathSource<'_, '_>,
         res: Option<Res>,
     ) -> BaseError {
         // Make the base error.
@@ -420,7 +420,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
         path: &[Segment],
         following_seg: Option<&Segment>,
         span: Span,
-        source: PathSource<'_>,
+        source: PathSource<'_, '_>,
         res: Option<Res>,
         qself: Option<&QSelf>,
     ) -> (Diag<'tcx>, Vec<ImportSuggestion>) {
@@ -525,12 +525,12 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
         path: &[Segment],
         following_seg: Option<&Segment>,
         span: Span,
-        source: PathSource<'_>,
+        source: PathSource<'_, '_>,
         res: Option<Res>,
         qself: Option<&QSelf>,
     ) {
         if let Some(Res::Def(DefKind::AssocFn, _)) = res
-            && let PathSource::TraitItem(TypeNS) = source
+            && let PathSource::TraitItem(TypeNS, _) = source
             && let None = following_seg
             && let Some(qself) = qself
             && let TyKind::Path(None, ty_path) = &qself.ty.kind
@@ -636,7 +636,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
     fn try_lookup_name_relaxed(
         &mut self,
         err: &mut Diag<'_>,
-        source: PathSource<'_>,
+        source: PathSource<'_, '_>,
         path: &[Segment],
         following_seg: Option<&Segment>,
         span: Span,
@@ -855,7 +855,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
     fn suggest_trait_and_bounds(
         &mut self,
         err: &mut Diag<'_>,
-        source: PathSource<'_>,
+        source: PathSource<'_, '_>,
         res: Option<Res>,
         span: Span,
         base_error: &BaseError,
@@ -932,7 +932,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
     fn suggest_typo(
         &mut self,
         err: &mut Diag<'_>,
-        source: PathSource<'_>,
+        source: PathSource<'_, '_>,
         path: &[Segment],
         following_seg: Option<&Segment>,
         span: Span,
@@ -978,7 +978,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
     fn suggest_shadowed(
         &mut self,
         err: &mut Diag<'_>,
-        source: PathSource<'_>,
+        source: PathSource<'_, '_>,
         path: &[Segment],
         following_seg: Option<&Segment>,
         span: Span,
@@ -1011,7 +1011,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
     fn err_code_special_cases(
         &mut self,
         err: &mut Diag<'_>,
-        source: PathSource<'_>,
+        source: PathSource<'_, '_>,
         path: &[Segment],
         span: Span,
     ) {
@@ -1056,7 +1056,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
     fn suggest_self_ty(
         &mut self,
         err: &mut Diag<'_>,
-        source: PathSource<'_>,
+        source: PathSource<'_, '_>,
         path: &[Segment],
         span: Span,
     ) -> bool {
@@ -1079,7 +1079,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
     fn suggest_self_value(
         &mut self,
         err: &mut Diag<'_>,
-        source: PathSource<'_>,
+        source: PathSource<'_, '_>,
         path: &[Segment],
         span: Span,
     ) -> bool {
@@ -1247,7 +1247,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
     fn suggest_swapping_misplaced_self_ty_and_trait(
         &mut self,
         err: &mut Diag<'_>,
-        source: PathSource<'_>,
+        source: PathSource<'_, '_>,
         res: Option<Res>,
         span: Span,
     ) {
@@ -1276,7 +1276,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
         &mut self,
         err: &mut Diag<'_>,
         res: Option<Res>,
-        source: PathSource<'_>,
+        source: PathSource<'_, '_>,
     ) {
         let PathSource::TupleStruct(_, _) = source else { return };
         let Some(Res::Def(DefKind::Fn, _)) = res else { return };
@@ -1288,7 +1288,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
         &mut self,
         err: &mut Diag<'_>,
         res: Option<Res>,
-        source: PathSource<'_>,
+        source: PathSource<'_, '_>,
         span: Span,
     ) {
         let PathSource::Trait(_) = source else { return };
@@ -1337,7 +1337,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
     fn suggest_pattern_match_with_let(
         &mut self,
         err: &mut Diag<'_>,
-        source: PathSource<'_>,
+        source: PathSource<'_, '_>,
         span: Span,
     ) -> bool {
         if let PathSource::Expr(_) = source
@@ -1363,10 +1363,10 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
     fn get_single_associated_item(
         &mut self,
         path: &[Segment],
-        source: &PathSource<'_>,
+        source: &PathSource<'_, '_>,
         filter_fn: &impl Fn(Res) -> bool,
     ) -> Option<TypoSuggestion> {
-        if let crate::PathSource::TraitItem(_) = source {
+        if let crate::PathSource::TraitItem(_, _) = source {
             let mod_path = &path[..path.len() - 1];
             if let PathResult::Module(ModuleOrUniformRoot::Module(module)) =
                 self.resolve_path(mod_path, None, None)
@@ -1471,7 +1471,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
 
     /// Check if the source is call expression and the first argument is `self`. If true,
     /// return the span of whole call and the span for all arguments expect the first one (`self`).
-    fn call_has_self_arg(&self, source: PathSource<'_>) -> Option<(Span, Option<Span>)> {
+    fn call_has_self_arg(&self, source: PathSource<'_, '_>) -> Option<(Span, Option<Span>)> {
         let mut has_self_arg = None;
         if let PathSource::Expr(Some(parent)) = source
             && let ExprKind::Call(_, args) = &parent.kind
@@ -1529,7 +1529,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
         &mut self,
         err: &mut Diag<'_>,
         span: Span,
-        source: PathSource<'_>,
+        source: PathSource<'_, '_>,
         path: &[Segment],
         res: Res,
         path_str: &str,
@@ -1581,7 +1581,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
             }
         };
 
-        let find_span = |source: &PathSource<'_>, err: &mut Diag<'_>| {
+        let find_span = |source: &PathSource<'_, '_>, err: &mut Diag<'_>| {
             match source {
                 PathSource::Expr(Some(Expr { span, kind: ExprKind::Call(_, _), .. }))
                 | PathSource::TupleStruct(span, _) => {
@@ -1965,8 +1965,86 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
                 err.span_label(span, fallback_label.to_string());
                 err.note("can't use `Self` as a constructor, you must use the implemented struct");
             }
-            (Res::Def(DefKind::TyAlias | DefKind::AssocTy, _), _) if ns == ValueNS => {
+            (
+                Res::Def(DefKind::TyAlias | DefKind::AssocTy, _),
+                PathSource::TraitItem(ValueNS, PathSource::TupleStruct(whole, args)),
+            ) => {
+                err.note("can't use a type alias as tuple pattern");
+
+                let mut suggestion = Vec::new();
+
+                if let &&[first, ..] = args
+                    && let &&[.., last] = args
+                {
+                    suggestion.extend([
+                        // "0: " has to be included here so that the fix is machine applicable.
+                        //
+                        // If this would only add " { " and then the code below add "0: ",
+                        // rustfix would crash, because end of this suggestion is the same as start
+                        // of the suggestion below. Thus, we have to merge these...
+                        (span.between(first), " { 0: ".to_owned()),
+                        (last.between(whole.shrink_to_hi()), " }".to_owned()),
+                    ]);
+
+                    suggestion.extend(
+                        args.iter()
+                            .enumerate()
+                            .skip(1) // See above
+                            .map(|(index, &arg)| (arg.shrink_to_lo(), format!("{index}: "))),
+                    )
+                } else {
+                    suggestion.push((span.between(whole.shrink_to_hi()), " {}".to_owned()));
+                }
+
+                err.multipart_suggestion(
+                    "use struct pattern instead",
+                    suggestion,
+                    Applicability::MachineApplicable,
+                );
+            }
+            (
+                Res::Def(DefKind::TyAlias | DefKind::AssocTy, _),
+                PathSource::TraitItem(
+                    ValueNS,
+                    PathSource::Expr(Some(ast::Expr {
+                        span: whole,
+                        kind: ast::ExprKind::Call(_, args),
+                        ..
+                    })),
+                ),
+            ) => {
                 err.note("can't use a type alias as a constructor");
+
+                let mut suggestion = Vec::new();
+
+                if let [first, ..] = &**args
+                    && let [.., last] = &**args
+                {
+                    suggestion.extend([
+                        // "0: " has to be included here so that the fix is machine applicable.
+                        //
+                        // If this would only add " { " and then the code below add "0: ",
+                        // rustfix would crash, because end of this suggestion is the same as start
+                        // of the suggestion below. Thus, we have to merge these...
+                        (span.between(first.span), " { 0: ".to_owned()),
+                        (last.span.between(whole.shrink_to_hi()), " }".to_owned()),
+                    ]);
+
+                    suggestion.extend(
+                        args.iter()
+                            .enumerate()
+                            .skip(1) // See above
+                            .map(|(index, arg)| (arg.span.shrink_to_lo(), format!("{index}: "))),
+                    )
+                } else {
+                    suggestion.push((span.between(whole.shrink_to_hi()), " {}".to_owned()));
+                }
+
+                err.multipart_suggestion(
+                    "use struct expression instead",
+                    suggestion,
+                    Applicability::MachineApplicable,
+                );
             }
             _ => return false,
         }
@@ -2535,7 +2613,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
     fn suggest_using_enum_variant(
         &mut self,
         err: &mut Diag<'_>,
-        source: PathSource<'_>,
+        source: PathSource<'_, '_>,
         def_id: DefId,
         span: Span,
     ) {
@@ -2713,7 +2791,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
     pub(crate) fn suggest_adding_generic_parameter(
         &self,
         path: &[Segment],
-        source: PathSource<'_>,
+        source: PathSource<'_, '_>,
     ) -> Option<(Span, &'static str, String, Applicability)> {
         let (ident, span) = match path {
             [segment]
diff --git a/tests/ui/associated-types/tuple-struct-expr-pat.fixed b/tests/ui/associated-types/tuple-struct-expr-pat.fixed
new file mode 100644
index 00000000000..d6e2385f821
--- /dev/null
+++ b/tests/ui/associated-types/tuple-struct-expr-pat.fixed
@@ -0,0 +1,48 @@
+// Check that fully qualified syntax can **not** be used in tuple struct expressions (calls) and
+// patterns. Both tuple struct expressions and patterns are resolved in value namespace and thus
+// can't be resolved through associated *types*.
+//
+//@ run-rustfix
+
+#![feature(more_qualified_paths)]
+
+fn main() {
+    let <T<0> as Trait>::Assoc {} = <T<0> as Trait>::Assoc {};
+    //~^ error: expected method or associated constant, found associated type
+    //~| error: expected tuple struct or tuple variant, found associated type
+    let <T<1> as Trait>::Assoc { 0: _a } = <T<1> as Trait>::Assoc { 0: 0 };
+    //~^ error: expected method or associated constant, found associated type
+    //~| error: expected tuple struct or tuple variant, found associated type
+    let <T<2> as Trait>::Assoc { 0: _a, 1: _b } = <T<2> as Trait>::Assoc { 0: 0, 1: 1 };
+    //~^ error: expected method or associated constant, found associated type
+    //~| error: expected tuple struct or tuple variant, found associated type
+    let <T<3> as Trait>::Assoc { 0: ref _a, 1: ref mut _b, 2: mut _c } = <T<3> as Trait>::Assoc { 0: 0, 1: 1, 2: 2 };
+    //~^ error: expected method or associated constant, found associated type
+    //~| error: expected tuple struct or tuple variant, found associated type
+}
+
+
+struct T<const N: usize>;
+
+struct T0();
+struct T1(u8);
+struct T2(u8, u8);
+struct T3(u8, u8, u8);
+
+trait Trait {
+    type Assoc;
+}
+
+impl Trait for T<0> {
+    type Assoc = T0;
+}
+
+impl Trait for T<1> {
+    type Assoc = T1;
+}
+impl Trait for T<2> {
+    type Assoc = T2;
+}
+impl Trait for T<3> {
+    type Assoc = T3;
+}
diff --git a/tests/ui/associated-types/tuple-struct-expr-pat.rs b/tests/ui/associated-types/tuple-struct-expr-pat.rs
index b0676717d6f..f27a5fe1753 100644
--- a/tests/ui/associated-types/tuple-struct-expr-pat.rs
+++ b/tests/ui/associated-types/tuple-struct-expr-pat.rs
@@ -1,22 +1,24 @@
 // Check that fully qualified syntax can **not** be used in tuple struct expressions (calls) and
 // patterns. Both tuple struct expressions and patterns are resolved in value namespace and thus
 // can't be resolved through associated *types*.
+//
+//@ run-rustfix
 
 #![feature(more_qualified_paths)]
 
 fn main() {
     let <T<0> as Trait>::Assoc() = <T<0> as Trait>::Assoc();
     //~^ error: expected method or associated constant, found associated type
-    //~| error: expected method or associated constant, found associated type
+    //~| error: expected tuple struct or tuple variant, found associated type
     let <T<1> as Trait>::Assoc(_a) = <T<1> as Trait>::Assoc(0);
     //~^ error: expected method or associated constant, found associated type
-    //~| error: expected method or associated constant, found associated type
+    //~| error: expected tuple struct or tuple variant, found associated type
     let <T<2> as Trait>::Assoc(_a, _b) = <T<2> as Trait>::Assoc(0, 1);
     //~^ error: expected method or associated constant, found associated type
-    //~| error: expected method or associated constant, found associated type
+    //~| error: expected tuple struct or tuple variant, found associated type
     let <T<3> as Trait>::Assoc(ref _a, ref mut _b, mut _c) = <T<3> as Trait>::Assoc(0, 1, 2);
     //~^ error: expected method or associated constant, found associated type
-    //~| error: expected method or associated constant, found associated type
+    //~| error: expected tuple struct or tuple variant, found associated type
 }
 
 
diff --git a/tests/ui/associated-types/tuple-struct-expr-pat.stderr b/tests/ui/associated-types/tuple-struct-expr-pat.stderr
index d77fae0730b..135dfcb3447 100644
--- a/tests/ui/associated-types/tuple-struct-expr-pat.stderr
+++ b/tests/ui/associated-types/tuple-struct-expr-pat.stderr
@@ -1,66 +1,96 @@
 error[E0575]: expected method or associated constant, found associated type `Trait::Assoc`
-  --> $DIR/tuple-struct-expr-pat.rs:8:36
+  --> $DIR/tuple-struct-expr-pat.rs:10:36
    |
 LL |     let <T<0> as Trait>::Assoc() = <T<0> as Trait>::Assoc();
-   |                                    ^^^^^^^^^^^^^^^^^^^^^^
+   |                                    ^^^^^^^^^^^^^^^^^^^^^^-- help: use struct expression instead: `{}`
    |
    = note: can't use a type alias as a constructor
 
-error[E0575]: expected method or associated constant, found associated type `Trait::Assoc`
-  --> $DIR/tuple-struct-expr-pat.rs:8:9
+error[E0575]: expected tuple struct or tuple variant, found associated type `Trait::Assoc`
+  --> $DIR/tuple-struct-expr-pat.rs:10:9
    |
 LL |     let <T<0> as Trait>::Assoc() = <T<0> as Trait>::Assoc();
-   |         ^^^^^^^^^^^^^^^^^^^^^^
+   |         ^^^^^^^^^^^^^^^^^^^^^^-- help: use struct pattern instead: `{}`
    |
-   = note: can't use a type alias as a constructor
+   = note: can't use a type alias as tuple pattern
 
 error[E0575]: expected method or associated constant, found associated type `Trait::Assoc`
-  --> $DIR/tuple-struct-expr-pat.rs:11:38
+  --> $DIR/tuple-struct-expr-pat.rs:13:38
    |
 LL |     let <T<1> as Trait>::Assoc(_a) = <T<1> as Trait>::Assoc(0);
    |                                      ^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: can't use a type alias as a constructor
+help: use struct expression instead
+   |
+LL -     let <T<1> as Trait>::Assoc(_a) = <T<1> as Trait>::Assoc(0);
+LL +     let <T<1> as Trait>::Assoc(_a) = <T<1> as Trait>::Assoc { 0: 0 };
+   |
 
-error[E0575]: expected method or associated constant, found associated type `Trait::Assoc`
-  --> $DIR/tuple-struct-expr-pat.rs:11:9
+error[E0575]: expected tuple struct or tuple variant, found associated type `Trait::Assoc`
+  --> $DIR/tuple-struct-expr-pat.rs:13:9
    |
 LL |     let <T<1> as Trait>::Assoc(_a) = <T<1> as Trait>::Assoc(0);
    |         ^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: can't use a type alias as a constructor
+   = note: can't use a type alias as tuple pattern
+help: use struct pattern instead
+   |
+LL -     let <T<1> as Trait>::Assoc(_a) = <T<1> as Trait>::Assoc(0);
+LL +     let <T<1> as Trait>::Assoc { 0: _a } = <T<1> as Trait>::Assoc(0);
+   |
 
 error[E0575]: expected method or associated constant, found associated type `Trait::Assoc`
-  --> $DIR/tuple-struct-expr-pat.rs:14:42
+  --> $DIR/tuple-struct-expr-pat.rs:16:42
    |
 LL |     let <T<2> as Trait>::Assoc(_a, _b) = <T<2> as Trait>::Assoc(0, 1);
    |                                          ^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: can't use a type alias as a constructor
+help: use struct expression instead
+   |
+LL -     let <T<2> as Trait>::Assoc(_a, _b) = <T<2> as Trait>::Assoc(0, 1);
+LL +     let <T<2> as Trait>::Assoc(_a, _b) = <T<2> as Trait>::Assoc { 0: 0, 1: 1 };
+   |
 
-error[E0575]: expected method or associated constant, found associated type `Trait::Assoc`
-  --> $DIR/tuple-struct-expr-pat.rs:14:9
+error[E0575]: expected tuple struct or tuple variant, found associated type `Trait::Assoc`
+  --> $DIR/tuple-struct-expr-pat.rs:16:9
    |
 LL |     let <T<2> as Trait>::Assoc(_a, _b) = <T<2> as Trait>::Assoc(0, 1);
    |         ^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: can't use a type alias as a constructor
+   = note: can't use a type alias as tuple pattern
+help: use struct pattern instead
+   |
+LL -     let <T<2> as Trait>::Assoc(_a, _b) = <T<2> as Trait>::Assoc(0, 1);
+LL +     let <T<2> as Trait>::Assoc { 0: _a, 1: _b } = <T<2> as Trait>::Assoc(0, 1);
+   |
 
 error[E0575]: expected method or associated constant, found associated type `Trait::Assoc`
-  --> $DIR/tuple-struct-expr-pat.rs:17:62
+  --> $DIR/tuple-struct-expr-pat.rs:19:62
    |
 LL |     let <T<3> as Trait>::Assoc(ref _a, ref mut _b, mut _c) = <T<3> as Trait>::Assoc(0, 1, 2);
    |                                                              ^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: can't use a type alias as a constructor
+help: use struct expression instead
+   |
+LL -     let <T<3> as Trait>::Assoc(ref _a, ref mut _b, mut _c) = <T<3> as Trait>::Assoc(0, 1, 2);
+LL +     let <T<3> as Trait>::Assoc(ref _a, ref mut _b, mut _c) = <T<3> as Trait>::Assoc { 0: 0, 1: 1, 2: 2 };
+   |
 
-error[E0575]: expected method or associated constant, found associated type `Trait::Assoc`
-  --> $DIR/tuple-struct-expr-pat.rs:17:9
+error[E0575]: expected tuple struct or tuple variant, found associated type `Trait::Assoc`
+  --> $DIR/tuple-struct-expr-pat.rs:19:9
    |
 LL |     let <T<3> as Trait>::Assoc(ref _a, ref mut _b, mut _c) = <T<3> as Trait>::Assoc(0, 1, 2);
    |         ^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: can't use a type alias as a constructor
+   = note: can't use a type alias as tuple pattern
+help: use struct pattern instead
+   |
+LL -     let <T<3> as Trait>::Assoc(ref _a, ref mut _b, mut _c) = <T<3> as Trait>::Assoc(0, 1, 2);
+LL +     let <T<3> as Trait>::Assoc { 0: ref _a, 1: ref mut _b, 2: mut _c } = <T<3> as Trait>::Assoc(0, 1, 2);
+   |
 
 error: aborting due to 8 previous errors