diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index a325b8c634a5..9bd6a5ccf7d4 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), diff --git a/src/libsyntax/ext/auto_serialize.rs b/src/libsyntax/ext/auto_serialize.rs index 2f44204c3a5b..346b1cf5b599 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 57cebbf044af..7f2c2509f810 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 41b8b8f27d45..5b889b4ad966 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 9d7731e8441b..b31e63a9f684 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, + bounds: @~[ast::ty_param_bound], decl: ast::fn_decl, id: option, 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 c988c89f8c2a..08572e83f6e7 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -195,8 +195,9 @@ fn visit_ty(t: @ty, e: E, v: vt) { 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(ni: @foreign_item, e: E, v: vt) { } } +fn visit_ty_param_bounds(bounds: @~[ty_param_bound], e: E, v: vt) { + 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(tps: ~[ty_param], e: E, v: vt) { 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 a834147af961..e66d0cef71ba 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 458dc149802c..9e67157b1811 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 2f090cdab7c3..16c08641e17a 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::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::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 1555f2df89ae..27f7c8c01833 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 814e0cc2f157..91eb030ec039 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 e96fe4e86794..c91607bc9d14 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 fffc70e95259..c9008bc13891 100644 --- a/src/rustc/middle/typeck/astconv.rs +++ b/src/rustc/middle/typeck/astconv.rs @@ -261,8 +261,10 @@ fn ast_ty_to_ty( }; 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( 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( _ => 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 efe728f9e127..2c6be53601c5 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 c1211d79a7e4..ce41330d25d7 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 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] { - 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"); - ~[] - } - } - } - } - } - } @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 8c9cbc075987..42291ea30c71 100644 --- a/src/rustc/middle/typeck/infer.rs +++ b/src/rustc/middle/typeck/infer.rs @@ -1717,6 +1717,7 @@ fn super_fns( // 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 000000000000..b21050f4d43e --- /dev/null +++ b/src/test/run-pass/bounded-fn-type.rs @@ -0,0 +1,7 @@ +fn ignore(_x: T) {} + +fn main() { + let f: fn@:send() = ||(); + ignore(f); +} +