1 // Copyright 2014 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.
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.
11 //! Code for type-checking closure expressions.
13 use super::{check_fn, Expectation, FnCtxt}
;
18 use middle
::ty
::{self, ToPolyTraitRef, Ty}
;
24 pub fn check_expr_closure
<'a
,'tcx
>(fcx
: &FnCtxt
<'a
,'tcx
>,
26 _capture
: ast
::CaptureClause
,
27 decl
: &'tcx ast
::FnDecl
,
28 body
: &'tcx ast
::Block
,
29 expected
: Expectation
<'tcx
>) {
30 debug
!("check_expr_closure(expr={:?},expected={:?})",
34 // It's always helpful for inference if we know the kind of
35 // closure sooner rather than later, so first examine the expected
36 // type, and see if can glean a closure kind from there.
37 let (expected_sig
,expected_kind
) = match expected
.to_option(fcx
) {
38 Some(ty
) => deduce_expectations_from_expected_type(fcx
, ty
),
41 check_closure(fcx
, expr
, expected_kind
, decl
, body
, expected_sig
)
44 fn check_closure
<'a
,'tcx
>(fcx
: &FnCtxt
<'a
,'tcx
>,
46 opt_kind
: Option
<ty
::ClosureKind
>,
47 decl
: &'tcx ast
::FnDecl
,
48 body
: &'tcx ast
::Block
,
49 expected_sig
: Option
<ty
::FnSig
<'tcx
>>) {
50 let expr_def_id
= ast_util
::local_def(expr
.id
);
52 debug
!("check_closure opt_kind={:?} expected_sig={:?}",
56 let mut fn_ty
= astconv
::ty_of_closure(fcx
,
57 ast
::Unsafety
::Normal
,
62 // Create type variables (for now) to represent the transformed
63 // types of upvars. These will be unified during the upvar
64 // inference phase (`upvar.rs`).
65 let num_upvars
= fcx
.tcx().with_freevars(expr
.id
, |fv
| fv
.len());
66 let upvar_tys
= fcx
.infcx().next_ty_vars(num_upvars
);
68 debug
!("check_closure: expr.id={:?} upvar_tys={:?}",
72 fcx
.ccx
.tcx
.mk_closure(
74 fcx
.ccx
.tcx
.mk_substs(fcx
.inh
.infcx
.parameter_environment
.free_substs
.clone()),
77 fcx
.write_ty(expr
.id
, closure_type
);
79 let fn_sig
= fcx
.tcx().liberate_late_bound_regions(
80 region
::DestructionScopeData
::new(body
.id
), &fn_ty
.sig
);
83 ast
::Unsafety
::Normal
,
91 // Tuple up the arguments and insert the resulting function type into
92 // the `closures` table.
93 fn_ty
.sig
.0.inputs
= vec
![fcx
.tcx().mk_tup(fn_ty
.sig
.0.inputs
)];
95 debug
!("closure for {:?} --> sig={:?} opt_kind={:?}",
100 fcx
.inh
.tables
.borrow_mut().closure_tys
.insert(expr_def_id
, fn_ty
);
102 Some(kind
) => { fcx.inh.tables.borrow_mut().closure_kinds.insert(expr_def_id, kind); }
107 fn deduce_expectations_from_expected_type
<'a
,'tcx
>(
108 fcx
: &FnCtxt
<'a
,'tcx
>,
109 expected_ty
: Ty
<'tcx
>)
110 -> (Option
<ty
::FnSig
<'tcx
>>,Option
<ty
::ClosureKind
>)
112 debug
!("deduce_expectations_from_expected_type(expected_ty={:?})",
115 match expected_ty
.sty
{
116 ty
::TyTrait(ref object_type
) => {
117 let proj_bounds
= object_type
.projection_bounds_with_self_ty(fcx
.tcx(),
118 fcx
.tcx().types
.err
);
119 let sig
= proj_bounds
.iter()
120 .filter_map(|pb
| deduce_sig_from_projection(fcx
, pb
))
122 let kind
= fcx
.tcx().lang_items
.fn_trait_kind(object_type
.principal_def_id());
125 ty
::TyInfer(ty
::TyVar(vid
)) => {
126 deduce_expectations_from_obligations(fcx
, vid
)
134 fn deduce_expectations_from_obligations
<'a
,'tcx
>(
135 fcx
: &FnCtxt
<'a
,'tcx
>,
136 expected_vid
: ty
::TyVid
)
137 -> (Option
<ty
::FnSig
<'tcx
>>, Option
<ty
::ClosureKind
>)
139 let fulfillment_cx
= fcx
.inh
.infcx
.fulfillment_cx
.borrow();
140 // Here `expected_ty` is known to be a type inference variable.
144 .pending_obligations()
146 .filter_map(|obligation
| {
147 debug
!("deduce_expectations_from_obligations: obligation.predicate={:?}",
148 obligation
.predicate
);
150 match obligation
.predicate
{
151 // Given a Projection predicate, we can potentially infer
152 // the complete signature.
153 ty
::Predicate
::Projection(ref proj_predicate
) => {
154 let trait_ref
= proj_predicate
.to_poly_trait_ref();
155 self_type_matches_expected_vid(fcx
, trait_ref
, expected_vid
)
156 .and_then(|_
| deduce_sig_from_projection(fcx
, proj_predicate
))
165 // Even if we can't infer the full signature, we may be able to
166 // infer the kind. This can occur if there is a trait-reference
167 // like `F : Fn<A>`. Note that due to subtyping we could encounter
168 // many viable options, so pick the most restrictive.
171 .pending_obligations()
173 .filter_map(|obligation
| {
174 let opt_trait_ref
= match obligation
.predicate
{
175 ty
::Predicate
::Projection(ref data
) => Some(data
.to_poly_trait_ref()),
176 ty
::Predicate
::Trait(ref data
) => Some(data
.to_poly_trait_ref()),
177 ty
::Predicate
::Equate(..) => None
,
178 ty
::Predicate
::RegionOutlives(..) => None
,
179 ty
::Predicate
::TypeOutlives(..) => None
,
182 .and_then(|trait_ref
| self_type_matches_expected_vid(fcx
, trait_ref
, expected_vid
))
183 .and_then(|trait_ref
| fcx
.tcx().lang_items
.fn_trait_kind(trait_ref
.def_id()))
185 .fold(None
, pick_most_restrictive_closure_kind
);
187 (expected_sig
, expected_kind
)
190 fn pick_most_restrictive_closure_kind(best
: Option
<ty
::ClosureKind
>,
191 cur
: ty
::ClosureKind
)
192 -> Option
<ty
::ClosureKind
>
196 Some(best
) => Some(cmp
::min(best
, cur
))
200 /// Given a projection like "<F as Fn(X)>::Result == Y", we can deduce
201 /// everything we need to know about a closure.
202 fn deduce_sig_from_projection
<'a
,'tcx
>(
203 fcx
: &FnCtxt
<'a
,'tcx
>,
204 projection
: &ty
::PolyProjectionPredicate
<'tcx
>)
205 -> Option
<ty
::FnSig
<'tcx
>>
209 debug
!("deduce_sig_from_projection({:?})",
212 let trait_ref
= projection
.to_poly_trait_ref();
214 if tcx
.lang_items
.fn_trait_kind(trait_ref
.def_id()).is_none() {
218 let arg_param_ty
= *trait_ref
.substs().types
.get(subst
::TypeSpace
, 0);
219 let arg_param_ty
= fcx
.infcx().resolve_type_vars_if_possible(&arg_param_ty
);
220 debug
!("deduce_sig_from_projection: arg_param_ty {:?}", arg_param_ty
);
222 let input_tys
= match arg_param_ty
.sty
{
223 ty
::TyTuple(ref tys
) => { (*tys).clone() }
224 _
=> { return None; }
226 debug
!("deduce_sig_from_projection: input_tys {:?}", input_tys
);
228 let ret_param_ty
= projection
.0.ty
;
229 let ret_param_ty
= fcx
.infcx().resolve_type_vars_if_possible(&ret_param_ty
);
230 debug
!("deduce_sig_from_projection: ret_param_ty {:?}", ret_param_ty
);
232 let fn_sig
= ty
::FnSig
{
234 output
: ty
::FnConverging(ret_param_ty
),
237 debug
!("deduce_sig_from_projection: fn_sig {:?}", fn_sig
);
242 fn self_type_matches_expected_vid
<'a
,'tcx
>(
243 fcx
: &FnCtxt
<'a
,'tcx
>,
244 trait_ref
: ty
::PolyTraitRef
<'tcx
>,
245 expected_vid
: ty
::TyVid
)
246 -> Option
<ty
::PolyTraitRef
<'tcx
>>
248 let self_ty
= fcx
.infcx().shallow_resolve(trait_ref
.self_ty());
249 debug
!("self_type_matches_expected_vid(trait_ref={:?}, self_ty={:?})",
253 ty
::TyInfer(ty
::TyVar(v
)) if expected_vid
== v
=> Some(trait_ref
),