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};
16 use middle::region::CodeExtent;
18 use middle::ty::{self, ToPolyTraitRef, Ty};
19 use rscope::RegionScope;
23 use util::ppaux::Repr;
25 pub fn check_expr_closure<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>,
27 _capture: ast::CaptureClause,
28 opt_kind: Option<ast::UnboxedClosureKind>,
31 expected: Expectation<'tcx>) {
32 debug!("check_expr_closure(expr={},expected={})",
34 expected.repr(fcx.tcx()));
36 let expected_sig_and_kind = expected.to_option(fcx).and_then(|ty| {
37 deduce_unboxed_closure_expectations_from_expected_type(fcx, ty)
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;
51 check_unboxed_closure(fcx, expr, kind, decl, body, None);
53 span_err!(fcx.ccx.tcx.sess, expr.span, E0187,
54 "can't infer the \"kind\" of the closure, explicitly annotate it. e.g. \
57 Some((sig, kind)) => {
58 check_unboxed_closure(fcx, expr, kind, decl, body, Some(sig));
64 let kind = match kind {
65 ast::FnUnboxedClosureKind => ty::FnUnboxedClosureKind,
66 ast::FnMutUnboxedClosureKind => ty::FnMutUnboxedClosureKind,
67 ast::FnOnceUnboxedClosureKind => ty::FnOnceUnboxedClosureKind,
70 let expected_sig = expected_sig_and_kind.map(|t| t.0);
71 check_unboxed_closure(fcx, expr, kind, decl, body, expected_sig);
76 fn check_unboxed_closure<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>,
78 kind: ty::UnboxedClosureKind,
81 expected_sig: Option<ty::FnSig<'tcx>>) {
82 let expr_def_id = ast_util::local_def(expr.id);
84 debug!("check_unboxed_closure kind={:?} expected_sig={}",
86 expected_sig.repr(fcx.tcx()));
88 let mut fn_ty = astconv::ty_of_closure(
90 ast::Unsafety::Normal,
93 // The `RegionTraitStore` and region_existential_bounds
94 // are lies, but we ignore them so it doesn't matter.
96 // FIXME(pcwalton): Refactor this API.
97 ty::region_existential_bound(ty::ReStatic),
98 ty::RegionTraitStore(ty::ReStatic, ast::MutImmutable),
104 let region = match fcx.anon_regions(expr.span, 1) {
106 fcx.ccx.tcx.sess.span_bug(expr.span,
107 "can't make anon regions here?!")
109 Ok(regions) => regions[0],
112 let closure_type = ty::mk_unboxed_closure(fcx.ccx.tcx,
114 fcx.ccx.tcx.mk_region(region),
115 fcx.ccx.tcx.mk_substs(
116 fcx.inh.param_env.free_substs.clone()));
118 fcx.write_ty(expr.id, closure_type);
121 ty::liberate_late_bound_regions(fcx.tcx(), CodeExtent::from_node_id(body.id), &fn_ty.sig);
124 ast::Unsafety::Normal,
132 // Tuple up the arguments and insert the resulting function type into
133 // the `unboxed_closures` table.
134 fn_ty.sig.0.inputs = vec![ty::mk_tup(fcx.tcx(), fn_ty.sig.0.inputs)];
136 debug!("unboxed_closure for {} --> sig={} kind={:?}",
137 expr_def_id.repr(fcx.tcx()),
138 fn_ty.sig.repr(fcx.tcx()),
141 let unboxed_closure = ty::UnboxedClosure {
149 .insert(expr_def_id, unboxed_closure);
152 fn deduce_unboxed_closure_expectations_from_expected_type<'a,'tcx>(
153 fcx: &FnCtxt<'a,'tcx>,
154 expected_ty: Ty<'tcx>)
155 -> Option<(ty::FnSig<'tcx>,ty::UnboxedClosureKind)>
157 match expected_ty.sty {
158 ty::ty_trait(ref object_type) => {
160 object_type.principal_trait_ref_with_self_ty(fcx.tcx(),
161 fcx.tcx().types.err);
162 deduce_unboxed_closure_expectations_from_trait_ref(fcx, &trait_ref)
164 ty::ty_infer(ty::TyVar(vid)) => {
165 deduce_unboxed_closure_expectations_from_obligations(fcx, vid)
173 fn deduce_unboxed_closure_expectations_from_trait_ref<'a,'tcx>(
174 fcx: &FnCtxt<'a,'tcx>,
175 trait_ref: &ty::PolyTraitRef<'tcx>)
176 -> Option<(ty::FnSig<'tcx>, ty::UnboxedClosureKind)>
180 debug!("deduce_unboxed_closure_expectations_from_object_type({})",
181 trait_ref.repr(tcx));
183 let kind = match tcx.lang_items.fn_trait_kind(trait_ref.def_id()) {
185 None => { return None; }
188 debug!("found object type {:?}", kind);
190 let arg_param_ty = *trait_ref.substs().types.get(subst::TypeSpace, 0);
191 let arg_param_ty = fcx.infcx().resolve_type_vars_if_possible(&arg_param_ty);
192 debug!("arg_param_ty {}", arg_param_ty.repr(tcx));
194 let input_tys = match arg_param_ty.sty {
195 ty::ty_tup(ref tys) => { (*tys).clone() }
196 _ => { return None; }
198 debug!("input_tys {}", input_tys.repr(tcx));
200 let ret_param_ty = *trait_ref.substs().types.get(subst::TypeSpace, 1);
201 let ret_param_ty = fcx.infcx().resolve_type_vars_if_possible(&ret_param_ty);
202 debug!("ret_param_ty {}", ret_param_ty.repr(tcx));
204 let fn_sig = ty::FnSig {
206 output: ty::FnConverging(ret_param_ty),
209 debug!("fn_sig {}", fn_sig.repr(tcx));
211 return Some((fn_sig, kind));
214 fn deduce_unboxed_closure_expectations_from_obligations<'a,'tcx>(
215 fcx: &FnCtxt<'a,'tcx>,
216 expected_vid: ty::TyVid)
217 -> Option<(ty::FnSig<'tcx>, ty::UnboxedClosureKind)>
219 // Here `expected_ty` is known to be a type inference variable.
220 for obligation in fcx.inh.fulfillment_cx.borrow().pending_obligations().iter() {
221 match obligation.predicate {
222 ty::Predicate::Trait(ref trait_predicate) => {
223 let trait_ref = trait_predicate.to_poly_trait_ref();
224 let self_ty = fcx.infcx().shallow_resolve(trait_ref.self_ty());
226 ty::ty_infer(ty::TyVar(v)) if expected_vid == v => { }
230 match deduce_unboxed_closure_expectations_from_trait_ref(fcx, &trait_ref) {
231 Some(e) => { return Some(e); }