about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorMazdak Farrokhzad <twingoow@gmail.com>2019-12-13 15:52:51 +0100
committerMazdak Farrokhzad <twingoow@gmail.com>2019-12-13 15:52:51 +0100
commitf97c37f8ae9a3bb9eed2d2fa812c01ac78b460fb (patch)
tree4117acb43a727ac307b9b2b59df2257deeacc01e /src
parent3964a55ba59bb6c3d4badcbddc49f6929ef76862 (diff)
downloadrust-f97c37f8ae9a3bb9eed2d2fa812c01ac78b460fb.tar.gz
rust-f97c37f8ae9a3bb9eed2d2fa812c01ac78b460fb.zip
coerce_inner: use initial expected_ty
Diffstat (limited to 'src')
-rw-r--r--src/librustc_typeck/check/coercion.rs16
-rw-r--r--src/test/ui/type/type-check/issue-67273-assignment-match-prior-arm-bool-expected-unit.rs27
-rw-r--r--src/test/ui/type/type-check/issue-67273-assignment-match-prior-arm-bool-expected-unit.stderr22
3 files changed, 63 insertions, 2 deletions
diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs
index 253fc5575c5..726b3ba9857 100644
--- a/src/librustc_typeck/check/coercion.rs
+++ b/src/librustc_typeck/check/coercion.rs
@@ -1289,8 +1289,20 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
                 }
 
                 // 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 00000000000..e23c0d0a40a
--- /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 00000000000..3547285542a
--- /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`.