Skip to content

Commit 774cd6b

Browse files
committed
---
yaml --- r: 178623 b: refs/heads/snap-stage3 c: 5a39a0d h: refs/heads/master i: 178621: 4c4bcb1 178619: 86ae9ce 178615: 626b6c4 178607: 1ac9fc6 178591: 8ff03a2 178559: d440189 v: v3
1 parent e5989e6 commit 774cd6b

11 files changed

+355
-48
lines changed

[refs]

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
---
22
refs/heads/master: 3d072a193bfcb76206aab576049e696d6d8db25d
33
refs/heads/snap-stage1: e33de59e47c5076a89eadeb38f4934f58a3618a6
4-
refs/heads/snap-stage3: e1f54f01d666279f50153536eb5a8494f26d89a7
4+
refs/heads/snap-stage3: 5a39a0d266705d594ff31b8e386bc8c1e54ab019
55
refs/heads/try: ccf8fedf1cffcb8f6f3581d53d220039e192fe77
66
refs/tags/release-0.1: 1f5c5126e96c79d22cb7862f75304136e204f105
77
refs/heads/dist-snap: ba4081a5a8573875fed17545846f6f6902c8ba8d

branches/snap-stage3/src/librustc_typeck/check/callee.rs

Lines changed: 42 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ use super::check_argument_types;
1414
use super::check_expr;
1515
use super::check_method_argument_types;
1616
use super::demand;
17-
use super::DeferredResolution;
17+
use super::DeferredCallResolution;
1818
use super::err_args;
1919
use super::Expectation;
2020
use super::expected_types_for_fn_args;
@@ -99,8 +99,8 @@ pub fn check_call<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
9999
confirm_builtin_call(fcx, call_expr, callee_ty, arg_exprs, expected);
100100
}
101101

102-
Some(CallStep::Closure(fn_sig)) => {
103-
confirm_closure_call(fcx, call_expr, arg_exprs, expected, fn_sig);
102+
Some(CallStep::DeferredClosure(fn_sig)) => {
103+
confirm_deferred_closure_call(fcx, call_expr, arg_exprs, expected, fn_sig);
104104
}
105105

106106
Some(CallStep::Overloaded(method_callee)) => {
@@ -112,7 +112,7 @@ pub fn check_call<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
112112

113113
enum CallStep<'tcx> {
114114
Builtin,
115-
Closure(ty::FnSig<'tcx>),
115+
DeferredClosure(ty::FnSig<'tcx>),
116116
Overloaded(ty::MethodCallee<'tcx>)
117117
}
118118

@@ -138,21 +138,28 @@ fn try_overloaded_call_step<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
138138
}
139139

140140
ty::ty_closure(def_id, _, substs) => {
141-
let closure_ty =
142-
fcx.closure_type(def_id, substs);
143-
let fn_sig =
144-
fcx.infcx().replace_late_bound_regions_with_fresh_var(call_expr.span,
145-
infer::FnCall,
146-
&closure_ty.sig).0;
147-
fcx.record_deferred_resolution(box CallResolution {
148-
call_expr: call_expr,
149-
callee_expr: callee_expr,
150-
adjusted_ty: adjusted_ty,
151-
autoderefref: autoderefref,
152-
fn_sig: fn_sig.clone(),
153-
closure_def_id: def_id,
154-
});
155-
return Some(CallStep::Closure(fn_sig));
141+
assert_eq!(def_id.krate, ast::LOCAL_CRATE);
142+
143+
// Check whether this is a call to a closure where we
144+
// haven't yet decided on whether the closure is fn vs
145+
// fnmut vs fnonce. If so, we have to defer further processing.
146+
if fcx.closure_kind(def_id).is_none() {
147+
let closure_ty =
148+
fcx.closure_type(def_id, substs);
149+
let fn_sig =
150+
fcx.infcx().replace_late_bound_regions_with_fresh_var(call_expr.span,
151+
infer::FnCall,
152+
&closure_ty.sig).0;
153+
fcx.record_deferred_call_resolution(
154+
def_id,
155+
box CallResolution {call_expr: call_expr,
156+
callee_expr: callee_expr,
157+
adjusted_ty: adjusted_ty,
158+
autoderefref: autoderefref,
159+
fn_sig: fn_sig.clone(),
160+
closure_def_id: def_id});
161+
return Some(CallStep::DeferredClosure(fn_sig));
162+
}
156163
}
157164

158165
_ => {}
@@ -258,11 +265,11 @@ fn confirm_builtin_call<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>,
258265
write_call(fcx, call_expr, fn_sig.output);
259266
}
260267

261-
fn confirm_closure_call<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>,
262-
call_expr: &ast::Expr,
263-
arg_exprs: &'tcx [P<ast::Expr>],
264-
expected: Expectation<'tcx>,
265-
fn_sig: ty::FnSig<'tcx>)
268+
fn confirm_deferred_closure_call<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>,
269+
call_expr: &ast::Expr,
270+
arg_exprs: &'tcx [P<ast::Expr>],
271+
expected: Expectation<'tcx>,
272+
fn_sig: ty::FnSig<'tcx>)
266273
{
267274
// `fn_sig` is the *signature* of the cosure being called. We
268275
// don't know the full details yet (`Fn` vs `FnMut` etc), but we
@@ -338,22 +345,18 @@ impl<'tcx> Repr<'tcx> for CallResolution<'tcx> {
338345
}
339346
}
340347

341-
impl<'tcx> DeferredResolution<'tcx> for CallResolution<'tcx> {
342-
fn attempt_resolution<'a>(&self, fcx: &FnCtxt<'a,'tcx>) -> bool {
343-
debug!("attempt_resolution() {}",
348+
impl<'tcx> DeferredCallResolution<'tcx> for CallResolution<'tcx> {
349+
fn resolve<'a>(&mut self, fcx: &FnCtxt<'a,'tcx>) {
350+
debug!("DeferredCallResolution::resolve() {}",
344351
self.repr(fcx.tcx()));
345352

346-
match fcx.closure_kind(self.closure_def_id) {
347-
Some(_) => { }
348-
None => {
349-
return false;
350-
}
351-
}
353+
// we should not be invoked until the closure kind has been
354+
// determined by upvar inference
355+
assert!(fcx.closure_kind(self.closure_def_id).is_some());
352356

353357
// We may now know enough to figure out fn vs fnmut etc.
354358
match try_overloaded_call_traits(fcx, self.call_expr, self.callee_expr,
355359
self.adjusted_ty, self.autoderefref.clone()) {
356-
None => false,
357360
Some(method_callee) => {
358361
// One problem is that when we get here, we are going
359362
// to have a newly instantiated function signature
@@ -382,8 +385,11 @@ impl<'tcx> DeferredResolution<'tcx> for CallResolution<'tcx> {
382385
self.fn_sig.output.unwrap());
383386

384387
write_overloaded_call_method_map(fcx, self.call_expr, method_callee);
385-
386-
true
388+
}
389+
None => {
390+
fcx.tcx().sess.span_bug(
391+
self.call_expr.span,
392+
"failed to find an overloaded call trait for closure call");
387393
}
388394
}
389395
}

branches/snap-stage3/src/librustc_typeck/check/mod.rs

Lines changed: 30 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,7 @@ use util::nodemap::{DefIdMap, FnvHashMap, NodeMap};
110110
use util::lev_distance::lev_distance;
111111

112112
use std::cell::{Cell, Ref, RefCell};
113+
use std::collections::hash_map::Entry::{Occupied, Vacant};
113114
use std::mem::replace;
114115
use std::rc::Rc;
115116
use std::iter::repeat;
@@ -172,15 +173,21 @@ pub struct Inherited<'a, 'tcx: 'a> {
172173
// Tracks trait obligations incurred during this function body.
173174
fulfillment_cx: RefCell<traits::FulfillmentContext<'tcx>>,
174175

175-
//
176-
deferred_resolutions: RefCell<Vec<DeferredResolutionHandler<'tcx>>>,
176+
// When we process a call like `c()` where `c` is a closure type,
177+
// we may not have decided yet whether `c` is a `Fn`, `FnMut`, or
178+
// `FnOnce` closure. In that case, we defer full resolution of the
179+
// call until upvar inference can kick in and make the
180+
// decision. We keep these deferred resolutions sorted by the
181+
// def-id of the closure, so that once we decide, we can easily go
182+
// back and process them.
183+
deferred_call_resolutions: RefCell<DefIdMap<Vec<DeferredCallResolutionHandler<'tcx>>>>,
177184
}
178185

179-
trait DeferredResolution<'tcx> {
180-
fn attempt_resolution<'a>(&self, fcx: &FnCtxt<'a,'tcx>) -> bool;
186+
trait DeferredCallResolution<'tcx> {
187+
fn resolve<'a>(&mut self, fcx: &FnCtxt<'a,'tcx>);
181188
}
182189

183-
type DeferredResolutionHandler<'tcx> = Box<DeferredResolution<'tcx>+'tcx>;
190+
type DeferredCallResolutionHandler<'tcx> = Box<DeferredCallResolution<'tcx>+'tcx>;
184191

185192
/// When type-checking an expression, we propagate downward
186193
/// whatever type hint we are able in the form of an `Expectation`.
@@ -391,7 +398,7 @@ impl<'a, 'tcx> Inherited<'a, 'tcx> {
391398
closure_kinds: RefCell::new(DefIdMap()),
392399
fn_sig_map: RefCell::new(NodeMap()),
393400
fulfillment_cx: RefCell::new(traits::FulfillmentContext::new()),
394-
deferred_resolutions: RefCell::new(Vec::new()),
401+
deferred_call_resolutions: RefCell::new(DefIdMap()),
395402
}
396403
}
397404

@@ -1295,8 +1302,23 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
12951302
if ty::type_has_ty_infer(t) || ty::type_is_error(t) { Err(()) } else { Ok(t) }
12961303
}
12971304

1298-
fn record_deferred_resolution(&self, r: DeferredResolutionHandler<'tcx>) {
1299-
self.inh.deferred_resolutions.borrow_mut().push(r);
1305+
fn record_deferred_call_resolution(&self,
1306+
closure_def_id: ast::DefId,
1307+
r: DeferredCallResolutionHandler<'tcx>) {
1308+
let mut deferred_call_resolutions = self.inh.deferred_call_resolutions.borrow_mut();
1309+
let mut vec = match deferred_call_resolutions.entry(closure_def_id) {
1310+
Occupied(entry) => entry.into_mut(),
1311+
Vacant(entry) => entry.insert(Vec::new()),
1312+
};
1313+
vec.push(r);
1314+
}
1315+
1316+
fn remove_deferred_call_resolutions(&self,
1317+
closure_def_id: ast::DefId)
1318+
-> Vec<DeferredCallResolutionHandler<'tcx>>
1319+
{
1320+
let mut deferred_call_resolutions = self.inh.deferred_call_resolutions.borrow_mut();
1321+
deferred_call_resolutions.remove(&closure_def_id).unwrap_or(Vec::new())
13001322
}
13011323

13021324
pub fn tag(&self) -> String {

branches/snap-stage3/src/librustc_typeck/check/upvar.rs

Lines changed: 50 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,9 @@ pub fn closure_analyze_fn(fcx: &FnCtxt,
6767

6868
let mut adjust = AdjustBorrowKind::new(fcx, &closures_with_inferred_kinds);
6969
adjust.visit_block(body);
70+
71+
// it's our job to process these.
72+
assert!(fcx.inh.deferred_call_resolutions.borrow().is_empty());
7073
}
7174

7275
///////////////////////////////////////////////////////////////////////////
@@ -186,10 +189,56 @@ impl<'a,'tcx> AdjustBorrowKind<'a,'tcx> {
186189

187190
self.visit_block(body);
188191

189-
debug!("analyzing fn body with id {}", body.id);
192+
debug!("analyzing closure `{}` with fn body id `{}`", id, body.id);
190193

191194
let mut euv = euv::ExprUseVisitor::new(self, self.fcx);
192195
euv.walk_fn(decl, body);
196+
197+
// If we had not yet settled on a closure kind for this closure,
198+
// then we should have by now. Process and remove any deferred resolutions.
199+
//
200+
// Interesting fact: all calls to this closure must come
201+
// *after* its definition. Initially, I thought that some
202+
// kind of fixed-point iteration would be required, due to the
203+
// possibility of twisted examples like this one:
204+
//
205+
// ```rust
206+
// let mut closure0 = None;
207+
// let vec = vec!(1, 2, 3);
208+
//
209+
// loop {
210+
// {
211+
// let closure1 = || {
212+
// match closure0.take() {
213+
// Some(c) => {
214+
// return c(); // (*) call to `closure0` before it is defined
215+
// }
216+
// None => { }
217+
// }
218+
// };
219+
// closure1();
220+
// }
221+
//
222+
// closure0 = || vec;
223+
// }
224+
// ```
225+
//
226+
// However, this turns out to be wrong. Examples like this
227+
// fail to compile because the type of the variable `c` above
228+
// is an inference variable. And in fact since closure types
229+
// cannot be written, there is no way to make this example
230+
// work without a boxed closure. This implies that we can't
231+
// have two closures that recursively call one another without
232+
// some form of boxing (and hence explicit writing of a
233+
// closure kind) involved. Huzzah. -nmatsakis
234+
let closure_def_id = ast_util::local_def(id);
235+
if self.closures_with_inferred_kinds.contains(&id) {
236+
let mut deferred_call_resolutions =
237+
self.fcx.remove_deferred_call_resolutions(closure_def_id);
238+
for deferred_call_resolution in deferred_call_resolutions.iter_mut() {
239+
deferred_call_resolution.resolve(self.fcx);
240+
}
241+
}
193242
}
194243

195244
fn adjust_upvar_borrow_kind_for_consume(&self,

branches/snap-stage3/src/librustc_typeck/check/vtable.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -280,8 +280,6 @@ fn check_object_type_binds_all_associated_types<'tcx>(tcx: &ty::ctxt<'tcx>,
280280
pub fn select_all_fcx_obligations_and_apply_defaults(fcx: &FnCtxt) {
281281
debug!("select_all_fcx_obligations_and_apply_defaults");
282282

283-
fcx.inh.deferred_resolutions.borrow_mut()
284-
.retain(|r| !r.attempt_resolution(fcx));
285283
select_fcx_obligations_where_possible(fcx);
286284
fcx.default_type_parameters();
287285
select_fcx_obligations_where_possible(fcx);
@@ -290,6 +288,10 @@ pub fn select_all_fcx_obligations_and_apply_defaults(fcx: &FnCtxt) {
290288
pub fn select_all_fcx_obligations_or_error(fcx: &FnCtxt) {
291289
debug!("select_all_fcx_obligations_or_error");
292290

291+
// upvar inference should have ensured that all deferrred call
292+
// resolutions are handled by now.
293+
assert!(fcx.inh.deferred_call_resolutions.borrow().is_empty());
294+
293295
select_all_fcx_obligations_and_apply_defaults(fcx);
294296
let mut fulfillment_cx = fcx.inh.fulfillment_cx.borrow_mut();
295297
let r = fulfillment_cx.select_all_or_error(fcx.infcx(), fcx);
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// Various unsuccessful attempts to put the unboxed closure kind
12+
// inference into an awkward position that might require fixed point
13+
// iteration (basically where inferring the kind of a closure `c`
14+
// would require knowing the kind of `c`). I currently believe this is
15+
// impossible.
16+
17+
fn a() {
18+
// This case of recursion wouldn't even require fixed-point
19+
// iteration, but it still doesn't work. The weird structure with
20+
// the `Option` is to avoid giving any useful hints about the `Fn`
21+
// kind via the expected type.
22+
let mut factorial: Option<Box<Fn(u32) -> u32>> = None;
23+
24+
let f = |x: u32| -> u32 {
25+
let g = factorial.as_ref().unwrap();
26+
if x == 0 {1} else {x * g(x-1)}
27+
};
28+
29+
factorial = Some(Box::new(f));
30+
//~^ ERROR cannot assign to `factorial` because it is borrowed
31+
}
32+
33+
fn main() { }
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// Various unsuccessful attempts to put the unboxed closure kind
12+
// inference into an awkward position that might require fixed point
13+
// iteration (basically where inferring the kind of a closure `c`
14+
// would require knowing the kind of `c`). I currently believe this is
15+
// impossible.
16+
17+
fn a() {
18+
let mut closure0 = None;
19+
let vec = vec!(1, 2, 3);
20+
21+
loop {
22+
{
23+
let closure1 = || {
24+
match closure0.take() {
25+
Some(c) => {
26+
return c();
27+
//~^ ERROR the type of this value must be known in this context
28+
}
29+
None => { }
30+
}
31+
};
32+
closure1();
33+
}
34+
35+
closure0 = || vec;
36+
}
37+
}
38+
39+
fn main() { }

0 commit comments

Comments
 (0)