Skip to content

Commit 0ab8d5d

Browse files
committed
Auto merge of #21805 - nikomatsakis:closure-inference-refactor-1, r=eddyb
Currently, we only infer the kind of a closure based on the expected type or explicit annotation. If neither applies, we currently report an error. This pull request changes that case to defer the decision until we are able to analyze the actions of the closure: closures which mutate their environment require `FnMut`, closures which move out of their environment require `FnOnce`. This PR is not the end of the story: - It does not remove the explicit annotations nor disregard them. The latter is the logical next step to removing them (we'll need a snapshot before we can do anything anyhow). Disregarding explicit annotations might expose more bugs since right now all closures in libstd/rustc use explicit annotations or the expected type, so this inference never kicks in. - The interaction with instantiating type parameter fallbacks leaves something to be desired. This is mostly just saying that the algorithm from rust-lang/rfcs#213 needs to be implemented, which is a separate bug. There are some semi-subtle interactions though because not knowing whether a closure is `Fn` vs `FnMut` prevents us from resolving obligations like `F : FnMut(...)`, which can in turn prevent unification of some type parameters, which might (in turn) lead to undesired fallback. We can improve this situation however -- even if we don't know whether (or just how) `F : FnMut(..)` holds or not for some closure type `F`, we can still perform unification since we *do* know the argument and return types. Once kind inference is done, we can complete the `F : FnMut(..)` analysis -- which might yield an error if (e.g.) the `F` moves out of its environment. r? @nick29581
2 parents f1f9cb7 + 870aea2 commit 0ab8d5d

37 files changed

+1201
-415
lines changed

src/librustc/metadata/common.rs

+6-8
Original file line numberDiff line numberDiff line change
@@ -139,10 +139,11 @@ pub enum astencode_tag { // Reserves 0x40 -- 0x5f
139139
tag_table_adjustments = 0x51,
140140
tag_table_moves_map = 0x52,
141141
tag_table_capture_map = 0x53,
142-
tag_table_closures = 0x54,
143-
tag_table_upvar_capture_map = 0x55,
144-
tag_table_capture_modes = 0x56,
145-
tag_table_object_cast_map = 0x57,
142+
tag_table_closure_tys = 0x54,
143+
tag_table_closure_kinds = 0x55,
144+
tag_table_upvar_capture_map = 0x56,
145+
tag_table_capture_modes = 0x57,
146+
tag_table_object_cast_map = 0x58,
146147
}
147148

148149
static first_astencode_tag: uint = tag_ast as uint;
@@ -225,10 +226,7 @@ pub struct LinkMeta {
225226
pub crate_hash: Svh,
226227
}
227228

228-
pub const tag_closures: uint = 0x95;
229-
pub const tag_closure: uint = 0x96;
230-
pub const tag_closure_type: uint = 0x97;
231-
pub const tag_closure_kind: uint = 0x98;
229+
// GAP 0x94...0x98
232230

233231
pub const tag_struct_fields: uint = 0x99;
234232
pub const tag_struct_field: uint = 0x9a;

src/librustc/metadata/encoder.rs

-37
Original file line numberDiff line numberDiff line change
@@ -618,17 +618,6 @@ fn encode_visibility(rbml_w: &mut Encoder, visibility: ast::Visibility) {
618618
rbml_w.end_tag();
619619
}
620620

621-
fn encode_closure_kind(rbml_w: &mut Encoder, kind: ty::ClosureKind) {
622-
rbml_w.start_tag(tag_closure_kind);
623-
let ch = match kind {
624-
ty::FnClosureKind => 'f',
625-
ty::FnMutClosureKind => 'm',
626-
ty::FnOnceClosureKind => 'o',
627-
};
628-
rbml_w.wr_str(&ch.to_string()[]);
629-
rbml_w.end_tag();
630-
}
631-
632621
fn encode_explicit_self(rbml_w: &mut Encoder,
633622
explicit_self: &ty::ExplicitSelfCategory) {
634623
rbml_w.start_tag(tag_item_trait_method_explicit_self);
@@ -1843,24 +1832,6 @@ fn encode_macro_defs(rbml_w: &mut Encoder,
18431832
rbml_w.end_tag();
18441833
}
18451834

1846-
fn encode_closures<'a>(ecx: &'a EncodeContext, rbml_w: &'a mut Encoder) {
1847-
rbml_w.start_tag(tag_closures);
1848-
for (closure_id, closure) in ecx.tcx.closures.borrow().iter() {
1849-
if closure_id.krate != ast::LOCAL_CRATE {
1850-
continue
1851-
}
1852-
1853-
rbml_w.start_tag(tag_closure);
1854-
encode_def_id(rbml_w, *closure_id);
1855-
rbml_w.start_tag(tag_closure_type);
1856-
write_closure_type(ecx, rbml_w, &closure.closure_type);
1857-
rbml_w.end_tag();
1858-
encode_closure_kind(rbml_w, closure.kind);
1859-
rbml_w.end_tag();
1860-
}
1861-
rbml_w.end_tag();
1862-
}
1863-
18641835
fn encode_struct_field_attrs(rbml_w: &mut Encoder, krate: &ast::Crate) {
18651836
struct StructFieldVisitor<'a, 'b:'a> {
18661837
rbml_w: &'a mut Encoder<'b>,
@@ -2069,7 +2040,6 @@ fn encode_metadata_inner(wr: &mut SeekableMemWriter,
20692040
native_lib_bytes: u64,
20702041
plugin_registrar_fn_bytes: u64,
20712042
macro_defs_bytes: u64,
2072-
closure_bytes: u64,
20732043
impl_bytes: u64,
20742044
misc_bytes: u64,
20752045
item_bytes: u64,
@@ -2084,7 +2054,6 @@ fn encode_metadata_inner(wr: &mut SeekableMemWriter,
20842054
native_lib_bytes: 0,
20852055
plugin_registrar_fn_bytes: 0,
20862056
macro_defs_bytes: 0,
2087-
closure_bytes: 0,
20882057
impl_bytes: 0,
20892058
misc_bytes: 0,
20902059
item_bytes: 0,
@@ -2154,11 +2123,6 @@ fn encode_metadata_inner(wr: &mut SeekableMemWriter,
21542123
encode_macro_defs(&mut rbml_w, krate);
21552124
stats.macro_defs_bytes = rbml_w.writer.tell().unwrap() - i;
21562125

2157-
// Encode the types of all closures in this crate.
2158-
i = rbml_w.writer.tell().unwrap();
2159-
encode_closures(&ecx, &mut rbml_w);
2160-
stats.closure_bytes = rbml_w.writer.tell().unwrap() - i;
2161-
21622126
// Encode the def IDs of impls, for coherence checking.
21632127
i = rbml_w.writer.tell().unwrap();
21642128
encode_impls(&ecx, krate, &mut rbml_w);
@@ -2199,7 +2163,6 @@ fn encode_metadata_inner(wr: &mut SeekableMemWriter,
21992163
println!(" native bytes: {}", stats.native_lib_bytes);
22002164
println!("plugin registrar bytes: {}", stats.plugin_registrar_fn_bytes);
22012165
println!(" macro def bytes: {}", stats.macro_defs_bytes);
2202-
println!(" closure bytes: {}", stats.closure_bytes);
22032166
println!(" impl bytes: {}", stats.impl_bytes);
22042167
println!(" misc bytes: {}", stats.misc_bytes);
22052168
println!(" item bytes: {}", stats.item_bytes);

src/librustc/middle/astencode.rs

+39-58
Original file line numberDiff line numberDiff line change
@@ -647,30 +647,7 @@ impl<'tcx> tr for MethodOrigin<'tcx> {
647647
}
648648

649649
pub fn encode_closure_kind(ebml_w: &mut Encoder, kind: ty::ClosureKind) {
650-
use serialize::Encoder;
651-
652-
ebml_w.emit_enum("ClosureKind", |ebml_w| {
653-
match kind {
654-
ty::FnClosureKind => {
655-
ebml_w.emit_enum_variant("FnClosureKind", 0, 3, |_| {
656-
Ok(())
657-
})
658-
}
659-
ty::FnMutClosureKind => {
660-
ebml_w.emit_enum_variant("FnMutClosureKind", 1, 3, |_| {
661-
Ok(())
662-
})
663-
}
664-
ty::FnOnceClosureKind => {
665-
ebml_w.emit_enum_variant("FnOnceClosureKind",
666-
2,
667-
3,
668-
|_| {
669-
Ok(())
670-
})
671-
}
672-
}
673-
}).unwrap()
650+
kind.encode(ebml_w).unwrap();
674651
}
675652

676653
pub trait vtable_decoder_helpers<'tcx> {
@@ -1310,12 +1287,20 @@ fn encode_side_tables_for_id(ecx: &e::EncodeContext,
13101287
})
13111288
}
13121289

1313-
for closure in tcx.closures.borrow().get(&ast_util::local_def(id)).iter() {
1314-
rbml_w.tag(c::tag_table_closures, |rbml_w| {
1290+
for &closure_type in tcx.closure_tys.borrow().get(&ast_util::local_def(id)).iter() {
1291+
rbml_w.tag(c::tag_table_closure_tys, |rbml_w| {
1292+
rbml_w.id(id);
1293+
rbml_w.tag(c::tag_table_val, |rbml_w| {
1294+
rbml_w.emit_closure_type(ecx, closure_type);
1295+
})
1296+
})
1297+
}
1298+
1299+
for &&closure_kind in tcx.closure_kinds.borrow().get(&ast_util::local_def(id)).iter() {
1300+
rbml_w.tag(c::tag_table_closure_kinds, |rbml_w| {
13151301
rbml_w.id(id);
13161302
rbml_w.tag(c::tag_table_val, |rbml_w| {
1317-
rbml_w.emit_closure_type(ecx, &closure.closure_type);
1318-
encode_closure_kind(rbml_w, closure.kind)
1303+
encode_closure_kind(rbml_w, closure_kind)
13191304
})
13201305
})
13211306
}
@@ -1354,8 +1339,10 @@ trait rbml_decoder_decoder_helpers<'tcx> {
13541339
-> subst::Substs<'tcx>;
13551340
fn read_auto_adjustment<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>)
13561341
-> ty::AutoAdjustment<'tcx>;
1357-
fn read_closure<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>)
1358-
-> ty::Closure<'tcx>;
1342+
fn read_closure_kind<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>)
1343+
-> ty::ClosureKind;
1344+
fn read_closure_ty<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>)
1345+
-> ty::ClosureTy<'tcx>;
13591346
fn read_auto_deref_ref<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>)
13601347
-> ty::AutoDerefRef<'tcx>;
13611348
fn read_autoref<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>)
@@ -1782,35 +1769,23 @@ impl<'a, 'tcx> rbml_decoder_decoder_helpers<'tcx> for reader::Decoder<'a> {
17821769
}).unwrap()
17831770
}
17841771

1785-
fn read_closure<'b, 'c>(&mut self, dcx: &DecodeContext<'b, 'c, 'tcx>)
1786-
-> ty::Closure<'tcx> {
1787-
let closure_type = self.read_opaque(|this, doc| {
1772+
fn read_closure_kind<'b, 'c>(&mut self, _dcx: &DecodeContext<'b, 'c, 'tcx>)
1773+
-> ty::ClosureKind
1774+
{
1775+
Decodable::decode(self).ok().unwrap()
1776+
}
1777+
1778+
fn read_closure_ty<'b, 'c>(&mut self, dcx: &DecodeContext<'b, 'c, 'tcx>)
1779+
-> ty::ClosureTy<'tcx>
1780+
{
1781+
self.read_opaque(|this, doc| {
17881782
Ok(tydecode::parse_ty_closure_data(
17891783
doc.data,
17901784
dcx.cdata.cnum,
17911785
doc.start,
17921786
dcx.tcx,
17931787
|s, a| this.convert_def_id(dcx, s, a)))
1794-
}).unwrap();
1795-
let variants = &[
1796-
"FnClosureKind",
1797-
"FnMutClosureKind",
1798-
"FnOnceClosureKind"
1799-
];
1800-
let kind = self.read_enum("ClosureKind", |this| {
1801-
this.read_enum_variant(variants, |_, i| {
1802-
Ok(match i {
1803-
0 => ty::FnClosureKind,
1804-
1 => ty::FnMutClosureKind,
1805-
2 => ty::FnOnceClosureKind,
1806-
_ => panic!("bad enum variant for ty::ClosureKind"),
1807-
})
1808-
})
1809-
}).unwrap();
1810-
ty::Closure {
1811-
closure_type: closure_type,
1812-
kind: kind,
1813-
}
1788+
}).unwrap()
18141789
}
18151790

18161791
/// Converts a def-id that appears in a type. The correct
@@ -1937,11 +1912,17 @@ fn decode_side_tables(dcx: &DecodeContext,
19371912
let adj: ty::AutoAdjustment = val_dsr.read_auto_adjustment(dcx);
19381913
dcx.tcx.adjustments.borrow_mut().insert(id, adj);
19391914
}
1940-
c::tag_table_closures => {
1941-
let closure =
1942-
val_dsr.read_closure(dcx);
1943-
dcx.tcx.closures.borrow_mut().insert(ast_util::local_def(id),
1944-
closure);
1915+
c::tag_table_closure_tys => {
1916+
let closure_ty =
1917+
val_dsr.read_closure_ty(dcx);
1918+
dcx.tcx.closure_tys.borrow_mut().insert(ast_util::local_def(id),
1919+
closure_ty);
1920+
}
1921+
c::tag_table_closure_kinds => {
1922+
let closure_kind =
1923+
val_dsr.read_closure_kind(dcx);
1924+
dcx.tcx.closure_kinds.borrow_mut().insert(ast_util::local_def(id),
1925+
closure_kind);
19451926
}
19461927
_ => {
19471928
dcx.tcx.sess.bug(

src/librustc/middle/expr_use_visitor.rs

+2-4
Original file line numberDiff line numberDiff line change
@@ -260,12 +260,10 @@ impl OverloadedCallType {
260260
fn from_closure(tcx: &ty::ctxt, closure_did: ast::DefId)
261261
-> OverloadedCallType {
262262
let trait_did =
263-
tcx.closures
263+
tcx.closure_kinds
264264
.borrow()
265265
.get(&closure_did)
266-
.expect("OverloadedCallType::from_closure: didn't \
267-
find closure id")
268-
.kind
266+
.expect("OverloadedCallType::from_closure: didn't find closure id")
269267
.trait_did(tcx);
270268
OverloadedCallType::from_trait_id(tcx, trait_did)
271269
}

src/librustc/middle/mem_categorization.rs

+10-2
Original file line numberDiff line numberDiff line change
@@ -594,8 +594,16 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> {
594594
let ty = try!(self.node_ty(fn_node_id));
595595
match ty.sty {
596596
ty::ty_closure(closure_id, _, _) => {
597-
let kind = self.typer.closure_kind(closure_id);
598-
self.cat_upvar(id, span, var_id, fn_node_id, kind)
597+
match self.typer.closure_kind(closure_id) {
598+
Some(kind) => {
599+
self.cat_upvar(id, span, var_id, fn_node_id, kind)
600+
}
601+
None => {
602+
self.tcx().sess.span_bug(
603+
span,
604+
&*format!("No closure kind for {:?}", closure_id));
605+
}
606+
}
599607
}
600608
_ => {
601609
self.tcx().sess.span_bug(

src/librustc/middle/traits/select.rs

+11-6
Original file line numberDiff line numberDiff line change
@@ -1024,12 +1024,17 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
10241024
kind,
10251025
obligation.repr(self.tcx()));
10261026

1027-
let closure_kind = self.closure_typer.closure_kind(closure_def_id);
1028-
1029-
debug!("closure_kind = {:?}", closure_kind);
1030-
1031-
if closure_kind == kind {
1032-
candidates.vec.push(ClosureCandidate(closure_def_id, substs.clone()));
1027+
match self.closure_typer.closure_kind(closure_def_id) {
1028+
Some(closure_kind) => {
1029+
debug!("assemble_unboxed_candidates: closure_kind = {:?}", closure_kind);
1030+
if closure_kind == kind {
1031+
candidates.vec.push(ClosureCandidate(closure_def_id, substs.clone()));
1032+
}
1033+
}
1034+
None => {
1035+
debug!("assemble_unboxed_candidates: closure_kind not yet known");
1036+
candidates.ambiguous = true;
1037+
}
10331038
}
10341039

10351040
Ok(())

0 commit comments

Comments
 (0)