1
Fork 0

Auto merge of #22963 - Manishearth:rollup, r=Manishearth

This commit is contained in:
bors 2015-03-02 20:26:39 +00:00
commit 2ca6eaedae
34 changed files with 125 additions and 268 deletions

View file

@ -510,10 +510,10 @@ numbers[1] is 3
numbers[0] is 2 numbers[0] is 2
``` ```
Each time, we can get a slithtly different output because the threads Each time, we can get a slightly different output because the threads are not
are not quaranteed to run in any set order. If you get the same order guaranteed to run in any set order. If you get the same order every time it is
every time it is because each of these threads are very small and because each of these threads are very small and complete too fast for their
complete too fast for their indeterminate behavior to surface. indeterminate behavior to surface.
The important part here is that the Rust compiler was able to use ownership to The important part here is that the Rust compiler was able to use ownership to
give us assurance _at compile time_ that we weren't doing something incorrect give us assurance _at compile time_ that we weren't doing something incorrect

View file

@ -422,11 +422,11 @@ In this case, we say `x` is a `u32` explicitly, so Rust is able to properly
tell `random()` what to generate. In a similar fashion, both of these work: tell `random()` what to generate. In a similar fashion, both of these work:
```{rust,ignore} ```{rust,ignore}
let input_num = "5".parse::<u32>(); // input_num: Option<u32> let input_num_option = "5".parse::<u32>().ok(); // input_num: Option<u32>
let input_num: Result<u32, _> = "5".parse(); // input_num: Result<u32, <u32 as FromStr>::Err> let input_num_result: Result<u32, _> = "5".parse(); // input_num: Result<u32, <u32 as FromStr>::Err>
``` ```
Here we're converting the `Result` returned by `parse` to an `Option` by using Above, we're converting the `Result` returned by `parse` to an `Option` by using
the `ok` method as well. Anyway, with us now converting our input to a number, the `ok` method as well. Anyway, with us now converting our input to a number,
our code looks like this: our code looks like this:
@ -470,14 +470,14 @@ Let's try it out!
```bash ```bash
$ cargo build $ cargo build
Compiling guessing_game v0.0.1 (file:///home/you/projects/guessing_game) Compiling guessing_game v0.0.1 (file:///home/you/projects/guessing_game)
src/main.rs:22:15: 22:24 error: mismatched types: expected `u32` but found `core::option::Option<u32>` (expected u32 but found enum core::option::Option) src/main.rs:21:15: 21:24 error: mismatched types: expected `u32`, found `core::result::Result<u32, core::num::ParseIntError>` (expected u32, found enum `core::result::Result`) [E0308]
src/main.rs:22 match cmp(input_num, secret_number) { src/main.rs:21 match cmp(input_num, secret_number) {
^~~~~~~~~ ^~~~~~~~~
error: aborting due to previous error error: aborting due to previous error
``` ```
Oh yeah! Our `input_num` has the type `Option<u32>`, rather than `u32`. We Oh yeah! Our `input_num` has the type `Result<u32, <some error>>`, rather than `u32`. We
need to unwrap the Option. If you remember from before, `match` is a great way need to unwrap the Result. If you remember from before, `match` is a great way
to do that. Try this code: to do that. Try this code:
```{rust,no_run} ```{rust,no_run}
@ -500,7 +500,7 @@ fn main() {
let input_num: Result<u32, _> = input.parse(); let input_num: Result<u32, _> = input.parse();
let num = match input_num { let num = match input_num {
Ok(num) => num, Ok(n) => n,
Err(_) => { Err(_) => {
println!("Please input a number!"); println!("Please input a number!");
return; return;
@ -524,7 +524,7 @@ fn cmp(a: u32, b: u32) -> Ordering {
} }
``` ```
We use a `match` to either give us the `u32` inside of the `Option`, or else We use a `match` to either give us the `u32` inside of the `Result`, or else
print an error message and return. Let's give this a shot: print an error message and return. Let's give this a shot:
```bash ```bash

View file

@ -364,7 +364,7 @@
//! * `o` - precedes the argument with a "0o" //! * `o` - precedes the argument with a "0o"
//! * '0' - This is used to indicate for integer formats that the padding should //! * '0' - This is used to indicate for integer formats that the padding should
//! both be done with a `0` character as well as be sign-aware. A format //! both be done with a `0` character as well as be sign-aware. A format
//! like `{:08d}` would yield `00000001` for the integer `1`, while the //! like `{:08}` would yield `00000001` for the integer `1`, while the
//! same format would yield `-0000001` for the integer `-1`. Notice that //! same format would yield `-0000001` for the integer `-1`. Notice that
//! the negative version has one fewer zero than the positive version. //! the negative version has one fewer zero than the positive version.
//! //!

View file

@ -555,11 +555,9 @@ fn parse_ty_<'a, 'tcx, F>(st: &mut PState<'a, 'tcx>, conv: &mut F) -> Ty<'tcx> w
'k' => { 'k' => {
assert_eq!(next(st), '['); assert_eq!(next(st), '[');
let did = parse_def_(st, ClosureSource, conv); let did = parse_def_(st, ClosureSource, conv);
let region = parse_region_(st, conv);
let substs = parse_substs_(st, conv); let substs = parse_substs_(st, conv);
assert_eq!(next(st), ']'); assert_eq!(next(st), ']');
return ty::mk_closure(st.tcx, did, return ty::mk_closure(st.tcx, did, st.tcx.mk_substs(substs));
st.tcx.mk_region(region), st.tcx.mk_substs(substs));
} }
'P' => { 'P' => {
assert_eq!(next(st), '['); assert_eq!(next(st), '[');

View file

@ -139,9 +139,8 @@ pub fn enc_ty<'a, 'tcx>(w: &mut SeekableMemWriter, cx: &ctxt<'a, 'tcx>, t: Ty<'t
enc_substs(w, cx, substs); enc_substs(w, cx, substs);
mywrite!(w, "]"); mywrite!(w, "]");
} }
ty::ty_closure(def, region, substs) => { ty::ty_closure(def, substs) => {
mywrite!(w, "k[{}|", (cx.ds)(def)); mywrite!(w, "k[{}|", (cx.ds)(def));
enc_region(w, cx, *region);
enc_substs(w, cx, substs); enc_substs(w, cx, substs);
mywrite!(w, "]"); mywrite!(w, "]");
} }

View file

@ -74,7 +74,7 @@ pub fn simplify_type(tcx: &ty::ctxt,
let def_id = tcx.lang_items.owned_box().unwrap(); let def_id = tcx.lang_items.owned_box().unwrap();
Some(StructSimplifiedType(def_id)) Some(StructSimplifiedType(def_id))
} }
ty::ty_closure(def_id, _, _) => { ty::ty_closure(def_id, _) => {
Some(ClosureSimplifiedType(def_id)) Some(ClosureSimplifiedType(def_id))
} }
ty::ty_tup(ref tys) => { ty::ty_tup(ref tys) => {

View file

@ -503,15 +503,14 @@ pub fn super_tys<'tcx, C>(this: &C,
Ok(ty::mk_struct(tcx, a_id, tcx.mk_substs(substs))) Ok(ty::mk_struct(tcx, a_id, tcx.mk_substs(substs)))
} }
(&ty::ty_closure(a_id, a_region, a_substs), (&ty::ty_closure(a_id, a_substs),
&ty::ty_closure(b_id, b_region, b_substs)) &ty::ty_closure(b_id, b_substs))
if a_id == b_id => { if a_id == b_id => {
// All ty_closure types with the same id represent // All ty_closure types with the same id represent
// the (anonymous) type of the same closure expression. So // the (anonymous) type of the same closure expression. So
// all of their regions should be equated. // all of their regions should be equated.
let region = try!(this.equate().regions(*a_region, *b_region));
let substs = try!(this.substs_variances(None, a_substs, b_substs)); let substs = try!(this.substs_variances(None, a_substs, b_substs));
Ok(ty::mk_closure(tcx, a_id, tcx.mk_region(region), tcx.mk_substs(substs))) Ok(ty::mk_closure(tcx, a_id, tcx.mk_substs(substs)))
} }
(&ty::ty_uniq(a_inner), &ty::ty_uniq(b_inner)) => { (&ty::ty_uniq(a_inner), &ty::ty_uniq(b_inner)) => {

View file

@ -1496,7 +1496,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
fn fn_ret(&self, id: NodeId) -> ty::PolyFnOutput<'tcx> { fn fn_ret(&self, id: NodeId) -> ty::PolyFnOutput<'tcx> {
let fn_ty = ty::node_id_to_type(self.ir.tcx, id); let fn_ty = ty::node_id_to_type(self.ir.tcx, id);
match fn_ty.sty { match fn_ty.sty {
ty::ty_closure(closure_def_id, _, substs) => ty::ty_closure(closure_def_id, substs) =>
self.ir.tcx.closure_type(closure_def_id, substs).sig.output(), self.ir.tcx.closure_type(closure_def_id, substs).sig.output(),
_ => _ =>
ty::ty_fn_ret(fn_ty), ty::ty_fn_ret(fn_ty),

View file

@ -607,7 +607,7 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> {
def::DefUpvar(var_id, fn_node_id) => { def::DefUpvar(var_id, fn_node_id) => {
let ty = try!(self.node_ty(fn_node_id)); let ty = try!(self.node_ty(fn_node_id));
match ty.sty { match ty.sty {
ty::ty_closure(closure_id, _, _) => { ty::ty_closure(closure_id, _) => {
match self.typer.closure_kind(closure_id) { match self.typer.closure_kind(closure_id) {
Some(kind) => { Some(kind) => {
self.cat_upvar(id, span, var_id, fn_node_id, kind) self.cat_upvar(id, span, var_id, fn_node_id, kind)

View file

@ -320,8 +320,10 @@ impl InnermostEnclosingExpr {
#[derive(Debug, Copy)] #[derive(Debug, Copy)]
pub struct Context { pub struct Context {
/// the scope that contains any new variables declared
var_parent: InnermostDeclaringBlock, var_parent: InnermostDeclaringBlock,
/// region parent of expressions etc
parent: InnermostEnclosingExpr, parent: InnermostEnclosingExpr,
} }

View file

@ -154,7 +154,7 @@ fn consider_unification_despite_ambiguity<'cx,'tcx>(selcx: &mut SelectionContext
debug!("consider_unification_despite_ambiguity: self_ty.sty={:?}", debug!("consider_unification_despite_ambiguity: self_ty.sty={:?}",
self_ty.sty); self_ty.sty);
match self_ty.sty { match self_ty.sty {
ty::ty_closure(closure_def_id, _, substs) => { ty::ty_closure(closure_def_id, substs) => {
let closure_typer = selcx.closure_typer(); let closure_typer = selcx.closure_typer();
let closure_type = closure_typer.closure_type(closure_def_id, substs); let closure_type = closure_typer.closure_type(closure_def_id, substs);
let ty::Binder((_, ret_type)) = let ty::Binder((_, ret_type)) =

View file

@ -293,7 +293,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
// lifetimes can appear inside the self-type. // lifetimes can appear inside the self-type.
let self_ty = self.infcx.shallow_resolve(obligation.self_ty()); let self_ty = self.infcx.shallow_resolve(obligation.self_ty());
let (closure_def_id, substs) = match self_ty.sty { let (closure_def_id, substs) = match self_ty.sty {
ty::ty_closure(id, _, ref substs) => (id, substs.clone()), ty::ty_closure(id, ref substs) => (id, substs.clone()),
_ => { return; } _ => { return; }
}; };
assert!(!substs.has_escaping_regions()); assert!(!substs.has_escaping_regions());
@ -1054,7 +1054,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
let self_ty = self.infcx.shallow_resolve(obligation.self_ty()); let self_ty = self.infcx.shallow_resolve(obligation.self_ty());
let (closure_def_id, substs) = match self_ty.sty { let (closure_def_id, substs) = match self_ty.sty {
ty::ty_closure(id, _, ref substs) => (id, substs.clone()), ty::ty_closure(id, ref substs) => (id, substs.clone()),
ty::ty_infer(ty::TyVar(_)) => { ty::ty_infer(ty::TyVar(_)) => {
debug!("assemble_unboxed_closure_candidates: ambiguous self-type"); debug!("assemble_unboxed_closure_candidates: ambiguous self-type");
candidates.ambiguous = true; candidates.ambiguous = true;
@ -1533,7 +1533,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
// (T1, ..., Tn) -- meets any bound that all of T1...Tn meet // (T1, ..., Tn) -- meets any bound that all of T1...Tn meet
ty::ty_tup(ref tys) => Ok(If(tys.clone())), ty::ty_tup(ref tys) => Ok(If(tys.clone())),
ty::ty_closure(def_id, _, substs) => { ty::ty_closure(def_id, substs) => {
// FIXME -- This case is tricky. In the case of by-ref // FIXME -- This case is tricky. In the case of by-ref
// closures particularly, we need the results of // closures particularly, we need the results of
// inference to decide how to reflect the type of each // inference to decide how to reflect the type of each
@ -1687,7 +1687,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
Some(tys.clone()) Some(tys.clone())
} }
ty::ty_closure(def_id, _, substs) => { ty::ty_closure(def_id, substs) => {
assert_eq!(def_id.krate, ast::LOCAL_CRATE); assert_eq!(def_id.krate, ast::LOCAL_CRATE);
match self.closure_typer.closure_upvars(def_id, substs) { match self.closure_typer.closure_upvars(def_id, substs) {

View file

@ -1367,7 +1367,7 @@ pub enum sty<'tcx> {
ty_trait(Box<TyTrait<'tcx>>), ty_trait(Box<TyTrait<'tcx>>),
ty_struct(DefId, &'tcx Substs<'tcx>), ty_struct(DefId, &'tcx Substs<'tcx>),
ty_closure(DefId, &'tcx Region, &'tcx Substs<'tcx>), ty_closure(DefId, &'tcx Substs<'tcx>),
ty_tup(Vec<Ty<'tcx>>), ty_tup(Vec<Ty<'tcx>>),
@ -2658,8 +2658,7 @@ impl FlagComputation {
} }
} }
&ty_closure(_, region, substs) => { &ty_closure(_, substs) => {
self.add_region(*region);
self.add_substs(substs); self.add_substs(substs);
} }
@ -2927,10 +2926,9 @@ pub fn mk_struct<'tcx>(cx: &ctxt<'tcx>, struct_id: ast::DefId,
mk_t(cx, ty_struct(struct_id, substs)) mk_t(cx, ty_struct(struct_id, substs))
} }
pub fn mk_closure<'tcx>(cx: &ctxt<'tcx>, closure_id: ast::DefId, pub fn mk_closure<'tcx>(cx: &ctxt<'tcx>, closure_id: ast::DefId, substs: &'tcx Substs<'tcx>)
region: &'tcx Region, substs: &'tcx Substs<'tcx>)
-> Ty<'tcx> { -> Ty<'tcx> {
mk_t(cx, ty_closure(closure_id, region, substs)) mk_t(cx, ty_closure(closure_id, substs))
} }
pub fn mk_var<'tcx>(cx: &ctxt<'tcx>, v: TyVid) -> Ty<'tcx> { pub fn mk_var<'tcx>(cx: &ctxt<'tcx>, v: TyVid) -> Ty<'tcx> {
@ -3513,13 +3511,11 @@ pub fn type_contents<'tcx>(cx: &ctxt<'tcx>, ty: Ty<'tcx>) -> TypeContents {
apply_lang_items(cx, did, res) apply_lang_items(cx, did, res)
} }
ty_closure(did, r, substs) => { ty_closure(did, substs) => {
// FIXME(#14449): `borrowed_contents` below assumes `&mut` closure. // FIXME(#14449): `borrowed_contents` below assumes `&mut` closure.
let param_env = ty::empty_parameter_environment(cx); let param_env = ty::empty_parameter_environment(cx);
let upvars = closure_upvars(&param_env, did, substs).unwrap(); let upvars = closure_upvars(&param_env, did, substs).unwrap();
TypeContents::union(&upvars, TypeContents::union(&upvars, |f| tc_ty(cx, &f.ty, cache))
|f| tc_ty(cx, &f.ty, cache))
| borrowed_contents(*r, MutMutable)
} }
ty_tup(ref tys) => { ty_tup(ref tys) => {
@ -5175,7 +5171,7 @@ pub fn ty_to_def_id(ty: Ty) -> Option<ast::DefId> {
Some(tt.principal_def_id()), Some(tt.principal_def_id()),
ty_struct(id, _) | ty_struct(id, _) |
ty_enum(id, _) | ty_enum(id, _) |
ty_closure(id, _, _) => ty_closure(id, _) =>
Some(id), Some(id),
_ => _ =>
None None
@ -6301,10 +6297,9 @@ pub fn hash_crate_independent<'tcx>(tcx: &ctxt<'tcx>, ty: Ty<'tcx>, svh: &Svh) -
} }
ty_infer(_) => unreachable!(), ty_infer(_) => unreachable!(),
ty_err => byte!(21), ty_err => byte!(21),
ty_closure(d, r, _) => { ty_closure(d, _) => {
byte!(22); byte!(22);
did(state, d); did(state, d);
region(state, *r);
} }
ty_projection(ref data) => { ty_projection(ref data) => {
byte!(23); byte!(23);
@ -6618,8 +6613,7 @@ pub fn accumulate_lifetimes_in_type(accumulator: &mut Vec<ty::Region>,
ty_struct(_, substs) => { ty_struct(_, substs) => {
accum_substs(accumulator, substs); accum_substs(accumulator, substs);
} }
ty_closure(_, region, substs) => { ty_closure(_, substs) => {
accumulator.push(*region);
accum_substs(accumulator, substs); accum_substs(accumulator, substs);
} }
ty_bool | ty_bool |

View file

@ -650,10 +650,9 @@ pub fn super_fold_ty<'tcx, T: TypeFolder<'tcx>>(this: &mut T,
let substs = substs.fold_with(this); let substs = substs.fold_with(this);
ty::ty_struct(did, this.tcx().mk_substs(substs)) ty::ty_struct(did, this.tcx().mk_substs(substs))
} }
ty::ty_closure(did, ref region, ref substs) => { ty::ty_closure(did, ref substs) => {
let r = region.fold_with(this);
let s = substs.fold_with(this); let s = substs.fold_with(this);
ty::ty_closure(did, this.tcx().mk_region(r), this.tcx().mk_substs(s)) ty::ty_closure(did, this.tcx().mk_substs(s))
} }
ty::ty_projection(ref data) => { ty::ty_projection(ref data) => {
ty::ty_projection(data.fold_with(this)) ty::ty_projection(data.fold_with(this))

View file

@ -45,7 +45,7 @@ impl<'tcx> TypeWalker<'tcx> {
} }
ty::ty_enum(_, ref substs) | ty::ty_enum(_, ref substs) |
ty::ty_struct(_, ref substs) | ty::ty_struct(_, ref substs) |
ty::ty_closure(_, _, ref substs) => { ty::ty_closure(_, ref substs) => {
self.push_reversed(substs.types.as_slice()); self.push_reversed(substs.types.as_slice());
} }
ty::ty_tup(ref ts) => { ty::ty_tup(ref ts) => {

View file

@ -406,7 +406,7 @@ pub fn ty_to_string<'tcx>(cx: &ctxt<'tcx>, typ: &ty::TyS<'tcx>) -> String {
data.item_name.user_string(cx)) data.item_name.user_string(cx))
} }
ty_str => "str".to_string(), ty_str => "str".to_string(),
ty_closure(ref did, _, substs) => { ty_closure(ref did, substs) => {
let closure_tys = cx.closure_tys.borrow(); let closure_tys = cx.closure_tys.borrow();
closure_tys.get(did).map(|closure_type| { closure_tys.get(did).map(|closure_type| {
closure_to_string(cx, &closure_type.subst(cx, substs)) closure_to_string(cx, &closure_type.subst(cx, substs))

View file

@ -169,7 +169,7 @@ fn represent_type_uncached<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
Univariant(mk_struct(cx, &ftys[..], packed, t), dtor) Univariant(mk_struct(cx, &ftys[..], packed, t), dtor)
} }
ty::ty_closure(def_id, _, substs) => { ty::ty_closure(def_id, substs) => {
let typer = NormalizingClosureTyper::new(cx.tcx()); let typer = NormalizingClosureTyper::new(cx.tcx());
let upvars = typer.closure_upvars(def_id, substs).unwrap(); let upvars = typer.closure_upvars(def_id, substs).unwrap();
let upvar_types = upvars.iter().map(|u| u.ty).collect::<Vec<_>>(); let upvar_types = upvars.iter().map(|u| u.ty).collect::<Vec<_>>();

View file

@ -291,7 +291,7 @@ pub fn decl_rust_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
ty::ty_bare_fn(_, ref f) => { ty::ty_bare_fn(_, ref f) => {
(&f.sig, f.abi, None) (&f.sig, f.abi, None)
} }
ty::ty_closure(closure_did, _, substs) => { ty::ty_closure(closure_did, substs) => {
let typer = common::NormalizingClosureTyper::new(ccx.tcx()); let typer = common::NormalizingClosureTyper::new(ccx.tcx());
function_type = typer.closure_type(closure_did, substs); function_type = typer.closure_type(closure_did, substs);
let self_type = self_type_for_closure(ccx, closure_did, fn_ty); let self_type = self_type_for_closure(ccx, closure_did, fn_ty);
@ -685,7 +685,7 @@ pub fn iter_structural_ty<'blk, 'tcx, F>(cx: Block<'blk, 'tcx>,
} }
}) })
} }
ty::ty_closure(def_id, _, substs) => { ty::ty_closure(def_id, substs) => {
let repr = adt::represent_type(cx.ccx(), t); let repr = adt::represent_type(cx.ccx(), t);
let typer = common::NormalizingClosureTyper::new(cx.tcx()); let typer = common::NormalizingClosureTyper::new(cx.tcx());
let upvars = typer.closure_upvars(def_id, substs).unwrap(); let upvars = typer.closure_upvars(def_id, substs).unwrap();
@ -2437,7 +2437,7 @@ pub fn get_fn_llvm_attributes<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fn_ty: Ty<
let function_type; let function_type;
let (fn_sig, abi, env_ty) = match fn_ty.sty { let (fn_sig, abi, env_ty) = match fn_ty.sty {
ty::ty_bare_fn(_, ref f) => (&f.sig, f.abi, None), ty::ty_bare_fn(_, ref f) => (&f.sig, f.abi, None),
ty::ty_closure(closure_did, _, substs) => { ty::ty_closure(closure_did, substs) => {
let typer = common::NormalizingClosureTyper::new(ccx.tcx()); let typer = common::NormalizingClosureTyper::new(ccx.tcx());
function_type = typer.closure_type(closure_did, substs); function_type = typer.closure_type(closure_did, substs);
let self_type = self_type_for_closure(ccx, closure_did, fn_ty); let self_type = self_type_for_closure(ccx, closure_did, fn_ty);
@ -2454,7 +2454,7 @@ pub fn get_fn_llvm_attributes<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fn_ty: Ty<
// These have an odd calling convention, so we need to manually // These have an odd calling convention, so we need to manually
// unpack the input ty's // unpack the input ty's
let input_tys = match fn_ty.sty { let input_tys = match fn_ty.sty {
ty::ty_closure(_, _, _) => { ty::ty_closure(..) => {
assert!(abi == RustCall); assert!(abi == RustCall);
match fn_sig.inputs[0].sty { match fn_sig.inputs[0].sty {

View file

@ -138,7 +138,7 @@ pub fn get_or_create_declaration_if_closure<'a, 'tcx>(ccx: &CrateContext<'a, 'tc
// duplicate declarations // duplicate declarations
let function_type = erase_regions(ccx.tcx(), &function_type); let function_type = erase_regions(ccx.tcx(), &function_type);
let params = match function_type.sty { let params = match function_type.sty {
ty::ty_closure(_, _, substs) => &substs.types, ty::ty_closure(_, substs) => &substs.types,
_ => unreachable!() _ => unreachable!()
}; };
let mono_id = MonoId { let mono_id = MonoId {

View file

@ -472,7 +472,7 @@ impl<'tcx> TypeMap<'tcx> {
} }
} }
}, },
ty::ty_closure(def_id, _, substs) => { ty::ty_closure(def_id, substs) => {
let typer = NormalizingClosureTyper::new(cx.tcx()); let typer = NormalizingClosureTyper::new(cx.tcx());
let closure_ty = typer.closure_type(def_id, substs); let closure_ty = typer.closure_type(def_id, substs);
self.get_unique_type_id_of_closure_type(cx, self.get_unique_type_id_of_closure_type(cx,
@ -2983,7 +2983,7 @@ fn type_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
ty::ty_bare_fn(_, ref barefnty) => { ty::ty_bare_fn(_, ref barefnty) => {
subroutine_type_metadata(cx, unique_type_id, &barefnty.sig, usage_site_span) subroutine_type_metadata(cx, unique_type_id, &barefnty.sig, usage_site_span)
} }
ty::ty_closure(def_id, _, substs) => { ty::ty_closure(def_id, substs) => {
let typer = NormalizingClosureTyper::new(cx.tcx()); let typer = NormalizingClosureTyper::new(cx.tcx());
let sig = typer.closure_type(def_id, substs).sig; let sig = typer.closure_type(def_id, substs).sig;
subroutine_type_metadata(cx, unique_type_id, &sig, usage_site_span) subroutine_type_metadata(cx, unique_type_id, &sig, usage_site_span)

View file

@ -313,8 +313,7 @@ fn trans_struct_drop<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
ty::mk_nil(bcx.tcx())); ty::mk_nil(bcx.tcx()));
let (_, variant_cx) = invoke(variant_cx, dtor_addr, &args[..], dtor_ty, DebugLoc::None); let (_, variant_cx) = invoke(variant_cx, dtor_addr, &args[..], dtor_ty, DebugLoc::None);
variant_cx.fcx.pop_and_trans_custom_cleanup_scope(variant_cx, field_scope); variant_cx.fcx.pop_and_trans_custom_cleanup_scope(variant_cx, field_scope)
variant_cx
}) })
} }

View file

@ -137,7 +137,7 @@ fn try_overloaded_call_step<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
return Some(CallStep::Builtin); return Some(CallStep::Builtin);
} }
ty::ty_closure(def_id, _, substs) => { ty::ty_closure(def_id, substs) => {
assert_eq!(def_id.krate, ast::LOCAL_CRATE); assert_eq!(def_id.krate, ast::LOCAL_CRATE);
// Check whether this is a call to a closure where we // Check whether this is a call to a closure where we

View file

@ -16,7 +16,6 @@ use astconv;
use middle::region; use middle::region;
use middle::subst; use middle::subst;
use middle::ty::{self, ToPolyTraitRef, Ty}; use middle::ty::{self, ToPolyTraitRef, Ty};
use rscope::RegionScope;
use syntax::abi; use syntax::abi;
use syntax::ast; use syntax::ast;
use syntax::ast_util; use syntax::ast_util;
@ -61,17 +60,8 @@ fn check_closure<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>,
abi::RustCall, abi::RustCall,
expected_sig); expected_sig);
let region = match fcx.anon_regions(expr.span, 1) {
Err(_) => {
fcx.ccx.tcx.sess.span_bug(expr.span,
"can't make anon regions here?!")
}
Ok(regions) => regions[0],
};
let closure_type = ty::mk_closure(fcx.ccx.tcx, let closure_type = ty::mk_closure(fcx.ccx.tcx,
expr_def_id, expr_def_id,
fcx.ccx.tcx.mk_region(region),
fcx.ccx.tcx.mk_substs( fcx.ccx.tcx.mk_substs(
fcx.inh.param_env.free_substs.clone())); fcx.inh.param_env.free_substs.clone()));

View file

@ -29,6 +29,7 @@ use util::ppaux::Repr;
pub enum Implication<'tcx> { pub enum Implication<'tcx> {
RegionSubRegion(Option<Ty<'tcx>>, ty::Region, ty::Region), RegionSubRegion(Option<Ty<'tcx>>, ty::Region, ty::Region),
RegionSubGeneric(Option<Ty<'tcx>>, ty::Region, GenericKind<'tcx>), RegionSubGeneric(Option<Ty<'tcx>>, ty::Region, GenericKind<'tcx>),
RegionSubClosure(Option<Ty<'tcx>>, ty::Region, ast::DefId, &'tcx Substs<'tcx>),
Predicate(ast::DefId, ty::Predicate<'tcx>), Predicate(ast::DefId, ty::Predicate<'tcx>),
} }
@ -91,29 +92,9 @@ impl<'a, 'tcx> Implicator<'a, 'tcx> {
// No borrowed content reachable here. // No borrowed content reachable here.
} }
ty::ty_closure(_, region, _) => { ty::ty_closure(def_id, substs) => {
// An "closure type" is basically let &(r_a, opt_ty) = self.stack.last().unwrap();
// modeled here as equivalent to a struct like self.out.push(Implication::RegionSubClosure(opt_ty, r_a, def_id, substs));
//
// struct TheClosure<'b> {
// ...
// }
//
// where the `'b` is the lifetime bound of the
// contents (i.e., all contents must outlive 'b).
//
// Even though closures are glorified structs
// of upvars, we do not need to consider them as they
// can't generate any new constraints. The
// substitutions on the closure are equal to the free
// substitutions of the enclosing parameter
// environment. An upvar captured by value has the
// same type as the original local variable which is
// already checked for consistency. If the upvar is
// captured by reference it must also outlive the
// region bound on the closure, but this is explicitly
// handled by logic in regionck.
self.push_region_constraint_from_top(*region);
} }
ty::ty_trait(ref t) => { ty::ty_trait(ref t) => {
@ -448,6 +429,13 @@ impl<'tcx> Repr<'tcx> for Implication<'tcx> {
p.repr(tcx)) p.repr(tcx))
} }
Implication::RegionSubClosure(_, ref a, ref b, ref c) => {
format!("RegionSubClosure({}, {}, {})",
a.repr(tcx),
b.repr(tcx),
c.repr(tcx))
}
Implication::Predicate(ref def_id, ref p) => { Implication::Predicate(ref def_id, ref p) => {
format!("Predicate({}, {})", format!("Predicate({}, {})",
def_id.repr(tcx), def_id.repr(tcx),

View file

@ -278,7 +278,7 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
} }
ty::ty_enum(did, _) | ty::ty_enum(did, _) |
ty::ty_struct(did, _) | ty::ty_struct(did, _) |
ty::ty_closure(did, _, _) => { ty::ty_closure(did, _) => {
self.assemble_inherent_impl_candidates_for_type(did); self.assemble_inherent_impl_candidates_for_type(did);
} }
ty::ty_uniq(_) => { ty::ty_uniq(_) => {
@ -641,8 +641,8 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
// If so, add "synthetic impls". // If so, add "synthetic impls".
let steps = self.steps.clone(); let steps = self.steps.clone();
for step in &*steps { for step in &*steps {
let (closure_def_id, _, _) = match step.self_ty.sty { let closure_def_id = match step.self_ty.sty {
ty::ty_closure(a, b, ref c) => (a, b, c), ty::ty_closure(a, _) => a,
_ => continue, _ => continue,
}; };

View file

@ -87,12 +87,11 @@ use check::dropck;
use check::FnCtxt; use check::FnCtxt;
use check::implicator; use check::implicator;
use check::vtable; use check::vtable;
use middle::def;
use middle::mem_categorization as mc; use middle::mem_categorization as mc;
use middle::region::CodeExtent; use middle::region::CodeExtent;
use middle::subst::Substs;
use middle::traits; use middle::traits;
use middle::ty::{ReScope}; use middle::ty::{self, ClosureTyper, ReScope, Ty, MethodCall};
use middle::ty::{self, Ty, MethodCall};
use middle::infer::{self, GenericKind}; use middle::infer::{self, GenericKind};
use middle::pat_util; use middle::pat_util;
use util::ppaux::{ty_to_string, Repr}; use util::ppaux::{ty_to_string, Repr};
@ -179,20 +178,6 @@ pub struct Rcx<'a, 'tcx: 'a> {
} }
/// Returns the validity region of `def` -- that is, how long is `def` valid?
fn region_of_def(fcx: &FnCtxt, def: def::Def) -> ty::Region {
let tcx = fcx.tcx();
match def {
def::DefLocal(node_id) | def::DefUpvar(node_id, _) => {
tcx.region_maps.var_region(node_id)
}
_ => {
tcx.sess.bug(&format!("unexpected def in region_of_def: {:?}",
def))
}
}
}
struct RepeatingScope(ast::NodeId); struct RepeatingScope(ast::NodeId);
pub enum SubjectNode { Subject(ast::NodeId), None } pub enum SubjectNode { Subject(ast::NodeId), None }
@ -368,7 +353,15 @@ impl<'a, 'tcx> Rcx<'a, 'tcx> {
ty::ReInfer(ty::ReVar(vid_b))) => { ty::ReInfer(ty::ReVar(vid_b))) => {
self.fcx.inh.infcx.add_given(free_a, vid_b); self.fcx.inh.infcx.add_given(free_a, vid_b);
} }
implicator::Implication::RegionSubRegion(..) => { implicator::Implication::RegionSubGeneric(_, r_a, ref generic_b) => {
debug!("RegionSubGeneric: {} <= {}",
r_a.repr(tcx), generic_b.repr(tcx));
self.region_bound_pairs.push((r_a, generic_b.clone()));
}
implicator::Implication::RegionSubRegion(..) |
implicator::Implication::RegionSubClosure(..) |
implicator::Implication::Predicate(..) => {
// In principle, we could record (and take // In principle, we could record (and take
// advantage of) every relationship here, but // advantage of) every relationship here, but
// we are also free not to -- it simply means // we are also free not to -- it simply means
@ -379,13 +372,6 @@ impl<'a, 'tcx> Rcx<'a, 'tcx> {
// relationship that arises here, but // relationship that arises here, but
// presently we do not.) // presently we do not.)
} }
implicator::Implication::RegionSubGeneric(_, r_a, ref generic_b) => {
debug!("RegionSubGeneric: {} <= {}",
r_a.repr(tcx), generic_b.repr(tcx));
self.region_bound_pairs.push((r_a, generic_b.clone()));
}
implicator::Implication::Predicate(..) => { }
} }
} }
} }
@ -792,124 +778,9 @@ fn constrain_cast(rcx: &mut Rcx,
fn check_expr_fn_block(rcx: &mut Rcx, fn check_expr_fn_block(rcx: &mut Rcx,
expr: &ast::Expr, expr: &ast::Expr,
body: &ast::Block) { body: &ast::Block) {
let tcx = rcx.fcx.tcx();
let function_type = rcx.resolve_node_type(expr.id);
match function_type.sty {
ty::ty_closure(_, region, _) => {
ty::with_freevars(tcx, expr.id, |freevars| {
constrain_captured_variables(rcx, *region, expr, freevars);
})
}
_ => { }
}
let repeating_scope = rcx.set_repeating_scope(body.id); let repeating_scope = rcx.set_repeating_scope(body.id);
visit::walk_expr(rcx, expr); visit::walk_expr(rcx, expr);
rcx.set_repeating_scope(repeating_scope); rcx.set_repeating_scope(repeating_scope);
match function_type.sty {
ty::ty_closure(_, region, _) => {
ty::with_freevars(tcx, expr.id, |freevars| {
let bounds = ty::region_existential_bound(*region);
ensure_free_variable_types_outlive_closure_bound(rcx, &bounds, expr, freevars);
})
}
_ => {}
}
/// Make sure that the type of all free variables referenced inside a closure/proc outlive the
/// closure/proc's lifetime bound. This is just a special case of the usual rules about closed
/// over values outliving the object's lifetime bound.
fn ensure_free_variable_types_outlive_closure_bound(
rcx: &mut Rcx,
bounds: &ty::ExistentialBounds,
expr: &ast::Expr,
freevars: &[ty::Freevar])
{
let tcx = rcx.fcx.ccx.tcx;
debug!("ensure_free_variable_types_outlive_closure_bound({}, {})",
bounds.region_bound.repr(tcx), expr.repr(tcx));
for freevar in freevars {
let var_node_id = {
let def_id = freevar.def.def_id();
assert!(def_id.krate == ast::LOCAL_CRATE);
def_id.node
};
// Compute the type of the field in the environment that
// represents `var_node_id`. For a by-value closure, this
// will be the same as the type of the variable. For a
// by-reference closure, this will be `&T` where `T` is
// the type of the variable.
let raw_var_ty = rcx.resolve_node_type(var_node_id);
let upvar_id = ty::UpvarId { var_id: var_node_id,
closure_expr_id: expr.id };
let var_ty = match rcx.fcx.inh.upvar_capture_map.borrow()[upvar_id] {
ty::UpvarCapture::ByRef(ref upvar_borrow) => {
ty::mk_rptr(rcx.tcx(),
rcx.tcx().mk_region(upvar_borrow.region),
ty::mt { mutbl: upvar_borrow.kind.to_mutbl_lossy(),
ty: raw_var_ty })
}
ty::UpvarCapture::ByValue => raw_var_ty,
};
// Check that the type meets the criteria of the existential bounds:
for builtin_bound in &bounds.builtin_bounds {
let code = traits::ClosureCapture(var_node_id, expr.span, builtin_bound);
let cause = traits::ObligationCause::new(freevar.span, rcx.fcx.body_id, code);
rcx.fcx.register_builtin_bound(var_ty, builtin_bound, cause);
}
type_must_outlive(
rcx, infer::FreeVariable(expr.span, var_node_id),
var_ty, bounds.region_bound);
}
}
/// Make sure that all free variables referenced inside the closure outlive the closure's
/// lifetime bound. Also, create an entry in the upvar_borrows map with a region.
fn constrain_captured_variables(
rcx: &mut Rcx,
region_bound: ty::Region,
expr: &ast::Expr,
freevars: &[ty::Freevar])
{
let tcx = rcx.fcx.ccx.tcx;
debug!("constrain_captured_variables({}, {})",
region_bound.repr(tcx), expr.repr(tcx));
for freevar in freevars {
debug!("constrain_captured_variables: freevar.def={:?}", freevar.def);
// Identify the variable being closed over and its node-id.
let def = freevar.def;
let var_node_id = {
let def_id = def.def_id();
assert!(def_id.krate == ast::LOCAL_CRATE);
def_id.node
};
let upvar_id = ty::UpvarId { var_id: var_node_id,
closure_expr_id: expr.id };
match rcx.fcx.inh.upvar_capture_map.borrow()[upvar_id] {
ty::UpvarCapture::ByValue => { }
ty::UpvarCapture::ByRef(upvar_borrow) => {
rcx.fcx.mk_subr(infer::FreeVariable(freevar.span, var_node_id),
region_bound, upvar_borrow.region);
// Guarantee that the closure does not outlive the variable itself.
let enclosing_region = region_of_def(rcx.fcx, def);
debug!("constrain_captured_variables: enclosing_region = {}",
enclosing_region.repr(tcx));
rcx.fcx.mk_subr(infer::FreeVariable(freevar.span, var_node_id),
region_bound, enclosing_region);
}
}
}
}
} }
fn constrain_callee(rcx: &mut Rcx, fn constrain_callee(rcx: &mut Rcx,
@ -1538,6 +1409,9 @@ pub fn type_must_outlive<'a, 'tcx>(rcx: &mut Rcx<'a, 'tcx>,
let o1 = infer::ReferenceOutlivesReferent(ty, origin.span()); let o1 = infer::ReferenceOutlivesReferent(ty, origin.span());
generic_must_outlive(rcx, o1, r_a, generic_b); generic_must_outlive(rcx, o1, r_a, generic_b);
} }
implicator::Implication::RegionSubClosure(_, r_a, def_id, substs) => {
closure_must_outlive(rcx, origin.clone(), r_a, def_id, substs);
}
implicator::Implication::Predicate(def_id, predicate) => { implicator::Implication::Predicate(def_id, predicate) => {
let cause = traits::ObligationCause::new(origin.span(), let cause = traits::ObligationCause::new(origin.span(),
rcx.body_id, rcx.body_id,
@ -1549,6 +1423,23 @@ pub fn type_must_outlive<'a, 'tcx>(rcx: &mut Rcx<'a, 'tcx>,
} }
} }
fn closure_must_outlive<'a, 'tcx>(rcx: &mut Rcx<'a, 'tcx>,
origin: infer::SubregionOrigin<'tcx>,
region: ty::Region,
def_id: ast::DefId,
substs: &'tcx Substs<'tcx>) {
debug!("closure_must_outlive(region={}, def_id={}, substs={})",
region.repr(rcx.tcx()), def_id.repr(rcx.tcx()), substs.repr(rcx.tcx()));
let upvars = rcx.fcx.closure_upvars(def_id, substs).unwrap();
for upvar in upvars {
let var_id = upvar.def.def_id().local_id();
type_must_outlive(
rcx, infer::FreeVariable(origin.span(), var_id),
upvar.ty, region);
}
}
fn generic_must_outlive<'a, 'tcx>(rcx: &Rcx<'a, 'tcx>, fn generic_must_outlive<'a, 'tcx>(rcx: &Rcx<'a, 'tcx>,
origin: infer::SubregionOrigin<'tcx>, origin: infer::SubregionOrigin<'tcx>,
region: ty::Region, region: ty::Region,

View file

@ -397,7 +397,7 @@ impl<'a, 'tcx> CoherenceChecker<'a, 'tcx> {
match self_type.ty.sty { match self_type.ty.sty {
ty::ty_enum(type_def_id, _) | ty::ty_enum(type_def_id, _) |
ty::ty_struct(type_def_id, _) | ty::ty_struct(type_def_id, _) |
ty::ty_closure(type_def_id, _, _) => { ty::ty_closure(type_def_id, _) => {
tcx.destructor_for_type tcx.destructor_for_type
.borrow_mut() .borrow_mut()
.insert(type_def_id, method_def_id.def_id()); .insert(type_def_id, method_def_id.def_id());

View file

@ -28,25 +28,25 @@
//! a thread will unwind the stack, running destructors and freeing //! a thread will unwind the stack, running destructors and freeing
//! owned resources. Thread panic is unrecoverable from within //! owned resources. Thread panic is unrecoverable from within
//! the panicking thread (i.e. there is no 'try/catch' in Rust), but //! the panicking thread (i.e. there is no 'try/catch' in Rust), but
//! panic may optionally be detected from a different thread. If //! the panic may optionally be detected from a different thread. If
//! the main thread panics the application will exit with a non-zero //! the main thread panics, the application will exit with a non-zero
//! exit code. //! exit code.
//! //!
//! When the main thread of a Rust program terminates, the entire program shuts //! When the main thread of a Rust program terminates, the entire program shuts
//! down, even if other threads are still running. However, this module provides //! down, even if other threads are still running. However, this module provides
//! convenient facilities for automatically waiting for the termination of a //! convenient facilities for automatically waiting for the termination of a
//! child thread (i.e., join), described below. //! child thread (i.e., join).
//! //!
//! ## The `Thread` type //! ## The `Thread` type
//! //!
//! Already-running threads are represented via the `Thread` type, which you can //! Threads are represented via the `Thread` type, which you can
//! get in one of two ways: //! get in one of two ways:
//! //!
//! * By spawning a new thread, e.g. using the `thread::spawn` constructor; //! * By spawning a new thread, e.g. using the `thread::spawn` function.
//! * By requesting the current thread, using the `thread::current` function. //! * By requesting the current thread, using the `thread::current` function.
//! //!
//! Threads can be named, and provide some built-in support for low-level //! Threads can be named, and provide some built-in support for low-level
//! synchronization described below. //! synchronization (described below).
//! //!
//! The `thread::current()` function is available even for threads not spawned //! The `thread::current()` function is available even for threads not spawned
//! by the APIs of this module. //! by the APIs of this module.
@ -59,29 +59,27 @@
//! use std::thread; //! use std::thread;
//! //!
//! thread::spawn(move || { //! thread::spawn(move || {
//! println!("Hello, World!"); //! // some work here
//! // some computation here
//! }); //! });
//! ``` //! ```
//! //!
//! In this example, the spawned thread is "detached" from the current //! In this example, the spawned thread is "detached" from the current
//! thread, meaning that it can outlive the thread that spawned //! thread. This means that it can outlive its parent (the thread that spawned
//! it. (Note, however, that when the main thread terminates all //! it), unless this parent is the main thread.
//! detached threads are terminated as well.)
//! //!
//! ## Scoped threads //! ## Scoped threads
//! //!
//! Often a parent thread uses a child thread to perform some particular task, //! Often a parent thread uses a child thread to perform some particular task,
//! and at some point must wait for the child to complete before continuing. //! and at some point must wait for the child to complete before continuing.
//! For this scenario, use the `scoped` constructor: //! For this scenario, use the `thread::scoped` function:
//! //!
//! ```rust //! ```rust
//! use std::thread; //! use std::thread;
//! //!
//! let guard = thread::scoped(move || { //! let guard = thread::scoped(move || {
//! println!("Hello, World!"); //! // some work here
//! // some computation here
//! }); //! });
//!
//! // do some other work in the meantime //! // do some other work in the meantime
//! let output = guard.join(); //! let output = guard.join();
//! ``` //! ```
@ -92,11 +90,7 @@
//! terminates) when it is dropped. You can join the child thread in //! terminates) when it is dropped. You can join the child thread in
//! advance by calling the `join` method on the guard, which will also //! advance by calling the `join` method on the guard, which will also
//! return the result produced by the thread. A handle to the thread //! return the result produced by the thread. A handle to the thread
//! itself is available via the `thread` method on the join guard. //! itself is available via the `thread` method of the join guard.
//!
//! (Note: eventually, the `scoped` constructor will allow the parent and child
//! threads to data that lives on the parent thread's stack, but some language
//! changes are needed before this is possible.)
//! //!
//! ## Configuring threads //! ## Configuring threads
//! //!
@ -108,7 +102,7 @@
//! use std::thread; //! use std::thread;
//! //!
//! thread::Builder::new().name("child1".to_string()).spawn(move || { //! thread::Builder::new().name("child1".to_string()).spawn(move || {
//! println!("Hello, world!") //! println!("Hello, world!");
//! }); //! });
//! ``` //! ```
//! //!
@ -121,7 +115,7 @@
//! initially not present: //! initially not present:
//! //!
//! * The `thread::park()` function blocks the current thread unless or until //! * The `thread::park()` function blocks the current thread unless or until
//! the token is available for its thread handle, at which point It atomically //! the token is available for its thread handle, at which point it atomically
//! consumes the token. It may also return *spuriously*, without consuming the //! consumes the token. It may also return *spuriously*, without consuming the
//! token. `thread::park_timeout()` does the same, but allows specifying a //! token. `thread::park_timeout()` does the same, but allows specifying a
//! maximum time to block the thread for. //! maximum time to block the thread for.
@ -143,7 +137,7 @@
//! * It avoids the need to allocate mutexes and condvars when building new //! * It avoids the need to allocate mutexes and condvars when building new
//! synchronization primitives; the threads already provide basic blocking/signaling. //! synchronization primitives; the threads already provide basic blocking/signaling.
//! //!
//! * It can be implemented highly efficiently on many platforms. //! * It can be implemented very efficiently on many platforms.
#![stable(feature = "rust1", since = "1.0.0")] #![stable(feature = "rust1", since = "1.0.0")]

View file

@ -173,6 +173,7 @@ pub static KNOWN_ATTRIBUTES: &'static [(&'static str, AttributeType)] = &[
("plugin_registrar", Normal), ("plugin_registrar", Normal),
("cfg", Normal), ("cfg", Normal),
("cfg_attr", Normal),
("main", Normal), ("main", Normal),
("start", Normal), ("start", Normal),
("test", Normal), ("test", Normal),

View file

@ -14,7 +14,9 @@
fn id<T>(t: T) -> T { t } fn id<T>(t: T) -> T { t }
fn f<'r, T>(v: &'r T) -> Box<FnMut() -> T + 'r> { fn f<'r, T>(v: &'r T) -> Box<FnMut() -> T + 'r> {
id(box || *v) //~ ERROR cannot infer id(box || *v)
//~^ ERROR `v` does not live long enough
//~| ERROR cannot move out of borrowed content
} }
fn main() { fn main() {

View file

@ -18,7 +18,7 @@ fn borrowed_proc<'a>(x: &'a isize) -> Box<FnMut()->(isize) + 'a> {
fn static_proc(x: &isize) -> Box<FnMut()->(isize) + 'static> { fn static_proc(x: &isize) -> Box<FnMut()->(isize) + 'static> {
// This is illegal, because the region bound on `proc` is 'static. // This is illegal, because the region bound on `proc` is 'static.
box move|| { *x } //~ ERROR cannot infer box move|| { *x } //~ ERROR captured variable `x` does not outlive the enclosing closure
} }
fn main() { } fn main() { }

View file

@ -20,9 +20,9 @@ fn box_it<'r>(x: Box<FnMut() + 'r>) -> closure_box<'r> {
} }
fn main() { fn main() {
let cl_box = { let mut cl_box = {
let mut i = 3; let mut i = 3;
box_it(box || i += 1) //~ ERROR cannot infer box_it(box || i += 1) //~ ERROR `i` does not live long enough
}; };
cl_box.cl.call_mut(()); cl_box.cl.call_mut(());
} }

View file

@ -13,9 +13,10 @@ use std::thread;
fn main() { fn main() {
let bad = { let bad = {
let x = 1; let x = 1;
let y = &x; let y = &x; //~ ERROR `x` does not live long enough
thread::scoped(|| { //~ ERROR cannot infer an appropriate lifetime thread::scoped(|| {
//~^ ERROR `y` does not live long enough
let _z = y; let _z = y;
}) })
}; };

View file

@ -15,6 +15,6 @@
fn main() { fn main() {
let _f = { let _f = {
let x = 0_usize; let x = 0_usize;
|| x //~ ERROR cannot infer an appropriate lifetime due to conflicting requirements || x //~ ERROR `x` does not live long enough
}; };
} }