Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor how closures are represented to expose the types of the upvars #27087

Merged
merged 10 commits into from
Jul 24, 2015
7 changes: 6 additions & 1 deletion src/librustc/metadata/tydecode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -564,8 +564,13 @@ fn parse_ty_<'a, 'tcx, F>(st: &mut PState<'a, 'tcx>, conv: &mut F) -> Ty<'tcx> w
assert_eq!(next(st), '[');
let did = parse_def_(st, ClosureSource, conv);
let substs = parse_substs_(st, conv);
let mut tys = vec![];
while peek(st) != '.' {
tys.push(parse_ty_(st, conv));
}
assert_eq!(next(st), '.');
assert_eq!(next(st), ']');
return st.tcx.mk_closure(did, st.tcx.mk_substs(substs));
return st.tcx.mk_closure(did, st.tcx.mk_substs(substs), tys);
}
'P' => {
assert_eq!(next(st), '[');
Expand Down
8 changes: 6 additions & 2 deletions src/librustc/metadata/tyencode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -143,9 +143,13 @@ pub fn enc_ty<'a, 'tcx>(w: &mut Encoder, cx: &ctxt<'a, 'tcx>, t: Ty<'tcx>) {
enc_substs(w, cx, substs);
mywrite!(w, "]");
}
ty::TyClosure(def, substs) => {
ty::TyClosure(def, ref substs) => {
mywrite!(w, "k[{}|", (cx.ds)(def));
enc_substs(w, cx, substs);
enc_substs(w, cx, &substs.func_substs);
for ty in &substs.upvar_tys {
enc_ty(w, cx, ty);
}
mywrite!(w, ".");
mywrite!(w, "]");
}
ty::TyProjection(ref data) => {
Expand Down
5 changes: 4 additions & 1 deletion src/librustc/middle/expr_use_visitor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -256,7 +256,10 @@ macro_rules! return_if_err {
($inp: expr) => (
match $inp {
Ok(v) => v,
Err(()) => return
Err(()) => {
debug!("mc reported err");
return
}
}
)
}
Expand Down
1 change: 0 additions & 1 deletion src/librustc/middle/free_region.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@ impl FreeRegionMap {
self.relate_free_regions(free_a, free_b);
}
Implication::RegionSubRegion(..) |
Implication::RegionSubClosure(..) |
Implication::RegionSubGeneric(..) |
Implication::Predicate(..) => {
}
Expand Down
60 changes: 56 additions & 4 deletions src/librustc/middle/implicator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@ use util::nodemap::FnvHashSet;
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 @@ -96,9 +95,47 @@ impl<'a, 'tcx> Implicator<'a, 'tcx> {
// No borrowed content reachable here.
}

ty::TyClosure(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::TyClosure(_, ref substs) => {
// FIXME(#27086). We do not accumulate from substs, since they
// don't represent reachable data. This means that, in
// practice, some of the lifetime parameters might not
// be in scope when the body runs, so long as there is
// no reachable data with that lifetime. For better or
// worse, this is consistent with fn types, however,
// which can also encapsulate data in this fashion
// (though it's somewhat harder, and typically
// requires virtual dispatch).
//
// Note that changing this (in a naive way, at least)
// causes regressions for what appears to be perfectly
// reasonable code like this:
//
// ```
// fn foo<'a>(p: &Data<'a>) {
// bar(|q: &mut Parser| q.read_addr())
// }
// fn bar(p: Box<FnMut(&mut Parser)+'static>) {
// }
// ```
//
// Note that `p` (and `'a`) are not used in the
// closure at all, but to meet the requirement that
// the closure type `C: 'static` (so it can be coerced
// to the object type), we get the requirement that
// `'a: 'static` since `'a` appears in the closure
// type `C`.
//
// A smarter fix might "prune" unused `func_substs` --
// this would avoid breaking simple examples like
// this, but would still break others (which might
// indeed be invalid, depending on your POV). Pruning
// would be a subtle process, since we have to see
// what func/type parameters are used and unused,
// taking into consideration UFCS and so forth.

for &upvar_ty in &substs.upvar_tys {
self.accumulate_from_ty(upvar_ty);
}
}

ty::TyTrait(ref t) => {
Expand Down Expand Up @@ -273,6 +310,21 @@ impl<'a, 'tcx> Implicator<'a, 'tcx> {
self.out.extend(obligations);

let variances = self.tcx().item_variances(def_id);
self.accumulate_from_substs(substs, Some(&variances));
}

fn accumulate_from_substs(&mut self,
substs: &Substs<'tcx>,
variances: Option<&ty::ItemVariances>)
{
let mut tmp_variances = None;
let variances = variances.unwrap_or_else(|| {
tmp_variances = Some(ty::ItemVariances {
types: substs.types.map(|_| ty::Variance::Invariant),
regions: substs.regions().map(|_| ty::Variance::Invariant),
});
tmp_variances.as_ref().unwrap()
});

for (&region, &variance) in substs.regions().iter().zip(&variances.regions) {
match variance {
Expand Down
30 changes: 10 additions & 20 deletions src/librustc/middle/infer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1162,7 +1162,12 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
/// these unconstrained type variables.
fn resolve_type_vars_or_error(&self, t: &Ty<'tcx>) -> mc::McResult<Ty<'tcx>> {
let ty = self.resolve_type_vars_if_possible(t);
if ty.has_infer_types() || ty.references_error() { Err(()) } else { Ok(ty) }
if ty.references_error() || ty.is_ty_var() {
debug!("resolve_type_vars_or_error: error from {:?}", ty);
Err(())
} else {
Ok(ty)
}
}

pub fn fully_resolve<T:TypeFoldable<'tcx>>(&self, value: &T) -> FixupResult<T> {
Expand Down Expand Up @@ -1374,38 +1379,23 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
}

pub fn closure_type(&self,
def_id: ast::DefId,
substs: &subst::Substs<'tcx>)
-> ty::ClosureTy<'tcx>
def_id: ast::DefId,
substs: &ty::ClosureSubsts<'tcx>)
-> ty::ClosureTy<'tcx>
{

let closure_ty = self.tables
.borrow()
.closure_tys
.get(&def_id)
.unwrap()
.subst(self.tcx, substs);
.subst(self.tcx, &substs.func_substs);

if self.normalize {
normalize_associated_type(&self.tcx, &closure_ty)
} else {
closure_ty
}
}

pub fn closure_upvars(&self,
def_id: ast::DefId,
substs: &Substs<'tcx>)
-> Option<Vec<ty::ClosureUpvar<'tcx>>>
{
let result = ty::ctxt::closure_upvars(self, def_id, substs);

if self.normalize {
normalize_associated_type(&self.tcx, &result)
} else {
result
}
}
}

impl<'tcx> TypeTrace<'tcx> {
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 @@ -1493,7 +1493,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
fn fn_ret(&self, id: NodeId) -> ty::PolyFnOutput<'tcx> {
let fn_ty = self.ir.tcx.node_id_to_type(id);
match fn_ty.sty {
ty::TyClosure(closure_def_id, substs) =>
ty::TyClosure(closure_def_id, ref substs) =>
self.ir.tcx.closure_type(closure_def_id, substs).sig.output(),
_ => fn_ty.fn_ret()
}
Expand Down
8 changes: 7 additions & 1 deletion src/librustc/middle/mem_categorization.rs
Original file line number Diff line number Diff line change
Expand Up @@ -367,7 +367,13 @@ impl<'t, 'a,'tcx> MemCategorizationContext<'t, 'a, 'tcx> {
}

fn expr_ty(&self, expr: &ast::Expr) -> McResult<Ty<'tcx>> {
self.typer.node_ty(expr.id)
match self.typer.node_ty(expr.id) {
Ok(t) => Ok(t),
Err(()) => {
debug!("expr_ty({:?}) yielded Err", expr);
Err(())
}
}
}

fn expr_ty_adjusted(&self, expr: &ast::Expr) -> McResult<Ty<'tcx>> {
Expand Down
4 changes: 2 additions & 2 deletions src/librustc/middle/traits/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -270,7 +270,7 @@ pub struct VtableImplData<'tcx, N> {
#[derive(Clone, PartialEq, Eq)]
pub struct VtableClosureData<'tcx, N> {
pub closure_def_id: ast::DefId,
pub substs: subst::Substs<'tcx>,
pub substs: ty::ClosureSubsts<'tcx>,
/// Nested obligations. This can be non-empty if the closure
/// signature contains associated types.
pub nested: Vec<N>
Expand Down Expand Up @@ -548,7 +548,7 @@ impl<'tcx, N> Vtable<'tcx, N> {
VtableClosure(c) => VtableClosure(VtableClosureData {
closure_def_id: c.closure_def_id,
substs: c.substs,
nested: c.nested.into_iter().map(f).collect()
nested: c.nested.into_iter().map(f).collect(),
})
}
}
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::TyClosure(closure_def_id, substs) => {
ty::TyClosure(closure_def_id, ref 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
Loading