]> git.lizzy.rs Git - rust.git/blob - src/librustc_typeck/check/closure.rs
Auto merge of #35856 - phimuemue:master, r=brson
[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::AstConv;
16 use rustc::ty::{self, ToPolyTraitRef, Ty};
17 use std::cmp;
18 use syntax::abi::Abi;
19 use rustc::hir;
20
21 impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
22     pub fn check_expr_closure(&self,
23                               expr: &hir::Expr,
24                               _capture: hir::CaptureClause,
25                               decl: &'gcx hir::FnDecl,
26                               body: &'gcx 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(self) {
36             Some(ty) => self.deduce_expectations_from_expected_type(ty),
37             None => (None, None)
38         };
39         self.check_closure(expr, expected_kind, decl, body, expected_sig)
40     }
41
42     fn check_closure(&self,
43                      expr: &hir::Expr,
44                      opt_kind: Option<ty::ClosureKind>,
45                      decl: &'gcx hir::FnDecl,
46                      body: &'gcx hir::Block,
47                      expected_sig: Option<ty::FnSig<'tcx>>) {
48         let expr_def_id = self.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(self,
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 = self.tcx.with_freevars(expr.id, |fv| fv.len());
64         let upvar_tys = self.next_ty_vars(num_upvars);
65
66         debug!("check_closure: expr.id={:?} upvar_tys={:?}",
67                expr.id, upvar_tys);
68
69         let closure_type = self.tcx.mk_closure(expr_def_id,
70             self.parameter_environment.free_substs,
71             upvar_tys);
72
73         self.write_ty(expr.id, closure_type);
74
75         let fn_sig = self.tcx.liberate_late_bound_regions(
76             self.tcx.region_maps.call_site_extent(expr.id, body.id), &fn_ty.sig);
77         let fn_sig =
78             (**self).normalize_associated_types_in(body.span, body.id, &fn_sig);
79
80         check_fn(self, hir::Unsafety::Normal, expr.id, &fn_sig, decl, expr.id, &body);
81
82         // Tuple up the arguments and insert the resulting function type into
83         // the `closures` table.
84         fn_ty.sig.0.inputs = vec![self.tcx.mk_tup(fn_ty.sig.0.inputs)];
85
86         debug!("closure for {:?} --> sig={:?} opt_kind={:?}",
87                expr_def_id,
88                fn_ty.sig,
89                opt_kind);
90
91         self.tables.borrow_mut().closure_tys.insert(expr_def_id, fn_ty);
92         match opt_kind {
93             Some(kind) => { self.tables.borrow_mut().closure_kinds.insert(expr_def_id, kind); }
94             None => { }
95         }
96     }
97
98     fn deduce_expectations_from_expected_type(&self, expected_ty: Ty<'tcx>)
99         -> (Option<ty::FnSig<'tcx>>,Option<ty::ClosureKind>)
100     {
101         debug!("deduce_expectations_from_expected_type(expected_ty={:?})",
102                expected_ty);
103
104         match expected_ty.sty {
105             ty::TyTrait(ref object_type) => {
106                 let sig = object_type.projection_bounds.iter().filter_map(|pb| {
107                     let pb = pb.with_self_ty(self.tcx, self.tcx.types.err);
108                     self.deduce_sig_from_projection(&pb)
109                 }).next();
110                 let kind = self.tcx.lang_items.fn_trait_kind(object_type.principal.def_id());
111                 (sig, kind)
112             }
113             ty::TyInfer(ty::TyVar(vid)) => {
114                 self.deduce_expectations_from_obligations(vid)
115             }
116             _ => {
117                 (None, None)
118             }
119         }
120     }
121
122     fn deduce_expectations_from_obligations(&self, expected_vid: ty::TyVid)
123         -> (Option<ty::FnSig<'tcx>>, Option<ty::ClosureKind>)
124     {
125         let fulfillment_cx = self.fulfillment_cx.borrow();
126         // Here `expected_ty` is known to be a type inference variable.
127
128         let expected_sig =
129             fulfillment_cx
130             .pending_obligations()
131             .iter()
132             .map(|obligation| &obligation.obligation)
133             .filter_map(|obligation| {
134                 debug!("deduce_expectations_from_obligations: obligation.predicate={:?}",
135                        obligation.predicate);
136
137                 match obligation.predicate {
138                     // Given a Projection predicate, we can potentially infer
139                     // the complete signature.
140                     ty::Predicate::Projection(ref proj_predicate) => {
141                         let trait_ref = proj_predicate.to_poly_trait_ref();
142                         self.self_type_matches_expected_vid(trait_ref, expected_vid)
143                             .and_then(|_| self.deduce_sig_from_projection(proj_predicate))
144                     }
145                     _ => {
146                         None
147                     }
148                 }
149             })
150             .next();
151
152         // Even if we can't infer the full signature, we may be able to
153         // infer the kind. This can occur if there is a trait-reference
154         // like `F : Fn<A>`. Note that due to subtyping we could encounter
155         // many viable options, so pick the most restrictive.
156         let expected_kind =
157             fulfillment_cx
158             .pending_obligations()
159             .iter()
160             .map(|obligation| &obligation.obligation)
161             .filter_map(|obligation| {
162                 let opt_trait_ref = match obligation.predicate {
163                     ty::Predicate::Projection(ref data) => Some(data.to_poly_trait_ref()),
164                     ty::Predicate::Trait(ref data) => Some(data.to_poly_trait_ref()),
165                     ty::Predicate::Equate(..) => None,
166                     ty::Predicate::RegionOutlives(..) => None,
167                     ty::Predicate::TypeOutlives(..) => None,
168                     ty::Predicate::WellFormed(..) => None,
169                     ty::Predicate::ObjectSafe(..) => None,
170
171                     // NB: This predicate is created by breaking down a
172                     // `ClosureType: FnFoo()` predicate, where
173                     // `ClosureType` represents some `TyClosure`. It can't
174                     // possibly be referring to the current closure,
175                     // because we haven't produced the `TyClosure` for
176                     // this closure yet; this is exactly why the other
177                     // code is looking for a self type of a unresolved
178                     // inference variable.
179                     ty::Predicate::ClosureKind(..) => None,
180                 };
181                 opt_trait_ref
182                     .and_then(|tr| self.self_type_matches_expected_vid(tr, expected_vid))
183                     .and_then(|tr| self.tcx.lang_items.fn_trait_kind(tr.def_id()))
184             })
185             .fold(None, |best, cur| Some(best.map_or(cur, |best| cmp::min(best, cur))));
186
187         (expected_sig, expected_kind)
188     }
189
190     /// Given a projection like "<F as Fn(X)>::Result == Y", we can deduce
191     /// everything we need to know about a closure.
192     fn deduce_sig_from_projection(&self,
193         projection: &ty::PolyProjectionPredicate<'tcx>)
194         -> Option<ty::FnSig<'tcx>>
195     {
196         let tcx = self.tcx;
197
198         debug!("deduce_sig_from_projection({:?})",
199                projection);
200
201         let trait_ref = projection.to_poly_trait_ref();
202
203         if tcx.lang_items.fn_trait_kind(trait_ref.def_id()).is_none() {
204             return None;
205         }
206
207         let arg_param_ty = trait_ref.substs().type_at(1);
208         let arg_param_ty = self.resolve_type_vars_if_possible(&arg_param_ty);
209         debug!("deduce_sig_from_projection: arg_param_ty {:?}", arg_param_ty);
210
211         let input_tys = match arg_param_ty.sty {
212             ty::TyTuple(tys) => tys.to_vec(),
213             _ => { return None; }
214         };
215         debug!("deduce_sig_from_projection: input_tys {:?}", input_tys);
216
217         let ret_param_ty = projection.0.ty;
218         let ret_param_ty = self.resolve_type_vars_if_possible(&ret_param_ty);
219         debug!("deduce_sig_from_projection: ret_param_ty {:?}", ret_param_ty);
220
221         let fn_sig = ty::FnSig {
222             inputs: input_tys,
223             output: ret_param_ty,
224             variadic: false
225         };
226         debug!("deduce_sig_from_projection: fn_sig {:?}", fn_sig);
227
228         Some(fn_sig)
229     }
230
231     fn self_type_matches_expected_vid(&self,
232         trait_ref: ty::PolyTraitRef<'tcx>,
233         expected_vid: ty::TyVid)
234         -> Option<ty::PolyTraitRef<'tcx>>
235     {
236         let self_ty = self.shallow_resolve(trait_ref.self_ty());
237         debug!("self_type_matches_expected_vid(trait_ref={:?}, self_ty={:?})",
238                trait_ref,
239                self_ty);
240         match self_ty.sty {
241             ty::TyInfer(ty::TyVar(v)) if expected_vid == v => Some(trait_ref),
242             _ => None,
243         }
244     }
245 }