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
```
Each time, we can get a slithtly different output because the threads
are not quaranteed to run in any set order. If you get the same order
every time it is because each of these threads are very small and
complete too fast for their indeterminate behavior to surface.
Each time, we can get a slightly different output because the threads are not
guaranteed to run in any set order. If you get the same order every time it is
because each of these threads are very small and complete too fast for their
indeterminate behavior to surface.
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

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:
```{rust,ignore}
let input_num = "5".parse::<u32>(); // input_num: Option<u32>
let input_num: Result<u32, _> = "5".parse(); // input_num: Result<u32, <u32 as FromStr>::Err>
let input_num_option = "5".parse::<u32>().ok(); // input_num: Option<u32>
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,
our code looks like this:
@ -470,14 +470,14 @@ Let's try it out!
```bash
$ cargo build
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:22 match cmp(input_num, secret_number) {
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:21 match cmp(input_num, secret_number) {
^~~~~~~~~
error: aborting due to previous error
```
Oh yeah! Our `input_num` has the type `Option<u32>`, rather than `u32`. We
need to unwrap the Option. If you remember from before, `match` is a great way
Oh yeah! Our `input_num` has the type `Result<u32, <some error>>`, rather than `u32`. We
need to unwrap the Result. If you remember from before, `match` is a great way
to do that. Try this code:
```{rust,no_run}
@ -500,7 +500,7 @@ fn main() {
let input_num: Result<u32, _> = input.parse();
let num = match input_num {
Ok(num) => num,
Ok(n) => n,
Err(_) => {
println!("Please input a number!");
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:
```bash

View File

@ -364,7 +364,7 @@
//! * `o` - precedes the argument with a "0o"
//! * '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
//! 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
//! 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' => {
assert_eq!(next(st), '[');
let did = parse_def_(st, ClosureSource, conv);
let region = parse_region_(st, conv);
let substs = parse_substs_(st, conv);
assert_eq!(next(st), ']');
return ty::mk_closure(st.tcx, did,
st.tcx.mk_region(region), st.tcx.mk_substs(substs));
return ty::mk_closure(st.tcx, did, st.tcx.mk_substs(substs));
}
'P' => {
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);
mywrite!(w, "]");
}
ty::ty_closure(def, region, substs) => {
ty::ty_closure(def, substs) => {
mywrite!(w, "k[{}|", (cx.ds)(def));
enc_region(w, cx, *region);
enc_substs(w, cx, substs);
mywrite!(w, "]");
}

View File

@ -74,7 +74,7 @@ pub fn simplify_type(tcx: &ty::ctxt,
let def_id = tcx.lang_items.owned_box().unwrap();
Some(StructSimplifiedType(def_id))
}
ty::ty_closure(def_id, _, _) => {
ty::ty_closure(def_id, _) => {
Some(ClosureSimplifiedType(def_id))
}
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)))
}
(&ty::ty_closure(a_id, a_region, a_substs),
&ty::ty_closure(b_id, b_region, b_substs))
(&ty::ty_closure(a_id, a_substs),
&ty::ty_closure(b_id, b_substs))
if a_id == b_id => {
// All ty_closure types with the same id represent
// the (anonymous) type of the same closure expression. So
// 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));
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)) => {

View File

@ -1496,7 +1496,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
fn fn_ret(&self, id: NodeId) -> ty::PolyFnOutput<'tcx> {
let fn_ty = ty::node_id_to_type(self.ir.tcx, id);
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(),
_ =>
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) => {
let ty = try!(self.node_ty(fn_node_id));
match ty.sty {
ty::ty_closure(closure_id, _, _) => {
ty::ty_closure(closure_id, _) => {
match self.typer.closure_kind(closure_id) {
Some(kind) => {
self.cat_upvar(id, span, var_id, fn_node_id, kind)

View File

@ -320,8 +320,10 @@ impl InnermostEnclosingExpr {
#[derive(Debug, Copy)]
pub struct Context {
/// the scope that contains any new variables declared
var_parent: InnermostDeclaringBlock,
/// region parent of expressions etc
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={:?}",
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_type = closure_typer.closure_type(closure_def_id, substs);
let ty::Binder((_, ret_type)) =

View File

@ -293,7 +293,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
// lifetimes can appear inside the self-type.
let self_ty = self.infcx.shallow_resolve(obligation.self_ty());
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; }
};
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 (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(_)) => {
debug!("assemble_unboxed_closure_candidates: ambiguous self-type");
candidates.ambiguous = true;
@ -1533,7 +1533,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
// (T1, ..., Tn) -- meets any bound that all of T1...Tn meet
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
// closures particularly, we need the results of
// inference to decide how to reflect the type of each
@ -1687,7 +1687,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
Some(tys.clone())
}
ty::ty_closure(def_id, _, substs) => {
ty::ty_closure(def_id, substs) => {
assert_eq!(def_id.krate, ast::LOCAL_CRATE);
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_struct(DefId, &'tcx Substs<'tcx>),
ty_closure(DefId, &'tcx Region, &'tcx Substs<'tcx>),
ty_closure(DefId, &'tcx Substs<'tcx>),
ty_tup(Vec<Ty<'tcx>>),
@ -2658,8 +2658,7 @@ impl FlagComputation {
}
}
&ty_closure(_, region, substs) => {
self.add_region(*region);
&ty_closure(_, 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))
}
pub fn mk_closure<'tcx>(cx: &ctxt<'tcx>, closure_id: ast::DefId,
region: &'tcx Region, substs: &'tcx Substs<'tcx>)
pub fn mk_closure<'tcx>(cx: &ctxt<'tcx>, closure_id: ast::DefId, substs: &'tcx Substs<'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> {
@ -3513,13 +3511,11 @@ pub fn type_contents<'tcx>(cx: &ctxt<'tcx>, ty: Ty<'tcx>) -> TypeContents {
apply_lang_items(cx, did, res)
}
ty_closure(did, r, substs) => {
ty_closure(did, substs) => {
// FIXME(#14449): `borrowed_contents` below assumes `&mut` closure.
let param_env = ty::empty_parameter_environment(cx);
let upvars = closure_upvars(&param_env, did, substs).unwrap();
TypeContents::union(&upvars,
|f| tc_ty(cx, &f.ty, cache))
| borrowed_contents(*r, MutMutable)
TypeContents::union(&upvars, |f| tc_ty(cx, &f.ty, cache))
}
ty_tup(ref tys) => {
@ -5175,7 +5171,7 @@ pub fn ty_to_def_id(ty: Ty) -> Option<ast::DefId> {
Some(tt.principal_def_id()),
ty_struct(id, _) |
ty_enum(id, _) |
ty_closure(id, _, _) =>
ty_closure(id, _) =>
Some(id),
_ =>
None
@ -6301,10 +6297,9 @@ pub fn hash_crate_independent<'tcx>(tcx: &ctxt<'tcx>, ty: Ty<'tcx>, svh: &Svh) -
}
ty_infer(_) => unreachable!(),
ty_err => byte!(21),
ty_closure(d, r, _) => {
ty_closure(d, _) => {
byte!(22);
did(state, d);
region(state, *r);
}
ty_projection(ref data) => {
byte!(23);
@ -6618,8 +6613,7 @@ pub fn accumulate_lifetimes_in_type(accumulator: &mut Vec<ty::Region>,
ty_struct(_, substs) => {
accum_substs(accumulator, substs);
}
ty_closure(_, region, substs) => {
accumulator.push(*region);
ty_closure(_, substs) => {
accum_substs(accumulator, substs);
}
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);
ty::ty_struct(did, this.tcx().mk_substs(substs))
}
ty::ty_closure(did, ref region, ref substs) => {
let r = region.fold_with(this);
ty::ty_closure(did, ref substs) => {
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(data.fold_with(this))

View File

@ -45,7 +45,7 @@ impl<'tcx> TypeWalker<'tcx> {
}
ty::ty_enum(_, ref substs) |
ty::ty_struct(_, ref substs) |
ty::ty_closure(_, _, ref substs) => {
ty::ty_closure(_, ref substs) => {
self.push_reversed(substs.types.as_slice());
}
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))
}
ty_str => "str".to_string(),
ty_closure(ref did, _, substs) => {
ty_closure(ref did, substs) => {
let closure_tys = cx.closure_tys.borrow();
closure_tys.get(did).map(|closure_type| {
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)
}
ty::ty_closure(def_id, _, substs) => {
ty::ty_closure(def_id, substs) => {
let typer = NormalizingClosureTyper::new(cx.tcx());
let upvars = typer.closure_upvars(def_id, substs).unwrap();
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) => {
(&f.sig, f.abi, None)
}
ty::ty_closure(closure_did, _, substs) => {
ty::ty_closure(closure_did, substs) => {
let typer = common::NormalizingClosureTyper::new(ccx.tcx());
function_type = typer.closure_type(closure_did, substs);
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 typer = common::NormalizingClosureTyper::new(cx.tcx());
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 (fn_sig, abi, env_ty) = match fn_ty.sty {
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());
function_type = typer.closure_type(closure_did, substs);
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
// unpack the input ty's
let input_tys = match fn_ty.sty {
ty::ty_closure(_, _, _) => {
ty::ty_closure(..) => {
assert!(abi == RustCall);
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
let function_type = erase_regions(ccx.tcx(), &function_type);
let params = match function_type.sty {
ty::ty_closure(_, _, substs) => &substs.types,
ty::ty_closure(_, substs) => &substs.types,
_ => unreachable!()
};
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 closure_ty = typer.closure_type(def_id, substs);
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) => {
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 sig = typer.closure_type(def_id, substs).sig;
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()));
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
variant_cx.fcx.pop_and_trans_custom_cleanup_scope(variant_cx, field_scope)
})
}

View File

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

View File

@ -16,7 +16,6 @@ use astconv;
use middle::region;
use middle::subst;
use middle::ty::{self, ToPolyTraitRef, Ty};
use rscope::RegionScope;
use syntax::abi;
use syntax::ast;
use syntax::ast_util;
@ -61,17 +60,8 @@ fn check_closure<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>,
abi::RustCall,
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,
expr_def_id,
fcx.ccx.tcx.mk_region(region),
fcx.ccx.tcx.mk_substs(
fcx.inh.param_env.free_substs.clone()));

View File

@ -29,6 +29,7 @@ use util::ppaux::Repr;
pub enum Implication<'tcx> {
RegionSubRegion(Option<Ty<'tcx>>, ty::Region, ty::Region),
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>),
}
@ -91,29 +92,9 @@ impl<'a, 'tcx> Implicator<'a, 'tcx> {
// No borrowed content reachable here.
}
ty::ty_closure(_, region, _) => {
// An "closure type" is basically
// modeled here as equivalent to a struct like
//
// 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_closure(def_id, substs) => {
let &(r_a, opt_ty) = self.stack.last().unwrap();
self.out.push(Implication::RegionSubClosure(opt_ty, r_a, def_id, substs));
}
ty::ty_trait(ref t) => {
@ -448,6 +429,13 @@ impl<'tcx> Repr<'tcx> for Implication<'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) => {
format!("Predicate({}, {})",
def_id.repr(tcx),

View File

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

View File

@ -87,12 +87,11 @@ use check::dropck;
use check::FnCtxt;
use check::implicator;
use check::vtable;
use middle::def;
use middle::mem_categorization as mc;
use middle::region::CodeExtent;
use middle::subst::Substs;
use middle::traits;
use middle::ty::{ReScope};
use middle::ty::{self, Ty, MethodCall};
use middle::ty::{self, ClosureTyper, ReScope, Ty, MethodCall};
use middle::infer::{self, GenericKind};
use middle::pat_util;
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);
pub enum SubjectNode { Subject(ast::NodeId), None }
@ -368,7 +353,15 @@ impl<'a, 'tcx> Rcx<'a, 'tcx> {
ty::ReInfer(ty::ReVar(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
// advantage of) every relationship here, but
// we are also free not to -- it simply means
@ -379,13 +372,6 @@ impl<'a, 'tcx> Rcx<'a, 'tcx> {
// relationship that arises here, but
// 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,
expr: &ast::Expr,
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);
visit::walk_expr(rcx, expr);
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,
@ -1538,6 +1409,9 @@ pub fn type_must_outlive<'a, 'tcx>(rcx: &mut Rcx<'a, 'tcx>,
let o1 = infer::ReferenceOutlivesReferent(ty, origin.span());
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) => {
let cause = traits::ObligationCause::new(origin.span(),
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>,
origin: infer::SubregionOrigin<'tcx>,
region: ty::Region,

View File

@ -397,7 +397,7 @@ impl<'a, 'tcx> CoherenceChecker<'a, 'tcx> {
match self_type.ty.sty {
ty::ty_enum(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
.borrow_mut()
.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
//! owned resources. Thread panic is unrecoverable from within
//! the panicking thread (i.e. there is no 'try/catch' in Rust), but
//! panic may optionally be detected from a different thread. If
//! the main thread panics the application will exit with a non-zero
//! the panic may optionally be detected from a different thread. If
//! the main thread panics, the application will exit with a non-zero
//! exit code.
//!
//! 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
//! 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
//!
//! 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:
//!
//! * 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.
//!
//! 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
//! by the APIs of this module.
@ -59,29 +59,27 @@
//! use std::thread;
//!
//! thread::spawn(move || {
//! println!("Hello, World!");
//! // some computation here
//! // some work here
//! });
//! ```
//!
//! In this example, the spawned thread is "detached" from the current
//! thread, meaning that it can outlive the thread that spawned
//! it. (Note, however, that when the main thread terminates all
//! detached threads are terminated as well.)
//! thread. This means that it can outlive its parent (the thread that spawned
//! it), unless this parent is the main thread.
//!
//! ## Scoped threads
//!
//! 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.
//! For this scenario, use the `scoped` constructor:
//! For this scenario, use the `thread::scoped` function:
//!
//! ```rust
//! use std::thread;
//!
//! let guard = thread::scoped(move || {
//! println!("Hello, World!");
//! // some computation here
//! // some work here
//! });
//!
//! // do some other work in the meantime
//! let output = guard.join();
//! ```
@ -92,11 +90,7 @@
//! terminates) when it is dropped. You can join the child thread in
//! advance by calling the `join` method on the guard, which will also
//! return the result produced by the thread. A handle to the thread
//! itself is available via the `thread` method on 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.)
//! itself is available via the `thread` method of the join guard.
//!
//! ## Configuring threads
//!
@ -108,7 +102,7 @@
//! use std::thread;
//!
//! thread::Builder::new().name("child1".to_string()).spawn(move || {
//! println!("Hello, world!")
//! println!("Hello, world!");
//! });
//! ```
//!
@ -121,7 +115,7 @@
//! initially not present:
//!
//! * 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
//! token. `thread::park_timeout()` does the same, but allows specifying a
//! maximum time to block the thread for.
@ -143,7 +137,7 @@
//! * It avoids the need to allocate mutexes and condvars when building new
//! 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")]

View File

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

View File

@ -14,7 +14,9 @@
fn id<T>(t: T) -> T { t }
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() {

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> {
// 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() { }

View File

@ -20,9 +20,9 @@ fn box_it<'r>(x: Box<FnMut() + 'r>) -> closure_box<'r> {
}
fn main() {
let cl_box = {
let mut cl_box = {
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(());
}

View File

@ -13,9 +13,10 @@ use std::thread;
fn main() {
let bad = {
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;
})
};

View File

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