Auto merge of #22963 - Manishearth:rollup, r=Manishearth
This commit is contained in:
commit
2ca6eaedae
34 changed files with 125 additions and 268 deletions
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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.
|
||||||
//!
|
//!
|
||||||
|
|
|
@ -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), '[');
|
||||||
|
|
|
@ -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, "]");
|
||||||
}
|
}
|
||||||
|
|
|
@ -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) => {
|
||||||
|
|
|
@ -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)) => {
|
||||||
|
|
|
@ -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),
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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)) =
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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(¶m_env, did, substs).unwrap();
|
let upvars = closure_upvars(¶m_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 |
|
||||||
|
|
|
@ -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))
|
||||||
|
|
|
@ -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) => {
|
||||||
|
|
|
@ -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))
|
||||||
|
|
|
@ -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<_>>();
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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()));
|
||||||
|
|
||||||
|
|
|
@ -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),
|
||||||
|
|
|
@ -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,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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());
|
||||||
|
|
|
@ -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")]
|
||||||
|
|
||||||
|
|
|
@ -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),
|
||||||
|
|
|
@ -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() {
|
||||||
|
|
|
@ -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() { }
|
||||||
|
|
|
@ -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(());
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
})
|
})
|
||||||
};
|
};
|
||||||
|
|
|
@ -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
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue