]> git.proxmox.com Git - rustc.git/blame - src/librustc_typeck/check/closure.rs
Imported Upstream version 1.3.0+dfsg1
[rustc.git] / src / librustc_typeck / check / closure.rs
CommitLineData
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
13use super::{check_fn, Expectation, FnCtxt};
14
15use astconv;
85aaf69f 16use middle::region;
1a4d82fc
JJ
17use middle::subst;
18use middle::ty::{self, ToPolyTraitRef, Ty};
c34b1796 19use std::cmp;
1a4d82fc
JJ
20use syntax::abi;
21use syntax::ast;
22use syntax::ast_util;
1a4d82fc
JJ
23
24pub 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
44fn 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 107fn 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
134fn 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
190fn 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 202fn 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 242fn 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}