Skip to content

Commit

Permalink
Rollup merge of #91098 - compiler-errors:issue-91058, r=estebank
Browse files Browse the repository at this point in the history
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 #91058
  • Loading branch information
matthiaskrgr authored Nov 21, 2021
2 parents 3eb30b8 + 01b2404 commit a54eae9
Show file tree
Hide file tree
Showing 4 changed files with 44 additions and 6 deletions.
24 changes: 18 additions & 6 deletions compiler/rustc_infer/src/infer/error_reporting/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1695,11 +1695,23 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
}
_ => exp_found,
};
debug!("exp_found {:?} terr {:?}", exp_found, terr);
debug!("exp_found {:?} terr {:?} cause.code {:?}", exp_found, terr, cause.code);
if let Some(exp_found) = exp_found {
self.suggest_as_ref_where_appropriate(span, &exp_found, diag);
self.suggest_accessing_field_where_appropriate(cause, &exp_found, diag);
self.suggest_await_on_expect_found(cause, span, &exp_found, diag);
let should_suggest_fixes = if let ObligationCauseCode::Pattern { root_ty, .. } =
&cause.code
{
// Skip if the root_ty of the pattern is not the same as the expected_ty.
// If these types aren't equal then we've probably peeled off a layer of arrays.
same_type_modulo_infer(self.resolve_vars_if_possible(*root_ty), exp_found.expected)
} else {
true
};

if should_suggest_fixes {
self.suggest_as_ref_where_appropriate(span, &exp_found, diag);
self.suggest_accessing_field_where_appropriate(cause, &exp_found, diag);
self.suggest_await_on_expect_found(cause, span, &exp_found, diag);
}
}

// In some (most?) cases cause.body_id points to actual body, but in some cases
Expand Down Expand Up @@ -1879,7 +1891,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
.iter()
.filter(|field| field.vis.is_accessible_from(field.did, self.tcx))
.map(|field| (field.ident.name, field.ty(self.tcx, expected_substs)))
.find(|(_, ty)| ty::TyS::same_type(ty, exp_found.found))
.find(|(_, ty)| same_type_modulo_infer(ty, exp_found.found))
{
if let ObligationCauseCode::Pattern { span: Some(span), .. } = cause.code {
if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) {
Expand Down Expand Up @@ -1944,7 +1956,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
| (_, ty::Infer(_))
| (ty::Param(_), _)
| (ty::Infer(_), _) => {}
_ if ty::TyS::same_type(exp_ty, found_ty) => {}
_ if same_type_modulo_infer(exp_ty, found_ty) => {}
_ => show_suggestion = false,
};
}
Expand Down
4 changes: 4 additions & 0 deletions src/test/ui/issues/issue-5358-1.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ LL | Either::Right(_) => {}
|
= note: expected struct `S`
found enum `Either<_, _>`
help: you might have meant to use field `0` whose type is `Either<usize, usize>`
|
LL | match S(Either::Left(5)).0 {
| ~~~~~~~~~~~~~~~~~~~~

error: aborting due to previous error

Expand Down
11 changes: 11 additions & 0 deletions src/test/ui/match/issue-91058.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
struct S(());

fn main() {
let array = [S(())];

match array {
[()] => {}
//~^ ERROR mismatched types [E0308]
_ => {}
}
}
11 changes: 11 additions & 0 deletions src/test/ui/match/issue-91058.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
error[E0308]: mismatched types
--> $DIR/issue-91058.rs:7:10
|
LL | match array {
| ----- this expression has type `[S; 1]`
LL | [()] => {}
| ^^ expected struct `S`, found `()`

error: aborting due to previous error

For more information about this error, try `rustc --explain E0308`.

0 comments on commit a54eae9

Please sign in to comment.