]> git.lizzy.rs Git - rust.git/blob - src/librustc_typeck/check/closure.rs
rollup merge of #21367: steveklabnik/remove_gate
[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                     span_err!(fcx.ccx.tcx.sess, expr.span, E0187,
54                         "can't infer the \"kind\" of the closure, explicitly annotate it. e.g. \
55                         `|&:| {{}}`");
56                 },
57                 Some((sig, kind)) => {
58                     check_unboxed_closure(fcx, expr, kind, decl, body, Some(sig));
59                 }
60             }
61         }
62
63         Some(kind) => {
64             let kind = match kind {
65                 ast::FnUnboxedClosureKind => ty::FnUnboxedClosureKind,
66                 ast::FnMutUnboxedClosureKind => ty::FnMutUnboxedClosureKind,
67                 ast::FnOnceUnboxedClosureKind => ty::FnOnceUnboxedClosureKind,
68             };
69
70             let expected_sig = expected_sig_and_kind.map(|t| t.0);
71             check_unboxed_closure(fcx, expr, kind, decl, body, expected_sig);
72         }
73     }
74 }
75
76 fn check_unboxed_closure<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>,
77                                   expr: &ast::Expr,
78                                   kind: ty::UnboxedClosureKind,
79                                   decl: &ast::FnDecl,
80                                   body: &ast::Block,
81                                   expected_sig: Option<ty::FnSig<'tcx>>) {
82     let expr_def_id = ast_util::local_def(expr.id);
83
84     debug!("check_unboxed_closure kind={:?} expected_sig={}",
85            kind,
86            expected_sig.repr(fcx.tcx()));
87
88     let mut fn_ty = astconv::ty_of_closure(
89         fcx,
90         ast::Unsafety::Normal,
91         ast::Many,
92
93         // The `RegionTraitStore` and region_existential_bounds
94         // are lies, but we ignore them so it doesn't matter.
95         //
96         // FIXME(pcwalton): Refactor this API.
97         ty::region_existential_bound(ty::ReStatic),
98         ty::RegionTraitStore(ty::ReStatic, ast::MutImmutable),
99
100         decl,
101         abi::RustCall,
102         expected_sig);
103
104     let region = match fcx.anon_regions(expr.span, 1) {
105         Err(_) => {
106             fcx.ccx.tcx.sess.span_bug(expr.span,
107                                       "can't make anon regions here?!")
108         }
109         Ok(regions) => regions[0],
110     };
111
112     let closure_type = ty::mk_unboxed_closure(fcx.ccx.tcx,
113                                               expr_def_id,
114                                               fcx.ccx.tcx.mk_region(region),
115                                               fcx.ccx.tcx.mk_substs(
116                                                   fcx.inh.param_env.free_substs.clone()));
117
118     fcx.write_ty(expr.id, closure_type);
119
120     let fn_sig =
121         ty::liberate_late_bound_regions(fcx.tcx(), CodeExtent::from_node_id(body.id), &fn_ty.sig);
122
123     check_fn(fcx.ccx,
124              ast::Unsafety::Normal,
125              expr.id,
126              &fn_sig,
127              decl,
128              expr.id,
129              &*body,
130              fcx.inh);
131
132     // Tuple up the arguments and insert the resulting function type into
133     // the `unboxed_closures` table.
134     fn_ty.sig.0.inputs = vec![ty::mk_tup(fcx.tcx(), fn_ty.sig.0.inputs)];
135
136     debug!("unboxed_closure for {} --> sig={} kind={:?}",
137            expr_def_id.repr(fcx.tcx()),
138            fn_ty.sig.repr(fcx.tcx()),
139            kind);
140
141     let unboxed_closure = ty::UnboxedClosure {
142         closure_type: fn_ty,
143         kind: kind,
144     };
145
146     fcx.inh
147         .unboxed_closures
148         .borrow_mut()
149         .insert(expr_def_id, unboxed_closure);
150 }
151
152 fn deduce_unboxed_closure_expectations_from_expected_type<'a,'tcx>(
153     fcx: &FnCtxt<'a,'tcx>,
154     expected_ty: Ty<'tcx>)
155     -> Option<(ty::FnSig<'tcx>,ty::UnboxedClosureKind)>
156 {
157     match expected_ty.sty {
158         ty::ty_trait(ref object_type) => {
159             let trait_ref =
160                 object_type.principal_trait_ref_with_self_ty(fcx.tcx(),
161                                                              fcx.tcx().types.err);
162             deduce_unboxed_closure_expectations_from_trait_ref(fcx, &trait_ref)
163         }
164         ty::ty_infer(ty::TyVar(vid)) => {
165             deduce_unboxed_closure_expectations_from_obligations(fcx, vid)
166         }
167         _ => {
168             None
169         }
170     }
171 }
172
173 fn deduce_unboxed_closure_expectations_from_trait_ref<'a,'tcx>(
174     fcx: &FnCtxt<'a,'tcx>,
175     trait_ref: &ty::PolyTraitRef<'tcx>)
176     -> Option<(ty::FnSig<'tcx>, ty::UnboxedClosureKind)>
177 {
178     let tcx = fcx.tcx();
179
180     debug!("deduce_unboxed_closure_expectations_from_object_type({})",
181            trait_ref.repr(tcx));
182
183     let kind = match tcx.lang_items.fn_trait_kind(trait_ref.def_id()) {
184         Some(k) => k,
185         None => { return None; }
186     };
187
188     debug!("found object type {:?}", kind);
189
190     let arg_param_ty = *trait_ref.substs().types.get(subst::TypeSpace, 0);
191     let arg_param_ty = fcx.infcx().resolve_type_vars_if_possible(&arg_param_ty);
192     debug!("arg_param_ty {}", arg_param_ty.repr(tcx));
193
194     let input_tys = match arg_param_ty.sty {
195         ty::ty_tup(ref tys) => { (*tys).clone() }
196         _ => { return None; }
197     };
198     debug!("input_tys {}", input_tys.repr(tcx));
199
200     let ret_param_ty = *trait_ref.substs().types.get(subst::TypeSpace, 1);
201     let ret_param_ty = fcx.infcx().resolve_type_vars_if_possible(&ret_param_ty);
202     debug!("ret_param_ty {}", ret_param_ty.repr(tcx));
203
204     let fn_sig = ty::FnSig {
205         inputs: input_tys,
206         output: ty::FnConverging(ret_param_ty),
207         variadic: false
208     };
209     debug!("fn_sig {}", fn_sig.repr(tcx));
210
211     return Some((fn_sig, kind));
212 }
213
214 fn deduce_unboxed_closure_expectations_from_obligations<'a,'tcx>(
215     fcx: &FnCtxt<'a,'tcx>,
216     expected_vid: ty::TyVid)
217     -> Option<(ty::FnSig<'tcx>, ty::UnboxedClosureKind)>
218 {
219     // Here `expected_ty` is known to be a type inference variable.
220     for obligation in fcx.inh.fulfillment_cx.borrow().pending_obligations().iter() {
221         match obligation.predicate {
222             ty::Predicate::Trait(ref trait_predicate) => {
223                 let trait_ref = trait_predicate.to_poly_trait_ref();
224                 let self_ty = fcx.infcx().shallow_resolve(trait_ref.self_ty());
225                 match self_ty.sty {
226                     ty::ty_infer(ty::TyVar(v)) if expected_vid == v => { }
227                     _ => { continue; }
228                 }
229
230                 match deduce_unboxed_closure_expectations_from_trait_ref(fcx, &trait_ref) {
231                     Some(e) => { return Some(e); }
232                     None => { }
233                 }
234             }
235             _ => { }
236         }
237     }
238
239     None
240 }