]> git.lizzy.rs Git - rust.git/blob - src/librustc_typeck/check/closure.rs
auto merge of #21018 : tomjakubowski/rust/rustdoc-where-xcrate, 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::region::CodeExtent;
17 use middle::subst;
18 use middle::ty::{self, ToPolyTraitRef, Ty};
19 use rscope::RegionScope;
20 use syntax::abi;
21 use syntax::ast;
22 use syntax::ast_util;
23 use util::ppaux::Repr;
24
25 pub fn check_expr_closure<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>,
26                                    expr: &ast::Expr,
27                                    _capture: ast::CaptureClause,
28                                    opt_kind: Option<ast::UnboxedClosureKind>,
29                                    decl: &ast::FnDecl,
30                                    body: &ast::Block,
31                                    expected: Expectation<'tcx>) {
32     debug!("check_expr_closure(expr={},expected={})",
33            expr.repr(fcx.tcx()),
34            expected.repr(fcx.tcx()));
35
36     let expected_sig_and_kind = expected.to_option(fcx).and_then(|ty| {
37         deduce_unboxed_closure_expectations_from_expected_type(fcx, ty)
38     });
39
40     match opt_kind {
41         None => {
42             // If users didn't specify what sort of closure they want,
43             // examine the expected type. For now, if we see explicit
44             // evidence than an unboxed closure is desired, we'll use
45             // that, otherwise we'll fall back to boxed closures.
46             match expected_sig_and_kind {
47                 None => { // don't have information about the kind, request explicit annotation
48                     // NB We still need to typeck the body, so assume `FnMut` kind just for that
49                     let kind = ty::FnMutUnboxedClosureKind;
50
51                     check_unboxed_closure(fcx, expr, kind, decl, body, None);
52
53                     fcx.ccx.tcx.sess.span_err(
54                         expr.span,
55                         "can't infer the \"kind\" of the closure, explicitly annotate it. e.g. \
56                         `|&:| {}`");
57                 },
58                 Some((sig, kind)) => {
59                     check_unboxed_closure(fcx, expr, kind, decl, body, Some(sig));
60                 }
61             }
62         }
63
64         Some(kind) => {
65             let kind = match kind {
66                 ast::FnUnboxedClosureKind => ty::FnUnboxedClosureKind,
67                 ast::FnMutUnboxedClosureKind => ty::FnMutUnboxedClosureKind,
68                 ast::FnOnceUnboxedClosureKind => ty::FnOnceUnboxedClosureKind,
69             };
70
71             let expected_sig = expected_sig_and_kind.map(|t| t.0);
72             check_unboxed_closure(fcx, expr, kind, decl, body, expected_sig);
73         }
74     }
75 }
76
77 fn check_unboxed_closure<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>,
78                                   expr: &ast::Expr,
79                                   kind: ty::UnboxedClosureKind,
80                                   decl: &ast::FnDecl,
81                                   body: &ast::Block,
82                                   expected_sig: Option<ty::FnSig<'tcx>>) {
83     let expr_def_id = ast_util::local_def(expr.id);
84
85     debug!("check_unboxed_closure kind={:?} expected_sig={}",
86            kind,
87            expected_sig.repr(fcx.tcx()));
88
89     let mut fn_ty = astconv::ty_of_closure(
90         fcx,
91         ast::Unsafety::Normal,
92         ast::Many,
93
94         // The `RegionTraitStore` and region_existential_bounds
95         // are lies, but we ignore them so it doesn't matter.
96         //
97         // FIXME(pcwalton): Refactor this API.
98         ty::region_existential_bound(ty::ReStatic),
99         ty::RegionTraitStore(ty::ReStatic, ast::MutImmutable),
100
101         decl,
102         abi::RustCall,
103         expected_sig);
104
105     let region = match fcx.anon_regions(expr.span, 1) {
106         Err(_) => {
107             fcx.ccx.tcx.sess.span_bug(expr.span,
108                                       "can't make anon regions here?!")
109         }
110         Ok(regions) => regions[0],
111     };
112
113     let closure_type = ty::mk_unboxed_closure(fcx.ccx.tcx,
114                                               expr_def_id,
115                                               fcx.ccx.tcx.mk_region(region),
116                                               fcx.ccx.tcx.mk_substs(
117                                                   fcx.inh.param_env.free_substs.clone()));
118
119     fcx.write_ty(expr.id, closure_type);
120
121     let fn_sig =
122         ty::liberate_late_bound_regions(fcx.tcx(), CodeExtent::from_node_id(body.id), &fn_ty.sig);
123
124     check_fn(fcx.ccx,
125              ast::Unsafety::Normal,
126              expr.id,
127              &fn_sig,
128              decl,
129              expr.id,
130              &*body,
131              fcx.inh);
132
133     // Tuple up the arguments and insert the resulting function type into
134     // the `unboxed_closures` table.
135     fn_ty.sig.0.inputs = vec![ty::mk_tup(fcx.tcx(), fn_ty.sig.0.inputs)];
136
137     debug!("unboxed_closure for {} --> sig={} kind={:?}",
138            expr_def_id.repr(fcx.tcx()),
139            fn_ty.sig.repr(fcx.tcx()),
140            kind);
141
142     let unboxed_closure = ty::UnboxedClosure {
143         closure_type: fn_ty,
144         kind: kind,
145     };
146
147     fcx.inh
148         .unboxed_closures
149         .borrow_mut()
150         .insert(expr_def_id, unboxed_closure);
151 }
152
153 fn deduce_unboxed_closure_expectations_from_expected_type<'a,'tcx>(
154     fcx: &FnCtxt<'a,'tcx>,
155     expected_ty: Ty<'tcx>)
156     -> Option<(ty::FnSig<'tcx>,ty::UnboxedClosureKind)>
157 {
158     match expected_ty.sty {
159         ty::ty_trait(ref object_type) => {
160             let trait_ref =
161                 object_type.principal_trait_ref_with_self_ty(fcx.tcx(),
162                                                              fcx.tcx().types.err);
163             deduce_unboxed_closure_expectations_from_trait_ref(fcx, &trait_ref)
164         }
165         ty::ty_infer(ty::TyVar(vid)) => {
166             deduce_unboxed_closure_expectations_from_obligations(fcx, vid)
167         }
168         _ => {
169             None
170         }
171     }
172 }
173
174 fn deduce_unboxed_closure_expectations_from_trait_ref<'a,'tcx>(
175     fcx: &FnCtxt<'a,'tcx>,
176     trait_ref: &ty::PolyTraitRef<'tcx>)
177     -> Option<(ty::FnSig<'tcx>, ty::UnboxedClosureKind)>
178 {
179     let tcx = fcx.tcx();
180
181     debug!("deduce_unboxed_closure_expectations_from_object_type({})",
182            trait_ref.repr(tcx));
183
184     let kind = match tcx.lang_items.fn_trait_kind(trait_ref.def_id()) {
185         Some(k) => k,
186         None => { return None; }
187     };
188
189     debug!("found object type {:?}", kind);
190
191     let arg_param_ty = *trait_ref.substs().types.get(subst::TypeSpace, 0);
192     let arg_param_ty = fcx.infcx().resolve_type_vars_if_possible(&arg_param_ty);
193     debug!("arg_param_ty {}", arg_param_ty.repr(tcx));
194
195     let input_tys = match arg_param_ty.sty {
196         ty::ty_tup(ref tys) => { (*tys).clone() }
197         _ => { return None; }
198     };
199     debug!("input_tys {}", input_tys.repr(tcx));
200
201     let ret_param_ty = *trait_ref.substs().types.get(subst::TypeSpace, 1);
202     let ret_param_ty = fcx.infcx().resolve_type_vars_if_possible(&ret_param_ty);
203     debug!("ret_param_ty {}", ret_param_ty.repr(tcx));
204
205     let fn_sig = ty::FnSig {
206         inputs: input_tys,
207         output: ty::FnConverging(ret_param_ty),
208         variadic: false
209     };
210     debug!("fn_sig {}", fn_sig.repr(tcx));
211
212     return Some((fn_sig, kind));
213 }
214
215 fn deduce_unboxed_closure_expectations_from_obligations<'a,'tcx>(
216     fcx: &FnCtxt<'a,'tcx>,
217     expected_vid: ty::TyVid)
218     -> Option<(ty::FnSig<'tcx>, ty::UnboxedClosureKind)>
219 {
220     // Here `expected_ty` is known to be a type inference variable.
221     for obligation in fcx.inh.fulfillment_cx.borrow().pending_obligations().iter() {
222         match obligation.predicate {
223             ty::Predicate::Trait(ref trait_predicate) => {
224                 let trait_ref = trait_predicate.to_poly_trait_ref();
225                 let self_ty = fcx.infcx().shallow_resolve(trait_ref.self_ty());
226                 match self_ty.sty {
227                     ty::ty_infer(ty::TyVar(v)) if expected_vid == v => { }
228                     _ => { continue; }
229                 }
230
231                 match deduce_unboxed_closure_expectations_from_trait_ref(fcx, &trait_ref) {
232                     Some(e) => { return Some(e); }
233                     None => { }
234                 }
235             }
236             _ => { }
237         }
238     }
239
240     None
241 }