librustc: Implement sugar for the FnMut
trait
This commit is contained in:
parent
907d961876
commit
f02b6f3a8b
12 changed files with 343 additions and 46 deletions
|
@ -57,6 +57,7 @@ static KNOWN_FEATURES: &'static [(&'static str, Status)] = &[
|
||||||
("linkage", Active),
|
("linkage", Active),
|
||||||
("struct_inherit", Active),
|
("struct_inherit", Active),
|
||||||
("overloaded_calls", Active),
|
("overloaded_calls", Active),
|
||||||
|
("unboxed_closure_sugar", Active),
|
||||||
|
|
||||||
("quad_precision_float", Active),
|
("quad_precision_float", Active),
|
||||||
|
|
||||||
|
@ -291,6 +292,11 @@ impl<'a> Visitor<()> for Context<'a> {
|
||||||
|
|
||||||
},
|
},
|
||||||
ast::TyBox(_) => { self.gate_box(t.span); }
|
ast::TyBox(_) => { self.gate_box(t.span); }
|
||||||
|
ast::TyUnboxedFn(_) => {
|
||||||
|
self.gate_feature("unboxed_closure_sugar",
|
||||||
|
t.span,
|
||||||
|
"unboxed closure trait sugar is experimental");
|
||||||
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3862,8 +3862,14 @@ impl<'a> Resolver<'a> {
|
||||||
TraitTyParamBound(ref tref) => {
|
TraitTyParamBound(ref tref) => {
|
||||||
self.resolve_trait_reference(id, tref, TraitBoundingTypeParameter)
|
self.resolve_trait_reference(id, tref, TraitBoundingTypeParameter)
|
||||||
}
|
}
|
||||||
StaticRegionTyParamBound => {}
|
UnboxedFnTyParamBound(ref unboxed_function) => {
|
||||||
OtherRegionTyParamBound(_) => {}
|
for argument in unboxed_function.decl.inputs.iter() {
|
||||||
|
self.resolve_type(argument.ty);
|
||||||
|
}
|
||||||
|
|
||||||
|
self.resolve_type(unboxed_function.decl.output);
|
||||||
|
}
|
||||||
|
StaticRegionTyParamBound | OtherRegionTyParamBound(_) => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -51,13 +51,14 @@
|
||||||
|
|
||||||
use middle::const_eval;
|
use middle::const_eval;
|
||||||
use middle::def;
|
use middle::def;
|
||||||
use middle::subst;
|
use middle::lang_items::FnMutTraitLangItem;
|
||||||
use middle::subst::{Subst, Substs};
|
use middle::subst::{Subst, Substs};
|
||||||
use middle::ty::{ty_param_substs_and_ty};
|
use middle::subst;
|
||||||
|
use middle::ty::ty_param_substs_and_ty;
|
||||||
use middle::ty;
|
use middle::ty;
|
||||||
use middle::typeck::rscope;
|
|
||||||
use middle::typeck::rscope::{RegionScope};
|
|
||||||
use middle::typeck::lookup_def_tcx;
|
use middle::typeck::lookup_def_tcx;
|
||||||
|
use middle::typeck::rscope::RegionScope;
|
||||||
|
use middle::typeck::rscope;
|
||||||
use util::ppaux::Repr;
|
use util::ppaux::Repr;
|
||||||
|
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
@ -469,6 +470,38 @@ fn ast_ty_to_mt<AC:AstConv, RS:RegionScope>(this: &AC,
|
||||||
ty::mt {ty: ast_ty_to_ty(this, rscope, ty), mutbl: ast::MutImmutable}
|
ty::mt {ty: ast_ty_to_ty(this, rscope, ty), mutbl: ast::MutImmutable}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn trait_ref_for_unboxed_function<AC:AstConv,
|
||||||
|
RS:RegionScope>(
|
||||||
|
this: &AC,
|
||||||
|
rscope: &RS,
|
||||||
|
unboxed_function: &ast::UnboxedFnTy)
|
||||||
|
-> ty::TraitRef {
|
||||||
|
let fn_mut_trait_did = this.tcx()
|
||||||
|
.lang_items
|
||||||
|
.require(FnMutTraitLangItem)
|
||||||
|
.unwrap();
|
||||||
|
let input_types =
|
||||||
|
unboxed_function.decl
|
||||||
|
.inputs
|
||||||
|
.iter()
|
||||||
|
.map(|input| {
|
||||||
|
ast_ty_to_ty(this, rscope, input.ty)
|
||||||
|
}).collect::<Vec<_>>();
|
||||||
|
let input_tuple = ty::mk_tup(this.tcx(), input_types);
|
||||||
|
let output_type = ast_ty_to_ty(this,
|
||||||
|
rscope,
|
||||||
|
unboxed_function.decl.output);
|
||||||
|
let substs = subst::Substs {
|
||||||
|
self_ty: None,
|
||||||
|
tps: vec!(input_tuple, output_type),
|
||||||
|
regions: subst::NonerasedRegions(Vec::new()),
|
||||||
|
};
|
||||||
|
ty::TraitRef {
|
||||||
|
def_id: fn_mut_trait_did,
|
||||||
|
substs: substs,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Handle `~`, `Box`, and `&` being able to mean strs and vecs.
|
// Handle `~`, `Box`, and `&` being able to mean strs and vecs.
|
||||||
// If a_seq_ty is a str or a vec, make it a str/vec.
|
// If a_seq_ty is a str or a vec, make it a str/vec.
|
||||||
// Also handle first-class trait types.
|
// Also handle first-class trait types.
|
||||||
|
@ -491,6 +524,32 @@ fn mk_pointer<AC:AstConv,
|
||||||
}
|
}
|
||||||
return constr(ty::mk_vec(tcx, mt, None));
|
return constr(ty::mk_vec(tcx, mt, None));
|
||||||
}
|
}
|
||||||
|
ast::TyUnboxedFn(ref unboxed_function) => {
|
||||||
|
let trait_store = match ptr_ty {
|
||||||
|
Uniq => ty::UniqTraitStore,
|
||||||
|
RPtr(r) => {
|
||||||
|
ty::RegionTraitStore(r, a_seq_ty.mutbl)
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
tcx.sess.span_err(
|
||||||
|
a_seq_ty.ty.span,
|
||||||
|
"~trait or &trait are the only supported \
|
||||||
|
forms of casting-to-trait");
|
||||||
|
return ty::mk_err();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let ty::TraitRef {
|
||||||
|
def_id,
|
||||||
|
substs
|
||||||
|
} = trait_ref_for_unboxed_function(this,
|
||||||
|
rscope,
|
||||||
|
*unboxed_function);
|
||||||
|
return ty::mk_trait(this.tcx(),
|
||||||
|
def_id,
|
||||||
|
substs,
|
||||||
|
trait_store,
|
||||||
|
ty::empty_builtin_bounds());
|
||||||
|
}
|
||||||
ast::TyPath(ref path, ref bounds, id) => {
|
ast::TyPath(ref path, ref bounds, id) => {
|
||||||
// Note that the "bounds must be empty if path is not a trait"
|
// Note that the "bounds must be empty if path is not a trait"
|
||||||
// restriction is enforced in the below case for ty_path, which
|
// restriction is enforced in the below case for ty_path, which
|
||||||
|
@ -528,7 +587,10 @@ fn mk_pointer<AC:AstConv,
|
||||||
return ty::mk_err();
|
return ty::mk_err();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let bounds = conv_builtin_bounds(this.tcx(), bounds, trait_store);
|
let bounds = conv_builtin_bounds(this.tcx(),
|
||||||
|
path.span,
|
||||||
|
bounds,
|
||||||
|
trait_store);
|
||||||
return ty::mk_trait(tcx,
|
return ty::mk_trait(tcx,
|
||||||
result.def_id,
|
result.def_id,
|
||||||
result.substs.clone(),
|
result.substs.clone(),
|
||||||
|
@ -621,7 +683,10 @@ pub fn ast_ty_to_ty<AC:AstConv, RS:RegionScope>(
|
||||||
|
|
||||||
// Use corresponding trait store to figure out default bounds
|
// Use corresponding trait store to figure out default bounds
|
||||||
// if none were specified.
|
// if none were specified.
|
||||||
let bounds = conv_builtin_bounds(this.tcx(), &f.bounds, store);
|
let bounds = conv_builtin_bounds(this.tcx(),
|
||||||
|
ast_ty.span,
|
||||||
|
&f.bounds,
|
||||||
|
store);
|
||||||
|
|
||||||
let fn_decl = ty_of_closure(this,
|
let fn_decl = ty_of_closure(this,
|
||||||
ast_ty.id,
|
ast_ty.id,
|
||||||
|
@ -636,7 +701,10 @@ pub fn ast_ty_to_ty<AC:AstConv, RS:RegionScope>(
|
||||||
ast::TyProc(ref f) => {
|
ast::TyProc(ref f) => {
|
||||||
// Use corresponding trait store to figure out default bounds
|
// Use corresponding trait store to figure out default bounds
|
||||||
// if none were specified.
|
// if none were specified.
|
||||||
let bounds = conv_builtin_bounds(this.tcx(), &f.bounds, ty::UniqTraitStore);
|
let bounds = conv_builtin_bounds(this.tcx(),
|
||||||
|
ast_ty.span,
|
||||||
|
&f.bounds,
|
||||||
|
ty::UniqTraitStore);
|
||||||
|
|
||||||
let fn_decl = ty_of_closure(this,
|
let fn_decl = ty_of_closure(this,
|
||||||
ast_ty.id,
|
ast_ty.id,
|
||||||
|
@ -648,6 +716,11 @@ pub fn ast_ty_to_ty<AC:AstConv, RS:RegionScope>(
|
||||||
None);
|
None);
|
||||||
ty::mk_closure(tcx, fn_decl)
|
ty::mk_closure(tcx, fn_decl)
|
||||||
}
|
}
|
||||||
|
ast::TyUnboxedFn(_) => {
|
||||||
|
tcx.sess.span_err(ast_ty.span,
|
||||||
|
"cannot use unboxed functions here");
|
||||||
|
ty::mk_err()
|
||||||
|
}
|
||||||
ast::TyPath(ref path, ref bounds, id) => {
|
ast::TyPath(ref path, ref bounds, id) => {
|
||||||
let a_def = match tcx.def_map.borrow().find(&id) {
|
let a_def = match tcx.def_map.borrow().find(&id) {
|
||||||
None => {
|
None => {
|
||||||
|
@ -891,7 +964,9 @@ pub fn ty_of_closure<AC:AstConv>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn conv_builtin_bounds(tcx: &ty::ctxt, ast_bounds: &Option<OwnedSlice<ast::TyParamBound>>,
|
fn conv_builtin_bounds(tcx: &ty::ctxt,
|
||||||
|
span: Span,
|
||||||
|
ast_bounds: &Option<OwnedSlice<ast::TyParamBound>>,
|
||||||
store: ty::TraitStore)
|
store: ty::TraitStore)
|
||||||
-> ty::BuiltinBounds {
|
-> ty::BuiltinBounds {
|
||||||
//! Converts a list of bounds from the AST into a `BuiltinBounds`
|
//! Converts a list of bounds from the AST into a `BuiltinBounds`
|
||||||
|
@ -928,6 +1003,11 @@ fn conv_builtin_bounds(tcx: &ty::ctxt, ast_bounds: &Option<OwnedSlice<ast::TyPar
|
||||||
ast::StaticRegionTyParamBound => {
|
ast::StaticRegionTyParamBound => {
|
||||||
builtin_bounds.add(ty::BoundStatic);
|
builtin_bounds.add(ty::BoundStatic);
|
||||||
}
|
}
|
||||||
|
ast::UnboxedFnTyParamBound(_) => {
|
||||||
|
tcx.sess.span_err(span,
|
||||||
|
"unboxed functions are not allowed \
|
||||||
|
here");
|
||||||
|
}
|
||||||
ast::OtherRegionTyParamBound(span) => {
|
ast::OtherRegionTyParamBound(span) => {
|
||||||
if !tcx.sess.features.issue_5723_bootstrap.get() {
|
if !tcx.sess.features.issue_5723_bootstrap.get() {
|
||||||
tcx.sess.span_err(
|
tcx.sess.span_err(
|
||||||
|
|
|
@ -48,22 +48,21 @@ use middle::typeck::{CrateCtxt, lookup_def_tcx, no_params, write_ty_to_tcx};
|
||||||
use util::ppaux;
|
use util::ppaux;
|
||||||
use util::ppaux::Repr;
|
use util::ppaux::Repr;
|
||||||
|
|
||||||
use std::rc::Rc;
|
|
||||||
use std::collections::{HashMap, HashSet};
|
use std::collections::{HashMap, HashSet};
|
||||||
|
use std::rc::Rc;
|
||||||
use syntax::abi;
|
use syntax::abi;
|
||||||
use syntax::ast::{StaticRegionTyParamBound, OtherRegionTyParamBound,
|
use syntax::ast::{StaticRegionTyParamBound, OtherRegionTyParamBound};
|
||||||
TraitTyParamBound};
|
use syntax::ast::{TraitTyParamBound, UnboxedFnTyParamBound};
|
||||||
use syntax::ast;
|
use syntax::ast;
|
||||||
use syntax::ast_map;
|
use syntax::ast_map;
|
||||||
use syntax::ast_util::{local_def, split_trait_methods};
|
use syntax::ast_util::{local_def, split_trait_methods};
|
||||||
use syntax::codemap::Span;
|
use syntax::codemap::Span;
|
||||||
use syntax::codemap;
|
use syntax::codemap;
|
||||||
|
use syntax::owned_slice::OwnedSlice;
|
||||||
use syntax::parse::token::special_idents;
|
use syntax::parse::token::special_idents;
|
||||||
use syntax::parse::token;
|
use syntax::parse::token;
|
||||||
use syntax::print::pprust::{path_to_str};
|
use syntax::print::pprust::{path_to_str};
|
||||||
use syntax::visit;
|
use syntax::visit;
|
||||||
use syntax::owned_slice::OwnedSlice;
|
|
||||||
|
|
||||||
struct CollectItemTypesVisitor<'a> {
|
struct CollectItemTypesVisitor<'a> {
|
||||||
ccx: &'a CrateCtxt<'a>
|
ccx: &'a CrateCtxt<'a>
|
||||||
|
@ -1114,6 +1113,20 @@ fn ty_generics(ccx: &CrateCtxt,
|
||||||
param_bounds.builtin_bounds.add(ty::BoundStatic);
|
param_bounds.builtin_bounds.add(ty::BoundStatic);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
UnboxedFnTyParamBound(ref unboxed_function) => {
|
||||||
|
let rscope = ExplicitRscope;
|
||||||
|
let mut trait_ref =
|
||||||
|
astconv::trait_ref_for_unboxed_function(
|
||||||
|
ccx,
|
||||||
|
&rscope,
|
||||||
|
unboxed_function);
|
||||||
|
let self_ty = ty::mk_param(ccx.tcx,
|
||||||
|
param_ty.idx,
|
||||||
|
param_ty.def_id);
|
||||||
|
trait_ref.substs.self_ty = Some(self_ty);
|
||||||
|
param_bounds.trait_bounds.push(Rc::new(trait_ref));
|
||||||
|
}
|
||||||
|
|
||||||
OtherRegionTyParamBound(span) => {
|
OtherRegionTyParamBound(span) => {
|
||||||
if !ccx.tcx.sess.features.issue_5723_bootstrap.get() {
|
if !ccx.tcx.sess.features.issue_5723_bootstrap.get() {
|
||||||
ccx.tcx.sess.span_err(
|
ccx.tcx.sess.span_err(
|
||||||
|
|
|
@ -909,6 +909,9 @@ impl<'a> Rebuilder<'a> {
|
||||||
match tpb {
|
match tpb {
|
||||||
&ast::StaticRegionTyParamBound => ast::StaticRegionTyParamBound,
|
&ast::StaticRegionTyParamBound => ast::StaticRegionTyParamBound,
|
||||||
&ast::OtherRegionTyParamBound(s) => ast::OtherRegionTyParamBound(s),
|
&ast::OtherRegionTyParamBound(s) => ast::OtherRegionTyParamBound(s),
|
||||||
|
&ast::UnboxedFnTyParamBound(unboxed_function_type) => {
|
||||||
|
ast::UnboxedFnTyParamBound(unboxed_function_type)
|
||||||
|
}
|
||||||
&ast::TraitTyParamBound(ref tr) => {
|
&ast::TraitTyParamBound(ref tr) => {
|
||||||
let last_seg = tr.path.segments.last().unwrap();
|
let last_seg = tr.path.segments.last().unwrap();
|
||||||
let mut insert = Vec::new();
|
let mut insert = Vec::new();
|
||||||
|
|
|
@ -477,6 +477,10 @@ impl Clean<TyParamBound> for ast::TyParamBound {
|
||||||
match *self {
|
match *self {
|
||||||
ast::StaticRegionTyParamBound => RegionBound,
|
ast::StaticRegionTyParamBound => RegionBound,
|
||||||
ast::OtherRegionTyParamBound(_) => RegionBound,
|
ast::OtherRegionTyParamBound(_) => RegionBound,
|
||||||
|
ast::UnboxedFnTyParamBound(_) => {
|
||||||
|
// FIXME(pcwalton): Wrong.
|
||||||
|
RegionBound
|
||||||
|
}
|
||||||
ast::TraitTyParamBound(ref t) => TraitBound(t.clean()),
|
ast::TraitTyParamBound(ref t) => TraitBound(t.clean()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -175,6 +175,7 @@ pub static DUMMY_NODE_ID: NodeId = -1;
|
||||||
pub enum TyParamBound {
|
pub enum TyParamBound {
|
||||||
TraitTyParamBound(TraitRef),
|
TraitTyParamBound(TraitRef),
|
||||||
StaticRegionTyParamBound,
|
StaticRegionTyParamBound,
|
||||||
|
UnboxedFnTyParamBound(UnboxedFnTy),
|
||||||
OtherRegionTyParamBound(Span) // FIXME -- just here until work for #5723 lands
|
OtherRegionTyParamBound(Span) // FIXME -- just here until work for #5723 lands
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -769,6 +770,11 @@ pub struct BareFnTy {
|
||||||
pub decl: P<FnDecl>
|
pub decl: P<FnDecl>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash)]
|
||||||
|
pub struct UnboxedFnTy {
|
||||||
|
pub decl: P<FnDecl>,
|
||||||
|
}
|
||||||
|
|
||||||
#[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash)]
|
#[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash)]
|
||||||
pub enum Ty_ {
|
pub enum Ty_ {
|
||||||
TyNil,
|
TyNil,
|
||||||
|
@ -782,6 +788,7 @@ pub enum Ty_ {
|
||||||
TyClosure(@ClosureTy, Option<Lifetime>),
|
TyClosure(@ClosureTy, Option<Lifetime>),
|
||||||
TyProc(@ClosureTy),
|
TyProc(@ClosureTy),
|
||||||
TyBareFn(@BareFnTy),
|
TyBareFn(@BareFnTy),
|
||||||
|
TyUnboxedFn(@UnboxedFnTy),
|
||||||
TyTup(Vec<P<Ty>> ),
|
TyTup(Vec<P<Ty>> ),
|
||||||
TyPath(Path, Option<OwnedSlice<TyParamBound>>, NodeId), // for #7264; see above
|
TyPath(Path, Option<OwnedSlice<TyParamBound>>, NodeId), // for #7264; see above
|
||||||
TyTypeof(@Expr),
|
TyTypeof(@Expr),
|
||||||
|
|
|
@ -185,6 +185,11 @@ pub trait Folder {
|
||||||
decl: self.fold_fn_decl(f.decl)
|
decl: self.fold_fn_decl(f.decl)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
TyUnboxedFn(ref f) => {
|
||||||
|
TyUnboxedFn(@UnboxedFnTy {
|
||||||
|
decl: self.fold_fn_decl(f.decl),
|
||||||
|
})
|
||||||
|
}
|
||||||
TyTup(ref tys) => TyTup(tys.iter().map(|&ty| self.fold_ty(ty)).collect()),
|
TyTup(ref tys) => TyTup(tys.iter().map(|&ty| self.fold_ty(ty)).collect()),
|
||||||
TyPath(ref path, ref bounds, id) => {
|
TyPath(ref path, ref bounds, id) => {
|
||||||
let id = self.new_id(id);
|
let id = self.new_id(id);
|
||||||
|
@ -440,6 +445,11 @@ fn fold_ty_param_bound<T: Folder>(tpb: &TyParamBound, fld: &mut T)
|
||||||
match *tpb {
|
match *tpb {
|
||||||
TraitTyParamBound(ref ty) => TraitTyParamBound(fold_trait_ref(ty, fld)),
|
TraitTyParamBound(ref ty) => TraitTyParamBound(fold_trait_ref(ty, fld)),
|
||||||
StaticRegionTyParamBound => StaticRegionTyParamBound,
|
StaticRegionTyParamBound => StaticRegionTyParamBound,
|
||||||
|
UnboxedFnTyParamBound(ref unboxed_function_type) => {
|
||||||
|
UnboxedFnTyParamBound(UnboxedFnTy {
|
||||||
|
decl: fld.fold_fn_decl(unboxed_function_type.decl),
|
||||||
|
})
|
||||||
|
}
|
||||||
OtherRegionTyParamBound(s) => OtherRegionTyParamBound(s)
|
OtherRegionTyParamBound(s) => OtherRegionTyParamBound(s)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -52,9 +52,9 @@ use ast::{TTNonterminal, TupleVariantKind, Ty, Ty_, TyBot, TyBox};
|
||||||
use ast::{TypeField, TyFixedLengthVec, TyClosure, TyProc, TyBareFn};
|
use ast::{TypeField, TyFixedLengthVec, TyClosure, TyProc, TyBareFn};
|
||||||
use ast::{TyTypeof, TyInfer, TypeMethod};
|
use ast::{TyTypeof, TyInfer, TypeMethod};
|
||||||
use ast::{TyNil, TyParam, TyParamBound, TyPath, TyPtr, TyRptr};
|
use ast::{TyNil, TyParam, TyParamBound, TyPath, TyPtr, TyRptr};
|
||||||
use ast::{TyTup, TyU32, TyUniq, TyVec, UnUniq};
|
use ast::{TyTup, TyU32, TyUnboxedFn, TyUniq, TyVec, UnUniq};
|
||||||
use ast::{UnnamedField, UnsafeBlock, UnsafeFn, ViewItem};
|
use ast::{UnboxedFnTy, UnboxedFnTyParamBound, UnnamedField, UnsafeBlock};
|
||||||
use ast::{ViewItem_, ViewItemExternCrate, ViewItemUse};
|
use ast::{UnsafeFn, ViewItem, ViewItem_, ViewItemExternCrate, ViewItemUse};
|
||||||
use ast::{ViewPath, ViewPathGlob, ViewPathList, ViewPathSimple};
|
use ast::{ViewPath, ViewPathGlob, ViewPathList, ViewPathSimple};
|
||||||
use ast::Visibility;
|
use ast::Visibility;
|
||||||
use ast;
|
use ast;
|
||||||
|
@ -1058,15 +1058,27 @@ impl<'a> Parser<'a> {
|
||||||
Vec::new()
|
Vec::new()
|
||||||
};
|
};
|
||||||
|
|
||||||
let inputs = if self.eat(&token::OROR) {
|
let (is_unboxed, inputs) = if self.eat(&token::OROR) {
|
||||||
Vec::new()
|
(false, Vec::new())
|
||||||
} else {
|
} else {
|
||||||
self.expect_or();
|
self.expect_or();
|
||||||
|
|
||||||
|
let is_unboxed = self.token == token::BINOP(token::AND) &&
|
||||||
|
self.look_ahead(1, |t| {
|
||||||
|
token::is_keyword(keywords::Mut, t)
|
||||||
|
}) &&
|
||||||
|
self.look_ahead(2, |t| *t == token::COLON);
|
||||||
|
if is_unboxed {
|
||||||
|
self.bump();
|
||||||
|
self.bump();
|
||||||
|
self.bump();
|
||||||
|
}
|
||||||
|
|
||||||
let inputs = self.parse_seq_to_before_or(
|
let inputs = self.parse_seq_to_before_or(
|
||||||
&token::COMMA,
|
&token::COMMA,
|
||||||
|p| p.parse_arg_general(false));
|
|p| p.parse_arg_general(false));
|
||||||
self.expect_or();
|
self.expect_or();
|
||||||
inputs
|
(is_unboxed, inputs)
|
||||||
};
|
};
|
||||||
|
|
||||||
let (region, bounds) = self.parse_optional_ty_param_bounds(true);
|
let (region, bounds) = self.parse_optional_ty_param_bounds(true);
|
||||||
|
@ -1079,6 +1091,11 @@ impl<'a> Parser<'a> {
|
||||||
variadic: false
|
variadic: false
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if is_unboxed {
|
||||||
|
TyUnboxedFn(@UnboxedFnTy {
|
||||||
|
decl: decl,
|
||||||
|
})
|
||||||
|
} else {
|
||||||
TyClosure(@ClosureTy {
|
TyClosure(@ClosureTy {
|
||||||
fn_style: fn_style,
|
fn_style: fn_style,
|
||||||
onceness: onceness,
|
onceness: onceness,
|
||||||
|
@ -1087,6 +1104,7 @@ impl<'a> Parser<'a> {
|
||||||
lifetimes: lifetimes,
|
lifetimes: lifetimes,
|
||||||
}, region)
|
}, region)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn parse_unsafety(&mut self) -> FnStyle {
|
pub fn parse_unsafety(&mut self) -> FnStyle {
|
||||||
if self.eat_keyword(keywords::Unsafe) {
|
if self.eat_keyword(keywords::Unsafe) {
|
||||||
|
@ -3345,6 +3363,41 @@ impl<'a> Parser<'a> {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn parse_unboxed_function_type(&mut self) -> UnboxedFnTy {
|
||||||
|
let inputs = if self.eat(&token::OROR) {
|
||||||
|
Vec::new()
|
||||||
|
} else {
|
||||||
|
self.expect_or();
|
||||||
|
|
||||||
|
if self.token == token::BINOP(token::AND) &&
|
||||||
|
self.look_ahead(1, |t| {
|
||||||
|
token::is_keyword(keywords::Mut, t)
|
||||||
|
}) &&
|
||||||
|
self.look_ahead(2, |t| *t == token::COLON) {
|
||||||
|
self.bump();
|
||||||
|
self.bump();
|
||||||
|
self.bump();
|
||||||
|
}
|
||||||
|
|
||||||
|
let inputs = self.parse_seq_to_before_or(&token::COMMA,
|
||||||
|
|p| {
|
||||||
|
p.parse_arg_general(false)
|
||||||
|
});
|
||||||
|
self.expect_or();
|
||||||
|
inputs
|
||||||
|
};
|
||||||
|
|
||||||
|
let (return_style, output) = self.parse_ret_ty();
|
||||||
|
UnboxedFnTy {
|
||||||
|
decl: P(FnDecl {
|
||||||
|
inputs: inputs,
|
||||||
|
output: output,
|
||||||
|
cf: return_style,
|
||||||
|
variadic: false,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// matches optbounds = ( ( : ( boundseq )? )? )
|
// matches optbounds = ( ( : ( boundseq )? )? )
|
||||||
// where boundseq = ( bound + boundseq ) | bound
|
// where boundseq = ( bound + boundseq ) | bound
|
||||||
// and bound = 'static | ty
|
// and bound = 'static | ty
|
||||||
|
@ -3394,6 +3447,11 @@ impl<'a> Parser<'a> {
|
||||||
let tref = self.parse_trait_ref();
|
let tref = self.parse_trait_ref();
|
||||||
result.push(TraitTyParamBound(tref));
|
result.push(TraitTyParamBound(tref));
|
||||||
}
|
}
|
||||||
|
token::BINOP(token::OR) | token::OROR => {
|
||||||
|
let unboxed_function_type =
|
||||||
|
self.parse_unboxed_function_type();
|
||||||
|
result.push(UnboxedFnTyParamBound(unboxed_function_type));
|
||||||
|
}
|
||||||
_ => break,
|
_ => break,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
|
|
||||||
use abi;
|
use abi;
|
||||||
use ast::{P, StaticRegionTyParamBound, OtherRegionTyParamBound,
|
use ast::{P, StaticRegionTyParamBound, OtherRegionTyParamBound,
|
||||||
TraitTyParamBound, Required, Provided};
|
TraitTyParamBound, UnboxedFnTyParamBound, Required, Provided};
|
||||||
use ast;
|
use ast;
|
||||||
use ast_util;
|
use ast_util;
|
||||||
use owned_slice::OwnedSlice;
|
use owned_slice::OwnedSlice;
|
||||||
|
@ -505,27 +505,64 @@ impl<'a> State<'a> {
|
||||||
lifetimes: f.lifetimes.clone(),
|
lifetimes: f.lifetimes.clone(),
|
||||||
ty_params: OwnedSlice::empty()
|
ty_params: OwnedSlice::empty()
|
||||||
};
|
};
|
||||||
try!(self.print_ty_fn(Some(f.abi), None, &None,
|
try!(self.print_ty_fn(Some(f.abi),
|
||||||
f.fn_style, ast::Many, f.decl, None, &None,
|
None,
|
||||||
Some(&generics), None));
|
&None,
|
||||||
|
f.fn_style,
|
||||||
|
ast::Many,
|
||||||
|
f.decl,
|
||||||
|
None,
|
||||||
|
&None,
|
||||||
|
Some(&generics),
|
||||||
|
None,
|
||||||
|
false));
|
||||||
}
|
}
|
||||||
ast::TyClosure(f, ref region) => {
|
ast::TyClosure(f, ref region) => {
|
||||||
let generics = ast::Generics {
|
let generics = ast::Generics {
|
||||||
lifetimes: f.lifetimes.clone(),
|
lifetimes: f.lifetimes.clone(),
|
||||||
ty_params: OwnedSlice::empty()
|
ty_params: OwnedSlice::empty()
|
||||||
};
|
};
|
||||||
try!(self.print_ty_fn(None, Some('&'), region, f.fn_style,
|
try!(self.print_ty_fn(None,
|
||||||
f.onceness, f.decl, None, &f.bounds,
|
Some('&'),
|
||||||
Some(&generics), None));
|
region,
|
||||||
|
f.fn_style,
|
||||||
|
f.onceness,
|
||||||
|
f.decl,
|
||||||
|
None,
|
||||||
|
&f.bounds,
|
||||||
|
Some(&generics),
|
||||||
|
None,
|
||||||
|
false));
|
||||||
}
|
}
|
||||||
ast::TyProc(f) => {
|
ast::TyProc(f) => {
|
||||||
let generics = ast::Generics {
|
let generics = ast::Generics {
|
||||||
lifetimes: f.lifetimes.clone(),
|
lifetimes: f.lifetimes.clone(),
|
||||||
ty_params: OwnedSlice::empty()
|
ty_params: OwnedSlice::empty()
|
||||||
};
|
};
|
||||||
try!(self.print_ty_fn(None, Some('~'), &None, f.fn_style,
|
try!(self.print_ty_fn(None,
|
||||||
f.onceness, f.decl, None, &f.bounds,
|
Some('~'),
|
||||||
Some(&generics), None));
|
&None,
|
||||||
|
f.fn_style,
|
||||||
|
f.onceness,
|
||||||
|
f.decl,
|
||||||
|
None,
|
||||||
|
&f.bounds,
|
||||||
|
Some(&generics),
|
||||||
|
None,
|
||||||
|
false));
|
||||||
|
}
|
||||||
|
ast::TyUnboxedFn(f) => {
|
||||||
|
try!(self.print_ty_fn(None,
|
||||||
|
None,
|
||||||
|
&None,
|
||||||
|
ast::NormalFn,
|
||||||
|
ast::Many,
|
||||||
|
f.decl,
|
||||||
|
None,
|
||||||
|
&None,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
true));
|
||||||
}
|
}
|
||||||
ast::TyPath(ref path, ref bounds, _) => {
|
ast::TyPath(ref path, ref bounds, _) => {
|
||||||
try!(self.print_bounded_path(path, bounds));
|
try!(self.print_bounded_path(path, bounds));
|
||||||
|
@ -930,7 +967,8 @@ impl<'a> State<'a> {
|
||||||
Some(m.ident),
|
Some(m.ident),
|
||||||
&None,
|
&None,
|
||||||
Some(&m.generics),
|
Some(&m.generics),
|
||||||
Some(m.explicit_self.node)));
|
Some(m.explicit_self.node),
|
||||||
|
false));
|
||||||
word(&mut self.s, ";")
|
word(&mut self.s, ";")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1925,6 +1963,19 @@ impl<'a> State<'a> {
|
||||||
try!(match *bound {
|
try!(match *bound {
|
||||||
TraitTyParamBound(ref tref) => self.print_trait_ref(tref),
|
TraitTyParamBound(ref tref) => self.print_trait_ref(tref),
|
||||||
StaticRegionTyParamBound => word(&mut self.s, "'static"),
|
StaticRegionTyParamBound => word(&mut self.s, "'static"),
|
||||||
|
UnboxedFnTyParamBound(ref unboxed_function_type) => {
|
||||||
|
self.print_ty_fn(None,
|
||||||
|
None,
|
||||||
|
&None,
|
||||||
|
ast::NormalFn,
|
||||||
|
ast::Many,
|
||||||
|
unboxed_function_type.decl,
|
||||||
|
None,
|
||||||
|
&None,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
true)
|
||||||
|
}
|
||||||
OtherRegionTyParamBound(_) => Ok(())
|
OtherRegionTyParamBound(_) => Ok(())
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -2112,7 +2163,8 @@ impl<'a> State<'a> {
|
||||||
id: Option<ast::Ident>,
|
id: Option<ast::Ident>,
|
||||||
opt_bounds: &Option<OwnedSlice<ast::TyParamBound>>,
|
opt_bounds: &Option<OwnedSlice<ast::TyParamBound>>,
|
||||||
generics: Option<&ast::Generics>,
|
generics: Option<&ast::Generics>,
|
||||||
opt_explicit_self: Option<ast::ExplicitSelf_>)
|
opt_explicit_self: Option<ast::ExplicitSelf_>,
|
||||||
|
is_unboxed: bool)
|
||||||
-> IoResult<()> {
|
-> IoResult<()> {
|
||||||
try!(self.ibox(indent_unit));
|
try!(self.ibox(indent_unit));
|
||||||
|
|
||||||
|
@ -2129,8 +2181,10 @@ impl<'a> State<'a> {
|
||||||
try!(self.print_fn_style(fn_style));
|
try!(self.print_fn_style(fn_style));
|
||||||
try!(self.print_opt_abi_and_extern_if_nondefault(opt_abi));
|
try!(self.print_opt_abi_and_extern_if_nondefault(opt_abi));
|
||||||
try!(self.print_onceness(onceness));
|
try!(self.print_onceness(onceness));
|
||||||
|
if !is_unboxed {
|
||||||
try!(word(&mut self.s, "fn"));
|
try!(word(&mut self.s, "fn"));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
match id {
|
match id {
|
||||||
Some(id) => {
|
Some(id) => {
|
||||||
|
@ -2143,15 +2197,20 @@ impl<'a> State<'a> {
|
||||||
match generics { Some(g) => try!(self.print_generics(g)), _ => () }
|
match generics { Some(g) => try!(self.print_generics(g)), _ => () }
|
||||||
try!(zerobreak(&mut self.s));
|
try!(zerobreak(&mut self.s));
|
||||||
|
|
||||||
if opt_sigil == Some('&') {
|
if is_unboxed || opt_sigil == Some('&') {
|
||||||
try!(word(&mut self.s, "|"));
|
try!(word(&mut self.s, "|"));
|
||||||
} else {
|
} else {
|
||||||
try!(self.popen());
|
try!(self.popen());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if is_unboxed {
|
||||||
|
try!(word(&mut self.s, "&mut"));
|
||||||
|
try!(self.word_space(":"));
|
||||||
|
}
|
||||||
|
|
||||||
try!(self.print_fn_args(decl, opt_explicit_self));
|
try!(self.print_fn_args(decl, opt_explicit_self));
|
||||||
|
|
||||||
if opt_sigil == Some('&') {
|
if is_unboxed || opt_sigil == Some('&') {
|
||||||
try!(word(&mut self.s, "|"));
|
try!(word(&mut self.s, "|"));
|
||||||
} else {
|
} else {
|
||||||
if decl.variadic {
|
if decl.variadic {
|
||||||
|
|
|
@ -383,6 +383,12 @@ pub fn walk_ty<E: Clone, V: Visitor<E>>(visitor: &mut V, typ: &Ty, env: E) {
|
||||||
walk_lifetime_decls(visitor, &function_declaration.lifetimes,
|
walk_lifetime_decls(visitor, &function_declaration.lifetimes,
|
||||||
env.clone());
|
env.clone());
|
||||||
}
|
}
|
||||||
|
TyUnboxedFn(ref function_declaration) => {
|
||||||
|
for argument in function_declaration.decl.inputs.iter() {
|
||||||
|
visitor.visit_ty(argument.ty, env.clone())
|
||||||
|
}
|
||||||
|
visitor.visit_ty(function_declaration.decl.output, env.clone());
|
||||||
|
}
|
||||||
TyPath(ref path, ref bounds, id) => {
|
TyPath(ref path, ref bounds, id) => {
|
||||||
visitor.visit_path(path, id, env.clone());
|
visitor.visit_path(path, id, env.clone());
|
||||||
for bounds in bounds.iter() {
|
for bounds in bounds.iter() {
|
||||||
|
@ -501,6 +507,13 @@ pub fn walk_ty_param_bounds<E: Clone, V: Visitor<E>>(visitor: &mut V,
|
||||||
walk_trait_ref_helper(visitor, typ, env.clone())
|
walk_trait_ref_helper(visitor, typ, env.clone())
|
||||||
}
|
}
|
||||||
StaticRegionTyParamBound => {}
|
StaticRegionTyParamBound => {}
|
||||||
|
UnboxedFnTyParamBound(ref function_declaration) => {
|
||||||
|
for argument in function_declaration.decl.inputs.iter() {
|
||||||
|
visitor.visit_ty(argument.ty, env.clone())
|
||||||
|
}
|
||||||
|
visitor.visit_ty(function_declaration.decl.output,
|
||||||
|
env.clone());
|
||||||
|
}
|
||||||
OtherRegionTyParamBound(..) => {}
|
OtherRegionTyParamBound(..) => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
38
src/test/run-pass/fn-trait-sugar.rs
Normal file
38
src/test/run-pass/fn-trait-sugar.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.
|
||||||
|
|
||||||
|
#![feature(unboxed_closure_sugar)]
|
||||||
|
|
||||||
|
use std::ops::FnMut;
|
||||||
|
|
||||||
|
struct S;
|
||||||
|
|
||||||
|
impl FnMut<(int,),int> for S {
|
||||||
|
fn call_mut(&mut self, (x,): (int,)) -> int {
|
||||||
|
x * x
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn call_it<F:|int|->int>(mut f: F, x: int) -> int {
|
||||||
|
f.call_mut((x,)) + 3
|
||||||
|
}
|
||||||
|
|
||||||
|
fn call_box(f: &mut |&mut: int|->int, x: int) -> int {
|
||||||
|
f.call_mut((x,)) + 3
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let x = call_it(S, 1);
|
||||||
|
let y = call_box(&mut S, 1);
|
||||||
|
assert!(x == 4);
|
||||||
|
assert!(y == 4);
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue