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.
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.
11 //! Code for type-checking closure expressions.
13 use super::{check_fn, Expectation, FnCtxt};
17 use middle::region::CodeExtent;
19 use middle::ty::{self, ToPolyTraitRef, Ty};
20 use rscope::RegionScope;
23 use syntax::ast::CaptureClause::*;
25 use util::ppaux::Repr;
27 pub fn check_expr_closure<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>,
29 capture: ast::CaptureClause,
30 opt_kind: Option<ast::UnboxedClosureKind>,
33 expected: Expectation<'tcx>) {
34 debug!("check_expr_closure(expr={},expected={})",
36 expected.repr(fcx.tcx()));
38 let expected_sig_and_kind = expected.map_to_option(fcx, |ty| {
39 deduce_unboxed_closure_expectations_from_expected_type(fcx, ty)
44 // If users didn't specify what sort of closure they want,
45 // examine the expected type. For now, if we see explicit
46 // evidence than an unboxed closure is desired, we'll use
47 // that, otherwise we'll fall back to boxed closures.
48 match expected_sig_and_kind {
49 None => { // doesn't look like an unboxed closure
50 let region = astconv::opt_ast_region_to_region(fcx,
55 check_boxed_closure(fcx,
57 ty::RegionTraitStore(region, ast::MutMutable),
64 fcx.ccx.tcx.sess.span_err(
66 "boxed closures can't capture by value, \
67 if you want to use an unboxed closure, \
68 explicitly annotate its kind: e.g. `move |:|`");
73 Some((sig, kind)) => {
74 check_unboxed_closure(fcx, expr, kind, decl, body, Some(sig));
80 let kind = match kind {
81 ast::FnUnboxedClosureKind => ty::FnUnboxedClosureKind,
82 ast::FnMutUnboxedClosureKind => ty::FnMutUnboxedClosureKind,
83 ast::FnOnceUnboxedClosureKind => ty::FnOnceUnboxedClosureKind,
86 let expected_sig = expected_sig_and_kind.map(|t| t.0);
87 check_unboxed_closure(fcx, expr, kind, decl, body, expected_sig);
92 fn check_unboxed_closure<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>,
94 kind: ty::UnboxedClosureKind,
97 expected_sig: Option<ty::FnSig<'tcx>>) {
98 let expr_def_id = ast_util::local_def(expr.id);
100 debug!("check_unboxed_closure kind={} expected_sig={}",
102 expected_sig.repr(fcx.tcx()));
104 let mut fn_ty = astconv::ty_of_closure(
106 ast::Unsafety::Normal,
109 // The `RegionTraitStore` and region_existential_bounds
110 // are lies, but we ignore them so it doesn't matter.
112 // FIXME(pcwalton): Refactor this API.
113 ty::region_existential_bound(ty::ReStatic),
114 ty::RegionTraitStore(ty::ReStatic, ast::MutImmutable),
120 let region = match fcx.anon_regions(expr.span, 1) {
122 fcx.ccx.tcx.sess.span_bug(expr.span,
123 "can't make anon regions here?!")
125 Ok(regions) => regions[0],
128 let closure_type = ty::mk_unboxed_closure(fcx.ccx.tcx,
130 fcx.ccx.tcx.mk_region(region),
131 fcx.ccx.tcx.mk_substs(
132 fcx.inh.param_env.free_substs.clone()));
134 fcx.write_ty(expr.id, closure_type);
137 ty::liberate_late_bound_regions(fcx.tcx(), CodeExtent::from_node_id(body.id), &fn_ty.sig);
140 ast::Unsafety::Normal,
148 // Tuple up the arguments and insert the resulting function type into
149 // the `unboxed_closures` table.
150 fn_ty.sig.0.inputs = vec![ty::mk_tup(fcx.tcx(), fn_ty.sig.0.inputs)];
152 debug!("unboxed_closure for {} --> sig={} kind={}",
153 expr_def_id.repr(fcx.tcx()),
154 fn_ty.sig.repr(fcx.tcx()),
157 let unboxed_closure = ty::UnboxedClosure {
165 .insert(expr_def_id, unboxed_closure);
168 fn deduce_unboxed_closure_expectations_from_expected_type<'a,'tcx>(
169 fcx: &FnCtxt<'a,'tcx>,
170 expected_ty: Ty<'tcx>)
171 -> Option<(ty::FnSig<'tcx>,ty::UnboxedClosureKind)>
173 match expected_ty.sty {
174 ty::ty_trait(ref object_type) => {
176 object_type.principal_trait_ref_with_self_ty(fcx.tcx(),
177 fcx.tcx().types.err);
178 deduce_unboxed_closure_expectations_from_trait_ref(fcx, &trait_ref)
180 ty::ty_infer(ty::TyVar(vid)) => {
181 deduce_unboxed_closure_expectations_from_obligations(fcx, vid)
189 fn deduce_unboxed_closure_expectations_from_trait_ref<'a,'tcx>(
190 fcx: &FnCtxt<'a,'tcx>,
191 trait_ref: &ty::PolyTraitRef<'tcx>)
192 -> Option<(ty::FnSig<'tcx>, ty::UnboxedClosureKind)>
196 debug!("deduce_unboxed_closure_expectations_from_object_type({})",
197 trait_ref.repr(tcx));
199 let kind = match tcx.lang_items.fn_trait_kind(trait_ref.def_id()) {
201 None => { return None; }
204 debug!("found object type {}", kind);
206 let arg_param_ty = *trait_ref.substs().types.get(subst::TypeSpace, 0);
207 let arg_param_ty = fcx.infcx().resolve_type_vars_if_possible(&arg_param_ty);
208 debug!("arg_param_ty {}", arg_param_ty.repr(tcx));
210 let input_tys = match arg_param_ty.sty {
211 ty::ty_tup(ref tys) => { (*tys).clone() }
212 _ => { return None; }
214 debug!("input_tys {}", input_tys.repr(tcx));
216 let ret_param_ty = *trait_ref.substs().types.get(subst::TypeSpace, 1);
217 let ret_param_ty = fcx.infcx().resolve_type_vars_if_possible(&ret_param_ty);
218 debug!("ret_param_ty {}", ret_param_ty.repr(tcx));
220 let fn_sig = ty::FnSig {
222 output: ty::FnConverging(ret_param_ty),
225 debug!("fn_sig {}", fn_sig.repr(tcx));
227 return Some((fn_sig, kind));
230 fn deduce_unboxed_closure_expectations_from_obligations<'a,'tcx>(
231 fcx: &FnCtxt<'a,'tcx>,
232 expected_vid: ty::TyVid)
233 -> Option<(ty::FnSig<'tcx>, ty::UnboxedClosureKind)>
235 // Here `expected_ty` is known to be a type inference variable.
236 for obligation in fcx.inh.fulfillment_cx.borrow().pending_obligations().iter() {
237 match obligation.predicate {
238 ty::Predicate::Trait(ref trait_predicate) => {
239 let trait_ref = trait_predicate.to_poly_trait_ref();
240 let self_ty = fcx.infcx().shallow_resolve(trait_ref.self_ty());
242 ty::ty_infer(ty::TyVar(v)) if expected_vid == v => { }
246 match deduce_unboxed_closure_expectations_from_trait_ref(fcx, &trait_ref) {
247 Some(e) => { return Some(e); }
259 fn check_boxed_closure<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>,
261 store: ty::TraitStore,
264 expected: Expectation<'tcx>) {
265 let tcx = fcx.ccx.tcx;
267 // Find the expected input/output types (if any). Substitute
268 // fresh bound regions for any bound regions we find in the
269 // expected types so as to avoid capture.
270 let expected_cenv = expected.map_to_option(fcx, |ty| match ty.sty {
271 ty::ty_closure(ref cenv) => Some(cenv),
274 let (expected_sig, expected_onceness, expected_bounds) = match expected_cenv {
277 ty::replace_late_bound_regions(
280 |_, debruijn| fcx.inh.infcx.fresh_bound_region(debruijn));
281 let onceness = match (&store, &cenv.store) {
282 // As the closure type and onceness go, only three
283 // combinations are legit:
287 // If the actual and expected closure type disagree with
288 // each other, set expected onceness to be always Once or
289 // Many according to the actual type. Otherwise, it will
290 // yield either an illegal "many proc" or a less known
291 // "once closure" in the error message.
292 (&ty::UniqTraitStore, &ty::UniqTraitStore) |
293 (&ty::RegionTraitStore(..), &ty::RegionTraitStore(..)) =>
295 (&ty::UniqTraitStore, _) => ast::Once,
296 (&ty::RegionTraitStore(..), _) => ast::Many,
298 (Some(sig), onceness, cenv.bounds.clone())
301 // Not an error! Means we're inferring the closure type
302 let region = fcx.infcx().next_region_var(
303 infer::AddrOfRegion(expr.span));
304 let bounds = ty::region_existential_bound(region);
305 let onceness = ast::Many;
306 (None, onceness, bounds)
310 // construct the function type
311 let fn_ty = astconv::ty_of_closure(fcx,
312 ast::Unsafety::Normal,
319 let fn_sig = fn_ty.sig.clone();
320 let fty = ty::mk_closure(tcx, fn_ty);
321 debug!("check_expr_fn fty={}", fcx.infcx().ty_to_string(fty));
323 fcx.write_ty(expr.id, fty);
325 // If the closure is a stack closure and hasn't had some non-standard
326 // style inferred for it, then check it under its parent's style.
327 // Otherwise, use its own
328 let (inherited_style, inherited_style_id) = match store {
329 ty::RegionTraitStore(..) => (fcx.ps.borrow().unsafety,
330 fcx.ps.borrow().def),
331 ty::UniqTraitStore => (ast::Unsafety::Normal, expr.id)
335 ty::liberate_late_bound_regions(tcx, CodeExtent::from_node_id(body.id), &fn_sig);