提交 a08a376d 编写于 作者: T Tim Chevalier 提交者: Graydon Hoare

Make controlflow part of a function type

Change ty_fn to have a controlflow field. A 'controlflow' is
essentially a bit of data that says whether or not this function
never returns to the caller (if it never returns, that means it calls
"fail" or another "never-returns" function on every control path).

Also add syntax for annotating functions that never return:

fn foo() -> ! {
   fail;
}

for example. Functions marked with ! implicitly have a result type of
ty_bot, which is a new type that this commit also adds.
上级 3dd28779
......@@ -307,7 +307,8 @@ fn unop_to_str(unop op) -> str {
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 @@ fn unop_to_str(unop op) -> str {
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;
......
......@@ -13,6 +13,8 @@
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 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];
}
......
......@@ -12,6 +12,8 @@
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 @@
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_fn_input_ty(&parser p) -> rec(ast::mode mode, @ast::ty ty) {
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_method_sig(&parser p) -> ast::ty_method {
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),
......
......@@ -67,7 +67,7 @@
(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](_,_,_),
......
......@@ -144,6 +144,7 @@ fn enc_mt(&io::writer w, &@ctxt cx, &ty::mt mt) {
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 @@ fn enc_sty(&io::writer w, &@ctxt cx, &ty::sty st) {
}
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 @@ fn enc_sty(&io::writer w, &@ctxt cx, &ty::sty st) {
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 @@ fn enc_proto(&io::writer w, ast::proto proto) {
}
}
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);
}
}
}
}
......
......@@ -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);
......@@ -2114,7 +2114,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,
......@@ -2186,7 +2186,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,
......@@ -2650,7 +2650,7 @@ fn iter_boxpp(@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)];
......@@ -2700,7 +2700,7 @@ fn iter_boxpp(@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),
......@@ -4386,7 +4386,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);
}
......@@ -4429,7 +4429,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");
}
}
}
......@@ -6578,7 +6578,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;
}
}
......@@ -6587,7 +6587,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;
}
}
......@@ -6739,7 +6739,7 @@ fn meth_lteq(&@ast::method a, &@ast::method b) -> bool {
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,
......@@ -7099,7 +7099,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);
......
......@@ -381,20 +381,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);
alt (ty::struct(ccx.tcx, ty::ann_to_type(ccx.tcx.node_types,
expr_ann(e)))) {
case (ty::ty_fn(_,_,_,?cf)) {
ret cf;
}
case (some[def](def_obj_field(?d))) {
ret controlflow_def_id(ccx, d);
}
case (_) {
case (_) {
ret return;
}
}
......
......@@ -13,6 +13,7 @@
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 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 @@
// 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 @@ fn method_ty_to_fn_ty(&ctxt cx, method m) -> t {
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 @@ fn method_ty_to_fn_ty(&ctxt cx, method m) -> t {
tag type_err {
terr_mismatch;
terr_controlflow_mismatch;
terr_box_mutability;
terr_vec_mutability;
terr_tuple_size(uint, uint);
......@@ -358,7 +361,7 @@ fn derive_flags_sig(&ctxt cx,
}
}
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 mt_to_str(&ctxt cx, &mt m) -> 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_fn(uint id, &vec[arg] args, &t rty) -> 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_def(&ast::def_id did_a, &ast::def_id did_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 @@ fn unify_fn(&@ctxt cx,
&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 @@ fn unify_fn(&@ctxt cx,
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 @@ fn unify_obj(&@ctxt cx,
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 @@ fn unify_step(&@ctxt cx, &t expected, &t actual) -> result {
}
}
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 (_) {
......
......@@ -314,11 +314,11 @@ fn instantiate(&ty::ctxt tcx,
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 instantiate(&ty::ctxt tcx,
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 @@ fn ty_of_fn_decl(&@ctxt cx,
&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 @@ fn ty_of_method(@ctxt cx, &@ast::method m) -> method {
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 @@ fn ty_of_obj_ctor(@ctxt cx,
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 @@ fn get_tag_variant_types(&@ctxt cx, &ast::def_id tag_id,
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 @@ fn convert(@ctxt cx, @mutable option::t[ast::native_abi] abi,
// 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_call_or_bind(&@stmt_ctxt scx, &@ast::expr f,
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_call(&@stmt_ctxt scx, &@ast::expr f, &vec[@ast::expr] args) {
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_call(&@stmt_ctxt scx, &@ast::expr f, &vec[@ast::expr] args) {
}
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_call(&@stmt_ctxt scx, &@ast::expr f, &vec[@ast::expr] args) {
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_call(&@stmt_ctxt scx, &@ast::expr f, &vec[@ast::expr] args) {
// 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_call(&@stmt_ctxt scx, &@ast::expr f, &vec[@ast::expr] args) {
}
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);
}
......
......@@ -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);
}
......
......@@ -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 get_span(&ast::ty_field f) -> common::span {
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_arg(ps s, &ast::ty_arg input) {
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);
}
}
......
......@@ -45,6 +45,11 @@
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"; }
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册