Skip to content

Commit

Permalink
Rollup merge of rust-lang#22966 - nikomatsakis:closure-region-hierarc…
Browse files Browse the repository at this point in the history
…hy, r=pnkfelix

 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 is refactoring towards rust-lang#3696.

r? @pnkfelix
  • Loading branch information
Manishearth committed Mar 2, 2015
2 parents f608afe + 00fcf79 commit c4b1500
Show file tree
Hide file tree
Showing 28 changed files with 93 additions and 230 deletions.
4 changes: 1 addition & 3 deletions src/librustc/metadata/tydecode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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), '[');
Expand Down
3 changes: 1 addition & 2 deletions src/librustc/metadata/tyencode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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, "]");
}
Expand Down
2 changes: 1 addition & 1 deletion src/librustc/middle/fast_reject.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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) => {
Expand Down
7 changes: 3 additions & 4 deletions src/librustc/middle/infer/combine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)) => {
Expand Down
2 changes: 1 addition & 1 deletion src/librustc/middle/liveness.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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),
Expand Down
2 changes: 1 addition & 1 deletion src/librustc/middle/mem_categorization.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
2 changes: 2 additions & 0 deletions src/librustc/middle/region.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
}

Expand Down
2 changes: 1 addition & 1 deletion src/librustc/middle/traits/project.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)) =
Expand Down
8 changes: 4 additions & 4 deletions src/librustc/middle/traits/select.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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());
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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) {
Expand Down
24 changes: 9 additions & 15 deletions src/librustc/middle/ty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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>>),

Expand Down Expand Up @@ -2658,8 +2658,7 @@ impl FlagComputation {
}
}

&ty_closure(_, region, substs) => {
self.add_region(*region);
&ty_closure(_, substs) => {
self.add_substs(substs);
}

Expand Down Expand Up @@ -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> {
Expand Down Expand Up @@ -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) => {
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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 |
Expand Down
5 changes: 2 additions & 3 deletions src/librustc/middle/ty_fold.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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))
Expand Down
2 changes: 1 addition & 1 deletion src/librustc/middle/ty_walk.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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) => {
Expand Down
2 changes: 1 addition & 1 deletion src/librustc/util/ppaux.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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))
Expand Down
2 changes: 1 addition & 1 deletion src/librustc_trans/trans/adt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<_>>();
Expand Down
8 changes: 4 additions & 4 deletions src/librustc_trans/trans/base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -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);
Expand All @@ -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 {
Expand Down
2 changes: 1 addition & 1 deletion src/librustc_trans/trans/closure.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
4 changes: 2 additions & 2 deletions src/librustc_trans/trans/debuginfo.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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)
Expand Down
2 changes: 1 addition & 1 deletion src/librustc_typeck/check/callee.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
10 changes: 0 additions & 10 deletions src/librustc_typeck/check/closure.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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()));

Expand Down
34 changes: 11 additions & 23 deletions src/librustc_typeck/check/implicator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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>),
}

Expand Down Expand Up @@ -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) => {
Expand Down Expand Up @@ -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),
Expand Down
Loading

0 comments on commit c4b1500

Please sign in to comment.