Skip to content

Commit c1aacdc

Browse files
committed
Auto merge of #45864 - nikomatsakis:issue-30046-infer-fn-once-in-closures, r=eddyb
adjust closure kind based on the guarantor's upvar note Fixes #30046. r? @eddyb
2 parents e9f8542 + 629efae commit c1aacdc

5 files changed

+87
-61
lines changed

src/librustc/middle/mem_categorization.rs

+5-60
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ use std::fmt;
8888
use std::rc::Rc;
8989
use util::nodemap::ItemLocalSet;
9090

91-
#[derive(Clone, PartialEq)]
91+
#[derive(Clone, Debug, PartialEq)]
9292
pub enum Categorization<'tcx> {
9393
Rvalue(ty::Region<'tcx>), // temporary val, argument is its scope
9494
StaticItem,
@@ -109,7 +109,7 @@ pub struct Upvar {
109109
}
110110

111111
// different kinds of pointers:
112-
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
112+
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
113113
pub enum PointerKind<'tcx> {
114114
/// `Box<T>`
115115
Unique,
@@ -177,7 +177,7 @@ pub enum Note {
177177
// dereference, but its type is the type *before* the dereference
178178
// (`@T`). So use `cmt.ty` to find the type of the value in a consistent
179179
// fashion. For more details, see the method `cat_pattern`
180-
#[derive(Clone, PartialEq)]
180+
#[derive(Clone, Debug, PartialEq)]
181181
pub struct cmt_<'tcx> {
182182
pub id: ast::NodeId, // id of expr/pat producing this value
183183
pub span: Span, // span of same expr/pat
@@ -750,12 +750,13 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
750750

751751
let kind = match self.node_ty(fn_hir_id)?.sty {
752752
ty::TyGenerator(..) => ty::ClosureKind::FnOnce,
753-
_ => {
753+
ty::TyClosure(..) => {
754754
match self.tables.closure_kinds().get(fn_hir_id) {
755755
Some(&(kind, _)) => kind,
756756
None => span_bug!(span, "missing closure kind"),
757757
}
758758
}
759+
ref t => span_bug!(span, "unexpected type for fn in mem_categorization: {:?}", t),
759760
};
760761

761762
let closure_expr_def_index = self.tcx.hir.local_def_id(fn_node_id).index;
@@ -1499,41 +1500,6 @@ impl<'tcx> cmt_<'tcx> {
14991500
}
15001501
}
15011502

1502-
impl<'tcx> fmt::Debug for cmt_<'tcx> {
1503-
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1504-
write!(f, "{{{:?} id:{} m:{:?} ty:{:?}}}",
1505-
self.cat,
1506-
self.id,
1507-
self.mutbl,
1508-
self.ty)
1509-
}
1510-
}
1511-
1512-
impl<'tcx> fmt::Debug for Categorization<'tcx> {
1513-
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1514-
match *self {
1515-
Categorization::StaticItem => write!(f, "static"),
1516-
Categorization::Rvalue(r) => { write!(f, "rvalue({:?})", r) }
1517-
Categorization::Local(id) => {
1518-
let name = ty::tls::with(|tcx| tcx.hir.name(id));
1519-
write!(f, "local({})", name)
1520-
}
1521-
Categorization::Upvar(upvar) => {
1522-
write!(f, "upvar({:?})", upvar)
1523-
}
1524-
Categorization::Deref(ref cmt, ptr) => {
1525-
write!(f, "{:?}-{:?}->", cmt.cat, ptr)
1526-
}
1527-
Categorization::Interior(ref cmt, interior) => {
1528-
write!(f, "{:?}.{:?}", cmt.cat, interior)
1529-
}
1530-
Categorization::Downcast(ref cmt, _) => {
1531-
write!(f, "{:?}->(enum)", cmt.cat)
1532-
}
1533-
}
1534-
}
1535-
}
1536-
15371503
pub fn ptr_sigil(ptr: PointerKind) -> &'static str {
15381504
match ptr {
15391505
Unique => "Box",
@@ -1547,27 +1513,6 @@ pub fn ptr_sigil(ptr: PointerKind) -> &'static str {
15471513
}
15481514
}
15491515

1550-
impl<'tcx> fmt::Debug for PointerKind<'tcx> {
1551-
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1552-
match *self {
1553-
Unique => write!(f, "Box"),
1554-
BorrowedPtr(ty::ImmBorrow, ref r) |
1555-
Implicit(ty::ImmBorrow, ref r) => {
1556-
write!(f, "&{:?}", r)
1557-
}
1558-
BorrowedPtr(ty::MutBorrow, ref r) |
1559-
Implicit(ty::MutBorrow, ref r) => {
1560-
write!(f, "&{:?} mut", r)
1561-
}
1562-
BorrowedPtr(ty::UniqueImmBorrow, ref r) |
1563-
Implicit(ty::UniqueImmBorrow, ref r) => {
1564-
write!(f, "&{:?} uniq", r)
1565-
}
1566-
UnsafePtr(_) => write!(f, "*")
1567-
}
1568-
}
1569-
}
1570-
15711516
impl fmt::Debug for InteriorKind {
15721517
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
15731518
match *self {

src/librustc_typeck/check/upvar.rs

+5-1
Original file line numberDiff line numberDiff line change
@@ -289,10 +289,14 @@ impl<'a, 'gcx, 'tcx> InferBorrowKind<'a, 'gcx, 'tcx> {
289289
let guarantor = cmt.guarantor();
290290
debug!("adjust_upvar_borrow_kind_for_consume: guarantor={:?}",
291291
guarantor);
292+
debug!("adjust_upvar_borrow_kind_for_consume: guarantor.cat={:?}",
293+
guarantor.cat);
292294
match guarantor.cat {
293295
Categorization::Deref(_, mc::BorrowedPtr(..)) |
294296
Categorization::Deref(_, mc::Implicit(..)) => {
295-
match cmt.note {
297+
debug!("adjust_upvar_borrow_kind_for_consume: found deref with note {:?}",
298+
cmt.note);
299+
match guarantor.note {
296300
mc::NoteUpvarRef(upvar_id) => {
297301
debug!("adjust_upvar_borrow_kind_for_consume: \
298302
setting upvar_id={:?} to by value",
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
#![allow(unused)]
12+
13+
fn foo<F>(f: F)
14+
where F: FnOnce()
15+
{
16+
}
17+
18+
fn main() {
19+
// Test that this closure is inferred to `FnOnce`
20+
// because it moves from `y.as<Option::Some>.0`:
21+
let x = Some(vec![1, 2, 3]);
22+
foo(|| {
23+
match x {
24+
Some(y) => { }
25+
None => { }
26+
}
27+
});
28+
29+
// Test that this closure is inferred to `FnOnce`
30+
// because it moves from `y.0`:
31+
let y = (vec![1, 2, 3], 0);
32+
foo(|| {
33+
let x = y.0;
34+
});
35+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
#![allow(unused)]
12+
13+
fn foo<F>(f: F)
14+
where F: Fn()
15+
{
16+
}
17+
18+
fn main() {
19+
// Test that this closure is inferred to `FnOnce` because it moves
20+
// from `y.0`. This affects the error output (the error is that
21+
// the closure implements `FnOnce`, not that it moves from inside
22+
// a `Fn` closure.)
23+
let y = (vec![1, 2, 3], 0);
24+
let c = || drop(y.0);
25+
foo(c);
26+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
error[E0525]: expected a closure that implements the `Fn` trait, but this closure only implements `FnOnce`
2+
--> $DIR/unboxed-closures-infer-fn-once-move-from-projection.rs:24:13
3+
|
4+
24 | let c = || drop(y.0);
5+
| ^^^^^^^^^^^^
6+
25 | foo(c);
7+
| --- the requirement to implement `Fn` derives from here
8+
|
9+
note: closure is `FnOnce` because it moves the variable `y` out of its environment
10+
--> $DIR/unboxed-closures-infer-fn-once-move-from-projection.rs:24:21
11+
|
12+
24 | let c = || drop(y.0);
13+
| ^
14+
15+
error: aborting due to previous error
16+

0 commit comments

Comments
 (0)