Auto merge of #22963 - Manishearth:rollup, r=Manishearth
This commit is contained in:
commit
2ca6eaedae
@ -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
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
//!
|
||||
|
@ -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), '[');
|
||||
|
@ -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, "]");
|
||||
}
|
||||
|
@ -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) => {
|
||||
|
@ -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)) => {
|
||||
|
@ -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),
|
||||
|
@ -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)
|
||||
|
@ -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,
|
||||
}
|
||||
|
||||
|
@ -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)) =
|
||||
|
@ -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) {
|
||||
|
@ -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(¶m_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 |
|
||||
|
@ -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))
|
||||
|
@ -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) => {
|
||||
|
@ -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))
|
||||
|
@ -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<_>>();
|
||||
|
@ -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 {
|
||||
|
@ -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 {
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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()));
|
||||
|
||||
|
@ -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),
|
||||
|
@ -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,
|
||||
};
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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());
|
||||
|
@ -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")]
|
||||
|
||||
|
@ -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),
|
||||
|
@ -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() {
|
||||
|
@ -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() { }
|
||||
|
@ -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(());
|
||||
}
|
||||
|
@ -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;
|
||||
})
|
||||
};
|
||||
|
@ -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
|
||||
};
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user