librustc: Implement sugar for the FnMut trait

This commit is contained in:
Patrick Walton 2014-06-01 18:41:46 -07:00
parent 907d961876
commit f02b6f3a8b
12 changed files with 343 additions and 46 deletions

View file

@ -175,6 +175,7 @@ pub static DUMMY_NODE_ID: NodeId = -1;
pub enum TyParamBound {
TraitTyParamBound(TraitRef),
StaticRegionTyParamBound,
UnboxedFnTyParamBound(UnboxedFnTy),
OtherRegionTyParamBound(Span) // FIXME -- just here until work for #5723 lands
}
@ -769,6 +770,11 @@ pub struct BareFnTy {
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)]
pub enum Ty_ {
TyNil,
@ -782,6 +788,7 @@ pub enum Ty_ {
TyClosure(@ClosureTy, Option<Lifetime>),
TyProc(@ClosureTy),
TyBareFn(@BareFnTy),
TyUnboxedFn(@UnboxedFnTy),
TyTup(Vec<P<Ty>> ),
TyPath(Path, Option<OwnedSlice<TyParamBound>>, NodeId), // for #7264; see above
TyTypeof(@Expr),

View file

@ -185,6 +185,11 @@ pub trait Folder {
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()),
TyPath(ref path, ref bounds, 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 {
TraitTyParamBound(ref ty) => TraitTyParamBound(fold_trait_ref(ty, fld)),
StaticRegionTyParamBound => StaticRegionTyParamBound,
UnboxedFnTyParamBound(ref unboxed_function_type) => {
UnboxedFnTyParamBound(UnboxedFnTy {
decl: fld.fold_fn_decl(unboxed_function_type.decl),
})
}
OtherRegionTyParamBound(s) => OtherRegionTyParamBound(s)
}
}

View file

@ -52,9 +52,9 @@ use ast::{TTNonterminal, TupleVariantKind, Ty, Ty_, TyBot, TyBox};
use ast::{TypeField, TyFixedLengthVec, TyClosure, TyProc, TyBareFn};
use ast::{TyTypeof, TyInfer, TypeMethod};
use ast::{TyNil, TyParam, TyParamBound, TyPath, TyPtr, TyRptr};
use ast::{TyTup, TyU32, TyUniq, TyVec, UnUniq};
use ast::{UnnamedField, UnsafeBlock, UnsafeFn, ViewItem};
use ast::{ViewItem_, ViewItemExternCrate, ViewItemUse};
use ast::{TyTup, TyU32, TyUnboxedFn, TyUniq, TyVec, UnUniq};
use ast::{UnboxedFnTy, UnboxedFnTyParamBound, UnnamedField, UnsafeBlock};
use ast::{UnsafeFn, ViewItem, ViewItem_, ViewItemExternCrate, ViewItemUse};
use ast::{ViewPath, ViewPathGlob, ViewPathList, ViewPathSimple};
use ast::Visibility;
use ast;
@ -1058,15 +1058,27 @@ impl<'a> Parser<'a> {
Vec::new()
};
let inputs = if self.eat(&token::OROR) {
Vec::new()
let (is_unboxed, inputs) = if self.eat(&token::OROR) {
(false, Vec::new())
} else {
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(
&token::COMMA,
|p| p.parse_arg_general(false));
self.expect_or();
inputs
(is_unboxed, inputs)
};
let (region, bounds) = self.parse_optional_ty_param_bounds(true);
@ -1079,13 +1091,19 @@ impl<'a> Parser<'a> {
variadic: false
});
TyClosure(@ClosureTy {
fn_style: fn_style,
onceness: onceness,
bounds: bounds,
decl: decl,
lifetimes: lifetimes,
}, region)
if is_unboxed {
TyUnboxedFn(@UnboxedFnTy {
decl: decl,
})
} else {
TyClosure(@ClosureTy {
fn_style: fn_style,
onceness: onceness,
bounds: bounds,
decl: decl,
lifetimes: lifetimes,
}, region)
}
}
pub fn parse_unsafety(&mut self) -> FnStyle {
@ -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 )? )? )
// where boundseq = ( bound + boundseq ) | bound
// and bound = 'static | ty
@ -3394,6 +3447,11 @@ impl<'a> Parser<'a> {
let tref = self.parse_trait_ref();
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,
}

View file

@ -10,7 +10,7 @@
use abi;
use ast::{P, StaticRegionTyParamBound, OtherRegionTyParamBound,
TraitTyParamBound, Required, Provided};
TraitTyParamBound, UnboxedFnTyParamBound, Required, Provided};
use ast;
use ast_util;
use owned_slice::OwnedSlice;
@ -505,27 +505,64 @@ impl<'a> State<'a> {
lifetimes: f.lifetimes.clone(),
ty_params: OwnedSlice::empty()
};
try!(self.print_ty_fn(Some(f.abi), None, &None,
f.fn_style, ast::Many, f.decl, None, &None,
Some(&generics), None));
try!(self.print_ty_fn(Some(f.abi),
None,
&None,
f.fn_style,
ast::Many,
f.decl,
None,
&None,
Some(&generics),
None,
false));
}
ast::TyClosure(f, ref region) => {
let generics = ast::Generics {
lifetimes: f.lifetimes.clone(),
ty_params: OwnedSlice::empty()
};
try!(self.print_ty_fn(None, Some('&'), region, f.fn_style,
f.onceness, f.decl, None, &f.bounds,
Some(&generics), None));
try!(self.print_ty_fn(None,
Some('&'),
region,
f.fn_style,
f.onceness,
f.decl,
None,
&f.bounds,
Some(&generics),
None,
false));
}
ast::TyProc(f) => {
let generics = ast::Generics {
lifetimes: f.lifetimes.clone(),
ty_params: OwnedSlice::empty()
};
try!(self.print_ty_fn(None, Some('~'), &None, f.fn_style,
f.onceness, f.decl, None, &f.bounds,
Some(&generics), None));
try!(self.print_ty_fn(None,
Some('~'),
&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, _) => {
try!(self.print_bounded_path(path, bounds));
@ -930,7 +967,8 @@ impl<'a> State<'a> {
Some(m.ident),
&None,
Some(&m.generics),
Some(m.explicit_self.node)));
Some(m.explicit_self.node),
false));
word(&mut self.s, ";")
}
@ -1925,6 +1963,19 @@ impl<'a> State<'a> {
try!(match *bound {
TraitTyParamBound(ref tref) => self.print_trait_ref(tref),
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(())
})
}
@ -2112,8 +2163,9 @@ impl<'a> State<'a> {
id: Option<ast::Ident>,
opt_bounds: &Option<OwnedSlice<ast::TyParamBound>>,
generics: Option<&ast::Generics>,
opt_explicit_self: Option<ast::ExplicitSelf_>)
-> IoResult<()> {
opt_explicit_self: Option<ast::ExplicitSelf_>,
is_unboxed: bool)
-> IoResult<()> {
try!(self.ibox(indent_unit));
// Duplicates the logic in `print_fn_header_info()`. This is because that
@ -2129,7 +2181,9 @@ impl<'a> State<'a> {
try!(self.print_fn_style(fn_style));
try!(self.print_opt_abi_and_extern_if_nondefault(opt_abi));
try!(self.print_onceness(onceness));
try!(word(&mut self.s, "fn"));
if !is_unboxed {
try!(word(&mut self.s, "fn"));
}
}
match id {
@ -2143,15 +2197,20 @@ impl<'a> State<'a> {
match generics { Some(g) => try!(self.print_generics(g)), _ => () }
try!(zerobreak(&mut self.s));
if opt_sigil == Some('&') {
if is_unboxed || opt_sigil == Some('&') {
try!(word(&mut self.s, "|"));
} else {
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));
if opt_sigil == Some('&') {
if is_unboxed || opt_sigil == Some('&') {
try!(word(&mut self.s, "|"));
} else {
if decl.variadic {

View file

@ -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,
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) => {
visitor.visit_path(path, id, env.clone());
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())
}
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(..) => {}
}
}