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),
self.propagate_through_expr(&**e, succ)
}
- ast::ExprClosure(_, _, _, ref blk) => {
+ ast::ExprClosure(_, _, ref blk) => {
debug!("{} is an ExprClosure",
expr_to_string(expr));
};
match fn_expr.node {
- ast::ExprClosure(_, _, _, ref body) => body.id,
+ ast::ExprClosure(_, _, ref body) => body.id,
_ => unreachable!()
}
};
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
}
_ => {
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);
type, found {:?}", ty)[]),
}
},
- ast::ExprClosure(_, _, ref decl, ref body) => {
+ ast::ExprClosure(_, ref decl, ref body) => {
if generated_code(body.span) {
return
}
}
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")
}
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,
})
}
- ast::ExprClosure(_, _, ref decl, ref block) => {
+ ast::ExprClosure(_, ref decl, ref block) => {
with_new_scope(cx,
block.span,
scope_stack,
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) => {
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>) {
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>,
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)
}
}
}
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
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,
+ }
+}
+
+
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);
visit::walk_expr(rcx, expr);
}
- ast::ExprClosure(_, _, _, ref body) => {
+ ast::ExprClosure(_, _, ref body) => {
check_expr_fn_block(rcx, expr, &**body);
}
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);
}
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);
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::*;
// 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>),
}
}
-#[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.
}
}
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"),
},
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)
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)})
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))
}
ProcType,
ProcExpr,
ClosureType,
+ ClosureKind,
}
pub trait ParserObsoleteMethods {
"`|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"
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};
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};
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)
- }
-
- if self.token == token::BinOp(token::And) &&
- self.look_ahead(1, |t| *t == token::Colon) {
+ } else 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;
+ } else if
+ self.eat(&token::Colon)
+ {
+ /* nothing */
+ } else {
+ return;
}
- 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_ {
-> 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,
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> {
}
// 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.
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};
}
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 {
}
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() {
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, "|"));
visitor.visit_arm(arm)
}
}
- ExprClosure(_, _, ref function_declaration, ref body) => {
+ ExprClosure(_, ref function_declaration, ref body) => {
visitor.visit_fn(FkFnBlock,
&**function_declaration,
&**body,