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};
17 use middle::ty::{self, ToPolyTraitRef, Ty};
22 pub fn check_expr_closure<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>,
24 _capture: hir::CaptureClause,
25 decl: &'tcx hir::FnDecl,
26 body: &'tcx hir::Block,
27 expected: Expectation<'tcx>) {
28 debug!("check_expr_closure(expr={:?},expected={:?})",
32 // It's always helpful for inference if we know the kind of
33 // closure sooner rather than later, so first examine the expected
34 // type, and see if can glean a closure kind from there.
35 let (expected_sig,expected_kind) = match expected.to_option(fcx) {
36 Some(ty) => deduce_expectations_from_expected_type(fcx, ty),
39 check_closure(fcx, expr, expected_kind, decl, body, expected_sig)
42 fn check_closure<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>,
44 opt_kind: Option<ty::ClosureKind>,
45 decl: &'tcx hir::FnDecl,
46 body: &'tcx hir::Block,
47 expected_sig: Option<ty::FnSig<'tcx>>) {
48 let expr_def_id = fcx.tcx().map.local_def_id(expr.id);
50 debug!("check_closure opt_kind={:?} expected_sig={:?}",
54 let mut fn_ty = astconv::ty_of_closure(fcx,
55 hir::Unsafety::Normal,
60 // Create type variables (for now) to represent the transformed
61 // types of upvars. These will be unified during the upvar
62 // inference phase (`upvar.rs`).
63 let num_upvars = fcx.tcx().with_freevars(expr.id, |fv| fv.len());
64 let upvar_tys = fcx.infcx().next_ty_vars(num_upvars);
66 debug!("check_closure: expr.id={:?} upvar_tys={:?}",
70 fcx.ccx.tcx.mk_closure(
72 fcx.ccx.tcx.mk_substs(fcx.inh.infcx.parameter_environment.free_substs.clone()),
75 fcx.write_ty(expr.id, closure_type);
77 let fn_sig = fcx.tcx().liberate_late_bound_regions(
78 fcx.tcx().region_maps.call_site_extent(expr.id, body.id), &fn_ty.sig);
81 hir::Unsafety::Normal,
89 // Tuple up the arguments and insert the resulting function type into
90 // the `closures` table.
91 fn_ty.sig.0.inputs = vec![fcx.tcx().mk_tup(fn_ty.sig.0.inputs)];
93 debug!("closure for {:?} --> sig={:?} opt_kind={:?}",
98 fcx.inh.tables.borrow_mut().closure_tys.insert(expr_def_id, fn_ty);
100 Some(kind) => { fcx.inh.tables.borrow_mut().closure_kinds.insert(expr_def_id, kind); }
105 fn deduce_expectations_from_expected_type<'a,'tcx>(
106 fcx: &FnCtxt<'a,'tcx>,
107 expected_ty: Ty<'tcx>)
108 -> (Option<ty::FnSig<'tcx>>,Option<ty::ClosureKind>)
110 debug!("deduce_expectations_from_expected_type(expected_ty={:?})",
113 match expected_ty.sty {
114 ty::TyTrait(ref object_type) => {
115 let proj_bounds = object_type.projection_bounds_with_self_ty(fcx.tcx(),
116 fcx.tcx().types.err);
117 let sig = proj_bounds.iter()
118 .filter_map(|pb| deduce_sig_from_projection(fcx, pb))
120 let kind = fcx.tcx().lang_items.fn_trait_kind(object_type.principal_def_id());
123 ty::TyInfer(ty::TyVar(vid)) => {
124 deduce_expectations_from_obligations(fcx, vid)
132 fn deduce_expectations_from_obligations<'a,'tcx>(
133 fcx: &FnCtxt<'a,'tcx>,
134 expected_vid: ty::TyVid)
135 -> (Option<ty::FnSig<'tcx>>, Option<ty::ClosureKind>)
137 let fulfillment_cx = fcx.inh.infcx.fulfillment_cx.borrow();
138 // Here `expected_ty` is known to be a type inference variable.
142 .pending_obligations()
144 .map(|obligation| &obligation.obligation)
145 .filter_map(|obligation| {
146 debug!("deduce_expectations_from_obligations: obligation.predicate={:?}",
147 obligation.predicate);
149 match obligation.predicate {
150 // Given a Projection predicate, we can potentially infer
151 // the complete signature.
152 ty::Predicate::Projection(ref proj_predicate) => {
153 let trait_ref = proj_predicate.to_poly_trait_ref();
154 self_type_matches_expected_vid(fcx, trait_ref, expected_vid)
155 .and_then(|_| deduce_sig_from_projection(fcx, proj_predicate))
164 // Even if we can't infer the full signature, we may be able to
165 // infer the kind. This can occur if there is a trait-reference
166 // like `F : Fn<A>`. Note that due to subtyping we could encounter
167 // many viable options, so pick the most restrictive.
170 .pending_obligations()
172 .map(|obligation| &obligation.obligation)
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,
180 ty::Predicate::WellFormed(..) => None,
181 ty::Predicate::ObjectSafe(..) => None,
184 .and_then(|trait_ref| self_type_matches_expected_vid(fcx, trait_ref, expected_vid))
185 .and_then(|trait_ref| fcx.tcx().lang_items.fn_trait_kind(trait_ref.def_id()))
187 .fold(None, pick_most_restrictive_closure_kind);
189 (expected_sig, expected_kind)
192 fn pick_most_restrictive_closure_kind(best: Option<ty::ClosureKind>,
193 cur: ty::ClosureKind)
194 -> Option<ty::ClosureKind>
198 Some(best) => Some(cmp::min(best, cur))
202 /// Given a projection like "<F as Fn(X)>::Result == Y", we can deduce
203 /// everything we need to know about a closure.
204 fn deduce_sig_from_projection<'a,'tcx>(
205 fcx: &FnCtxt<'a,'tcx>,
206 projection: &ty::PolyProjectionPredicate<'tcx>)
207 -> Option<ty::FnSig<'tcx>>
211 debug!("deduce_sig_from_projection({:?})",
214 let trait_ref = projection.to_poly_trait_ref();
216 if tcx.lang_items.fn_trait_kind(trait_ref.def_id()).is_none() {
220 let arg_param_ty = *trait_ref.substs().types.get(subst::TypeSpace, 0);
221 let arg_param_ty = fcx.infcx().resolve_type_vars_if_possible(&arg_param_ty);
222 debug!("deduce_sig_from_projection: arg_param_ty {:?}", arg_param_ty);
224 let input_tys = match arg_param_ty.sty {
225 ty::TyTuple(ref tys) => { (*tys).clone() }
226 _ => { return None; }
228 debug!("deduce_sig_from_projection: input_tys {:?}", input_tys);
230 let ret_param_ty = projection.0.ty;
231 let ret_param_ty = fcx.infcx().resolve_type_vars_if_possible(&ret_param_ty);
232 debug!("deduce_sig_from_projection: ret_param_ty {:?}", ret_param_ty);
234 let fn_sig = ty::FnSig {
236 output: ty::FnConverging(ret_param_ty),
239 debug!("deduce_sig_from_projection: fn_sig {:?}", fn_sig);
244 fn self_type_matches_expected_vid<'a,'tcx>(
245 fcx: &FnCtxt<'a,'tcx>,
246 trait_ref: ty::PolyTraitRef<'tcx>,
247 expected_vid: ty::TyVid)
248 -> Option<ty::PolyTraitRef<'tcx>>
250 let self_ty = fcx.infcx().shallow_resolve(trait_ref.self_ty());
251 debug!("self_type_matches_expected_vid(trait_ref={:?}, self_ty={:?})",
255 ty::TyInfer(ty::TyVar(v)) if expected_vid == v => Some(trait_ref),