Remove the explicit closure kind syntax from the parser and AST;
upgrade the inference based on expected type so that it is able to infer the fn kind in isolation even if the full signature is not available (and we could perhaps do better still in some cases, such as extracting just the types of the arguments but not the return value).
This commit is contained in:
parent
47f18659ff
commit
0431134119
@ -45,7 +45,7 @@ impl<'a, 'v> Visitor<'v> for CheckLoopVisitor<'a> {
|
||||
ast::ExprLoop(ref b, _) => {
|
||||
self.with_context(Loop, |v| v.visit_block(&**b));
|
||||
}
|
||||
ast::ExprClosure(_, _, _, ref b) => {
|
||||
ast::ExprClosure(_, _, ref b) => {
|
||||
self.with_context(Closure, |v| v.visit_block(&**b));
|
||||
}
|
||||
ast::ExprBreak(_) => self.require_loop("break", e.span),
|
||||
|
@ -959,7 +959,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
|
||||
self.propagate_through_expr(&**e, succ)
|
||||
}
|
||||
|
||||
ast::ExprClosure(_, _, _, ref blk) => {
|
||||
ast::ExprClosure(_, _, ref blk) => {
|
||||
debug!("{} is an ExprClosure",
|
||||
expr_to_string(expr));
|
||||
|
||||
|
@ -739,7 +739,7 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> {
|
||||
};
|
||||
|
||||
match fn_expr.node {
|
||||
ast::ExprClosure(_, _, _, ref body) => body.id,
|
||||
ast::ExprClosure(_, _, ref body) => body.id,
|
||||
_ => unreachable!()
|
||||
}
|
||||
};
|
||||
|
@ -324,7 +324,7 @@ pub fn closure_to_block(closure_id: ast::NodeId,
|
||||
tcx: &ty::ctxt) -> ast::NodeId {
|
||||
match tcx.map.get(closure_id) {
|
||||
ast_map::NodeExpr(expr) => match expr.node {
|
||||
ast::ExprClosure(_, _, _, ref block) => {
|
||||
ast::ExprClosure(_, _, ref block) => {
|
||||
block.id
|
||||
}
|
||||
_ => {
|
||||
|
@ -4521,7 +4521,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
||||
visit::walk_expr(self, expr);
|
||||
}
|
||||
|
||||
ExprClosure(_, _, ref fn_decl, ref block) => {
|
||||
ExprClosure(_, ref fn_decl, ref block) => {
|
||||
self.resolve_function(ClosureRibKind(expr.id),
|
||||
Some(&**fn_decl), NoTypeParameters,
|
||||
&**block);
|
||||
|
@ -1394,7 +1394,7 @@ impl<'l, 'tcx, 'v> Visitor<'v> for DxrVisitor<'l, 'tcx> {
|
||||
type, found {:?}", ty)[]),
|
||||
}
|
||||
},
|
||||
ast::ExprClosure(_, _, ref decl, ref body) => {
|
||||
ast::ExprClosure(_, ref decl, ref body) => {
|
||||
if generated_code(body.span) {
|
||||
return
|
||||
}
|
||||
|
@ -1340,7 +1340,7 @@ fn build_cfg(tcx: &ty::ctxt, id: ast::NodeId) -> (ast::NodeId, Option<cfg::CFG>)
|
||||
}
|
||||
Some(ast_map::NodeExpr(e)) => {
|
||||
match e.node {
|
||||
ast::ExprClosure(_, _, _, ref blk) => {
|
||||
ast::ExprClosure(_, _, ref blk) => {
|
||||
blk
|
||||
}
|
||||
_ => tcx.sess.bug("unexpected expr variant in has_nested_returns")
|
||||
|
@ -1283,7 +1283,7 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
|
||||
}
|
||||
ast_map::NodeExpr(ref expr) => {
|
||||
match expr.node {
|
||||
ast::ExprClosure(_, _, 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[]);
|
||||
(name, &**fn_decl,
|
||||
@ -3595,7 +3595,7 @@ fn create_scope_map(cx: &CrateContext,
|
||||
})
|
||||
}
|
||||
|
||||
ast::ExprClosure(_, _, ref decl, ref block) => {
|
||||
ast::ExprClosure(_, ref decl, ref block) => {
|
||||
with_new_scope(cx,
|
||||
block.span,
|
||||
scope_stack,
|
||||
|
@ -1094,7 +1094,7 @@ fn trans_rvalue_dps_unadjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
||||
ast::ExprVec(..) | ast::ExprRepeat(..) => {
|
||||
tvec::trans_fixed_vstore(bcx, expr, dest)
|
||||
}
|
||||
ast::ExprClosure(_, _, ref decl, ref body) => {
|
||||
ast::ExprClosure(_, ref decl, ref body) => {
|
||||
closure::trans_closure_expr(bcx, &**decl, &**body, expr.id, dest)
|
||||
}
|
||||
ast::ExprCall(ref f, ref args) => {
|
||||
|
@ -25,7 +25,6 @@ use util::ppaux::Repr;
|
||||
pub fn check_expr_closure<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>,
|
||||
expr: &ast::Expr,
|
||||
_capture: ast::CaptureClause,
|
||||
opt_kind: Option<ast::ClosureKind>,
|
||||
decl: &'tcx ast::FnDecl,
|
||||
body: &'tcx ast::Block,
|
||||
expected: Expectation<'tcx>) {
|
||||
@ -33,38 +32,14 @@ pub fn check_expr_closure<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>,
|
||||
expr.repr(fcx.tcx()),
|
||||
expected.repr(fcx.tcx()));
|
||||
|
||||
let expected_sig_and_kind = expected.to_option(fcx).and_then(|ty| {
|
||||
deduce_expectations_from_expected_type(fcx, ty)
|
||||
});
|
||||
|
||||
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 leave it unspecified, to be filled
|
||||
// in by upvar inference.
|
||||
match expected_sig_and_kind {
|
||||
None => { // don't have information about the kind, request explicit annotation
|
||||
check_closure(fcx, expr, None, decl, body, None);
|
||||
},
|
||||
Some((sig, kind)) => {
|
||||
check_closure(fcx, expr, Some(kind), decl, body, Some(sig));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Some(kind) => {
|
||||
let kind = match kind {
|
||||
ast::FnClosureKind => ty::FnClosureKind,
|
||||
ast::FnMutClosureKind => ty::FnMutClosureKind,
|
||||
ast::FnOnceClosureKind => ty::FnOnceClosureKind,
|
||||
};
|
||||
|
||||
let expected_sig = expected_sig_and_kind.map(|t| t.0);
|
||||
check_closure(fcx, expr, Some(kind), decl, body, expected_sig);
|
||||
}
|
||||
}
|
||||
// It's always helpful for inference if we know the kind of
|
||||
// closure sooner rather than later, so first examine the expected
|
||||
// type, and see if can glean a closure kind from there.
|
||||
let (expected_sig,expected_kind) = match expected.to_option(fcx) {
|
||||
Some(ty) => deduce_expectations_from_expected_type(fcx, ty),
|
||||
None => (None, None)
|
||||
};
|
||||
check_closure(fcx, expr, expected_kind, decl, body, expected_sig)
|
||||
}
|
||||
|
||||
fn check_closure<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>,
|
||||
@ -133,21 +108,30 @@ fn check_closure<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>,
|
||||
fn deduce_expectations_from_expected_type<'a,'tcx>(
|
||||
fcx: &FnCtxt<'a,'tcx>,
|
||||
expected_ty: Ty<'tcx>)
|
||||
-> Option<(ty::FnSig<'tcx>,ty::ClosureKind)>
|
||||
-> (Option<ty::FnSig<'tcx>>,Option<ty::ClosureKind>)
|
||||
{
|
||||
debug!("deduce_expectations_from_expected_type(expected_ty={})",
|
||||
expected_ty.repr(fcx.tcx()));
|
||||
|
||||
match expected_ty.sty {
|
||||
ty::ty_trait(ref object_type) => {
|
||||
let proj_bounds = object_type.projection_bounds_with_self_ty(fcx.tcx(),
|
||||
fcx.tcx().types.err);
|
||||
proj_bounds.iter()
|
||||
.filter_map(|pb| deduce_expectations_from_projection(fcx, pb))
|
||||
.next()
|
||||
let expectations =
|
||||
proj_bounds.iter()
|
||||
.filter_map(|pb| deduce_expectations_from_projection(fcx, pb))
|
||||
.next();
|
||||
|
||||
match expectations {
|
||||
Some((sig, kind)) => (Some(sig), Some(kind)),
|
||||
None => (None, None)
|
||||
}
|
||||
}
|
||||
ty::ty_infer(ty::TyVar(vid)) => {
|
||||
deduce_expectations_from_obligations(fcx, vid)
|
||||
}
|
||||
_ => {
|
||||
None
|
||||
(None, None)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -155,33 +139,61 @@ fn deduce_expectations_from_expected_type<'a,'tcx>(
|
||||
fn deduce_expectations_from_obligations<'a,'tcx>(
|
||||
fcx: &FnCtxt<'a,'tcx>,
|
||||
expected_vid: ty::TyVid)
|
||||
-> Option<(ty::FnSig<'tcx>, ty::ClosureKind)>
|
||||
-> (Option<ty::FnSig<'tcx>>, Option<ty::ClosureKind>)
|
||||
{
|
||||
let fulfillment_cx = fcx.inh.fulfillment_cx.borrow();
|
||||
// Here `expected_ty` is known to be a type inference variable.
|
||||
|
||||
fulfillment_cx.pending_obligations()
|
||||
.iter()
|
||||
.filter_map(|obligation| {
|
||||
match obligation.predicate {
|
||||
ty::Predicate::Projection(ref proj_predicate) => {
|
||||
let trait_ref = proj_predicate.to_poly_trait_ref();
|
||||
let self_ty = fcx.infcx().shallow_resolve(trait_ref.self_ty());
|
||||
match self_ty.sty {
|
||||
ty::ty_infer(ty::TyVar(v)) if expected_vid == v => {
|
||||
deduce_expectations_from_projection(fcx, proj_predicate)
|
||||
}
|
||||
_ => {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
None
|
||||
}
|
||||
}
|
||||
})
|
||||
.next()
|
||||
let expected_sig_and_kind =
|
||||
fulfillment_cx
|
||||
.pending_obligations()
|
||||
.iter()
|
||||
.filter_map(|obligation| {
|
||||
debug!("deduce_expectations_from_obligations: obligation.predicate={}",
|
||||
obligation.predicate.repr(fcx.tcx()));
|
||||
|
||||
match obligation.predicate {
|
||||
// Given a Projection predicate, we can potentially infer
|
||||
// the complete signature.
|
||||
ty::Predicate::Projection(ref proj_predicate) => {
|
||||
let trait_ref = proj_predicate.to_poly_trait_ref();
|
||||
self_type_matches_expected_vid(fcx, trait_ref, expected_vid)
|
||||
.and_then(|_| deduce_expectations_from_projection(fcx, proj_predicate))
|
||||
}
|
||||
_ => {
|
||||
None
|
||||
}
|
||||
}
|
||||
})
|
||||
.next();
|
||||
|
||||
match expected_sig_and_kind {
|
||||
Some((sig, kind)) => { return (Some(sig), Some(kind)); }
|
||||
None => { }
|
||||
}
|
||||
|
||||
// Even if we can't infer the full signature, we may be able to
|
||||
// infer the kind. This can occur if there is a trait-reference
|
||||
// like `F : Fn<A>`.
|
||||
let expected_kind =
|
||||
fulfillment_cx
|
||||
.pending_obligations()
|
||||
.iter()
|
||||
.filter_map(|obligation| {
|
||||
let opt_trait_ref = match obligation.predicate {
|
||||
ty::Predicate::Projection(ref data) => Some(data.to_poly_trait_ref()),
|
||||
ty::Predicate::Trait(ref data) => Some(data.to_poly_trait_ref()),
|
||||
ty::Predicate::Equate(..) => None,
|
||||
ty::Predicate::RegionOutlives(..) => None,
|
||||
ty::Predicate::TypeOutlives(..) => None,
|
||||
};
|
||||
opt_trait_ref
|
||||
.and_then(|trait_ref| self_type_matches_expected_vid(fcx, trait_ref, expected_vid))
|
||||
.and_then(|trait_ref| fcx.tcx().lang_items.fn_trait_kind(trait_ref.def_id()))
|
||||
})
|
||||
.next();
|
||||
|
||||
(None, expected_kind)
|
||||
}
|
||||
|
||||
/// Given a projection like "<F as Fn(X)>::Result == Y", we can deduce
|
||||
@ -229,3 +241,20 @@ fn deduce_expectations_from_projection<'a,'tcx>(
|
||||
return Some((fn_sig, kind));
|
||||
}
|
||||
|
||||
fn self_type_matches_expected_vid<'a,'tcx>(
|
||||
fcx: &FnCtxt<'a,'tcx>,
|
||||
trait_ref: ty::PolyTraitRef<'tcx>,
|
||||
expected_vid: ty::TyVid)
|
||||
-> Option<ty::PolyTraitRef<'tcx>>
|
||||
{
|
||||
let self_ty = fcx.infcx().shallow_resolve(trait_ref.self_ty());
|
||||
debug!("self_type_matches_expected_vid(trait_ref={}, self_ty={})",
|
||||
trait_ref.repr(fcx.tcx()),
|
||||
self_ty.repr(fcx.tcx()));
|
||||
match self_ty.sty {
|
||||
ty::ty_infer(ty::TyVar(v)) if expected_vid == v => Some(trait_ref),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -3736,8 +3736,8 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>,
|
||||
ast::ExprMatch(ref discrim, ref arms, match_src) => {
|
||||
_match::check_match(fcx, expr, &**discrim, arms.as_slice(), expected, match_src);
|
||||
}
|
||||
ast::ExprClosure(capture, opt_kind, ref decl, ref body) => {
|
||||
closure::check_expr_closure(fcx, expr, capture, opt_kind, &**decl, &**body, expected);
|
||||
ast::ExprClosure(capture, ref decl, ref body) => {
|
||||
closure::check_expr_closure(fcx, expr, capture, &**decl, &**body, expected);
|
||||
}
|
||||
ast::ExprBlock(ref b) => {
|
||||
check_block_with_expected(fcx, &**b, expected);
|
||||
|
@ -638,7 +638,7 @@ fn visit_expr(rcx: &mut Rcx, expr: &ast::Expr) {
|
||||
visit::walk_expr(rcx, expr);
|
||||
}
|
||||
|
||||
ast::ExprClosure(_, _, _, ref body) => {
|
||||
ast::ExprClosure(_, _, ref body) => {
|
||||
check_expr_fn_block(rcx, expr, &**body);
|
||||
}
|
||||
|
||||
|
@ -83,7 +83,7 @@ struct SeedBorrowKind<'a,'tcx:'a> {
|
||||
impl<'a, 'tcx, 'v> Visitor<'v> for SeedBorrowKind<'a, 'tcx> {
|
||||
fn visit_expr(&mut self, expr: &ast::Expr) {
|
||||
match expr.node {
|
||||
ast::ExprClosure(cc, _, _, ref body) => {
|
||||
ast::ExprClosure(cc, _, ref body) => {
|
||||
self.check_closure(expr, cc, &**body);
|
||||
}
|
||||
|
||||
|
@ -118,7 +118,7 @@ impl<'cx, 'tcx, 'v> Visitor<'v> for WritebackCx<'cx, 'tcx> {
|
||||
MethodCall::expr(e.id));
|
||||
|
||||
match e.node {
|
||||
ast::ExprClosure(_, _, ref decl, _) => {
|
||||
ast::ExprClosure(_, ref decl, _) => {
|
||||
for input in &decl.inputs {
|
||||
let _ = self.visit_node_id(ResolvingExpr(e.span),
|
||||
input.id);
|
||||
|
@ -48,7 +48,6 @@ pub use self::TraitItem::*;
|
||||
pub use self::Ty_::*;
|
||||
pub use self::TyParamBound::*;
|
||||
pub use self::UintTy::*;
|
||||
pub use self::ClosureKind::*;
|
||||
pub use self::UnOp::*;
|
||||
pub use self::UnsafeSource::*;
|
||||
pub use self::VariantKind::*;
|
||||
@ -736,7 +735,7 @@ 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),
|
||||
ExprClosure(CaptureClause, Option<ClosureKind>, P<FnDecl>, P<Block>),
|
||||
ExprClosure(CaptureClause, P<FnDecl>, P<Block>),
|
||||
ExprBlock(P<Block>),
|
||||
|
||||
ExprAssign(P<Expr>, P<Expr>),
|
||||
@ -1687,13 +1686,6 @@ impl ForeignItem_ {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)]
|
||||
pub enum ClosureKind {
|
||||
FnClosureKind,
|
||||
FnMutClosureKind,
|
||||
FnOnceClosureKind,
|
||||
}
|
||||
|
||||
/// The data we save and restore about an inlined item or method. This is not
|
||||
/// part of the AST that we parse from a file, but it becomes part of the tree
|
||||
/// that we trans.
|
||||
|
@ -218,7 +218,7 @@ impl<'a> FnLikeNode<'a> {
|
||||
}
|
||||
}
|
||||
ast_map::NodeExpr(e) => match e.node {
|
||||
ast::ExprClosure(_, _, ref decl, ref block) =>
|
||||
ast::ExprClosure(_, ref decl, ref block) =>
|
||||
closure(ClosureParts::new(&**decl, &**block, e.id, e.span)),
|
||||
_ => panic!("expr FnLikeNode that is not fn-like"),
|
||||
},
|
||||
|
@ -876,14 +876,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::ExprClosure(ast::CaptureByRef, None, fn_decl, blk))
|
||||
self.expr(span, ast::ExprClosure(ast::CaptureByRef, 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::ExprClosure(ast::CaptureByRef, None, fn_decl, blk))
|
||||
self.expr(span, ast::ExprClosure(ast::CaptureByRef, fn_decl, blk))
|
||||
}
|
||||
fn lambda0(&self, span: Span, blk: P<ast::Block>) -> P<ast::Expr> {
|
||||
self.lambda(span, Vec::new(), blk)
|
||||
|
@ -322,11 +322,10 @@ pub fn expand_expr(e: P<ast::Expr>, fld: &mut MacroExpander) -> P<ast::Expr> {
|
||||
fld.cx.expr_match(span, into_iter_expr, vec![iter_arm])
|
||||
}
|
||||
|
||||
ast::ExprClosure(capture_clause, opt_kind, fn_decl, block) => {
|
||||
ast::ExprClosure(capture_clause, fn_decl, block) => {
|
||||
let (rewritten_fn_decl, rewritten_block)
|
||||
= expand_and_rename_fn_decl_and_block(fn_decl, block, fld);
|
||||
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)})
|
||||
|
@ -1325,9 +1325,8 @@ pub fn noop_fold_expr<T: Folder>(Expr {id, node, span}: Expr, folder: &mut T) ->
|
||||
arms.move_map(|x| folder.fold_arm(x)),
|
||||
source)
|
||||
}
|
||||
ExprClosure(capture_clause, opt_kind, decl, body) => {
|
||||
ExprClosure(capture_clause, decl, body) => {
|
||||
ExprClosure(capture_clause,
|
||||
opt_kind,
|
||||
folder.fold_fn_decl(decl),
|
||||
folder.fold_block(body))
|
||||
}
|
||||
|
@ -27,6 +27,7 @@ pub enum ObsoleteSyntax {
|
||||
ProcType,
|
||||
ProcExpr,
|
||||
ClosureType,
|
||||
ClosureKind,
|
||||
}
|
||||
|
||||
pub trait ParserObsoleteMethods {
|
||||
@ -65,6 +66,10 @@ impl<'a> ParserObsoleteMethods for parser::Parser<'a> {
|
||||
"`|usize| -> bool` closure type syntax",
|
||||
"use unboxed closures instead, no type annotation needed"
|
||||
),
|
||||
ObsoleteSyntax::ClosureKind => (
|
||||
"`:`, `&mut:`, or `&:` syntax",
|
||||
"rely on inference instead"
|
||||
),
|
||||
ObsoleteSyntax::Sized => (
|
||||
"`Sized? T` syntax for removing the `Sized` bound",
|
||||
"write `T: ?Sized` instead"
|
||||
|
@ -28,8 +28,6 @@ use ast::{ExprLit, ExprLoop, ExprMac, ExprRange};
|
||||
use ast::{ExprMethodCall, ExprParen, ExprPath, ExprQPath};
|
||||
use ast::{ExprRepeat, ExprRet, ExprStruct, ExprTup, ExprUnary};
|
||||
use ast::{ExprVec, ExprWhile, ExprWhileLet, ExprForLoop, Field, FnDecl};
|
||||
use ast::{FnClosureKind, FnMutClosureKind};
|
||||
use ast::{FnOnceClosureKind};
|
||||
use ast::{ForeignItem, ForeignItemStatic, ForeignItemFn, ForeignMod, FunctionRetTy};
|
||||
use ast::{Ident, Inherited, ImplItem, Item, Item_, ItemStatic};
|
||||
use ast::{ItemEnum, ItemFn, ItemForeignMod, ItemImpl, ItemConst};
|
||||
@ -57,7 +55,7 @@ use ast::{TyFixedLengthVec, TyBareFn};
|
||||
use ast::{TyTypeof, TyInfer, TypeMethod};
|
||||
use ast::{TyParam, TyParamBound, TyParen, TyPath, TyPolyTraitRef, TyPtr, TyQPath};
|
||||
use ast::{TyRptr, TyTup, TyU32, TyVec, UnUniq};
|
||||
use ast::{TypeImplItem, TypeTraitItem, Typedef, ClosureKind};
|
||||
use ast::{TypeImplItem, TypeTraitItem, Typedef,};
|
||||
use ast::{UnnamedField, UnsafeBlock};
|
||||
use ast::{ViewPath, ViewPathGlob, ViewPathList, ViewPathSimple};
|
||||
use ast::{Visibility, WhereClause};
|
||||
@ -1139,29 +1137,36 @@ impl<'a> Parser<'a> {
|
||||
TyInfer
|
||||
}
|
||||
|
||||
/// Parses an optional closure kind (`&:`, `&mut:`, or `:`).
|
||||
pub fn parse_optional_closure_kind(&mut self) -> Option<ClosureKind> {
|
||||
if self.check(&token::BinOp(token::And)) &&
|
||||
self.look_ahead(1, |t| t.is_keyword(keywords::Mut)) &&
|
||||
self.look_ahead(2, |t| *t == token::Colon) {
|
||||
/// Parses an obsolete closure kind (`&:`, `&mut:`, or `:`).
|
||||
pub fn parse_obsolete_closure_kind(&mut self) {
|
||||
// let lo = self.span.lo;
|
||||
if
|
||||
self.check(&token::BinOp(token::And)) &&
|
||||
self.look_ahead(1, |t| t.is_keyword(keywords::Mut)) &&
|
||||
self.look_ahead(2, |t| *t == token::Colon)
|
||||
{
|
||||
self.bump();
|
||||
self.bump();
|
||||
self.bump();
|
||||
return Some(FnMutClosureKind)
|
||||
} else if
|
||||
self.token == token::BinOp(token::And) &&
|
||||
self.look_ahead(1, |t| *t == token::Colon)
|
||||
{
|
||||
self.bump();
|
||||
self.bump();
|
||||
return;
|
||||
} else if
|
||||
self.eat(&token::Colon)
|
||||
{
|
||||
/* nothing */
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
if self.token == token::BinOp(token::And) &&
|
||||
self.look_ahead(1, |t| *t == token::Colon) {
|
||||
self.bump();
|
||||
self.bump();
|
||||
return Some(FnClosureKind)
|
||||
}
|
||||
|
||||
if self.eat(&token::Colon) {
|
||||
return Some(FnOnceClosureKind)
|
||||
}
|
||||
|
||||
return None
|
||||
// SNAP a45e117
|
||||
// Enable these obsolete errors after snapshot:
|
||||
// let span = mk_sp(lo, self.span.hi);
|
||||
// self.obsolete(span, ObsoleteSyntax::ClosureKind);
|
||||
}
|
||||
|
||||
pub fn parse_ty_bare_fn_or_ty_closure(&mut self, lifetime_defs: Vec<LifetimeDef>) -> Ty_ {
|
||||
@ -3047,7 +3052,7 @@ impl<'a> Parser<'a> {
|
||||
-> P<Expr>
|
||||
{
|
||||
let lo = self.span.lo;
|
||||
let (decl, optional_closure_kind) = self.parse_fn_block_decl();
|
||||
let decl = self.parse_fn_block_decl();
|
||||
let body = self.parse_expr();
|
||||
let fakeblock = P(ast::Block {
|
||||
id: ast::DUMMY_NODE_ID,
|
||||
@ -3060,7 +3065,7 @@ impl<'a> Parser<'a> {
|
||||
self.mk_expr(
|
||||
lo,
|
||||
fakeblock.span.hi,
|
||||
ExprClosure(capture_clause, optional_closure_kind, decl, fakeblock))
|
||||
ExprClosure(capture_clause, decl, fakeblock))
|
||||
}
|
||||
|
||||
pub fn parse_else_expr(&mut self) -> P<Expr> {
|
||||
@ -4529,30 +4534,29 @@ impl<'a> Parser<'a> {
|
||||
}
|
||||
|
||||
// parse the |arg, arg| header on a lambda
|
||||
fn parse_fn_block_decl(&mut self) -> (P<FnDecl>, Option<ClosureKind>) {
|
||||
let (optional_closure_kind, inputs_captures) = {
|
||||
fn parse_fn_block_decl(&mut self) -> P<FnDecl> {
|
||||
let inputs_captures = {
|
||||
if self.eat(&token::OrOr) {
|
||||
(None, Vec::new())
|
||||
Vec::new()
|
||||
} else {
|
||||
self.expect(&token::BinOp(token::Or));
|
||||
let optional_closure_kind =
|
||||
self.parse_optional_closure_kind();
|
||||
self.parse_obsolete_closure_kind();
|
||||
let args = self.parse_seq_to_before_end(
|
||||
&token::BinOp(token::Or),
|
||||
seq_sep_trailing_allowed(token::Comma),
|
||||
|p| p.parse_fn_block_arg()
|
||||
);
|
||||
self.bump();
|
||||
(optional_closure_kind, args)
|
||||
args
|
||||
}
|
||||
};
|
||||
let output = self.parse_ret_ty();
|
||||
|
||||
(P(FnDecl {
|
||||
P(FnDecl {
|
||||
inputs: inputs_captures,
|
||||
output: output,
|
||||
variadic: false
|
||||
}), optional_closure_kind)
|
||||
})
|
||||
}
|
||||
|
||||
/// Parses the `(arg, arg) -> return_type` header on a procedure.
|
||||
|
@ -11,11 +11,9 @@
|
||||
pub use self::AnnNode::*;
|
||||
|
||||
use abi;
|
||||
use ast::{self, FnClosureKind, FnMutClosureKind};
|
||||
use ast::{FnOnceClosureKind};
|
||||
use ast;
|
||||
use ast::{MethodImplItem, RegionTyParamBound, TraitTyParamBound, TraitBoundModifier};
|
||||
use ast::{RequiredMethod, ProvidedMethod, TypeImplItem, TypeTraitItem};
|
||||
use ast::{ClosureKind};
|
||||
use ast_util;
|
||||
use owned_slice::OwnedSlice;
|
||||
use attr::{AttrMetaMethods, AttributeMethods};
|
||||
@ -350,7 +348,7 @@ pub fn method_to_string(p: &ast::Method) -> String {
|
||||
}
|
||||
|
||||
pub fn fn_block_to_string(p: &ast::FnDecl) -> String {
|
||||
$to_string(|s| s.print_fn_block_args(p, None))
|
||||
$to_string(|s| s.print_fn_block_args(p))
|
||||
}
|
||||
|
||||
pub fn path_to_string(p: &ast::Path) -> String {
|
||||
@ -1747,10 +1745,10 @@ impl<'a> State<'a> {
|
||||
}
|
||||
try!(self.bclose_(expr.span, indent_unit));
|
||||
}
|
||||
ast::ExprClosure(capture_clause, opt_kind, ref decl, ref body) => {
|
||||
ast::ExprClosure(capture_clause, ref decl, ref body) => {
|
||||
try!(self.print_capture_clause(capture_clause));
|
||||
|
||||
try!(self.print_fn_block_args(&**decl, opt_kind));
|
||||
try!(self.print_fn_block_args(&**decl));
|
||||
try!(space(&mut self.s));
|
||||
|
||||
if !body.stmts.is_empty() || !body.expr.is_some() {
|
||||
@ -2350,16 +2348,9 @@ impl<'a> State<'a> {
|
||||
|
||||
pub fn print_fn_block_args(
|
||||
&mut self,
|
||||
decl: &ast::FnDecl,
|
||||
closure_kind: Option<ClosureKind>)
|
||||
decl: &ast::FnDecl)
|
||||
-> IoResult<()> {
|
||||
try!(word(&mut self.s, "|"));
|
||||
match closure_kind {
|
||||
None => {}
|
||||
Some(FnClosureKind) => try!(self.word_space("&:")),
|
||||
Some(FnMutClosureKind) => try!(self.word_space("&mut:")),
|
||||
Some(FnOnceClosureKind) => try!(self.word_space(":")),
|
||||
}
|
||||
try!(self.print_fn_args(decl, None));
|
||||
try!(word(&mut self.s, "|"));
|
||||
|
||||
|
@ -836,7 +836,7 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr) {
|
||||
visitor.visit_arm(arm)
|
||||
}
|
||||
}
|
||||
ExprClosure(_, _, ref function_declaration, ref body) => {
|
||||
ExprClosure(_, ref function_declaration, ref body) => {
|
||||
visitor.visit_fn(FkFnBlock,
|
||||
&**function_declaration,
|
||||
&**body,
|
||||
|
Loading…
Reference in New Issue
Block a user