Skip to content

Commit 53c1956

Browse files
committed
Introduce the notion of deferred resolutions and use it to hold off on
doing the final checking for closure calls until after trait inference is performed. This isn't important now, but it's essential if we are to delay inferring the closure kind.
1 parent fe4340a commit 53c1956

File tree

7 files changed

+308
-144
lines changed

7 files changed

+308
-144
lines changed

src/librustc_typeck/check/_match.rs

Lines changed: 17 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ use syntax::print::pprust;
3030
use syntax::ptr::P;
3131

3232
pub fn check_pat<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>,
33-
pat: &ast::Pat,
33+
pat: &'tcx ast::Pat,
3434
expected: Ty<'tcx>)
3535
{
3636
let fcx = pcx.fcx;
@@ -157,9 +157,10 @@ pub fn check_pat<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>,
157157
}
158158
ast::PatIdent(_, ref path, _) => {
159159
let path = ast_util::ident_to_path(path.span, path.node);
160-
check_pat_enum(pcx, pat, &path, &Some(vec![]), expected);
160+
check_pat_enum(pcx, pat, &path, Some(&[]), expected);
161161
}
162162
ast::PatEnum(ref path, ref subpats) => {
163+
let subpats = subpats.as_ref().map(|v| &v[]);
163164
check_pat_enum(pcx, pat, path, subpats, expected);
164165
}
165166
ast::PatStruct(ref path, ref fields, etc) => {
@@ -335,9 +336,9 @@ pub fn check_dereferencable<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>,
335336
}
336337

337338
pub fn check_match<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
338-
expr: &ast::Expr,
339-
discrim: &ast::Expr,
340-
arms: &[ast::Arm],
339+
expr: &'tcx ast::Expr,
340+
discrim: &'tcx ast::Expr,
341+
arms: &'tcx [ast::Arm],
341342
expected: Expectation<'tcx>,
342343
match_src: ast::MatchSource) {
343344
let tcx = fcx.ccx.tcx;
@@ -424,8 +425,8 @@ pub struct pat_ctxt<'a, 'tcx: 'a> {
424425
pub map: PatIdMap,
425426
}
426427

427-
pub fn check_pat_struct<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, pat: &ast::Pat,
428-
path: &ast::Path, fields: &[Spanned<ast::FieldPat>],
428+
pub fn check_pat_struct<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, pat: &'tcx ast::Pat,
429+
path: &ast::Path, fields: &'tcx [Spanned<ast::FieldPat>],
429430
etc: bool, expected: Ty<'tcx>) {
430431
let fcx = pcx.fcx;
431432
let tcx = pcx.fcx.ccx.tcx;
@@ -483,10 +484,12 @@ pub fn check_pat_struct<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, pat: &ast::Pat,
483484
variant_def_id, etc);
484485
}
485486

486-
pub fn check_pat_enum<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, pat: &ast::Pat,
487-
path: &ast::Path, subpats: &Option<Vec<P<ast::Pat>>>,
488-
expected: Ty<'tcx>) {
489-
487+
pub fn check_pat_enum<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>,
488+
pat: &ast::Pat,
489+
path: &ast::Path,
490+
subpats: Option<&'tcx [P<ast::Pat>]>,
491+
expected: Ty<'tcx>)
492+
{
490493
// Typecheck the path.
491494
let fcx = pcx.fcx;
492495
let tcx = pcx.fcx.ccx.tcx;
@@ -536,7 +539,7 @@ pub fn check_pat_enum<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, pat: &ast::Pat,
536539
"`{}` does not name a non-struct variant or a tuple struct", name);
537540
fcx.write_error(pat.id);
538541

539-
if let Some(ref subpats) = *subpats {
542+
if let Some(subpats) = subpats {
540543
for pat in subpats.iter() {
541544
check_pat(pcx, &**pat, tcx.types.err);
542545
}
@@ -545,7 +548,7 @@ pub fn check_pat_enum<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, pat: &ast::Pat,
545548
}
546549
};
547550

548-
if let Some(ref subpats) = *subpats {
551+
if let Some(subpats) = subpats {
549552
if subpats.len() == arg_tys.len() {
550553
for (subpat, arg_ty) in subpats.iter().zip(arg_tys.iter()) {
551554
check_pat(pcx, &**subpat, *arg_ty);
@@ -579,7 +582,7 @@ pub fn check_pat_enum<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, pat: &ast::Pat,
579582
/// `etc` is true if the pattern said '...' and false otherwise.
580583
pub fn check_struct_pat_fields<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>,
581584
span: Span,
582-
fields: &[Spanned<ast::FieldPat>],
585+
fields: &'tcx [Spanned<ast::FieldPat>],
583586
struct_fields: &[ty::field<'tcx>],
584587
struct_id: ast::DefId,
585588
etc: bool) {

src/librustc_typeck/check/callee.rs

Lines changed: 166 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ use super::AutorefArgs;
1313
use super::check_argument_types;
1414
use super::check_expr;
1515
use super::check_method_argument_types;
16+
use super::demand;
17+
use super::DeferredResolution;
1618
use super::err_args;
1719
use super::Expectation;
1820
use super::expected_types_for_fn_args;
@@ -24,13 +26,14 @@ use super::TupleArgumentsFlag;
2426
use super::UnresolvedTypeAction;
2527
use super::write_call;
2628

29+
use CrateCtxt;
2730
use middle::infer;
28-
use middle::ty::{self, Ty};
31+
use middle::ty::{self, Ty, ClosureTyper};
2932
use syntax::ast;
3033
use syntax::codemap::Span;
3134
use syntax::parse::token;
3235
use syntax::ptr::P;
33-
use CrateCtxt;
36+
use util::ppaux::Repr;
3437

3538
/// Check that it is legal to call methods of the trait corresponding
3639
/// to `trait_id` (this only cares about the trait, not the specific
@@ -66,9 +69,9 @@ pub fn check_legal_trait_for_method_call(ccx: &CrateCtxt, span: Span, trait_id:
6669
}
6770

6871
pub fn check_call<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
69-
call_expr: &ast::Expr,
70-
callee_expr: &ast::Expr,
71-
arg_exprs: &[P<ast::Expr>],
72+
call_expr: &'tcx ast::Expr,
73+
callee_expr: &'tcx ast::Expr,
74+
arg_exprs: &'tcx [P<ast::Expr>],
7275
expected: Expectation<'tcx>)
7376
{
7477
check_expr(fcx, callee_expr);
@@ -96,24 +99,35 @@ pub fn check_call<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
9699
confirm_builtin_call(fcx, call_expr, callee_ty, arg_exprs, expected);
97100
}
98101

102+
Some(CallStep::Closure(fn_sig)) => {
103+
confirm_closure_call(fcx, call_expr, arg_exprs, expected, fn_sig);
104+
}
105+
99106
Some(CallStep::Overloaded(method_callee)) => {
100-
confirm_overloaded_call(fcx, call_expr, arg_exprs, method_callee, expected);
107+
confirm_overloaded_call(fcx, call_expr, callee_expr,
108+
arg_exprs, expected, method_callee);
101109
}
102110
}
103111
}
104112

105113
enum CallStep<'tcx> {
106114
Builtin,
115+
Closure(ty::FnSig<'tcx>),
107116
Overloaded(ty::MethodCallee<'tcx>)
108117
}
109118

110119
fn try_overloaded_call_step<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
111-
call_expr: &ast::Expr,
112-
callee_expr: &ast::Expr,
120+
call_expr: &'tcx ast::Expr,
121+
callee_expr: &'tcx ast::Expr,
113122
adjusted_ty: Ty<'tcx>,
114123
autoderefref: ty::AutoDerefRef<'tcx>)
115124
-> Option<CallStep<'tcx>>
116125
{
126+
debug!("try_overloaded_call_step(call_expr={}, adjusted_ty={}, autoderefref={})",
127+
call_expr.repr(fcx.tcx()),
128+
adjusted_ty.repr(fcx.tcx()),
129+
autoderefref.repr(fcx.tcx()));
130+
117131
// If the callee is a bare function or a closure, then we're all set.
118132
match structurally_resolved_type(fcx, callee_expr.span, adjusted_ty).sty {
119133
ty::ty_bare_fn(..) => {
@@ -123,9 +137,37 @@ fn try_overloaded_call_step<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
123137
return Some(CallStep::Builtin);
124138
}
125139

140+
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+
});
154+
return Some(CallStep::Closure(fn_sig));
155+
}
156+
126157
_ => {}
127158
}
128159

160+
try_overloaded_call_traits(fcx, call_expr, callee_expr, adjusted_ty, autoderefref)
161+
.map(|method_callee| CallStep::Overloaded(method_callee))
162+
}
163+
164+
fn try_overloaded_call_traits<'a,'tcx>(fcx: &FnCtxt<'a, 'tcx>,
165+
call_expr: &ast::Expr,
166+
callee_expr: &ast::Expr,
167+
adjusted_ty: Ty<'tcx>,
168+
autoderefref: ty::AutoDerefRef<'tcx>)
169+
-> Option<ty::MethodCallee<'tcx>>
170+
{
129171
// Try the options that are least restrictive on the caller first.
130172
for &(opt_trait_def_id, method_name) in [
131173
(fcx.tcx().lang_items.fn_trait(), token::intern("call")),
@@ -147,7 +189,7 @@ fn try_overloaded_call_step<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
147189
None) {
148190
None => continue,
149191
Some(method_callee) => {
150-
return Some(CallStep::Overloaded(method_callee));
192+
return Some(method_callee);
151193
}
152194
}
153195
}
@@ -158,7 +200,7 @@ fn try_overloaded_call_step<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
158200
fn confirm_builtin_call<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>,
159201
call_expr: &ast::Expr,
160202
callee_ty: Ty<'tcx>,
161-
arg_exprs: &[P<ast::Expr>],
203+
arg_exprs: &'tcx [P<ast::Expr>],
162204
expected: Expectation<'tcx>)
163205
{
164206
let error_fn_sig;
@@ -215,22 +257,124 @@ fn confirm_builtin_call<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>,
215257
write_call(fcx, call_expr, fn_sig.output);
216258
}
217259

260+
fn confirm_closure_call<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>,
261+
call_expr: &ast::Expr,
262+
arg_exprs: &'tcx [P<ast::Expr>],
263+
expected: Expectation<'tcx>,
264+
fn_sig: ty::FnSig<'tcx>)
265+
{
266+
// `fn_sig` is the *signature* of the cosure being called. We
267+
// don't know the full details yet (`Fn` vs `FnMut` etc), but we
268+
// do know the types expected for each argument and the return
269+
// type.
270+
271+
let expected_arg_tys =
272+
expected_types_for_fn_args(fcx,
273+
call_expr.span,
274+
expected,
275+
fn_sig.output.clone(),
276+
&*fn_sig.inputs);
277+
278+
check_argument_types(fcx,
279+
call_expr.span,
280+
&*fn_sig.inputs,
281+
&*expected_arg_tys,
282+
arg_exprs,
283+
AutorefArgs::No,
284+
fn_sig.variadic,
285+
TupleArgumentsFlag::TupleArguments);
286+
287+
write_call(fcx, call_expr, fn_sig.output);
288+
}
289+
218290
fn confirm_overloaded_call<'a,'tcx>(fcx: &FnCtxt<'a, 'tcx>,
219291
call_expr: &ast::Expr,
220-
arg_exprs: &[P<ast::Expr>],
221-
method_callee: ty::MethodCallee<'tcx>,
222-
expected: Expectation<'tcx>)
292+
callee_expr: &'tcx ast::Expr,
293+
arg_exprs: &'tcx [P<ast::Expr>],
294+
expected: Expectation<'tcx>,
295+
method_callee: ty::MethodCallee<'tcx>)
223296
{
224-
let output_type = check_method_argument_types(fcx,
225-
call_expr.span,
226-
method_callee.ty,
227-
call_expr,
228-
arg_exprs,
229-
AutorefArgs::No,
230-
TupleArgumentsFlag::TupleArguments,
231-
expected);
297+
let output_type =
298+
check_method_argument_types(fcx,
299+
call_expr.span,
300+
method_callee.ty,
301+
callee_expr,
302+
arg_exprs,
303+
AutorefArgs::No,
304+
TupleArgumentsFlag::TupleArguments,
305+
expected);
306+
write_call(fcx, call_expr, output_type);
307+
308+
write_overloaded_call_method_map(fcx, call_expr, method_callee);
309+
}
310+
311+
fn write_overloaded_call_method_map<'a,'tcx>(fcx: &FnCtxt<'a, 'tcx>,
312+
call_expr: &ast::Expr,
313+
method_callee: ty::MethodCallee<'tcx>) {
232314
let method_call = ty::MethodCall::expr(call_expr.id);
233315
fcx.inh.method_map.borrow_mut().insert(method_call, method_callee);
234-
write_call(fcx, call_expr, output_type);
235316
}
236317

318+
struct CallResolution<'tcx> {
319+
call_expr: &'tcx ast::Expr,
320+
callee_expr: &'tcx ast::Expr,
321+
adjusted_ty: Ty<'tcx>,
322+
autoderefref: ty::AutoDerefRef<'tcx>,
323+
fn_sig: ty::FnSig<'tcx>,
324+
}
325+
326+
impl<'tcx> Repr<'tcx> for CallResolution<'tcx> {
327+
fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String {
328+
format!("CallResolution(call_expr={}, callee_expr={}, adjusted_ty={}, \
329+
autoderefref={}, fn_sig={})",
330+
self.call_expr.repr(tcx),
331+
self.callee_expr.repr(tcx),
332+
self.adjusted_ty.repr(tcx),
333+
self.autoderefref.repr(tcx),
334+
self.fn_sig.repr(tcx))
335+
}
336+
}
337+
338+
impl<'tcx> DeferredResolution<'tcx> for CallResolution<'tcx> {
339+
fn attempt_resolution<'a>(&self, fcx: &FnCtxt<'a,'tcx>) -> bool {
340+
debug!("attempt_resolution() {}",
341+
self.repr(fcx.tcx()));
342+
343+
// We may now know enough to figure out fn vs fnmut etc.
344+
match try_overloaded_call_traits(fcx, self.call_expr, self.callee_expr,
345+
self.adjusted_ty, self.autoderefref.clone()) {
346+
None => false,
347+
Some(method_callee) => {
348+
// One problem is that when we get here, we are going
349+
// to have a newly instantiated function signature
350+
// from the call trait. This has to be reconciled with
351+
// the older function signature we had before. In
352+
// principle we *should* be able to fn_sigs(), but we
353+
// can't because of the annoying need for a TypeTrace.
354+
// (This always bites me, should find a way to
355+
// refactor it.)
356+
let method_sig =
357+
ty::assert_no_late_bound_regions(fcx.tcx(),
358+
ty::ty_fn_sig(method_callee.ty));
359+
360+
debug!("attempt_resolution: method_callee={}",
361+
method_callee.repr(fcx.tcx()));
362+
363+
for (&method_arg_ty, &self_arg_ty) in
364+
method_sig.inputs[1..].iter().zip(self.fn_sig.inputs.iter())
365+
{
366+
demand::eqtype(fcx, self.call_expr.span, self_arg_ty, method_arg_ty);
367+
}
368+
369+
demand::eqtype(fcx,
370+
self.call_expr.span,
371+
method_sig.output.unwrap(),
372+
self.fn_sig.output.unwrap());
373+
374+
write_overloaded_call_method_map(fcx, self.call_expr, method_callee);
375+
376+
true
377+
}
378+
}
379+
}
380+
}

src/librustc_typeck/check/closure.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,8 @@ pub fn check_expr_closure<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>,
2626
expr: &ast::Expr,
2727
_capture: ast::CaptureClause,
2828
opt_kind: Option<ast::ClosureKind>,
29-
decl: &ast::FnDecl,
30-
body: &ast::Block,
29+
decl: &'tcx ast::FnDecl,
30+
body: &'tcx ast::Block,
3131
expected: Expectation<'tcx>) {
3232
debug!("check_expr_closure(expr={},expected={})",
3333
expr.repr(fcx.tcx()),
@@ -76,8 +76,8 @@ pub fn check_expr_closure<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>,
7676
fn check_closure<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>,
7777
expr: &ast::Expr,
7878
kind: ty::ClosureKind,
79-
decl: &ast::FnDecl,
80-
body: &ast::Block,
79+
decl: &'tcx ast::FnDecl,
80+
body: &'tcx ast::Block,
8181
expected_sig: Option<ty::FnSig<'tcx>>) {
8282
let expr_def_id = ast_util::local_def(expr.id);
8383

0 commit comments

Comments
 (0)