Move closure checking into its own file. Shrink check/mod.rs!
This commit is contained in:
parent
cf7df1e638
commit
fe2fcb39f4
193
src/librustc/middle/typeck/check/closure.rs
Normal file
193
src/librustc/middle/typeck/check/closure.rs
Normal file
@ -0,0 +1,193 @@
|
||||
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
/*!
|
||||
* Code for type-checking closure expressions.
|
||||
*/
|
||||
|
||||
use super::check_fn;
|
||||
use super::Expectation;
|
||||
use super::FnCtxt;
|
||||
|
||||
use middle::ty;
|
||||
use middle::typeck::astconv;
|
||||
use middle::typeck::infer;
|
||||
use middle::typeck::rscope::RegionScope;
|
||||
use syntax::abi;
|
||||
use syntax::ast;
|
||||
use syntax::ast_util;
|
||||
use util::ppaux::Repr;
|
||||
|
||||
pub fn check_unboxed_closure(fcx: &FnCtxt,
|
||||
expr: &ast::Expr,
|
||||
kind: ast::UnboxedClosureKind,
|
||||
decl: &ast::FnDecl,
|
||||
body: &ast::Block) {
|
||||
let expr_def_id = ast_util::local_def(expr.id);
|
||||
|
||||
let mut fn_ty = astconv::ty_of_closure(
|
||||
fcx,
|
||||
ast::NormalFn,
|
||||
ast::Many,
|
||||
|
||||
// The `RegionTraitStore` and region_existential_bounds
|
||||
// are lies, but we ignore them so it doesn't matter.
|
||||
//
|
||||
// FIXME(pcwalton): Refactor this API.
|
||||
ty::region_existential_bound(ty::ReStatic),
|
||||
ty::RegionTraitStore(ty::ReStatic, ast::MutImmutable),
|
||||
|
||||
decl,
|
||||
abi::RustCall,
|
||||
None);
|
||||
|
||||
let region = match fcx.infcx().anon_regions(expr.span, 1) {
|
||||
Err(_) => {
|
||||
fcx.ccx.tcx.sess.span_bug(expr.span,
|
||||
"can't make anon regions here?!")
|
||||
}
|
||||
Ok(regions) => regions[0],
|
||||
};
|
||||
|
||||
let closure_type = ty::mk_unboxed_closure(fcx.ccx.tcx,
|
||||
expr_def_id,
|
||||
region,
|
||||
fcx.inh.param_env.free_substs.clone());
|
||||
|
||||
fcx.write_ty(expr.id, closure_type);
|
||||
|
||||
check_fn(fcx.ccx,
|
||||
ast::NormalFn,
|
||||
expr.id,
|
||||
&fn_ty.sig,
|
||||
decl,
|
||||
expr.id,
|
||||
&*body,
|
||||
fcx.inh);
|
||||
|
||||
// Tuple up the arguments and insert the resulting function type into
|
||||
// the `unboxed_closures` table.
|
||||
fn_ty.sig.inputs = vec![ty::mk_tup(fcx.tcx(), fn_ty.sig.inputs)];
|
||||
|
||||
let kind = match kind {
|
||||
ast::FnUnboxedClosureKind => ty::FnUnboxedClosureKind,
|
||||
ast::FnMutUnboxedClosureKind => ty::FnMutUnboxedClosureKind,
|
||||
ast::FnOnceUnboxedClosureKind => ty::FnOnceUnboxedClosureKind,
|
||||
};
|
||||
|
||||
debug!("unboxed_closure for {} --> sig={} kind={}",
|
||||
expr_def_id.repr(fcx.tcx()),
|
||||
fn_ty.sig.repr(fcx.tcx()),
|
||||
kind);
|
||||
|
||||
let unboxed_closure = ty::UnboxedClosure {
|
||||
closure_type: fn_ty,
|
||||
kind: kind,
|
||||
};
|
||||
|
||||
fcx.inh
|
||||
.unboxed_closures
|
||||
.borrow_mut()
|
||||
.insert(expr_def_id, unboxed_closure);
|
||||
}
|
||||
|
||||
pub fn check_expr_fn<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>,
|
||||
expr: &ast::Expr,
|
||||
store: ty::TraitStore,
|
||||
decl: &ast::FnDecl,
|
||||
body: &ast::Block,
|
||||
expected: Expectation<'tcx>) {
|
||||
let tcx = fcx.ccx.tcx;
|
||||
|
||||
// Find the expected input/output types (if any). Substitute
|
||||
// fresh bound regions for any bound regions we find in the
|
||||
// expected types so as to avoid capture.
|
||||
let expected_sty = expected.map_to_option(fcx, |x| Some((*x).clone()));
|
||||
let (expected_sig,
|
||||
expected_onceness,
|
||||
expected_bounds) = {
|
||||
match expected_sty {
|
||||
Some(ty::ty_closure(ref cenv)) => {
|
||||
let (sig, _) =
|
||||
ty::replace_late_bound_regions(
|
||||
tcx,
|
||||
&cenv.sig,
|
||||
|_, debruijn| fcx.inh.infcx.fresh_bound_region(debruijn));
|
||||
let onceness = match (&store, &cenv.store) {
|
||||
// As the closure type and onceness go, only three
|
||||
// combinations are legit:
|
||||
// once closure
|
||||
// many closure
|
||||
// once proc
|
||||
// If the actual and expected closure type disagree with
|
||||
// each other, set expected onceness to be always Once or
|
||||
// Many according to the actual type. Otherwise, it will
|
||||
// yield either an illegal "many proc" or a less known
|
||||
// "once closure" in the error message.
|
||||
(&ty::UniqTraitStore, &ty::UniqTraitStore) |
|
||||
(&ty::RegionTraitStore(..), &ty::RegionTraitStore(..)) =>
|
||||
cenv.onceness,
|
||||
(&ty::UniqTraitStore, _) => ast::Once,
|
||||
(&ty::RegionTraitStore(..), _) => ast::Many,
|
||||
};
|
||||
(Some(sig), onceness, cenv.bounds)
|
||||
}
|
||||
_ => {
|
||||
// Not an error! Means we're inferring the closure type
|
||||
let (bounds, onceness) = match expr.node {
|
||||
ast::ExprProc(..) => {
|
||||
let mut bounds = ty::region_existential_bound(ty::ReStatic);
|
||||
bounds.builtin_bounds.insert(ty::BoundSend); // FIXME
|
||||
(bounds, ast::Once)
|
||||
}
|
||||
_ => {
|
||||
let region = fcx.infcx().next_region_var(
|
||||
infer::AddrOfRegion(expr.span));
|
||||
(ty::region_existential_bound(region), ast::Many)
|
||||
}
|
||||
};
|
||||
(None, onceness, bounds)
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// construct the function type
|
||||
let fn_ty = astconv::ty_of_closure(fcx,
|
||||
ast::NormalFn,
|
||||
expected_onceness,
|
||||
expected_bounds,
|
||||
store,
|
||||
decl,
|
||||
abi::Rust,
|
||||
expected_sig);
|
||||
let fty_sig = fn_ty.sig.clone();
|
||||
let fty = ty::mk_closure(tcx, fn_ty);
|
||||
debug!("check_expr_fn fty={}", fcx.infcx().ty_to_string(fty));
|
||||
|
||||
fcx.write_ty(expr.id, fty);
|
||||
|
||||
// If the closure is a stack closure and hasn't had some non-standard
|
||||
// style inferred for it, then check it under its parent's style.
|
||||
// Otherwise, use its own
|
||||
let (inherited_style, inherited_style_id) = match store {
|
||||
ty::RegionTraitStore(..) => (fcx.ps.borrow().fn_style,
|
||||
fcx.ps.borrow().def),
|
||||
ty::UniqTraitStore => (ast::NormalFn, expr.id)
|
||||
};
|
||||
|
||||
check_fn(fcx.ccx,
|
||||
inherited_style,
|
||||
inherited_style_id,
|
||||
&fty_sig,
|
||||
&*decl,
|
||||
expr.id,
|
||||
&*body,
|
||||
fcx.inh);
|
||||
}
|
@ -147,6 +147,7 @@ pub mod regionck;
|
||||
pub mod demand;
|
||||
pub mod method;
|
||||
pub mod wf;
|
||||
mod closure;
|
||||
|
||||
/// Fields that are part of a `FnCtxt` which are inherited by
|
||||
/// closures defined within the function. For example:
|
||||
@ -3519,174 +3520,6 @@ fn check_expr_with_unifier<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
|
||||
})
|
||||
}
|
||||
|
||||
fn check_unboxed_closure(fcx: &FnCtxt,
|
||||
expr: &ast::Expr,
|
||||
kind: ast::UnboxedClosureKind,
|
||||
decl: &ast::FnDecl,
|
||||
body: &ast::Block) {
|
||||
let mut fn_ty = astconv::ty_of_closure(
|
||||
fcx,
|
||||
ast::NormalFn,
|
||||
ast::Many,
|
||||
|
||||
// The `RegionTraitStore` and region_existential_bounds
|
||||
// are lies, but we ignore them so it doesn't matter.
|
||||
//
|
||||
// FIXME(pcwalton): Refactor this API.
|
||||
ty::region_existential_bound(ty::ReStatic),
|
||||
ty::RegionTraitStore(ty::ReStatic, ast::MutImmutable),
|
||||
|
||||
decl,
|
||||
abi::RustCall,
|
||||
None);
|
||||
|
||||
let region = match fcx.infcx().anon_regions(expr.span, 1) {
|
||||
Err(_) => {
|
||||
fcx.ccx.tcx.sess.span_bug(expr.span,
|
||||
"can't make anon regions here?!")
|
||||
}
|
||||
Ok(regions) => regions[0],
|
||||
};
|
||||
let closure_type = ty::mk_unboxed_closure(fcx.ccx.tcx,
|
||||
local_def(expr.id),
|
||||
region,
|
||||
fcx.inh.param_env.free_substs.clone());
|
||||
fcx.write_ty(expr.id, closure_type);
|
||||
|
||||
check_fn(fcx.ccx,
|
||||
ast::NormalFn,
|
||||
expr.id,
|
||||
&fn_ty.sig,
|
||||
decl,
|
||||
expr.id,
|
||||
&*body,
|
||||
fcx.inh);
|
||||
|
||||
// Tuple up the arguments and insert the resulting function type into
|
||||
// the `unboxed_closures` table.
|
||||
fn_ty.sig.inputs = vec![ty::mk_tup(fcx.tcx(), fn_ty.sig.inputs)];
|
||||
|
||||
let kind = match kind {
|
||||
ast::FnUnboxedClosureKind => ty::FnUnboxedClosureKind,
|
||||
ast::FnMutUnboxedClosureKind => ty::FnMutUnboxedClosureKind,
|
||||
ast::FnOnceUnboxedClosureKind => ty::FnOnceUnboxedClosureKind,
|
||||
};
|
||||
|
||||
debug!("unboxed_closure for {} --> sig={} kind={}",
|
||||
local_def(expr.id).repr(fcx.tcx()),
|
||||
fn_ty.sig.repr(fcx.tcx()),
|
||||
kind);
|
||||
|
||||
let unboxed_closure = ty::UnboxedClosure {
|
||||
closure_type: fn_ty,
|
||||
kind: kind,
|
||||
};
|
||||
|
||||
fcx.inh
|
||||
.unboxed_closures
|
||||
.borrow_mut()
|
||||
.insert(local_def(expr.id), unboxed_closure);
|
||||
}
|
||||
|
||||
fn check_expr_fn<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
|
||||
expr: &ast::Expr,
|
||||
store: ty::TraitStore,
|
||||
decl: &ast::FnDecl,
|
||||
body: &ast::Block,
|
||||
expected: Expectation<'tcx>) {
|
||||
let tcx = fcx.ccx.tcx;
|
||||
|
||||
debug!("check_expr_fn(expr={}, expected={})",
|
||||
expr.repr(tcx),
|
||||
expected.repr(tcx));
|
||||
|
||||
// Find the expected input/output types (if any). Substitute
|
||||
// fresh bound regions for any bound regions we find in the
|
||||
// expected types so as to avoid capture.
|
||||
let expected_sty = expected.map_to_option(fcx, |x| Some((*x).clone()));
|
||||
let (expected_sig,
|
||||
expected_onceness,
|
||||
expected_bounds) = {
|
||||
match expected_sty {
|
||||
Some(ty::ty_closure(ref cenv)) => {
|
||||
let (sig, _) =
|
||||
replace_late_bound_regions(
|
||||
tcx,
|
||||
&cenv.sig,
|
||||
|_, debruijn| fcx.inh.infcx.fresh_bound_region(debruijn));
|
||||
let onceness = match (&store, &cenv.store) {
|
||||
// As the closure type and onceness go, only three
|
||||
// combinations are legit:
|
||||
// once closure
|
||||
// many closure
|
||||
// once proc
|
||||
// If the actual and expected closure type disagree with
|
||||
// each other, set expected onceness to be always Once or
|
||||
// Many according to the actual type. Otherwise, it will
|
||||
// yield either an illegal "many proc" or a less known
|
||||
// "once closure" in the error message.
|
||||
(&ty::UniqTraitStore, &ty::UniqTraitStore) |
|
||||
(&ty::RegionTraitStore(..), &ty::RegionTraitStore(..)) =>
|
||||
cenv.onceness,
|
||||
(&ty::UniqTraitStore, _) => ast::Once,
|
||||
(&ty::RegionTraitStore(..), _) => ast::Many,
|
||||
};
|
||||
(Some(sig), onceness, cenv.bounds)
|
||||
}
|
||||
_ => {
|
||||
// Not an error! Means we're inferring the closure type
|
||||
let (bounds, onceness) = match expr.node {
|
||||
ast::ExprProc(..) => {
|
||||
let mut bounds = ty::region_existential_bound(ty::ReStatic);
|
||||
bounds.builtin_bounds.insert(ty::BoundSend); // FIXME
|
||||
(bounds, ast::Once)
|
||||
}
|
||||
_ => {
|
||||
let region = fcx.infcx().next_region_var(
|
||||
infer::AddrOfRegion(expr.span));
|
||||
(ty::region_existential_bound(region), ast::Many)
|
||||
}
|
||||
};
|
||||
(None, onceness, bounds)
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// construct the function type
|
||||
let fn_ty = astconv::ty_of_closure(fcx,
|
||||
ast::NormalFn,
|
||||
expected_onceness,
|
||||
expected_bounds,
|
||||
store,
|
||||
decl,
|
||||
abi::Rust,
|
||||
expected_sig);
|
||||
let fty_sig = fn_ty.sig.clone();
|
||||
let fty = ty::mk_closure(tcx, fn_ty);
|
||||
debug!("check_expr_fn fty={}", fcx.infcx().ty_to_string(fty));
|
||||
|
||||
fcx.write_ty(expr.id, fty);
|
||||
|
||||
// If the closure is a stack closure and hasn't had some non-standard
|
||||
// style inferred for it, then check it under its parent's style.
|
||||
// Otherwise, use its own
|
||||
let (inherited_style, inherited_style_id) = match store {
|
||||
ty::RegionTraitStore(..) => (fcx.ps.borrow().fn_style,
|
||||
fcx.ps.borrow().def),
|
||||
ty::UniqTraitStore => (ast::NormalFn, expr.id)
|
||||
};
|
||||
|
||||
check_fn(fcx.ccx,
|
||||
inherited_style,
|
||||
inherited_style_id,
|
||||
&fty_sig,
|
||||
&*decl,
|
||||
expr.id,
|
||||
&*body,
|
||||
fcx.inh);
|
||||
}
|
||||
|
||||
|
||||
// Check field access expressions
|
||||
fn check_field(fcx: &FnCtxt,
|
||||
expr: &ast::Expr,
|
||||
@ -4320,27 +4153,27 @@ fn check_expr_with_unifier<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
|
||||
fcx.infcx(),
|
||||
expr.span,
|
||||
&None);
|
||||
check_expr_fn(fcx,
|
||||
expr,
|
||||
ty::RegionTraitStore(region, ast::MutMutable),
|
||||
&**decl,
|
||||
&**body,
|
||||
expected);
|
||||
closure::check_expr_fn(fcx,
|
||||
expr,
|
||||
ty::RegionTraitStore(region, ast::MutMutable),
|
||||
&**decl,
|
||||
&**body,
|
||||
expected);
|
||||
}
|
||||
ast::ExprUnboxedFn(_, kind, ref decl, ref body) => {
|
||||
check_unboxed_closure(fcx,
|
||||
expr,
|
||||
kind,
|
||||
&**decl,
|
||||
&**body);
|
||||
closure::check_unboxed_closure(fcx,
|
||||
expr,
|
||||
kind,
|
||||
&**decl,
|
||||
&**body);
|
||||
}
|
||||
ast::ExprProc(ref decl, ref body) => {
|
||||
check_expr_fn(fcx,
|
||||
expr,
|
||||
ty::UniqTraitStore,
|
||||
&**decl,
|
||||
&**body,
|
||||
expected);
|
||||
closure::check_expr_fn(fcx,
|
||||
expr,
|
||||
ty::UniqTraitStore,
|
||||
&**decl,
|
||||
&**body,
|
||||
expected);
|
||||
}
|
||||
ast::ExprBlock(ref b) => {
|
||||
check_block_with_expected(fcx, &**b, expected);
|
||||
|
Loading…
x
Reference in New Issue
Block a user