Skip to content

Commit 053383d

Browse files
committed
new rules for merging expected/supplied types in closure signatures
Also, fix numbering in mir-opt tests. We are now anonymizing more consistently, I think, and hence some of the `TyAnon` indices shifted.
1 parent ea4db35 commit 053383d

18 files changed

+646
-68
lines changed

src/librustc_typeck/check/closure.rs

+204-64
Original file line numberDiff line numberDiff line change
@@ -13,14 +13,22 @@
1313
use super::{check_fn, Expectation, FnCtxt};
1414

1515
use astconv::AstConv;
16+
use rustc::hir::def_id::DefId;
17+
use rustc::infer::LateBoundRegionConversionTime;
1618
use rustc::infer::type_variable::TypeVariableOrigin;
1719
use rustc::ty::{self, ToPolyTraitRef, Ty};
1820
use rustc::ty::subst::Substs;
21+
use rustc::ty::TypeFoldable;
1922
use std::cmp;
2023
use std::iter;
2124
use syntax::abi::Abi;
2225
use rustc::hir;
2326

27+
struct ClosureSignatures<'tcx> {
28+
bound_sig: ty::PolyFnSig<'tcx>,
29+
liberated_sig: ty::FnSig<'tcx>,
30+
}
31+
2432
impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
2533
pub fn check_expr_closure(&self,
2634
expr: &hir::Expr,
@@ -56,15 +64,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
5664
expected_sig);
5765

5866
let expr_def_id = self.tcx.hir.local_def_id(expr.id);
59-
let sig = self.ty_of_closure(decl, expected_sig);
6067

61-
debug!("check_closure: ty_of_closure returns {:?}", sig);
68+
let ClosureSignatures { bound_sig, liberated_sig } =
69+
self.sig_of_closure(expr_def_id, decl, body, expected_sig);
6270

63-
// `deduce_expectations_from_expected_type` introduces late-bound
64-
// lifetimes defined elsewhere, which we need to anonymize away.
65-
let sig = self.tcx.anonymize_late_bound_regions(&sig);
71+
debug!("check_closure: ty_of_closure returns {:?}", liberated_sig);
6672

67-
debug!("check_closure: anonymized sig={:?}", sig);
73+
let interior = check_fn(self, self.param_env, liberated_sig, decl, expr.id, body, true).1;
6874

6975
// Create type variables (for now) to represent the transformed
7076
// types of upvars. These will be unified during the upvar
@@ -75,14 +81,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
7581
|_, _| span_bug!(expr.span, "closure has region param"),
7682
|_, _| self.infcx.next_ty_var(TypeVariableOrigin::TransformedUpvar(expr.span))
7783
);
78-
79-
let fn_sig = self.liberate_late_bound_regions(expr_def_id, &sig);
80-
let fn_sig = self.inh.normalize_associated_types_in(body.value.span,
81-
body.value.id,
82-
self.param_env,
83-
&fn_sig);
84-
85-
let interior = check_fn(self, self.param_env, fn_sig, decl, expr.id, body, true).1;
84+
let closure_type = self.tcx.mk_closure(expr_def_id, substs);
8685

8786
if let Some(interior) = interior {
8887
let closure_substs = ty::ClosureSubsts {
@@ -91,13 +90,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
9190
return self.tcx.mk_generator(expr_def_id, closure_substs, interior);
9291
}
9392

94-
let closure_type = self.tcx.mk_closure(expr_def_id, substs);
95-
9693
debug!("check_closure: expr.id={:?} closure_type={:?}", expr.id, closure_type);
9794

9895
// Tuple up the arguments and insert the resulting function type into
9996
// the `closures` table.
100-
let sig = sig.map_bound(|sig| self.tcx.mk_fn_sig(
97+
let sig = bound_sig.map_bound(|sig| self.tcx.mk_fn_sig(
10198
iter::once(self.tcx.intern_tup(sig.inputs(), false)),
10299
sig.output(),
103100
sig.variadic,
@@ -271,71 +268,214 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
271268
}
272269
}
273270

271+
fn sig_of_closure(&self,
272+
expr_def_id: DefId,
273+
decl: &hir::FnDecl,
274+
body: &hir::Body,
275+
expected_sig: Option<ty::FnSig<'tcx>>)
276+
-> ClosureSignatures<'tcx>
277+
{
278+
if let Some(e) = expected_sig {
279+
self.sig_of_closure_with_expectation(expr_def_id, decl, body, e)
280+
} else {
281+
self.sig_of_closure_no_expectation(expr_def_id, decl, body)
282+
}
283+
}
284+
285+
/// If there is no expected signature, then we will convert the
286+
/// types that the user gave into a signature.
287+
fn sig_of_closure_no_expectation(&self,
288+
expr_def_id: DefId,
289+
decl: &hir::FnDecl,
290+
body: &hir::Body)
291+
-> ClosureSignatures<'tcx>
292+
{
293+
debug!("sig_of_closure_no_expectation()");
294+
295+
let bound_sig = self.supplied_sig_of_closure(decl);
296+
297+
self.closure_sigs(expr_def_id, body, bound_sig)
298+
}
299+
274300
/// Invoked to compute the signature of a closure expression. This
275301
/// combines any user-provided type annotations (e.g., `|x: u32|
276302
/// -> u32 { .. }`) with the expected signature.
277303
///
278-
/// The arguments here are a bit odd-ball:
304+
/// The approach is as follows:
305+
///
306+
/// - Let `S` be the (higher-ranked) signature that we derive from the user's annotations.
307+
/// - Let `E` be the (higher-ranked) signature that we derive from the expectations, if any.
308+
/// - If we have no expectation `E`, then the signature of the closure is `S`.
309+
/// - Otherwise, the signature of the closure is E. Moreover:
310+
/// - Skolemize the late-bound regions in `E`, yielding `E'`.
311+
/// - Instantiate all the late-bound regions bound in the closure within `S`
312+
/// with fresh (existential) variables, yielding `S'`
313+
/// - Require that `E' = S'`
314+
/// - We could use some kind of subtyping relationship here,
315+
/// I imagine, but equality is easier and works fine for
316+
/// our purposes.
317+
///
318+
/// The key intuition here is that the user's types must be valid
319+
/// from "the inside" of the closure, but the expectation
320+
/// ultimately drives the overall signature.
321+
///
322+
/// # Examples
323+
///
324+
/// ```
325+
/// fn with_closure<F>(_: F)
326+
/// where F: Fn(&u32) -> &u32 { .. }
327+
///
328+
/// with_closure(|x: &u32| { ... })
329+
/// ```
330+
///
331+
/// Here:
332+
/// - E would be `fn(&u32) -> &u32`.
333+
/// - S would be `fn(&u32) ->
334+
/// - E' is `&'!0 u32 -> &'!0 u32`
335+
/// - S' is `&'?0 u32 -> ?T`
336+
///
337+
/// S' can be unified with E' with `['?0 = '!0, ?T = &'!10 u32]`.
338+
///
339+
/// # Arguments
279340
///
341+
/// - `expr_def_id`: the def-id of the closure expression
280342
/// - `decl`: the HIR declaration of the closure
343+
/// - `body`: the body of the closure
281344
/// - `expected_sig`: the expected signature (if any). Note that
282345
/// this is missing a binder: that is, there may be late-bound
283346
/// regions with depth 1, which are bound then by the closure.
284-
fn ty_of_closure(&self,
285-
decl: &hir::FnDecl,
286-
expected_sig: Option<ty::FnSig<'tcx>>)
287-
-> ty::PolyFnSig<'tcx>
347+
fn sig_of_closure_with_expectation(&self,
348+
expr_def_id: DefId,
349+
decl: &hir::FnDecl,
350+
body: &hir::Body,
351+
expected_sig: ty::FnSig<'tcx>)
352+
-> ClosureSignatures<'tcx>
288353
{
289-
let astconv: &AstConv = self;
290-
291-
debug!("ty_of_closure(expected_sig={:?})",
292-
expected_sig);
354+
debug!("sig_of_closure_with_expectation(expected_sig={:?})", expected_sig);
355+
356+
// Watch out for some surprises and just ignore the
357+
// expectation if things don't see to match up with what we
358+
// expect.
359+
if expected_sig.variadic != decl.variadic {
360+
return self.sig_of_closure_no_expectation(expr_def_id, decl, body);
361+
} else if expected_sig.inputs_and_output.len() != decl.inputs.len() + 1 {
362+
// we could probably handle this case more gracefully
363+
return self.sig_of_closure_no_expectation(expr_def_id, decl, body);
364+
}
293365

294-
let input_tys = decl.inputs.iter().enumerate().map(|(i, a)| {
295-
let expected_arg_ty = expected_sig.as_ref().and_then(|e| {
296-
// no guarantee that the correct number of expected args
297-
// were supplied
298-
if i < e.inputs().len() {
299-
Some(e.inputs()[i])
300-
} else {
301-
None
302-
}
303-
});
366+
// Create a `PolyFnSig`. Note the oddity that late bound
367+
// regions appearing free in `expected_sig` are now bound up
368+
// in this binder we are creating.
369+
assert!(!expected_sig.has_regions_escaping_depth(1));
370+
let bound_sig =
371+
ty::Binder(self.tcx.mk_fn_sig(
372+
expected_sig.inputs().iter().cloned(),
373+
expected_sig.output(),
374+
decl.variadic,
375+
hir::Unsafety::Normal,
376+
Abi::RustCall));
377+
378+
// `deduce_expectations_from_expected_type` introduces
379+
// late-bound lifetimes defined elsewhere, which we now
380+
// anonymize away, so as not to confuse the user.
381+
let bound_sig = self.tcx.anonymize_late_bound_regions(&bound_sig);
382+
383+
let closure_sigs = self.closure_sigs(expr_def_id, body, bound_sig);
384+
385+
// Up till this point, we have ignored the annotations that the user
386+
// gave. This function will check that they unify successfully.
387+
// Along the way, it also writes out entries for types that the user
388+
// wrote into our tables, which are then later used by the privacy
389+
// check.
390+
self.check_supplied_sig_against_expectation(decl, &closure_sigs);
391+
392+
closure_sigs
393+
}
304394

305-
let input_ty = astconv.ty_of_arg(a, expected_arg_ty);
306-
debug!("ty_of_closure: i={} input_ty={:?} expected_arg_ty={:?}",
307-
i, input_ty, expected_arg_ty);
395+
/// Enforce the user's types against the expectation. See
396+
/// `sig_of_closure_with_expectation` for details on the overall
397+
/// strategy.
398+
fn check_supplied_sig_against_expectation(&self,
399+
decl: &hir::FnDecl,
400+
expected_sigs: &ClosureSignatures<'tcx>)
401+
{
402+
// Get the signature S that the user gave.
403+
//
404+
// (See comment on `sig_of_closure_with_expectation` for the
405+
// meaning of these letters.)
406+
let supplied_sig = self.supplied_sig_of_closure(decl);
407+
408+
debug!("check_supplied_sig_against_expectation: supplied_sig={:?}",
409+
supplied_sig);
410+
411+
// The liberated version of this signature should be be a subtype
412+
// of the liberated form of the expectation.
413+
for ((hir_ty, &supplied_ty), expected_ty) in
414+
decl.inputs.iter()
415+
.zip(*supplied_sig.inputs().skip_binder()) // binder moved to (*) below
416+
.zip(expected_sigs.liberated_sig.inputs()) // `liberated_sig` is E'.
417+
{
418+
// Instantiate (this part of..) S to S', i.e., with fresh variables.
419+
let (supplied_ty, _) = self.infcx.replace_late_bound_regions_with_fresh_var(
420+
hir_ty.span,
421+
LateBoundRegionConversionTime::FnCall,
422+
&ty::Binder(supplied_ty)); // recreated from (*) above
423+
424+
// Check that E' = S'.
425+
self.demand_eqtype(hir_ty.span, expected_ty, supplied_ty);
426+
}
308427

309-
input_ty
310-
});
428+
let (supplied_output_ty, _) = self.infcx.replace_late_bound_regions_with_fresh_var(
429+
decl.output.span(),
430+
LateBoundRegionConversionTime::FnCall,
431+
&supplied_sig.output());
432+
self.demand_eqtype(decl.output.span(),
433+
expected_sigs.liberated_sig.output(),
434+
supplied_output_ty);
435+
}
311436

312-
let expected_ret_ty = expected_sig.as_ref().map(|e| e.output());
437+
/// If there is no expected signature, then we will convert the
438+
/// types that the user gave into a signature.
439+
fn supplied_sig_of_closure(&self,
440+
decl: &hir::FnDecl)
441+
-> ty::PolyFnSig<'tcx>
442+
{
443+
let astconv: &AstConv = self;
313444

314-
let output_ty = match decl.output {
315-
hir::Return(ref output) => {
316-
if let (&hir::TyInfer, Some(expected_ret_ty)) = (&output.node, expected_ret_ty) {
317-
astconv.record_ty(output.hir_id, expected_ret_ty, output.span);
318-
expected_ret_ty
319-
} else {
320-
astconv.ast_ty_to_ty(&output)
321-
}
322-
}
323-
hir::DefaultReturn(span) => {
324-
if let Some(expected_ret_ty) = expected_ret_ty {
325-
expected_ret_ty
326-
} else {
327-
astconv.ty_infer(span)
328-
}
329-
}
445+
// First, convert the types that the user supplied (if any).
446+
let supplied_arguments =
447+
decl.inputs
448+
.iter()
449+
.map(|a| astconv.ast_ty_to_ty(a));
450+
let supplied_return = match decl.output {
451+
hir::Return(ref output) => astconv.ast_ty_to_ty(&output),
452+
hir::DefaultReturn(_) => astconv.ty_infer(decl.output.span()),
330453
};
331454

332-
debug!("ty_of_closure: output_ty={:?}", output_ty);
333-
334-
ty::Binder(self.tcx.mk_fn_sig(
335-
input_tys,
336-
output_ty,
455+
let result = ty::Binder(self.tcx.mk_fn_sig(
456+
supplied_arguments,
457+
supplied_return,
337458
decl.variadic,
338459
hir::Unsafety::Normal,
339-
Abi::RustCall))
460+
Abi::RustCall));
461+
462+
debug!("supplied_sig_of_closure: result={:?}", result);
463+
464+
result
465+
}
466+
467+
fn closure_sigs(&self,
468+
expr_def_id: DefId,
469+
body: &hir::Body,
470+
bound_sig: ty::PolyFnSig<'tcx>)
471+
-> ClosureSignatures<'tcx>
472+
{
473+
let liberated_sig = self.liberate_late_bound_regions(expr_def_id, &bound_sig);
474+
let liberated_sig = self.inh.normalize_associated_types_in(body.value.span,
475+
body.value.id,
476+
self.param_env,
477+
&liberated_sig);
478+
ClosureSignatures { bound_sig, liberated_sig }
340479
}
341480
}
481+

src/librustc_typeck/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ This API is completely unstable and subject to change.
7676
#![feature(box_patterns)]
7777
#![feature(box_syntax)]
7878
#![feature(conservative_impl_trait)]
79+
#![feature(match_default_bindings)]
7980
#![feature(never_type)]
8081
#![feature(quote)]
8182
#![feature(rustc_diagnostic_macros)]
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
See `src/test/run-pass/closure-expected-type`.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
// Copyright 2016 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+
// must-compile-successfully
12+
13+
#![feature(underscore_lifetimes)]
14+
#![allow(warnings)]
15+
16+
type Different<'a, 'b> = &'a mut (&'a (), &'b ());
17+
type Same<'a> = Different<'a, 'a>;
18+
19+
fn with_closure_expecting_different<F>(_: F)
20+
where F: for<'a, 'b> FnOnce(Different<'a, 'b>)
21+
{
22+
}
23+
24+
fn with_closure_expecting_different_anon<F>(_: F)
25+
where F: FnOnce(Different<'_, '_>)
26+
{
27+
}
28+
29+
fn supplying_nothing_expecting_anon() {
30+
with_closure_expecting_different_anon(|x: Different| {
31+
})
32+
}
33+
34+
fn supplying_nothing_expecting_named() {
35+
with_closure_expecting_different(|x: Different| {
36+
})
37+
}
38+
39+
fn supplying_underscore_expecting_anon() {
40+
with_closure_expecting_different_anon(|x: Different<'_, '_>| {
41+
})
42+
}
43+
44+
fn supplying_underscore_expecting_named() {
45+
with_closure_expecting_different(|x: Different<'_, '_>| {
46+
})
47+
}
48+
49+
fn main() { }

0 commit comments

Comments
 (0)