about summary refs log tree commit diff
path: root/src/libsyntax
diff options
context:
space:
mode:
authorPatrick Walton <pcwalton@mimiga.net>2014-06-01 18:41:46 -0700
committerPatrick Walton <pcwalton@mimiga.net>2014-06-09 20:19:07 -0700
commitf02b6f3a8bf82ca11ba50a285841fb372c4da459 (patch)
tree4f0ae29d0f388e4570a20d22c2f6619eee464738 /src/libsyntax
parent907d96187641d8a018af2b73239723c66b011f71 (diff)
downloadrust-f02b6f3a8bf82ca11ba50a285841fb372c4da459.tar.gz
rust-f02b6f3a8bf82ca11ba50a285841fb372c4da459.zip
librustc: Implement sugar for the `FnMut` trait
Diffstat (limited to 'src/libsyntax')
-rw-r--r--src/libsyntax/ast.rs7
-rw-r--r--src/libsyntax/fold.rs10
-rw-r--r--src/libsyntax/parse/parser.rs84
-rw-r--r--src/libsyntax/print/pprust.rs91
-rw-r--r--src/libsyntax/visit.rs13
5 files changed, 176 insertions, 29 deletions
diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs
index 2bc24fd1eb3..9c3960d0f06 100644
--- a/src/libsyntax/ast.rs
+++ b/src/libsyntax/ast.rs
@@ -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
 }
 
@@ -770,6 +771,11 @@ pub struct BareFnTy {
 }
 
 #[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,
     TyBot, /* bottom type */
@@ -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),
diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs
index 8903eb80829..03d0c283bcc 100644
--- a/src/libsyntax/fold.rs
+++ b/src/libsyntax/fold.rs
@@ -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)
     }
 }
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index 4af4385e3c1..360b8daa948 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -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,
             }
 
diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs
index 05c2558da48..f22b24b5a29 100644
--- a/src/libsyntax/print/pprust.rs
+++ b/src/libsyntax/print/pprust.rs
@@ -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 {
diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs
index 906f0c16f39..b5ae8a3dea0 100644
--- a/src/libsyntax/visit.rs
+++ b/src/libsyntax/visit.rs
@@ -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(..) => {}
         }
     }