mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-30 18:53:39 +00:00
Remove the synthetic "region bound" from closures and instead update how
type-outlives works for closure types so that it ensures that all upvars outlive the region in question. This gives the same guarantees but without introducing artificial regions (and gives better error messages to boot).
This commit is contained in:
parent
c5142056f7
commit
00fcf79448
@ -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)
|
||||
|
@ -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());
|
||||
|
@ -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