]> git.lizzy.rs Git - rust.git/blob - src/librustc_typeck/check/closure.rs
Merge pull request #20510 from tshepang/patch-6
[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::infer;
17 use middle::region::CodeExtent;
18 use middle::subst;
19 use middle::ty::{self, ToPolyTraitRef, Ty};
20 use rscope::RegionScope;
21 use syntax::abi;
22 use syntax::ast;
23 use syntax::ast::CaptureClause::*;
24 use syntax::ast_util;
25 use util::ppaux::Repr;
26
27 pub fn check_expr_closure<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>,
28                                    expr: &ast::Expr,
29                                    capture: ast::CaptureClause,
30                                    opt_kind: Option<ast::UnboxedClosureKind>,
31                                    decl: &ast::FnDecl,
32                                    body: &ast::Block,
33                                    expected: Expectation<'tcx>) {
34     debug!("check_expr_closure(expr={},expected={})",
35            expr.repr(fcx.tcx()),
36            expected.repr(fcx.tcx()));
37
38     let expected_sig_and_kind = expected.map_to_option(fcx, |ty| {
39         deduce_unboxed_closure_expectations_from_expected_type(fcx, ty)
40     });
41
42     match opt_kind {
43         None => {
44             // If users didn't specify what sort of closure they want,
45             // examine the expected type. For now, if we see explicit
46             // evidence than an unboxed closure is desired, we'll use
47             // that, otherwise we'll fall back to boxed closures.
48             match expected_sig_and_kind {
49                 None => { // doesn't look like an unboxed closure
50                     let region = astconv::opt_ast_region_to_region(fcx,
51                                                                    fcx,
52                                                                    expr.span,
53                                                                    &None);
54
55                     check_boxed_closure(fcx,
56                                         expr,
57                                         ty::RegionTraitStore(region, ast::MutMutable),
58                                         decl,
59                                         body,
60                                         expected);
61
62                     match capture {
63                         CaptureByValue => {
64                             fcx.ccx.tcx.sess.span_err(
65                                 expr.span,
66                                 "boxed closures can't capture by value, \
67                                 if you want to use an unboxed closure, \
68                                 explicitly annotate its kind: e.g. `move |:|`");
69                         },
70                         CaptureByRef => {}
71                     }
72                 }
73                 Some((sig, kind)) => {
74                     check_unboxed_closure(fcx, expr, kind, decl, body, Some(sig));
75                 }
76             }
77         }
78
79         Some(kind) => {
80             let kind = match kind {
81                 ast::FnUnboxedClosureKind => ty::FnUnboxedClosureKind,
82                 ast::FnMutUnboxedClosureKind => ty::FnMutUnboxedClosureKind,
83                 ast::FnOnceUnboxedClosureKind => ty::FnOnceUnboxedClosureKind,
84             };
85
86             let expected_sig = expected_sig_and_kind.map(|t| t.0);
87             check_unboxed_closure(fcx, expr, kind, decl, body, expected_sig);
88         }
89     }
90 }
91
92 fn check_unboxed_closure<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>,
93                                   expr: &ast::Expr,
94                                   kind: ty::UnboxedClosureKind,
95                                   decl: &ast::FnDecl,
96                                   body: &ast::Block,
97                                   expected_sig: Option<ty::FnSig<'tcx>>) {
98     let expr_def_id = ast_util::local_def(expr.id);
99
100     debug!("check_unboxed_closure kind={} expected_sig={}",
101            kind,
102            expected_sig.repr(fcx.tcx()));
103
104     let mut fn_ty = astconv::ty_of_closure(
105         fcx,
106         ast::Unsafety::Normal,
107         ast::Many,
108
109         // The `RegionTraitStore` and region_existential_bounds
110         // are lies, but we ignore them so it doesn't matter.
111         //
112         // FIXME(pcwalton): Refactor this API.
113         ty::region_existential_bound(ty::ReStatic),
114         ty::RegionTraitStore(ty::ReStatic, ast::MutImmutable),
115
116         decl,
117         abi::RustCall,
118         expected_sig);
119
120     let region = match fcx.anon_regions(expr.span, 1) {
121         Err(_) => {
122             fcx.ccx.tcx.sess.span_bug(expr.span,
123                                       "can't make anon regions here?!")
124         }
125         Ok(regions) => regions[0],
126     };
127
128     let closure_type = ty::mk_unboxed_closure(fcx.ccx.tcx,
129                                               expr_def_id,
130                                               fcx.ccx.tcx.mk_region(region),
131                                               fcx.ccx.tcx.mk_substs(
132                                                   fcx.inh.param_env.free_substs.clone()));
133
134     fcx.write_ty(expr.id, closure_type);
135
136     let fn_sig =
137         ty::liberate_late_bound_regions(fcx.tcx(), CodeExtent::from_node_id(body.id), &fn_ty.sig);
138
139     check_fn(fcx.ccx,
140              ast::Unsafety::Normal,
141              expr.id,
142              &fn_sig,
143              decl,
144              expr.id,
145              &*body,
146              fcx.inh);
147
148     // Tuple up the arguments and insert the resulting function type into
149     // the `unboxed_closures` table.
150     fn_ty.sig.0.inputs = vec![ty::mk_tup(fcx.tcx(), fn_ty.sig.0.inputs)];
151
152     debug!("unboxed_closure for {} --> sig={} kind={}",
153            expr_def_id.repr(fcx.tcx()),
154            fn_ty.sig.repr(fcx.tcx()),
155            kind);
156
157     let unboxed_closure = ty::UnboxedClosure {
158         closure_type: fn_ty,
159         kind: kind,
160     };
161
162     fcx.inh
163         .unboxed_closures
164         .borrow_mut()
165         .insert(expr_def_id, unboxed_closure);
166 }
167
168 fn deduce_unboxed_closure_expectations_from_expected_type<'a,'tcx>(
169     fcx: &FnCtxt<'a,'tcx>,
170     expected_ty: Ty<'tcx>)
171     -> Option<(ty::FnSig<'tcx>,ty::UnboxedClosureKind)>
172 {
173     match expected_ty.sty {
174         ty::ty_trait(ref object_type) => {
175             let trait_ref =
176                 object_type.principal_trait_ref_with_self_ty(fcx.tcx(),
177                                                              fcx.tcx().types.err);
178             deduce_unboxed_closure_expectations_from_trait_ref(fcx, &trait_ref)
179         }
180         ty::ty_infer(ty::TyVar(vid)) => {
181             deduce_unboxed_closure_expectations_from_obligations(fcx, vid)
182         }
183         _ => {
184             None
185         }
186     }
187 }
188
189 fn deduce_unboxed_closure_expectations_from_trait_ref<'a,'tcx>(
190     fcx: &FnCtxt<'a,'tcx>,
191     trait_ref: &ty::PolyTraitRef<'tcx>)
192     -> Option<(ty::FnSig<'tcx>, ty::UnboxedClosureKind)>
193 {
194     let tcx = fcx.tcx();
195
196     debug!("deduce_unboxed_closure_expectations_from_object_type({})",
197            trait_ref.repr(tcx));
198
199     let kind = match tcx.lang_items.fn_trait_kind(trait_ref.def_id()) {
200         Some(k) => k,
201         None => { return None; }
202     };
203
204     debug!("found object type {}", kind);
205
206     let arg_param_ty = *trait_ref.substs().types.get(subst::TypeSpace, 0);
207     let arg_param_ty = fcx.infcx().resolve_type_vars_if_possible(&arg_param_ty);
208     debug!("arg_param_ty {}", arg_param_ty.repr(tcx));
209
210     let input_tys = match arg_param_ty.sty {
211         ty::ty_tup(ref tys) => { (*tys).clone() }
212         _ => { return None; }
213     };
214     debug!("input_tys {}", input_tys.repr(tcx));
215
216     let ret_param_ty = *trait_ref.substs().types.get(subst::TypeSpace, 1);
217     let ret_param_ty = fcx.infcx().resolve_type_vars_if_possible(&ret_param_ty);
218     debug!("ret_param_ty {}", ret_param_ty.repr(tcx));
219
220     let fn_sig = ty::FnSig {
221         inputs: input_tys,
222         output: ty::FnConverging(ret_param_ty),
223         variadic: false
224     };
225     debug!("fn_sig {}", fn_sig.repr(tcx));
226
227     return Some((fn_sig, kind));
228 }
229
230 fn deduce_unboxed_closure_expectations_from_obligations<'a,'tcx>(
231     fcx: &FnCtxt<'a,'tcx>,
232     expected_vid: ty::TyVid)
233     -> Option<(ty::FnSig<'tcx>, ty::UnboxedClosureKind)>
234 {
235     // Here `expected_ty` is known to be a type inference variable.
236     for obligation in fcx.inh.fulfillment_cx.borrow().pending_obligations().iter() {
237         match obligation.predicate {
238             ty::Predicate::Trait(ref trait_predicate) => {
239                 let trait_ref = trait_predicate.to_poly_trait_ref();
240                 let self_ty = fcx.infcx().shallow_resolve(trait_ref.self_ty());
241                 match self_ty.sty {
242                     ty::ty_infer(ty::TyVar(v)) if expected_vid == v => { }
243                     _ => { continue; }
244                 }
245
246                 match deduce_unboxed_closure_expectations_from_trait_ref(fcx, &trait_ref) {
247                     Some(e) => { return Some(e); }
248                     None => { }
249                 }
250             }
251             _ => { }
252         }
253     }
254
255     None
256 }
257
258
259 fn check_boxed_closure<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>,
260                                 expr: &ast::Expr,
261                                 store: ty::TraitStore,
262                                 decl: &ast::FnDecl,
263                                 body: &ast::Block,
264                                 expected: Expectation<'tcx>) {
265     let tcx = fcx.ccx.tcx;
266
267     // Find the expected input/output types (if any). Substitute
268     // fresh bound regions for any bound regions we find in the
269     // expected types so as to avoid capture.
270     let expected_cenv = expected.map_to_option(fcx, |ty| match ty.sty {
271         ty::ty_closure(ref cenv) => Some(cenv),
272         _ => None
273     });
274     let (expected_sig, expected_onceness, expected_bounds) = match expected_cenv {
275         Some(cenv) => {
276             let (sig, _) =
277                 ty::replace_late_bound_regions(
278                     tcx,
279                     &cenv.sig,
280                     |_, debruijn| fcx.inh.infcx.fresh_bound_region(debruijn));
281             let onceness = match (&store, &cenv.store) {
282                 // As the closure type and onceness go, only three
283                 // combinations are legit:
284                 //      once closure
285                 //      many closure
286                 //      once proc
287                 // If the actual and expected closure type disagree with
288                 // each other, set expected onceness to be always Once or
289                 // Many according to the actual type. Otherwise, it will
290                 // yield either an illegal "many proc" or a less known
291                 // "once closure" in the error message.
292                 (&ty::UniqTraitStore, &ty::UniqTraitStore) |
293                 (&ty::RegionTraitStore(..), &ty::RegionTraitStore(..)) =>
294                     cenv.onceness,
295                 (&ty::UniqTraitStore, _) => ast::Once,
296                 (&ty::RegionTraitStore(..), _) => ast::Many,
297             };
298             (Some(sig), onceness, cenv.bounds.clone())
299         }
300         _ => {
301             // Not an error! Means we're inferring the closure type
302             let region = fcx.infcx().next_region_var(
303                 infer::AddrOfRegion(expr.span));
304             let bounds = ty::region_existential_bound(region);
305             let onceness = ast::Many;
306             (None, onceness, bounds)
307         }
308     };
309
310     // construct the function type
311     let fn_ty = astconv::ty_of_closure(fcx,
312                                        ast::Unsafety::Normal,
313                                        expected_onceness,
314                                        expected_bounds,
315                                        store,
316                                        decl,
317                                        abi::Rust,
318                                        expected_sig);
319     let fn_sig = fn_ty.sig.clone();
320     let fty = ty::mk_closure(tcx, fn_ty);
321     debug!("check_expr_fn fty={}", fcx.infcx().ty_to_string(fty));
322
323     fcx.write_ty(expr.id, fty);
324
325     // If the closure is a stack closure and hasn't had some non-standard
326     // style inferred for it, then check it under its parent's style.
327     // Otherwise, use its own
328     let (inherited_style, inherited_style_id) = match store {
329         ty::RegionTraitStore(..) => (fcx.ps.borrow().unsafety,
330                                      fcx.ps.borrow().def),
331         ty::UniqTraitStore => (ast::Unsafety::Normal, expr.id)
332     };
333
334     let fn_sig =
335         ty::liberate_late_bound_regions(tcx, CodeExtent::from_node_id(body.id), &fn_sig);
336
337     check_fn(fcx.ccx,
338              inherited_style,
339              inherited_style_id,
340              &fn_sig,
341              &*decl,
342              expr.id,
343              &*body,
344              fcx.inh);
345 }