]> git.lizzy.rs Git - rust.git/blob - src/librustc_typeck/check/closure.rs
Auto merge of #30036 - mitaa:doc_id, r=alexcrichton
[rust.git] / src / librustc_typeck / check / closure.rs
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.
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 //! Code for type-checking closure expressions.
12
13 use super::{check_fn, Expectation, FnCtxt};
14
15 use astconv;
16 use middle::subst;
17 use middle::ty::{self, ToPolyTraitRef, Ty};
18 use std::cmp;
19 use syntax::abi;
20 use rustc_front::hir;
21
22 pub fn check_expr_closure<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>,
23                                    expr: &hir::Expr,
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={:?})",
29            expr,
30            expected);
31
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),
37         None => (None, None)
38     };
39     check_closure(fcx, expr, expected_kind, decl, body, expected_sig)
40 }
41
42 fn check_closure<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>,
43                           expr: &hir::Expr,
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);
49
50     debug!("check_closure opt_kind={:?} expected_sig={:?}",
51            opt_kind,
52            expected_sig);
53
54     let mut fn_ty = astconv::ty_of_closure(fcx,
55                                            hir::Unsafety::Normal,
56                                            decl,
57                                            abi::RustCall,
58                                            expected_sig);
59
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);
65
66     debug!("check_closure: expr.id={:?} upvar_tys={:?}",
67            expr.id, upvar_tys);
68
69     let closure_type =
70         fcx.ccx.tcx.mk_closure(
71             expr_def_id,
72             fcx.ccx.tcx.mk_substs(fcx.inh.infcx.parameter_environment.free_substs.clone()),
73             upvar_tys);
74
75     fcx.write_ty(expr.id, closure_type);
76
77     let fn_sig = fcx.tcx().liberate_late_bound_regions(
78         fcx.tcx().region_maps.item_extent(body.id), &fn_ty.sig);
79
80     check_fn(fcx.ccx,
81              hir::Unsafety::Normal,
82              expr.id,
83              &fn_sig,
84              decl,
85              expr.id,
86              &*body,
87              fcx.inh);
88
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)];
92
93     debug!("closure for {:?} --> sig={:?} opt_kind={:?}",
94            expr_def_id,
95            fn_ty.sig,
96            opt_kind);
97
98     fcx.inh.tables.borrow_mut().closure_tys.insert(expr_def_id, fn_ty);
99     match opt_kind {
100         Some(kind) => { fcx.inh.tables.borrow_mut().closure_kinds.insert(expr_def_id, kind); }
101         None => { }
102     }
103 }
104
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>)
109 {
110     debug!("deduce_expectations_from_expected_type(expected_ty={:?})",
111            expected_ty);
112
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))
119                                  .next();
120             let kind = fcx.tcx().lang_items.fn_trait_kind(object_type.principal_def_id());
121             (sig, kind)
122         }
123         ty::TyInfer(ty::TyVar(vid)) => {
124             deduce_expectations_from_obligations(fcx, vid)
125         }
126         _ => {
127             (None, None)
128         }
129     }
130 }
131
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>)
136 {
137     let fulfillment_cx = fcx.inh.infcx.fulfillment_cx.borrow();
138     // Here `expected_ty` is known to be a type inference variable.
139
140     let expected_sig =
141         fulfillment_cx
142         .pending_obligations()
143         .iter()
144         .filter_map(|obligation| {
145             debug!("deduce_expectations_from_obligations: obligation.predicate={:?}",
146                    obligation.predicate);
147
148             match obligation.predicate {
149                 // Given a Projection predicate, we can potentially infer
150                 // the complete signature.
151                 ty::Predicate::Projection(ref proj_predicate) => {
152                     let trait_ref = proj_predicate.to_poly_trait_ref();
153                     self_type_matches_expected_vid(fcx, trait_ref, expected_vid)
154                         .and_then(|_| deduce_sig_from_projection(fcx, proj_predicate))
155                 }
156                 _ => {
157                     None
158                 }
159             }
160         })
161         .next();
162
163     // Even if we can't infer the full signature, we may be able to
164     // infer the kind. This can occur if there is a trait-reference
165     // like `F : Fn<A>`. Note that due to subtyping we could encounter
166     // many viable options, so pick the most restrictive.
167     let expected_kind =
168         fulfillment_cx
169         .pending_obligations()
170         .iter()
171         .filter_map(|obligation| {
172             let opt_trait_ref = match obligation.predicate {
173                 ty::Predicate::Projection(ref data) => Some(data.to_poly_trait_ref()),
174                 ty::Predicate::Trait(ref data) => Some(data.to_poly_trait_ref()),
175                 ty::Predicate::Equate(..) => None,
176                 ty::Predicate::RegionOutlives(..) => None,
177                 ty::Predicate::TypeOutlives(..) => None,
178                 ty::Predicate::WellFormed(..) => None,
179                 ty::Predicate::ObjectSafe(..) => None,
180             };
181             opt_trait_ref
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()))
184         })
185         .fold(None, pick_most_restrictive_closure_kind);
186
187     (expected_sig, expected_kind)
188 }
189
190 fn pick_most_restrictive_closure_kind(best: Option<ty::ClosureKind>,
191                                       cur: ty::ClosureKind)
192                                       -> Option<ty::ClosureKind>
193 {
194     match best {
195         None => Some(cur),
196         Some(best) => Some(cmp::min(best, cur))
197     }
198 }
199
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>>
206 {
207     let tcx = fcx.tcx();
208
209     debug!("deduce_sig_from_projection({:?})",
210            projection);
211
212     let trait_ref = projection.to_poly_trait_ref();
213
214     if tcx.lang_items.fn_trait_kind(trait_ref.def_id()).is_none() {
215         return None;
216     }
217
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);
221
222     let input_tys = match arg_param_ty.sty {
223         ty::TyTuple(ref tys) => { (*tys).clone() }
224         _ => { return None; }
225     };
226     debug!("deduce_sig_from_projection: input_tys {:?}", input_tys);
227
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);
231
232     let fn_sig = ty::FnSig {
233         inputs: input_tys,
234         output: ty::FnConverging(ret_param_ty),
235         variadic: false
236     };
237     debug!("deduce_sig_from_projection: fn_sig {:?}", fn_sig);
238
239     Some(fn_sig)
240 }
241
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>>
247 {
248     let self_ty = fcx.infcx().shallow_resolve(trait_ref.self_ty());
249     debug!("self_type_matches_expected_vid(trait_ref={:?}, self_ty={:?})",
250            trait_ref,
251            self_ty);
252     match self_ty.sty {
253         ty::TyInfer(ty::TyVar(v)) if expected_vid == v => Some(trait_ref),
254         _ => None,
255     }
256 }