about summary refs log tree commit diff
diff options
context:
space:
mode:
authorGuillaume Gomez <guillaume1.gomez@gmail.com>2025-08-14 11:39:40 +0200
committerGitHub <noreply@github.com>2025-08-14 11:39:40 +0200
commit707e956946186fc6ebd90b7c29da581d802110ce (patch)
tree456f1784225e75503559a80f1c8a04f4e760be1d
parent44d3217c20ab0bdbbc9bd2edfc6810e6e605369e (diff)
parente0cc2beea3d52ce34b16df9730b65a670c68c623 (diff)
downloadrust-707e956946186fc6ebd90b7c29da581d802110ce.tar.gz
rust-707e956946186fc6ebd90b7c29da581d802110ce.zip
Rollup merge of #145361 - xizheyin:145294, r=compiler-errors
Suppress wrapper suggestion when expected and actual ty are the same adt and the variant is unresolved

Fixes rust-lang/rust#145294

I initially tried the desired suggestion in this issue, but since that suggestion occurs in the expected type, it is inappropriate to suggest for expected expressions (see other suggest methods in the same file). I believe that suppressing the incorrect suggestion is the more appropriate choice here.

I opted for a slightly more general approach: when the expected type and actual type are the same ADT (e.g., both are Result in this example), we assume that code tend to compare the internal generic parameters(i.e. `Option<&str>` vs `Option<String>`, instead of `E = _` vs `Result<Option<String>>>`). When `E` is an unresolved infer type in the expected type (`_` in this example), we should not wrapp the actual type.

Two commits show the difference.

r? compiler
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs9
-rw-r--r--tests/ui/typeck/suggestions/suggest-add-wrapper-issue-145294.rs26
-rw-r--r--tests/ui/typeck/suggestions/suggest-add-wrapper-issue-145294.stderr21
3 files changed, 56 insertions, 0 deletions
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
index 6013430e1ff..aca3840712e 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
@@ -2378,6 +2378,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 .filter_map(|variant| {
                     let sole_field = &variant.single_field();
 
+                    // When expected_ty and expr_ty are the same ADT, we prefer to compare their internal generic params,
+                    // When the current variant has a sole field whose type is still an unresolved inference variable,
+                    // suggestions would be often wrong. So suppress the suggestion. See #145294.
+                    if let (ty::Adt(exp_adt, _), ty::Adt(act_adt, _)) = (expected.kind(), expr_ty.kind())
+                        && exp_adt.did() == act_adt.did()
+                        && sole_field.ty(self.tcx, args).is_ty_var() {
+                            return None;
+                    }
+
                     let field_is_local = sole_field.did.is_local();
                     let field_is_accessible =
                         sole_field.vis.is_accessible_from(expr.hir_id.owner.def_id, self.tcx)
diff --git a/tests/ui/typeck/suggestions/suggest-add-wrapper-issue-145294.rs b/tests/ui/typeck/suggestions/suggest-add-wrapper-issue-145294.rs
new file mode 100644
index 00000000000..cfe167cf88d
--- /dev/null
+++ b/tests/ui/typeck/suggestions/suggest-add-wrapper-issue-145294.rs
@@ -0,0 +1,26 @@
+// Suppress the suggestion that adding a wrapper.
+// When expected_ty and expr_ty are the same ADT,
+// we prefer to compare their internal generic params,
+// so when the current variant corresponds to an unresolved infer,
+// the suggestion is rejected.
+// e.g. `Ok(Some("hi"))` is type of `Result<Option<&str>, _>`,
+// where `E` is still an unresolved inference variable.
+
+fn foo() -> Result<Option<String>, ()> {
+    todo!()
+}
+
+#[derive(PartialEq, Debug)]
+enum Bar<T, E> {
+    A(T),
+    B(E),
+}
+
+fn bar() -> Bar<String, ()> {
+    todo!()
+}
+
+fn main() {
+    assert_eq!(Ok(Some("hi")), foo()); //~ ERROR mismatched types [E0308]
+    assert_eq!(Bar::A("hi"), bar()); //~ ERROR mismatched types [E0308]
+}
diff --git a/tests/ui/typeck/suggestions/suggest-add-wrapper-issue-145294.stderr b/tests/ui/typeck/suggestions/suggest-add-wrapper-issue-145294.stderr
new file mode 100644
index 00000000000..5e4ad132210
--- /dev/null
+++ b/tests/ui/typeck/suggestions/suggest-add-wrapper-issue-145294.stderr
@@ -0,0 +1,21 @@
+error[E0308]: mismatched types
+  --> $DIR/suggest-add-wrapper-issue-145294.rs:24:32
+   |
+LL |     assert_eq!(Ok(Some("hi")), foo());
+   |                                ^^^^^ expected `Result<Option<&str>, _>`, found `Result<Option<String>, ()>`
+   |
+   = note: expected enum `Result<Option<&str>, _>`
+              found enum `Result<Option<String>, ()>`
+
+error[E0308]: mismatched types
+  --> $DIR/suggest-add-wrapper-issue-145294.rs:25:30
+   |
+LL |     assert_eq!(Bar::A("hi"), bar());
+   |                              ^^^^^ expected `Bar<&str, _>`, found `Bar<String, ()>`
+   |
+   = note: expected enum `Bar<&str, _>`
+              found enum `Bar<String, ()>`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0308`.