Rollup merge of #67278 - Centril:67273, r=oli-obk
`coerce_inner`: use initial `expected_ty`
Fixes #67273.
Follow-up to #59439.
r? @oli-obk
diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs
index 253fc55..726b3ba 100644
--- a/src/librustc_typeck/check/coercion.rs
+++ b/src/librustc_typeck/check/coercion.rs
@@ -1289,8 +1289,20 @@
}
// Error possibly reported in `check_assign` so avoid emitting error again.
- err.emit_unless(expression.filter(|e| fcx.is_assign_to_bool(e, expected))
- .is_some());
+ let assign_to_bool = expression
+ // #67273: Use initial expected type as opposed to `expected`.
+ // Otherwise we end up using prior coercions in e.g. a `match` expression:
+ // ```
+ // match i {
+ // 0 => true, // Because of this...
+ // 1 => i = 1, // ...`expected == bool` now, but not when checking `i = 1`.
+ // _ => (),
+ // };
+ // ```
+ .filter(|e| fcx.is_assign_to_bool(e, self.expected_ty()))
+ .is_some();
+
+ err.emit_unless(assign_to_bool);
self.final_ty = Some(fcx.tcx.types.err);
}
diff --git a/src/test/ui/type/type-check/issue-67273-assignment-match-prior-arm-bool-expected-unit.rs b/src/test/ui/type/type-check/issue-67273-assignment-match-prior-arm-bool-expected-unit.rs
new file mode 100644
index 0000000..e23c0d0
--- /dev/null
+++ b/src/test/ui/type/type-check/issue-67273-assignment-match-prior-arm-bool-expected-unit.rs
@@ -0,0 +1,27 @@
+fn main() {
+ let mut i: i64;
+ // Expected type is an inference variable `?T`
+ // because the `match` is used as a statement.
+ // This is the "initial" type of the `coercion`.
+ match i {
+ // Add `bool` to the overall `coercion`.
+ 0 => true,
+
+ // Necessary to cause the ICE:
+ 1 => true,
+
+ // Suppose that we had `let _: bool = match i { ... }`.
+ // In that case, as the expected type would be `bool`,
+ // we would suggest `i == 1` as a fix.
+ //
+ // However, no type error happens when checking `i = 1` because `expected == ?T`,
+ // which will unify with `typeof(i = 1) == ()`.
+ //
+ // However, in #67273, we would delay the unification of this arm with the above
+ // because we used the hitherto accumulated coercion as opposed to the "initial" type.
+ 2 => i = 1,
+ //~^ ERROR match arms have incompatible types
+
+ _ => (),
+ }
+}
diff --git a/src/test/ui/type/type-check/issue-67273-assignment-match-prior-arm-bool-expected-unit.stderr b/src/test/ui/type/type-check/issue-67273-assignment-match-prior-arm-bool-expected-unit.stderr
new file mode 100644
index 0000000..3547285
--- /dev/null
+++ b/src/test/ui/type/type-check/issue-67273-assignment-match-prior-arm-bool-expected-unit.stderr
@@ -0,0 +1,22 @@
+error[E0308]: match arms have incompatible types
+ --> $DIR/issue-67273-assignment-match-prior-arm-bool-expected-unit.rs:22:14
+ |
+LL | / match i {
+LL | | // Add `bool` to the overall `coercion`.
+LL | | 0 => true,
+ | | ---- this is found to be of type `bool`
+LL | |
+LL | | // Necessary to cause the ICE:
+LL | | 1 => true,
+ | | ---- this is found to be of type `bool`
+... |
+LL | | 2 => i = 1,
+ | | ^^^^^ expected `bool`, found `()`
+... |
+LL | | _ => (),
+LL | | }
+ | |_____- `match` arms have incompatible types
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.