parent
75eee8b194
commit
3abe3671bd
9 changed files with 74 additions and 38 deletions
|
@ -55,8 +55,11 @@ fn parse_ty_data(data: @[u8], crate_num: int, pos: uint, len: uint,
|
||||||
fn parse_ret_ty(st: @pstate, sd: str_def) -> (ast::ret_style, ty::t) {
|
fn parse_ret_ty(st: @pstate, sd: str_def) -> (ast::ret_style, ty::t) {
|
||||||
alt peek(st) as char {
|
alt peek(st) as char {
|
||||||
'!' { next(st); (ast::noreturn, ty::mk_bot(st.tcx)) }
|
'!' { next(st); (ast::noreturn, ty::mk_bot(st.tcx)) }
|
||||||
'&' { next(st); (ast::return_ref(false), parse_ty(st, sd)) }
|
'&' | '^' {
|
||||||
'^' { next(st); (ast::return_ref(true), parse_ty(st, sd)) }
|
let mut = next(st) == '^' as u8;
|
||||||
|
let arg = next(st) as uint;
|
||||||
|
(ast::return_ref(mut, arg), parse_ty(st, sd))
|
||||||
|
}
|
||||||
_ { (ast::return_val, parse_ty(st, sd)) }
|
_ { (ast::return_val, parse_ty(st, sd)) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -220,8 +220,9 @@ fn enc_ty_fn(w: io::writer, cx: @ctxt, args: [ty::arg], out: ty::t,
|
||||||
}
|
}
|
||||||
alt cf {
|
alt cf {
|
||||||
noreturn. { w.write_char('!'); }
|
noreturn. { w.write_char('!'); }
|
||||||
return_ref(mut) {
|
return_ref(mut, arg) {
|
||||||
w.write_char(mut ? '^' : '&');
|
w.write_char(mut ? '^' : '&');
|
||||||
|
w.write_bytes([arg as u8]);
|
||||||
enc_ty(w, cx, out);
|
enc_ty(w, cx, out);
|
||||||
}
|
}
|
||||||
_ { enc_ty(w, cx, out); }
|
_ { enc_ty(w, cx, out); }
|
||||||
|
|
|
@ -22,8 +22,10 @@ type binding = @{node_id: node_id,
|
||||||
unsafe_tys: [ty::t],
|
unsafe_tys: [ty::t],
|
||||||
mutable ok: valid,
|
mutable ok: valid,
|
||||||
mutable copied: copied};
|
mutable copied: copied};
|
||||||
|
|
||||||
|
tag ret_info { by_ref(bool, node_id); other; }
|
||||||
// FIXME it may be worthwhile to use a linked list of bindings instead
|
// FIXME it may be worthwhile to use a linked list of bindings instead
|
||||||
type scope = {bs: [binding], ret_style: ast::ret_style};
|
type scope = {bs: [binding], ret_info: ret_info};
|
||||||
|
|
||||||
fn mk_binding(cx: ctx, id: node_id, span: span, root_var: option::t<node_id>,
|
fn mk_binding(cx: ctx, id: node_id, span: span, root_var: option::t<node_id>,
|
||||||
unsafe: [ty::t]) -> binding {
|
unsafe: [ty::t]) -> binding {
|
||||||
|
@ -49,8 +51,7 @@ fn check_crate(tcx: ty::ctxt, crate: @ast::crate) -> copy_map {
|
||||||
visit_expr: bind visit_expr(cx, _, _, _),
|
visit_expr: bind visit_expr(cx, _, _, _),
|
||||||
visit_block: bind visit_block(cx, _, _, _)
|
visit_block: bind visit_block(cx, _, _, _)
|
||||||
with *visit::default_visitor::<scope>()};
|
with *visit::default_visitor::<scope>()};
|
||||||
visit::visit_crate(*crate, {bs: [], ret_style: ast::return_val},
|
visit::visit_crate(*crate, {bs: [], ret_info: other}, visit::mk_vt(v));
|
||||||
visit::mk_vt(v));
|
|
||||||
tcx.sess.abort_if_errors();
|
tcx.sess.abort_if_errors();
|
||||||
ret cx.copy_map;
|
ret cx.copy_map;
|
||||||
}
|
}
|
||||||
|
@ -70,7 +71,11 @@ fn visit_fn(cx: @ctx, f: ast::_fn, _tp: [ast::ty_param], _sp: span,
|
||||||
"reference-returning functions may not " +
|
"reference-returning functions may not " +
|
||||||
"return implicitly");
|
"return implicitly");
|
||||||
}
|
}
|
||||||
v.visit_block(f.body, {bs: bs, ret_style: f.decl.cf}, v);
|
let ret_info = alt f.decl.cf {
|
||||||
|
ast::return_ref(mut, n_arg) { by_ref(mut, f.decl.inputs[n_arg].id) }
|
||||||
|
_ { other }
|
||||||
|
};
|
||||||
|
v.visit_block(f.body, {bs: bs, ret_info: ret_info}, v);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_expr(cx: @ctx, ex: @ast::expr, sc: scope, v: vt<scope>) {
|
fn visit_expr(cx: @ctx, ex: @ast::expr, sc: scope, v: vt<scope>) {
|
||||||
|
@ -117,9 +122,9 @@ fn visit_expr(cx: @ctx, ex: @ast::expr, sc: scope, v: vt<scope>) {
|
||||||
}
|
}
|
||||||
ast::expr_ret(oexpr) {
|
ast::expr_ret(oexpr) {
|
||||||
if !is_none(oexpr) {
|
if !is_none(oexpr) {
|
||||||
alt sc.ret_style {
|
alt sc.ret_info {
|
||||||
ast::return_ref(mut) {
|
by_ref(mut, arg_node_id) {
|
||||||
check_ret_ref(*cx, sc, mut, option::get(oexpr));
|
check_ret_ref(*cx, sc, mut, arg_node_id, option::get(oexpr));
|
||||||
}
|
}
|
||||||
_ {}
|
_ {}
|
||||||
}
|
}
|
||||||
|
@ -180,15 +185,14 @@ fn add_bindings_for_let(cx: ctx, &bs: [binding], loc: @ast::local) {
|
||||||
alt root.ex.node {
|
alt root.ex.node {
|
||||||
ast::expr_call(f, args) {
|
ast::expr_call(f, args) {
|
||||||
let fty = ty::type_autoderef(cx.tcx, ty::expr_ty(cx.tcx, f));
|
let fty = ty::type_autoderef(cx.tcx, ty::expr_ty(cx.tcx, f));
|
||||||
let ret_style = ty::ty_fn_ret_style(cx.tcx, fty);
|
alt ty::ty_fn_ret_style(cx.tcx, fty) {
|
||||||
if ast_util::ret_by_ref(ret_style) {
|
ast::return_ref(mut, arg_n) {
|
||||||
// FIXME pick right arg
|
let arg = args[arg_n];
|
||||||
let arg = args[0];
|
|
||||||
let arg_root = expr_root(cx.tcx, arg, false);
|
let arg_root = expr_root(cx.tcx, arg, false);
|
||||||
root_var = path_def_id(cx, arg_root.ex);
|
root_var = path_def_id(cx, arg_root.ex);
|
||||||
if !is_none(root_var) {
|
if !is_none(root_var) {
|
||||||
is_temp = false;
|
is_temp = false;
|
||||||
if ret_style == ast::return_ref(true) {
|
if mut {
|
||||||
outer_ds = [@{mut: true, kind: unbox,
|
outer_ds = [@{mut: true, kind: unbox,
|
||||||
outer_t: ty::expr_ty(cx.tcx, arg)}];
|
outer_t: ty::expr_ty(cx.tcx, arg)}];
|
||||||
}
|
}
|
||||||
|
@ -196,6 +200,7 @@ fn add_bindings_for_let(cx: ctx, &bs: [binding], loc: @ast::local) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
_ {}
|
_ {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -333,12 +338,13 @@ fn check_call(cx: ctx, f: @ast::expr, args: [@ast::expr]) -> [binding] {
|
||||||
ret bindings;
|
ret bindings;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_ret_ref(cx: ctx, sc: scope, mut: bool, expr: @ast::expr) {
|
fn check_ret_ref(cx: ctx, sc: scope, mut: bool, arg_node_id: node_id,
|
||||||
|
expr: @ast::expr) {
|
||||||
let root = expr_root(cx.tcx, expr, false);
|
let root = expr_root(cx.tcx, expr, false);
|
||||||
let bad = none;
|
let bad = none;
|
||||||
let mut_field = mut_field(root.ds);
|
let mut_field = mut_field(root.ds);
|
||||||
alt path_def(cx, root.ex) {
|
alt path_def(cx, root.ex) {
|
||||||
none. { bad = some("temporary"); }
|
none. { bad = some("a temporary"); }
|
||||||
some(ast::def_local(did, _)) | some(ast::def_binding(did)) |
|
some(ast::def_local(did, _)) | some(ast::def_binding(did)) |
|
||||||
some(ast::def_arg(did, _)) {
|
some(ast::def_arg(did, _)) {
|
||||||
let cur_node = did.node;
|
let cur_node = did.node;
|
||||||
|
@ -346,7 +352,10 @@ fn check_ret_ref(cx: ctx, sc: scope, mut: bool, expr: @ast::expr) {
|
||||||
alt cx.tcx.items.find(cur_node) {
|
alt cx.tcx.items.find(cur_node) {
|
||||||
some(ast_map::node_arg(arg, _)) {
|
some(ast_map::node_arg(arg, _)) {
|
||||||
if arg.mode == ast::by_move {
|
if arg.mode == ast::by_move {
|
||||||
bad = some("move-mode parameter");
|
bad = some("a move-mode parameter");
|
||||||
|
}
|
||||||
|
if cur_node != arg_node_id {
|
||||||
|
bad = some("the wrong parameter");
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -359,31 +368,30 @@ fn check_ret_ref(cx: ctx, sc: scope, mut: bool, expr: @ast::expr) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if is_none(b.root_var) {
|
if is_none(b.root_var) {
|
||||||
bad = some("function-local value");
|
bad = some("a function-local value");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if b.copied == copied {
|
if b.copied == copied {
|
||||||
bad = some("implicitly copied reference");
|
bad = some("an implicitly copied reference");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
b.copied = not_allowed;
|
b.copied = not_allowed;
|
||||||
cur_node = option::get(b.root_var);
|
cur_node = option::get(b.root_var);
|
||||||
}
|
}
|
||||||
none. {
|
none. {
|
||||||
bad = some("function-local value");
|
bad = some("a function-local value");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// FIXME allow references to constants and static items?
|
_ { bad = some("a non-local value"); }
|
||||||
_ { bad = some("non-local value"); }
|
|
||||||
}
|
}
|
||||||
if mut_field && !mut { bad = some("mutable field"); }
|
if mut_field && !mut { bad = some("a mutable field"); }
|
||||||
alt bad {
|
alt bad {
|
||||||
some(name) {
|
some(name) {
|
||||||
cx.tcx.sess.span_err(expr.span, "can not return a reference " +
|
cx.tcx.sess.span_err(expr.span, "can not return a reference to " +
|
||||||
"to a " + name);
|
name);
|
||||||
}
|
}
|
||||||
_ {}
|
_ {}
|
||||||
}
|
}
|
||||||
|
@ -402,8 +410,7 @@ fn check_alt(cx: ctx, input: @ast::expr, arms: [ast::arm], sc: scope,
|
||||||
for pat in a.pats {
|
for pat in a.pats {
|
||||||
for proot in *pattern_roots(cx.tcx, *root.ds, pat) {
|
for proot in *pattern_roots(cx.tcx, *root.ds, pat) {
|
||||||
let canon_id = pat_id_map.get(proot.name);
|
let canon_id = pat_id_map.get(proot.name);
|
||||||
// FIXME I wanted to use a block, but that hit a
|
// FIXME I wanted to use a block here, but that hit bug #913
|
||||||
// typestate bug.
|
|
||||||
fn match(x: info, canon: node_id) -> bool { x.id == canon }
|
fn match(x: info, canon: node_id) -> bool { x.id == canon }
|
||||||
alt vec::find(bind match(_, canon_id), binding_info) {
|
alt vec::find(bind match(_, canon_id), binding_info) {
|
||||||
some(s) { s.unsafe += inner_mut(proot.ds); }
|
some(s) { s.unsafe += inner_mut(proot.ds); }
|
||||||
|
|
|
@ -2459,7 +2459,10 @@ fn type_err_to_str(err: ty::type_err) -> str {
|
||||||
alt s {
|
alt s {
|
||||||
ast::noreturn. { "non-returning" }
|
ast::noreturn. { "non-returning" }
|
||||||
ast::return_val. { "return-by-value" }
|
ast::return_val. { "return-by-value" }
|
||||||
ast::return_ref(_) { "return-by-reference" }
|
ast::return_ref(mut, arg) {
|
||||||
|
#fmt("return-by-%sreference on arg %u",
|
||||||
|
mut ? "mutable-" : "", arg)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ret to_str(actual) + " function found where " + to_str(expect) +
|
ret to_str(actual) + " function found where " + to_str(expect) +
|
||||||
|
|
|
@ -383,7 +383,7 @@ tag ret_style {
|
||||||
noreturn; // functions with return type _|_ that always
|
noreturn; // functions with return type _|_ that always
|
||||||
// raise an error or exit (i.e. never return to the caller)
|
// raise an error or exit (i.e. never return to the caller)
|
||||||
return_val; // everything else
|
return_val; // everything else
|
||||||
return_ref(bool);
|
return_ref(bool, uint);
|
||||||
}
|
}
|
||||||
|
|
||||||
type _fn = {decl: fn_decl, proto: proto, body: blk};
|
type _fn = {decl: fn_decl, proto: proto, body: blk};
|
||||||
|
|
|
@ -215,7 +215,7 @@ fn ternary_to_if(e: @expr) -> @expr {
|
||||||
|
|
||||||
fn ret_by_ref(style: ret_style) -> bool {
|
fn ret_by_ref(style: ret_style) -> bool {
|
||||||
alt style {
|
alt style {
|
||||||
return_ref(_) { true }
|
return_ref(_, _) { true }
|
||||||
_ { false }
|
_ { false }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -285,7 +285,7 @@ fn parse_ty_fn(proto: ast::proto, p: parser) -> ast::ty_ {
|
||||||
// FIXME: there's no syntax for this right now anyway
|
// FIXME: there's no syntax for this right now anyway
|
||||||
// auto constrs = parse_constrs(~[], p);
|
// auto constrs = parse_constrs(~[], p);
|
||||||
let constrs: [@ast::constr] = [];
|
let constrs: [@ast::constr] = [];
|
||||||
let (ret_style, ret_ty) = parse_ret_ty(p);
|
let (ret_style, ret_ty) = parse_ret_ty(p, vec::len(inputs.node));
|
||||||
ret ast::ty_fn(proto, inputs.node, ret_ty, ret_style, constrs);
|
ret ast::ty_fn(proto, inputs.node, ret_ty, ret_style, constrs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -437,7 +437,7 @@ fn parse_ty_postfix(orig_t: ast::ty_, p: parser, colons_before_params: bool)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_ret_ty(p: parser) -> (ast::ret_style, @ast::ty) {
|
fn parse_ret_ty(p: parser, n_args: uint) -> (ast::ret_style, @ast::ty) {
|
||||||
ret if eat(p, token::RARROW) {
|
ret if eat(p, token::RARROW) {
|
||||||
let lo = p.get_lo_pos();
|
let lo = p.get_lo_pos();
|
||||||
if eat(p, token::NOT) {
|
if eat(p, token::NOT) {
|
||||||
|
@ -445,7 +445,20 @@ fn parse_ret_ty(p: parser) -> (ast::ret_style, @ast::ty) {
|
||||||
} else {
|
} else {
|
||||||
let style = ast::return_val;
|
let style = ast::return_val;
|
||||||
if eat(p, token::BINOP(token::AND)) {
|
if eat(p, token::BINOP(token::AND)) {
|
||||||
style = ast::return_ref(eat(p, token::NOT));
|
if n_args == 0u {
|
||||||
|
p.fatal("can not return reference from argument-less fn");
|
||||||
|
}
|
||||||
|
let mut_root = eat(p, token::NOT), arg = 0u;
|
||||||
|
alt p.peek() {
|
||||||
|
token::LIT_INT(val) { p.bump(); arg = val as uint; }
|
||||||
|
_ { if n_args > 1u {
|
||||||
|
p.fatal("must specify referenced parameter");
|
||||||
|
} }
|
||||||
|
}
|
||||||
|
if arg >= n_args {
|
||||||
|
p.fatal("referenced argument does not exist");
|
||||||
|
}
|
||||||
|
style = ast::return_ref(mut_root, arg);
|
||||||
};
|
};
|
||||||
(style, parse_ty(p, false))
|
(style, parse_ty(p, false))
|
||||||
}
|
}
|
||||||
|
@ -1734,7 +1747,7 @@ fn parse_fn_decl(p: parser, purity: ast::purity, il: ast::inlineness) ->
|
||||||
p.bump();
|
p.bump();
|
||||||
constrs = parse_constrs(bind parse_ty_constr(inputs.node, _), p);
|
constrs = parse_constrs(bind parse_ty_constr(inputs.node, _), p);
|
||||||
}
|
}
|
||||||
let (ret_style, ret_ty) = parse_ret_ty(p);
|
let (ret_style, ret_ty) = parse_ret_ty(p, vec::len(inputs.node));
|
||||||
ret {inputs: inputs.node,
|
ret {inputs: inputs.node,
|
||||||
output: ret_ty,
|
output: ret_ty,
|
||||||
purity: purity,
|
purity: purity,
|
||||||
|
|
|
@ -1145,7 +1145,12 @@ fn print_fn_args_and_ret(s: ps, decl: ast::fn_decl, constrs: [@ast::constr]) {
|
||||||
space_if_not_bol(s);
|
space_if_not_bol(s);
|
||||||
word_space(s, "->");
|
word_space(s, "->");
|
||||||
alt decl.cf {
|
alt decl.cf {
|
||||||
ast::return_ref(mut) { word(s.s, mut ? "&!" : "&"); }
|
ast::return_ref(mut, arg) {
|
||||||
|
word(s.s, mut ? "&!" : "&");
|
||||||
|
if vec::len(decl.inputs) > 1u {
|
||||||
|
word(s.s, std::uint::str(arg));
|
||||||
|
}
|
||||||
|
}
|
||||||
_ {}
|
_ {}
|
||||||
}
|
}
|
||||||
print_type(s, decl.output);
|
print_type(s, decl.output);
|
||||||
|
@ -1347,7 +1352,10 @@ fn print_ty_fn(s: ps, proto: ast::proto, id: option::t<ast::ident>,
|
||||||
word_nbsp(s, "!");
|
word_nbsp(s, "!");
|
||||||
} else {
|
} else {
|
||||||
alt cf {
|
alt cf {
|
||||||
ast::return_ref(mut) { word(s.s, mut ? "&!" : "&"); }
|
ast::return_ref(mut, arg) {
|
||||||
|
word(s.s, mut ? "&!" : "&");
|
||||||
|
if vec::len(inputs) > 1u { word(s.s, std::uint::str(arg)); }
|
||||||
|
}
|
||||||
_ {}
|
_ {}
|
||||||
}
|
}
|
||||||
print_type(s, output);
|
print_type(s, output);
|
||||||
|
|
|
@ -61,8 +61,9 @@ fn ty_to_str(cx: ctxt, typ: t) -> str {
|
||||||
s += " -> ";
|
s += " -> ";
|
||||||
alt cf {
|
alt cf {
|
||||||
ast::noreturn. { s += "!"; }
|
ast::noreturn. { s += "!"; }
|
||||||
ast::return_ref(mut) {
|
ast::return_ref(mut, arg) {
|
||||||
s += mut ? "&!" : "&";
|
s += mut ? "&!" : "&";
|
||||||
|
if vec::len(inputs) > 1u { s += std::uint::str(arg); }
|
||||||
s += ty_to_str(cx, output);
|
s += ty_to_str(cx, output);
|
||||||
}
|
}
|
||||||
ast::return_val. { s += ty_to_str(cx, output); }
|
ast::return_val. { s += ty_to_str(cx, output); }
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue