Skip to content

Commit fe2fcb3

Browse files
committed
Move closure checking into its own file. Shrink check/mod.rs!
1 parent cf7df1e commit fe2fcb3

File tree

2 files changed

+211
-185
lines changed

2 files changed

+211
-185
lines changed
+193
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,193 @@
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+
/*!
12+
* Code for type-checking closure expressions.
13+
*/
14+
15+
use super::check_fn;
16+
use super::Expectation;
17+
use super::FnCtxt;
18+
19+
use middle::ty;
20+
use middle::typeck::astconv;
21+
use middle::typeck::infer;
22+
use middle::typeck::rscope::RegionScope;
23+
use syntax::abi;
24+
use syntax::ast;
25+
use syntax::ast_util;
26+
use util::ppaux::Repr;
27+
28+
pub fn check_unboxed_closure(fcx: &FnCtxt,
29+
expr: &ast::Expr,
30+
kind: ast::UnboxedClosureKind,
31+
decl: &ast::FnDecl,
32+
body: &ast::Block) {
33+
let expr_def_id = ast_util::local_def(expr.id);
34+
35+
let mut fn_ty = astconv::ty_of_closure(
36+
fcx,
37+
ast::NormalFn,
38+
ast::Many,
39+
40+
// The `RegionTraitStore` and region_existential_bounds
41+
// are lies, but we ignore them so it doesn't matter.
42+
//
43+
// FIXME(pcwalton): Refactor this API.
44+
ty::region_existential_bound(ty::ReStatic),
45+
ty::RegionTraitStore(ty::ReStatic, ast::MutImmutable),
46+
47+
decl,
48+
abi::RustCall,
49+
None);
50+
51+
let region = match fcx.infcx().anon_regions(expr.span, 1) {
52+
Err(_) => {
53+
fcx.ccx.tcx.sess.span_bug(expr.span,
54+
"can't make anon regions here?!")
55+
}
56+
Ok(regions) => regions[0],
57+
};
58+
59+
let closure_type = ty::mk_unboxed_closure(fcx.ccx.tcx,
60+
expr_def_id,
61+
region,
62+
fcx.inh.param_env.free_substs.clone());
63+
64+
fcx.write_ty(expr.id, closure_type);
65+
66+
check_fn(fcx.ccx,
67+
ast::NormalFn,
68+
expr.id,
69+
&fn_ty.sig,
70+
decl,
71+
expr.id,
72+
&*body,
73+
fcx.inh);
74+
75+
// Tuple up the arguments and insert the resulting function type into
76+
// the `unboxed_closures` table.
77+
fn_ty.sig.inputs = vec![ty::mk_tup(fcx.tcx(), fn_ty.sig.inputs)];
78+
79+
let kind = match kind {
80+
ast::FnUnboxedClosureKind => ty::FnUnboxedClosureKind,
81+
ast::FnMutUnboxedClosureKind => ty::FnMutUnboxedClosureKind,
82+
ast::FnOnceUnboxedClosureKind => ty::FnOnceUnboxedClosureKind,
83+
};
84+
85+
debug!("unboxed_closure for {} --> sig={} kind={}",
86+
expr_def_id.repr(fcx.tcx()),
87+
fn_ty.sig.repr(fcx.tcx()),
88+
kind);
89+
90+
let unboxed_closure = ty::UnboxedClosure {
91+
closure_type: fn_ty,
92+
kind: kind,
93+
};
94+
95+
fcx.inh
96+
.unboxed_closures
97+
.borrow_mut()
98+
.insert(expr_def_id, unboxed_closure);
99+
}
100+
101+
pub fn check_expr_fn<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>,
102+
expr: &ast::Expr,
103+
store: ty::TraitStore,
104+
decl: &ast::FnDecl,
105+
body: &ast::Block,
106+
expected: Expectation<'tcx>) {
107+
let tcx = fcx.ccx.tcx;
108+
109+
// Find the expected input/output types (if any). Substitute
110+
// fresh bound regions for any bound regions we find in the
111+
// expected types so as to avoid capture.
112+
let expected_sty = expected.map_to_option(fcx, |x| Some((*x).clone()));
113+
let (expected_sig,
114+
expected_onceness,
115+
expected_bounds) = {
116+
match expected_sty {
117+
Some(ty::ty_closure(ref cenv)) => {
118+
let (sig, _) =
119+
ty::replace_late_bound_regions(
120+
tcx,
121+
&cenv.sig,
122+
|_, debruijn| fcx.inh.infcx.fresh_bound_region(debruijn));
123+
let onceness = match (&store, &cenv.store) {
124+
// As the closure type and onceness go, only three
125+
// combinations are legit:
126+
// once closure
127+
// many closure
128+
// once proc
129+
// If the actual and expected closure type disagree with
130+
// each other, set expected onceness to be always Once or
131+
// Many according to the actual type. Otherwise, it will
132+
// yield either an illegal "many proc" or a less known
133+
// "once closure" in the error message.
134+
(&ty::UniqTraitStore, &ty::UniqTraitStore) |
135+
(&ty::RegionTraitStore(..), &ty::RegionTraitStore(..)) =>
136+
cenv.onceness,
137+
(&ty::UniqTraitStore, _) => ast::Once,
138+
(&ty::RegionTraitStore(..), _) => ast::Many,
139+
};
140+
(Some(sig), onceness, cenv.bounds)
141+
}
142+
_ => {
143+
// Not an error! Means we're inferring the closure type
144+
let (bounds, onceness) = match expr.node {
145+
ast::ExprProc(..) => {
146+
let mut bounds = ty::region_existential_bound(ty::ReStatic);
147+
bounds.builtin_bounds.insert(ty::BoundSend); // FIXME
148+
(bounds, ast::Once)
149+
}
150+
_ => {
151+
let region = fcx.infcx().next_region_var(
152+
infer::AddrOfRegion(expr.span));
153+
(ty::region_existential_bound(region), ast::Many)
154+
}
155+
};
156+
(None, onceness, bounds)
157+
}
158+
}
159+
};
160+
161+
// construct the function type
162+
let fn_ty = astconv::ty_of_closure(fcx,
163+
ast::NormalFn,
164+
expected_onceness,
165+
expected_bounds,
166+
store,
167+
decl,
168+
abi::Rust,
169+
expected_sig);
170+
let fty_sig = fn_ty.sig.clone();
171+
let fty = ty::mk_closure(tcx, fn_ty);
172+
debug!("check_expr_fn fty={}", fcx.infcx().ty_to_string(fty));
173+
174+
fcx.write_ty(expr.id, fty);
175+
176+
// If the closure is a stack closure and hasn't had some non-standard
177+
// style inferred for it, then check it under its parent's style.
178+
// Otherwise, use its own
179+
let (inherited_style, inherited_style_id) = match store {
180+
ty::RegionTraitStore(..) => (fcx.ps.borrow().fn_style,
181+
fcx.ps.borrow().def),
182+
ty::UniqTraitStore => (ast::NormalFn, expr.id)
183+
};
184+
185+
check_fn(fcx.ccx,
186+
inherited_style,
187+
inherited_style_id,
188+
&fty_sig,
189+
&*decl,
190+
expr.id,
191+
&*body,
192+
fcx.inh);
193+
}

0 commit comments

Comments
 (0)