]>
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 | ||
a7813a04 | 15 | use astconv::AstConv; |
476ff2be | 16 | use rustc::infer::type_variable::TypeVariableOrigin; |
54a0048b | 17 | use rustc::ty::{self, ToPolyTraitRef, Ty}; |
7cac9316 | 18 | use rustc::ty::subst::Substs; |
c34b1796 | 19 | use std::cmp; |
476ff2be | 20 | use std::iter; |
7453a54e | 21 | use syntax::abi::Abi; |
54a0048b | 22 | use rustc::hir; |
1a4d82fc | 23 | |
a7813a04 XL |
24 | impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { |
25 | pub fn check_expr_closure(&self, | |
26 | expr: &hir::Expr, | |
27 | _capture: hir::CaptureClause, | |
28 | decl: &'gcx hir::FnDecl, | |
32a655c1 | 29 | body_id: hir::BodyId, |
c30ab7b3 SL |
30 | expected: Expectation<'tcx>) |
31 | -> Ty<'tcx> { | |
a7813a04 XL |
32 | debug!("check_expr_closure(expr={:?},expected={:?})", |
33 | expr, | |
34 | expected); | |
35 | ||
36 | // It's always helpful for inference if we know the kind of | |
37 | // closure sooner rather than later, so first examine the expected | |
38 | // type, and see if can glean a closure kind from there. | |
c30ab7b3 | 39 | let (expected_sig, expected_kind) = match expected.to_option(self) { |
a7813a04 | 40 | Some(ty) => self.deduce_expectations_from_expected_type(ty), |
c30ab7b3 | 41 | None => (None, None), |
a7813a04 | 42 | }; |
32a655c1 | 43 | let body = self.tcx.hir.body(body_id); |
a7813a04 XL |
44 | self.check_closure(expr, expected_kind, decl, body, expected_sig) |
45 | } | |
1a4d82fc | 46 | |
a7813a04 XL |
47 | fn check_closure(&self, |
48 | expr: &hir::Expr, | |
49 | opt_kind: Option<ty::ClosureKind>, | |
50 | decl: &'gcx hir::FnDecl, | |
32a655c1 | 51 | body: &'gcx hir::Body, |
c30ab7b3 SL |
52 | expected_sig: Option<ty::FnSig<'tcx>>) |
53 | -> Ty<'tcx> { | |
a7813a04 XL |
54 | debug!("check_closure opt_kind={:?} expected_sig={:?}", |
55 | opt_kind, | |
56 | expected_sig); | |
57 | ||
32a655c1 | 58 | let expr_def_id = self.tcx.hir.local_def_id(expr.id); |
8bb4bdeb XL |
59 | let sig = AstConv::ty_of_closure(self, |
60 | hir::Unsafety::Normal, | |
61 | decl, | |
62 | Abi::RustCall, | |
63 | expected_sig); | |
7cac9316 XL |
64 | // `deduce_expectations_from_expected_type` introduces late-bound |
65 | // lifetimes defined elsewhere, which we need to anonymize away. | |
66 | let sig = self.tcx.anonymize_late_bound_regions(&sig); | |
a7813a04 XL |
67 | |
68 | // Create type variables (for now) to represent the transformed | |
69 | // types of upvars. These will be unified during the upvar | |
70 | // inference phase (`upvar.rs`). | |
7cac9316 XL |
71 | let base_substs = Substs::identity_for_item(self.tcx, |
72 | self.tcx.closure_base_def_id(expr_def_id)); | |
a7813a04 | 73 | let closure_type = self.tcx.mk_closure(expr_def_id, |
7cac9316 | 74 | base_substs.extend_to(self.tcx, expr_def_id, |
476ff2be SL |
75 | |_, _| span_bug!(expr.span, "closure has region param"), |
76 | |_, _| self.infcx.next_ty_var(TypeVariableOrigin::TransformedUpvar(expr.span)) | |
77 | ) | |
78 | ); | |
79 | ||
80 | debug!("check_closure: expr.id={:?} closure_type={:?}", expr.id, closure_type); | |
c30ab7b3 | 81 | |
7cac9316 | 82 | let fn_sig = self.liberate_late_bound_regions(expr_def_id, &sig); |
32a655c1 | 83 | let fn_sig = self.inh.normalize_associated_types_in(body.value.span, |
7cac9316 XL |
84 | body.value.id, |
85 | self.param_env, | |
86 | &fn_sig); | |
c30ab7b3 | 87 | |
7cac9316 | 88 | check_fn(self, self.param_env, fn_sig, decl, expr.id, body); |
a7813a04 XL |
89 | |
90 | // Tuple up the arguments and insert the resulting function type into | |
91 | // the `closures` table. | |
8bb4bdeb XL |
92 | let sig = sig.map_bound(|sig| self.tcx.mk_fn_sig( |
93 | iter::once(self.tcx.intern_tup(sig.inputs(), false)), | |
94 | sig.output(), | |
95 | sig.variadic, | |
96 | sig.unsafety, | |
97 | sig.abi | |
98 | )); | |
a7813a04 XL |
99 | |
100 | debug!("closure for {:?} --> sig={:?} opt_kind={:?}", | |
101 | expr_def_id, | |
8bb4bdeb | 102 | sig, |
a7813a04 XL |
103 | opt_kind); |
104 | ||
8bb4bdeb | 105 | self.tables.borrow_mut().closure_tys.insert(expr.id, sig); |
a7813a04 | 106 | match opt_kind { |
c30ab7b3 | 107 | Some(kind) => { |
7cac9316 | 108 | self.tables.borrow_mut().closure_kinds.insert(expr.id, (kind, None)); |
c30ab7b3 SL |
109 | } |
110 | None => {} | |
1a4d82fc | 111 | } |
9e0c209e SL |
112 | |
113 | closure_type | |
1a4d82fc | 114 | } |
1a4d82fc | 115 | |
c30ab7b3 SL |
116 | fn deduce_expectations_from_expected_type |
117 | (&self, | |
118 | expected_ty: Ty<'tcx>) | |
119 | -> (Option<ty::FnSig<'tcx>>, Option<ty::ClosureKind>) { | |
a7813a04 XL |
120 | debug!("deduce_expectations_from_expected_type(expected_ty={:?})", |
121 | expected_ty); | |
122 | ||
123 | match expected_ty.sty { | |
476ff2be SL |
124 | ty::TyDynamic(ref object_type, ..) => { |
125 | let sig = object_type.projection_bounds() | |
c30ab7b3 SL |
126 | .filter_map(|pb| { |
127 | let pb = pb.with_self_ty(self.tcx, self.tcx.types.err); | |
128 | self.deduce_sig_from_projection(&pb) | |
129 | }) | |
130 | .next(); | |
476ff2be SL |
131 | let kind = object_type.principal() |
132 | .and_then(|p| self.tcx.lang_items.fn_trait_kind(p.def_id())); | |
a7813a04 | 133 | (sig, kind) |
85aaf69f | 134 | } |
c30ab7b3 | 135 | ty::TyInfer(ty::TyVar(vid)) => self.deduce_expectations_from_obligations(vid), |
7cac9316 | 136 | ty::TyFnPtr(sig) => (Some(sig.skip_binder().clone()), Some(ty::ClosureKind::Fn)), |
c30ab7b3 | 137 | _ => (None, None), |
a7813a04 XL |
138 | } |
139 | } | |
c34b1796 | 140 | |
c30ab7b3 SL |
141 | fn deduce_expectations_from_obligations |
142 | (&self, | |
143 | expected_vid: ty::TyVid) | |
144 | -> (Option<ty::FnSig<'tcx>>, Option<ty::ClosureKind>) { | |
a7813a04 XL |
145 | let fulfillment_cx = self.fulfillment_cx.borrow(); |
146 | // Here `expected_ty` is known to be a type inference variable. | |
147 | ||
c30ab7b3 | 148 | let expected_sig = fulfillment_cx.pending_obligations() |
a7813a04 XL |
149 | .iter() |
150 | .map(|obligation| &obligation.obligation) | |
151 | .filter_map(|obligation| { | |
152 | debug!("deduce_expectations_from_obligations: obligation.predicate={:?}", | |
153 | obligation.predicate); | |
154 | ||
155 | match obligation.predicate { | |
156 | // Given a Projection predicate, we can potentially infer | |
157 | // the complete signature. | |
158 | ty::Predicate::Projection(ref proj_predicate) => { | |
041b39d2 | 159 | let trait_ref = proj_predicate.to_poly_trait_ref(self.tcx); |
a7813a04 XL |
160 | self.self_type_matches_expected_vid(trait_ref, expected_vid) |
161 | .and_then(|_| self.deduce_sig_from_projection(proj_predicate)) | |
162 | } | |
c30ab7b3 | 163 | _ => None, |
a7813a04 XL |
164 | } |
165 | }) | |
166 | .next(); | |
167 | ||
168 | // Even if we can't infer the full signature, we may be able to | |
169 | // infer the kind. This can occur if there is a trait-reference | |
170 | // like `F : Fn<A>`. Note that due to subtyping we could encounter | |
171 | // many viable options, so pick the most restrictive. | |
c30ab7b3 | 172 | let expected_kind = fulfillment_cx.pending_obligations() |
a7813a04 XL |
173 | .iter() |
174 | .map(|obligation| &obligation.obligation) | |
175 | .filter_map(|obligation| { | |
176 | let opt_trait_ref = match obligation.predicate { | |
041b39d2 | 177 | ty::Predicate::Projection(ref data) => Some(data.to_poly_trait_ref(self.tcx)), |
a7813a04 XL |
178 | ty::Predicate::Trait(ref data) => Some(data.to_poly_trait_ref()), |
179 | ty::Predicate::Equate(..) => None, | |
cc61c64b | 180 | ty::Predicate::Subtype(..) => None, |
a7813a04 XL |
181 | ty::Predicate::RegionOutlives(..) => None, |
182 | ty::Predicate::TypeOutlives(..) => None, | |
183 | ty::Predicate::WellFormed(..) => None, | |
184 | ty::Predicate::ObjectSafe(..) => None, | |
a7813a04 XL |
185 | |
186 | // NB: This predicate is created by breaking down a | |
187 | // `ClosureType: FnFoo()` predicate, where | |
188 | // `ClosureType` represents some `TyClosure`. It can't | |
189 | // possibly be referring to the current closure, | |
190 | // because we haven't produced the `TyClosure` for | |
191 | // this closure yet; this is exactly why the other | |
192 | // code is looking for a self type of a unresolved | |
193 | // inference variable. | |
194 | ty::Predicate::ClosureKind(..) => None, | |
195 | }; | |
c30ab7b3 | 196 | opt_trait_ref.and_then(|tr| self.self_type_matches_expected_vid(tr, expected_vid)) |
a7813a04 XL |
197 | .and_then(|tr| self.tcx.lang_items.fn_trait_kind(tr.def_id())) |
198 | }) | |
c30ab7b3 SL |
199 | .fold(None, |
200 | |best, cur| Some(best.map_or(cur, |best| cmp::min(best, cur)))); | |
a7813a04 XL |
201 | |
202 | (expected_sig, expected_kind) | |
c34b1796 | 203 | } |
85aaf69f | 204 | |
a7813a04 XL |
205 | /// Given a projection like "<F as Fn(X)>::Result == Y", we can deduce |
206 | /// everything we need to know about a closure. | |
207 | fn deduce_sig_from_projection(&self, | |
c30ab7b3 SL |
208 | projection: &ty::PolyProjectionPredicate<'tcx>) |
209 | -> Option<ty::FnSig<'tcx>> { | |
a7813a04 | 210 | let tcx = self.tcx; |
1a4d82fc | 211 | |
c30ab7b3 | 212 | debug!("deduce_sig_from_projection({:?})", projection); |
85aaf69f | 213 | |
041b39d2 | 214 | let trait_ref = projection.to_poly_trait_ref(tcx); |
1a4d82fc | 215 | |
a7813a04 XL |
216 | if tcx.lang_items.fn_trait_kind(trait_ref.def_id()).is_none() { |
217 | return None; | |
218 | } | |
1a4d82fc | 219 | |
9e0c209e | 220 | let arg_param_ty = trait_ref.substs().type_at(1); |
a7813a04 | 221 | let arg_param_ty = self.resolve_type_vars_if_possible(&arg_param_ty); |
c30ab7b3 SL |
222 | debug!("deduce_sig_from_projection: arg_param_ty {:?}", |
223 | arg_param_ty); | |
1a4d82fc | 224 | |
a7813a04 | 225 | let input_tys = match arg_param_ty.sty { |
8bb4bdeb | 226 | ty::TyTuple(tys, _) => tys.into_iter(), |
c30ab7b3 SL |
227 | _ => { |
228 | return None; | |
229 | } | |
a7813a04 | 230 | }; |
1a4d82fc | 231 | |
a7813a04 XL |
232 | let ret_param_ty = projection.0.ty; |
233 | let ret_param_ty = self.resolve_type_vars_if_possible(&ret_param_ty); | |
476ff2be | 234 | debug!("deduce_sig_from_projection: ret_param_ty {:?}", ret_param_ty); |
1a4d82fc | 235 | |
8bb4bdeb XL |
236 | let fn_sig = self.tcx.mk_fn_sig( |
237 | input_tys.cloned(), | |
238 | ret_param_ty, | |
239 | false, | |
240 | hir::Unsafety::Normal, | |
241 | Abi::Rust | |
242 | ); | |
a7813a04 | 243 | debug!("deduce_sig_from_projection: fn_sig {:?}", fn_sig); |
1a4d82fc | 244 | |
a7813a04 XL |
245 | Some(fn_sig) |
246 | } | |
1a4d82fc | 247 | |
a7813a04 | 248 | fn self_type_matches_expected_vid(&self, |
c30ab7b3 SL |
249 | trait_ref: ty::PolyTraitRef<'tcx>, |
250 | expected_vid: ty::TyVid) | |
251 | -> Option<ty::PolyTraitRef<'tcx>> { | |
a7813a04 XL |
252 | let self_ty = self.shallow_resolve(trait_ref.self_ty()); |
253 | debug!("self_type_matches_expected_vid(trait_ref={:?}, self_ty={:?})", | |
254 | trait_ref, | |
255 | self_ty); | |
256 | match self_ty.sty { | |
257 | ty::TyInfer(ty::TyVar(v)) if expected_vid == v => Some(trait_ref), | |
258 | _ => None, | |
259 | } | |
1a4d82fc | 260 | } |
1a4d82fc | 261 | } |