mirror of https://github.com/rust-lang/rust.git
auto merge of #20244 : japaric/rust/bc-no-move, r=nikomatsakis
closes #19141 closes #20193 closes #20228 --- Currently whenever we encounter `let f = || {/* */}`, we *always* type check the RHS as a *boxed* closure. This is wrong when the RHS is `move || {/* */}` (because boxed closures can't capture by value) and generates all sort of badness during trans (see issues above). What we *should* do is always type check `move || {/* */}` as an *unboxed* closure, but ~~I *think* (haven't tried)~~ (2) this is not feasible right now because we have a limited form of kind (`Fn` vs `FnMut` vs `FnOnce`) inference that only works when there is an expected type (1). In this PR, I've chosen to generate a type error whenever `let f = move || {/* */}` is encountered. The error asks the user to annotate the kind of the unboxed closure (e.g. `move |:| {/* */}`). Once annotated, the compiler will type check the RHS as an unboxed closure which is what the user wants. r? @nikomatsakis (1) AIUI it only triggers in this scenario: ``` rust fn is_uc<F>(_: F) where F: FnOnce() {} fn main() { is_uc(|| {}); // type checked as unboxed closure with kind `FnOnce` } ``` (2) I checked, and it's not possible because `check_unboxed_closure` expects a `kind` argument, but we can't supply that argument in this case (i.e. `let f = || {}`, what's the kind?). We could force the `FnOnce` kind in that case, but that's ad hoc. We should try to infer the kind depending on how the closure is used afterwards, but there is no inference mechanism to do that (at least, not right now).
This commit is contained in:
commit
0201334439
|
@ -19,11 +19,13 @@ use middle::ty::{mod, Ty};
|
|||
use rscope::RegionScope;
|
||||
use syntax::abi;
|
||||
use syntax::ast;
|
||||
use syntax::ast::CaptureClause::*;
|
||||
use syntax::ast_util;
|
||||
use util::ppaux::Repr;
|
||||
|
||||
pub fn check_expr_closure<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>,
|
||||
expr: &ast::Expr,
|
||||
capture: ast::CaptureClause,
|
||||
opt_kind: Option<ast::UnboxedClosureKind>,
|
||||
decl: &ast::FnDecl,
|
||||
body: &ast::Block,
|
||||
|
@ -48,12 +50,24 @@ pub fn check_expr_closure<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>,
|
|||
fcx.infcx(),
|
||||
expr.span,
|
||||
&None);
|
||||
|
||||
check_boxed_closure(fcx,
|
||||
expr,
|
||||
ty::RegionTraitStore(region, ast::MutMutable),
|
||||
decl,
|
||||
body,
|
||||
expected);
|
||||
|
||||
match capture {
|
||||
CaptureByValue => {
|
||||
fcx.ccx.tcx.sess.span_err(
|
||||
expr.span,
|
||||
"boxed closures can't capture by value, \
|
||||
if you want to use an unboxed closure, \
|
||||
explicitly annotate its kind: e.g. `move |:|`");
|
||||
},
|
||||
CaptureByRef => {}
|
||||
}
|
||||
}
|
||||
Some((sig, kind)) => {
|
||||
check_unboxed_closure(fcx, expr, kind, decl, body, Some(sig));
|
||||
|
|
|
@ -3973,8 +3973,8 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>,
|
|||
ast::ExprMatch(ref discrim, ref arms, match_src) => {
|
||||
_match::check_match(fcx, expr, &**discrim, arms.as_slice(), expected, match_src);
|
||||
}
|
||||
ast::ExprClosure(_, opt_kind, ref decl, ref body) => {
|
||||
closure::check_expr_closure(fcx, expr, opt_kind, &**decl, &**body, expected);
|
||||
ast::ExprClosure(capture, opt_kind, ref decl, ref body) => {
|
||||
closure::check_expr_closure(fcx, expr, capture, opt_kind, &**decl, &**body, expected);
|
||||
}
|
||||
ast::ExprBlock(ref b) => {
|
||||
check_block_with_expected(fcx, &**b, expected);
|
||||
|
|
|
@ -11,6 +11,6 @@
|
|||
pub fn main() {
|
||||
let bar = box 3;
|
||||
let _g = || {
|
||||
let _h = move|| -> int { *bar }; //~ ERROR cannot move out of captured outer variable
|
||||
let _h = move |:| -> int { *bar }; //~ ERROR cannot move out of captured outer variable
|
||||
};
|
||||
}
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
// 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.
|
||||
|
||||
fn main() {
|
||||
let n = 0u;
|
||||
|
||||
let f = move || n += 1; //~error boxed closures can't capture by value
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
// 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.
|
||||
|
||||
fn foo(t: &mut int){
|
||||
println!("{}", t);
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let test = 10;
|
||||
|
||||
let h = move || { //~error boxed closures can't capture by value
|
||||
let mut r = &mut test.clone();
|
||||
foo(r);
|
||||
};
|
||||
|
||||
h();
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
// 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.
|
||||
|
||||
struct S;
|
||||
|
||||
impl S {
|
||||
fn foo(&self) {
|
||||
let _ = move || { self }; //~error boxed closures can't capture by value
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
// 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.
|
||||
|
||||
struct S;
|
||||
|
||||
impl S {
|
||||
fn foo(&self) {
|
||||
let _ = move || { self.foo() }; //~error boxed closures can't capture by value
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
}
|
Loading…
Reference in New Issue