Change convention for specifying referenced argument

It is now 1-based, rather than 0 based. (Seems more natural, and allows 0 to
be used to refer to self and maybe to closure.)

Also allows non-referenced args to be implicitly copied again.

Issue #918
This commit is contained in:
Marijn Haverbeke 2011-09-16 12:42:18 +02:00
parent 059b31f7a3
commit d7587c1eda
5 changed files with 34 additions and 22 deletions

View File

@ -72,7 +72,9 @@ fn visit_fn(cx: @ctx, f: ast::_fn, _tp: [ast::ty_param], _sp: span,
"return implicitly");
}
let ret_info = alt f.decl.cf {
ast::return_ref(mut, n_arg) { by_ref(mut, f.decl.inputs[n_arg].id) }
ast::return_ref(mut, n_arg) {
by_ref(mut, f.decl.inputs[n_arg - 1u].id)
}
_ { other }
};
v.visit_block(f.body, {bs: bs, ret_info: ret_info}, v);
@ -220,7 +222,9 @@ fn cant_copy(cx: ctx, b: binding) -> bool {
fn check_call(cx: ctx, f: @ast::expr, args: [@ast::expr]) -> [binding] {
let fty = ty::type_autoderef(cx.tcx, ty::expr_ty(cx.tcx, f));
let ret_ref = ast_util::ret_by_ref(ty::ty_fn_ret_style(cx.tcx, fty));
let by_ref = alt ty::ty_fn_ret_style(cx.tcx, fty) {
ast::return_ref(_, arg_n) { arg_n } _ { 0u }
};
let arg_ts = ty::ty_fn_args(cx.tcx, fty);
let mut_roots: [{arg: uint, node: node_id}] = [];
let bindings = [];
@ -246,7 +250,9 @@ fn check_call(cx: ctx, f: @ast::expr, args: [@ast::expr]) -> [binding] {
mutable ok: valid,
mutable copied: alt arg_t.mode {
ast::by_move. { copied }
ast::by_ref. { ret_ref ? not_allowed : not_copied }
ast::by_ref. {
i + 1u == by_ref ? not_allowed : not_copied
}
ast::by_mut_ref. { not_allowed }
}}];
i += 1u;
@ -683,7 +689,7 @@ fn expr_root(cx: ctx, ex: @ast::expr, autoderef: bool) ->
let fty = ty::type_autoderef(cx.tcx, ty::expr_ty(cx.tcx, f));
alt ty::ty_fn_ret_style(cx.tcx, fty) {
ast::return_ref(mut, arg_n) {
let arg = args[arg_n];
let arg = args[arg_n - 1u];
let arg_root = expr_root(cx, arg, false);
ret {ex: arg_root.ex,
ds: @(*arg_root.ds +

View File

@ -3557,9 +3557,11 @@ fn trans_arg_expr(cx: @block_ctxt, arg: ty::arg, lldestty0: TypeRef,
// - create_llargs_for_fn_args.
// - new_fn_ctxt
// - trans_args
fn trans_args(cx: @block_ctxt, llenv: ValueRef, gen: option::t<generic_info>,
fn trans_args(cx: @block_ctxt, outer_cx: @block_ctxt, llenv: ValueRef,
gen: option::t<generic_info>,
lliterbody: option::t<ValueRef>, es: [@ast::expr], fn_ty: ty::t)
-> {bcx: @block_ctxt,
outer_cx: @block_ctxt,
args: [ValueRef],
retslot: ValueRef,
to_zero: [{v: ValueRef, t: ty::t}],
@ -3574,7 +3576,8 @@ fn trans_args(cx: @block_ctxt, llenv: ValueRef, gen: option::t<generic_info>,
let ccx = bcx_ccx(cx);
let tcx = ccx.tcx;
let bcx: @block_ctxt = cx;
let by_ref = ast_util::ret_by_ref(ty::ty_fn_ret_style(tcx, fn_ty));
let ret_style = ty::ty_fn_ret_style(tcx, fn_ty);
let by_ref = ast_util::ret_by_ref(ret_style);
// Arg 0: Output pointer.
// FIXME: test case looks like
@ -3583,6 +3586,7 @@ fn trans_args(cx: @block_ctxt, llenv: ValueRef, gen: option::t<generic_info>,
// This means an earlier arg was divergent.
// So this arg can't be evaluated.
ret {bcx: bcx,
outer_cx: outer_cx,
args: [],
retslot: C_nil(),
to_zero: to_zero,
@ -3652,13 +3656,18 @@ fn trans_args(cx: @block_ctxt, llenv: ValueRef, gen: option::t<generic_info>,
// So this arg can't be evaluated.
break;
}
let r =
trans_arg_expr(bcx, args[i], arg_tys[i], to_zero, to_revoke, e);
bcx = r.bcx;
let is_referenced = alt ret_style {
ast::return_ref(_, arg_n) { i + 1u == arg_n }
_ { false }
};
let r = trans_arg_expr(is_referenced ? outer_cx : bcx,
args[i], arg_tys[i], to_zero, to_revoke, e);
if is_referenced { outer_cx = r.bcx; } else { bcx = r.bcx; }
llargs += [r.val];
i += 1u;
}
ret {bcx: bcx,
outer_cx: outer_cx,
args: llargs,
retslot: llretslot,
to_zero: to_zero,
@ -3675,14 +3684,7 @@ fn trans_call(in_cx: @block_ctxt, f: @ast::expr,
let fn_ty = ty::type_autoderef(bcx_tcx(in_cx), fn_expr_ty);
let by_ref = ast_util::ret_by_ref(ty::ty_fn_ret_style(bcx_tcx(in_cx),
fn_ty));
// Things that return by reference must put their arguments (FIXME only
// the referenced arguments) into the outer scope, so that they are still
// alive when the return value is used.
let cx = if by_ref { in_cx } else {
let cx = new_scope_block_ctxt(in_cx, "call");
Br(in_cx, cx.llbb);
cx
};
let cx = new_scope_block_ctxt(in_cx, "call");
let f_res = trans_lval_gen(cx, f);
let bcx = f_res.res.bcx;
@ -3710,7 +3712,8 @@ fn trans_call(in_cx: @block_ctxt, f: @ast::expr,
let ret_ty = ty::node_id_to_type(bcx_tcx(cx), id);
let args_res =
trans_args(bcx, llenv, f_res.generic, lliterbody, args, fn_ty);
trans_args(bcx, in_cx, llenv, f_res.generic, lliterbody, args, fn_ty);
Br(args_res.outer_cx, cx.llbb);
bcx = args_res.bcx;
let llargs = args_res.args;
let llretslot = args_res.retslot;

View File

@ -448,16 +448,19 @@ fn parse_ret_ty(p: parser, n_args: uint) -> (ast::ret_style, @ast::ty) {
if n_args == 0u {
p.fatal("can not return reference from argument-less fn");
}
let mut_root = eat(p, token::NOT), arg = 0u;
let mut_root = eat(p, token::NOT), arg = 1u;
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 {
if arg > n_args {
p.fatal("referenced argument does not exist");
}
if arg == 0u {
p.fatal("referenced argument can't be 0");
}
style = ast::return_ref(mut_root, arg);
};
(style, parse_ty(p, false))

View File

@ -1,6 +1,6 @@
// error-pattern:can not return a reference to the wrong parameter
fn f(a: int, b: int) -> &1 int {
fn f(a: int, b: int) -> &2 int {
ret a;
}

View File

@ -6,7 +6,7 @@ fn get<@T>(opt: option<T>) -> &T {
}
}
fn get_mut(a: {mutable x: @int}, _b: int) -> &!0 @int {
fn get_mut(a: {mutable x: @int}, _b: int) -> &!1 @int {
ret a.x;
}