about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorNiko Matsakis <niko@alum.mit.edu>2017-11-08 04:46:44 -0500
committerNiko Matsakis <niko@alum.mit.edu>2017-11-08 05:29:03 -0500
commit629efae761d0a473ddeeb9a4f2e5c408d9ce99dc (patch)
treeac22b6828b0e32b27370010c942cf76501a432ed /src
parentdc6af49258f0b90489a9a8216d35306b27aaeed9 (diff)
downloadrust-629efae761d0a473ddeeb9a4f2e5c408d9ce99dc.tar.gz
rust-629efae761d0a473ddeeb9a4f2e5c408d9ce99dc.zip
look for the note on the guarantor, not the root cmt
This was causing upvar inference to fail for all cases where the move
was from a projection, not the root variable.
Diffstat (limited to 'src')
-rw-r--r--src/librustc_typeck/check/upvar.rs6
-rw-r--r--src/test/run-pass/unboxed-closures-move-from-projection-issue-30046.rs35
-rw-r--r--src/test/ui/unboxed-closures-infer-fn-once-move-from-projection.rs26
-rw-r--r--src/test/ui/unboxed-closures-infer-fn-once-move-from-projection.stderr16
4 files changed, 82 insertions, 1 deletions
diff --git a/src/librustc_typeck/check/upvar.rs b/src/librustc_typeck/check/upvar.rs
index d179b390a29..a6a81485b23 100644
--- a/src/librustc_typeck/check/upvar.rs
+++ b/src/librustc_typeck/check/upvar.rs
@@ -289,10 +289,14 @@ impl<'a, 'gcx, 'tcx> InferBorrowKind<'a, 'gcx, 'tcx> {
         let guarantor = cmt.guarantor();
         debug!("adjust_upvar_borrow_kind_for_consume: guarantor={:?}",
                guarantor);
+        debug!("adjust_upvar_borrow_kind_for_consume: guarantor.cat={:?}",
+               guarantor.cat);
         match guarantor.cat {
             Categorization::Deref(_, mc::BorrowedPtr(..)) |
             Categorization::Deref(_, mc::Implicit(..)) => {
-                match cmt.note {
+                debug!("adjust_upvar_borrow_kind_for_consume: found deref with note {:?}",
+                       cmt.note);
+                match guarantor.note {
                     mc::NoteUpvarRef(upvar_id) => {
                         debug!("adjust_upvar_borrow_kind_for_consume: \
                                 setting upvar_id={:?} to by value",
diff --git a/src/test/run-pass/unboxed-closures-move-from-projection-issue-30046.rs b/src/test/run-pass/unboxed-closures-move-from-projection-issue-30046.rs
new file mode 100644
index 00000000000..d902ebc9dc9
--- /dev/null
+++ b/src/test/run-pass/unboxed-closures-move-from-projection-issue-30046.rs
@@ -0,0 +1,35 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![allow(unused)]
+
+fn foo<F>(f: F)
+    where F: FnOnce()
+{
+}
+
+fn main() {
+    // Test that this closure is inferred to `FnOnce`
+    // because it moves from `y.as<Option::Some>.0`:
+    let x = Some(vec![1, 2, 3]);
+    foo(|| {
+        match x {
+            Some(y) => { }
+            None => { }
+        }
+    });
+
+    // Test that this closure is inferred to `FnOnce`
+    // because it moves from `y.0`:
+    let y = (vec![1, 2, 3], 0);
+    foo(|| {
+        let x = y.0;
+    });
+}
diff --git a/src/test/ui/unboxed-closures-infer-fn-once-move-from-projection.rs b/src/test/ui/unboxed-closures-infer-fn-once-move-from-projection.rs
new file mode 100644
index 00000000000..14ef3b5f178
--- /dev/null
+++ b/src/test/ui/unboxed-closures-infer-fn-once-move-from-projection.rs
@@ -0,0 +1,26 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![allow(unused)]
+
+fn foo<F>(f: F)
+    where F: Fn()
+{
+}
+
+fn main() {
+    // Test that this closure is inferred to `FnOnce` because it moves
+    // from `y.0`. This affects the error output (the error is that
+    // the closure implements `FnOnce`, not that it moves from inside
+    // a `Fn` closure.)
+    let y = (vec![1, 2, 3], 0);
+    let c = || drop(y.0);
+    foo(c);
+}
diff --git a/src/test/ui/unboxed-closures-infer-fn-once-move-from-projection.stderr b/src/test/ui/unboxed-closures-infer-fn-once-move-from-projection.stderr
new file mode 100644
index 00000000000..d968c409396
--- /dev/null
+++ b/src/test/ui/unboxed-closures-infer-fn-once-move-from-projection.stderr
@@ -0,0 +1,16 @@
+error[E0525]: expected a closure that implements the `Fn` trait, but this closure only implements `FnOnce`
+  --> $DIR/unboxed-closures-infer-fn-once-move-from-projection.rs:24:13
+   |
+24 |     let c = || drop(y.0);
+   |             ^^^^^^^^^^^^
+25 |     foo(c);
+   |     --- the requirement to implement `Fn` derives from here
+   |
+note: closure is `FnOnce` because it moves the variable `y` out of its environment
+  --> $DIR/unboxed-closures-infer-fn-once-move-from-projection.rs:24:21
+   |
+24 |     let c = || drop(y.0);
+   |                     ^
+
+error: aborting due to previous error
+