Skip to content

Commit a54eae9

Browse files
authored
Rollup merge of rust-lang#91098 - compiler-errors:issue-91058, r=estebank
Don't suggest certain fixups (`.field`, `.await`, etc) when reporting errors while matching on arrays When we have a type mismatch with a `cause.code` that is an `ObligationCauseCode::Pattern`, skip suggesting fixes like adding `.await` or accessing a struct's `.field` if the pattern's `root_ty` differs from the `expected` ty. This occurs in situations like this: ```rust struct S(()); fn main() { let array = [S(())]; match array { [()] => {} _ => {} } } ``` I think what's happening here is a layer of `[_; N]` is peeled off of both types and we end up seeing the mismatch between just `S` and `()`, but when we suggest a fixup, that applies to the expression with type `root_ty`. --- Questions: 1. Should this check live here, above all of the suggestions, or should I push this down into every suggestion when we match `ObligationCauseCode`? 2. Any other `ObligationCauseCode`s to check here? 3. Am I overlooking an easier way to get to this same conclusion without pattern matching on `ObligationCauseCode` and comparing `root_ty`? Fixes rust-lang#91058
2 parents 3eb30b8 + 01b2404 commit a54eae9

File tree

4 files changed

+44
-6
lines changed

4 files changed

+44
-6
lines changed

compiler/rustc_infer/src/infer/error_reporting/mod.rs

+18-6
Original file line numberDiff line numberDiff line change
@@ -1695,11 +1695,23 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
16951695
}
16961696
_ => exp_found,
16971697
};
1698-
debug!("exp_found {:?} terr {:?}", exp_found, terr);
1698+
debug!("exp_found {:?} terr {:?} cause.code {:?}", exp_found, terr, cause.code);
16991699
if let Some(exp_found) = exp_found {
1700-
self.suggest_as_ref_where_appropriate(span, &exp_found, diag);
1701-
self.suggest_accessing_field_where_appropriate(cause, &exp_found, diag);
1702-
self.suggest_await_on_expect_found(cause, span, &exp_found, diag);
1700+
let should_suggest_fixes = if let ObligationCauseCode::Pattern { root_ty, .. } =
1701+
&cause.code
1702+
{
1703+
// Skip if the root_ty of the pattern is not the same as the expected_ty.
1704+
// If these types aren't equal then we've probably peeled off a layer of arrays.
1705+
same_type_modulo_infer(self.resolve_vars_if_possible(*root_ty), exp_found.expected)
1706+
} else {
1707+
true
1708+
};
1709+
1710+
if should_suggest_fixes {
1711+
self.suggest_as_ref_where_appropriate(span, &exp_found, diag);
1712+
self.suggest_accessing_field_where_appropriate(cause, &exp_found, diag);
1713+
self.suggest_await_on_expect_found(cause, span, &exp_found, diag);
1714+
}
17031715
}
17041716

17051717
// In some (most?) cases cause.body_id points to actual body, but in some cases
@@ -1879,7 +1891,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
18791891
.iter()
18801892
.filter(|field| field.vis.is_accessible_from(field.did, self.tcx))
18811893
.map(|field| (field.ident.name, field.ty(self.tcx, expected_substs)))
1882-
.find(|(_, ty)| ty::TyS::same_type(ty, exp_found.found))
1894+
.find(|(_, ty)| same_type_modulo_infer(ty, exp_found.found))
18831895
{
18841896
if let ObligationCauseCode::Pattern { span: Some(span), .. } = cause.code {
18851897
if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) {
@@ -1944,7 +1956,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
19441956
| (_, ty::Infer(_))
19451957
| (ty::Param(_), _)
19461958
| (ty::Infer(_), _) => {}
1947-
_ if ty::TyS::same_type(exp_ty, found_ty) => {}
1959+
_ if same_type_modulo_infer(exp_ty, found_ty) => {}
19481960
_ => show_suggestion = false,
19491961
};
19501962
}

src/test/ui/issues/issue-5358-1.stderr

+4
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,10 @@ LL | Either::Right(_) => {}
88
|
99
= note: expected struct `S`
1010
found enum `Either<_, _>`
11+
help: you might have meant to use field `0` whose type is `Either<usize, usize>`
12+
|
13+
LL | match S(Either::Left(5)).0 {
14+
| ~~~~~~~~~~~~~~~~~~~~
1115

1216
error: aborting due to previous error
1317

src/test/ui/match/issue-91058.rs

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
struct S(());
2+
3+
fn main() {
4+
let array = [S(())];
5+
6+
match array {
7+
[()] => {}
8+
//~^ ERROR mismatched types [E0308]
9+
_ => {}
10+
}
11+
}

src/test/ui/match/issue-91058.stderr

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
error[E0308]: mismatched types
2+
--> $DIR/issue-91058.rs:7:10
3+
|
4+
LL | match array {
5+
| ----- this expression has type `[S; 1]`
6+
LL | [()] => {}
7+
| ^^ expected struct `S`, found `()`
8+
9+
error: aborting due to previous error
10+
11+
For more information about this error, try `rustc --explain E0308`.

0 commit comments

Comments
 (0)