]> git.lizzy.rs Git - rust.git/blob - src/librustc_typeck/check/closure.rs
rollup merge of #21392: japaric/iter
[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         decl,
92         abi::RustCall,
93         expected_sig);
94
95     let region = match fcx.anon_regions(expr.span, 1) {
96         Err(_) => {
97             fcx.ccx.tcx.sess.span_bug(expr.span,
98                                       "can't make anon regions here?!")
99         }
100         Ok(regions) => regions[0],
101     };
102
103     let closure_type = ty::mk_unboxed_closure(fcx.ccx.tcx,
104                                               expr_def_id,
105                                               fcx.ccx.tcx.mk_region(region),
106                                               fcx.ccx.tcx.mk_substs(
107                                                   fcx.inh.param_env.free_substs.clone()));
108
109     fcx.write_ty(expr.id, closure_type);
110
111     let fn_sig =
112         ty::liberate_late_bound_regions(fcx.tcx(), CodeExtent::from_node_id(body.id), &fn_ty.sig);
113
114     check_fn(fcx.ccx,
115              ast::Unsafety::Normal,
116              expr.id,
117              &fn_sig,
118              decl,
119              expr.id,
120              &*body,
121              fcx.inh);
122
123     // Tuple up the arguments and insert the resulting function type into
124     // the `unboxed_closures` table.
125     fn_ty.sig.0.inputs = vec![ty::mk_tup(fcx.tcx(), fn_ty.sig.0.inputs)];
126
127     debug!("unboxed_closure for {} --> sig={} kind={:?}",
128            expr_def_id.repr(fcx.tcx()),
129            fn_ty.sig.repr(fcx.tcx()),
130            kind);
131
132     let unboxed_closure = ty::UnboxedClosure {
133         closure_type: fn_ty,
134         kind: kind,
135     };
136
137     fcx.inh
138         .unboxed_closures
139         .borrow_mut()
140         .insert(expr_def_id, unboxed_closure);
141 }
142
143 fn deduce_unboxed_closure_expectations_from_expected_type<'a,'tcx>(
144     fcx: &FnCtxt<'a,'tcx>,
145     expected_ty: Ty<'tcx>)
146     -> Option<(ty::FnSig<'tcx>,ty::UnboxedClosureKind)>
147 {
148     match expected_ty.sty {
149         ty::ty_trait(ref object_type) => {
150             let trait_ref =
151                 object_type.principal_trait_ref_with_self_ty(fcx.tcx(),
152                                                              fcx.tcx().types.err);
153             deduce_unboxed_closure_expectations_from_trait_ref(fcx, &trait_ref)
154         }
155         ty::ty_infer(ty::TyVar(vid)) => {
156             deduce_unboxed_closure_expectations_from_obligations(fcx, vid)
157         }
158         _ => {
159             None
160         }
161     }
162 }
163
164 fn deduce_unboxed_closure_expectations_from_trait_ref<'a,'tcx>(
165     fcx: &FnCtxt<'a,'tcx>,
166     trait_ref: &ty::PolyTraitRef<'tcx>)
167     -> Option<(ty::FnSig<'tcx>, ty::UnboxedClosureKind)>
168 {
169     let tcx = fcx.tcx();
170
171     debug!("deduce_unboxed_closure_expectations_from_object_type({})",
172            trait_ref.repr(tcx));
173
174     let kind = match tcx.lang_items.fn_trait_kind(trait_ref.def_id()) {
175         Some(k) => k,
176         None => { return None; }
177     };
178
179     debug!("found object type {:?}", kind);
180
181     let arg_param_ty = *trait_ref.substs().types.get(subst::TypeSpace, 0);
182     let arg_param_ty = fcx.infcx().resolve_type_vars_if_possible(&arg_param_ty);
183     debug!("arg_param_ty {}", arg_param_ty.repr(tcx));
184
185     let input_tys = match arg_param_ty.sty {
186         ty::ty_tup(ref tys) => { (*tys).clone() }
187         _ => { return None; }
188     };
189     debug!("input_tys {}", input_tys.repr(tcx));
190
191     let ret_param_ty = *trait_ref.substs().types.get(subst::TypeSpace, 1);
192     let ret_param_ty = fcx.infcx().resolve_type_vars_if_possible(&ret_param_ty);
193     debug!("ret_param_ty {}", ret_param_ty.repr(tcx));
194
195     let fn_sig = ty::FnSig {
196         inputs: input_tys,
197         output: ty::FnConverging(ret_param_ty),
198         variadic: false
199     };
200     debug!("fn_sig {}", fn_sig.repr(tcx));
201
202     return Some((fn_sig, kind));
203 }
204
205 fn deduce_unboxed_closure_expectations_from_obligations<'a,'tcx>(
206     fcx: &FnCtxt<'a,'tcx>,
207     expected_vid: ty::TyVid)
208     -> Option<(ty::FnSig<'tcx>, ty::UnboxedClosureKind)>
209 {
210     // Here `expected_ty` is known to be a type inference variable.
211     for obligation in fcx.inh.fulfillment_cx.borrow().pending_obligations().iter() {
212         match obligation.predicate {
213             ty::Predicate::Trait(ref trait_predicate) => {
214                 let trait_ref = trait_predicate.to_poly_trait_ref();
215                 let self_ty = fcx.infcx().shallow_resolve(trait_ref.self_ty());
216                 match self_ty.sty {
217                     ty::ty_infer(ty::TyVar(v)) if expected_vid == v => { }
218                     _ => { continue; }
219                 }
220
221                 match deduce_unboxed_closure_expectations_from_trait_ref(fcx, &trait_ref) {
222                     Some(e) => { return Some(e); }
223                     None => { }
224                 }
225             }
226             _ => { }
227         }
228     }
229
230     None
231 }