about summary refs log tree commit diff
diff options
context:
space:
mode:
authorJacob Pratt <jacob@jhpratt.dev>2025-01-06 22:04:15 -0500
committerGitHub <noreply@github.com>2025-01-06 22:04:15 -0500
commit8b54f951e56a4c0edfd724d3ca7700696f7abe78 (patch)
tree7706d712179afc587a00efe8ec6018ea9654d061
parent3deb5c289e6881014b1a22ba6c26bc0078b4b590 (diff)
parent304ccf45d15153b29c413a84334a9b4aaee23d53 (diff)
downloadrust-8b54f951e56a4c0edfd724d3ca7700696f7abe78.tar.gz
rust-8b54f951e56a4c0edfd724d3ca7700696f7abe78.zip
Rollup merge of #135090 - compiler-errors:invalid-tuple-ctor-projection, r=lqd,jieyouxu
Suggest to replace tuple constructor through projection

See the code example. when `Self::Assoc` normalizes to a struct that has a tuple constructor, you cannot construct the type via `Self::Assoc(field, field)`. Instead, suggest to replace it with the correct named struct.

Fixes #120871
-rw-r--r--compiler/rustc_hir_typeck/src/method/suggest.rs26
-rw-r--r--tests/ui/associated-types/invalid-ctor.fixed22
-rw-r--r--tests/ui/associated-types/invalid-ctor.rs22
-rw-r--r--tests/ui/associated-types/invalid-ctor.stderr14
4 files changed, 83 insertions, 1 deletions
diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs
index 0b008fd10b5..b4f1dcfb9cc 100644
--- a/compiler/rustc_hir_typeck/src/method/suggest.rs
+++ b/compiler/rustc_hir_typeck/src/method/suggest.rs
@@ -14,7 +14,7 @@ use rustc_data_structures::sorted_map::SortedMap;
 use rustc_data_structures::unord::UnordSet;
 use rustc_errors::codes::*;
 use rustc_errors::{Applicability, Diag, MultiSpan, StashKey, pluralize, struct_span_code_err};
-use rustc_hir::def::DefKind;
+use rustc_hir::def::{CtorKind, DefKind, Res};
 use rustc_hir::def_id::DefId;
 use rustc_hir::intravisit::{self, Visitor};
 use rustc_hir::lang_items::LangItem;
@@ -690,6 +690,30 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 );
             }
 
+            // Check if we wrote `Self::Assoc(1)` as if it were a tuple ctor.
+            if let SelfSource::QPath(ty) = source
+                && let hir::TyKind::Path(hir::QPath::Resolved(_, path)) = ty.kind
+                && let Res::SelfTyAlias { alias_to: impl_def_id, .. } = path.res
+                && let DefKind::Impl { .. } = self.tcx.def_kind(impl_def_id)
+                && let Some(candidate) = tcx.associated_items(impl_def_id).find_by_name_and_kind(
+                    self.tcx,
+                    item_name,
+                    ty::AssocKind::Type,
+                    impl_def_id,
+                )
+                && let Some(adt_def) = tcx.type_of(candidate.def_id).skip_binder().ty_adt_def()
+                && adt_def.is_struct()
+                && adt_def.non_enum_variant().ctor_kind() == Some(CtorKind::Fn)
+            {
+                let def_path = tcx.def_path_str(adt_def.did());
+                err.span_suggestion(
+                    ty.span.to(item_name.span),
+                    format!("to construct a value of type `{}`, use the explicit path", def_path),
+                    def_path,
+                    Applicability::MachineApplicable,
+                );
+            }
+
             err
         };
         if tcx.sess.source_map().is_multiline(sugg_span) {
diff --git a/tests/ui/associated-types/invalid-ctor.fixed b/tests/ui/associated-types/invalid-ctor.fixed
new file mode 100644
index 00000000000..eba3820de0c
--- /dev/null
+++ b/tests/ui/associated-types/invalid-ctor.fixed
@@ -0,0 +1,22 @@
+//@ run-rustfix
+
+#![allow(unused)]
+
+struct Constructor(i32);
+
+trait Trait {
+    type Out;
+
+    fn mk() -> Self::Out;
+}
+
+impl Trait for () {
+    type Out = Constructor;
+
+    fn mk() -> Self::Out {
+        Constructor(1)
+        //~^ ERROR no associated item named `Out` found for unit type `()`
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/associated-types/invalid-ctor.rs b/tests/ui/associated-types/invalid-ctor.rs
new file mode 100644
index 00000000000..73335c065c2
--- /dev/null
+++ b/tests/ui/associated-types/invalid-ctor.rs
@@ -0,0 +1,22 @@
+//@ run-rustfix
+
+#![allow(unused)]
+
+struct Constructor(i32);
+
+trait Trait {
+    type Out;
+
+    fn mk() -> Self::Out;
+}
+
+impl Trait for () {
+    type Out = Constructor;
+
+    fn mk() -> Self::Out {
+        Self::Out(1)
+        //~^ ERROR no associated item named `Out` found for unit type `()`
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/associated-types/invalid-ctor.stderr b/tests/ui/associated-types/invalid-ctor.stderr
new file mode 100644
index 00000000000..b545c95a768
--- /dev/null
+++ b/tests/ui/associated-types/invalid-ctor.stderr
@@ -0,0 +1,14 @@
+error[E0599]: no associated item named `Out` found for unit type `()` in the current scope
+  --> $DIR/invalid-ctor.rs:17:15
+   |
+LL |         Self::Out(1)
+   |               ^^^ associated item not found in `()`
+   |
+help: to construct a value of type `Constructor`, use the explicit path
+   |
+LL |         Constructor(1)
+   |         ~~~~~~~~~~~
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0599`.