about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2020-10-30 07:05:57 +0000
committerbors <bors@rust-lang.org>2020-10-30 07:05:57 +0000
commit8df58ae03a8fda8ed126c02fbc16b530d18344df (patch)
treec0c78ef0211c49ea75eb27eccdd9441a017d81d9
parent0d33ab7af4aebe786410b4c10367eb6ddf13af0b (diff)
parent8bf9abbb7b7321ed4014b7f0d9978e425c966c95 (diff)
downloadrust-8df58ae03a8fda8ed126c02fbc16b530d18344df.tar.gz
rust-8df58ae03a8fda8ed126c02fbc16b530d18344df.zip
Auto merge of #78393 - SNCPlay42:match-if-guard, r=tmandry
Always record reference to binding in match if guards

When encountering a binding from a `match` pattern in its `if` guard when computing a generator's interior types, we must always record the type of a reference to the binding because of how `if` guards are lowered to MIR. This was missed in #75213 because the binding in that test case was autorefed and we recorded that adjusted type anyway.

Fixes #78366
-rw-r--r--compiler/rustc_typeck/src/check/generator_interior.rs12
-rw-r--r--src/test/ui/generator/yielding-in-match-guards.rs21
2 files changed, 32 insertions, 1 deletions
diff --git a/compiler/rustc_typeck/src/check/generator_interior.rs b/compiler/rustc_typeck/src/check/generator_interior.rs
index 4473aa2081f..f1828ddf3eb 100644
--- a/compiler/rustc_typeck/src/check/generator_interior.rs
+++ b/compiler/rustc_typeck/src/check/generator_interior.rs
@@ -344,6 +344,18 @@ impl<'a, 'tcx> Visitor<'tcx> for InteriorVisitor<'a, 'tcx> {
         // The type table might not have information for this expression
         // if it is in a malformed scope. (#66387)
         if let Some(ty) = self.fcx.typeck_results.borrow().expr_ty_opt(expr) {
+            if guard_borrowing_from_pattern {
+                // Match guards create references to all the bindings in the pattern that are used
+                // in the guard, e.g. `y if is_even(y) => ...` becomes `is_even(*r_y)` where `r_y`
+                // is a reference to `y`, so we must record a reference to the type of the binding.
+                let tcx = self.fcx.tcx;
+                let ref_ty = tcx.mk_ref(
+                    // Use `ReErased` as `resolve_interior` is going to replace all the regions anyway.
+                    tcx.mk_region(ty::RegionKind::ReErased),
+                    ty::TypeAndMut { ty, mutbl: hir::Mutability::Not },
+                );
+                self.record(ref_ty, scope, Some(expr), expr.span, guard_borrowing_from_pattern);
+            }
             self.record(ty, scope, Some(expr), expr.span, guard_borrowing_from_pattern);
         } else {
             self.fcx.tcx.sess.delay_span_bug(expr.span, "no type for node");
diff --git a/src/test/ui/generator/yielding-in-match-guards.rs b/src/test/ui/generator/yielding-in-match-guards.rs
index d8aa354b1c6..c76726414df 100644
--- a/src/test/ui/generator/yielding-in-match-guards.rs
+++ b/src/test/ui/generator/yielding-in-match-guards.rs
@@ -1,4 +1,4 @@
-// check-pass
+// build-pass
 // edition:2018
 
 // This test is derived from
@@ -11,6 +11,7 @@
 // of the underlying generator.
 
 async fn f() -> u8 { 1 }
+async fn foo() -> [bool; 10] { [false; 10] }
 
 pub async fn g(x: u8) {
     match x {
@@ -19,6 +20,24 @@ pub async fn g(x: u8) {
     }
 }
 
+// #78366: check the reference to the binding is recorded even if the binding is not autorefed
+
+async fn h(x: usize) {
+    match x {
+        y if foo().await[y] => (),
+        _ => (),
+    }
+}
+
+async fn i(x: u8) {
+    match x {
+        y if f().await == y + 1 => (),
+        _ => (),
+    }
+}
+
 fn main() {
     let _ = g(10);
+    let _ = h(9);
+    let _ = i(8);
 }