auto merge of #19113 : nikomatsakis/rust/unboxed-boxed-closure-unification, r=acrichto
Use the expected type to infer the argument/return types of unboxed closures. Also, in `||` expressions, use the expected type to decide if the result should be a boxed or unboxed closure (and if an unboxed closure, what kind). This supercedes PR #19089, which was already reviewed by @pcwalton.
This commit is contained in:
commit
1d81776209
@ -288,9 +288,12 @@ pub fn closure_to_block(closure_id: ast::NodeId,
|
||||
match tcx.map.get(closure_id) {
|
||||
ast_map::NodeExpr(expr) => match expr.node {
|
||||
ast::ExprProc(_, ref block) |
|
||||
ast::ExprFnBlock(_, _, ref block) |
|
||||
ast::ExprUnboxedFn(_, _, _, ref block) => { block.id }
|
||||
_ => panic!("encountered non-closure id: {}", closure_id)
|
||||
ast::ExprClosure(_, _, _, ref block) => {
|
||||
block.id
|
||||
}
|
||||
_ => {
|
||||
panic!("encountered non-closure id: {}", closure_id)
|
||||
}
|
||||
},
|
||||
_ => panic!("encountered non-expr id: {}", closure_id)
|
||||
}
|
||||
|
@ -496,9 +496,8 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> {
|
||||
}
|
||||
|
||||
ast::ExprMac(..) |
|
||||
ast::ExprFnBlock(..) |
|
||||
ast::ExprClosure(..) |
|
||||
ast::ExprProc(..) |
|
||||
ast::ExprUnboxedFn(..) |
|
||||
ast::ExprLit(..) |
|
||||
ast::ExprPath(..) => {
|
||||
self.straightline(expr, pred, None::<ast::Expr>.iter())
|
||||
|
@ -48,9 +48,8 @@ impl<'a, 'v> Visitor<'v> for CheckLoopVisitor<'a> {
|
||||
self.visit_expr(&**e);
|
||||
self.with_context(Loop, |v| v.visit_block(&**b));
|
||||
}
|
||||
ast::ExprFnBlock(_, _, ref b) |
|
||||
ast::ExprProc(_, ref b) |
|
||||
ast::ExprUnboxedFn(_, _, _, ref b) => {
|
||||
ast::ExprClosure(_, _, _, ref b) |
|
||||
ast::ExprProc(_, ref b) => {
|
||||
self.with_context(Closure, |v| v.visit_block(&**b));
|
||||
}
|
||||
ast::ExprBreak(_) => self.require_loop("break", e.span),
|
||||
|
@ -496,8 +496,7 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> {
|
||||
self.consume_expr(&**count);
|
||||
}
|
||||
|
||||
ast::ExprFnBlock(..) |
|
||||
ast::ExprUnboxedFn(..) |
|
||||
ast::ExprClosure(..) |
|
||||
ast::ExprProc(..) => {
|
||||
self.walk_captures(expr)
|
||||
}
|
||||
|
@ -458,7 +458,7 @@ fn visit_expr(ir: &mut IrMaps, expr: &Expr) {
|
||||
}
|
||||
visit::walk_expr(ir, expr);
|
||||
}
|
||||
ast::ExprFnBlock(..) | ast::ExprProc(..) | ast::ExprUnboxedFn(..) => {
|
||||
ast::ExprClosure(..) | ast::ExprProc(..) => {
|
||||
// Interesting control flow (for loops can contain labeled
|
||||
// breaks or continues)
|
||||
ir.add_live_node_for_node(expr.id, ExprNode(expr.span));
|
||||
@ -975,10 +975,9 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
|
||||
self.propagate_through_expr(&**e, succ)
|
||||
}
|
||||
|
||||
ast::ExprFnBlock(_, _, ref blk) |
|
||||
ast::ExprProc(_, ref blk) |
|
||||
ast::ExprUnboxedFn(_, _, _, ref blk) => {
|
||||
debug!("{} is an ExprFnBlock, ExprProc, or ExprUnboxedFn",
|
||||
ast::ExprClosure(_, _, _, ref blk) |
|
||||
ast::ExprProc(_, ref blk) => {
|
||||
debug!("{} is an ExprClosure or ExprProc",
|
||||
expr_to_string(expr));
|
||||
|
||||
/*
|
||||
@ -1495,7 +1494,7 @@ fn check_expr(this: &mut Liveness, expr: &Expr) {
|
||||
ast::ExprBreak(..) | ast::ExprAgain(..) | ast::ExprLit(_) |
|
||||
ast::ExprBlock(..) | ast::ExprMac(..) | ast::ExprAddrOf(..) |
|
||||
ast::ExprStruct(..) | ast::ExprRepeat(..) | ast::ExprParen(..) |
|
||||
ast::ExprFnBlock(..) | ast::ExprProc(..) | ast::ExprUnboxedFn(..) |
|
||||
ast::ExprClosure(..) | ast::ExprProc(..) |
|
||||
ast::ExprPath(..) | ast::ExprBox(..) | ast::ExprSlice(..) => {
|
||||
visit::walk_expr(this, expr);
|
||||
}
|
||||
|
@ -520,8 +520,8 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> {
|
||||
|
||||
ast::ExprAddrOf(..) | ast::ExprCall(..) |
|
||||
ast::ExprAssign(..) | ast::ExprAssignOp(..) |
|
||||
ast::ExprFnBlock(..) | ast::ExprProc(..) |
|
||||
ast::ExprUnboxedFn(..) | ast::ExprRet(..) |
|
||||
ast::ExprClosure(..) | ast::ExprProc(..) |
|
||||
ast::ExprRet(..) |
|
||||
ast::ExprUnary(..) | ast::ExprSlice(..) |
|
||||
ast::ExprMethodCall(..) | ast::ExprCast(..) |
|
||||
ast::ExprVec(..) | ast::ExprTup(..) | ast::ExprIf(..) |
|
||||
@ -693,9 +693,8 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> {
|
||||
};
|
||||
|
||||
match fn_expr.node {
|
||||
ast::ExprFnBlock(_, _, ref body) |
|
||||
ast::ExprProc(_, ref body) |
|
||||
ast::ExprUnboxedFn(_, _, _, ref body) => body.id,
|
||||
ast::ExprClosure(_, _, _, ref body) => body.id,
|
||||
_ => unreachable!()
|
||||
}
|
||||
};
|
||||
|
@ -50,8 +50,8 @@ use util::nodemap::{NodeMap, NodeSet, DefIdSet, FnvHashMap};
|
||||
|
||||
use syntax::ast::{Arm, BindByRef, BindByValue, BindingMode, Block, Crate, CrateNum};
|
||||
use syntax::ast::{DeclItem, DefId, Expr, ExprAgain, ExprBreak, ExprField};
|
||||
use syntax::ast::{ExprFnBlock, ExprForLoop, ExprLoop, ExprWhile, ExprMethodCall};
|
||||
use syntax::ast::{ExprPath, ExprProc, ExprStruct, ExprUnboxedFn, FnDecl};
|
||||
use syntax::ast::{ExprClosure, ExprForLoop, ExprLoop, ExprWhile, ExprMethodCall};
|
||||
use syntax::ast::{ExprPath, ExprProc, ExprStruct, FnDecl};
|
||||
use syntax::ast::{ForeignItem, ForeignItemFn, ForeignItemStatic, Generics};
|
||||
use syntax::ast::{Ident, ImplItem, Item, ItemEnum, ItemFn, ItemForeignMod};
|
||||
use syntax::ast::{ItemImpl, ItemMac, ItemMod, ItemStatic, ItemStruct};
|
||||
@ -5848,24 +5848,19 @@ impl<'a> Resolver<'a> {
|
||||
visit::walk_expr(self, expr);
|
||||
}
|
||||
|
||||
ExprFnBlock(capture_clause, ref fn_decl, ref block) => {
|
||||
ExprClosure(capture_clause, _, ref fn_decl, ref block) => {
|
||||
self.capture_mode_map.insert(expr.id, capture_clause);
|
||||
self.resolve_function(ClosureRibKind(expr.id, ast::DUMMY_NODE_ID),
|
||||
Some(&**fn_decl), NoTypeParameters,
|
||||
&**block);
|
||||
}
|
||||
|
||||
ExprProc(ref fn_decl, ref block) => {
|
||||
self.capture_mode_map.insert(expr.id, ast::CaptureByValue);
|
||||
self.resolve_function(ClosureRibKind(expr.id, block.id),
|
||||
Some(&**fn_decl), NoTypeParameters,
|
||||
&**block);
|
||||
}
|
||||
ExprUnboxedFn(capture_clause, _, ref fn_decl, ref block) => {
|
||||
self.capture_mode_map.insert(expr.id, capture_clause);
|
||||
self.resolve_function(ClosureRibKind(expr.id, block.id),
|
||||
Some(&**fn_decl), NoTypeParameters,
|
||||
&**block);
|
||||
}
|
||||
|
||||
ExprStruct(ref path, _, _) => {
|
||||
// Resolve the path to the structure it goes to. We don't
|
||||
|
@ -109,6 +109,10 @@ impl<'tcx> FulfillmentContext<'tcx> {
|
||||
self.select(&mut selcx, false)
|
||||
}
|
||||
|
||||
pub fn pending_trait_obligations(&self) -> &[Obligation<'tcx>] {
|
||||
self.trait_obligations[]
|
||||
}
|
||||
|
||||
fn select<'a>(&mut self,
|
||||
selcx: &mut SelectionContext<'a, 'tcx>,
|
||||
only_new_obligations: bool)
|
||||
|
@ -3919,9 +3919,8 @@ pub fn expr_kind(tcx: &ctxt, expr: &ast::Expr) -> ExprKind {
|
||||
ast::ExprTup(..) |
|
||||
ast::ExprIf(..) |
|
||||
ast::ExprMatch(..) |
|
||||
ast::ExprFnBlock(..) |
|
||||
ast::ExprClosure(..) |
|
||||
ast::ExprProc(..) |
|
||||
ast::ExprUnboxedFn(..) |
|
||||
ast::ExprBlock(..) |
|
||||
ast::ExprRepeat(..) |
|
||||
ast::ExprVec(..) => {
|
||||
|
@ -995,7 +995,7 @@ pub fn ast_ty_to_ty<'tcx, AC: AstConv<'tcx>, RS: RegionScope>(
|
||||
}
|
||||
ast::TyInfer => {
|
||||
// TyInfer also appears as the type of arguments or return
|
||||
// values in a ExprFnBlock, ExprProc, or ExprUnboxedFn, or as
|
||||
// values in a ExprClosure or ExprProc, or as
|
||||
// the type of local variables. Both of these cases are
|
||||
// handled specially and will not descend into this routine.
|
||||
this.ty_infer(ast_ty.span)
|
||||
|
346
src/librustc/middle/typeck/check/closure.rs
Normal file
346
src/librustc/middle/typeck/check/closure.rs
Normal file
@ -0,0 +1,346 @@
|
||||
// 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, ExpectCastableToType, ExpectHasType, NoExpectation};
|
||||
use super::FnCtxt;
|
||||
|
||||
use middle::subst;
|
||||
use middle::ty::{mod, 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_expr_closure<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>,
|
||||
expr: &ast::Expr,
|
||||
opt_kind: Option<ast::UnboxedClosureKind>,
|
||||
decl: &ast::FnDecl,
|
||||
body: &ast::Block,
|
||||
expected: Expectation<'tcx>) {
|
||||
debug!("check_expr_closure(expr={},expected={})",
|
||||
expr.repr(fcx.tcx()),
|
||||
expected.repr(fcx.tcx()));
|
||||
|
||||
match opt_kind {
|
||||
None => {
|
||||
// If users didn't specify what sort of closure they want,
|
||||
// examine the expected type. For now, if we see explicit
|
||||
// evidence than an unboxed closure is desired, we'll use
|
||||
// that, otherwise we'll fall back to boxed closures.
|
||||
match deduce_unboxed_closure_expectations_from_expectation(fcx, expected) {
|
||||
None => { // doesn't look like an unboxed closure
|
||||
let region = astconv::opt_ast_region_to_region(fcx,
|
||||
fcx.infcx(),
|
||||
expr.span,
|
||||
&None);
|
||||
check_boxed_closure(fcx,
|
||||
expr,
|
||||
ty::RegionTraitStore(region, ast::MutMutable),
|
||||
decl,
|
||||
body,
|
||||
expected);
|
||||
}
|
||||
Some((sig, kind)) => {
|
||||
check_unboxed_closure(fcx, expr, kind, decl, body, Some(sig));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Some(kind) => {
|
||||
let kind = match kind {
|
||||
ast::FnUnboxedClosureKind => ty::FnUnboxedClosureKind,
|
||||
ast::FnMutUnboxedClosureKind => ty::FnMutUnboxedClosureKind,
|
||||
ast::FnOnceUnboxedClosureKind => ty::FnOnceUnboxedClosureKind,
|
||||
};
|
||||
|
||||
let expected_sig =
|
||||
deduce_unboxed_closure_expectations_from_expectation(fcx, expected)
|
||||
.map(|t| t.0);
|
||||
|
||||
check_unboxed_closure(fcx, expr, kind, decl, body, expected_sig);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn check_unboxed_closure<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>,
|
||||
expr: &ast::Expr,
|
||||
kind: ty::UnboxedClosureKind,
|
||||
decl: &ast::FnDecl,
|
||||
body: &ast::Block,
|
||||
expected_sig: Option<ty::FnSig<'tcx>>) {
|
||||
let expr_def_id = ast_util::local_def(expr.id);
|
||||
|
||||
debug!("check_unboxed_closure kind={} expected_sig={}",
|
||||
kind,
|
||||
expected_sig.repr(fcx.tcx()));
|
||||
|
||||
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,
|
||||
expected_sig);
|
||||
|
||||
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)];
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
fn deduce_unboxed_closure_expectations_from_expectation<'a,'tcx>(
|
||||
fcx: &FnCtxt<'a,'tcx>,
|
||||
expected: Expectation<'tcx>)
|
||||
-> Option<(ty::FnSig<'tcx>,ty::UnboxedClosureKind)>
|
||||
{
|
||||
match expected.resolve(fcx) {
|
||||
NoExpectation => None,
|
||||
ExpectCastableToType(t) | ExpectHasType(t) => {
|
||||
deduce_unboxed_closure_expectations_from_expected_type(fcx, t)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn deduce_unboxed_closure_expectations_from_expected_type<'a,'tcx>(
|
||||
fcx: &FnCtxt<'a,'tcx>,
|
||||
expected_ty: Ty<'tcx>)
|
||||
-> Option<(ty::FnSig<'tcx>,ty::UnboxedClosureKind)>
|
||||
{
|
||||
match expected_ty.sty {
|
||||
ty::ty_trait(ref object_type) => {
|
||||
deduce_unboxed_closure_expectations_from_trait_ref(fcx, &object_type.principal)
|
||||
}
|
||||
ty::ty_infer(ty::TyVar(vid)) => {
|
||||
deduce_unboxed_closure_expectations_from_obligations(fcx, vid)
|
||||
}
|
||||
_ => {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn deduce_unboxed_closure_expectations_from_trait_ref<'a,'tcx>(
|
||||
fcx: &FnCtxt<'a,'tcx>,
|
||||
trait_ref: &ty::TraitRef<'tcx>)
|
||||
-> Option<(ty::FnSig<'tcx>, ty::UnboxedClosureKind)>
|
||||
{
|
||||
let tcx = fcx.tcx();
|
||||
|
||||
debug!("deduce_unboxed_closure_expectations_from_object_type({})",
|
||||
trait_ref.repr(tcx));
|
||||
|
||||
let def_id_kinds = [
|
||||
(tcx.lang_items.fn_trait(), ty::FnUnboxedClosureKind),
|
||||
(tcx.lang_items.fn_mut_trait(), ty::FnMutUnboxedClosureKind),
|
||||
(tcx.lang_items.fn_once_trait(), ty::FnOnceUnboxedClosureKind),
|
||||
];
|
||||
|
||||
for &(def_id, kind) in def_id_kinds.iter() {
|
||||
if Some(trait_ref.def_id) == def_id {
|
||||
debug!("found object type {}", kind);
|
||||
|
||||
let arg_param_ty = *trait_ref.substs.types.get(subst::TypeSpace, 0);
|
||||
let arg_param_ty = fcx.infcx().resolve_type_vars_if_possible(arg_param_ty);
|
||||
debug!("arg_param_ty {}", arg_param_ty.repr(tcx));
|
||||
|
||||
let input_tys = match arg_param_ty.sty {
|
||||
ty::ty_tup(ref tys) => { (*tys).clone() }
|
||||
_ => { continue; }
|
||||
};
|
||||
debug!("input_tys {}", input_tys.repr(tcx));
|
||||
|
||||
let ret_param_ty = *trait_ref.substs.types.get(subst::TypeSpace, 1);
|
||||
let ret_param_ty = fcx.infcx().resolve_type_vars_if_possible(ret_param_ty);
|
||||
debug!("ret_param_ty {}", ret_param_ty.repr(tcx));
|
||||
|
||||
let fn_sig = ty::FnSig {
|
||||
inputs: input_tys,
|
||||
output: ty::FnConverging(ret_param_ty),
|
||||
variadic: false
|
||||
};
|
||||
debug!("fn_sig {}", fn_sig.repr(tcx));
|
||||
|
||||
return Some((fn_sig, kind));
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
fn deduce_unboxed_closure_expectations_from_obligations<'a,'tcx>(
|
||||
fcx: &FnCtxt<'a,'tcx>,
|
||||
expected_vid: ty::TyVid)
|
||||
-> Option<(ty::FnSig<'tcx>, ty::UnboxedClosureKind)>
|
||||
{
|
||||
// Here `expected_ty` is known to be a type inference variable.
|
||||
for obligation in fcx.inh.fulfillment_cx.borrow().pending_trait_obligations().iter() {
|
||||
let obligation_self_ty = fcx.infcx().shallow_resolve(obligation.self_ty());
|
||||
match obligation_self_ty.sty {
|
||||
ty::ty_infer(ty::TyVar(v)) if expected_vid == v => { }
|
||||
_ => { continue; }
|
||||
}
|
||||
|
||||
match deduce_unboxed_closure_expectations_from_trait_ref(fcx, &*obligation.trait_ref) {
|
||||
Some(e) => { return Some(e); }
|
||||
None => { }
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
|
||||
pub fn check_boxed_closure<'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);
|
||||
}
|
@ -78,7 +78,7 @@ type parameter).
|
||||
|
||||
pub use self::LvaluePreference::*;
|
||||
pub use self::DerefArgs::*;
|
||||
use self::Expectation::*;
|
||||
pub use self::Expectation::*;
|
||||
use self::IsBinopAssignment::*;
|
||||
use self::TupleArgumentsFlag::*;
|
||||
|
||||
@ -97,7 +97,7 @@ use middle::ty::{FnSig, VariantInfo};
|
||||
use middle::ty::{Polytype};
|
||||
use middle::ty::{Disr, ParamTy, ParameterEnvironment};
|
||||
use middle::ty::{mod, Ty};
|
||||
use middle::ty::{replace_late_bound_regions, liberate_late_bound_regions};
|
||||
use middle::ty::liberate_late_bound_regions;
|
||||
use middle::ty_fold::TypeFolder;
|
||||
use middle::typeck::astconv::AstConv;
|
||||
use middle::typeck::astconv::{ast_region_to_region, ast_ty_to_ty};
|
||||
@ -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:
|
||||
@ -2833,9 +2834,7 @@ fn check_argument_types<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
|
||||
};
|
||||
for (i, arg) in args.iter().take(t).enumerate() {
|
||||
let is_block = match arg.node {
|
||||
ast::ExprFnBlock(..) |
|
||||
ast::ExprProc(..) |
|
||||
ast::ExprUnboxedFn(..) => true,
|
||||
ast::ExprClosure(..) | ast::ExprProc(..) => true,
|
||||
_ => false
|
||||
};
|
||||
|
||||
@ -3530,174 +3529,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,
|
||||
@ -4326,32 +4157,16 @@ fn check_expr_with_unifier<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
|
||||
ast::ExprMatch(ref discrim, ref arms, _) => {
|
||||
_match::check_match(fcx, expr, &**discrim, arms.as_slice());
|
||||
}
|
||||
ast::ExprFnBlock(_, ref decl, ref body) => {
|
||||
let region = astconv::opt_ast_region_to_region(fcx,
|
||||
fcx.infcx(),
|
||||
expr.span,
|
||||
&None);
|
||||
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);
|
||||
ast::ExprClosure(_, opt_kind, ref decl, ref body) => {
|
||||
closure::check_expr_closure(fcx, expr, opt_kind, &**decl, &**body, expected);
|
||||
}
|
||||
ast::ExprProc(ref decl, ref body) => {
|
||||
check_expr_fn(fcx,
|
||||
expr,
|
||||
ty::UniqTraitStore,
|
||||
&**decl,
|
||||
&**body,
|
||||
expected);
|
||||
closure::check_boxed_closure(fcx,
|
||||
expr,
|
||||
ty::UniqTraitStore,
|
||||
&**decl,
|
||||
&**body,
|
||||
expected);
|
||||
}
|
||||
ast::ExprBlock(ref b) => {
|
||||
check_block_with_expected(fcx, &**b, expected);
|
||||
|
@ -742,9 +742,8 @@ fn visit_expr(rcx: &mut Rcx, expr: &ast::Expr) {
|
||||
visit::walk_expr(rcx, expr);
|
||||
}
|
||||
|
||||
ast::ExprFnBlock(_, _, ref body) |
|
||||
ast::ExprProc(_, ref body) |
|
||||
ast::ExprUnboxedFn(_, _, _, ref body) => {
|
||||
ast::ExprClosure(_, _, _, ref body) => {
|
||||
check_expr_fn_block(rcx, expr, &**body);
|
||||
}
|
||||
|
||||
|
@ -122,9 +122,8 @@ impl<'cx, 'tcx, 'v> Visitor<'v> for WritebackCx<'cx, 'tcx> {
|
||||
MethodCall::expr(e.id));
|
||||
|
||||
match e.node {
|
||||
ast::ExprFnBlock(_, ref decl, _) |
|
||||
ast::ExprProc(ref decl, _) |
|
||||
ast::ExprUnboxedFn(_, _, ref decl, _) => {
|
||||
ast::ExprClosure(_, _, ref decl, _) |
|
||||
ast::ExprProc(ref decl, _) => {
|
||||
for input in decl.inputs.iter() {
|
||||
let _ = self.visit_node_id(ResolvingExpr(e.span),
|
||||
input.id);
|
||||
|
@ -241,8 +241,7 @@ mod svh_visitor {
|
||||
SawExprIf,
|
||||
SawExprWhile,
|
||||
SawExprMatch,
|
||||
SawExprFnBlock,
|
||||
SawExprUnboxedFn,
|
||||
SawExprClosure,
|
||||
SawExprProc,
|
||||
SawExprBlock,
|
||||
SawExprAssign,
|
||||
@ -274,8 +273,7 @@ mod svh_visitor {
|
||||
ExprWhile(..) => SawExprWhile,
|
||||
ExprLoop(_, id) => SawExprLoop(id.map(content)),
|
||||
ExprMatch(..) => SawExprMatch,
|
||||
ExprFnBlock(..) => SawExprFnBlock,
|
||||
ExprUnboxedFn(..) => SawExprUnboxedFn,
|
||||
ExprClosure(..) => SawExprClosure,
|
||||
ExprProc(..) => SawExprProc,
|
||||
ExprBlock(..) => SawExprBlock,
|
||||
ExprAssign(..) => SawExprAssign,
|
||||
|
@ -1345,7 +1345,7 @@ impl<'l, 'tcx, 'v> Visitor<'v> for DxrVisitor<'l, 'tcx> {
|
||||
"Expected struct type, but not ty_struct"),
|
||||
}
|
||||
},
|
||||
ast::ExprFnBlock(_, ref decl, ref body) => {
|
||||
ast::ExprClosure(_, _, ref decl, ref body) => {
|
||||
if generated_code(body.span) {
|
||||
return
|
||||
}
|
||||
|
@ -1385,9 +1385,8 @@ fn has_nested_returns(tcx: &ty::ctxt, id: ast::NodeId) -> bool {
|
||||
}
|
||||
Some(ast_map::NodeExpr(e)) => {
|
||||
match e.node {
|
||||
ast::ExprFnBlock(_, _, ref blk) |
|
||||
ast::ExprProc(_, ref blk) |
|
||||
ast::ExprUnboxedFn(_, _, _, ref blk) => {
|
||||
ast::ExprClosure(_, _, _, ref blk) |
|
||||
ast::ExprProc(_, ref blk) => {
|
||||
let mut explicit = CheckForNestedReturnsVisitor::explicit();
|
||||
let mut implicit = CheckForNestedReturnsVisitor::implicit();
|
||||
visit::walk_expr(&mut explicit, e);
|
||||
|
@ -1232,9 +1232,8 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
|
||||
}
|
||||
ast_map::NodeExpr(ref expr) => {
|
||||
match expr.node {
|
||||
ast::ExprFnBlock(_, ref fn_decl, ref top_level_block) |
|
||||
ast::ExprProc(ref fn_decl, ref top_level_block) |
|
||||
ast::ExprUnboxedFn(_, _, ref fn_decl, ref top_level_block) => {
|
||||
ast::ExprClosure(_, _, ref fn_decl, ref top_level_block) => {
|
||||
let name = format!("fn{}", token::gensym("fn"));
|
||||
let name = token::str_to_ident(name.as_slice());
|
||||
(name, &**fn_decl,
|
||||
@ -1310,7 +1309,7 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
|
||||
file_metadata,
|
||||
&mut function_name);
|
||||
|
||||
// There is no ast_map::Path for ast::ExprFnBlock-type functions. For now,
|
||||
// There is no ast_map::Path for ast::ExprClosure-type functions. For now,
|
||||
// just don't put them into a namespace. In the future this could be improved
|
||||
// somehow (storing a path in the ast_map, or construct a path using the
|
||||
// enclosing function).
|
||||
@ -3578,9 +3577,8 @@ fn populate_scope_map(cx: &CrateContext,
|
||||
})
|
||||
}
|
||||
|
||||
ast::ExprFnBlock(_, ref decl, ref block) |
|
||||
ast::ExprProc(ref decl, ref block) |
|
||||
ast::ExprUnboxedFn(_, _, ref decl, ref block) => {
|
||||
ast::ExprClosure(_, _, ref decl, ref block) => {
|
||||
with_new_scope(cx,
|
||||
block.span,
|
||||
scope_stack,
|
||||
|
@ -77,6 +77,7 @@ use trans::machine::{llsize_of, llsize_of_alloc};
|
||||
use trans::type_::Type;
|
||||
|
||||
use syntax::ast;
|
||||
use syntax::ast_util;
|
||||
use syntax::codemap;
|
||||
use syntax::print::pprust::{expr_to_string};
|
||||
use syntax::ptr::P;
|
||||
@ -1070,16 +1071,23 @@ fn trans_rvalue_dps_unadjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
||||
ast::ExprVec(..) | ast::ExprRepeat(..) => {
|
||||
tvec::trans_fixed_vstore(bcx, expr, dest)
|
||||
}
|
||||
ast::ExprFnBlock(_, ref decl, ref body) |
|
||||
ast::ExprClosure(_, _, ref decl, ref body) |
|
||||
ast::ExprProc(ref decl, ref body) => {
|
||||
let expr_ty = expr_ty(bcx, expr);
|
||||
let store = ty::ty_closure_store(expr_ty);
|
||||
debug!("translating block function {} with type {}",
|
||||
expr_to_string(expr), expr_ty.repr(tcx));
|
||||
closure::trans_expr_fn(bcx, store, &**decl, &**body, expr.id, dest)
|
||||
}
|
||||
ast::ExprUnboxedFn(_, _, ref decl, ref body) => {
|
||||
closure::trans_unboxed_closure(bcx, &**decl, &**body, expr.id, dest)
|
||||
// Check the side-table to see whether this is an unboxed
|
||||
// closure or an older, legacy style closure. Store this
|
||||
// into a variable to ensure the the RefCell-lock is
|
||||
// released before we recurse.
|
||||
let is_unboxed_closure =
|
||||
bcx.tcx().unboxed_closures.borrow().contains_key(&ast_util::local_def(expr.id));
|
||||
if is_unboxed_closure {
|
||||
closure::trans_unboxed_closure(bcx, &**decl, &**body, expr.id, dest)
|
||||
} else {
|
||||
let expr_ty = expr_ty(bcx, expr);
|
||||
let store = ty::ty_closure_store(expr_ty);
|
||||
debug!("translating block function {} with type {}",
|
||||
expr_to_string(expr), expr_ty.repr(tcx));
|
||||
closure::trans_expr_fn(bcx, store, &**decl, &**body, expr.id, dest)
|
||||
}
|
||||
}
|
||||
ast::ExprCall(ref f, ref args) => {
|
||||
if bcx.tcx().is_method_call(expr.id) {
|
||||
|
@ -667,9 +667,8 @@ pub enum Expr_ {
|
||||
// FIXME #6993: change to Option<Name> ... or not, if these are hygienic.
|
||||
ExprLoop(P<Block>, Option<Ident>),
|
||||
ExprMatch(P<Expr>, Vec<Arm>, MatchSource),
|
||||
ExprFnBlock(CaptureClause, P<FnDecl>, P<Block>),
|
||||
ExprClosure(CaptureClause, Option<UnboxedClosureKind>, P<FnDecl>, P<Block>),
|
||||
ExprProc(P<FnDecl>, P<Block>),
|
||||
ExprUnboxedFn(CaptureClause, UnboxedClosureKind, P<FnDecl>, P<Block>),
|
||||
ExprBlock(P<Block>),
|
||||
|
||||
ExprAssign(P<Expr>, P<Expr>),
|
||||
|
@ -37,7 +37,7 @@ use visit;
|
||||
///
|
||||
/// More specifically, it is one of either:
|
||||
/// - A function item,
|
||||
/// - A closure expr (i.e. an ExprFnBlock or ExprProc), or
|
||||
/// - A closure expr (i.e. an ExprClosure or ExprProc), or
|
||||
/// - The default implementation for a trait method.
|
||||
///
|
||||
/// To construct one, use the `Code::from_node` function.
|
||||
@ -71,7 +71,7 @@ impl MaybeFnLike for ast::TraitItem {
|
||||
impl MaybeFnLike for ast::Expr {
|
||||
fn is_fn_like(&self) -> bool {
|
||||
match self.node {
|
||||
ast::ExprFnBlock(..) | ast::ExprProc(..) => true,
|
||||
ast::ExprClosure(..) | ast::ExprProc(..) => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
@ -215,7 +215,7 @@ impl<'a> FnLikeNode<'a> {
|
||||
}
|
||||
}
|
||||
ast_map::NodeExpr(e) => match e.node {
|
||||
ast::ExprFnBlock(_, ref decl, ref block) =>
|
||||
ast::ExprClosure(_, _, ref decl, ref block) =>
|
||||
closure(ClosureParts::new(&**decl, &**block, e.id, e.span)),
|
||||
ast::ExprProc(ref decl, ref block) =>
|
||||
closure(ClosureParts::new(&**decl, &**block, e.id, e.span)),
|
||||
|
@ -864,14 +864,14 @@ impl<'a> AstBuilder for ExtCtxt<'a> {
|
||||
|
||||
fn lambda_fn_decl(&self, span: Span,
|
||||
fn_decl: P<ast::FnDecl>, blk: P<ast::Block>) -> P<ast::Expr> {
|
||||
self.expr(span, ast::ExprFnBlock(ast::CaptureByRef, fn_decl, blk))
|
||||
self.expr(span, ast::ExprClosure(ast::CaptureByRef, None, fn_decl, blk))
|
||||
}
|
||||
fn lambda(&self, span: Span, ids: Vec<ast::Ident>, blk: P<ast::Block>) -> P<ast::Expr> {
|
||||
let fn_decl = self.fn_decl(
|
||||
ids.iter().map(|id| self.arg(span, *id, self.ty_infer(span))).collect(),
|
||||
self.ty_infer(span));
|
||||
|
||||
self.expr(span, ast::ExprFnBlock(ast::CaptureByRef, fn_decl, blk))
|
||||
self.expr(span, ast::ExprClosure(ast::CaptureByRef, None, fn_decl, blk))
|
||||
}
|
||||
fn lambda0(&self, span: Span, blk: P<ast::Block>) -> P<ast::Expr> {
|
||||
self.lambda(span, Vec::new(), blk)
|
||||
|
@ -207,10 +207,11 @@ pub fn expand_expr(e: P<ast::Expr>, fld: &mut MacroExpander) -> P<ast::Expr> {
|
||||
fld.cx.expr(span, ast::ExprForLoop(pat, head, body, opt_ident))
|
||||
}
|
||||
|
||||
ast::ExprFnBlock(capture_clause, fn_decl, block) => {
|
||||
ast::ExprClosure(capture_clause, opt_kind, fn_decl, block) => {
|
||||
let (rewritten_fn_decl, rewritten_block)
|
||||
= expand_and_rename_fn_decl_and_block(fn_decl, block, fld);
|
||||
let new_node = ast::ExprFnBlock(capture_clause,
|
||||
let new_node = ast::ExprClosure(capture_clause,
|
||||
opt_kind,
|
||||
rewritten_fn_decl,
|
||||
rewritten_block);
|
||||
P(ast::Expr{id:id, node: new_node, span: fld.new_span(span)})
|
||||
@ -1555,7 +1556,7 @@ mod test {
|
||||
0)
|
||||
}
|
||||
|
||||
// closure arg hygiene (ExprFnBlock)
|
||||
// closure arg hygiene (ExprClosure)
|
||||
// expands to fn f(){(|x_1 : int| {(x_2 + x_1)})(3);}
|
||||
#[test] fn closure_arg_hygiene(){
|
||||
run_renaming_test(
|
||||
|
@ -309,7 +309,7 @@ impl<'a, 'v> Visitor<'v> for Context<'a> {
|
||||
|
||||
fn visit_expr(&mut self, e: &ast::Expr) {
|
||||
match e.node {
|
||||
ast::ExprUnboxedFn(..) => {
|
||||
ast::ExprClosure(_, Some(_), _, _) => {
|
||||
self.gate_feature("unboxed_closures",
|
||||
e.span,
|
||||
"unboxed closures are a work-in-progress \
|
||||
|
@ -1326,18 +1326,13 @@ pub fn noop_fold_expr<T: Folder>(Expr {id, node, span}: Expr, folder: &mut T) ->
|
||||
arms.move_map(|x| folder.fold_arm(x)),
|
||||
source)
|
||||
}
|
||||
ExprFnBlock(capture_clause, decl, body) => {
|
||||
ExprFnBlock(capture_clause,
|
||||
folder.fold_fn_decl(decl),
|
||||
folder.fold_block(body))
|
||||
}
|
||||
ExprProc(decl, body) => {
|
||||
ExprProc(folder.fold_fn_decl(decl),
|
||||
folder.fold_block(body))
|
||||
}
|
||||
ExprUnboxedFn(capture_clause, kind, decl, body) => {
|
||||
ExprUnboxedFn(capture_clause,
|
||||
kind,
|
||||
ExprClosure(capture_clause, opt_kind, decl, body) => {
|
||||
ExprClosure(capture_clause,
|
||||
opt_kind,
|
||||
folder.fold_fn_decl(decl),
|
||||
folder.fold_block(body))
|
||||
}
|
||||
|
@ -25,10 +25,10 @@ use ast::{DeclLocal, DefaultBlock, UnDeref, BiDiv, EMPTY_CTXT, EnumDef, Explicit
|
||||
use ast::{Expr, Expr_, ExprAddrOf, ExprMatch, ExprAgain};
|
||||
use ast::{ExprAssign, ExprAssignOp, ExprBinary, ExprBlock, ExprBox};
|
||||
use ast::{ExprBreak, ExprCall, ExprCast};
|
||||
use ast::{ExprField, ExprTupField, ExprFnBlock, ExprIf, ExprIfLet, ExprIndex, ExprSlice};
|
||||
use ast::{ExprField, ExprTupField, ExprClosure, ExprIf, ExprIfLet, ExprIndex, ExprSlice};
|
||||
use ast::{ExprLit, ExprLoop, ExprMac};
|
||||
use ast::{ExprMethodCall, ExprParen, ExprPath, ExprProc};
|
||||
use ast::{ExprRepeat, ExprRet, ExprStruct, ExprTup, ExprUnary, ExprUnboxedFn};
|
||||
use ast::{ExprRepeat, ExprRet, ExprStruct, ExprTup, ExprUnary};
|
||||
use ast::{ExprVec, ExprWhile, ExprWhileLet, ExprForLoop, Field, FnDecl};
|
||||
use ast::{Once, Many};
|
||||
use ast::{FnUnboxedClosureKind, FnMutUnboxedClosureKind};
|
||||
@ -2999,7 +2999,8 @@ impl<'a> Parser<'a> {
|
||||
|
||||
// `|args| expr`
|
||||
pub fn parse_lambda_expr(&mut self, capture_clause: CaptureClause)
|
||||
-> P<Expr> {
|
||||
-> P<Expr>
|
||||
{
|
||||
let lo = self.span.lo;
|
||||
let (decl, optional_unboxed_closure_kind) =
|
||||
self.parse_fn_block_decl();
|
||||
@ -3013,21 +3014,10 @@ impl<'a> Parser<'a> {
|
||||
rules: DefaultBlock,
|
||||
});
|
||||
|
||||
match optional_unboxed_closure_kind {
|
||||
Some(unboxed_closure_kind) => {
|
||||
self.mk_expr(lo,
|
||||
fakeblock.span.hi,
|
||||
ExprUnboxedFn(capture_clause,
|
||||
unboxed_closure_kind,
|
||||
decl,
|
||||
fakeblock))
|
||||
}
|
||||
None => {
|
||||
self.mk_expr(lo,
|
||||
fakeblock.span.hi,
|
||||
ExprFnBlock(capture_clause, decl, fakeblock))
|
||||
}
|
||||
}
|
||||
self.mk_expr(
|
||||
lo,
|
||||
fakeblock.span.hi,
|
||||
ExprClosure(capture_clause, optional_unboxed_closure_kind, decl, fakeblock))
|
||||
}
|
||||
|
||||
pub fn parse_else_expr(&mut self) -> P<Expr> {
|
||||
|
@ -444,9 +444,8 @@ pub fn visibility_qualified(vis: ast::Visibility, s: &str) -> String {
|
||||
fn needs_parentheses(expr: &ast::Expr) -> bool {
|
||||
match expr.node {
|
||||
ast::ExprAssign(..) | ast::ExprBinary(..) |
|
||||
ast::ExprFnBlock(..) | ast::ExprProc(..) |
|
||||
ast::ExprUnboxedFn(..) | ast::ExprAssignOp(..) |
|
||||
ast::ExprCast(..) => true,
|
||||
ast::ExprClosure(..) | ast::ExprProc(..) |
|
||||
ast::ExprAssignOp(..) | ast::ExprCast(..) => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
@ -1662,49 +1661,11 @@ impl<'a> State<'a> {
|
||||
}
|
||||
try!(self.bclose_(expr.span, indent_unit));
|
||||
}
|
||||
ast::ExprFnBlock(capture_clause, ref decl, ref body) => {
|
||||
ast::ExprClosure(capture_clause, opt_kind, ref decl, ref body) => {
|
||||
try!(self.print_capture_clause(capture_clause));
|
||||
|
||||
// in do/for blocks we don't want to show an empty
|
||||
// argument list, but at this point we don't know which
|
||||
// we are inside.
|
||||
//
|
||||
// if !decl.inputs.is_empty() {
|
||||
try!(self.print_fn_block_args(&**decl, None));
|
||||
try!(self.print_fn_block_args(&**decl, opt_kind));
|
||||
try!(space(&mut self.s));
|
||||
// }
|
||||
|
||||
if !body.stmts.is_empty() || !body.expr.is_some() {
|
||||
try!(self.print_block_unclosed(&**body));
|
||||
} else {
|
||||
// we extract the block, so as not to create another set of boxes
|
||||
match body.expr.as_ref().unwrap().node {
|
||||
ast::ExprBlock(ref blk) => {
|
||||
try!(self.print_block_unclosed(&**blk));
|
||||
}
|
||||
_ => {
|
||||
// this is a bare expression
|
||||
try!(self.print_expr(&**body.expr.as_ref().unwrap()));
|
||||
try!(self.end()); // need to close a box
|
||||
}
|
||||
}
|
||||
}
|
||||
// a box will be closed by print_expr, but we didn't want an overall
|
||||
// wrapper so we closed the corresponding opening. so create an
|
||||
// empty box to satisfy the close.
|
||||
try!(self.ibox(0));
|
||||
}
|
||||
ast::ExprUnboxedFn(capture_clause, kind, ref decl, ref body) => {
|
||||
try!(self.print_capture_clause(capture_clause));
|
||||
|
||||
// in do/for blocks we don't want to show an empty
|
||||
// argument list, but at this point we don't know which
|
||||
// we are inside.
|
||||
//
|
||||
// if !decl.inputs.is_empty() {
|
||||
try!(self.print_fn_block_args(&**decl, Some(kind)));
|
||||
try!(space(&mut self.s));
|
||||
// }
|
||||
|
||||
if !body.stmts.is_empty() || !body.expr.is_some() {
|
||||
try!(self.print_block_unclosed(&**body));
|
||||
|
@ -815,14 +815,7 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr) {
|
||||
visitor.visit_arm(arm)
|
||||
}
|
||||
}
|
||||
ExprFnBlock(_, ref function_declaration, ref body) => {
|
||||
visitor.visit_fn(FkFnBlock,
|
||||
&**function_declaration,
|
||||
&**body,
|
||||
expression.span,
|
||||
expression.id)
|
||||
}
|
||||
ExprUnboxedFn(_, _, ref function_declaration, ref body) => {
|
||||
ExprClosure(_, _, ref function_declaration, ref body) => {
|
||||
visitor.visit_fn(FkFnBlock,
|
||||
&**function_declaration,
|
||||
&**body,
|
||||
|
19
src/test/compile-fail/regions-escape-unboxed-closure.rs
Normal file
19
src/test/compile-fail/regions-escape-unboxed-closure.rs
Normal file
@ -0,0 +1,19 @@
|
||||
// Copyright 2012 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.
|
||||
|
||||
#![feature(unboxed_closures)]
|
||||
|
||||
fn with_int(f: &mut FnMut(&int)) {
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let mut x: Option<&int> = None;
|
||||
with_int(&mut |&mut: y| x = Some(y)); //~ ERROR cannot infer
|
||||
}
|
@ -0,0 +1,29 @@
|
||||
// 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.
|
||||
|
||||
// That a closure whose expected argument types include two distinct
|
||||
// bound regions.
|
||||
|
||||
#![feature(unboxed_closures)]
|
||||
|
||||
use std::cell::Cell;
|
||||
|
||||
fn doit<T,F>(val: T, f: &F)
|
||||
where F : Fn(&Cell<&T>, &T)
|
||||
{
|
||||
let x = Cell::new(&val);
|
||||
f.call((&x,&val))
|
||||
}
|
||||
|
||||
pub fn main() {
|
||||
doit(0i, &|&: x, y| {
|
||||
x.set(y); //~ ERROR cannot infer
|
||||
});
|
||||
}
|
@ -0,0 +1,24 @@
|
||||
// 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.
|
||||
|
||||
// Test that we are able to infer that the type of `x` is `int` based
|
||||
// on the expected type from the object.
|
||||
|
||||
#![feature(unboxed_closures)]
|
||||
|
||||
fn doit<T,F>(val: T, f: &F)
|
||||
where F : Fn(T)
|
||||
{
|
||||
f.call((val,))
|
||||
}
|
||||
|
||||
pub fn main() {
|
||||
doit(0i, &|&: x /*: int*/ | { x.to_int(); });
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
// 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.
|
||||
|
||||
// Test that we are able to infer that the type of `x` is `int` based
|
||||
// on the expected type from the object.
|
||||
|
||||
#![feature(unboxed_closures)]
|
||||
|
||||
fn doit<T>(val: T, f: &Fn(T)) { f.call((val,)) }
|
||||
|
||||
pub fn main() {
|
||||
doit(0i, &|&: x /*: int*/ | { x.to_int(); });
|
||||
}
|
@ -0,0 +1,24 @@
|
||||
// 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.
|
||||
|
||||
// Test that we are able to infer that the type of `x` is `int` based
|
||||
// on the expected type from the object.
|
||||
|
||||
#![feature(unboxed_closures)]
|
||||
|
||||
fn doit<T,F>(val: T, f: &F)
|
||||
where F : Fn(&T)
|
||||
{
|
||||
f.call((&val,))
|
||||
}
|
||||
|
||||
pub fn main() {
|
||||
doit(0i, &|&: x /*: int*/ | { x.to_int(); });
|
||||
}
|
38
src/test/run-pass/unboxed-closures-infer-kind.rs
Normal file
38
src/test/run-pass/unboxed-closures-infer-kind.rs
Normal file
@ -0,0 +1,38 @@
|
||||
// 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.
|
||||
|
||||
// Test that we can infer the "kind" of an unboxed closure based on
|
||||
// the expected type.
|
||||
|
||||
#![feature(unboxed_closures)]
|
||||
|
||||
// Test by-ref capture of environment in unboxed closure types
|
||||
|
||||
fn call_fn<F: Fn()>(f: F) {
|
||||
f()
|
||||
}
|
||||
|
||||
fn call_fn_mut<F: FnMut()>(mut f: F) {
|
||||
f()
|
||||
}
|
||||
|
||||
fn call_fn_once<F: FnOnce()>(f: F) {
|
||||
f()
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let mut x = 0u;
|
||||
let y = 2u;
|
||||
|
||||
call_fn(|| assert_eq!(x, 0));
|
||||
call_fn_mut(|| x += y);
|
||||
call_fn_once(|| x += y);
|
||||
assert_eq!(x, y * 2);
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user