]>
Commit | Line | Data |
---|---|---|
1a4d82fc JJ |
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; | |
85aaf69f | 16 | use middle::region; |
1a4d82fc JJ |
17 | use middle::subst; |
18 | use middle::ty::{self, ToPolyTraitRef, Ty}; | |
c34b1796 | 19 | use std::cmp; |
1a4d82fc JJ |
20 | use syntax::abi; |
21 | use syntax::ast; | |
22 | use syntax::ast_util; | |
1a4d82fc JJ |
23 | |
24 | pub fn check_expr_closure<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>, | |
25 | expr: &ast::Expr, | |
26 | _capture: ast::CaptureClause, | |
85aaf69f SL |
27 | decl: &'tcx ast::FnDecl, |
28 | body: &'tcx ast::Block, | |
1a4d82fc | 29 | expected: Expectation<'tcx>) { |
62682a34 SL |
30 | debug!("check_expr_closure(expr={:?},expected={:?})", |
31 | expr, | |
32 | expected); | |
1a4d82fc | 33 | |
85aaf69f SL |
34 | // It's always helpful for inference if we know the kind of |
35 | // closure sooner rather than later, so first examine the expected | |
36 | // type, and see if can glean a closure kind from there. | |
37 | let (expected_sig,expected_kind) = match expected.to_option(fcx) { | |
38 | Some(ty) => deduce_expectations_from_expected_type(fcx, ty), | |
39 | None => (None, None) | |
40 | }; | |
41 | check_closure(fcx, expr, expected_kind, decl, body, expected_sig) | |
1a4d82fc JJ |
42 | } |
43 | ||
85aaf69f SL |
44 | fn check_closure<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>, |
45 | expr: &ast::Expr, | |
46 | opt_kind: Option<ty::ClosureKind>, | |
47 | decl: &'tcx ast::FnDecl, | |
48 | body: &'tcx ast::Block, | |
49 | expected_sig: Option<ty::FnSig<'tcx>>) { | |
1a4d82fc JJ |
50 | let expr_def_id = ast_util::local_def(expr.id); |
51 | ||
62682a34 | 52 | debug!("check_closure opt_kind={:?} expected_sig={:?}", |
85aaf69f | 53 | opt_kind, |
62682a34 | 54 | expected_sig); |
1a4d82fc | 55 | |
c1a9b12d SL |
56 | let mut fn_ty = astconv::ty_of_closure(fcx, |
57 | ast::Unsafety::Normal, | |
58 | decl, | |
59 | abi::RustCall, | |
60 | expected_sig); | |
61 | ||
62 | // Create type variables (for now) to represent the transformed | |
63 | // types of upvars. These will be unified during the upvar | |
64 | // inference phase (`upvar.rs`). | |
65 | let num_upvars = fcx.tcx().with_freevars(expr.id, |fv| fv.len()); | |
66 | let upvar_tys = fcx.infcx().next_ty_vars(num_upvars); | |
67 | ||
68 | debug!("check_closure: expr.id={:?} upvar_tys={:?}", | |
69 | expr.id, upvar_tys); | |
70 | ||
71 | let closure_type = | |
72 | fcx.ccx.tcx.mk_closure( | |
73 | expr_def_id, | |
74 | fcx.ccx.tcx.mk_substs(fcx.inh.infcx.parameter_environment.free_substs.clone()), | |
75 | upvar_tys); | |
1a4d82fc JJ |
76 | |
77 | fcx.write_ty(expr.id, closure_type); | |
78 | ||
c1a9b12d SL |
79 | let fn_sig = fcx.tcx().liberate_late_bound_regions( |
80 | region::DestructionScopeData::new(body.id), &fn_ty.sig); | |
1a4d82fc JJ |
81 | |
82 | check_fn(fcx.ccx, | |
83 | ast::Unsafety::Normal, | |
84 | expr.id, | |
85 | &fn_sig, | |
86 | decl, | |
87 | expr.id, | |
88 | &*body, | |
89 | fcx.inh); | |
90 | ||
91 | // Tuple up the arguments and insert the resulting function type into | |
85aaf69f | 92 | // the `closures` table. |
c1a9b12d | 93 | fn_ty.sig.0.inputs = vec![fcx.tcx().mk_tup(fn_ty.sig.0.inputs)]; |
1a4d82fc | 94 | |
62682a34 SL |
95 | debug!("closure for {:?} --> sig={:?} opt_kind={:?}", |
96 | expr_def_id, | |
97 | fn_ty.sig, | |
85aaf69f | 98 | opt_kind); |
1a4d82fc | 99 | |
c1a9b12d | 100 | fcx.inh.tables.borrow_mut().closure_tys.insert(expr_def_id, fn_ty); |
85aaf69f | 101 | match opt_kind { |
c1a9b12d | 102 | Some(kind) => { fcx.inh.tables.borrow_mut().closure_kinds.insert(expr_def_id, kind); } |
85aaf69f SL |
103 | None => { } |
104 | } | |
1a4d82fc JJ |
105 | } |
106 | ||
85aaf69f | 107 | fn deduce_expectations_from_expected_type<'a,'tcx>( |
1a4d82fc JJ |
108 | fcx: &FnCtxt<'a,'tcx>, |
109 | expected_ty: Ty<'tcx>) | |
85aaf69f | 110 | -> (Option<ty::FnSig<'tcx>>,Option<ty::ClosureKind>) |
1a4d82fc | 111 | { |
62682a34 SL |
112 | debug!("deduce_expectations_from_expected_type(expected_ty={:?})", |
113 | expected_ty); | |
85aaf69f | 114 | |
1a4d82fc | 115 | match expected_ty.sty { |
62682a34 | 116 | ty::TyTrait(ref object_type) => { |
85aaf69f SL |
117 | let proj_bounds = object_type.projection_bounds_with_self_ty(fcx.tcx(), |
118 | fcx.tcx().types.err); | |
c34b1796 AL |
119 | let sig = proj_bounds.iter() |
120 | .filter_map(|pb| deduce_sig_from_projection(fcx, pb)) | |
121 | .next(); | |
122 | let kind = fcx.tcx().lang_items.fn_trait_kind(object_type.principal_def_id()); | |
123 | (sig, kind) | |
1a4d82fc | 124 | } |
62682a34 | 125 | ty::TyInfer(ty::TyVar(vid)) => { |
85aaf69f | 126 | deduce_expectations_from_obligations(fcx, vid) |
1a4d82fc JJ |
127 | } |
128 | _ => { | |
85aaf69f | 129 | (None, None) |
1a4d82fc JJ |
130 | } |
131 | } | |
132 | } | |
133 | ||
85aaf69f SL |
134 | fn deduce_expectations_from_obligations<'a,'tcx>( |
135 | fcx: &FnCtxt<'a,'tcx>, | |
136 | expected_vid: ty::TyVid) | |
137 | -> (Option<ty::FnSig<'tcx>>, Option<ty::ClosureKind>) | |
138 | { | |
c1a9b12d | 139 | let fulfillment_cx = fcx.inh.infcx.fulfillment_cx.borrow(); |
85aaf69f SL |
140 | // Here `expected_ty` is known to be a type inference variable. |
141 | ||
c34b1796 | 142 | let expected_sig = |
85aaf69f SL |
143 | fulfillment_cx |
144 | .pending_obligations() | |
145 | .iter() | |
146 | .filter_map(|obligation| { | |
62682a34 SL |
147 | debug!("deduce_expectations_from_obligations: obligation.predicate={:?}", |
148 | obligation.predicate); | |
85aaf69f SL |
149 | |
150 | match obligation.predicate { | |
151 | // Given a Projection predicate, we can potentially infer | |
152 | // the complete signature. | |
153 | ty::Predicate::Projection(ref proj_predicate) => { | |
154 | let trait_ref = proj_predicate.to_poly_trait_ref(); | |
155 | self_type_matches_expected_vid(fcx, trait_ref, expected_vid) | |
c34b1796 | 156 | .and_then(|_| deduce_sig_from_projection(fcx, proj_predicate)) |
85aaf69f SL |
157 | } |
158 | _ => { | |
159 | None | |
160 | } | |
161 | } | |
162 | }) | |
163 | .next(); | |
164 | ||
85aaf69f SL |
165 | // Even if we can't infer the full signature, we may be able to |
166 | // infer the kind. This can occur if there is a trait-reference | |
c34b1796 AL |
167 | // like `F : Fn<A>`. Note that due to subtyping we could encounter |
168 | // many viable options, so pick the most restrictive. | |
85aaf69f SL |
169 | let expected_kind = |
170 | fulfillment_cx | |
171 | .pending_obligations() | |
172 | .iter() | |
173 | .filter_map(|obligation| { | |
174 | let opt_trait_ref = match obligation.predicate { | |
175 | ty::Predicate::Projection(ref data) => Some(data.to_poly_trait_ref()), | |
176 | ty::Predicate::Trait(ref data) => Some(data.to_poly_trait_ref()), | |
177 | ty::Predicate::Equate(..) => None, | |
178 | ty::Predicate::RegionOutlives(..) => None, | |
179 | ty::Predicate::TypeOutlives(..) => None, | |
180 | }; | |
181 | opt_trait_ref | |
182 | .and_then(|trait_ref| self_type_matches_expected_vid(fcx, trait_ref, expected_vid)) | |
183 | .and_then(|trait_ref| fcx.tcx().lang_items.fn_trait_kind(trait_ref.def_id())) | |
184 | }) | |
c34b1796 | 185 | .fold(None, pick_most_restrictive_closure_kind); |
85aaf69f | 186 | |
c34b1796 AL |
187 | (expected_sig, expected_kind) |
188 | } | |
189 | ||
190 | fn pick_most_restrictive_closure_kind(best: Option<ty::ClosureKind>, | |
191 | cur: ty::ClosureKind) | |
192 | -> Option<ty::ClosureKind> | |
193 | { | |
194 | match best { | |
195 | None => Some(cur), | |
196 | Some(best) => Some(cmp::min(best, cur)) | |
197 | } | |
85aaf69f SL |
198 | } |
199 | ||
200 | /// Given a projection like "<F as Fn(X)>::Result == Y", we can deduce | |
201 | /// everything we need to know about a closure. | |
c34b1796 | 202 | fn deduce_sig_from_projection<'a,'tcx>( |
1a4d82fc | 203 | fcx: &FnCtxt<'a,'tcx>, |
85aaf69f | 204 | projection: &ty::PolyProjectionPredicate<'tcx>) |
c34b1796 | 205 | -> Option<ty::FnSig<'tcx>> |
1a4d82fc JJ |
206 | { |
207 | let tcx = fcx.tcx(); | |
208 | ||
62682a34 SL |
209 | debug!("deduce_sig_from_projection({:?})", |
210 | projection); | |
85aaf69f SL |
211 | |
212 | let trait_ref = projection.to_poly_trait_ref(); | |
1a4d82fc | 213 | |
c34b1796 AL |
214 | if tcx.lang_items.fn_trait_kind(trait_ref.def_id()).is_none() { |
215 | return None; | |
216 | } | |
1a4d82fc JJ |
217 | |
218 | let arg_param_ty = *trait_ref.substs().types.get(subst::TypeSpace, 0); | |
219 | let arg_param_ty = fcx.infcx().resolve_type_vars_if_possible(&arg_param_ty); | |
62682a34 | 220 | debug!("deduce_sig_from_projection: arg_param_ty {:?}", arg_param_ty); |
1a4d82fc JJ |
221 | |
222 | let input_tys = match arg_param_ty.sty { | |
62682a34 | 223 | ty::TyTuple(ref tys) => { (*tys).clone() } |
1a4d82fc JJ |
224 | _ => { return None; } |
225 | }; | |
62682a34 | 226 | debug!("deduce_sig_from_projection: input_tys {:?}", input_tys); |
1a4d82fc | 227 | |
85aaf69f | 228 | let ret_param_ty = projection.0.ty; |
1a4d82fc | 229 | let ret_param_ty = fcx.infcx().resolve_type_vars_if_possible(&ret_param_ty); |
62682a34 | 230 | debug!("deduce_sig_from_projection: ret_param_ty {:?}", ret_param_ty); |
1a4d82fc JJ |
231 | |
232 | let fn_sig = ty::FnSig { | |
233 | inputs: input_tys, | |
234 | output: ty::FnConverging(ret_param_ty), | |
235 | variadic: false | |
236 | }; | |
62682a34 | 237 | debug!("deduce_sig_from_projection: fn_sig {:?}", fn_sig); |
1a4d82fc | 238 | |
c34b1796 | 239 | Some(fn_sig) |
1a4d82fc JJ |
240 | } |
241 | ||
85aaf69f | 242 | fn self_type_matches_expected_vid<'a,'tcx>( |
1a4d82fc | 243 | fcx: &FnCtxt<'a,'tcx>, |
85aaf69f | 244 | trait_ref: ty::PolyTraitRef<'tcx>, |
1a4d82fc | 245 | expected_vid: ty::TyVid) |
85aaf69f | 246 | -> Option<ty::PolyTraitRef<'tcx>> |
1a4d82fc | 247 | { |
85aaf69f | 248 | let self_ty = fcx.infcx().shallow_resolve(trait_ref.self_ty()); |
62682a34 SL |
249 | debug!("self_type_matches_expected_vid(trait_ref={:?}, self_ty={:?})", |
250 | trait_ref, | |
251 | self_ty); | |
85aaf69f | 252 | match self_ty.sty { |
62682a34 | 253 | ty::TyInfer(ty::TyVar(v)) if expected_vid == v => Some(trait_ref), |
85aaf69f | 254 | _ => None, |
1a4d82fc | 255 | } |
1a4d82fc | 256 | } |