From dc6af49258f0b90489a9a8216d35306b27aaeed9 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 8 Nov 2017 04:43:13 -0500 Subject: [PATCH 1/2] use the derived Debug rather than our custom written ones That encoding that the custom Debugs was using is rather inscrutable, and incomplete. --- src/librustc/middle/mem_categorization.rs | 65 ++--------------------- 1 file changed, 5 insertions(+), 60 deletions(-) diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index e0e30f88316..3e3404f3a70 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -88,7 +88,7 @@ use std::fmt; use std::rc::Rc; use util::nodemap::ItemLocalMap; -#[derive(Clone, PartialEq)] +#[derive(Clone, Debug, PartialEq)] pub enum Categorization<'tcx> { Rvalue(ty::Region<'tcx>), // temporary val, argument is its scope StaticItem, @@ -109,7 +109,7 @@ pub struct Upvar { } // different kinds of pointers: -#[derive(Clone, Copy, PartialEq, Eq, Hash)] +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] pub enum PointerKind<'tcx> { /// `Box` Unique, @@ -177,7 +177,7 @@ pub enum Note { // dereference, but its type is the type *before* the dereference // (`@T`). So use `cmt.ty` to find the type of the value in a consistent // fashion. For more details, see the method `cat_pattern` -#[derive(Clone, PartialEq)] +#[derive(Clone, Debug, PartialEq)] pub struct cmt_<'tcx> { pub id: ast::NodeId, // id of expr/pat producing this value pub span: Span, // span of same expr/pat @@ -750,12 +750,13 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { let kind = match self.node_ty(fn_hir_id)?.sty { ty::TyGenerator(..) => ty::ClosureKind::FnOnce, - _ => { + ty::TyClosure(..) => { match self.tables.closure_kinds().get(fn_hir_id) { Some(&(kind, _)) => kind, None => span_bug!(span, "missing closure kind"), } } + ref t => span_bug!(span, "unexpected type for fn in mem_categorization: {:?}", t), }; let closure_expr_def_index = self.tcx.hir.local_def_id(fn_node_id).index; @@ -1499,41 +1500,6 @@ impl<'tcx> cmt_<'tcx> { } } -impl<'tcx> fmt::Debug for cmt_<'tcx> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{{{:?} id:{} m:{:?} ty:{:?}}}", - self.cat, - self.id, - self.mutbl, - self.ty) - } -} - -impl<'tcx> fmt::Debug for Categorization<'tcx> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match *self { - Categorization::StaticItem => write!(f, "static"), - Categorization::Rvalue(r) => { write!(f, "rvalue({:?})", r) } - Categorization::Local(id) => { - let name = ty::tls::with(|tcx| tcx.hir.name(id)); - write!(f, "local({})", name) - } - Categorization::Upvar(upvar) => { - write!(f, "upvar({:?})", upvar) - } - Categorization::Deref(ref cmt, ptr) => { - write!(f, "{:?}-{:?}->", cmt.cat, ptr) - } - Categorization::Interior(ref cmt, interior) => { - write!(f, "{:?}.{:?}", cmt.cat, interior) - } - Categorization::Downcast(ref cmt, _) => { - write!(f, "{:?}->(enum)", cmt.cat) - } - } - } -} - pub fn ptr_sigil(ptr: PointerKind) -> &'static str { match ptr { Unique => "Box", @@ -1547,27 +1513,6 @@ pub fn ptr_sigil(ptr: PointerKind) -> &'static str { } } -impl<'tcx> fmt::Debug for PointerKind<'tcx> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match *self { - Unique => write!(f, "Box"), - BorrowedPtr(ty::ImmBorrow, ref r) | - Implicit(ty::ImmBorrow, ref r) => { - write!(f, "&{:?}", r) - } - BorrowedPtr(ty::MutBorrow, ref r) | - Implicit(ty::MutBorrow, ref r) => { - write!(f, "&{:?} mut", r) - } - BorrowedPtr(ty::UniqueImmBorrow, ref r) | - Implicit(ty::UniqueImmBorrow, ref r) => { - write!(f, "&{:?} uniq", r) - } - UnsafePtr(_) => write!(f, "*") - } - } -} - impl fmt::Debug for InteriorKind { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { From 629efae761d0a473ddeeb9a4f2e5c408d9ce99dc Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 8 Nov 2017 04:46:44 -0500 Subject: [PATCH 2/2] 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. --- src/librustc_typeck/check/upvar.rs | 6 +++- ...osures-move-from-projection-issue-30046.rs | 35 +++++++++++++++++++ ...ures-infer-fn-once-move-from-projection.rs | 26 ++++++++++++++ ...-infer-fn-once-move-from-projection.stderr | 16 +++++++++ 4 files changed, 82 insertions(+), 1 deletion(-) create mode 100644 src/test/run-pass/unboxed-closures-move-from-projection-issue-30046.rs create mode 100644 src/test/ui/unboxed-closures-infer-fn-once-move-from-projection.rs create mode 100644 src/test/ui/unboxed-closures-infer-fn-once-move-from-projection.stderr 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![allow(unused)] + +fn foo(f: F) + where F: FnOnce() +{ +} + +fn main() { + // Test that this closure is inferred to `FnOnce` + // because it moves from `y.as.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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![allow(unused)] + +fn foo(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 +