From 00fcf794488e5e1a4761342dac7d2bcdfb66152f Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Sat, 28 Feb 2015 19:34:16 -0500 Subject: [PATCH] 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). --- src/librustc/metadata/tydecode.rs | 4 +- src/librustc/metadata/tyencode.rs | 3 +- src/librustc/middle/fast_reject.rs | 2 +- src/librustc/middle/infer/combine.rs | 7 +- src/librustc/middle/liveness.rs | 2 +- src/librustc/middle/mem_categorization.rs | 2 +- src/librustc/middle/region.rs | 2 + src/librustc/middle/traits/project.rs | 2 +- src/librustc/middle/traits/select.rs | 8 +- src/librustc/middle/ty.rs | 24 +-- src/librustc/middle/ty_fold.rs | 5 +- src/librustc/middle/ty_walk.rs | 2 +- src/librustc/util/ppaux.rs | 2 +- src/librustc_trans/trans/adt.rs | 2 +- src/librustc_trans/trans/base.rs | 8 +- src/librustc_trans/trans/closure.rs | 2 +- src/librustc_trans/trans/debuginfo.rs | 4 +- src/librustc_typeck/check/callee.rs | 2 +- src/librustc_typeck/check/closure.rs | 10 - src/librustc_typeck/check/implicator.rs | 34 ++-- src/librustc_typeck/check/method/probe.rs | 6 +- src/librustc_typeck/check/regionck.rs | 171 ++++-------------- src/librustc_typeck/coherence/mod.rs | 2 +- src/test/compile-fail/issue-4335.rs | 4 +- .../regions-proc-bound-capture.rs | 2 +- .../compile-fail/regions-steal-closure.rs | 4 +- .../send-is-not-static-ensures-scoping.rs | 5 +- .../compile-fail/unboxed-closure-region.rs | 2 +- 28 files changed, 93 insertions(+), 230 deletions(-) diff --git a/src/librustc/metadata/tydecode.rs b/src/librustc/metadata/tydecode.rs index baecfb7eb22c5..b33839f33e820 100644 --- a/src/librustc/metadata/tydecode.rs +++ b/src/librustc/metadata/tydecode.rs @@ -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), '['); diff --git a/src/librustc/metadata/tyencode.rs b/src/librustc/metadata/tyencode.rs index 76a365259aa57..ebb4153e32bce 100644 --- a/src/librustc/metadata/tyencode.rs +++ b/src/librustc/metadata/tyencode.rs @@ -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, "]"); } diff --git a/src/librustc/middle/fast_reject.rs b/src/librustc/middle/fast_reject.rs index 7584a2e44cc7c..063845c6c3425 100644 --- a/src/librustc/middle/fast_reject.rs +++ b/src/librustc/middle/fast_reject.rs @@ -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) => { diff --git a/src/librustc/middle/infer/combine.rs b/src/librustc/middle/infer/combine.rs index b782a655d89ff..be94a73df37ba 100644 --- a/src/librustc/middle/infer/combine.rs +++ b/src/librustc/middle/infer/combine.rs @@ -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)) => { diff --git a/src/librustc/middle/liveness.rs b/src/librustc/middle/liveness.rs index 5cb034667cc64..224a568c77f02 100644 --- a/src/librustc/middle/liveness.rs +++ b/src/librustc/middle/liveness.rs @@ -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), diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index c4446b87855ca..1f02f13a4a178 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -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) diff --git a/src/librustc/middle/region.rs b/src/librustc/middle/region.rs index 7db1138ac72f6..b4db3aba7867d 100644 --- a/src/librustc/middle/region.rs +++ b/src/librustc/middle/region.rs @@ -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, } diff --git a/src/librustc/middle/traits/project.rs b/src/librustc/middle/traits/project.rs index 7d4febb38e678..b9a863f4fe46f 100644 --- a/src/librustc/middle/traits/project.rs +++ b/src/librustc/middle/traits/project.rs @@ -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)) = diff --git a/src/librustc/middle/traits/select.rs b/src/librustc/middle/traits/select.rs index d8c62780a781f..470315c78f81d 100644 --- a/src/librustc/middle/traits/select.rs +++ b/src/librustc/middle/traits/select.rs @@ -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) { diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index 635ec09d3394c..aaba840825e69 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -1367,7 +1367,7 @@ pub enum sty<'tcx> { ty_trait(Box>), ty_struct(DefId, &'tcx Substs<'tcx>), - ty_closure(DefId, &'tcx Region, &'tcx Substs<'tcx>), + ty_closure(DefId, &'tcx Substs<'tcx>), ty_tup(Vec>), @@ -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 { 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_struct(_, substs) => { accum_substs(accumulator, substs); } - ty_closure(_, region, substs) => { - accumulator.push(*region); + ty_closure(_, substs) => { accum_substs(accumulator, substs); } ty_bool | diff --git a/src/librustc/middle/ty_fold.rs b/src/librustc/middle/ty_fold.rs index 4bf47c3a75f80..1b904aacc3012 100644 --- a/src/librustc/middle/ty_fold.rs +++ b/src/librustc/middle/ty_fold.rs @@ -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)) diff --git a/src/librustc/middle/ty_walk.rs b/src/librustc/middle/ty_walk.rs index 3336e7ee8bf71..5b5eac451783a 100644 --- a/src/librustc/middle/ty_walk.rs +++ b/src/librustc/middle/ty_walk.rs @@ -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) => { diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index 15b3c6d9d0602..0eeb746022c0d 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -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)) diff --git a/src/librustc_trans/trans/adt.rs b/src/librustc_trans/trans/adt.rs index 3ea14d3c58929..2fb0488cd704e 100644 --- a/src/librustc_trans/trans/adt.rs +++ b/src/librustc_trans/trans/adt.rs @@ -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::>(); diff --git a/src/librustc_trans/trans/base.rs b/src/librustc_trans/trans/base.rs index 1f578ac0bdbab..7a6960d379026 100644 --- a/src/librustc_trans/trans/base.rs +++ b/src/librustc_trans/trans/base.rs @@ -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 { diff --git a/src/librustc_trans/trans/closure.rs b/src/librustc_trans/trans/closure.rs index 1d4bbd79d7105..7fa26a7c12841 100644 --- a/src/librustc_trans/trans/closure.rs +++ b/src/librustc_trans/trans/closure.rs @@ -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 { diff --git a/src/librustc_trans/trans/debuginfo.rs b/src/librustc_trans/trans/debuginfo.rs index d70a904b81189..f3b7058336b2f 100644 --- a/src/librustc_trans/trans/debuginfo.rs +++ b/src/librustc_trans/trans/debuginfo.rs @@ -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) diff --git a/src/librustc_typeck/check/callee.rs b/src/librustc_typeck/check/callee.rs index 0ad15456df98f..f9495af79c5b0 100644 --- a/src/librustc_typeck/check/callee.rs +++ b/src/librustc_typeck/check/callee.rs @@ -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 diff --git a/src/librustc_typeck/check/closure.rs b/src/librustc_typeck/check/closure.rs index 0b7c5b04aaa44..0d4edc01a4c1d 100644 --- a/src/librustc_typeck/check/closure.rs +++ b/src/librustc_typeck/check/closure.rs @@ -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())); diff --git a/src/librustc_typeck/check/implicator.rs b/src/librustc_typeck/check/implicator.rs index f65e585d23edd..f99ba8940297d 100644 --- a/src/librustc_typeck/check/implicator.rs +++ b/src/librustc_typeck/check/implicator.rs @@ -29,6 +29,7 @@ use util::ppaux::Repr; pub enum Implication<'tcx> { RegionSubRegion(Option>, ty::Region, ty::Region), RegionSubGeneric(Option>, ty::Region, GenericKind<'tcx>), + RegionSubClosure(Option>, 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), diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index f24da78bc7d39..fbf002b709ee5 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -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, }; diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs index 1518a09e7dc06..a3e98b0c4c658 100644 --- a/src/librustc_typeck/check/regionck.rs +++ b/src/librustc_typeck/check/regionck.rs @@ -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, diff --git a/src/librustc_typeck/coherence/mod.rs b/src/librustc_typeck/coherence/mod.rs index 1913b55f1d8e6..58b67d31ab580 100644 --- a/src/librustc_typeck/coherence/mod.rs +++ b/src/librustc_typeck/coherence/mod.rs @@ -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()); diff --git a/src/test/compile-fail/issue-4335.rs b/src/test/compile-fail/issue-4335.rs index d0da51373d926..85298e4c6e096 100644 --- a/src/test/compile-fail/issue-4335.rs +++ b/src/test/compile-fail/issue-4335.rs @@ -14,7 +14,9 @@ fn id(t: T) -> T { t } fn f<'r, T>(v: &'r T) -> Box 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() { diff --git a/src/test/compile-fail/regions-proc-bound-capture.rs b/src/test/compile-fail/regions-proc-bound-capture.rs index 7ea4d1c7507af..cc33d11241757 100644 --- a/src/test/compile-fail/regions-proc-bound-capture.rs +++ b/src/test/compile-fail/regions-proc-bound-capture.rs @@ -18,7 +18,7 @@ fn borrowed_proc<'a>(x: &'a isize) -> Box(isize) + 'a> { fn static_proc(x: &isize) -> Box(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() { } diff --git a/src/test/compile-fail/regions-steal-closure.rs b/src/test/compile-fail/regions-steal-closure.rs index 97b51fdb32508..c9b378d1df26d 100644 --- a/src/test/compile-fail/regions-steal-closure.rs +++ b/src/test/compile-fail/regions-steal-closure.rs @@ -20,9 +20,9 @@ fn box_it<'r>(x: Box) -> 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(()); } diff --git a/src/test/compile-fail/send-is-not-static-ensures-scoping.rs b/src/test/compile-fail/send-is-not-static-ensures-scoping.rs index abbcd7e45904f..fe03ca8353d29 100755 --- a/src/test/compile-fail/send-is-not-static-ensures-scoping.rs +++ b/src/test/compile-fail/send-is-not-static-ensures-scoping.rs @@ -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; }) }; diff --git a/src/test/compile-fail/unboxed-closure-region.rs b/src/test/compile-fail/unboxed-closure-region.rs index 59c8495371852..5f4bf0d33be67 100644 --- a/src/test/compile-fail/unboxed-closure-region.rs +++ b/src/test/compile-fail/unboxed-closure-region.rs @@ -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 }; }