Skip to content

Commit 5e6b534

Browse files
committed
Auto merge of #27087 - nikomatsakis:closure-exploration, r=nrc
Refactors the "desugaring" of closures to expose the types of the upvars. This is necessary to be faithful with how actual structs work. The reasoning of the particular desugaring that I chose is explained in a fairly detailed comment. As a side-effect, recursive closure types are prohibited unless a trait object intermediary is used. This fixes #25954 and also eliminates concerns about unrepresentable closure types that have infinite size, I believe. I don't believe this can cause regressions because of #25954. (As for motivation, besides #25954 etc, this work is also intended as refactoring in support of incremental compilation, since closures are one of the thornier cases encountered when attempting to split node-ids into item-ids and within-item-ids. The goal is to eliminate the "internal def-id" distinction in astdecoding. However, I have to do more work on trans to really make progress there.) r? @nrc
2 parents 0fb8ab0 + 71d4418 commit 5e6b534

35 files changed

+539
-374
lines changed

src/librustc/metadata/tydecode.rs

+6-1
Original file line numberDiff line numberDiff line change
@@ -564,8 +564,13 @@ fn parse_ty_<'a, 'tcx, F>(st: &mut PState<'a, 'tcx>, conv: &mut F) -> Ty<'tcx> w
564564
assert_eq!(next(st), '[');
565565
let did = parse_def_(st, ClosureSource, conv);
566566
let substs = parse_substs_(st, conv);
567+
let mut tys = vec![];
568+
while peek(st) != '.' {
569+
tys.push(parse_ty_(st, conv));
570+
}
571+
assert_eq!(next(st), '.');
567572
assert_eq!(next(st), ']');
568-
return st.tcx.mk_closure(did, st.tcx.mk_substs(substs));
573+
return st.tcx.mk_closure(did, st.tcx.mk_substs(substs), tys);
569574
}
570575
'P' => {
571576
assert_eq!(next(st), '[');

src/librustc/metadata/tyencode.rs

+6-2
Original file line numberDiff line numberDiff line change
@@ -143,9 +143,13 @@ pub fn enc_ty<'a, 'tcx>(w: &mut Encoder, cx: &ctxt<'a, 'tcx>, t: Ty<'tcx>) {
143143
enc_substs(w, cx, substs);
144144
mywrite!(w, "]");
145145
}
146-
ty::TyClosure(def, substs) => {
146+
ty::TyClosure(def, ref substs) => {
147147
mywrite!(w, "k[{}|", (cx.ds)(def));
148-
enc_substs(w, cx, substs);
148+
enc_substs(w, cx, &substs.func_substs);
149+
for ty in &substs.upvar_tys {
150+
enc_ty(w, cx, ty);
151+
}
152+
mywrite!(w, ".");
149153
mywrite!(w, "]");
150154
}
151155
ty::TyProjection(ref data) => {

src/librustc/middle/expr_use_visitor.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -256,7 +256,10 @@ macro_rules! return_if_err {
256256
($inp: expr) => (
257257
match $inp {
258258
Ok(v) => v,
259-
Err(()) => return
259+
Err(()) => {
260+
debug!("mc reported err");
261+
return
262+
}
260263
}
261264
)
262265
}

src/librustc/middle/free_region.rs

-1
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,6 @@ impl FreeRegionMap {
4040
self.relate_free_regions(free_a, free_b);
4141
}
4242
Implication::RegionSubRegion(..) |
43-
Implication::RegionSubClosure(..) |
4443
Implication::RegionSubGeneric(..) |
4544
Implication::Predicate(..) => {
4645
}

src/librustc/middle/implicator.rs

+56-4
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@ use util::nodemap::FnvHashSet;
2828
pub enum Implication<'tcx> {
2929
RegionSubRegion(Option<Ty<'tcx>>, ty::Region, ty::Region),
3030
RegionSubGeneric(Option<Ty<'tcx>>, ty::Region, GenericKind<'tcx>),
31-
RegionSubClosure(Option<Ty<'tcx>>, ty::Region, ast::DefId, &'tcx Substs<'tcx>),
3231
Predicate(ast::DefId, ty::Predicate<'tcx>),
3332
}
3433

@@ -96,9 +95,47 @@ impl<'a, 'tcx> Implicator<'a, 'tcx> {
9695
// No borrowed content reachable here.
9796
}
9897

99-
ty::TyClosure(def_id, substs) => {
100-
let &(r_a, opt_ty) = self.stack.last().unwrap();
101-
self.out.push(Implication::RegionSubClosure(opt_ty, r_a, def_id, substs));
98+
ty::TyClosure(_, ref substs) => {
99+
// FIXME(#27086). We do not accumulate from substs, since they
100+
// don't represent reachable data. This means that, in
101+
// practice, some of the lifetime parameters might not
102+
// be in scope when the body runs, so long as there is
103+
// no reachable data with that lifetime. For better or
104+
// worse, this is consistent with fn types, however,
105+
// which can also encapsulate data in this fashion
106+
// (though it's somewhat harder, and typically
107+
// requires virtual dispatch).
108+
//
109+
// Note that changing this (in a naive way, at least)
110+
// causes regressions for what appears to be perfectly
111+
// reasonable code like this:
112+
//
113+
// ```
114+
// fn foo<'a>(p: &Data<'a>) {
115+
// bar(|q: &mut Parser| q.read_addr())
116+
// }
117+
// fn bar(p: Box<FnMut(&mut Parser)+'static>) {
118+
// }
119+
// ```
120+
//
121+
// Note that `p` (and `'a`) are not used in the
122+
// closure at all, but to meet the requirement that
123+
// the closure type `C: 'static` (so it can be coerced
124+
// to the object type), we get the requirement that
125+
// `'a: 'static` since `'a` appears in the closure
126+
// type `C`.
127+
//
128+
// A smarter fix might "prune" unused `func_substs` --
129+
// this would avoid breaking simple examples like
130+
// this, but would still break others (which might
131+
// indeed be invalid, depending on your POV). Pruning
132+
// would be a subtle process, since we have to see
133+
// what func/type parameters are used and unused,
134+
// taking into consideration UFCS and so forth.
135+
136+
for &upvar_ty in &substs.upvar_tys {
137+
self.accumulate_from_ty(upvar_ty);
138+
}
102139
}
103140

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

275312
let variances = self.tcx().item_variances(def_id);
313+
self.accumulate_from_substs(substs, Some(&variances));
314+
}
315+
316+
fn accumulate_from_substs(&mut self,
317+
substs: &Substs<'tcx>,
318+
variances: Option<&ty::ItemVariances>)
319+
{
320+
let mut tmp_variances = None;
321+
let variances = variances.unwrap_or_else(|| {
322+
tmp_variances = Some(ty::ItemVariances {
323+
types: substs.types.map(|_| ty::Variance::Invariant),
324+
regions: substs.regions().map(|_| ty::Variance::Invariant),
325+
});
326+
tmp_variances.as_ref().unwrap()
327+
});
276328

277329
for (&region, &variance) in substs.regions().iter().zip(&variances.regions) {
278330
match variance {

src/librustc/middle/infer/mod.rs

+10-20
Original file line numberDiff line numberDiff line change
@@ -1162,7 +1162,12 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
11621162
/// these unconstrained type variables.
11631163
fn resolve_type_vars_or_error(&self, t: &Ty<'tcx>) -> mc::McResult<Ty<'tcx>> {
11641164
let ty = self.resolve_type_vars_if_possible(t);
1165-
if ty.has_infer_types() || ty.references_error() { Err(()) } else { Ok(ty) }
1165+
if ty.references_error() || ty.is_ty_var() {
1166+
debug!("resolve_type_vars_or_error: error from {:?}", ty);
1167+
Err(())
1168+
} else {
1169+
Ok(ty)
1170+
}
11661171
}
11671172

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

13761381
pub fn closure_type(&self,
1377-
def_id: ast::DefId,
1378-
substs: &subst::Substs<'tcx>)
1379-
-> ty::ClosureTy<'tcx>
1382+
def_id: ast::DefId,
1383+
substs: &ty::ClosureSubsts<'tcx>)
1384+
-> ty::ClosureTy<'tcx>
13801385
{
1381-
13821386
let closure_ty = self.tables
13831387
.borrow()
13841388
.closure_tys
13851389
.get(&def_id)
13861390
.unwrap()
1387-
.subst(self.tcx, substs);
1391+
.subst(self.tcx, &substs.func_substs);
13881392

13891393
if self.normalize {
13901394
normalize_associated_type(&self.tcx, &closure_ty)
13911395
} else {
13921396
closure_ty
13931397
}
13941398
}
1395-
1396-
pub fn closure_upvars(&self,
1397-
def_id: ast::DefId,
1398-
substs: &Substs<'tcx>)
1399-
-> Option<Vec<ty::ClosureUpvar<'tcx>>>
1400-
{
1401-
let result = ty::ctxt::closure_upvars(self, def_id, substs);
1402-
1403-
if self.normalize {
1404-
normalize_associated_type(&self.tcx, &result)
1405-
} else {
1406-
result
1407-
}
1408-
}
14091399
}
14101400

14111401
impl<'tcx> TypeTrace<'tcx> {

src/librustc/middle/liveness.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1493,7 +1493,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
14931493
fn fn_ret(&self, id: NodeId) -> ty::PolyFnOutput<'tcx> {
14941494
let fn_ty = self.ir.tcx.node_id_to_type(id);
14951495
match fn_ty.sty {
1496-
ty::TyClosure(closure_def_id, substs) =>
1496+
ty::TyClosure(closure_def_id, ref substs) =>
14971497
self.ir.tcx.closure_type(closure_def_id, substs).sig.output(),
14981498
_ => fn_ty.fn_ret()
14991499
}

src/librustc/middle/mem_categorization.rs

+7-1
Original file line numberDiff line numberDiff line change
@@ -367,7 +367,13 @@ impl<'t, 'a,'tcx> MemCategorizationContext<'t, 'a, 'tcx> {
367367
}
368368

369369
fn expr_ty(&self, expr: &ast::Expr) -> McResult<Ty<'tcx>> {
370-
self.typer.node_ty(expr.id)
370+
match self.typer.node_ty(expr.id) {
371+
Ok(t) => Ok(t),
372+
Err(()) => {
373+
debug!("expr_ty({:?}) yielded Err", expr);
374+
Err(())
375+
}
376+
}
371377
}
372378

373379
fn expr_ty_adjusted(&self, expr: &ast::Expr) -> McResult<Ty<'tcx>> {

src/librustc/middle/traits/mod.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -270,7 +270,7 @@ pub struct VtableImplData<'tcx, N> {
270270
#[derive(Clone, PartialEq, Eq)]
271271
pub struct VtableClosureData<'tcx, N> {
272272
pub closure_def_id: ast::DefId,
273-
pub substs: subst::Substs<'tcx>,
273+
pub substs: ty::ClosureSubsts<'tcx>,
274274
/// Nested obligations. This can be non-empty if the closure
275275
/// signature contains associated types.
276276
pub nested: Vec<N>
@@ -548,7 +548,7 @@ impl<'tcx, N> Vtable<'tcx, N> {
548548
VtableClosure(c) => VtableClosure(VtableClosureData {
549549
closure_def_id: c.closure_def_id,
550550
substs: c.substs,
551-
nested: c.nested.into_iter().map(f).collect()
551+
nested: c.nested.into_iter().map(f).collect(),
552552
})
553553
}
554554
}

src/librustc/middle/traits/project.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,7 @@ fn consider_unification_despite_ambiguity<'cx,'tcx>(selcx: &mut SelectionContext
154154
debug!("consider_unification_despite_ambiguity: self_ty.sty={:?}",
155155
self_ty.sty);
156156
match self_ty.sty {
157-
ty::TyClosure(closure_def_id, substs) => {
157+
ty::TyClosure(closure_def_id, ref substs) => {
158158
let closure_typer = selcx.closure_typer();
159159
let closure_type = closure_typer.closure_type(closure_def_id, substs);
160160
let ty::Binder((_, ret_type)) =

0 commit comments

Comments
 (0)