diff --git a/src/comp/front/ast.rs b/src/comp/front/ast.rs index 75321f595f44..db625124be45 100644 --- a/src/comp/front/ast.rs +++ b/src/comp/front/ast.rs @@ -307,7 +307,8 @@ type mt = rec(@ty ty, mutability mut); type ty_field = rec(ident ident, mt mt); type ty_arg = rec(mode mode, @ty ty); type ty_method = rec(proto proto, ident ident, - vec[ty_arg] inputs, @ty output); + vec[ty_arg] inputs, @ty output, + controlflow cf); type ty = spanned[ty_]; tag ty_ { ty_nil; @@ -330,7 +331,7 @@ tag ty_ { ty_chan(@ty); ty_tup(vec[mt]); ty_rec(vec[ty_field]); - ty_fn(proto, vec[ty_arg], @ty); + ty_fn(proto, vec[ty_arg], @ty, controlflow); ty_obj(vec[ty_method]); ty_path(path, ann); ty_type; diff --git a/src/comp/front/creader.rs b/src/comp/front/creader.rs index 068c548798f1..da6d3b113163 100644 --- a/src/comp/front/creader.rs +++ b/src/comp/front/creader.rs @@ -13,6 +13,8 @@ import middle::ty; import back::x86; import util::common; import util::common::span; +import util::common::a_bang; +import util::common::a_ty; import std::str; import std::uint; @@ -47,6 +49,8 @@ type str_def = fn(str) -> ast::def_id; type pstate = rec(vec[u8] data, int crate, mutable uint pos, uint len, ty::ctxt tcx); +type ty_or_bang = util::common::ty_or_bang[ty::t]; + fn peek(@pstate st) -> u8 { ret st.data.(st.pos); } @@ -64,9 +68,17 @@ fn parse_ty_data(vec[u8] data, int crate_num, uint pos, uint len, ret result; } +fn parse_ty_or_bang(@pstate st, str_def sd) -> ty_or_bang { + alt (peek(st) as char) { + case ('!') { auto ignore = next(st); ret a_bang[ty::t]; } + case (_) { ret a_ty[ty::t](parse_ty(st, sd)); } + } +} + fn parse_ty(@pstate st, str_def sd) -> ty::t { alt (next(st) as char) { case ('n') { ret ty::mk_nil(st.tcx); } + case ('z') { ret ty::mk_bot(st.tcx); } case ('b') { ret ty::mk_bool(st.tcx); } case ('i') { ret ty::mk_int(st.tcx); } case ('u') { ret ty::mk_uint(st.tcx); } @@ -127,11 +139,11 @@ fn parse_ty(@pstate st, str_def sd) -> ty::t { } case ('F') { auto func = parse_ty_fn(st, sd); - ret ty::mk_fn(st.tcx, ast::proto_fn, func._0, func._1); + ret ty::mk_fn(st.tcx, ast::proto_fn, func._0, func._1, func._2); } case ('W') { auto func = parse_ty_fn(st, sd); - ret ty::mk_fn(st.tcx, ast::proto_iter, func._0, func._1); + ret ty::mk_fn(st.tcx, ast::proto_iter, func._0, func._1, func._2); } case ('N') { auto abi; @@ -159,9 +171,10 @@ fn parse_ty(@pstate st, str_def sd) -> ty::t { } auto func = parse_ty_fn(st, sd); methods += [rec(proto=proto, - ident=name, - inputs=func._0, - output=func._1)]; + ident=name, + inputs=func._0, + output=func._1, + cf=func._2)]; } st.pos += 1u; ret ty::mk_obj(st.tcx, methods); @@ -240,7 +253,8 @@ fn parse_hex(@pstate st) -> uint { ret n; } -fn parse_ty_fn(@pstate st, str_def sd) -> tup(vec[ty::arg], ty::t) { +fn parse_ty_fn(@pstate st, str_def sd) -> tup(vec[ty::arg], ty::t, + ast::controlflow) { assert (next(st) as char == '['); let vec[ty::arg] inputs = []; while (peek(st) as char != ']') { @@ -252,7 +266,15 @@ fn parse_ty_fn(@pstate st, str_def sd) -> tup(vec[ty::arg], ty::t) { inputs += [rec(mode=mode, ty=parse_ty(st, sd))]; } st.pos = st.pos + 1u; - ret tup(inputs, parse_ty(st, sd)); + auto res = parse_ty_or_bang(st, sd); + alt (res) { + case (a_bang[ty::t]) { + ret tup(inputs, ty::mk_bot(st.tcx), ast::noreturn); + } + case (a_ty[ty::t](?t)) { + ret tup(inputs, t, ast::return); + } + } } @@ -550,7 +572,7 @@ fn get_tag_variants(ty::ctxt tcx, ast::def_id def) auto ctor_ty = item_type(item, external_crate_id, tcx); let vec[ty::t] arg_tys = []; alt (ty::struct(tcx, ctor_ty)) { - case (ty::ty_fn(_, ?args, _)) { + case (ty::ty_fn(_, ?args, _, _)) { for (ty::arg a in args) { arg_tys += [a.ty]; } diff --git a/src/comp/front/parser.rs b/src/comp/front/parser.rs index 1774762dcf86..80397f2a65bb 100644 --- a/src/comp/front/parser.rs +++ b/src/comp/front/parser.rs @@ -12,6 +12,8 @@ import util::common::filename; import util::common::span; import util::common::new_str_hash; import util::data::interner; +import util::common::a_bang; +import util::common::a_ty; tag restriction { UNRESTRICTED; @@ -23,10 +25,7 @@ tag file_type { SOURCE_FILE; } -tag ty_or_bang { - a_ty(@ast::ty); - a_bang; -} +type ty_or_bang = util::common::ty_or_bang[@ast::ty]; state type parser = state obj { @@ -351,14 +350,24 @@ fn parse_ty_fn(ast::proto proto, &parser p, uint lo) parse_constrs(p); let @ast::ty output; + auto cf = ast::return; if (p.peek() == token::RARROW) { p.bump(); - output = parse_ty(p); + auto tmp = parse_ty_or_bang(p); + alt (tmp) { + case (a_ty[@ast::ty](?t)) { + output = t; + } + case (a_bang[@ast::ty]) { + output = @spanned(lo, inputs.span.hi, ast::ty_bot); + cf = ast::noreturn; + } + } } else { output = @spanned(lo, inputs.span.hi, ast::ty_nil); } - ret ast::ty_fn(proto, inputs.node, output); + ret ast::ty_fn(proto, inputs.node, output, cf); } fn parse_proto(&parser p) -> ast::proto { @@ -377,9 +386,9 @@ fn parse_ty_obj(&parser p, &mutable uint hi) -> ast::ty_ { auto f = parse_ty_fn(proto, p, flo); expect(p, token::SEMI); alt (f) { - case (ast::ty_fn(?proto, ?inputs, ?output)) { + case (ast::ty_fn(?proto, ?inputs, ?output, ?cf)) { ret rec(proto=proto, ident=ident, - inputs=inputs, output=output); + inputs=inputs, output=output, cf=cf); } } fail; @@ -457,8 +466,8 @@ fn parse_ty_constrs(@ast::ty t, &parser p) -> @ast::ty { fn parse_ty_or_bang(&parser p) -> ty_or_bang { alt (p.peek()) { - case (token::NOT) { p.bump(); ret a_bang; } - case (_) { ret a_ty(parse_ty(p)); } + case (token::NOT) { p.bump(); ret a_bang[@ast::ty]; } + case (_) { ret a_ty[@ast::ty](parse_ty(p)); } } } @@ -530,7 +539,7 @@ fn parse_ty(&parser p) -> @ast::ty { auto flo = p.get_last_lo_pos(); t = parse_ty_fn(ast::proto_fn, p, flo); alt (t) { - case (ast::ty_fn(_, _, ?out)) { + case (ast::ty_fn(_, _, ?out, _)) { hi = out.span.hi; } } @@ -538,7 +547,7 @@ fn parse_ty(&parser p) -> @ast::ty { auto flo = p.get_last_lo_pos(); t = parse_ty_fn(ast::proto_iter, p, flo); alt (t) { - case (ast::ty_fn(_, _, ?out)) { + case (ast::ty_fn(_, _, ?out, _)) { hi = out.span.hi; } } @@ -1735,15 +1744,16 @@ fn parse_fn_decl(&parser p, ast::purity purity) -> ast::fn_decl { p.bump(); res = parse_ty_or_bang(p); } else { - res = a_ty(@spanned(inputs.span.lo, inputs.span.hi, ast::ty_nil)); + res = a_ty[@ast::ty](@spanned(inputs.span.lo, inputs.span.hi, + ast::ty_nil)); } alt (res) { - case (a_ty(?t)) { + case (a_ty[@ast::ty](?t)) { ret rec(inputs=inputs.node, output=t, purity=purity, cf=ast::return); } - case (a_bang) { + case (a_bang[@ast::ty]) { ret rec(inputs=inputs.node, output=@spanned(p.get_lo_pos(), p.get_hi_pos(), ast::ty_bot), diff --git a/src/comp/middle/fold.rs b/src/comp/middle/fold.rs index f0de3c4b3cbc..9d48d50b4e65 100644 --- a/src/comp/middle/fold.rs +++ b/src/comp/middle/fold.rs @@ -67,7 +67,7 @@ type ast_fold[ENV] = (fn(&ENV e, &span sp, ast::proto proto, &vec[rec(ast::mode mode, @ty ty)] inputs, - &@ty output) -> @ty) fold_ty_fn, + &@ty output, &controlflow cf) -> @ty) fold_ty_fn, (fn(&ENV e, &span sp, &ast::path p, &ann a) -> @ty) fold_ty_path, @@ -423,12 +423,12 @@ fn fold_ty[ENV](&ENV env, &ast_fold[ENV] fld, &@ty t) -> @ty { let vec[ast::ty_method] meths_ = []; for (ast::ty_method m in meths) { auto tfn = fold_ty_fn(env_, fld, t.span, m.proto, - m.inputs, m.output); + m.inputs, m.output, m.cf); alt (tfn.node) { - case (ast::ty_fn(?p, ?ins, ?out)) { + case (ast::ty_fn(?p, ?ins, ?out, ?cf)) { vec::push[ast::ty_method] (meths_, rec(proto=p, inputs=ins, - output=out with m)); + output=out, cf=cf with m)); } } } @@ -440,8 +440,8 @@ fn fold_ty[ENV](&ENV env, &ast_fold[ENV] fld, &@ty t) -> @ty { ret fld.fold_ty_path(env_, t.span, pth_, ann); } - case (ast::ty_fn(?proto, ?inputs, ?output)) { - ret fold_ty_fn(env_, fld, t.span, proto, inputs, output); + case (ast::ty_fn(?proto, ?inputs, ?output, ?cf)) { + ret fold_ty_fn(env_, fld, t.span, proto, inputs, output, cf); } case (ast::ty_chan(?ty)) { @@ -459,7 +459,7 @@ fn fold_ty[ENV](&ENV env, &ast_fold[ENV] fld, &@ty t) -> @ty { fn fold_ty_fn[ENV](&ENV env, &ast_fold[ENV] fld, &span sp, ast::proto proto, &vec[rec(ast::mode mode, @ty ty)] inputs, - &@ty output) -> @ty { + &@ty output, &controlflow cf) -> @ty { auto output_ = fold_ty(env, fld, output); let vec[rec(ast::mode mode, @ty ty)] inputs_ = []; for (rec(ast::mode mode, @ty ty) input in inputs) { @@ -467,7 +467,7 @@ fn fold_ty_fn[ENV](&ENV env, &ast_fold[ENV] fld, &span sp, auto input_ = rec(ty=ty_ with input); inputs_ += [input_]; } - ret fld.fold_ty_fn(env, sp, proto, inputs_, output_); + ret fld.fold_ty_fn(env, sp, proto, inputs_, output_, cf); } fn fold_decl[ENV](&ENV env, &ast_fold[ENV] fld, &@decl d) -> @decl { @@ -1264,8 +1264,8 @@ fn identity_fold_ty_obj[ENV](&ENV env, &span sp, fn identity_fold_ty_fn[ENV](&ENV env, &span sp, ast::proto proto, &vec[rec(ast::mode mode, @ty ty)] inputs, - &@ty output) -> @ty { - ret @respan(sp, ast::ty_fn(proto, inputs, output)); + &@ty output, &controlflow cf) -> @ty { + ret @respan(sp, ast::ty_fn(proto, inputs, output, cf)); } fn identity_fold_ty_path[ENV](&ENV env, &span sp, &ast::path p, @@ -1742,7 +1742,7 @@ fn new_identity_fold[ENV]() -> ast_fold[ENV] { fold_ty_tup = bind identity_fold_ty_tup[ENV](_,_,_), fold_ty_rec = bind identity_fold_ty_rec[ENV](_,_,_), fold_ty_obj = bind identity_fold_ty_obj[ENV](_,_,_), - fold_ty_fn = bind identity_fold_ty_fn[ENV](_,_,_,_,_), + fold_ty_fn = bind identity_fold_ty_fn[ENV](_,_,_,_,_,_), fold_ty_path = bind identity_fold_ty_path[ENV](_,_,_,_), fold_ty_chan = bind identity_fold_ty_chan[ENV](_,_,_), fold_ty_port = bind identity_fold_ty_port[ENV](_,_,_), diff --git a/src/comp/middle/metadata.rs b/src/comp/middle/metadata.rs index 7f518506254b..97b2f3d7c4a3 100644 --- a/src/comp/middle/metadata.rs +++ b/src/comp/middle/metadata.rs @@ -144,6 +144,7 @@ mod Encode { fn enc_sty(&io::writer w, &@ctxt cx, &ty::sty st) { alt (st) { case (ty::ty_nil) { w.write_char('n'); } + case (ty::ty_bot) { w.write_char('z'); } case (ty::ty_bool) { w.write_char('b'); } case (ty::ty_int) { w.write_char('i'); } case (ty::ty_uint) { w.write_char('u'); } @@ -193,9 +194,9 @@ mod Encode { } w.write_char(']'); } - case (ty::ty_fn(?proto,?args,?out)) { + case (ty::ty_fn(?proto,?args,?out,?cf)) { enc_proto(w, proto); - enc_ty_fn(w, cx, args, out); + enc_ty_fn(w, cx, args, out, cf); } case (ty::ty_native_fn(?abi,?args,?out)) { w.write_char('N'); @@ -207,14 +208,14 @@ mod Encode { case (ast::native_abi_cdecl) { w.write_char('c'); } case (ast::native_abi_llvm) { w.write_char('l'); } } - enc_ty_fn(w, cx, args, out); + enc_ty_fn(w, cx, args, out, ast::return); } case (ty::ty_obj(?methods)) { w.write_str("O["); for (ty::method m in methods) { enc_proto(w, m.proto); w.write_str(m.ident); - enc_ty_fn(w, cx, m.inputs, m.output); + enc_ty_fn(w, cx, m.inputs, m.output, m.cf); } w.write_char(']'); } @@ -250,14 +251,22 @@ mod Encode { } } - fn enc_ty_fn(&io::writer w, &@ctxt cx, &vec[ty::arg] args, &ty::t out) { + fn enc_ty_fn(&io::writer w, &@ctxt cx, &vec[ty::arg] args, &ty::t out, + &ast::controlflow cf) { w.write_char('['); for (ty::arg arg in args) { if (arg.mode == ty::mo_alias) { w.write_char('&'); } enc_ty(w, cx, arg.ty); } w.write_char(']'); - enc_ty(w, cx, out); + alt (cf) { + case (ast::noreturn) { + w.write_char('!'); + } + case (_) { + enc_ty(w, cx, out); + } + } } } diff --git a/src/comp/middle/resolve.rs b/src/comp/middle/resolve.rs index 0ad368db9d4e..201e456dbc19 100644 --- a/src/comp/middle/resolve.rs +++ b/src/comp/middle/resolve.rs @@ -521,7 +521,7 @@ fn lookup_in_scope(&env e, list[scope] sc, &span sp, &ident id, namespace ns) } } } - fail; + e.sess.bug("reached unreachable code in lookup_in_scope"); // sigh } fn lookup_in_ty_params(&ident id, &vec[ast::ty_param] ty_params) @@ -757,7 +757,7 @@ fn lookup_in_local_mod(&env e, def_id defid, &ident id, namespace ns, } } } - fail; + e.sess.bug("reached unreachable code in lookup_in_regular_mod"); // sigh } fn lookup_in_mie(&env e, &mod_index_entry mie, namespace ns) diff --git a/src/comp/middle/trans.rs b/src/comp/middle/trans.rs index 23c74e063361..137a614a098c 100644 --- a/src/comp/middle/trans.rs +++ b/src/comp/middle/trans.rs @@ -807,7 +807,7 @@ fn type_of_inner(&@crate_ctxt cx, &ast::span sp, &ty::t t) -> TypeRef { } llty = T_struct(tys); } - case (ty::ty_fn(?proto, ?args, ?out)) { + case (ty::ty_fn(?proto, ?args, ?out, _)) { llty = T_fn_pair(cx.tn, type_of_fn(cx, sp, proto, args, out, 0u)); } case (ty::ty_native_fn(?abi, ?args, ?out)) { @@ -882,7 +882,7 @@ fn type_of_arg(@local_ctxt cx, &ast::span sp, &ty::arg arg) -> TypeRef { fn type_of_ty_param_count_and_ty(@local_ctxt lcx, &ast::span sp, &ty::ty_param_count_and_ty tpt) -> TypeRef { alt (ty::struct(lcx.ccx.tcx, tpt._1)) { - case (ty::ty_fn(?proto, ?inputs, ?output)) { + case (ty::ty_fn(?proto, ?inputs, ?output, _)) { auto llfnty = type_of_fn(lcx.ccx, sp, proto, inputs, output, tpt._0); ret T_fn_pair(lcx.ccx.tn, llfnty); @@ -2106,7 +2106,7 @@ fn make_free_glue(&@block_ctxt cx, ValueRef v0, &ty::t t) { rslt = trans_non_gc_free(cx_, b); } - case (ty::ty_fn(_,_,_)) { + case (ty::ty_fn(_,_,_,_)) { auto box_cell = cx.build.GEP(v0, @@ -2178,7 +2178,7 @@ fn make_drop_glue(&@block_ctxt cx, ValueRef v0, &ty::t t) { rslt = decr_refcnt_maybe_free(cx, box_cell, v0, t); } - case (ty::ty_fn(_,_,_)) { + case (ty::ty_fn(_,_,_,_)) { auto box_cell = cx.build.GEP(v0, @@ -2642,7 +2642,7 @@ fn iter_structural_ty_full(&@block_ctxt cx, // N-ary variant. auto fn_ty = variant.ctor_ty; alt (ty::struct(bcx.fcx.lcx.ccx.tcx, fn_ty)) { - case (ty::ty_fn(_, ?args, _)) { + case (ty::ty_fn(_, ?args, _, _)) { auto j = 0; for (ty::arg a in args) { auto v = [C_int(0), C_int(j as int)]; @@ -2692,7 +2692,7 @@ fn iter_structural_ty_full(&@block_ctxt cx, ret res(next_cx, C_nil()); } - case (ty::ty_fn(_,_,_)) { + case (ty::ty_fn(_,_,_,_)) { auto box_cell_a = cx.build.GEP(av, [C_int(0), @@ -4382,7 +4382,7 @@ fn trans_path(&@block_ctxt cx, &ast::path p, &ast::ann ann) -> lval_result { case (ast::def_variant(?tid, ?vid)) { auto v_tyt = ty::lookup_item_type(cx.fcx.lcx.ccx.tcx, vid); alt (ty::struct(cx.fcx.lcx.ccx.tcx, v_tyt._1)) { - case (ty::ty_fn(_, _, _)) { + case (ty::ty_fn(_, _, _, _)) { // N-ary variant. ret lval_generic_fn(cx, v_tyt, vid, ann); } @@ -4425,7 +4425,7 @@ fn trans_path(&@block_ctxt cx, &ast::path p, &ast::ann ann) -> lval_result { ret lval_generic_fn(cx, tyt, did, ann); } case (_) { - cx.fcx.lcx.ccx.sess.unimpl("def variant in trans"); + cx.fcx.lcx.ccx.sess.span_unimpl(cx.sp, "def variant in trans"); } } } @@ -6413,7 +6413,7 @@ fn is_terminated(&@block_ctxt cx) -> bool { fn arg_tys_of_fn(&@crate_ctxt ccx, ast::ann ann) -> vec[ty::arg] { alt (ty::struct(ccx.tcx, ty::ann_to_type(ccx.tcx.node_types, ann))) { - case (ty::ty_fn(_, ?arg_tys, _)) { + case (ty::ty_fn(_, ?arg_tys, _, _)) { ret arg_tys; } } @@ -6422,7 +6422,7 @@ fn arg_tys_of_fn(&@crate_ctxt ccx, ast::ann ann) -> vec[ty::arg] { fn ret_ty_of_fn_ty(&@crate_ctxt ccx, ty::t t) -> ty::t { alt (ty::struct(ccx.tcx, t)) { - case (ty::ty_fn(_, _, ?ret_ty)) { + case (ty::ty_fn(_, _, ?ret_ty, _)) { ret ret_ty; } } @@ -6574,7 +6574,7 @@ fn trans_vtbl(@local_ctxt cx, auto llfnty = T_nil(); alt (ty::struct(cx.ccx.tcx, node_ann_type(cx.ccx, m.node.ann))) { - case (ty::ty_fn(?proto, ?inputs, ?output)) { + case (ty::ty_fn(?proto, ?inputs, ?output, _)) { llfnty = type_of_fn_full(cx.ccx, m.span, proto, some[TypeRef](llself_ty), inputs, output, @@ -6934,7 +6934,7 @@ fn decl_fn_and_pair(&@crate_ctxt ccx, &ast::span sp, auto llfty; auto llpairty; alt (ty::struct(ccx.tcx, node_ann_type(ccx, ann))) { - case (ty::ty_fn(?proto, ?inputs, ?output)) { + case (ty::ty_fn(?proto, ?inputs, ?output, _)) { llfty = type_of_fn(ccx, sp, proto, inputs, output, vec::len[ast::ty_param](ty_params)); llpairty = T_fn_pair(ccx.tn, llfty); diff --git a/src/comp/middle/tstate/annotate.rs b/src/comp/middle/tstate/annotate.rs index 743f525401d1..ab1468d87c40 100644 --- a/src/comp/middle/tstate/annotate.rs +++ b/src/comp/middle/tstate/annotate.rs @@ -86,11 +86,12 @@ import util::common::log_expr; import util::common::log_block; import util::common::log_stmt; -import middle::tstate::aux::fn_info; -import middle::tstate::aux::fn_info_map; -import middle::tstate::aux::num_locals; -import middle::tstate::aux::get_fn_info; -import middle::tstate::aux::crate_ctxt; +import aux::fn_info; +import aux::fn_info_map; +import aux::num_locals; +import aux::get_fn_info; +import aux::crate_ctxt; +import aux::add_node; import middle::tstate::ann::empty_ann; fn collect_ids_expr(&@expr e, @vec[uint] res) -> () { @@ -140,7 +141,7 @@ fn node_ids_in_fn(&_fn f, &ident i, &def_id d, &ann a, @vec[uint] res) -> () { fn init_vecs(&crate_ctxt ccx, @vec[uint] node_ids, uint len) -> () { for (uint i in *node_ids) { log(uistr(i) + " |-> " + uistr(len)); - ccx.node_anns.insert(i, empty_ann(len)); + add_node(ccx, i, empty_ann(len)); } } diff --git a/src/comp/middle/tstate/auxiliary.rs b/src/comp/middle/tstate/auxiliary.rs index 39e72c0edc71..48302344d079 100644 --- a/src/comp/middle/tstate/auxiliary.rs +++ b/src/comp/middle/tstate/auxiliary.rs @@ -1,5 +1,7 @@ import std::bitv; +import std::vec; import std::vec::len; +import std::vec::grow; import std::vec::pop; import std::option; import std::option::none; @@ -156,7 +158,7 @@ type fn_info = rec(@std::map::hashmap[def_id, var_info] vars, controlflow cf); /* mapping from node ID to typestate annotation */ -type node_ann_table = @std::map::hashmap[uint, ts_ann]; +type node_ann_table = @vec[ts_ann]; /* mapping from function name to fn_info map */ type fn_info_map = @std::map::hashmap[def_id, fn_info]; @@ -175,10 +177,26 @@ fn get_fn_info(&crate_ctxt ccx, def_id did) -> fn_info { ret ccx.fm.get(did); } +fn add_node(&crate_ctxt ccx, uint i, &ts_ann a) -> () { + auto sz = len(*(ccx.node_anns)); + if (sz <= i) { + grow(*(ccx.node_anns), (i - sz) + 1u, empty_ann(0u)); + } + ccx.node_anns.(i) = a; +} + +fn get_ts_ann(&crate_ctxt ccx, uint i) -> option::t[ts_ann] { + if (i < len(*(ccx.node_anns))) { + ret some[ts_ann](ccx.node_anns.(i)); + } + else { + ret none[ts_ann]; + } +} /********* utils ********/ fn ann_to_ts_ann(&crate_ctxt ccx, &ann a) -> ts_ann { - alt (ccx.node_anns.find(a.id)) { + alt (get_ts_ann(ccx, a.id)) { case (none[ts_ann]) { log_err ("ann_to_ts_ann: no ts_ann for node_id " + uistr(a.id)); @@ -296,8 +314,8 @@ fn block_poststate(&crate_ctxt ccx, &block b) -> poststate { /* sets the pre_and_post for an ann */ fn with_pp(&crate_ctxt ccx, &ann a, pre_and_post p) { - ccx.node_anns.insert(a.id, @rec(conditions=p, - states=empty_states(pps_len(p)))); + add_node(ccx, a.id, @rec(conditions=p, + states=empty_states(pps_len(p)))); } fn set_prestate_ann(&crate_ctxt ccx, &ann a, &prestate pre) -> bool { @@ -370,8 +388,8 @@ fn num_locals(fn_info m) -> uint { } fn new_crate_ctxt(ty::ctxt cx) -> crate_ctxt { - ret rec(tcx=cx, node_anns=@new_uint_hash[ts_ann](), - fm=@new_def_hash[fn_info]()); + let vec[ts_ann] na = []; + ret rec(tcx=cx, node_anns=@na, fm=@new_def_hash[fn_info]()); } fn controlflow_def_id(&crate_ctxt ccx, &def_id d) -> controlflow { @@ -381,20 +399,16 @@ fn controlflow_def_id(&crate_ctxt ccx, &def_id d) -> controlflow { } } -/* conservative approximation: uses the mapping if e refers to a known - function or method, assumes returning otherwise. - There's no case for fail b/c we assume e is the callee and it - seems unlikely that one would apply "fail" to arguments. */ +/* Use e's type to determine whether it returns. + If it has a function type with a ! annotation, +the answer is noreturn. */ fn controlflow_expr(&crate_ctxt ccx, @expr e) -> controlflow { - auto f = expr_ann(e).id; - alt (ccx.tcx.def_map.find(f)) { - case (some[def](def_fn(?d))) { - ret controlflow_def_id(ccx, d); - } - case (some[def](def_obj_field(?d))) { - ret controlflow_def_id(ccx, d); + alt (ty::struct(ccx.tcx, ty::ann_to_type(ccx.tcx.node_types, + expr_ann(e)))) { + case (ty::ty_fn(_,_,_,?cf)) { + ret cf; } - case (_) { + case (_) { ret return; } } diff --git a/src/comp/middle/tstate/pre_post_conditions.rs b/src/comp/middle/tstate/pre_post_conditions.rs index 1752fcaf2b13..a837bd9f9a2c 100644 --- a/src/comp/middle/tstate/pre_post_conditions.rs +++ b/src/comp/middle/tstate/pre_post_conditions.rs @@ -79,7 +79,6 @@ import front::ast::lit; import front::ast::init_op; import front::ast::controlflow; import front::ast::return; -import front::ast::noreturn; import front::ast::_fn; import front::ast::_obj; import front::ast::crate; diff --git a/src/comp/middle/tstate/states.rs b/src/comp/middle/tstate/states.rs index 4af741670b02..c04ad500574c 100644 --- a/src/comp/middle/tstate/states.rs +++ b/src/comp/middle/tstate/states.rs @@ -235,17 +235,9 @@ fn find_pre_post_state_expr(&fn_ctxt fcx, &prestate pres, @expr e) -> bool { /* if this is a failing call, it sets the return value */ alt (controlflow_expr(fcx.ccx, operator)) { case (noreturn) { - /* - log_err("Call that might fail! to"); - log_expr_err(*operator); - */ changed = gen_poststate(fcx, a, fcx.id) || changed; } - case (_) { - /* log_err("non-failing call, to:"); - log_expr_err(*operator); - */ - } + case (_) { } } ret changed; } diff --git a/src/comp/middle/ty.rs b/src/comp/middle/ty.rs index 67fb829d4ad7..b92b7fb61db7 100644 --- a/src/comp/middle/ty.rs +++ b/src/comp/middle/ty.rs @@ -13,6 +13,7 @@ import std::option::some; import driver::session; import front::ast; import front::ast::mutability; +import front::ast::controlflow; import front::creader; import middle::metadata; import util::common; @@ -49,7 +50,8 @@ type field = rec(ast::ident ident, mt mt); type method = rec(ast::proto proto, ast::ident ident, vec[arg] inputs, - t output); + t output, + controlflow cf); tag any_item { any_item_rust(@ast::item); @@ -76,7 +78,7 @@ type ty_ctxt = ctxt; // Needed for disambiguation from unify::ctxt. // Convert from method type to function type. Pretty easy; we just drop // 'ident'. fn method_ty_to_fn_ty(&ctxt cx, method m) -> t { - ret mk_fn(cx, m.proto, m.inputs, m.output); + ret mk_fn(cx, m.proto, m.inputs, m.output, m.cf); } // Never construct these manually. These are interned. @@ -113,7 +115,7 @@ tag sty { ty_task; ty_tup(vec[mt]); ty_rec(vec[field]); - ty_fn(ast::proto, vec[arg], t); + ty_fn(ast::proto, vec[arg], t, controlflow); ty_native_fn(ast::native_abi, vec[arg], t); ty_obj(vec[method]); ty_var(int); // ephemeral type var @@ -135,6 +137,7 @@ type unify_handler = obj { tag type_err { terr_mismatch; + terr_controlflow_mismatch; terr_box_mutability; terr_vec_mutability; terr_tuple_size(uint, uint); @@ -358,7 +361,7 @@ fn mk_raw_ty(&ctxt cx, &sty st, &option::t[str] cname) -> raw_t { } } - case (ty_fn(_, ?args, ?tt)) { + case (ty_fn(_, ?args, ?tt, _)) { derive_flags_sig(cx, has_params, has_bound_params, has_vars, has_locals, args, tt); } @@ -462,8 +465,9 @@ fn mk_imm_tup(&ctxt cx, &vec[t] tys) -> t { fn mk_rec(&ctxt cx, &vec[field] fs) -> t { ret gen_ty(cx, ty_rec(fs)); } -fn mk_fn(&ctxt cx, &ast::proto proto, &vec[arg] args, &t ty) -> t { - ret gen_ty(cx, ty_fn(proto, args, ty)); +fn mk_fn(&ctxt cx, &ast::proto proto, &vec[arg] args, &t ty, + &controlflow cf) -> t { + ret gen_ty(cx, ty_fn(proto, args, ty, cf)); } fn mk_native_fn(&ctxt cx, &ast::native_abi abi, &vec[arg] args, &t ty) -> t { @@ -635,7 +639,7 @@ fn ty_to_str(&ctxt cx, &t typ) -> str { } } - case (ty_fn(?proto, ?inputs, ?output)) { + case (ty_fn(?proto, ?inputs, ?output, _)) { s += fn_to_str(cx, proto, none[ast::ident], inputs, output); } @@ -721,7 +725,7 @@ fn walk_ty(&ctxt cx, ty_walk walker, t ty) { walk_ty(cx, walker, fl.mt.ty); } } - case (ty_fn(?proto, ?args, ?ret_ty)) { + case (ty_fn(?proto, ?args, ?ret_ty, _)) { for (arg a in args) { walk_ty(cx, walker, a.ty); } @@ -805,14 +809,14 @@ fn fold_ty(&ctxt cx, ty_fold fld, t ty_0) -> t { } ty = copy_cname(cx, mk_rec(cx, new_fields), ty); } - case (ty_fn(?proto, ?args, ?ret_ty)) { + case (ty_fn(?proto, ?args, ?ret_ty, ?cf)) { let vec[arg] new_args = []; for (arg a in args) { auto new_ty = fold_ty(cx, fld, a.ty); new_args += [rec(mode=a.mode, ty=new_ty)]; } ty = copy_cname(cx, mk_fn(cx, proto, new_args, - fold_ty(cx, fld, ret_ty)), ty); + fold_ty(cx, fld, ret_ty), cf), ty); } case (ty_native_fn(?abi, ?args, ?ret_ty)) { let vec[arg] new_args = []; @@ -832,8 +836,8 @@ fn fold_ty(&ctxt cx, ty_fold fld, t ty_0) -> t { ty=fold_ty(cx, fld, a.ty))]; } new_methods += [rec(proto=m.proto, ident=m.ident, - inputs=new_args, - output=fold_ty(cx, fld, m.output))]; + inputs=new_args, + output=fold_ty(cx, fld, m.output), cf=m.cf)]; } ty = copy_cname(cx, mk_obj(cx, new_methods), ty); } @@ -885,7 +889,7 @@ fn type_is_structural(&ctxt cx, &t ty) -> bool { case (ty_tup(_)) { ret true; } case (ty_rec(_)) { ret true; } case (ty_tag(_,_)) { ret true; } - case (ty_fn(_,_,_)) { ret true; } + case (ty_fn(_,_,_,_)) { ret true; } case (ty_obj(_)) { ret true; } case (_) { ret false; } } @@ -1206,7 +1210,7 @@ fn hash_type_structure(&sty st) -> uint { } ret h; } - case (ty_fn(_, ?args, ?rty)) { ret hash_fn(25u, args, rty); } + case (ty_fn(_, ?args, ?rty, _)) { ret hash_fn(25u, args, rty); } case (ty_native_fn(_, ?args, ?rty)) { ret hash_fn(26u, args, rty); } case (ty_obj(?methods)) { auto h = 27u; @@ -1405,10 +1409,11 @@ fn equal_type_structures(&sty a, &sty b) -> bool { case (_) { ret false; } } } - case (ty_fn(?p_a, ?args_a, ?rty_a)) { + case (ty_fn(?p_a, ?args_a, ?rty_a, ?cf_a)) { alt (b) { - case (ty_fn(?p_b, ?args_b, ?rty_b)) { + case (ty_fn(?p_b, ?args_b, ?rty_b, ?cf_b)) { ret p_a == p_b && + cf_a == cf_b && equal_fn(args_a, rty_a, args_b, rty_b); } case (_) { ret false; } @@ -1635,7 +1640,7 @@ fn type_contains_bound_params(&ctxt cx, &t typ) -> bool { fn ty_fn_args(&ctxt cx, &t fty) -> vec[arg] { alt (struct(cx, fty)) { - case (ty::ty_fn(_, ?a, _)) { ret a; } + case (ty::ty_fn(_, ?a, _, _)) { ret a; } case (ty::ty_native_fn(_, ?a, _)) { ret a; } } fail; @@ -1643,7 +1648,7 @@ fn ty_fn_args(&ctxt cx, &t fty) -> vec[arg] { fn ty_fn_proto(&ctxt cx, &t fty) -> ast::proto { alt (struct(cx, fty)) { - case (ty::ty_fn(?p, _, _)) { ret p; } + case (ty::ty_fn(?p, _, _, _)) { ret p; } } fail; } @@ -1657,7 +1662,7 @@ fn ty_fn_abi(&ctxt cx, &t fty) -> ast::native_abi { fn ty_fn_ret(&ctxt cx, &t fty) -> t { alt (struct(cx, fty)) { - case (ty::ty_fn(_, _, ?r)) { ret r; } + case (ty::ty_fn(_, _, ?r, _)) { ret r; } case (ty::ty_native_fn(_, _, ?r)) { ret r; } } fail; @@ -1665,7 +1670,7 @@ fn ty_fn_ret(&ctxt cx, &t fty) -> t { fn is_fn_ty(&ctxt cx, &t fty) -> bool { alt (struct(cx, fty)) { - case (ty::ty_fn(_, _, _)) { ret true; } + case (ty::ty_fn(_, _, _, _)) { ret true; } case (ty::ty_native_fn(_, _, _)) { ret true; } case (_) { ret false; } } @@ -2088,12 +2093,32 @@ mod unify { &t expected, &t actual, &vec[arg] expected_inputs, &t expected_output, - &vec[arg] actual_inputs, &t actual_output) + &vec[arg] actual_inputs, &t actual_output, + &controlflow expected_cf, &controlflow actual_cf) -> result { if (e_proto != a_proto) { ret ures_err(terr_mismatch, expected, actual); } + alt (expected_cf) { + case (ast::return) { } // ok + case (ast::noreturn) { + alt (actual_cf) { + case (ast::noreturn) { + // ok + } + case (_) { + /* even though typestate checking is mostly + responsible for checking control flow annotations, + this check is necessary to ensure that the + annotation in an object method matches the + declared object type */ + ret ures_err(terr_controlflow_mismatch, + expected, actual); + } + } + } + } auto t = unify_fn_common(cx, expected, actual, expected_inputs, expected_output, actual_inputs, actual_output); @@ -2102,7 +2127,8 @@ mod unify { ret r; } case (fn_common_res_ok(?result_ins, ?result_out)) { - auto t2 = mk_fn(cx.tcx, e_proto, result_ins, result_out); + auto t2 = mk_fn(cx.tcx, e_proto, result_ins, result_out, + actual_cf); ret ures_ok(t2); } } @@ -2160,14 +2186,16 @@ mod unify { e_meth.proto, a_meth.proto, expected, actual, e_meth.inputs, e_meth.output, - a_meth.inputs, a_meth.output); + a_meth.inputs, a_meth.output, + e_meth.cf, a_meth.cf); alt (r) { case (ures_ok(?tfn)) { alt (struct(cx.tcx, tfn)) { - case (ty_fn(?proto, ?ins, ?out)) { + case (ty_fn(?proto, ?ins, ?out, ?cf)) { result_meths += [rec(inputs = ins, - output = out - with e_meth)]; + output = out, + cf = cf + with e_meth)]; } } } @@ -2539,13 +2567,16 @@ mod unify { } } - case (ty::ty_fn(?ep, ?expected_inputs, ?expected_output)) { + case (ty::ty_fn(?ep, ?expected_inputs, + ?expected_output, ?expected_cf)) { alt (struct(cx.tcx, actual)) { - case (ty::ty_fn(?ap, ?actual_inputs, ?actual_output)) { + case (ty::ty_fn(?ap, ?actual_inputs, + ?actual_output, ?actual_cf)) { ret unify_fn(cx, ep, ap, expected, actual, expected_inputs, expected_output, - actual_inputs, actual_output); + actual_inputs, actual_output, + expected_cf, actual_cf); } case (_) { @@ -2732,6 +2763,10 @@ fn type_err_to_str(&ty::type_err err) -> str { case (terr_mismatch) { ret "types differ"; } + case (terr_controlflow_mismatch) { + ret "returning function used where non-returning function" + + " was expected"; + } case (terr_box_mutability) { ret "boxed values differ in mutability"; } @@ -2911,7 +2946,7 @@ fn lookup_item_type(ctxt cx, ast::def_id did) -> ty_param_count_and_ty { fn ret_ty_of_fn_ty(ty_ctxt tcx, t a_ty) -> t { alt (ty::struct(tcx, a_ty)) { - case (ty::ty_fn(_, _, ?ret_ty)) { + case (ty::ty_fn(_, _, ?ret_ty, _)) { ret ret_ty; } case (_) { diff --git a/src/comp/middle/typeck.rs b/src/comp/middle/typeck.rs index 5427e5f3b059..de47fce619d8 100644 --- a/src/comp/middle/typeck.rs +++ b/src/comp/middle/typeck.rs @@ -314,11 +314,11 @@ fn ast_ty_to_ty(&ty::ctxt tcx, &ty_getter getter, &@ast::ty ast_ty) -> ty::t { typ = ty::mk_rec(tcx, flds); } - case (ast::ty_fn(?proto, ?inputs, ?output)) { + case (ast::ty_fn(?proto, ?inputs, ?output, ?cf)) { auto f = bind ast_arg_to_arg(tcx, getter, _); auto i = vec::map[ast::ty_arg, arg](f, inputs); auto out_ty = ast_ty_to_ty(tcx, getter, output); - typ = ty::mk_fn(tcx, proto, i, out_ty); + typ = ty::mk_fn(tcx, proto, i, out_ty, cf); } case (ast::ty_path(?path, ?ann)) { @@ -346,11 +346,13 @@ fn ast_ty_to_ty(&ty::ctxt tcx, &ty_getter getter, &@ast::ty ast_ty) -> ty::t { for (ast::ty_method m in meths) { auto ins = vec::map[ast::ty_arg, arg](f, m.inputs); auto out = ast_ty_to_ty(tcx, getter, m.output); - vec::push[ty::method](tmeths, + let ty::method new_m = rec(proto=m.proto, ident=m.ident, inputs=ins, - output=out)); + output=out, + cf=m.cf); + vec::push[ty::method](tmeths, new_m); } typ = ty::mk_obj(tcx, ty::sort_methods(tmeths)); @@ -458,7 +460,7 @@ mod collect { &ast::def_id def_id) -> ty::ty_param_count_and_ty { auto input_tys = vec::map[ast::arg,arg](ty_of_arg, decl.inputs); auto output_ty = convert(decl.output); - auto t_fn = ty::mk_fn(cx.tcx, proto, input_tys, output_ty); + auto t_fn = ty::mk_fn(cx.tcx, proto, input_tys, output_ty, decl.cf); auto ty_param_count = vec::len[ast::ty_param](ty_params); auto tpt = tup(ty_param_count, t_fn); cx.tcx.tcache.insert(def_id, tpt); @@ -513,7 +515,7 @@ mod collect { auto inputs = vec::map[ast::arg,arg](f, m.node.meth.decl.inputs); auto output = convert(m.node.meth.decl.output); ret rec(proto=m.node.meth.proto, ident=m.node.ident, - inputs=inputs, output=output); + inputs=inputs, output=output, cf=m.node.meth.decl.cf); } fn ty_of_obj(@ctxt cx, @@ -542,7 +544,8 @@ mod collect { vec::push[arg](t_inputs, rec(mode=ty::mo_alias, ty=t_field)); } - auto t_fn = ty::mk_fn(cx.tcx, ast::proto_fn, t_inputs, t_obj._1); + auto t_fn = ty::mk_fn(cx.tcx, ast::proto_fn, t_inputs, t_obj._1, + ast::return); auto tpt = tup(t_obj._0, t_fn); cx.tcx.tcache.insert(ctor_id, tpt); @@ -675,7 +678,8 @@ mod collect { args += [rec(mode=ty::mo_alias, ty=arg_ty)]; } auto tag_t = ty::mk_tag(cx.tcx, tag_id, ty_param_tys); - result_ty = ty::mk_fn(cx.tcx, ast::proto_fn, args, tag_t); + result_ty = ty::mk_fn(cx.tcx, ast::proto_fn, args, tag_t, + ast::return); } auto tpt = tup(ty_param_count, result_ty); @@ -782,7 +786,7 @@ mod collect { // TODO: typechecker botch let vec[arg] no_args = []; auto t = ty::mk_fn(cx.tcx, ast::proto_fn, no_args, - ty::mk_nil(cx.tcx)); + ty::mk_nil(cx.tcx), ast::return); write::ty_only(cx.tcx, m.node.ann.id, t); } } @@ -1073,7 +1077,7 @@ fn variant_arg_types(&@crate_ctxt ccx, &span sp, &ast::def_id vid, auto tpt = ty::lookup_item_type(ccx.tcx, vid); alt (struct(ccx.tcx, tpt._1)) { - case (ty::ty_fn(_, ?ins, _)) { + case (ty::ty_fn(_, ?ins, _, _)) { // N-ary variant. for (ty::arg arg in ins) { auto arg_ty = bind_params_in_type(ccx.tcx, arg.ty); @@ -1660,7 +1664,7 @@ fn check_pat(&@stmt_ctxt scx, &@ast::pat pat) { alt (struct(scx.fcx.ccx.tcx, t)) { // N-ary variants have function types. - case (ty::ty_fn(_, ?args, ?tag_ty)) { + case (ty::ty_fn(_, ?args, ?tag_ty, _)) { auto arg_len = vec::len[arg](args); auto subpats_len = vec::len[@ast::pat](subpats); if (arg_len != subpats_len) { @@ -1798,8 +1802,8 @@ fn check_expr(&@stmt_ctxt scx, &@ast::expr expr) { auto rt_0 = next_ty_var(scx); auto t_0; alt (struct(scx.fcx.ccx.tcx, expr_ty(scx.fcx.ccx.tcx, f))) { - case (ty::ty_fn(?proto, _, _)) { - t_0 = ty::mk_fn(scx.fcx.ccx.tcx, proto, arg_tys_0, rt_0); + case (ty::ty_fn(?proto, _, _, ?cf)) { + t_0 = ty::mk_fn(scx.fcx.ccx.tcx, proto, arg_tys_0, rt_0, cf); } case (ty::ty_native_fn(?abi, _, _)) { t_0 = ty::mk_native_fn(scx.fcx.ccx.tcx, abi, arg_tys_0, rt_0); @@ -2236,8 +2240,9 @@ fn check_expr(&@stmt_ctxt scx, &@ast::expr expr) { let vec[ty::arg] arg_tys_1 = []; auto rt_1; auto fty = expr_ty(scx.fcx.ccx.tcx, f); + auto t_1; alt (struct(scx.fcx.ccx.tcx, fty)) { - case (ty::ty_fn(?proto, ?arg_tys, ?rt)) { + case (ty::ty_fn(?proto, ?arg_tys, ?rt, ?cf)) { proto_1 = proto; rt_1 = rt; @@ -2253,14 +2258,14 @@ fn check_expr(&@stmt_ctxt scx, &@ast::expr expr) { } i += 1u; } + t_1 = ty::mk_fn(scx.fcx.ccx.tcx, proto_1, arg_tys_1, rt_1, + cf); } case (_) { log_err "LHS of bind expr didn't have a function type?!"; fail; } } - - auto t_1 = ty::mk_fn(scx.fcx.ccx.tcx, proto_1, arg_tys_1, rt_1); write::ty_only_fixup(scx, a.id, t_1); } @@ -2277,7 +2282,7 @@ fn check_expr(&@stmt_ctxt scx, &@ast::expr expr) { auto rt_1 = ty::mk_nil(scx.fcx.ccx.tcx); // FIXME: typestate botch auto fty = expr_ty(scx.fcx.ccx.tcx, f); alt (struct(scx.fcx.ccx.tcx, fty)) { - case (ty::ty_fn(_,_,?rt)) { rt_1 = rt; } + case (ty::ty_fn(_,_,?rt,_)) { rt_1 = rt; } case (ty::ty_native_fn(_, _, ?rt)) { rt_1 = rt; } case (_) { log_err "LHS of call expr didn't have a function type?!"; @@ -2321,7 +2326,7 @@ fn check_expr(&@stmt_ctxt scx, &@ast::expr expr) { // Check the return type auto fty = expr_ty(scx.fcx.ccx.tcx, f); alt (struct(scx.fcx.ccx.tcx, fty)) { - case (ty::ty_fn(_,_,?rt)) { + case (ty::ty_fn(_,_,?rt,_)) { alt (struct(scx.fcx.ccx.tcx, rt)) { case (ty::ty_nil) { // This is acceptable @@ -2485,7 +2490,7 @@ fn check_expr(&@stmt_ctxt scx, &@ast::expr expr) { } auto meth = methods.(ix); auto t = ty::mk_fn(scx.fcx.ccx.tcx, meth.proto, - meth.inputs, meth.output); + meth.inputs, meth.output, meth.cf); write::ty_only_fixup(scx, a.id, t); } diff --git a/src/comp/middle/walk.rs b/src/comp/middle/walk.rs index 5c0c5b3667f9..cac5fd0ea353 100644 --- a/src/comp/middle/walk.rs +++ b/src/comp/middle/walk.rs @@ -163,7 +163,7 @@ fn walk_ty(&ast_visitor v, @ast::ty t) { walk_ty(v, f.mt.ty); } } - case (ast::ty_fn(_, ?args, ?out)) { + case (ast::ty_fn(_, ?args, ?out, _)) { for (ast::ty_arg a in args) { walk_ty(v, a.ty); } diff --git a/src/comp/pretty/pprust.rs b/src/comp/pretty/pprust.rs index 695f7bf9c275..d104e862dc80 100644 --- a/src/comp/pretty/pprust.rs +++ b/src/comp/pretty/pprust.rs @@ -137,6 +137,7 @@ fn print_type(ps s, &@ast::ty ty) { alt (ty.node) { case (ast::ty_nil) {wrd(s.s, "()");} case (ast::ty_bool) {wrd(s.s, "bool");} + case (ast::ty_bot) {wrd(s.s, "_|_");} case (ast::ty_int) {wrd(s.s, "int");} case (ast::ty_uint) {wrd(s.s, "uint");} case (ast::ty_float) {wrd(s.s, "float");} @@ -188,15 +189,15 @@ fn print_type(ps s, &@ast::ty ty) { for (ast::ty_method m in methods) { hbox(s); print_ty_fn(s, m.proto, option::some[str](m.ident), - m.inputs, m.output); + m.inputs, m.output, m.cf); wrd(s.s, ";"); end(s.s); line(s.s); } bclose_c(s, ty.span); } - case (ast::ty_fn(?proto,?inputs,?output)) { - print_ty_fn(s, proto, option::none[str], inputs, output); + case (ast::ty_fn(?proto,?inputs,?output,?cf)) { + print_ty_fn(s, proto, option::none[str], inputs, output, cf); } case (ast::ty_path(?path,_)) { print_path(s, path); @@ -978,7 +979,8 @@ fn print_string(ps s, str st) { } fn print_ty_fn(ps s, ast::proto proto, option::t[str] id, - vec[ast::ty_arg] inputs, @ast::ty output) { + vec[ast::ty_arg] inputs, @ast::ty output, + ast::controlflow cf) { if (proto == ast::proto_fn) {wrd(s.s, "fn");} else {wrd(s.s, "iter");} alt (id) { @@ -998,7 +1000,14 @@ fn print_ty_fn(ps s, ast::proto proto, option::t[str] id, space(s.s); hbox(s); wrd1(s, "->"); - print_type(s, output); + alt (cf) { + case (ast::return) { + print_type(s, output); + } + case (ast::noreturn) { + wrd1(s, "!"); + } + } end(s.s); } } diff --git a/src/comp/util/common.rs b/src/comp/util/common.rs index 090ad57027ec..4e0714cd4292 100644 --- a/src/comp/util/common.rs +++ b/src/comp/util/common.rs @@ -45,6 +45,11 @@ tag ty_mach { ty_f64; } +tag ty_or_bang[T] { + a_ty(T); + a_bang; +} + fn ty_mach_to_str(ty_mach tm) -> str { alt (tm) { case (ty_u8) { ret "u8"; }