]> git.lizzy.rs Git - rust.git/commitdiff
auto merge of #14606 : pcwalton/rust/fn-trait-sugar, r=alexcrichton
authorbors <bors@rust-lang.org>
Tue, 10 Jun 2014 06:41:53 +0000 (23:41 -0700)
committerbors <bors@rust-lang.org>
Tue, 10 Jun 2014 06:41:53 +0000 (23:41 -0700)
r? @alexcrichton

12 files changed:
src/librustc/front/feature_gate.rs
src/librustc/middle/resolve.rs
src/librustc/middle/typeck/astconv.rs
src/librustc/middle/typeck/collect.rs
src/librustc/middle/typeck/infer/error_reporting.rs
src/librustdoc/clean/mod.rs
src/libsyntax/ast.rs
src/libsyntax/fold.rs
src/libsyntax/parse/parser.rs
src/libsyntax/print/pprust.rs
src/libsyntax/visit.rs
src/test/run-pass/fn-trait-sugar.rs [new file with mode: 0644]

index a9b9892c2c9c33a514e3b40d818451fc084dc582..cd472321237624db94cc4ad4b6e4c6776dbb5145 100644 (file)
@@ -57,6 +57,7 @@
     ("linkage", Active),
     ("struct_inherit", Active),
     ("overloaded_calls", Active),
+    ("unboxed_closure_sugar", Active),
 
     ("quad_precision_float", Active),
 
@@ -291,6 +292,11 @@ fn visit_ty(&mut self, t: &ast::Ty, _: ()) {
 
             },
             ast::TyBox(_) => { self.gate_box(t.span); }
+            ast::TyUnboxedFn(_) => {
+                self.gate_feature("unboxed_closure_sugar",
+                                  t.span,
+                                  "unboxed closure trait sugar is experimental");
+            }
             _ => {}
         }
 
index 9bfa0e10aedeff3ba653d0e483356b144c51c8eb..89d37bb98b89af187c4bdfecfce26dfdf7a46d4b 100644 (file)
@@ -3856,14 +3856,20 @@ fn resolve_type_parameters(&mut self,
     }
 
     fn resolve_type_parameter_bound(&mut self,
-                                        id: NodeId,
-                                        type_parameter_bound: &TyParamBound) {
+                                    id: NodeId,
+                                    type_parameter_bound: &TyParamBound) {
         match *type_parameter_bound {
             TraitTyParamBound(ref tref) => {
                 self.resolve_trait_reference(id, tref, TraitBoundingTypeParameter)
             }
-            StaticRegionTyParamBound => {}
-            OtherRegionTyParamBound(_) => {}
+            UnboxedFnTyParamBound(ref unboxed_function) => {
+                for argument in unboxed_function.decl.inputs.iter() {
+                    self.resolve_type(argument.ty);
+                }
+
+                self.resolve_type(unboxed_function.decl.output);
+            }
+            StaticRegionTyParamBound | OtherRegionTyParamBound(_) => {}
         }
     }
 
index bdb23aea06708acd655c29132a739bb99b6b31ae..1e6f5fe870be321b74df6f78cf03f976afef45a0 100644 (file)
 
 use middle::const_eval;
 use middle::def;
-use middle::subst;
+use middle::lang_items::FnMutTraitLangItem;
 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::typeck::rscope;
-use middle::typeck::rscope::{RegionScope};
 use middle::typeck::lookup_def_tcx;
+use middle::typeck::rscope::RegionScope;
+use middle::typeck::rscope;
 use util::ppaux::Repr;
 
 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}
 }
 
+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.
 // If a_seq_ty is a str or a vec, make it a str/vec.
 // Also handle first-class trait types.
@@ -491,6 +524,32 @@ fn mk_pointer<AC:AstConv,
             }
             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) => {
             // Note that the "bounds must be empty if path is not a trait"
             // restriction is enforced in the below case for ty_path, which
@@ -528,7 +587,10 @@ fn mk_pointer<AC:AstConv,
                             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,
                                         result.def_id,
                                         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
                 // 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,
                                             ast_ty.id,
@@ -636,7 +701,10 @@ pub fn ast_ty_to_ty<AC:AstConv, RS:RegionScope>(
             ast::TyProc(ref f) => {
                 // Use corresponding trait store to figure out default bounds
                 // 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,
                                             ast_ty.id,
@@ -648,6 +716,11 @@ pub fn ast_ty_to_ty<AC:AstConv, RS:RegionScope>(
                                             None);
                 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) => {
                 let a_def = match tcx.def_map.borrow().find(&id) {
                     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)
                        -> ty::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 => {
                         builtin_bounds.add(ty::BoundStatic);
                     }
+                    ast::UnboxedFnTyParamBound(_) => {
+                        tcx.sess.span_err(span,
+                                          "unboxed functions are not allowed \
+                                           here");
+                    }
                     ast::OtherRegionTyParamBound(span) => {
                         if !tcx.sess.features.issue_5723_bootstrap.get() {
                             tcx.sess.span_err(
index c6bc6ce72974052cc40b7143650ad0e8efa98547..edb7f589e952305bee2428335c1efbb3e510f5d3 100644 (file)
 use util::ppaux;
 use util::ppaux::Repr;
 
-use std::rc::Rc;
 use std::collections::{HashMap, HashSet};
-
+use std::rc::Rc;
 use syntax::abi;
-use syntax::ast::{StaticRegionTyParamBound, OtherRegionTyParamBound,
-                  TraitTyParamBound};
+use syntax::ast::{StaticRegionTyParamBound, OtherRegionTyParamBound};
+use syntax::ast::{TraitTyParamBound, UnboxedFnTyParamBound};
 use syntax::ast;
 use syntax::ast_map;
 use syntax::ast_util::{local_def, split_trait_methods};
 use syntax::codemap::Span;
 use syntax::codemap;
+use syntax::owned_slice::OwnedSlice;
 use syntax::parse::token::special_idents;
 use syntax::parse::token;
 use syntax::print::pprust::{path_to_str};
 use syntax::visit;
-use syntax::owned_slice::OwnedSlice;
 
 struct CollectItemTypesVisitor<'a> {
     ccx: &'a CrateCtxt<'a>
@@ -1114,6 +1113,20 @@ fn compute_bounds(
                     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) => {
                     if !ccx.tcx.sess.features.issue_5723_bootstrap.get() {
                         ccx.tcx.sess.span_err(
index 6464b191b76911b431cdabbb970ef4af4d9ae57f..8f53c0a7530516a778af8878bd86564d9c69272b 100644 (file)
@@ -909,6 +909,9 @@ fn rebuild_ty_param_bounds(&self,
             match tpb {
                 &ast::StaticRegionTyParamBound => ast::StaticRegionTyParamBound,
                 &ast::OtherRegionTyParamBound(s) => ast::OtherRegionTyParamBound(s),
+                &ast::UnboxedFnTyParamBound(unboxed_function_type) => {
+                    ast::UnboxedFnTyParamBound(unboxed_function_type)
+                }
                 &ast::TraitTyParamBound(ref tr) => {
                     let last_seg = tr.path.segments.last().unwrap();
                     let mut insert = Vec::new();
index 650cd749af69e1e8d949f0bc2139887f3d3036f1..54128fda6c6a5fc95b2e7182eba07119b5a8f5dc 100644 (file)
@@ -477,6 +477,10 @@ fn clean(&self) -> TyParamBound {
         match *self {
             ast::StaticRegionTyParamBound => RegionBound,
             ast::OtherRegionTyParamBound(_) => RegionBound,
+            ast::UnboxedFnTyParamBound(_) => {
+                // FIXME(pcwalton): Wrong.
+                RegionBound
+            }
             ast::TraitTyParamBound(ref t) => TraitBound(t.clean()),
         }
     }
index 2bc24fd1eb36994fa3801ed3cbfc6b6ebea0b044..9c3960d0f0622328299856e3363b5c4e878be690 100644 (file)
@@ -175,6 +175,7 @@ pub struct DefId {
 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),
index 8903eb80829b4d7efd61bf0b48401d8a797470bb..03d0c283bcc5c522a81027e61cb6592fe9ad5707 100644 (file)
@@ -185,6 +185,11 @@ fn fold_ty(&mut self, t: P<Ty>) -> P<Ty> {
                     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)
     }
 }
index 4af4385e3c1da3bc05ef14ab47f02b5574155079..360b8daa948f3647d54bede0d22f5db24f70e571 100644 (file)
@@ -52,9 +52,9 @@
 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 @@ pub fn parse_ty_closure(&mut self) -> Ty_ {
             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 @@ pub fn parse_ty_closure(&mut self) -> Ty_ {
             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 @@ fn parse_block_tail_(&mut self, lo: BytePos, s: BlockCheckMode,
         })
     }
 
+    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 @@ fn parse_optional_ty_param_bounds(&mut self, allow_any_lifetime: bool)
                     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,
             }
 
index 05c2558da486f80a45d909b39b4172df68c19f87..f22b24b5a29dd66aa97216ea9f145e9753224407 100644 (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 @@ pub fn print_type(&mut self, ty: &ast::Ty) -> IoResult<()> {
                     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 @@ pub fn print_ty_method(&mut self, m: &ast::TypeMethod) -> IoResult<()> {
                               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 @@ pub fn print_bounds(&mut self,
                 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 @@ pub fn print_ty_fn(&mut self,
                        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 @@ pub fn print_ty_fn(&mut self,
             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 @@ pub fn print_ty_fn(&mut self,
         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 {
index 906f0c16f396478e0b904bc496962bf048a1c03d..b5ae8a3dea0e9e8aa98914ec6d955ccf23c8a269 100644 (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(..) => {}
         }
     }
diff --git a/src/test/run-pass/fn-trait-sugar.rs b/src/test/run-pass/fn-trait-sugar.rs
new file mode 100644 (file)
index 0000000..b0c8d84
--- /dev/null
@@ -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);
+}
+