Skip to content

Commit e3645b5

Browse files
committed
Auto merge of #45879 - nikomatsakis:nll-kill-cyclic-closures, r=<try>
[WIP] move closure kind, signature into `ClosureSubsts` Instead of using side-tables, store the closure-kind and signature in the substitutions themselves. This has two key effects: - It means that the closure's type changes as inference finds out more things, which is very nice. - As a result, it avoids the need for the `freshen_closure_like` code (though we still use it for generators). - It avoids cyclic closures calls. - These were never meant to be supported, precisely because they make a lot of the fancy inference that we do much more complicated. However, due to an oversight, it was previously possible -- if challenging -- to create a setup where a closure *directly* called itself (see e.g. #21410). We have to see what the effect of this change is, though. Needs a crater run. Marking as [WIP] until that has been assessed. r? @arielb1
2 parents b7ccb0a + 0f6bd17 commit e3645b5

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

44 files changed

+729
-647
lines changed

src/librustc/dep_graph/dep_node.rs

-2
Original file line numberDiff line numberDiff line change
@@ -498,9 +498,7 @@ define_dep_nodes!( <'tcx>
498498
[] IsAutoImpl(DefId),
499499
[] ImplTraitRef(DefId),
500500
[] ImplPolarity(DefId),
501-
[] ClosureKind(DefId),
502501
[] FnSignature(DefId),
503-
[] GenSignature(DefId),
504502
[] CoerceUnsizedInfo(DefId),
505503

506504
[] ItemVarianceConstraints(DefId),

src/librustc/ich/impls_ty.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -236,8 +236,9 @@ impl<'gcx> HashStable<StableHashingContext<'gcx>> for ty::Predicate<'gcx> {
236236
ty::Predicate::ObjectSafe(def_id) => {
237237
def_id.hash_stable(hcx, hasher);
238238
}
239-
ty::Predicate::ClosureKind(def_id, closure_kind) => {
239+
ty::Predicate::ClosureKind(def_id, closure_substs, closure_kind) => {
240240
def_id.hash_stable(hcx, hasher);
241+
closure_substs.hash_stable(hcx, hasher);
241242
closure_kind.hash_stable(hcx, hasher);
242243
}
243244
ty::Predicate::ConstEvaluatable(def_id, substs) => {

src/librustc/infer/error_reporting/need_type_info.rs

+1-3
Original file line numberDiff line numberDiff line change
@@ -125,9 +125,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
125125
// ```
126126
labels.clear();
127127
labels.push((pattern.span, format!("consider giving this closure parameter a type")));
128-
}
129-
130-
if let Some(pattern) = local_visitor.found_local_pattern {
128+
} else if let Some(pattern) = local_visitor.found_local_pattern {
131129
if let Some(simple_name) = pattern.simple_name() {
132130
labels.push((pattern.span, format!("consider giving `{}` a type", simple_name)));
133131
} else {

src/librustc/infer/freshen.rs

+2-131
Original file line numberDiff line numberDiff line change
@@ -43,9 +43,7 @@
4343
4444
use ty::{self, Ty, TyCtxt, TypeFoldable};
4545
use ty::fold::TypeFolder;
46-
use ty::subst::Substs;
4746
use util::nodemap::FxHashMap;
48-
use hir::def_id::DefId;
4947

5048
use std::collections::hash_map::Entry;
5149

@@ -56,7 +54,6 @@ pub struct TypeFreshener<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
5654
infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
5755
freshen_count: u32,
5856
freshen_map: FxHashMap<ty::InferTy, Ty<'tcx>>,
59-
closure_set: Vec<DefId>,
6057
}
6158

6259
impl<'a, 'gcx, 'tcx> TypeFreshener<'a, 'gcx, 'tcx> {
@@ -66,7 +63,6 @@ impl<'a, 'gcx, 'tcx> TypeFreshener<'a, 'gcx, 'tcx> {
6663
infcx,
6764
freshen_count: 0,
6865
freshen_map: FxHashMap(),
69-
closure_set: vec![],
7066
}
7167
}
7268

@@ -92,88 +88,6 @@ impl<'a, 'gcx, 'tcx> TypeFreshener<'a, 'gcx, 'tcx> {
9288
}
9389
}
9490
}
95-
96-
fn next_fresh<F>(&mut self,
97-
freshener: F)
98-
-> Ty<'tcx>
99-
where F: FnOnce(u32) -> ty::InferTy,
100-
{
101-
let index = self.freshen_count;
102-
self.freshen_count += 1;
103-
self.infcx.tcx.mk_infer(freshener(index))
104-
}
105-
106-
fn freshen_closure_like<M, C>(&mut self,
107-
def_id: DefId,
108-
substs: ty::ClosureSubsts<'tcx>,
109-
t: Ty<'tcx>,
110-
markers: M,
111-
combine: C)
112-
-> Ty<'tcx>
113-
where M: FnOnce(&mut Self) -> (Ty<'tcx>, Ty<'tcx>),
114-
C: FnOnce(&'tcx Substs<'tcx>) -> Ty<'tcx>
115-
{
116-
let tcx = self.infcx.tcx;
117-
118-
let closure_in_progress = self.infcx.in_progress_tables.map_or(false, |tables| {
119-
tcx.hir.as_local_node_id(def_id).map_or(false, |closure_id| {
120-
tables.borrow().local_id_root ==
121-
Some(DefId::local(tcx.hir.node_to_hir_id(closure_id).owner))
122-
})
123-
});
124-
125-
if !closure_in_progress {
126-
// If this closure belongs to another infcx, its kind etc. were
127-
// fully inferred and its signature/kind are exactly what's listed
128-
// in its infcx. So we don't need to add the markers for them.
129-
return t.super_fold_with(self);
130-
}
131-
132-
// We are encoding a closure in progress. Because we want our freshening
133-
// key to contain all inference information needed to make sense of our
134-
// value, we need to encode the closure signature and kind. The way
135-
// we do that is to add them as 2 variables to the closure substs,
136-
// basically because it's there (and nobody cares about adding extra stuff
137-
// to substs).
138-
//
139-
// This means the "freshened" closure substs ends up looking like
140-
// fresh_substs = [PARENT_SUBSTS* ; UPVARS* ; SIG_MARKER ; KIND_MARKER]
141-
let (marker_1, marker_2) = if self.closure_set.contains(&def_id) {
142-
// We found the closure def-id within its own signature. Just
143-
// leave a new freshened type - any matching operations would
144-
// have found and compared the exterior closure already to
145-
// get here.
146-
//
147-
// In that case, we already know what the signature would
148-
// be - the parent closure on the stack already contains a
149-
// "copy" of the signature, so there is no reason to encode
150-
// it again for injectivity. Just use a fresh type variable
151-
// to make everything comparable.
152-
//
153-
// For example (closure kinds omitted for clarity)
154-
// t=[closure FOO sig=[closure BAR sig=[closure FOO ..]]]
155-
// Would get encoded to
156-
// t=[closure FOO sig=[closure BAR sig=[closure FOO sig=$0]]]
157-
//
158-
// and we can decode by having
159-
// $0=[closure BAR {sig doesn't exist in decode}]
160-
// and get
161-
// t=[closure FOO]
162-
// sig[FOO] = [closure BAR]
163-
// sig[BAR] = [closure FOO]
164-
(self.next_fresh(ty::FreshTy), self.next_fresh(ty::FreshTy))
165-
} else {
166-
self.closure_set.push(def_id);
167-
let markers = markers(self);
168-
self.closure_set.pop();
169-
markers
170-
};
171-
172-
combine(tcx.mk_substs(
173-
substs.substs.iter().map(|k| k.fold_with(self)).chain(
174-
[marker_1, marker_2].iter().cloned().map(From::from)
175-
)))
176-
}
17791
}
17892

17993
impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for TypeFreshener<'a, 'gcx, 'tcx> {
@@ -249,51 +163,7 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for TypeFreshener<'a, 'gcx, 'tcx> {
249163
t
250164
}
251165

252-
ty::TyClosure(def_id, substs) => {
253-
self.freshen_closure_like(
254-
def_id, substs, t,
255-
|this| {
256-
// HACK: use a "random" integer type to mark the kind. Because
257-
// different closure kinds shouldn't get unified during
258-
// selection, the "subtyping" relationship (where any kind is
259-
// better than no kind) shouldn't matter here, just that the
260-
// types are different.
261-
let closure_kind = this.infcx.closure_kind(def_id);
262-
let closure_kind_marker = match closure_kind {
263-
None => tcx.types.i8,
264-
Some(ty::ClosureKind::Fn) => tcx.types.i16,
265-
Some(ty::ClosureKind::FnMut) => tcx.types.i32,
266-
Some(ty::ClosureKind::FnOnce) => tcx.types.i64,
267-
};
268-
269-
let closure_sig = this.infcx.fn_sig(def_id);
270-
(tcx.mk_fn_ptr(closure_sig.fold_with(this)),
271-
closure_kind_marker)
272-
},
273-
|substs| tcx.mk_closure(def_id, substs)
274-
)
275-
}
276-
277-
ty::TyGenerator(def_id, substs, interior) => {
278-
self.freshen_closure_like(
279-
def_id, substs, t,
280-
|this| {
281-
let gen_sig = this.infcx.generator_sig(def_id).unwrap();
282-
// FIXME: want to revise this strategy when generator
283-
// signatures can actually contain LBRs.
284-
let sig = this.tcx().no_late_bound_regions(&gen_sig)
285-
.unwrap_or_else(|| {
286-
bug!("late-bound regions in signature of {:?}",
287-
def_id)
288-
});
289-
(sig.yield_ty, sig.return_ty).fold_with(this)
290-
},
291-
|substs| {
292-
tcx.mk_generator(def_id, ty::ClosureSubsts { substs }, interior)
293-
}
294-
)
295-
}
296-
166+
ty::TyGenerator(..) |
297167
ty::TyBool |
298168
ty::TyChar |
299169
ty::TyInt(..) |
@@ -314,6 +184,7 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for TypeFreshener<'a, 'gcx, 'tcx> {
314184
ty::TyProjection(..) |
315185
ty::TyForeign(..) |
316186
ty::TyParam(..) |
187+
ty::TyClosure(..) |
317188
ty::TyAnon(..) => {
318189
t.super_fold_with(self)
319190
}

src/librustc/infer/mod.rs

+19-33
Original file line numberDiff line numberDiff line change
@@ -1338,26 +1338,17 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
13381338
!traits::type_known_to_meet_bound(self, param_env, ty, copy_def_id, span)
13391339
}
13401340

1341+
/// Obtains the latest type of the given closure; this may be a
1342+
/// closure in the current function, in which case its
1343+
/// `ClosureKind` may not yet be known.
13411344
pub fn closure_kind(&self,
1342-
def_id: DefId)
1345+
closure_def_id: DefId,
1346+
closure_substs: ty::ClosureSubsts<'tcx>)
13431347
-> Option<ty::ClosureKind>
13441348
{
1345-
if let Some(tables) = self.in_progress_tables {
1346-
if let Some(id) = self.tcx.hir.as_local_node_id(def_id) {
1347-
let hir_id = self.tcx.hir.node_to_hir_id(id);
1348-
return tables.borrow()
1349-
.closure_kinds()
1350-
.get(hir_id)
1351-
.cloned()
1352-
.map(|(kind, _)| kind);
1353-
}
1354-
}
1355-
1356-
// During typeck, ALL closures are local. But afterwards,
1357-
// during trans, we see closure ids from other traits.
1358-
// That may require loading the closure data out of the
1359-
// cstore.
1360-
Some(self.tcx.closure_kind(def_id))
1349+
let closure_kind_ty = closure_substs.closure_kind_ty(closure_def_id, self.tcx);
1350+
let closure_kind_ty = self.shallow_resolve(&closure_kind_ty);
1351+
closure_kind_ty.to_opt_closure_kind()
13611352
}
13621353

13631354
/// Obtain the signature of a function or closure.
@@ -1368,27 +1359,22 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
13681359
if let Some(tables) = self.in_progress_tables {
13691360
if let Some(id) = self.tcx.hir.as_local_node_id(def_id) {
13701361
let hir_id = self.tcx.hir.node_to_hir_id(id);
1371-
if let Some(&ty) = tables.borrow().closure_tys().get(hir_id) {
1372-
return ty;
1373-
}
1362+
let closure_ty = tables.borrow().node_id_to_type(hir_id);
1363+
let (closure_def_id, closure_substs) = match closure_ty.sty {
1364+
ty::TyClosure(closure_def_id, closure_substs) =>
1365+
(closure_def_id, closure_substs),
1366+
_ =>
1367+
bug!("closure with non-closure type: {:?}", closure_ty),
1368+
};
1369+
assert_eq!(def_id, closure_def_id);
1370+
let closure_sig_ty = closure_substs.closure_sig_ty(def_id, self.tcx);
1371+
let closure_sig_ty = self.shallow_resolve(&closure_sig_ty);
1372+
return closure_sig_ty.fn_sig(self.tcx);
13741373
}
13751374
}
13761375

13771376
self.tcx.fn_sig(def_id)
13781377
}
1379-
1380-
pub fn generator_sig(&self, def_id: DefId) -> Option<ty::PolyGenSig<'tcx>> {
1381-
if let Some(tables) = self.in_progress_tables {
1382-
if let Some(id) = self.tcx.hir.as_local_node_id(def_id) {
1383-
let hir_id = self.tcx.hir.node_to_hir_id(id);
1384-
if let Some(&ty) = tables.borrow().generator_sigs().get(hir_id) {
1385-
return ty.map(|t| ty::Binder(t));
1386-
}
1387-
}
1388-
}
1389-
1390-
self.tcx.generator_sig(def_id)
1391-
}
13921378
}
13931379

13941380
impl<'a, 'gcx, 'tcx> TypeTrace<'tcx> {

src/librustc/infer/type_variable.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,10 @@ pub enum TypeVariableOrigin {
5656
NormalizeProjectionType(Span),
5757
TypeInference(Span),
5858
TypeParameterDefinition(Span, ast::Name),
59-
TransformedUpvar(Span),
59+
60+
/// one of the upvars or closure kind parameters in a `ClosureSubsts`
61+
/// (before it has been determined)
62+
ClosureSynthetic(Span),
6063
SubstitutionPlaceholder(Span),
6164
AutoDeref(Span),
6265
AdjustmentType(Span),

src/librustc/lib.rs

+2
Original file line numberDiff line numberDiff line change
@@ -49,13 +49,15 @@
4949
#![feature(inclusive_range_syntax)]
5050
#![cfg_attr(windows, feature(libc))]
5151
#![feature(macro_vis_matcher)]
52+
#![feature(match_default_bindings)]
5253
#![feature(never_type)]
5354
#![feature(nonzero)]
5455
#![feature(quote)]
5556
#![feature(rustc_diagnostic_macros)]
5657
#![feature(slice_patterns)]
5758
#![feature(specialization)]
5859
#![feature(unboxed_closures)]
60+
#![feature(underscore_lifetimes)]
5961
#![feature(trace_macros)]
6062
#![feature(test)]
6163
#![feature(const_atomic_bool_new)]

src/librustc/middle/mem_categorization.rs

+13-4
Original file line numberDiff line numberDiff line change
@@ -750,10 +750,19 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
750750

751751
let kind = match self.node_ty(fn_hir_id)?.sty {
752752
ty::TyGenerator(..) => ty::ClosureKind::FnOnce,
753-
ty::TyClosure(..) => {
754-
match self.tables.closure_kinds().get(fn_hir_id) {
755-
Some(&(kind, _)) => kind,
756-
None => span_bug!(span, "missing closure kind"),
753+
ty::TyClosure(closure_def_id, closure_substs) => {
754+
match self.infcx {
755+
// During upvar inference we may not know the
756+
// closure kind, just use the LATTICE_BOTTOM value.
757+
Some(infcx) =>
758+
infcx.closure_kind(closure_def_id, closure_substs)
759+
.unwrap_or(ty::ClosureKind::LATTICE_BOTTOM),
760+
761+
None =>
762+
self.tcx.global_tcx()
763+
.lift(&closure_substs)
764+
.expect("no inference cx, but inference variables in closure ty")
765+
.closure_kind(closure_def_id, self.tcx.global_tcx()),
757766
}
758767
}
759768
ref t => span_bug!(span, "unexpected type for fn in mem_categorization: {:?}", t),

src/librustc/traits/error_reporting.rs

+7-7
Original file line numberDiff line numberDiff line change
@@ -661,8 +661,8 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
661661
violations)
662662
}
663663

664-
ty::Predicate::ClosureKind(closure_def_id, kind) => {
665-
let found_kind = self.closure_kind(closure_def_id).unwrap();
664+
ty::Predicate::ClosureKind(closure_def_id, closure_substs, kind) => {
665+
let found_kind = self.closure_kind(closure_def_id, closure_substs).unwrap();
666666
let closure_span = self.tcx.hir.span_if_local(closure_def_id).unwrap();
667667
let node_id = self.tcx.hir.as_local_node_id(closure_def_id).unwrap();
668668
let mut err = struct_span_err!(
@@ -681,14 +681,14 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
681681
if let Some(tables) = self.in_progress_tables {
682682
let tables = tables.borrow();
683683
let closure_hir_id = self.tcx.hir.node_to_hir_id(node_id);
684-
match tables.closure_kinds().get(closure_hir_id) {
685-
Some(&(ty::ClosureKind::FnOnce, Some((span, name)))) => {
686-
err.span_note(span, &format!(
684+
match (found_kind, tables.closure_kind_origins().get(closure_hir_id)) {
685+
(ty::ClosureKind::FnOnce, Some((span, name))) => {
686+
err.span_note(*span, &format!(
687687
"closure is `FnOnce` because it moves the \
688688
variable `{}` out of its environment", name));
689689
},
690-
Some(&(ty::ClosureKind::FnMut, Some((span, name)))) => {
691-
err.span_note(span, &format!(
690+
(ty::ClosureKind::FnMut, Some((span, name))) => {
691+
err.span_note(*span, &format!(
692692
"closure is `FnMut` because it mutates the \
693693
variable `{}` here", name));
694694
},

src/librustc/traits/fulfill.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -491,8 +491,8 @@ fn process_predicate<'a, 'gcx, 'tcx>(
491491
}
492492
}
493493

494-
ty::Predicate::ClosureKind(closure_def_id, kind) => {
495-
match selcx.infcx().closure_kind(closure_def_id) {
494+
ty::Predicate::ClosureKind(closure_def_id, closure_substs, kind) => {
495+
match selcx.infcx().closure_kind(closure_def_id, closure_substs) {
496496
Some(closure_kind) => {
497497
if closure_kind.extends(kind) {
498498
Ok(Some(vec![]))

src/librustc/traits/project.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -1264,8 +1264,7 @@ fn confirm_generator_candidate<'cx, 'gcx, 'tcx>(
12641264
vtable: VtableGeneratorData<'tcx, PredicateObligation<'tcx>>)
12651265
-> Progress<'tcx>
12661266
{
1267-
let gen_sig = selcx.infcx().generator_sig(vtable.closure_def_id).unwrap()
1268-
.subst(selcx.tcx(), vtable.substs.substs);
1267+
let gen_sig = vtable.substs.generator_poly_sig(vtable.closure_def_id, selcx.tcx());
12691268
let Normalized {
12701269
value: gen_sig,
12711270
obligations

0 commit comments

Comments
 (0)