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) {
|
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)) }
|
||||||
'&' | '^' {
|
|
||||||
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)) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -214,11 +214,6 @@ 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, arg) {
|
|
||||||
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); }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,10 +28,8 @@ type binding = @{node_id: node_id,
|
||||||
unsafe_tys: [unsafe_ty],
|
unsafe_tys: [unsafe_ty],
|
||||||
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],
|
type scope = {bs: [binding],
|
||||||
ret_info: ret_info,
|
|
||||||
invalid: @mutable list<@invalid>};
|
invalid: @mutable list<@invalid>};
|
||||||
|
|
||||||
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>,
|
||||||
|
@ -67,7 +65,7 @@ fn check_crate(tcx: ty::ctxt, crate: @ast::crate) -> (copy_map, ref_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>()};
|
||||||
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));
|
visit::visit_crate(*crate, sc, visit::mk_vt(v));
|
||||||
tcx.sess.abort_if_errors();
|
tcx.sess.abort_if_errors();
|
||||||
ret (cx.copy_map, cx.ref_map);
|
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
|
// Blocks need to obey any restrictions from the enclosing scope, and may
|
||||||
// be called multiple times.
|
// be called multiple times.
|
||||||
if f.proto == ast::proto_block {
|
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);}
|
check_loop(*cx, sc) {|| v.visit_block(f.body, sc, v);}
|
||||||
} else {
|
} 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);
|
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) {
|
ast::expr_assign(dest, src) | ast::expr_assign_op(_, dest, src) {
|
||||||
check_assign(cx, dest, src, sc, v);
|
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_if(c, then, els) { check_if(c, then, els, sc, v); }
|
||||||
ast::expr_while(_, _) | ast::expr_do_while(_, _) {
|
ast::expr_while(_, _) | ast::expr_do_while(_, _) {
|
||||||
check_loop(*cx, sc) {|| visit::visit_expr(ex, sc, v); }
|
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])
|
fn check_call(cx: ctx, sc: scope, f: @ast::expr, args: [@ast::expr])
|
||||||
-> [binding] {
|
-> [binding] {
|
||||||
let fty = ty::expr_ty(cx.tcx, f);
|
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 arg_ts = ty::ty_fn_args(cx.tcx, fty);
|
||||||
let mut_roots: [{arg: uint, node: node_id}] = [];
|
let mut_roots: [{arg: uint, node: node_id}] = [];
|
||||||
let bindings = [];
|
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 {
|
mutable copied: alt arg_t.mode {
|
||||||
ast::by_move. | ast::by_copy. { copied }
|
ast::by_move. | ast::by_copy. { copied }
|
||||||
ast::by_mut_ref. { not_allowed }
|
ast::by_mut_ref. { not_allowed }
|
||||||
_ { i + 1u == by_ref ? not_allowed : not_copied }
|
_ { not_copied }
|
||||||
}}];
|
}}];
|
||||||
i += 1u;
|
i += 1u;
|
||||||
}
|
}
|
||||||
|
@ -338,69 +310,6 @@ fn check_call(cx: ctx, sc: scope, f: @ast::expr, args: [@ast::expr])
|
||||||
ret bindings;
|
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,
|
fn check_alt(cx: ctx, input: @ast::expr, arms: [ast::arm], sc: scope,
|
||||||
v: vt<scope>) {
|
v: vt<scope>) {
|
||||||
v.visit_expr(input, sc, v);
|
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};
|
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,
|
type ctx = {tcx: ty::ctxt,
|
||||||
rval_map: rval_map,
|
rval_map: rval_map,
|
||||||
last_uses: last_use::last_uses,
|
last_uses: last_use::last_uses};
|
||||||
mutable ret_by_ref: bool};
|
|
||||||
|
|
||||||
fn check_crate(tcx: ty::ctxt, last_uses: last_use::last_uses,
|
fn check_crate(tcx: ty::ctxt, last_uses: last_use::last_uses,
|
||||||
crate: @crate) -> rval_map {
|
crate: @crate) -> rval_map {
|
||||||
let ctx = {tcx: tcx,
|
let ctx = {tcx: tcx,
|
||||||
rval_map: std::map::new_int_hash(),
|
rval_map: std::map::new_int_hash(),
|
||||||
last_uses: last_uses,
|
last_uses: last_uses};
|
||||||
mutable ret_by_ref: false};
|
|
||||||
let visit = visit::mk_vt(@{
|
let visit = visit::mk_vt(@{
|
||||||
visit_expr: check_expr,
|
visit_expr: check_expr,
|
||||||
visit_stmt: check_stmt,
|
visit_stmt: check_stmt
|
||||||
visit_fn: visit_fn
|
|
||||||
with *visit::default_visitor()
|
with *visit::default_visitor()
|
||||||
});
|
});
|
||||||
visit::visit_crate(*crate, ctx, visit);
|
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_assign(_, ex) | expr_assign_op(_, _, ex) |
|
||||||
expr_block({node: {expr: some(ex), _}, _}) |
|
expr_block({node: {expr: some(ex), _}, _}) |
|
||||||
expr_unary(box(_), ex) | expr_unary(uniq(_), ex) { maybe_copy(cx, 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); }
|
expr_copy(expr) { check_copy_ex(cx, expr, false); }
|
||||||
// Vector add copies.
|
// Vector add copies.
|
||||||
expr_binary(add., ls, rs) { maybe_copy(cx, ls); maybe_copy(cx, rs); }
|
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);
|
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) {
|
fn maybe_copy(cx: ctx, ex: @expr) {
|
||||||
check_copy_ex(cx, ex, true);
|
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
|
// - new_fn_ctxt
|
||||||
// - trans_args
|
// - trans_args
|
||||||
fn type_of_fn(cx: @crate_ctxt, sp: span,
|
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)
|
output: ty::t, ty_param_count: uint)
|
||||||
: non_ty_var(cx, output) -> TypeRef {
|
: non_ty_var(cx, output) -> TypeRef {
|
||||||
let atys: [TypeRef] = [];
|
let atys: [TypeRef] = [];
|
||||||
|
|
||||||
// Arg 0: Output pointer.
|
// Arg 0: Output pointer.
|
||||||
let out_ty = T_ptr(type_of_inner(cx, sp, output));
|
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)
|
// Arg 1: Env (closure-bindings / self-obj)
|
||||||
if is_method {
|
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,
|
fn type_of_fn_from_ty(cx: @crate_ctxt, sp: span, fty: ty::t,
|
||||||
ty_param_count: uint)
|
ty_param_count: uint)
|
||||||
: returns_non_ty_var(cx, fty) -> TypeRef {
|
: 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
|
// FIXME: Check should be unnecessary, b/c it's implied
|
||||||
// by returns_non_ty_var(t). Make that a postcondition
|
// by returns_non_ty_var(t). Make that a postcondition
|
||||||
// (see Issue #586)
|
// (see Issue #586)
|
||||||
let ret_ty = ty::ty_fn_ret(cx.tcx, fty);
|
let ret_ty = ty::ty_fn_ret(cx.tcx, fty);
|
||||||
check non_ty_var(cx, ret_ty);
|
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);
|
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 v = GEPi(bcx, vtbl, [0, ix as int]);
|
||||||
let fn_ty: ty::t = ty::method_ty_to_fn_ty(tcx, mths[ix]);
|
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_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?
|
// FIXME: constrain ty_obj?
|
||||||
check non_ty_var(ccx, ret_ty);
|
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);
|
ty::ty_fn_args(tcx, fn_ty), ret_ty, 0u);
|
||||||
v = Load(bcx, PointerCast(bcx, v, T_ptr(T_ptr(ll_fn_ty))));
|
v = Load(bcx, PointerCast(bcx, v, T_ptr(T_ptr(ll_fn_ty))));
|
||||||
ret {bcx: bcx, mthptr: v, objptr: o};
|
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.
|
// - create_llargs_for_fn_args.
|
||||||
// - new_fn_ctxt
|
// - new_fn_ctxt
|
||||||
// - trans_args
|
// - 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,
|
gen: option::t<generic_info>, es: [@ast::expr], fn_ty: ty::t,
|
||||||
dest: dest)
|
dest: dest)
|
||||||
-> {bcx: @block_ctxt,
|
-> {bcx: @block_ctxt,
|
||||||
outer_cx: @block_ctxt,
|
|
||||||
args: [ValueRef],
|
args: [ValueRef],
|
||||||
retslot: ValueRef,
|
retslot: ValueRef,
|
||||||
to_zero: [{v: ValueRef, t: ty::t}],
|
to_zero: [{v: ValueRef, t: ty::t}],
|
||||||
to_revoke: [{v: ValueRef, t: ty::t}],
|
to_revoke: [{v: ValueRef, t: ty::t}]} {
|
||||||
ret_ref: bool} {
|
|
||||||
|
|
||||||
let args: [ty::arg] = ty::ty_fn_args(bcx_tcx(cx), fn_ty);
|
let args: [ty::arg] = ty::ty_fn_args(bcx_tcx(cx), fn_ty);
|
||||||
let llargs: [ValueRef] = [];
|
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 ccx = bcx_ccx(cx);
|
||||||
let tcx = ccx.tcx;
|
let tcx = ccx.tcx;
|
||||||
let bcx = cx;
|
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;
|
let retty = ty::ty_fn_ret(tcx, fn_ty), full_retty = retty;
|
||||||
alt gen {
|
alt gen {
|
||||||
|
@ -3691,18 +3685,14 @@ fn trans_args(cx: @block_ctxt, outer_cx: @block_ctxt, llenv: ValueRef,
|
||||||
}
|
}
|
||||||
// Arg 0: Output pointer.
|
// Arg 0: Output pointer.
|
||||||
let llretty = type_of_or_i8(bcx, full_retty);
|
let llretty = type_of_or_i8(bcx, full_retty);
|
||||||
let llretslot = if ret_ref {
|
let llretslot = alt dest {
|
||||||
alloca(cx, T_ptr(llretty))
|
ignore. {
|
||||||
} else {
|
if ty::type_is_nil(tcx, retty) {
|
||||||
alt dest {
|
llvm::LLVMGetUndef(T_ptr(llretty))
|
||||||
ignore. {
|
} else { alloca(cx, llretty) }
|
||||||
if ty::type_is_nil(tcx, retty) {
|
}
|
||||||
llvm::LLVMGetUndef(T_ptr(llretty))
|
save_in(dst) { dst }
|
||||||
} else { alloca(cx, llretty) }
|
by_val(_) { alloca(cx, llretty) }
|
||||||
}
|
|
||||||
save_in(dst) { dst }
|
|
||||||
by_val(_) { alloca(cx, llretty) }
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
if ty::type_contains_params(tcx, retty) {
|
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.
|
// view, for the sake of making a type-compatible call.
|
||||||
check non_ty_var(ccx, retty);
|
check non_ty_var(ccx, retty);
|
||||||
let llretty = T_ptr(type_of_inner(ccx, bcx.sp, retty));
|
let llretty = T_ptr(type_of_inner(ccx, bcx.sp, retty));
|
||||||
if ret_ref { llretty = T_ptr(llretty); }
|
|
||||||
llargs += [PointerCast(cx, llretslot, llretty)];
|
llargs += [PointerCast(cx, llretslot, llretty)];
|
||||||
} else { llargs += [llretslot]; }
|
} 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
|
// 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.
|
// to cast her view of the arguments to the caller's view.
|
||||||
let arg_tys = type_of_explicit_args(ccx, cx.sp, args);
|
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 {
|
for e: @ast::expr in es {
|
||||||
let is_referenced = alt ret_style {
|
let r = trans_arg_expr(bcx, args[i], arg_tys[i], to_zero, to_revoke,
|
||||||
ast::return_ref(_, arg_n) { i + 1u == arg_n }
|
e);
|
||||||
_ { false }
|
bcx = r.bcx;
|
||||||
};
|
|
||||||
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];
|
llargs += [r.val];
|
||||||
i += 1u;
|
i += 1u;
|
||||||
}
|
}
|
||||||
ret {bcx: bcx,
|
ret {bcx: bcx,
|
||||||
outer_cx: outer_cx,
|
|
||||||
args: llargs,
|
args: llargs,
|
||||||
retslot: llretslot,
|
retslot: llretslot,
|
||||||
to_zero: to_zero,
|
to_zero: to_zero,
|
||||||
to_revoke: to_revoke,
|
to_revoke: to_revoke};
|
||||||
ret_ref: ret_ref};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn trans_call(in_cx: @block_ctxt, f: @ast::expr,
|
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 }
|
//NDM }
|
||||||
|
|
||||||
let cx = new_scope_block_ctxt(in_cx, "call");
|
let cx = new_scope_block_ctxt(in_cx, "call");
|
||||||
|
Br(in_cx, cx.llbb);
|
||||||
let f_res = trans_callee(cx, f);
|
let f_res = trans_callee(cx, f);
|
||||||
let bcx = f_res.bcx;
|
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 ret_ty = ty::node_id_to_type(tcx, id);
|
||||||
let args_res =
|
let args_res =
|
||||||
trans_args(bcx, in_cx, llenv, f_res.generic, args, fn_expr_ty, dest);
|
trans_args(bcx, llenv, f_res.generic, args, fn_expr_ty, dest);
|
||||||
Br(args_res.outer_cx, cx.llbb);
|
|
||||||
bcx = args_res.bcx;
|
bcx = args_res.bcx;
|
||||||
let llargs = args_res.args;
|
let llargs = args_res.args;
|
||||||
let llretslot = args_res.retslot;
|
let llretslot = args_res.retslot;
|
||||||
|
@ -3803,8 +3786,7 @@ fn trans_call(in_cx: @block_ctxt, f: @ast::expr,
|
||||||
args_res.to_revoke);
|
args_res.to_revoke);
|
||||||
alt dest {
|
alt dest {
|
||||||
ignore. {
|
ignore. {
|
||||||
if llvm::LLVMIsUndef(llretslot) != lib::llvm::True &&
|
if llvm::LLVMIsUndef(llretslot) != lib::llvm::True {
|
||||||
!args_res.ret_ref {
|
|
||||||
bcx = drop_ty(bcx, llretslot, ret_ty);
|
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 {
|
fn trans_ret(bcx: @block_ctxt, e: option::t<@ast::expr>) -> @block_ctxt {
|
||||||
let cleanup_cx = bcx, bcx = bcx;
|
let cleanup_cx = bcx, bcx = bcx;
|
||||||
alt e {
|
alt e {
|
||||||
some(x) {
|
some(x) { bcx = trans_expr_save_in(bcx, x, bcx.fcx.llretptr); }
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ {}
|
_ {}
|
||||||
}
|
}
|
||||||
// run all cleanups and back out.
|
// 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);
|
let nt = ty::mk_nil(ccx.tcx);
|
||||||
check non_ty_var(ccx, nt);
|
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",
|
let llfdecl = decl_fn(ccx.llmod, "_rust_main",
|
||||||
lib::llvm::LLVMCCallConv, llfty);
|
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) {
|
alt ty::struct(cx.tcx, x) {
|
||||||
ty::ty_native_fn(args, out) {
|
ty::ty_native_fn(args, out) {
|
||||||
check non_ty_var(cx, 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);
|
let nil_res = ty::mk_nil(ccx.tcx);
|
||||||
// FIXME: Silly check -- mk_nil should have a postcondition
|
// FIXME: Silly check -- mk_nil should have a postcondition
|
||||||
check non_ty_var(ccx, nil_res);
|
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}],
|
[{mode: ast::by_ref, ty: inner_t}],
|
||||||
nil_res, params);
|
nil_res, params);
|
||||||
ret trans::get_extern_const(ccx.externs, ccx.llmod,
|
ret trans::get_extern_const(ccx.externs, ccx.llmod,
|
||||||
|
@ -430,14 +430,14 @@ fn find_scope_cx(cx: @block_ctxt) -> @block_ctxt {
|
||||||
// Accessors
|
// Accessors
|
||||||
// TODO: When we have overloading, simplify these names!
|
// 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_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_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_lcx(bcx: @block_ctxt) -> @local_ctxt { ret bcx.fcx.lcx; }
|
||||||
pure fn bcx_fcx(bcx: @block_ctxt) -> &@fn_ctxt { ret bcx.fcx; }
|
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_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 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 lcx_ccx(lcx: @local_ctxt) -> @crate_ctxt { ret lcx.ccx; }
|
||||||
pure fn ccx_tcx(ccx: @crate_ctxt) -> &ty::ctxt { ret ccx.tcx; }
|
pure fn ccx_tcx(ccx: @crate_ctxt) -> ty::ctxt { ret ccx.tcx; }
|
||||||
|
|
||||||
// LLVM type constructors.
|
// LLVM type constructors.
|
||||||
fn T_void() -> TypeRef {
|
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)) {
|
alt ty::struct(cx.ccx.tcx, node_id_type(cx.ccx, m.node.id)) {
|
||||||
ty::ty_fn(_, inputs, output, rs, _) {
|
ty::ty_fn(_, inputs, output, rs, _) {
|
||||||
check non_ty_var(ccx, output);
|
check non_ty_var(ccx, output);
|
||||||
llfnty = type_of_fn(ccx, m.span, true,
|
llfnty = type_of_fn(ccx, m.span, true, inputs, output,
|
||||||
ast_util::ret_by_ref(rs), inputs, output,
|
|
||||||
vec::len(ty_params));
|
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 {
|
tps: [ast::ty_param]) -> TypeRef {
|
||||||
let out_ty = m.output;
|
let out_ty = m.output;
|
||||||
check non_ty_var(ccx, out_ty);
|
check non_ty_var(ccx, out_ty);
|
||||||
type_of_fn(ccx, sp, true, ast_util::ret_by_ref(m.cf),
|
type_of_fn(ccx, sp, true, m.inputs, out_ty, vec::len(tps))
|
||||||
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 }
|
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 }
|
_ { false }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2623,10 +2619,6 @@ 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(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) +
|
||||||
|
|
|
@ -397,7 +397,6 @@ 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, uint);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type _fn = {decl: fn_decl, proto: proto, body: blk};
|
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 ty_param_kind(tp: ty_param) -> kind { tp.kind }
|
||||||
|
|
||||||
fn compare_lit(a: @lit, b: @lit) -> int {
|
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
|
// 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, 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);
|
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) {
|
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) {
|
||||||
(ast::noreturn, @spanned(lo, p.get_last_hi_pos(), ast::ty_bot))
|
(ast::noreturn, @spanned(lo, p.get_last_hi_pos(), ast::ty_bot))
|
||||||
} else {
|
} else { (ast::return_val, parse_ty(p, false)) }
|
||||||
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 {
|
} else {
|
||||||
let pos = p.get_lo_pos();
|
let pos = p.get_lo_pos();
|
||||||
(ast::return_val, @spanned(pos, pos, ast::ty_nil))
|
(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();
|
p.bump();
|
||||||
constrs = parse_constrs({|x| parse_ty_constr(inputs.node, x) }, p);
|
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,
|
ret {inputs: inputs.node,
|
||||||
output: ret_ty,
|
output: ret_ty,
|
||||||
purity: purity,
|
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 {
|
if decl.output.node != ast::ty_nil {
|
||||||
space_if_not_bol(s);
|
space_if_not_bol(s);
|
||||||
word_space(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);
|
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);
|
space_if_not_bol(s);
|
||||||
ibox(s, indent_unit);
|
ibox(s, indent_unit);
|
||||||
word_space(s, "->");
|
word_space(s, "->");
|
||||||
if cf == ast::noreturn {
|
if cf == ast::noreturn { word_nbsp(s, "!"); }
|
||||||
word_nbsp(s, "!");
|
else { print_type(s, output); }
|
||||||
} 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);
|
|
||||||
}
|
|
||||||
end(s);
|
end(s);
|
||||||
}
|
}
|
||||||
word(s.s, ast_ty_fn_constrs_str(constrs));
|
word(s.s, ast_ty_fn_constrs_str(constrs));
|
||||||
|
|
|
@ -62,11 +62,6 @@ 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, 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); }
|
ast::return_val. { s += ty_to_str(cx, output); }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,7 +30,7 @@ Failure:
|
||||||
|
|
||||||
Fails if the value equals `none`.
|
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"; } }
|
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