Rollback return-by-reference
It's proving too inflexible, so I'm ripping out the extra complexity in the hope that regions will, at some point, provide something similar. Closes #918
This commit is contained in:
parent
acbc4aa9f8
commit
9fb3719ded
23 changed files with 50 additions and 370 deletions
|
@ -55,11 +55,6 @@ 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) {
|
||||
alt peek(st) as char {
|
||||
'!' { next(st); (ast::noreturn, ty::mk_bot(st.tcx)) }
|
||||
'&' | '^' {
|
||||
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)) }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -214,11 +214,6 @@ fn enc_ty_fn(w: io::writer, cx: @ctxt, args: [ty::arg], out: ty::t,
|
|||
}
|
||||
alt cf {
|
||||
noreturn. { w.write_char('!'); }
|
||||
return_ref(mut, arg) {
|
||||
w.write_char(mut ? '^' : '&');
|
||||
w.write_bytes([arg as u8]);
|
||||
enc_ty(w, cx, out);
|
||||
}
|
||||
_ { enc_ty(w, cx, out); }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,10 +28,8 @@ type binding = @{node_id: node_id,
|
|||
unsafe_tys: [unsafe_ty],
|
||||
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
|
||||
type scope = {bs: [binding],
|
||||
ret_info: ret_info,
|
||||
invalid: @mutable list<@invalid>};
|
||||
|
||||
fn mk_binding(cx: ctx, id: node_id, span: span, root_var: option::t<node_id>,
|
||||
|
@ -67,7 +65,7 @@ fn check_crate(tcx: ty::ctxt, crate: @ast::crate) -> (copy_map, ref_map) {
|
|||
visit_expr: bind visit_expr(cx, _, _, _),
|
||||
visit_block: bind visit_block(cx, _, _, _)
|
||||
with *visit::default_visitor::<scope>()};
|
||||
let sc = {bs: [], ret_info: other, invalid: @mutable list::nil};
|
||||
let sc = {bs: [], invalid: @mutable list::nil};
|
||||
visit::visit_crate(*crate, sc, visit::mk_vt(v));
|
||||
tcx.sess.abort_if_errors();
|
||||
ret (cx.copy_map, cx.ref_map);
|
||||
|
@ -84,24 +82,12 @@ fn visit_fn(cx: @ctx, f: ast::_fn, _tp: [ast::ty_param], sp: span,
|
|||
}
|
||||
}
|
||||
|
||||
if ast_util::ret_by_ref(f.decl.cf) && !is_none(f.body.node.expr) {
|
||||
// FIXME this will be easier to lift once have DPS
|
||||
err(*cx, option::get(f.body.node.expr).span,
|
||||
"reference-returning functions may not return implicitly");
|
||||
}
|
||||
let ret_info = alt f.decl.cf {
|
||||
ast::return_ref(mut, n_arg) {
|
||||
by_ref(mut, f.decl.inputs[n_arg - 1u].id)
|
||||
}
|
||||
_ { other }
|
||||
};
|
||||
// Blocks need to obey any restrictions from the enclosing scope, and may
|
||||
// be called multiple times.
|
||||
if f.proto == ast::proto_block {
|
||||
let sc = {ret_info: ret_info with sc};
|
||||
check_loop(*cx, sc) {|| v.visit_block(f.body, sc, v);}
|
||||
} else {
|
||||
let sc = {bs: [], ret_info: ret_info, invalid: @mutable list::nil};
|
||||
let sc = {bs: [], invalid: @mutable list::nil};
|
||||
v.visit_block(f.body, sc, v);
|
||||
}
|
||||
}
|
||||
|
@ -134,17 +120,6 @@ fn visit_expr(cx: @ctx, ex: @ast::expr, sc: scope, v: vt<scope>) {
|
|||
ast::expr_assign(dest, src) | ast::expr_assign_op(_, dest, src) {
|
||||
check_assign(cx, dest, src, sc, v);
|
||||
}
|
||||
ast::expr_ret(oexpr) {
|
||||
if !is_none(oexpr) {
|
||||
alt sc.ret_info {
|
||||
by_ref(mut, arg_node_id) {
|
||||
check_ret_ref(*cx, sc, mut, arg_node_id, option::get(oexpr));
|
||||
}
|
||||
_ {}
|
||||
}
|
||||
}
|
||||
handled = false;
|
||||
}
|
||||
ast::expr_if(c, then, els) { check_if(c, then, els, sc, v); }
|
||||
ast::expr_while(_, _) | ast::expr_do_while(_, _) {
|
||||
check_loop(*cx, sc) {|| visit::visit_expr(ex, sc, v); }
|
||||
|
@ -237,9 +212,6 @@ fn cant_copy(cx: ctx, b: binding) -> bool {
|
|||
fn check_call(cx: ctx, sc: scope, f: @ast::expr, args: [@ast::expr])
|
||||
-> [binding] {
|
||||
let fty = ty::expr_ty(cx.tcx, f);
|
||||
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 = [];
|
||||
|
@ -265,7 +237,7 @@ fn check_call(cx: ctx, sc: scope, f: @ast::expr, args: [@ast::expr])
|
|||
mutable copied: alt arg_t.mode {
|
||||
ast::by_move. | ast::by_copy. { copied }
|
||||
ast::by_mut_ref. { not_allowed }
|
||||
_ { i + 1u == by_ref ? not_allowed : not_copied }
|
||||
_ { not_copied }
|
||||
}}];
|
||||
i += 1u;
|
||||
}
|
||||
|
@ -338,69 +310,6 @@ fn check_call(cx: ctx, sc: scope, f: @ast::expr, args: [@ast::expr])
|
|||
ret bindings;
|
||||
}
|
||||
|
||||
fn check_ret_ref(cx: ctx, sc: scope, mut: bool, arg_node_id: node_id,
|
||||
expr: @ast::expr) {
|
||||
let root = expr_root(cx, expr, false);
|
||||
let bad = none;
|
||||
let mut_field = !is_none(root.mut);
|
||||
alt path_def(cx, root.ex) {
|
||||
none. {
|
||||
bad = some("a temporary");
|
||||
}
|
||||
some(ast::def_local(did, _)) | some(ast::def_binding(did)) |
|
||||
some(ast::def_arg(did, _)) {
|
||||
let cur_node = did.node;
|
||||
while true {
|
||||
alt cx.tcx.items.find(cur_node) {
|
||||
some(ast_map::node_arg(arg, _)) {
|
||||
if arg.mode == ast::by_move {
|
||||
bad = some("a move-mode parameter");
|
||||
}
|
||||
if arg.mode == ast::by_copy {
|
||||
bad = some("a copy-mode parameter");
|
||||
}
|
||||
if cur_node != arg_node_id {
|
||||
bad = some("the wrong parameter");
|
||||
}
|
||||
break;
|
||||
}
|
||||
_ {}
|
||||
}
|
||||
alt vec::find({|b| b.node_id == cur_node}, sc.bs) {
|
||||
some(b) {
|
||||
if vec::len(b.unsafe_tys) > 0u {
|
||||
mut_field = true;
|
||||
break;
|
||||
}
|
||||
if is_none(b.root_var) {
|
||||
bad = some("a function-local value");
|
||||
break;
|
||||
}
|
||||
if b.copied == copied {
|
||||
bad = some("an implicitly copied reference");
|
||||
break;
|
||||
}
|
||||
b.copied = not_allowed;
|
||||
cur_node = option::get(b.root_var);
|
||||
}
|
||||
none. {
|
||||
bad = some("a function-local value");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
_ { bad = some("a non-local value"); }
|
||||
}
|
||||
if mut_field && !mut { bad = some("a mutable field"); }
|
||||
alt bad {
|
||||
some(name) {
|
||||
err(cx, expr.span, "can not return a reference to " + name);
|
||||
}
|
||||
_ {}
|
||||
}
|
||||
}
|
||||
|
||||
fn check_alt(cx: ctx, input: @ast::expr, arms: [ast::arm], sc: scope,
|
||||
v: vt<scope>) {
|
||||
v.visit_expr(input, sc, v);
|
||||
|
@ -733,22 +642,6 @@ fn expr_root(cx: ctx, ex: @ast::expr, autoderef: bool)
|
|||
_ {}
|
||||
}
|
||||
}
|
||||
ast::expr_call(f, args, _) {
|
||||
let fty = 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 - 1u];
|
||||
let arg_root = expr_root(cx, arg, false);
|
||||
if mut {
|
||||
let ret_ty = ty::expr_ty(cx.tcx, base_root.ex);
|
||||
unsafe_ty = some(mut_contains(ret_ty));
|
||||
}
|
||||
if !is_none(arg_root.mut) { unsafe_ty = arg_root.mut; }
|
||||
ret {ex: arg_root.ex, mut: unsafe_ty};
|
||||
}
|
||||
_ {}
|
||||
}
|
||||
}
|
||||
_ {}
|
||||
}
|
||||
ret {ex: base_root.ex, mut: unsafe_ty};
|
||||
|
|
|
@ -30,19 +30,16 @@ type rval_map = std::map::hashmap<node_id, ()>;
|
|||
|
||||
type ctx = {tcx: ty::ctxt,
|
||||
rval_map: rval_map,
|
||||
last_uses: last_use::last_uses,
|
||||
mutable ret_by_ref: bool};
|
||||
last_uses: last_use::last_uses};
|
||||
|
||||
fn check_crate(tcx: ty::ctxt, last_uses: last_use::last_uses,
|
||||
crate: @crate) -> rval_map {
|
||||
let ctx = {tcx: tcx,
|
||||
rval_map: std::map::new_int_hash(),
|
||||
last_uses: last_uses,
|
||||
mutable ret_by_ref: false};
|
||||
last_uses: last_uses};
|
||||
let visit = visit::mk_vt(@{
|
||||
visit_expr: check_expr,
|
||||
visit_stmt: check_stmt,
|
||||
visit_fn: visit_fn
|
||||
visit_stmt: check_stmt
|
||||
with *visit::default_visitor()
|
||||
});
|
||||
visit::visit_crate(*crate, ctx, visit);
|
||||
|
@ -55,7 +52,7 @@ fn check_expr(e: @expr, cx: ctx, v: visit::vt<ctx>) {
|
|||
expr_assign(_, ex) | expr_assign_op(_, _, ex) |
|
||||
expr_block({node: {expr: some(ex), _}, _}) |
|
||||
expr_unary(box(_), ex) | expr_unary(uniq(_), ex) { maybe_copy(cx, ex); }
|
||||
expr_ret(some(ex)) { if !cx.ret_by_ref { maybe_copy(cx, ex); } }
|
||||
expr_ret(some(ex)) { maybe_copy(cx, ex); }
|
||||
expr_copy(expr) { check_copy_ex(cx, expr, false); }
|
||||
// Vector add copies.
|
||||
expr_binary(add., ls, rs) { maybe_copy(cx, ls); maybe_copy(cx, rs); }
|
||||
|
@ -138,14 +135,6 @@ fn check_stmt(stmt: @stmt, cx: ctx, v: visit::vt<ctx>) {
|
|||
visit::visit_stmt(stmt, cx, v);
|
||||
}
|
||||
|
||||
fn visit_fn(f: _fn, tps: [ty_param], sp: span, ident: fn_ident,
|
||||
id: node_id, cx: ctx, v: visit::vt<ctx>) {
|
||||
let old_ret = cx.ret_by_ref;
|
||||
cx.ret_by_ref = ast_util::ret_by_ref(f.decl.cf);
|
||||
visit::visit_fn(f, tps, sp, ident, id, cx, v);
|
||||
cx.ret_by_ref = old_ret;
|
||||
}
|
||||
|
||||
fn maybe_copy(cx: ctx, ex: @expr) {
|
||||
check_copy_ex(cx, ex, true);
|
||||
}
|
||||
|
|
|
@ -80,14 +80,14 @@ fn type_of_explicit_args(cx: @crate_ctxt, sp: span, inputs: [ty::arg]) ->
|
|||
// - new_fn_ctxt
|
||||
// - trans_args
|
||||
fn type_of_fn(cx: @crate_ctxt, sp: span,
|
||||
is_method: bool, ret_ref: bool, inputs: [ty::arg],
|
||||
is_method: bool, inputs: [ty::arg],
|
||||
output: ty::t, ty_param_count: uint)
|
||||
: non_ty_var(cx, output) -> TypeRef {
|
||||
let atys: [TypeRef] = [];
|
||||
|
||||
// Arg 0: Output pointer.
|
||||
let out_ty = T_ptr(type_of_inner(cx, sp, output));
|
||||
atys += [ret_ref ? T_ptr(out_ty) : out_ty];
|
||||
atys += [out_ty];
|
||||
|
||||
// Arg 1: Env (closure-bindings / self-obj)
|
||||
if is_method {
|
||||
|
@ -108,13 +108,12 @@ fn type_of_fn(cx: @crate_ctxt, sp: span,
|
|||
fn type_of_fn_from_ty(cx: @crate_ctxt, sp: span, fty: ty::t,
|
||||
ty_param_count: uint)
|
||||
: returns_non_ty_var(cx, fty) -> TypeRef {
|
||||
let by_ref = ast_util::ret_by_ref(ty::ty_fn_ret_style(cx.tcx, fty));
|
||||
// FIXME: Check should be unnecessary, b/c it's implied
|
||||
// by returns_non_ty_var(t). Make that a postcondition
|
||||
// (see Issue #586)
|
||||
let ret_ty = ty::ty_fn_ret(cx.tcx, fty);
|
||||
check non_ty_var(cx, ret_ty);
|
||||
ret type_of_fn(cx, sp, false, by_ref, ty::ty_fn_args(cx.tcx, fty),
|
||||
ret type_of_fn(cx, sp, false, ty::ty_fn_args(cx.tcx, fty),
|
||||
ret_ty, ty_param_count);
|
||||
}
|
||||
|
||||
|
@ -3046,11 +3045,10 @@ fn trans_object_field_inner(bcx: @block_ctxt, o: ValueRef,
|
|||
let v = GEPi(bcx, vtbl, [0, ix as int]);
|
||||
let fn_ty: ty::t = ty::method_ty_to_fn_ty(tcx, mths[ix]);
|
||||
let ret_ty = ty::ty_fn_ret(tcx, fn_ty);
|
||||
let ret_ref = ast_util::ret_by_ref(ty::ty_fn_ret_style(tcx, fn_ty));
|
||||
// FIXME: constrain ty_obj?
|
||||
check non_ty_var(ccx, ret_ty);
|
||||
|
||||
let ll_fn_ty = type_of_fn(ccx, bcx.sp, true, ret_ref,
|
||||
let ll_fn_ty = type_of_fn(ccx, bcx.sp, true,
|
||||
ty::ty_fn_args(tcx, fn_ty), ret_ty, 0u);
|
||||
v = Load(bcx, PointerCast(bcx, v, T_ptr(T_ptr(ll_fn_ty))));
|
||||
ret {bcx: bcx, mthptr: v, objptr: o};
|
||||
|
@ -3656,16 +3654,14 @@ 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, outer_cx: @block_ctxt, llenv: ValueRef,
|
||||
fn trans_args(cx: @block_ctxt, llenv: ValueRef,
|
||||
gen: option::t<generic_info>, es: [@ast::expr], fn_ty: ty::t,
|
||||
dest: dest)
|
||||
-> {bcx: @block_ctxt,
|
||||
outer_cx: @block_ctxt,
|
||||
args: [ValueRef],
|
||||
retslot: ValueRef,
|
||||
to_zero: [{v: ValueRef, t: ty::t}],
|
||||
to_revoke: [{v: ValueRef, t: ty::t}],
|
||||
ret_ref: bool} {
|
||||
to_revoke: [{v: ValueRef, t: ty::t}]} {
|
||||
|
||||
let args: [ty::arg] = ty::ty_fn_args(bcx_tcx(cx), fn_ty);
|
||||
let llargs: [ValueRef] = [];
|
||||
|
@ -3676,8 +3672,6 @@ fn trans_args(cx: @block_ctxt, outer_cx: @block_ctxt, llenv: ValueRef,
|
|||
let ccx = bcx_ccx(cx);
|
||||
let tcx = ccx.tcx;
|
||||
let bcx = cx;
|
||||
let ret_style = ty::ty_fn_ret_style(tcx, fn_ty);
|
||||
let ret_ref = ast_util::ret_by_ref(ret_style);
|
||||
|
||||
let retty = ty::ty_fn_ret(tcx, fn_ty), full_retty = retty;
|
||||
alt gen {
|
||||
|
@ -3691,10 +3685,7 @@ fn trans_args(cx: @block_ctxt, outer_cx: @block_ctxt, llenv: ValueRef,
|
|||
}
|
||||
// Arg 0: Output pointer.
|
||||
let llretty = type_of_or_i8(bcx, full_retty);
|
||||
let llretslot = if ret_ref {
|
||||
alloca(cx, T_ptr(llretty))
|
||||
} else {
|
||||
alt dest {
|
||||
let llretslot = alt dest {
|
||||
ignore. {
|
||||
if ty::type_is_nil(tcx, retty) {
|
||||
llvm::LLVMGetUndef(T_ptr(llretty))
|
||||
|
@ -3702,7 +3693,6 @@ fn trans_args(cx: @block_ctxt, outer_cx: @block_ctxt, llenv: ValueRef,
|
|||
}
|
||||
save_in(dst) { dst }
|
||||
by_val(_) { alloca(cx, llretty) }
|
||||
}
|
||||
};
|
||||
|
||||
if ty::type_contains_params(tcx, retty) {
|
||||
|
@ -3713,7 +3703,6 @@ fn trans_args(cx: @block_ctxt, outer_cx: @block_ctxt, llenv: ValueRef,
|
|||
// view, for the sake of making a type-compatible call.
|
||||
check non_ty_var(ccx, retty);
|
||||
let llretty = T_ptr(type_of_inner(ccx, bcx.sp, retty));
|
||||
if ret_ref { llretty = T_ptr(llretty); }
|
||||
llargs += [PointerCast(cx, llretslot, llretty)];
|
||||
} else { llargs += [llretslot]; }
|
||||
|
||||
|
@ -3729,25 +3718,19 @@ fn trans_args(cx: @block_ctxt, outer_cx: @block_ctxt, llenv: ValueRef,
|
|||
// This will be needed if this is a generic call, because the callee has
|
||||
// to cast her view of the arguments to the caller's view.
|
||||
let arg_tys = type_of_explicit_args(ccx, cx.sp, args);
|
||||
let i = 0u, outer_cx = outer_cx;
|
||||
let i = 0u;
|
||||
for e: @ast::expr in es {
|
||||
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; }
|
||||
let r = trans_arg_expr(bcx, args[i], arg_tys[i], to_zero, to_revoke,
|
||||
e);
|
||||
bcx = r.bcx;
|
||||
llargs += [r.val];
|
||||
i += 1u;
|
||||
}
|
||||
ret {bcx: bcx,
|
||||
outer_cx: outer_cx,
|
||||
args: llargs,
|
||||
retslot: llretslot,
|
||||
to_zero: to_zero,
|
||||
to_revoke: to_revoke,
|
||||
ret_ref: ret_ref};
|
||||
to_revoke: to_revoke};
|
||||
}
|
||||
|
||||
fn trans_call(in_cx: @block_ctxt, f: @ast::expr,
|
||||
|
@ -3764,6 +3747,7 @@ fn trans_call(in_cx: @block_ctxt, f: @ast::expr,
|
|||
//NDM }
|
||||
|
||||
let cx = new_scope_block_ctxt(in_cx, "call");
|
||||
Br(in_cx, cx.llbb);
|
||||
let f_res = trans_callee(cx, f);
|
||||
let bcx = f_res.bcx;
|
||||
|
||||
|
@ -3789,8 +3773,7 @@ fn trans_call(in_cx: @block_ctxt, f: @ast::expr,
|
|||
|
||||
let ret_ty = ty::node_id_to_type(tcx, id);
|
||||
let args_res =
|
||||
trans_args(bcx, in_cx, llenv, f_res.generic, args, fn_expr_ty, dest);
|
||||
Br(args_res.outer_cx, cx.llbb);
|
||||
trans_args(bcx, llenv, f_res.generic, args, fn_expr_ty, dest);
|
||||
bcx = args_res.bcx;
|
||||
let llargs = args_res.args;
|
||||
let llretslot = args_res.retslot;
|
||||
|
@ -3803,8 +3786,7 @@ fn trans_call(in_cx: @block_ctxt, f: @ast::expr,
|
|||
args_res.to_revoke);
|
||||
alt dest {
|
||||
ignore. {
|
||||
if llvm::LLVMIsUndef(llretslot) != lib::llvm::True &&
|
||||
!args_res.ret_ref {
|
||||
if llvm::LLVMIsUndef(llretslot) != lib::llvm::True {
|
||||
bcx = drop_ty(bcx, llretslot, ret_ty);
|
||||
}
|
||||
}
|
||||
|
@ -4445,16 +4427,7 @@ fn trans_cont(sp: span, cx: @block_ctxt) -> @block_ctxt {
|
|||
fn trans_ret(bcx: @block_ctxt, e: option::t<@ast::expr>) -> @block_ctxt {
|
||||
let cleanup_cx = bcx, bcx = bcx;
|
||||
alt e {
|
||||
some(x) {
|
||||
if ast_util::ret_by_ref(bcx.fcx.ret_style) {
|
||||
let {bcx: cx, val, kind} = trans_lval(bcx, x);
|
||||
assert kind == owned;
|
||||
Store(cx, val, bcx.fcx.llretptr);
|
||||
bcx = cx;
|
||||
} else {
|
||||
bcx = trans_expr_save_in(bcx, x, bcx.fcx.llretptr);
|
||||
}
|
||||
}
|
||||
some(x) { bcx = trans_expr_save_in(bcx, x, bcx.fcx.llretptr); }
|
||||
_ {}
|
||||
}
|
||||
// run all cleanups and back out.
|
||||
|
@ -5604,7 +5577,7 @@ fn create_main_wrapper(ccx: @crate_ctxt, sp: span, main_llfn: ValueRef,
|
|||
let nt = ty::mk_nil(ccx.tcx);
|
||||
check non_ty_var(ccx, nt);
|
||||
|
||||
let llfty = type_of_fn(ccx, sp, false, false, [vecarg_ty], nt, 0u);
|
||||
let llfty = type_of_fn(ccx, sp, false, [vecarg_ty], nt, 0u);
|
||||
let llfdecl = decl_fn(ccx.llmod, "_rust_main",
|
||||
lib::llvm::LLVMCCallConv, llfty);
|
||||
|
||||
|
@ -5700,7 +5673,7 @@ fn native_fn_wrapper_type(cx: @crate_ctxt, sp: span, ty_param_count: uint,
|
|||
alt ty::struct(cx.tcx, x) {
|
||||
ty::ty_native_fn(args, out) {
|
||||
check non_ty_var(cx, out);
|
||||
ret type_of_fn(cx, sp, false, false, args, out, ty_param_count);
|
||||
ret type_of_fn(cx, sp, false, args, out, ty_param_count);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -321,7 +321,7 @@ fn get_res_dtor(ccx: @crate_ctxt, sp: span, did: ast::def_id, inner_t: ty::t)
|
|||
let nil_res = ty::mk_nil(ccx.tcx);
|
||||
// FIXME: Silly check -- mk_nil should have a postcondition
|
||||
check non_ty_var(ccx, nil_res);
|
||||
let f_t = type_of_fn(ccx, sp, false, false,
|
||||
let f_t = type_of_fn(ccx, sp, false,
|
||||
[{mode: ast::by_ref, ty: inner_t}],
|
||||
nil_res, params);
|
||||
ret trans::get_extern_const(ccx.externs, ccx.llmod,
|
||||
|
@ -430,14 +430,14 @@ fn find_scope_cx(cx: @block_ctxt) -> @block_ctxt {
|
|||
// Accessors
|
||||
// TODO: When we have overloading, simplify these names!
|
||||
|
||||
pure fn bcx_tcx(bcx: @block_ctxt) -> &ty::ctxt { ret bcx.fcx.lcx.ccx.tcx; }
|
||||
pure fn bcx_ccx(bcx: @block_ctxt) -> &@crate_ctxt { ret bcx.fcx.lcx.ccx; }
|
||||
pure fn bcx_lcx(bcx: @block_ctxt) -> &@local_ctxt { ret bcx.fcx.lcx; }
|
||||
pure fn bcx_fcx(bcx: @block_ctxt) -> &@fn_ctxt { ret bcx.fcx; }
|
||||
pure fn fcx_ccx(fcx: @fn_ctxt) -> &@crate_ctxt { ret fcx.lcx.ccx; }
|
||||
pure fn fcx_tcx(fcx: @fn_ctxt) -> &ty::ctxt { ret fcx.lcx.ccx.tcx; }
|
||||
pure fn lcx_ccx(lcx: @local_ctxt) -> &@crate_ctxt { ret lcx.ccx; }
|
||||
pure fn ccx_tcx(ccx: @crate_ctxt) -> &ty::ctxt { ret ccx.tcx; }
|
||||
pure fn bcx_tcx(bcx: @block_ctxt) -> ty::ctxt { ret bcx.fcx.lcx.ccx.tcx; }
|
||||
pure fn bcx_ccx(bcx: @block_ctxt) -> @crate_ctxt { ret bcx.fcx.lcx.ccx; }
|
||||
pure fn bcx_lcx(bcx: @block_ctxt) -> @local_ctxt { ret bcx.fcx.lcx; }
|
||||
pure fn bcx_fcx(bcx: @block_ctxt) -> @fn_ctxt { ret bcx.fcx; }
|
||||
pure fn fcx_ccx(fcx: @fn_ctxt) -> @crate_ctxt { ret fcx.lcx.ccx; }
|
||||
pure fn fcx_tcx(fcx: @fn_ctxt) -> ty::ctxt { ret fcx.lcx.ccx.tcx; }
|
||||
pure fn lcx_ccx(lcx: @local_ctxt) -> @crate_ctxt { ret lcx.ccx; }
|
||||
pure fn ccx_tcx(ccx: @crate_ctxt) -> ty::ctxt { ret ccx.tcx; }
|
||||
|
||||
// LLVM type constructors.
|
||||
fn T_void() -> TypeRef {
|
||||
|
|
|
@ -879,8 +879,7 @@ fn process_normal_mthd(cx: @local_ctxt, m: @ast::method, self_ty: ty::t,
|
|||
alt ty::struct(cx.ccx.tcx, node_id_type(cx.ccx, m.node.id)) {
|
||||
ty::ty_fn(_, inputs, output, rs, _) {
|
||||
check non_ty_var(ccx, output);
|
||||
llfnty = type_of_fn(ccx, m.span, true,
|
||||
ast_util::ret_by_ref(rs), inputs, output,
|
||||
llfnty = type_of_fn(ccx, m.span, true, inputs, output,
|
||||
vec::len(ty_params));
|
||||
}
|
||||
}
|
||||
|
@ -933,8 +932,7 @@ fn type_of_meth(ccx: @crate_ctxt, sp: span, m: @ty::method,
|
|||
tps: [ast::ty_param]) -> TypeRef {
|
||||
let out_ty = m.output;
|
||||
check non_ty_var(ccx, out_ty);
|
||||
type_of_fn(ccx, sp, true, ast_util::ret_by_ref(m.cf),
|
||||
m.inputs, out_ty, vec::len(tps))
|
||||
type_of_fn(ccx, sp, true, m.inputs, out_ty, vec::len(tps))
|
||||
}
|
||||
|
||||
//
|
||||
|
|
|
@ -1670,10 +1670,6 @@ fn expr_is_lval(tcx: ty::ctxt, e: @ast::expr) -> bool {
|
|||
ty_rec(_) { true }
|
||||
}
|
||||
}
|
||||
ast::expr_call(f, _, _) {
|
||||
let fty = expr_ty(tcx, f);
|
||||
ast_util::ret_by_ref(ty_fn_ret_style(tcx, fty))
|
||||
}
|
||||
_ { false }
|
||||
}
|
||||
}
|
||||
|
@ -2623,10 +2619,6 @@ fn type_err_to_str(err: ty::type_err) -> str {
|
|||
alt s {
|
||||
ast::noreturn. { "non-returning" }
|
||||
ast::return_val. { "return-by-value" }
|
||||
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) +
|
||||
|
|
|
@ -397,7 +397,6 @@ tag ret_style {
|
|||
noreturn; // functions with return type _|_ that always
|
||||
// raise an error or exit (i.e. never return to the caller)
|
||||
return_val; // everything else
|
||||
return_ref(bool, uint);
|
||||
}
|
||||
|
||||
type _fn = {decl: fn_decl, proto: proto, body: blk};
|
||||
|
|
|
@ -223,13 +223,6 @@ fn ternary_to_if(e: @expr) -> @expr {
|
|||
}
|
||||
}
|
||||
|
||||
fn ret_by_ref(style: ret_style) -> bool {
|
||||
alt style {
|
||||
return_ref(_, _) { true }
|
||||
_ { false }
|
||||
}
|
||||
}
|
||||
|
||||
fn ty_param_kind(tp: ty_param) -> kind { tp.kind }
|
||||
|
||||
fn compare_lit(a: @lit, b: @lit) -> int {
|
||||
|
|
|
@ -295,7 +295,7 @@ fn parse_ty_fn(proto: ast::proto, p: parser) -> ast::ty_ {
|
|||
// FIXME: there's no syntax for this right now anyway
|
||||
// auto constrs = parse_constrs(~[], p);
|
||||
let constrs: [@ast::constr] = [];
|
||||
let (ret_style, ret_ty) = parse_ret_ty(p, vec::len(inputs.node));
|
||||
let (ret_style, ret_ty) = parse_ret_ty(p);
|
||||
ret ast::ty_fn(proto, inputs.node, ret_ty, ret_style, constrs);
|
||||
}
|
||||
|
||||
|
@ -439,34 +439,12 @@ fn parse_ty_postfix(orig_t: ast::ty_, p: parser, colons_before_params: bool)
|
|||
}
|
||||
}
|
||||
|
||||
fn parse_ret_ty(p: parser, n_args: uint) -> (ast::ret_style, @ast::ty) {
|
||||
fn parse_ret_ty(p: parser) -> (ast::ret_style, @ast::ty) {
|
||||
ret if eat(p, token::RARROW) {
|
||||
let lo = p.get_lo_pos();
|
||||
if eat(p, token::NOT) {
|
||||
(ast::noreturn, @spanned(lo, p.get_last_hi_pos(), ast::ty_bot))
|
||||
} else {
|
||||
let style = ast::return_val;
|
||||
if eat(p, token::BINOP(token::AND)) {
|
||||
if n_args == 0u {
|
||||
p.fatal("can not return reference from argument-less fn");
|
||||
}
|
||||
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 {
|
||||
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))
|
||||
}
|
||||
} else { (ast::return_val, parse_ty(p, false)) }
|
||||
} else {
|
||||
let pos = p.get_lo_pos();
|
||||
(ast::return_val, @spanned(pos, pos, ast::ty_nil))
|
||||
|
@ -1791,7 +1769,7 @@ fn parse_fn_decl(p: parser, purity: ast::purity, il: ast::inlineness) ->
|
|||
p.bump();
|
||||
constrs = parse_constrs({|x| parse_ty_constr(inputs.node, x) }, p);
|
||||
}
|
||||
let (ret_style, ret_ty) = parse_ret_ty(p, vec::len(inputs.node));
|
||||
let (ret_style, ret_ty) = parse_ret_ty(p);
|
||||
ret {inputs: inputs.node,
|
||||
output: ret_ty,
|
||||
purity: purity,
|
||||
|
|
|
@ -1130,15 +1130,6 @@ fn print_fn_args_and_ret(s: ps, decl: ast::fn_decl, constrs: [@ast::constr]) {
|
|||
if decl.output.node != ast::ty_nil {
|
||||
space_if_not_bol(s);
|
||||
word_space(s, "->");
|
||||
alt decl.cf {
|
||||
ast::return_ref(mut, arg) {
|
||||
word(s.s, mut ? "&!" : "&");
|
||||
if vec::len(decl.inputs) > 1u {
|
||||
word_space(s, std::uint::str(arg));
|
||||
}
|
||||
}
|
||||
_ {}
|
||||
}
|
||||
print_type(s, decl.output);
|
||||
}
|
||||
}
|
||||
|
@ -1336,18 +1327,8 @@ fn print_ty_fn(s: ps, proto: ast::proto, id: option::t<ast::ident>,
|
|||
space_if_not_bol(s);
|
||||
ibox(s, indent_unit);
|
||||
word_space(s, "->");
|
||||
if cf == ast::noreturn {
|
||||
word_nbsp(s, "!");
|
||||
} else {
|
||||
alt cf {
|
||||
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);
|
||||
}
|
||||
if cf == ast::noreturn { word_nbsp(s, "!"); }
|
||||
else { print_type(s, output); }
|
||||
end(s);
|
||||
}
|
||||
word(s.s, ast_ty_fn_constrs_str(constrs));
|
||||
|
|
|
@ -62,11 +62,6 @@ fn ty_to_str(cx: ctxt, typ: t) -> str {
|
|||
s += " -> ";
|
||||
alt cf {
|
||||
ast::noreturn. { s += "!"; }
|
||||
ast::return_ref(mut, arg) {
|
||||
s += mut ? "&!" : "&";
|
||||
if vec::len(inputs) > 1u { s += std::uint::str(arg); }
|
||||
s += ty_to_str(cx, output);
|
||||
}
|
||||
ast::return_val. { s += ty_to_str(cx, output); }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -30,7 +30,7 @@ Failure:
|
|||
|
||||
Fails if the value equals `none`.
|
||||
*/
|
||||
fn get<T>(opt: t<T>) -> &T {
|
||||
fn get<copy T>(opt: t<T>) -> T {
|
||||
alt opt { some(x) { ret x; } none. { fail "option none"; } }
|
||||
}
|
||||
|
||||
|
|
|
@ -1,9 +0,0 @@
|
|||
// error-pattern:a reference binding can't be rooted in a temporary
|
||||
|
||||
fn f(a: {x: int}) -> &int {
|
||||
ret a.x;
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let &_a = f({x: 4});
|
||||
}
|
|
@ -1,8 +0,0 @@
|
|||
// error-pattern:can not return a reference to a function-local value
|
||||
|
||||
fn f(a: {mutable x: int}) -> &int {
|
||||
let x = {y: 4};
|
||||
ret x.y;
|
||||
}
|
||||
|
||||
fn main() {}
|
|
@ -1,7 +0,0 @@
|
|||
// error-pattern:can not return a reference to a mutable field
|
||||
|
||||
fn f(a: {mutable x: int}) -> &int {
|
||||
ret a.x;
|
||||
}
|
||||
|
||||
fn main() {}
|
|
@ -1,12 +0,0 @@
|
|||
// error-pattern:taking the value of x will invalidate reference a
|
||||
|
||||
fn f(a: {mutable x: int}) -> &!int {
|
||||
ret a.x;
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let x = {mutable x: 4};
|
||||
let &a = f(x);
|
||||
x;
|
||||
a;
|
||||
}
|
|
@ -1,12 +0,0 @@
|
|||
// error-pattern:overwriting x will invalidate reference a
|
||||
|
||||
fn f(a: {x: {mutable x: int}}) -> &{mutable x: int} {
|
||||
ret a.x;
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let x = {x: {mutable x: 4}};
|
||||
let &a = f(x);
|
||||
x = {x: {mutable x: 5}};
|
||||
a;
|
||||
}
|
|
@ -1,7 +0,0 @@
|
|||
// error-pattern:must specify referenced parameter
|
||||
|
||||
fn f(a: int, b: int) -> &int {
|
||||
ret a;
|
||||
}
|
||||
|
||||
fn main() {}
|
|
@ -1,7 +0,0 @@
|
|||
// error-pattern:can not return a reference to a temporary
|
||||
|
||||
fn f(a: int) -> &int {
|
||||
ret 10;
|
||||
}
|
||||
|
||||
fn main() {}
|
|
@ -1,7 +0,0 @@
|
|||
// error-pattern:can not return a reference to the wrong parameter
|
||||
|
||||
fn f(a: int, b: int) -> &2 int {
|
||||
ret a;
|
||||
}
|
||||
|
||||
fn main() {}
|
|
@ -1,32 +0,0 @@
|
|||
tag option<T> { some(T); none; }
|
||||
|
||||
fn get<T>(opt: option<T>) -> &T {
|
||||
alt opt {
|
||||
some(x) { ret x; }
|
||||
}
|
||||
}
|
||||
|
||||
fn get_mut(a: {mutable x: @int}, _b: int) -> &!1 @int {
|
||||
ret a.x;
|
||||
}
|
||||
|
||||
fn get_deep(a: {mutable y: {mutable x: @int}}) -> &!@int {
|
||||
ret get_mut(a.y, 1);
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let x = some(@50);
|
||||
let &y = get(x);
|
||||
assert *y == 50;
|
||||
assert get(some(10)) == 10;
|
||||
|
||||
let y = {mutable x: @50};
|
||||
let &box = get_mut(y, 4);
|
||||
assert *box == 50;
|
||||
assert *get_mut({mutable x: @70}, 5) == 70;
|
||||
|
||||
let u = {mutable y: {mutable x: @10}};
|
||||
let &deep = get_deep(u);
|
||||
assert *deep == 10;
|
||||
assert *get_deep({mutable y: {mutable x: @11}}) + 2 == 13;
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue