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:
Niko Matsakis 2015-02-28 19:34:16 -05:00
parent c5142056f7
commit 00fcf79448
28 changed files with 93 additions and 230 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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