about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2013-10-31 22:26:24 -0700
committerbors <bors@rust-lang.org>2013-10-31 22:26:24 -0700
commit41ffc90e983a0d1a1c7cde0e530377d2f29cf7e2 (patch)
tree90a6c01f48aa39ab5b5a4eb87b5ee2fd9f665327
parent1bbd4afb4ae5503bc04a7f500bc8ade6e1db0854 (diff)
parenta6f776d2dc22a998c6dbeb4216816489b7c4fdbe (diff)
downloadrust-41ffc90e983a0d1a1c7cde0e530377d2f29cf7e2.tar.gz
rust-41ffc90e983a0d1a1c7cde0e530377d2f29cf7e2.zip
auto merge of #10187 : pcwalton/rust/remove-mocks, r=pcwalton
r? @alexcrichton
-rw-r--r--src/librustc/util/ppaux.rs54
-rw-r--r--src/libstd/rt/io/extensions.rs262
-rw-r--r--src/libstd/rt/io/mock.rs47
-rw-r--r--src/libstd/rt/io/mod.rs3
-rw-r--r--src/libsyntax/parse/parser.rs186
-rw-r--r--src/libsyntax/print/pprust.rs45
-rw-r--r--src/test/compile-fail/block-coerce-no-2.rs2
-rw-r--r--src/test/compile-fail/closure-reform-bad.rs13
-rw-r--r--src/test/pretty/closure-reform-pretty.rs17
-rw-r--r--src/test/pretty/disamb-stmt-expr.rs2
-rw-r--r--src/test/pretty/do1.rs2
-rw-r--r--src/test/pretty/fn-types.rs4
-rw-r--r--src/test/run-pass/closure-reform.rs52
13 files changed, 451 insertions, 238 deletions
diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs
index 2f8c1f6f97d..ab1ca420afa 100644
--- a/src/librustc/util/ppaux.rs
+++ b/src/librustc/util/ppaux.rs
@@ -308,10 +308,11 @@ pub fn ty_to_str(cx: ctxt, typ: t) -> ~str {
                       ident: Option<ast::Ident>,
                       sig: &ty::FnSig)
                       -> ~str {
-        let mut s = ~"extern ";
-
-        s.push_str(abis.to_str());
-        s.push_char(' ');
+        let mut s = if abis.is_rust() {
+            ~""
+        } else {
+            format!("extern {} ", abis.to_str())
+        };
 
         match purity {
             ast::impure_fn => {}
@@ -331,16 +332,16 @@ pub fn ty_to_str(cx: ctxt, typ: t) -> ~str {
           _ => { }
         }
 
-        push_sig_to_str(cx, &mut s, sig);
+        push_sig_to_str(cx, &mut s, '(', ')', sig);
 
         return s;
     }
-    fn closure_to_str(cx: ctxt, cty: &ty::ClosureTy) -> ~str
-    {
+    fn closure_to_str(cx: ctxt, cty: &ty::ClosureTy) -> ~str {
         let is_proc =
             (cty.sigil, cty.onceness) == (ast::OwnedSigil, ast::Once);
+        let is_borrowed_closure = cty.sigil == ast::BorrowedSigil;
 
-        let mut s = if is_proc {
+        let mut s = if is_proc || is_borrowed_closure {
             ~""
         } else {
             cty.sigil.to_str()
@@ -374,23 +375,42 @@ pub fn ty_to_str(cx: ctxt, typ: t) -> ~str {
                 }
             };
 
-            s.push_str("fn");
+            if !is_borrowed_closure {
+                s.push_str("fn");
+            }
         }
 
-        if !cty.bounds.is_empty() {
-            s.push_str(":");
-        }
-        s.push_str(cty.bounds.repr(cx));
+        if !is_borrowed_closure {
+            // Print bounds before `fn` if this is not a borrowed closure.
+            if !cty.bounds.is_empty() {
+                s.push_str(":");
+                s.push_str(cty.bounds.repr(cx));
+            }
+
+            push_sig_to_str(cx, &mut s, '(', ')', &cty.sig);
+        } else {
+            // Print bounds after the signature if this is a borrowed closure.
+            push_sig_to_str(cx, &mut s, '|', '|', &cty.sig);
 
-        push_sig_to_str(cx, &mut s, &cty.sig);
+            if is_borrowed_closure {
+                if !cty.bounds.is_empty() {
+                    s.push_str(":");
+                    s.push_str(cty.bounds.repr(cx));
+                }
+            }
+        }
 
         return s;
     }
-    fn push_sig_to_str(cx: ctxt, s: &mut ~str, sig: &ty::FnSig) {
-        s.push_char('(');
+    fn push_sig_to_str(cx: ctxt,
+                       s: &mut ~str,
+                       bra: char,
+                       ket: char,
+                       sig: &ty::FnSig) {
+        s.push_char(bra);
         let strs = sig.inputs.map(|a| fn_input_to_str(cx, *a));
         s.push_str(strs.connect(", "));
-        s.push_char(')');
+        s.push_char(ket);
         if ty::get(sig.output).sty != ty_nil {
             s.push_str(" -> ");
             if ty::type_is_bot(sig.output) {
diff --git a/src/libstd/rt/io/extensions.rs b/src/libstd/rt/io/extensions.rs
index 8bbc4b62eb9..261792977b3 100644
--- a/src/libstd/rt/io/extensions.rs
+++ b/src/libstd/rt/io/extensions.rs
@@ -138,11 +138,118 @@ pub fn u64_from_be_bytes(data: &[u8],
 
 #[cfg(test)]
 mod test {
-    use option::{Some, None};
-    use cell::Cell;
+    use option::{None, Option, Some};
     use rt::io::mem::{MemReader, MemWriter};
-    use rt::io::mock::MockReader;
-    use rt::io::{io_error, placeholder_error};
+    use rt::io::{Reader, io_error, placeholder_error};
+
+    struct InitialZeroByteReader {
+        count: int,
+    }
+
+    impl Reader for InitialZeroByteReader {
+        fn read(&mut self, buf: &mut [u8]) -> Option<uint> {
+            if self.count == 0 {
+                self.count = 1;
+                Some(0)
+            } else {
+                buf[0] = 10;
+                Some(1)
+            }
+        }
+        fn eof(&mut self) -> bool {
+            false
+        }
+    }
+
+    struct EofReader;
+
+    impl Reader for EofReader {
+        fn read(&mut self, _: &mut [u8]) -> Option<uint> {
+            None
+        }
+        fn eof(&mut self) -> bool {
+            false
+        }
+    }
+
+    struct ErroringReader;
+
+    impl Reader for ErroringReader {
+        fn read(&mut self, _: &mut [u8]) -> Option<uint> {
+            io_error::cond.raise(placeholder_error());
+            None
+        }
+        fn eof(&mut self) -> bool {
+            false
+        }
+    }
+
+    struct PartialReader {
+        count: int,
+    }
+
+    impl Reader for PartialReader {
+        fn read(&mut self, buf: &mut [u8]) -> Option<uint> {
+            if self.count == 0 {
+                self.count = 1;
+                buf[0] = 10;
+                buf[1] = 11;
+                Some(2)
+            } else {
+                buf[0] = 12;
+                buf[1] = 13;
+                Some(2)
+            }
+        }
+        fn eof(&mut self) -> bool {
+            false
+        }
+    }
+
+    struct ErroringLaterReader {
+        count: int,
+    }
+
+    impl Reader for ErroringLaterReader {
+        fn read(&mut self, buf: &mut [u8]) -> Option<uint> {
+            if self.count == 0 {
+                self.count = 1;
+                buf[0] = 10;
+                Some(1)
+            } else {
+                io_error::cond.raise(placeholder_error());
+                None
+            }
+        }
+        fn eof(&mut self) -> bool {
+            false
+        }
+    }
+
+    struct ThreeChunkReader {
+        count: int,
+    }
+
+    impl Reader for ThreeChunkReader {
+        fn read(&mut self, buf: &mut [u8]) -> Option<uint> {
+            if self.count == 0 {
+                self.count = 1;
+                buf[0] = 10;
+                buf[1] = 11;
+                Some(2)
+            } else if self.count == 1 {
+                self.count = 2;
+                buf[0] = 12;
+                buf[1] = 13;
+                Some(2)
+            } else {
+                None
+            }
+        }
+        fn eof(&mut self) -> bool {
+            false
+        }
+    }
 
     #[test]
     fn read_byte() {
@@ -153,18 +260,8 @@ mod test {
 
     #[test]
     fn read_byte_0_bytes() {
-        let mut reader = MockReader::new();
-        let count = Cell::new(0);
-        reader.read = |buf| {
-            do count.with_mut_ref |count| {
-                if *count == 0 {
-                    *count = 1;
-                    Some(0)
-                } else {
-                    buf[0] = 10;
-                    Some(1)
-                }
-            }
+        let mut reader = InitialZeroByteReader {
+            count: 0,
         };
         let byte = reader.read_byte();
         assert!(byte == Some(10));
@@ -172,19 +269,14 @@ mod test {
 
     #[test]
     fn read_byte_eof() {
-        let mut reader = MockReader::new();
-        reader.read = |_| None;
+        let mut reader = EofReader;
         let byte = reader.read_byte();
         assert!(byte == None);
     }
 
     #[test]
     fn read_byte_error() {
-        let mut reader = MockReader::new();
-        reader.read = |_| {
-            io_error::cond.raise(placeholder_error());
-            None
-        };
+        let mut reader = ErroringReader;
         do io_error::cond.trap(|_| {
         }).inside {
             let byte = reader.read_byte();
@@ -194,18 +286,8 @@ mod test {
 
     #[test]
     fn bytes_0_bytes() {
-        let mut reader = MockReader::new();
-        let count = Cell::new(0);
-        reader.read = |buf| {
-            do count.with_mut_ref |count| {
-                if *count == 0 {
-                    *count = 1;
-                    Some(0)
-                } else {
-                    buf[0] = 10;
-                    Some(1)
-                }
-            }
+        let reader = InitialZeroByteReader {
+            count: 0,
         };
         let byte = reader.bytes().next();
         assert!(byte == Some(10));
@@ -213,19 +295,14 @@ mod test {
 
     #[test]
     fn bytes_eof() {
-        let mut reader = MockReader::new();
-        reader.read = |_| None;
+        let reader = EofReader;
         let byte = reader.bytes().next();
         assert!(byte == None);
     }
 
     #[test]
     fn bytes_error() {
-        let mut reader = MockReader::new();
-        reader.read = |_| {
-            io_error::cond.raise(placeholder_error());
-            None
-        };
+        let reader = ErroringReader;
         let mut it = reader.bytes();
         do io_error::cond.trap(|_| ()).inside {
             let byte = it.next();
@@ -233,7 +310,6 @@ mod test {
         }
     }
 
-
     #[test]
     fn read_bytes() {
         let mut reader = MemReader::new(~[10, 11, 12, 13]);
@@ -243,21 +319,8 @@ mod test {
 
     #[test]
     fn read_bytes_partial() {
-        let mut reader = MockReader::new();
-        let count = Cell::new(0);
-        reader.read = |buf| {
-            do count.with_mut_ref |count| {
-                if *count == 0 {
-                    *count = 1;
-                    buf[0] = 10;
-                    buf[1] = 11;
-                    Some(2)
-                } else {
-                    buf[0] = 12;
-                    buf[1] = 13;
-                    Some(2)
-                }
-            }
+        let mut reader = PartialReader {
+            count: 0,
         };
         let bytes = reader.read_bytes(4);
         assert!(bytes == ~[10, 11, 12, 13]);
@@ -282,21 +345,8 @@ mod test {
 
     #[test]
     fn push_bytes_partial() {
-        let mut reader = MockReader::new();
-        let count = Cell::new(0);
-        reader.read = |buf| {
-            do count.with_mut_ref |count| {
-                if *count == 0 {
-                    *count = 1;
-                    buf[0] = 10;
-                    buf[1] = 11;
-                    Some(2)
-                } else {
-                    buf[0] = 12;
-                    buf[1] = 13;
-                    Some(2)
-                }
-            }
+        let mut reader = PartialReader {
+            count: 0,
         };
         let mut buf = ~[8, 9];
         reader.push_bytes(&mut buf, 4);
@@ -316,19 +366,8 @@ mod test {
 
     #[test]
     fn push_bytes_error() {
-        let mut reader = MockReader::new();
-        let count = Cell::new(0);
-        reader.read = |buf| {
-            do count.with_mut_ref |count| {
-                if *count == 0 {
-                    *count = 1;
-                    buf[0] = 10;
-                    Some(1)
-                } else {
-                    io_error::cond.raise(placeholder_error());
-                    None
-                }
-            }
+        let mut reader = ErroringLaterReader {
+            count: 0,
         };
         let mut buf = ~[8, 9];
         do io_error::cond.trap(|_| { } ).inside {
@@ -342,19 +381,8 @@ mod test {
     fn push_bytes_fail_reset_len() {
         // push_bytes unsafely sets the vector length. This is testing that
         // upon failure the length is reset correctly.
-        let mut reader = MockReader::new();
-        let count = Cell::new(0);
-        reader.read = |buf| {
-            do count.with_mut_ref |count| {
-                if *count == 0 {
-                    *count = 1;
-                    buf[0] = 10;
-                    Some(1)
-                } else {
-                    io_error::cond.raise(placeholder_error());
-                    None
-                }
-            }
+        let mut reader = ErroringLaterReader {
+            count: 0,
         };
         let buf = @mut ~[8, 9];
         do (|| {
@@ -368,24 +396,8 @@ mod test {
 
     #[test]
     fn read_to_end() {
-        let mut reader = MockReader::new();
-        let count = Cell::new(0);
-        reader.read = |buf| {
-            do count.with_mut_ref |count| {
-                if *count == 0 {
-                    *count = 1;
-                    buf[0] = 10;
-                    buf[1] = 11;
-                    Some(2)
-                } else if *count == 1 {
-                    *count = 2;
-                    buf[0] = 12;
-                    buf[1] = 13;
-                    Some(2)
-                } else {
-                    None
-                }
-            }
+        let mut reader = ThreeChunkReader {
+            count: 0,
         };
         let buf = reader.read_to_end();
         assert!(buf == ~[10, 11, 12, 13]);
@@ -394,20 +406,8 @@ mod test {
     #[test]
     #[should_fail]
     fn read_to_end_error() {
-        let mut reader = MockReader::new();
-        let count = Cell::new(0);
-        reader.read = |buf| {
-            do count.with_mut_ref |count| {
-                if *count == 0 {
-                    *count = 1;
-                    buf[0] = 10;
-                    buf[1] = 11;
-                    Some(2)
-                } else {
-                    io_error::cond.raise(placeholder_error());
-                    None
-                }
-            }
+        let mut reader = ThreeChunkReader {
+            count: 0,
         };
         let buf = reader.read_to_end();
         assert!(buf == ~[10, 11]);
diff --git a/src/libstd/rt/io/mock.rs b/src/libstd/rt/io/mock.rs
deleted file mode 100644
index a0fd6846ce9..00000000000
--- a/src/libstd/rt/io/mock.rs
+++ /dev/null
@@ -1,47 +0,0 @@
-// Copyright 2013 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.
-
-use option::{Option, None};
-use rt::io::{Reader, Writer};
-
-pub struct MockReader {
-    read: ~fn(buf: &mut [u8]) -> Option<uint>,
-    priv eof: ~fn() -> bool
-}
-
-impl MockReader {
-    pub fn new() -> MockReader {
-        MockReader {
-            read: |_| None,
-            eof: || false
-        }
-    }
-}
-
-impl Reader for MockReader {
-    fn read(&mut self, buf: &mut [u8]) -> Option<uint> { (self.read)(buf) }
-    fn eof(&mut self) -> bool { (self.eof)() }
-}
-
-pub struct MockWriter {
-    priv write: ~fn(buf: &[u8]),
-}
-
-impl MockWriter {
-    pub fn new() -> MockWriter {
-        MockWriter {
-            write: |_| (),
-        }
-    }
-}
-
-impl Writer for MockWriter {
-    fn write(&mut self, buf: &[u8]) { (self.write)(buf) }
-}
diff --git a/src/libstd/rt/io/mod.rs b/src/libstd/rt/io/mod.rs
index 1fd3bf1f238..be205749186 100644
--- a/src/libstd/rt/io/mod.rs
+++ b/src/libstd/rt/io/mod.rs
@@ -323,9 +323,6 @@ pub mod native {
     }
 }
 
-/// Mock implementations for testing
-mod mock;
-
 /// Signal handling
 pub mod signal;
 
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index 68796a39f1b..56254704e28 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -561,6 +561,45 @@ impl Parser {
         }
     }
 
+    // Expect and consume a `|`. If `||` is seen, replace it with a single
+    // `|` and continue. If a `|` is not seen, signal an error.
+    fn expect_or(&self) {
+        match *self.token {
+            token::BINOP(token::OR) => self.bump(),
+            token::OROR => {
+                self.replace_token(token::BINOP(token::OR),
+                                   self.span.lo + BytePos(1),
+                                   self.span.hi)
+            }
+            _ => {
+                let found_token = self.token_to_str(&token::BINOP(token::OR));
+                self.fatal(format!("expected `{}`, found `{}`",
+                                   found_token,
+                                   self.this_token_to_str()))
+            }
+        }
+    }
+
+    // Parse a sequence bracketed by `|` and `|`, stopping before the `|`.
+    fn parse_seq_to_before_or<T>(&self,
+                                 sep: &token::Token,
+                                 f: &fn(&Parser) -> T)
+                                 -> ~[T] {
+        let mut first = true;
+        let mut vector = ~[];
+        while *self.token != token::BINOP(token::OR) &&
+                *self.token != token::OROR {
+            if first {
+                first = false
+            } else {
+                self.expect(sep)
+            }
+
+            vector.push(f(self))
+        }
+        vector
+    }
+
     // expect and consume a GT. if a >> is seen, replace it
     // with a single > and continue. If a GT is not seen,
     // signal an error.
@@ -761,11 +800,33 @@ impl Parser {
         get_ident_interner().get(id.name)
     }
 
-    // is this one of the keywords that signals a closure type?
-    pub fn token_is_closure_keyword(&self, tok: &token::Token) -> bool {
-        token::is_keyword(keywords::Unsafe, tok) ||
-            token::is_keyword(keywords::Once, tok) ||
-            token::is_keyword(keywords::Fn, tok)
+    // Is the current token one of the keywords that signals a bare function
+    // type?
+    pub fn token_is_bare_fn_keyword(&self) -> bool {
+        if token::is_keyword(keywords::Fn, self.token) {
+            return true
+        }
+
+        if token::is_keyword(keywords::Unsafe, self.token) ||
+            token::is_keyword(keywords::Once, self.token) {
+            return self.look_ahead(1, |t| token::is_keyword(keywords::Fn, t))
+        }
+
+        false
+    }
+
+    // Is the current token one of the keywords that signals a closure type?
+    pub fn token_is_closure_keyword(&self) -> bool {
+        token::is_keyword(keywords::Unsafe, self.token) ||
+            token::is_keyword(keywords::Once, self.token)
+    }
+
+    // Is the current token one of the keywords that signals an old-style
+    // closure type (with explicit sigil)?
+    pub fn token_is_old_style_closure_keyword(&self) -> bool {
+        token::is_keyword(keywords::Unsafe, self.token) ||
+            token::is_keyword(keywords::Once, self.token) ||
+            token::is_keyword(keywords::Fn, self.token)
     }
 
     pub fn token_is_lifetime(&self, tok: &token::Token) -> bool {
@@ -786,15 +847,15 @@ impl Parser {
     pub fn parse_ty_bare_fn(&self) -> ty_ {
         /*
 
-        extern "ABI" [unsafe] fn <'lt> (S) -> T
-               ^~~~^ ^~~~~~~^    ^~~~^ ^~^    ^
-                 |     |           |    |     |
-                 |     |           |    |   Return type
-                 |     |           |  Argument types
-                 |     |       Lifetimes
-                 |     |
-                 |   Purity
-                ABI
+        [extern "ABI"] [unsafe] fn <'lt> (S) -> T
+                ^~~~^  ^~~~~~~^    ^~~~^ ^~^    ^
+                  |      |           |    |     |
+                  |      |           |    |   Return type
+                  |      |           |  Argument types
+                  |      |       Lifetimes
+                  |      |
+                  |    Purity
+                 ABI
 
         */
 
@@ -828,8 +889,8 @@ impl Parser {
 
     // parse a ty_closure type
     pub fn parse_ty_closure(&self,
-                            sigil: ast::Sigil,
-                            region: Option<ast::Lifetime>)
+                            opt_sigil: Option<ast::Sigil>,
+                            mut region: Option<ast::Lifetime>)
                             -> ty_ {
         /*
 
@@ -852,10 +913,58 @@ impl Parser {
 
         let purity = self.parse_unsafety();
         let onceness = parse_onceness(self);
-        self.expect_keyword(keywords::Fn);
-        let bounds = self.parse_optional_ty_param_bounds();
 
-        let (decl, lifetimes) = self.parse_ty_fn_decl();
+        let (sigil, decl, lifetimes, bounds) = match opt_sigil {
+            Some(sigil) => {
+                // Old-style closure syntax (`fn(A)->B`).
+                self.expect_keyword(keywords::Fn);
+                let bounds = self.parse_optional_ty_param_bounds();
+                let (decl, lifetimes) = self.parse_ty_fn_decl();
+                (sigil, decl, lifetimes, bounds)
+            }
+            None => {
+                // New-style closure syntax (`<'lt>|A|:K -> B`).
+                let lifetimes = if self.eat(&token::LT) {
+                    let lifetimes = self.parse_lifetimes();
+                    self.expect_gt();
+
+                    // Re-parse the region here. What a hack.
+                    if region.is_some() {
+                        self.span_err(*self.last_span,
+                                      "lifetime declarations must precede \
+                                       the lifetime associated with a \
+                                       closure");
+                    }
+                    region = self.parse_opt_lifetime();
+
+                    lifetimes
+                } else {
+                    opt_vec::Empty
+                };
+
+                let inputs = if self.eat(&token::OROR) {
+                    ~[]
+                } else {
+                    self.expect_or();
+                    let inputs = self.parse_seq_to_before_or(
+                        &token::COMMA,
+                        |p| p.parse_arg_general(false));
+                    self.expect_or();
+                    inputs
+                };
+
+                let bounds = self.parse_optional_ty_param_bounds();
+
+                let (return_style, output) = self.parse_ret_ty();
+                let decl = ast::fn_decl {
+                    inputs: inputs,
+                    output: output,
+                    cf: return_style,
+                };
+
+                (BorrowedSigil, decl, lifetimes, bounds)
+            }
+        };
 
         return ty_closure(@TyClosure {
             sigil: sigil,
@@ -1120,13 +1229,23 @@ impl Parser {
             // BORROWED POINTER
             self.bump();
             self.parse_borrowed_pointee()
-        } else if self.eat_keyword(keywords::Extern) {
-            // EXTERN FUNCTION
+        } else if self.is_keyword(keywords::Extern) ||
+                self.token_is_bare_fn_keyword() {
+            // BARE FUNCTION
             self.parse_ty_bare_fn()
-        } else if self.token_is_closure_keyword(self.token) {
+        } else if self.token_is_closure_keyword() ||
+                *self.token == token::BINOP(token::OR) ||
+                *self.token == token::OROR ||
+                *self.token == token::LT ||
+                self.token_is_lifetime(self.token) {
             // CLOSURE
-            let result = self.parse_ty_closure(ast::BorrowedSigil, None);
-            self.obsolete(*self.last_span, ObsoleteBareFnType);
+            //
+            // XXX(pcwalton): Eventually `token::LT` will not unambiguously
+            // introduce a closure, once procs can have lifetime bounds. We
+            // will need to refactor the grammar a little bit at that point.
+
+            let lifetime = self.parse_opt_lifetime();
+            let result = self.parse_ty_closure(None, lifetime);
             result
         } else if self.eat_keyword(keywords::Typeof) {
             // TYPEOF
@@ -1161,12 +1280,12 @@ impl Parser {
         match *self.token {
             token::LIFETIME(*) => {
                 let lifetime = self.parse_lifetime();
-                return self.parse_ty_closure(sigil, Some(lifetime));
+                return self.parse_ty_closure(Some(sigil), Some(lifetime));
             }
 
             token::IDENT(*) => {
-                if self.token_is_closure_keyword(self.token) {
-                    return self.parse_ty_closure(sigil, None);
+                if self.token_is_old_style_closure_keyword() {
+                    return self.parse_ty_closure(Some(sigil), None);
                 }
             }
             _ => {}
@@ -1187,8 +1306,8 @@ impl Parser {
         // look for `&'lt` or `&'foo ` and interpret `foo` as the region name:
         let opt_lifetime = self.parse_opt_lifetime();
 
-        if self.token_is_closure_keyword(self.token) {
-            return self.parse_ty_closure(BorrowedSigil, opt_lifetime);
+        if self.token_is_old_style_closure_keyword() {
+            return self.parse_ty_closure(Some(BorrowedSigil), opt_lifetime);
         }
 
         let mt = self.parse_mt();
@@ -4390,8 +4509,13 @@ impl Parser {
         }
     }
 
-    // parse a string as an ABI spec on an extern type or module
+    // Parses a string as an ABI spec on an extern type or module. Consumes
+    // the `extern` keyword, if one is found.
     fn parse_opt_abis(&self) -> Option<AbiSet> {
+        if !self.eat_keyword(keywords::Extern) {
+            return None
+        }
+
         match *self.token {
             token::LIT_STR(s)
             | token::LIT_STR_RAW(s, _) => {
@@ -4467,7 +4591,7 @@ impl Parser {
             });
         }
         // either a view item or an item:
-        if self.eat_keyword(keywords::Extern) {
+        if self.is_keyword(keywords::Extern) {
             let opt_abis = self.parse_opt_abis();
 
             if self.eat_keyword(keywords::Fn) {
diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs
index 33bdcdd1b03..0eb1045efe9 100644
--- a/src/libsyntax/print/pprust.rs
+++ b/src/libsyntax/print/pprust.rs
@@ -2015,20 +2015,39 @@ pub fn print_ty_fn(s: @ps,
     // function prints the sigil in the wrong place.  That should be fixed.
     if opt_sigil == Some(ast::OwnedSigil) && onceness == ast::Once {
         word(s.s, "proc");
-    } else {
+    } else if opt_sigil == Some(ast::BorrowedSigil) {
         print_extern_opt_abis(s, opt_abis);
+        for lifetime in opt_region.iter() {
+            print_lifetime(s, lifetime);
+        }
+        print_purity(s, purity);
+        print_onceness(s, onceness);
+    } else {
+        print_opt_abis_and_extern_if_nondefault(s, opt_abis);
         print_opt_sigil(s, opt_sigil);
         print_opt_lifetime(s, opt_region);
         print_purity(s, purity);
         print_onceness(s, onceness);
         word(s.s, "fn");
     }
+
     match id { Some(id) => { word(s.s, " "); print_ident(s, id); } _ => () }
-    do opt_bounds.as_ref().map |bounds| { print_bounds(s, bounds, true); };
+
+    if opt_sigil != Some(ast::BorrowedSigil) {
+        do opt_bounds.as_ref().map |bounds| {
+            print_bounds(s, bounds, true);
+        };
+    }
+
     match generics { Some(g) => print_generics(s, g), _ => () }
     zerobreak(s.s);
 
-    popen(s);
+    if opt_sigil == Some(ast::BorrowedSigil) {
+        word(s.s, "|");
+    } else {
+        popen(s);
+    }
+
     // It is unfortunate to duplicate the commasep logic, but we want the
     // self type and the args all in the same box.
     box(s, 0u, inconsistent);
@@ -2041,7 +2060,14 @@ pub fn print_ty_fn(s: @ps,
         print_arg(s, arg);
     }
     end(s);
-    pclose(s);
+
+    if opt_sigil == Some(ast::BorrowedSigil) {
+        word(s.s, "|");
+
+        opt_bounds.as_ref().map(|bounds| print_bounds(s, bounds, true));
+    } else {
+        pclose(s);
+    }
 
     maybe_print_comment(s, decl.output.span.lo);
 
@@ -2274,6 +2300,17 @@ pub fn print_opt_purity(s: @ps, opt_purity: Option<ast::purity>) {
     }
 }
 
+pub fn print_opt_abis_and_extern_if_nondefault(s: @ps,
+                                               opt_abis: Option<AbiSet>) {
+    match opt_abis {
+        Some(abis) if !abis.is_rust() => {
+            word_nbsp(s, "extern");
+            word_nbsp(s, abis.to_str());
+        }
+        Some(_) | None => {}
+    };
+}
+
 pub fn print_extern_opt_abis(s: @ps, opt_abis: Option<AbiSet>) {
     match opt_abis {
         Some(abis) => {
diff --git a/src/test/compile-fail/block-coerce-no-2.rs b/src/test/compile-fail/block-coerce-no-2.rs
index 85ef09cc2a6..3e38ce9ab35 100644
--- a/src/test/compile-fail/block-coerce-no-2.rs
+++ b/src/test/compile-fail/block-coerce-no-2.rs
@@ -19,5 +19,5 @@ fn main() {
     }
 
     f(g);
-    //~^ ERROR mismatched types: expected `extern "Rust" fn(extern "Rust" fn(extern "Rust" fn()))`
+    //~^ ERROR mismatched types: expected `fn(fn(fn()))`
 }
diff --git a/src/test/compile-fail/closure-reform-bad.rs b/src/test/compile-fail/closure-reform-bad.rs
new file mode 100644
index 00000000000..3da709942e0
--- /dev/null
+++ b/src/test/compile-fail/closure-reform-bad.rs
@@ -0,0 +1,13 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+fn call_bare(f: fn(&str)) {
+    f("Hello ");
+}
+
+fn main() {
+    let string = "world!";
+    let f: |&str| = |s| println(s + string);
+    call_bare(f)    //~ ERROR mismatched types
+}
+
diff --git a/src/test/pretty/closure-reform-pretty.rs b/src/test/pretty/closure-reform-pretty.rs
new file mode 100644
index 00000000000..5169652a6c0
--- /dev/null
+++ b/src/test/pretty/closure-reform-pretty.rs
@@ -0,0 +1,17 @@
+// Any copyright is dedicated to the Public Domain.
+// http://creativecommons.org/publicdomain/zero/1.0/
+
+// pp-exact
+
+fn call_it(f: proc(~str) -> ~str) { }
+
+fn call_this(f: |&str|: Send) { }
+
+fn call_that(f: <'a>|&'a int, &'a int|: -> int) { }
+
+fn call_extern(f: fn() -> int) { }
+
+fn call_abid_extern(f: extern "C" fn() -> int) { }
+
+pub fn main() { }
+
diff --git a/src/test/pretty/disamb-stmt-expr.rs b/src/test/pretty/disamb-stmt-expr.rs
index f6787fa9c3d..d3d6f1c0e35 100644
--- a/src/test/pretty/disamb-stmt-expr.rs
+++ b/src/test/pretty/disamb-stmt-expr.rs
@@ -14,7 +14,7 @@
 // preserved.  They are needed to disambiguate `{return n+1}; - 0` from
 // `({return n+1}-0)`.
 
-fn id(f: &fn() -> int) -> int { f() }
+fn id(f: || -> int) -> int { f() }
 
 fn wsucc(_n: int) -> int { (do id || { 1 }) - 0 }
 fn main() { }
diff --git a/src/test/pretty/do1.rs b/src/test/pretty/do1.rs
index 751aedb39a3..1fb2359da53 100644
--- a/src/test/pretty/do1.rs
+++ b/src/test/pretty/do1.rs
@@ -10,6 +10,6 @@
 
 // pp-exact
 
-fn f(f: &fn(int)) { f(10) }
+fn f(f: |int|) { f(10) }
 
 fn main() { do f |i| { assert!(i == 10) } }
diff --git a/src/test/pretty/fn-types.rs b/src/test/pretty/fn-types.rs
index b000c9f9137..27e56fb6074 100644
--- a/src/test/pretty/fn-types.rs
+++ b/src/test/pretty/fn-types.rs
@@ -10,7 +10,7 @@
 
 // pp-exact
 
-fn from_foreign_fn(_x: extern "Rust" fn()) { }
-fn from_stack_closure(_x: &fn()) { }
+fn from_foreign_fn(_x: fn()) { }
+fn from_stack_closure(_x: ||) { }
 fn from_unique_closure(_x: ~fn()) { }
 fn main() { }
diff --git a/src/test/run-pass/closure-reform.rs b/src/test/run-pass/closure-reform.rs
index c765ebe9643..18ca64d0f27 100644
--- a/src/test/run-pass/closure-reform.rs
+++ b/src/test/run-pass/closure-reform.rs
@@ -1,11 +1,42 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
+use std::cast;
+
 fn call_it(f: proc(~str) -> ~str) {
     println(f(~"Fred"))
 }
 
+fn call_a_thunk(f: ||) {
+    f();
+}
+
+fn call_this(f: |&str|:Send) {
+    f("Hello!");
+}
+
+fn call_that(f: <'a>|&'a int, &'a int|: -> int) {
+    let (ten, forty_two) = (10, 42);
+    println!("Your lucky number is {}", f(&ten, &forty_two));
+}
+
+fn call_cramped(f:||->uint,g:<'a>||->&'a uint) {
+    let number = f();
+    let other_number = *g();
+    println!("Ticket {} wins an all-expenses-paid trip to Mountain View", number + other_number);
+}
+
+fn call_bare(f: fn(&str)) {
+    f("Hello world!")
+}
+
+fn call_bare_again(f: extern "Rust" fn(&str)) {
+    f("Goodbye world!")
+}
+
 pub fn main() {
+    // Procs
+
     let greeting = ~"Hi ";
     do call_it |s| {
         greeting + s
@@ -23,5 +54,26 @@ pub fn main() {
     call_it(proc(s: ~str) -> ~str {
         greeting + s
     });
+
+    // Closures
+
+    call_a_thunk(|| println("Hello world!"));
+
+    call_this(|s| println(s));
+
+    call_that(|x, y| *x + *y);
+
+    let z = 100;
+    call_that(|x, y| *x + *y - z);
+
+    call_cramped(|| 1, || unsafe {
+        cast::transmute(&100)
+    });
+
+    // External functions
+
+    call_bare(println);
+
+    call_bare_again(println);
 }