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
This commit is contained in:
Guillaume Gomez 2025-08-14 11:39:40 +02:00 committed by GitHub
commit 707e956946
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 56 additions and 0 deletions

View file

@ -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)

View file

@ -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]
}

View file

@ -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`.