about summary refs log tree commit diff
diff options
context:
space:
mode:
authorPatrick Walton <pcwalton@mimiga.net>2012-08-06 18:54:20 -0700
committerPatrick Walton <pcwalton@mimiga.net>2012-08-06 18:55:24 -0700
commit60f47eabe2ef2730b98713dee2b5fd59513e8c6c (patch)
treecf491427dd1bfac38de4fd93d934702db9669fda
parentc0f7ed68e235b61a2e9710864a2283f554bb470d (diff)
downloadrust-60f47eabe2ef2730b98713dee2b5fd59513e8c6c.tar.gz
rust-60f47eabe2ef2730b98713dee2b5fd59513e8c6c.zip
rustc: Parse and stub (broken) typechecking for bounded function types
-rw-r--r--src/libsyntax/ast.rs2
-rw-r--r--src/libsyntax/ext/auto_serialize.rs14
-rw-r--r--src/libsyntax/fold.rs5
-rw-r--r--src/libsyntax/parse/parser.rs37
-rw-r--r--src/libsyntax/print/pprust.rs8
-rw-r--r--src/libsyntax/visit.rs19
-rw-r--r--src/rustc/metadata/tydecode.rs5
-rw-r--r--src/rustc/metadata/tyencode.rs1
-rw-r--r--src/rustc/middle/trans/base.rs2
-rw-r--r--src/rustc/middle/trans/foreign.rs1
-rw-r--r--src/rustc/middle/ty.rs4
-rw-r--r--src/rustc/middle/typeck.rs2
-rw-r--r--src/rustc/middle/typeck/astconv.rs9
-rw-r--r--src/rustc/middle/typeck/check.rs4
-rw-r--r--src/rustc/middle/typeck/collect.rs66
-rw-r--r--src/rustc/middle/typeck/infer.rs1
-rw-r--r--src/test/run-pass/bounded-fn-type.rs7
17 files changed, 117 insertions, 70 deletions
diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs
index a325b8c634a..9bd6a5ccf7d 100644
--- a/src/libsyntax/ast.rs
+++ b/src/libsyntax/ast.rs
@@ -558,7 +558,7 @@ enum ty_ {
     ty_ptr(mt),
     ty_rptr(@region, mt),
     ty_rec(~[ty_field]),
-    ty_fn(proto, fn_decl),
+    ty_fn(proto, @~[ty_param_bound], fn_decl),
     ty_tup(~[@ty]),
     ty_path(@path, node_id),
     ty_fixed_length(@ty, option<uint>),
diff --git a/src/libsyntax/ext/auto_serialize.rs b/src/libsyntax/ext/auto_serialize.rs
index 2f44204c3a5..346b1cf5b59 100644
--- a/src/libsyntax/ext/auto_serialize.rs
+++ b/src/libsyntax/ext/auto_serialize.rs
@@ -186,10 +186,12 @@ impl helpers of ext_ctxt_helpers for ext_ctxt {
         };
 
         @{id: self.next_id(),
-          node: ast::ty_fn(ast::proto_block, {inputs: args,
-                                              output: output,
-                                              purity: ast::impure_fn,
-                                              cf: ast::return_val}),
+          node: ast::ty_fn(ast::proto_block,
+                           @~[],
+                           {inputs: args,
+                            output: output,
+                            purity: ast::impure_fn,
+                            cf: ast::return_val}),
           span: span}
     }
 
@@ -441,7 +443,7 @@ fn ser_ty(cx: ext_ctxt, tps: ser_tps_map,
         ~[#ast[stmt]{$(s).emit_rec($(fld_lambda));}]
       }
 
-      ast::ty_fn(_, _) => {
+      ast::ty_fn(*) => {
         cx.span_err(ty.span, ~"cannot serialize function types");
         ~[]
       }
@@ -681,7 +683,7 @@ fn deser_ty(cx: ext_ctxt, tps: deser_tps_map,
         #ast{ $(d).read_rec($(fld_lambda)) }
       }
 
-      ast::ty_fn(_, _) => {
+      ast::ty_fn(*) => {
         #ast{ fail }
       }
 
diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs
index 57cebbf044a..7f2c2509f81 100644
--- a/src/libsyntax/fold.rs
+++ b/src/libsyntax/fold.rs
@@ -514,7 +514,10 @@ fn noop_fold_ty(t: ty_, fld: ast_fold) -> ty_ {
       ty_ptr(mt) => ty_ptr(fold_mt(mt, fld)),
       ty_rptr(region, mt) => ty_rptr(region, fold_mt(mt, fld)),
       ty_rec(fields) => ty_rec(vec::map(fields, |f| fold_field(f, fld))),
-      ty_fn(proto, decl) => ty_fn(proto, fold_fn_decl(decl, fld)),
+      ty_fn(proto, bounds, decl) =>
+        ty_fn(proto, @vec::map(*bounds,
+                               |x| fold_ty_param_bound(x, fld)),
+                               fold_fn_decl(decl, fld)),
       ty_tup(tys) => ty_tup(vec::map(tys, |ty| fld.fold_ty(ty))),
       ty_path(path, id) => ty_path(fld.fold_path(path), fld.new_id(id)),
       ty_fixed_length(t, vs) => ty_fixed_length(fld.fold_ty(t), vs),
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index 41b8b8f27d4..5b889b4ad96 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -50,10 +50,10 @@ import ast::{_mod, add, alt_check, alt_exhaustive, arg, arm, attribute,
              stmt_semi, subtract, sty_box, sty_by_ref, sty_region, sty_uniq,
              sty_value, token_tree, trait_method, trait_ref, tt_delim, tt_seq,
              tt_tok, tt_nonterminal, ty, ty_, ty_bot, ty_box, ty_field, ty_fn,
-             ty_infer, ty_mac, ty_method, ty_nil, ty_param, ty_path, ty_ptr,
-             ty_rec, ty_rptr, ty_tup, ty_u32, ty_uniq, ty_vec,
-             ty_fixed_length, unchecked_blk, uniq, unsafe_blk, unsafe_fn,
-             variant, view_item, view_item_, view_item_export,
+             ty_infer, ty_mac, ty_method, ty_nil, ty_param, ty_param_bound,
+             ty_path, ty_ptr, ty_rec, ty_rptr, ty_tup, ty_u32, ty_uniq,
+             ty_vec, ty_fixed_length, unchecked_blk, uniq, unsafe_blk,
+             unsafe_fn, variant, view_item, view_item_, view_item_export,
              view_item_import, view_item_use, view_path, view_path_glob,
              view_path_list, view_path_simple, visibility, vstore, vstore_box,
              vstore_fixed, vstore_slice, vstore_uniq};
@@ -240,14 +240,17 @@ class parser {
     fn get_id() -> node_id { next_node_id(self.sess) }
 
     fn parse_ty_fn(purity: ast::purity) -> ty_ {
-        let proto = if self.eat_keyword(~"extern") {
+        let proto, bounds;
+        if self.eat_keyword(~"extern") {
             self.expect_keyword(~"fn");
-            ast::proto_bare
+            proto = ast::proto_bare;
+            bounds = @~[];
         } else {
             self.expect_keyword(~"fn");
-            self.parse_fn_ty_proto()
+            proto = self.parse_fn_ty_proto();
+            bounds = self.parse_optional_ty_param_bounds();
         };
-        ty_fn(proto, self.parse_ty_fn_decl(purity))
+        ty_fn(proto, bounds, self.parse_ty_fn_decl(purity))
     }
 
     fn parse_ty_fn_decl(purity: ast::purity) -> fn_decl {
@@ -467,7 +470,7 @@ class parser {
             self.parse_ty_fn(ast::impure_fn)
         } else if self.eat_keyword(~"extern") {
             self.expect_keyword(~"fn");
-            ty_fn(proto_bare, self.parse_ty_fn_decl(ast::impure_fn))
+            ty_fn(proto_bare, @~[], self.parse_ty_fn_decl(ast::impure_fn))
         } else if self.token == token::MOD_SEP || is_ident(self.token) {
             let path = self.parse_path_with_tps(colons_before_params);
             ty_path(path, self.get_id())
@@ -2125,11 +2128,10 @@ class parser {
         return spanned(lo, hi, bloc);
     }
 
-    fn parse_ty_param() -> ty_param {
+    fn parse_optional_ty_param_bounds() -> @~[ty_param_bound] {
         let mut bounds = ~[];
-        let ident = self.parse_ident();
         if self.eat(token::COLON) {
-            while self.token != token::COMMA && self.token != token::GT {
+            while is_ident(self.token) {
                 if self.eat_keyword(~"send") {
                     push(bounds, bound_send); }
                 else if self.eat_keyword(~"copy") {
@@ -2139,10 +2141,17 @@ class parser {
                 } else if self.eat_keyword(~"owned") {
                     push(bounds, bound_owned);
                 } else {
-                    push(bounds, bound_trait(self.parse_ty(false))); }
+                    push(bounds, bound_trait(self.parse_ty(false)));
+                }
             }
         }
-        return {ident: ident, id: self.get_id(), bounds: @bounds};
+        return @move bounds;
+    }
+
+    fn parse_ty_param() -> ty_param {
+        let ident = self.parse_ident();
+        let bounds = self.parse_optional_ty_param_bounds();
+        return {ident: ident, id: self.get_id(), bounds: bounds};
     }
 
     fn parse_ty_params() -> ~[ty_param] {
diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs
index 9d7731e8441..b31e63a9f68 100644
--- a/src/libsyntax/print/pprust.rs
+++ b/src/libsyntax/print/pprust.rs
@@ -399,8 +399,8 @@ fn print_type_ex(s: ps, &&ty: @ast::ty, print_colons: bool) {
         commasep(s, inconsistent, elts, print_type);
         pclose(s);
       }
-      ast::ty_fn(proto, d) => {
-        print_ty_fn(s, some(proto), d, none, none);
+      ast::ty_fn(proto, bounds, d) => {
+        print_ty_fn(s, some(proto), bounds, d, none, none);
       }
       ast::ty_path(path, _) => print_path(s, path, print_colons),
       ast::ty_fixed_length(t, v) => {
@@ -702,7 +702,7 @@ fn print_ty_method(s: ps, m: ast::ty_method) {
     hardbreak_if_not_bol(s);
     maybe_print_comment(s, m.span.lo);
     print_outer_attributes(s, m.attrs);
-    print_ty_fn(s, none, m.decl, some(m.ident), some(m.tps));
+    print_ty_fn(s, none, @~[], m.decl, some(m.ident), some(m.tps));
     word(s.s, ~";");
 }
 
@@ -1645,10 +1645,12 @@ fn print_arg(s: ps, input: ast::arg) {
 }
 
 fn print_ty_fn(s: ps, opt_proto: option<ast::proto>,
+               bounds: @~[ast::ty_param_bound],
                decl: ast::fn_decl, id: option<ast::ident>,
                tps: option<~[ast::ty_param]>) {
     ibox(s, indent_unit);
     word(s.s, opt_proto_to_str(opt_proto));
+    print_bounds(s, bounds);
     match id { some(id) => { word(s.s, ~" "); word(s.s, *id); } _ => () }
     match tps { some(tps) => print_type_params(s, tps), _ => () }
     zerobreak(s.s);
diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs
index c988c89f8c2..08572e83f6e 100644
--- a/src/libsyntax/visit.rs
+++ b/src/libsyntax/visit.rs
@@ -195,8 +195,9 @@ fn visit_ty<E>(t: @ty, e: E, v: vt<E>) {
       ty_tup(ts) => for ts.each |tt| {
         v.visit_ty(tt, e, v);
       }
-      ty_fn(_, decl) => {
+      ty_fn(_, bounds, decl) => {
         for decl.inputs.each |a| { v.visit_ty(a.ty, e, v); }
+        visit_ty_param_bounds(bounds, e, v);
         v.visit_ty(decl.output, e, v);
       }
       ty_path(p, _) => visit_path(p, e, v),
@@ -251,14 +252,18 @@ fn visit_foreign_item<E>(ni: @foreign_item, e: E, v: vt<E>) {
     }
 }
 
+fn visit_ty_param_bounds<E>(bounds: @~[ty_param_bound], e: E, v: vt<E>) {
+    for vec::each(*bounds) |bound| {
+        match bound {
+          bound_trait(t) => v.visit_ty(t, e, v),
+          bound_copy | bound_send | bound_const | bound_owned => ()
+        }
+    }
+}
+
 fn visit_ty_params<E>(tps: ~[ty_param], e: E, v: vt<E>) {
     for tps.each |tp| {
-        for vec::each(*tp.bounds) |bound| {
-            match bound {
-              bound_trait(t) => v.visit_ty(t, e, v),
-              bound_copy | bound_send | bound_const | bound_owned => ()
-            }
-        }
+        visit_ty_param_bounds(tp.bounds, e, v);
     }
 }
 
diff --git a/src/rustc/metadata/tydecode.rs b/src/rustc/metadata/tydecode.rs
index a834147af96..e66d0cef71b 100644
--- a/src/rustc/metadata/tydecode.rs
+++ b/src/rustc/metadata/tydecode.rs
@@ -362,6 +362,7 @@ fn parse_purity(c: char) -> purity {
 fn parse_ty_fn(st: @pstate, conv: conv_did) -> ty::fn_ty {
     let proto = parse_proto(next(st));
     let purity = parse_purity(next(st));
+    let bounds = parse_bounds(st, conv);
     assert (next(st) == '[');
     let mut inputs: ~[ty::arg] = ~[];
     while peek(st) != ']' {
@@ -377,8 +378,8 @@ fn parse_ty_fn(st: @pstate, conv: conv_did) -> ty::fn_ty {
     }
     st.pos += 1u; // eat the ']'
     let (ret_style, ret_ty) = parse_ret_ty(st, conv);
-    return {purity: purity, proto: proto, inputs: inputs, output: ret_ty,
-         ret_style: ret_style};
+    return {purity: purity, proto: proto, bounds: bounds, inputs: inputs,
+            output: ret_ty, ret_style: ret_style};
 }
 
 
diff --git a/src/rustc/metadata/tyencode.rs b/src/rustc/metadata/tyencode.rs
index 458dc149802..9e67157b181 100644
--- a/src/rustc/metadata/tyencode.rs
+++ b/src/rustc/metadata/tyencode.rs
@@ -337,6 +337,7 @@ fn enc_purity(w: io::writer, p: purity) {
 fn enc_ty_fn(w: io::writer, cx: @ctxt, ft: ty::fn_ty) {
     enc_proto(w, ft.proto);
     enc_purity(w, ft.purity);
+    enc_bounds(w, cx, ft.bounds);
     w.write_char('[');
     for ft.inputs.each |arg| {
         enc_mode(w, cx, arg.mode);
diff --git a/src/rustc/middle/trans/base.rs b/src/rustc/middle/trans/base.rs
index 2f090cdab7c..16c08641e17 100644
--- a/src/rustc/middle/trans/base.rs
+++ b/src/rustc/middle/trans/base.rs
@@ -1982,6 +1982,7 @@ fn normalize_for_monomorphization(tcx: ty::ctxt, ty: ty::t) -> option<ty::t> {
       ty::ty_fn(fty) => {
         some(ty::mk_fn(tcx, {purity: ast::impure_fn,
                              proto: fty.proto,
+                             bounds: @~[],
                              inputs: ~[],
                              output: ty::mk_nil(tcx),
                              ret_style: ast::return_val}))
@@ -1989,6 +1990,7 @@ fn normalize_for_monomorphization(tcx: ty::ctxt, ty: ty::t) -> option<ty::t> {
       ty::ty_trait(_, _) => {
         some(ty::mk_fn(tcx, {purity: ast::impure_fn,
                              proto: ast::proto_box,
+                             bounds: @~[],
                              inputs: ~[],
                              output: ty::mk_nil(tcx),
                              ret_style: ast::return_val}))
diff --git a/src/rustc/middle/trans/foreign.rs b/src/rustc/middle/trans/foreign.rs
index 1555f2df89a..27f7c8c0183 100644
--- a/src/rustc/middle/trans/foreign.rs
+++ b/src/rustc/middle/trans/foreign.rs
@@ -961,6 +961,7 @@ fn trans_intrinsic(ccx: @crate_ctxt, decl: ValueRef, item: @ast::foreign_item,
         let fty = ty::mk_fn(bcx.tcx(), {
             purity: ast::impure_fn,
             proto: ast::proto_block,
+            bounds: @~[],
             inputs: ~[{
                 mode: ast::expl(ast::by_val),
                 ty: ty::mk_imm_ptr(
diff --git a/src/rustc/middle/ty.rs b/src/rustc/middle/ty.rs
index 814e0cc2f15..91eb030ec03 100644
--- a/src/rustc/middle/ty.rs
+++ b/src/rustc/middle/ty.rs
@@ -316,11 +316,13 @@ enum closure_kind {
 ///
 /// - `purity` is the function's effect (pure, impure, unsafe).
 /// - `proto` is the protocol (fn@, fn~, etc).
+/// - `bound` is the parameter bounds on the function's upvars.
 /// - `inputs` is the list of arguments and their modes.
 /// - `output` is the return type.
-/// - `ret_style`indicates whether the function returns a value or fails.
+/// - `ret_style` indicates whether the function returns a value or fails.
 type fn_ty = {purity: ast::purity,
               proto: ast::proto,
+              bounds: @~[param_bound],
               inputs: ~[arg],
               output: t,
               ret_style: ret_style};
diff --git a/src/rustc/middle/typeck.rs b/src/rustc/middle/typeck.rs
index e96fe4e8679..c91607bc9d1 100644
--- a/src/rustc/middle/typeck.rs
+++ b/src/rustc/middle/typeck.rs
@@ -246,7 +246,7 @@ fn check_main_fn_ty(ccx: @crate_ctxt,
     let tcx = ccx.tcx;
     let main_t = ty::node_id_to_type(tcx, main_id);
     match ty::get(main_t).struct {
-      ty::ty_fn({purity: ast::impure_fn, proto: ast::proto_bare,
+      ty::ty_fn({purity: ast::impure_fn, proto: ast::proto_bare, bounds,
                  inputs, output, ret_style: ast::return_val}) => {
         match tcx.items.find(main_id) {
          some(ast_map::node_item(it,_)) => {
diff --git a/src/rustc/middle/typeck/astconv.rs b/src/rustc/middle/typeck/astconv.rs
index fffc70e9525..c9008bc1389 100644
--- a/src/rustc/middle/typeck/astconv.rs
+++ b/src/rustc/middle/typeck/astconv.rs
@@ -261,8 +261,10 @@ fn ast_ty_to_ty<AC: ast_conv, RS: region_scope copy owned>(
         };
         ty::mk_rec(tcx, flds)
       }
-      ast::ty_fn(proto, decl) => {
-        ty::mk_fn(tcx, ty_of_fn_decl(self, rscope, proto, decl, none))
+      ast::ty_fn(proto, ast_bounds, decl) => {
+        let bounds = collect::compute_bounds(self.ccx(), ast_bounds);
+        let fn_decl = ty_of_fn_decl(self, rscope, proto, bounds, decl, none);
+        ty::mk_fn(tcx, fn_decl)
       }
       ast::ty_path(path, id) => {
         let a_def = match tcx.def_map.find(id) {
@@ -398,6 +400,7 @@ type expected_tys = option<{inputs: ~[ty::arg],
 fn ty_of_fn_decl<AC: ast_conv, RS: region_scope copy owned>(
     self: AC, rscope: RS,
     proto: ast::proto,
+    bounds: @~[ty::param_bound],
     decl: ast::fn_decl,
     expected_tys: expected_tys) -> ty::fn_ty {
 
@@ -423,7 +426,7 @@ fn ty_of_fn_decl<AC: ast_conv, RS: region_scope copy owned>(
           _ => ast_ty_to_ty(self, rb, decl.output)
         };
 
-        {purity: decl.purity, proto: proto, inputs: input_tys,
+        {purity: decl.purity, proto: proto, bounds: bounds, inputs: input_tys,
          output: output_ty, ret_style: decl.cf}
     }
 }
diff --git a/src/rustc/middle/typeck/check.rs b/src/rustc/middle/typeck/check.rs
index efe728f9e12..2c6be53601c 100644
--- a/src/rustc/middle/typeck/check.rs
+++ b/src/rustc/middle/typeck/check.rs
@@ -1135,7 +1135,7 @@ fn check_expr_with_unifier(fcx: @fn_ctxt,
         };
 
         // construct the function type
-        let fn_ty = astconv::ty_of_fn_decl(fcx, fcx, proto,
+        let fn_ty = astconv::ty_of_fn_decl(fcx, fcx, proto, @~[],
                                            decl, expected_tys);
         let fty = ty::mk_fn(tcx, fn_ty);
 
@@ -2401,6 +2401,7 @@ fn check_intrinsic_type(ccx: @crate_ctxt, it: @ast::foreign_item) {
         let fty = ty::mk_fn(ccx.tcx, {
             purity: ast::impure_fn,
             proto: ast::proto_block,
+            bounds: @~[],
             inputs: ~[{
                 mode: ast::expl(ast::by_val),
                 ty: ty::mk_imm_ptr(
@@ -2420,6 +2421,7 @@ fn check_intrinsic_type(ccx: @crate_ctxt, it: @ast::foreign_item) {
     };
     let fty = ty::mk_fn(tcx, {purity: ast::impure_fn,
                               proto: ast::proto_bare,
+                              bounds: @~[],
                               inputs: inputs, output: output,
                               ret_style: ast::return_val});
     let i_ty = ty::lookup_item_type(ccx.tcx, local_def(it.id));
diff --git a/src/rustc/middle/typeck/collect.rs b/src/rustc/middle/typeck/collect.rs
index c1211d79a7e..ce41330d25d 100644
--- a/src/rustc/middle/typeck/collect.rs
+++ b/src/rustc/middle/typeck/collect.rs
@@ -125,6 +125,7 @@ fn get_enum_variant_types(ccx: @crate_ctxt,
             });
             ty::mk_fn(tcx, {purity: ast::pure_fn,
                             proto: ast::proto_box,
+                            bounds: @~[],
                             inputs: args,
                             output: enum_ty,
                             ret_style: ast::return_val})
@@ -396,6 +397,7 @@ fn convert(ccx: @crate_ctxt, it: @ast::item) {
             let t_ctor = ty::mk_fn(
                 tcx, {purity: ast::impure_fn,
                       proto: ast::proto_block,
+                      bounds: @~[],
                       inputs: t_args,
                       output: t_res,
                       ret_style: ast::return_val});
@@ -410,7 +412,7 @@ fn convert(ccx: @crate_ctxt, it: @ast::item) {
             // Write the dtor type
             let t_dtor = ty::mk_fn(
                 tcx,
-                ty_of_fn_decl(ccx, type_rscope(rp), ast::proto_block,
+                ty_of_fn_decl(ccx, type_rscope(rp), ast::proto_block, @~[],
                               ast_util::dtor_dec(), none));
             write_ty_to_tcx(tcx, dtor.node.id, t_dtor);
             tcx.tcache.insert(local_def(dtor.node.id),
@@ -460,9 +462,10 @@ fn convert_foreign(ccx: @crate_ctxt, i: @ast::foreign_item) {
 fn ty_of_method(ccx: @crate_ctxt,
                 m: @ast::method,
                 rp: bool) -> ty::method {
+    // XXX: Are the bounds correct here?
     {ident: m.ident,
      tps: ty_param_bounds(ccx, m.tps),
-     fty: ty_of_fn_decl(ccx, type_rscope(rp), ast::proto_bare,
+     fty: ty_of_fn_decl(ccx, type_rscope(rp), ast::proto_bare, @~[],
                         m.decl, none),
      self_ty: m.self_ty.node,
      purity: m.decl.purity,
@@ -474,8 +477,8 @@ fn ty_of_ty_method(self: @crate_ctxt,
                    rp: bool) -> ty::method {
     {ident: m.ident,
      tps: ty_param_bounds(self, m.tps),
-     fty: ty_of_fn_decl(self, type_rscope(rp), ast::proto_bare,
-                                 m.decl, none),
+     fty: ty_of_fn_decl(self, type_rscope(rp), ast::proto_bare, @~[], m.decl,
+                        none),
      // assume public, because this is only invoked on trait methods
      self_ty: m.self_ty.node,
      purity: m.decl.purity, vis: ast::public}
@@ -528,8 +531,8 @@ fn ty_of_item(ccx: @crate_ctxt, it: @ast::item)
       }
       ast::item_fn(decl, tps, _) => {
         let bounds = ty_param_bounds(ccx, tps);
-        let tofd = ty_of_fn_decl(ccx, empty_rscope, ast::proto_bare,
-                                          decl, none);
+        let tofd = ty_of_fn_decl(ccx, empty_rscope, ast::proto_bare, @~[],
+                                 decl, none);
         let tpt = {bounds: bounds,
                    rp: false, // functions do not have a self
                    ty: ty::mk_fn(ccx.tcx, tofd)};
@@ -599,40 +602,42 @@ fn ty_of_foreign_item(ccx: @crate_ctxt, it: @ast::foreign_item)
       }
     }
 }
-fn ty_param_bounds(ccx: @crate_ctxt,
-                   params: ~[ast::ty_param]) -> @~[ty::param_bounds] {
 
-    fn compute_bounds(ccx: @crate_ctxt,
-                      param: ast::ty_param) -> ty::param_bounds {
-        @do vec::flat_map(*param.bounds) |b| {
-            match b {
-              ast::bound_send => ~[ty::bound_send],
-              ast::bound_copy => ~[ty::bound_copy],
-              ast::bound_const => ~[ty::bound_const],
-              ast::bound_owned => ~[ty::bound_owned],
-              ast::bound_trait(t) => {
-                let ity = ast_ty_to_ty(ccx, empty_rscope, t);
-                match ty::get(ity).struct {
-                  ty::ty_trait(*) => {
-                    ~[ty::bound_trait(ity)]
-                  }
-                  _ => {
-                    ccx.tcx.sess.span_err(
-                        t.span, ~"type parameter bounds must be \
-                                  trait types");
-                    ~[]
-                  }
-                }
+fn compute_bounds(ccx: @crate_ctxt,
+                  ast_bounds: @~[ast::ty_param_bound]) -> ty::param_bounds {
+    @do vec::flat_map(*ast_bounds) |b| {
+        match b {
+          ast::bound_send => ~[ty::bound_send],
+          ast::bound_copy => ~[ty::bound_copy],
+          ast::bound_const => ~[ty::bound_const],
+          ast::bound_owned => ~[ty::bound_owned],
+          ast::bound_trait(t) => {
+            let ity = ast_ty_to_ty(ccx, empty_rscope, t);
+            match ty::get(ity).struct {
+              ty::ty_trait(*) => {
+                ~[ty::bound_trait(ity)]
+              }
+              _ => {
+                ccx.tcx.sess.span_err(
+                    t.span, ~"type parameter bounds must be \
+                              trait types");
+                ~[]
               }
             }
+          }
         }
     }
+}
+
+fn ty_param_bounds(ccx: @crate_ctxt,
+                   params: ~[ast::ty_param]) -> @~[ty::param_bounds] {
+
 
     @do params.map |param| {
         match ccx.tcx.ty_param_bounds.find(param.id) {
           some(bs) => bs,
           none => {
-            let bounds = compute_bounds(ccx, param);
+            let bounds = compute_bounds(ccx, param.bounds);
             ccx.tcx.ty_param_bounds.insert(param.id, bounds);
             bounds
           }
@@ -652,6 +657,7 @@ fn ty_of_foreign_fn_decl(ccx: @crate_ctxt,
 
     let t_fn = ty::mk_fn(ccx.tcx, {purity: decl.purity,
                                    proto: ast::proto_bare,
+                                   bounds: @~[],
                                    inputs: input_tys,
                                    output: output_ty,
                                    ret_style: ast::return_val});
diff --git a/src/rustc/middle/typeck/infer.rs b/src/rustc/middle/typeck/infer.rs
index 8c9cbc07598..42291ea30c7 100644
--- a/src/rustc/middle/typeck/infer.rs
+++ b/src/rustc/middle/typeck/infer.rs
@@ -1717,6 +1717,7 @@ fn super_fns<C:combine>(
                     //                         b_f.constraints).then {||
                         ok({purity: purity,
                             proto: p,
+                            bounds: a_f.bounds, // XXX: This is wrong!
                             inputs: inputs,
                             output: output,
                             ret_style: rs})
diff --git a/src/test/run-pass/bounded-fn-type.rs b/src/test/run-pass/bounded-fn-type.rs
new file mode 100644
index 00000000000..b21050f4d43
--- /dev/null
+++ b/src/test/run-pass/bounded-fn-type.rs
@@ -0,0 +1,7 @@
+fn ignore<T>(_x: T) {}
+
+fn main() {
+    let f: fn@:send() = ||();
+    ignore(f);
+}
+