提交 77b06d24 编写于 作者: N Niko Matsakis

infer modes rather than overwriting with expected ty

上级 5163606d
...@@ -382,7 +382,7 @@ fn mk_main(cx: test_ctxt) -> @ast::item { ...@@ -382,7 +382,7 @@ fn mk_main(cx: test_ctxt) -> @ast::item {
let args_ty: ast::ty = nospan(ast::ty_vec(args_mt)); let args_ty: ast::ty = nospan(ast::ty_vec(args_mt));
let args_arg: ast::arg = let args_arg: ast::arg =
{mode: ast::by_val, {mode: ast::expl(ast::by_val),
ty: @args_ty, ty: @args_ty,
ident: "args", ident: "args",
id: cx.sess.next_node_id()}; id: cx.sess.next_node_id()};
......
...@@ -353,7 +353,7 @@ fn parse_ty_fn(st: @pstate, conv: conv_did) -> ty::fn_ty { ...@@ -353,7 +353,7 @@ fn parse_ty_fn(st: @pstate, conv: conv_did) -> ty::fn_ty {
'#' { ast::by_val } '#' { ast::by_val }
}; };
st.pos += 1u; st.pos += 1u;
inputs += [{mode: mode, ty: parse_ty(st, conv)}]; inputs += [{mode: ast::expl(mode), ty: parse_ty(st, conv)}];
} }
st.pos += 1u; // eat the ']' st.pos += 1u; // eat the ']'
let cs = parse_constrs(st, conv); let cs = parse_constrs(st, conv);
......
...@@ -203,16 +203,12 @@ fn enc_proto(w: io::writer, proto: proto) { ...@@ -203,16 +203,12 @@ fn enc_proto(w: io::writer, proto: proto) {
fn enc_ty_fn(w: io::writer, cx: @ctxt, ft: ty::fn_ty) { fn enc_ty_fn(w: io::writer, cx: @ctxt, ft: ty::fn_ty) {
w.write_char('['); w.write_char('[');
for arg: ty::arg in ft.inputs { for arg: ty::arg in ft.inputs {
alt arg.mode { alt ty::resolved_mode(cx.tcx, arg.mode) {
by_mut_ref { w.write_char('&'); } by_mut_ref { w.write_char('&'); }
by_move { w.write_char('-'); } by_move { w.write_char('-'); }
by_copy { w.write_char('+'); } by_copy { w.write_char('+'); }
by_ref { w.write_char('='); } by_ref { w.write_char('='); }
by_val { w.write_char('#'); } by_val { w.write_char('#'); }
// tediously, this has to be there until there's a way
// to constraint post-typeck types not to contain a mode_infer
mode_infer { cx.tcx.sess.bug("enc_ty_fn: shouldn't see \
mode_infer"); }
} }
enc_ty(w, cx, arg.ty); enc_ty(w, cx, arg.ty);
} }
......
...@@ -82,9 +82,11 @@ fn visit_fn(cx: @ctx, _fk: visit::fn_kind, decl: ast::fn_decl, ...@@ -82,9 +82,11 @@ fn visit_fn(cx: @ctx, _fk: visit::fn_kind, decl: ast::fn_decl,
let fty = ty::node_id_to_type(cx.tcx, id); let fty = ty::node_id_to_type(cx.tcx, id);
let args = ty::ty_fn_args(cx.tcx, fty); let args = ty::ty_fn_args(cx.tcx, fty);
for arg in args { for arg in args {
if arg.mode == ast::by_val && alt ty::resolved_mode(cx.tcx, arg.mode) {
ty::type_has_dynamic_size(cx.tcx, arg.ty) { ast::by_val if ty::type_has_dynamic_size(cx.tcx, arg.ty) {
err(*cx, sp, "can not pass a dynamically-sized type by value"); err(*cx, sp, "can not pass a dynamically-sized type by value");
}
_ { /* fallthrough */ }
} }
} }
...@@ -226,7 +228,8 @@ fn check_call(cx: ctx, sc: scope, f: @ast::expr, args: [@ast::expr]) ...@@ -226,7 +228,8 @@ fn check_call(cx: ctx, sc: scope, f: @ast::expr, args: [@ast::expr])
for arg_t: ty::arg in arg_ts { for arg_t: ty::arg in arg_ts {
let arg = args[i]; let arg = args[i];
let root = expr_root(cx, arg, false); let root = expr_root(cx, arg, false);
if arg_t.mode == ast::by_mut_ref { alt ty::resolved_mode(cx.tcx, arg_t.mode) {
ast::by_mut_ref {
alt path_def(cx, arg) { alt path_def(cx, arg) {
some(def) { some(def) {
let dnum = ast_util::def_id_of_def(def).node; let dnum = ast_util::def_id_of_def(def).node;
...@@ -234,18 +237,21 @@ fn check_call(cx: ctx, sc: scope, f: @ast::expr, args: [@ast::expr]) ...@@ -234,18 +237,21 @@ fn check_call(cx: ctx, sc: scope, f: @ast::expr, args: [@ast::expr])
} }
_ { } _ { }
} }
}
ast::by_ref | ast::by_val | ast::by_move | ast::by_copy { }
} }
let root_var = path_def_id(cx, root.ex); let root_var = path_def_id(cx, root.ex);
let arg_copied = alt ty::resolved_mode(cx.tcx, arg_t.mode) {
ast::by_move | ast::by_copy { copied }
ast::by_mut_ref { not_allowed }
ast::by_ref | ast::by_val { not_copied }
};
bindings += [@{node_id: arg.id, bindings += [@{node_id: arg.id,
span: arg.span, span: arg.span,
root_var: root_var, root_var: root_var,
local_id: 0u, local_id: 0u,
unsafe_tys: unsafe_set(root.mut), unsafe_tys: unsafe_set(root.mut),
mutable copied: alt arg_t.mode { mutable copied: arg_copied}];
ast::by_move | ast::by_copy { copied }
ast::by_mut_ref { not_allowed }
_ { not_copied }
}}];
i += 1u; i += 1u;
} }
let f_may_close = let f_may_close =
...@@ -279,7 +285,8 @@ fn check_call(cx: ctx, sc: scope, f: @ast::expr, args: [@ast::expr]) ...@@ -279,7 +285,8 @@ fn check_call(cx: ctx, sc: scope, f: @ast::expr, args: [@ast::expr])
for unsafe_ty in b.unsafe_tys { for unsafe_ty in b.unsafe_tys {
let i = 0u; let i = 0u;
for arg_t: ty::arg in arg_ts { for arg_t: ty::arg in arg_ts {
let mut_alias = arg_t.mode == ast::by_mut_ref; let mut_alias =
(ast::by_mut_ref == ty::arg_mode(cx.tcx, arg_t));
if i != j && if i != j &&
ty_can_unsafely_include(cx, unsafe_ty, arg_t.ty, ty_can_unsafely_include(cx, unsafe_ty, arg_t.ty,
mut_alias) && mut_alias) &&
......
...@@ -28,7 +28,7 @@ fn visit_expr(ex: @expr, cx: ctx, v: visit::vt<ctx>) { ...@@ -28,7 +28,7 @@ fn visit_expr(ex: @expr, cx: ctx, v: visit::vt<ctx>) {
v.visit_expr(f, cx, v); v.visit_expr(f, cx, v);
let i = 0u; let i = 0u;
for arg_t in ty::ty_fn_args(cx.tcx, ty::expr_ty(cx.tcx, f)) { for arg_t in ty::ty_fn_args(cx.tcx, ty::expr_ty(cx.tcx, f)) {
cx.allow_block = arg_t.mode == by_ref; cx.allow_block = (ty::arg_mode(cx.tcx, arg_t) == by_ref);
v.visit_expr(args[i], cx, v); v.visit_expr(args[i], cx, v);
i += 1u; i += 1u;
} }
......
...@@ -165,7 +165,10 @@ fn check_expr(e: @expr, cx: ctx, v: visit::vt<ctx>) { ...@@ -165,7 +165,10 @@ fn check_expr(e: @expr, cx: ctx, v: visit::vt<ctx>) {
expr_call(f, args, _) { expr_call(f, args, _) {
let i = 0u; let i = 0u;
for arg_t in ty::ty_fn_args(cx.tcx, ty::expr_ty(cx.tcx, f)) { for arg_t in ty::ty_fn_args(cx.tcx, ty::expr_ty(cx.tcx, f)) {
alt arg_t.mode { by_copy { maybe_copy(cx, args[i]); } _ {} } alt ty::arg_mode(cx.tcx, arg_t) {
by_copy { maybe_copy(cx, args[i]); }
by_ref | by_val | by_mut_ref | by_move { }
}
i += 1u; i += 1u;
} }
} }
......
...@@ -157,7 +157,7 @@ fn visit_expr(ex: @expr, cx: ctx, v: visit::vt<ctx>) { ...@@ -157,7 +157,7 @@ fn visit_expr(ex: @expr, cx: ctx, v: visit::vt<ctx>) {
fns += [arg]; fns += [arg];
} }
_ { _ {
alt arg_ts[i].mode { alt ty::arg_mode(cx.tcx, arg_ts[i]) {
by_mut_ref { clear_if_path(cx, arg, v, false); } by_mut_ref { clear_if_path(cx, arg, v, false); }
_ { v.visit_expr(arg, cx, v); } _ { v.visit_expr(arg, cx, v); }
} }
...@@ -286,11 +286,21 @@ fn clear_in_current(cx: ctx, my_def: node_id, to: bool) { ...@@ -286,11 +286,21 @@ fn clear_in_current(cx: ctx, my_def: node_id, to: bool) {
fn clear_def_if_path(cx: ctx, d: def, to: bool) fn clear_def_if_path(cx: ctx, d: def, to: bool)
-> option<node_id> { -> option<node_id> {
alt d { alt d {
def_local(def_id, let_copy) | def_arg(def_id, by_copy) | def_local(def_id, let_copy) {
def_arg(def_id, by_move) {
clear_in_current(cx, def_id.node, to); clear_in_current(cx, def_id.node, to);
some(def_id.node) some(def_id.node)
} }
def_arg(def_id, m) {
alt ty::resolved_mode(cx.tcx, m) {
by_copy | by_move {
clear_in_current(cx, def_id.node, to);
some(def_id.node)
}
by_ref | by_val | by_mut_ref {
none
}
}
}
_ { _ {
none none
} }
......
...@@ -228,10 +228,10 @@ fn check_call(cx: @ctx, f: @expr, args: [@expr]) { ...@@ -228,10 +228,10 @@ fn check_call(cx: @ctx, f: @expr, args: [@expr]) {
let arg_ts = ty::ty_fn_args(cx.tcx, ty::expr_ty(cx.tcx, f)); let arg_ts = ty::ty_fn_args(cx.tcx, ty::expr_ty(cx.tcx, f));
let i = 0u; let i = 0u;
for arg_t: ty::arg in arg_ts { for arg_t: ty::arg in arg_ts {
alt arg_t.mode { alt ty::resolved_mode(cx.tcx, arg_t.mode) {
by_mut_ref { check_lval(cx, args[i], msg_mut_ref); } by_mut_ref { check_lval(cx, args[i], msg_mut_ref); }
by_move { check_lval(cx, args[i], msg_move_out); } by_move { check_lval(cx, args[i], msg_move_out); }
_ {} by_ref | by_val | by_copy { }
} }
i += 1u; i += 1u;
} }
...@@ -267,8 +267,12 @@ fn is_immutable_def(cx: @ctx, def: def) -> option<str> { ...@@ -267,8 +267,12 @@ fn is_immutable_def(cx: @ctx, def: def) -> option<str> {
def_use(_) { def_use(_) {
some("static item") some("static item")
} }
def_arg(_, by_ref) | def_arg(_, by_val) | def_arg(_, m) {
def_arg(_, mode_infer) { some("argument") } alt ty::resolved_mode(cx.tcx, m) {
by_ref | by_val { some("argument") }
by_mut_ref | by_move | by_copy { none }
}
}
def_self(_) { some("self argument") } def_self(_) { some("self argument") }
def_upvar(_, inner, node_id) { def_upvar(_, inner, node_id) {
let ty = ty::node_id_to_type(cx.tcx, node_id); let ty = ty::node_id_to_type(cx.tcx, node_id);
......
...@@ -63,16 +63,18 @@ fn type_of(cx: @crate_ctxt, t: ty::t) : type_has_static_size(cx, t) ...@@ -63,16 +63,18 @@ fn type_of(cx: @crate_ctxt, t: ty::t) : type_has_static_size(cx, t)
fn type_of_explicit_args(cx: @crate_ctxt, inputs: [ty::arg]) -> fn type_of_explicit_args(cx: @crate_ctxt, inputs: [ty::arg]) ->
[TypeRef] { [TypeRef] {
let atys = []; let tcx = ccx_tcx(cx);
for arg in inputs { vec::map(inputs) {|arg|
let arg_ty = arg.ty; let arg_ty = arg.ty;
// FIXME: would be nice to have a constraint on arg // FIXME: would be nice to have a constraint on arg
// that would obviate the need for this check // that would obviate the need for this check
check non_ty_var(cx, arg_ty); check non_ty_var(cx, arg_ty);
let llty = type_of_inner(cx, arg_ty); let llty = type_of_inner(cx, arg_ty);
atys += [if arg.mode == ast::by_val { llty } else { T_ptr(llty) }]; alt ty::resolved_mode(tcx, arg.mode) {
ast::by_val { llty }
_ { T_ptr(llty) }
}
} }
ret atys;
} }
...@@ -2981,15 +2983,16 @@ fn trans_arg_expr(cx: @block_ctxt, arg: ty::arg, lldestty: TypeRef, ...@@ -2981,15 +2983,16 @@ fn trans_arg_expr(cx: @block_ctxt, arg: ty::arg, lldestty: TypeRef,
let lv = trans_temp_lval(cx, e); let lv = trans_temp_lval(cx, e);
let bcx = lv.bcx; let bcx = lv.bcx;
let val = lv.val; let val = lv.val;
let arg_mode = ty::resolved_mode(ccx.tcx, arg.mode);
if is_bot { if is_bot {
// For values of type _|_, we generate an // For values of type _|_, we generate an
// "undef" value, as such a value should never // "undef" value, as such a value should never
// be inspected. It's important for the value // be inspected. It's important for the value
// to have type lldestty (the callee's expected type). // to have type lldestty (the callee's expected type).
val = llvm::LLVMGetUndef(lldestty); val = llvm::LLVMGetUndef(lldestty);
} else if arg.mode == ast::by_ref || arg.mode == ast::by_val { } else if arg_mode == ast::by_ref || arg_mode == ast::by_val {
let copied = false, imm = ty::type_is_immediate(ccx.tcx, e_ty); let copied = false, imm = ty::type_is_immediate(ccx.tcx, e_ty);
if arg.mode == ast::by_ref && lv.kind != owned && imm { if arg_mode == ast::by_ref && lv.kind != owned && imm {
val = do_spill_noroot(bcx, val); val = do_spill_noroot(bcx, val);
copied = true; copied = true;
} }
...@@ -3002,10 +3005,10 @@ fn trans_arg_expr(cx: @block_ctxt, arg: ty::arg, lldestty: TypeRef, ...@@ -3002,10 +3005,10 @@ fn trans_arg_expr(cx: @block_ctxt, arg: ty::arg, lldestty: TypeRef,
} else { bcx = take_ty(bcx, val, e_ty); } } else { bcx = take_ty(bcx, val, e_ty); }
add_clean(bcx, val, e_ty); add_clean(bcx, val, e_ty);
} }
if arg.mode == ast::by_val && (lv.kind == owned || !imm) { if arg_mode == ast::by_val && (lv.kind == owned || !imm) {
val = Load(bcx, val); val = Load(bcx, val);
} }
} else if arg.mode == ast::by_copy { } else if arg_mode == ast::by_copy {
let {bcx: cx, val: alloc} = alloc_ty(bcx, e_ty); let {bcx: cx, val: alloc} = alloc_ty(bcx, e_ty);
let last_use = ccx.last_uses.contains_key(e.id); let last_use = ccx.last_uses.contains_key(e.id);
bcx = cx; bcx = cx;
...@@ -3031,7 +3034,7 @@ fn trans_arg_expr(cx: @block_ctxt, arg: ty::arg, lldestty: TypeRef, ...@@ -3031,7 +3034,7 @@ fn trans_arg_expr(cx: @block_ctxt, arg: ty::arg, lldestty: TypeRef,
} }
// Collect arg for later if it happens to be one we've moving out. // Collect arg for later if it happens to be one we've moving out.
if arg.mode == ast::by_move { if arg_mode == ast::by_move {
if lv.kind == owned { if lv.kind == owned {
// Use actual ty, not declared ty -- anything else doesn't make // Use actual ty, not declared ty -- anything else doesn't make
// sense if declared ty is a ty param // sense if declared ty is a ty param
...@@ -4414,9 +4417,10 @@ fn create_llargs_for_fn_args(cx: @fn_ctxt, ty_self: self_arg, ...@@ -4414,9 +4417,10 @@ fn create_llargs_for_fn_args(cx: @fn_ctxt, ty_self: self_arg,
fn copy_args_to_allocas(fcx: @fn_ctxt, bcx: @block_ctxt, args: [ast::arg], fn copy_args_to_allocas(fcx: @fn_ctxt, bcx: @block_ctxt, args: [ast::arg],
arg_tys: [ty::arg]) -> @block_ctxt { arg_tys: [ty::arg]) -> @block_ctxt {
let tcx = bcx_tcx(bcx);
let arg_n: uint = 0u, bcx = bcx; let arg_n: uint = 0u, bcx = bcx;
fn epic_fail_(bcx: @block_ctxt) -> ! { let epic_fail = fn@() -> ! {
bcx_tcx(bcx).sess.bug("Someone forgot\ tcx.sess.bug("Someone forgot\
to document an invariant in copy_args_to_allocas!"); to document an invariant in copy_args_to_allocas!");
} }
let epic_fail = bind epic_fail_(bcx); let epic_fail = bind epic_fail_(bcx);
...@@ -4424,7 +4428,7 @@ fn epic_fail_(bcx: @block_ctxt) -> ! { ...@@ -4424,7 +4428,7 @@ fn epic_fail_(bcx: @block_ctxt) -> ! {
let id = args[arg_n].id; let id = args[arg_n].id;
let argval = alt fcx.llargs.get(id) { local_mem(v) { v } let argval = alt fcx.llargs.get(id) { local_mem(v) { v }
_ { epic_fail() } }; _ { epic_fail() } };
alt arg.mode { alt ty::resolved_mode(tcx, arg.mode) {
ast::by_mut_ref { } ast::by_mut_ref { }
ast::by_move | ast::by_copy { add_clean(bcx, argval, arg.ty); } ast::by_move | ast::by_copy { add_clean(bcx, argval, arg.ty); }
ast::by_val { ast::by_val {
...@@ -4438,7 +4442,6 @@ fn epic_fail_(bcx: @block_ctxt) -> ! { ...@@ -4438,7 +4442,6 @@ fn epic_fail_(bcx: @block_ctxt) -> ! {
} }
} }
ast::by_ref {} ast::by_ref {}
_ { epic_fail(); }
} }
if fcx_ccx(fcx).sess.opts.extra_debuginfo { if fcx_ccx(fcx).sess.opts.extra_debuginfo {
debuginfo::create_arg(bcx, args[arg_n], args[arg_n].ty.span); debuginfo::create_arg(bcx, args[arg_n], args[arg_n].ty.span);
...@@ -4585,7 +4588,7 @@ fn trans_enum_variant(ccx: @crate_ctxt, ...@@ -4585,7 +4588,7 @@ fn trans_enum_variant(ccx: @crate_ctxt,
// Translate variant arguments to function arguments. // Translate variant arguments to function arguments.
let fn_args = [], i = 0u; let fn_args = [], i = 0u;
for varg in variant.node.args { for varg in variant.node.args {
fn_args += [{mode: ast::by_copy, fn_args += [{mode: ast::expl(ast::by_copy),
ty: varg.ty, ty: varg.ty,
ident: "arg" + uint::to_str(i, 10u), ident: "arg" + uint::to_str(i, 10u),
id: varg.id}]; id: varg.id}];
...@@ -5039,7 +5042,7 @@ fn create_main(ccx: @crate_ctxt, main_llfn: ValueRef, ...@@ -5039,7 +5042,7 @@ fn create_main(ccx: @crate_ctxt, main_llfn: ValueRef,
takes_argv: bool) -> ValueRef { takes_argv: bool) -> ValueRef {
let unit_ty = ty::mk_str(ccx.tcx); let unit_ty = ty::mk_str(ccx.tcx);
let vecarg_ty: ty::arg = let vecarg_ty: ty::arg =
{mode: ast::by_val, {mode: ast::expl(ast::by_val),
ty: ty::mk_vec(ccx.tcx, {ty: unit_ty, mut: ast::imm})}; ty: ty::mk_vec(ccx.tcx, {ty: unit_ty, mut: ast::imm})};
// FIXME: mk_nil should have a postcondition // FIXME: mk_nil should have a postcondition
let nt = ty::mk_nil(ccx.tcx); let nt = ty::mk_nil(ccx.tcx);
......
...@@ -895,13 +895,20 @@ fn trans_bind_thunk(ccx: @crate_ctxt, ...@@ -895,13 +895,20 @@ fn trans_bind_thunk(ccx: @crate_ctxt,
[0, abi::closure_body_bindings, b]); [0, abi::closure_body_bindings, b]);
bcx = bound_arg.bcx; bcx = bound_arg.bcx;
let val = bound_arg.val; let val = bound_arg.val;
if out_arg.mode == ast::by_val { val = Load(bcx, val); }
if out_arg.mode == ast::by_copy { alt ty::resolved_mode(tcx, out_arg.mode) {
ast::by_val {
val = Load(bcx, val);
}
ast::by_copy {
let {bcx: cx, val: alloc} = alloc_ty(bcx, out_arg.ty); let {bcx: cx, val: alloc} = alloc_ty(bcx, out_arg.ty);
bcx = memmove_ty(cx, alloc, val, out_arg.ty); bcx = memmove_ty(cx, alloc, val, out_arg.ty);
bcx = take_ty(bcx, alloc, out_arg.ty); bcx = take_ty(bcx, alloc, out_arg.ty);
val = alloc; val = alloc;
}
ast::by_ref | ast::by_mut_ref | ast::by_move { }
} }
// If the type is parameterized, then we need to cast the // If the type is parameterized, then we need to cast the
// type we actually have to the parameterized out type. // type we actually have to the parameterized out type.
if ty::type_contains_params(ccx.tcx, out_arg.ty) { if ty::type_contains_params(ccx.tcx, out_arg.ty) {
......
...@@ -300,7 +300,8 @@ fn get_res_dtor(ccx: @crate_ctxt, did: ast::def_id, inner_t: ty::t) ...@@ -300,7 +300,8 @@ fn get_res_dtor(ccx: @crate_ctxt, 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, [{mode: ast::by_ref, ty: inner_t}], let fn_mode = ast::expl(ast::by_ref);
let f_t = type_of_fn(ccx, [{mode: fn_mode, ty: inner_t}],
nil_res, *param_bounds); nil_res, *param_bounds);
ret base::get_extern_const(ccx.externs, ccx.llmod, ret base::get_extern_const(ccx.externs, ccx.llmod,
csearch::get_symbol(ccx.sess.cstore, csearch::get_symbol(ccx.sess.cstore,
......
...@@ -63,7 +63,8 @@ fn trans_impl(ccx: @crate_ctxt, path: path, name: ast::ident, ...@@ -63,7 +63,8 @@ fn trans_impl(ccx: @crate_ctxt, path: path, name: ast::ident,
fn trans_self_arg(bcx: @block_ctxt, base: @ast::expr) -> result { fn trans_self_arg(bcx: @block_ctxt, base: @ast::expr) -> result {
let tz = [], tr = []; let tz = [], tr = [];
let basety = expr_ty(bcx, base); let basety = expr_ty(bcx, base);
let {bcx, val} = trans_arg_expr(bcx, {mode: ast::by_ref, ty: basety}, let m_by_ref = ast::expl(ast::by_ref);
let {bcx, val} = trans_arg_expr(bcx, {mode: m_by_ref, ty: basety},
T_ptr(type_of_or_i8(bcx, basety)), tz, T_ptr(type_of_or_i8(bcx, basety)), tz,
tr, base); tr, base);
rslt(bcx, PointerCast(bcx, val, T_opaque_cbox_ptr(bcx_ccx(bcx)))) rslt(bcx, PointerCast(bcx, val, T_opaque_cbox_ptr(bcx_ccx(bcx))))
......
...@@ -1089,10 +1089,12 @@ fn callee_modes(fcx: fn_ctxt, callee: node_id) -> [mode] { ...@@ -1089,10 +1089,12 @@ fn callee_modes(fcx: fn_ctxt, callee: node_id) -> [mode] {
} }
fn callee_arg_init_ops(fcx: fn_ctxt, callee: node_id) -> [init_op] { fn callee_arg_init_ops(fcx: fn_ctxt, callee: node_id) -> [init_op] {
fn mode_to_op(m: mode) -> init_op { vec::map(callee_modes(fcx, callee)) {|m|
alt m { by_move { init_move } _ { init_assign } } alt ty::resolved_mode(fcx.ccx.tcx, m) {
by_move { init_move }
by_copy | by_ref | by_val | by_mut_ref { init_assign }
}
} }
vec::map(callee_modes(fcx, callee), mode_to_op)
} }
fn anon_bindings(ops: [init_op], es: [@expr]) -> [binding] { fn anon_bindings(ops: [init_op], es: [@expr]) -> [binding] {
......
...@@ -276,12 +276,11 @@ fn handle_var_def(fcx: fn_ctxt, rslt: pre_and_post, def: def, name: ident) { ...@@ -276,12 +276,11 @@ fn handle_var_def(fcx: fn_ctxt, rslt: pre_and_post, def: def, name: ident) {
fn forget_args_moved_in(fcx: fn_ctxt, parent: @expr, modes: [mode], fn forget_args_moved_in(fcx: fn_ctxt, parent: @expr, modes: [mode],
operands: [@expr]) { operands: [@expr]) {
let i = 0u; vec::iteri(modes) {|i,mode|
for mode: mode in modes { alt ty::resolved_mode(fcx.ccx.tcx, mode) {
if mode == by_move { by_move { forget_in_postcond(fcx, parent.id, operands[i].id); }
forget_in_postcond(fcx, parent.id, operands[i].id); by_ref | by_val | by_mut_ref | by_copy { }
} }
i += 1u;
} }
} }
......
...@@ -19,7 +19,6 @@ ...@@ -19,7 +19,6 @@
import syntax::util::interner; import syntax::util::interner;
import util::ppaux::ty_to_str; import util::ppaux::ty_to_str;
import util::ppaux::ty_constr_to_str; import util::ppaux::ty_constr_to_str;
import util::ppaux::mode_str;
import syntax::print::pprust::*; import syntax::print::pprust::*;
export node_id_to_type; export node_id_to_type;
...@@ -168,6 +167,10 @@ ...@@ -168,6 +167,10 @@
export type_structurally_contains_uniques; export type_structurally_contains_uniques;
export type_autoderef; export type_autoderef;
export type_param; export type_param;
export resolved_mode;
export arg_mode;
export unify_mode;
export set_default_mode;
export unify; export unify;
export variant_info; export variant_info;
export walk_ty; export walk_ty;
...@@ -178,12 +181,12 @@ ...@@ -178,12 +181,12 @@
export ck_uniq; export ck_uniq;
export param_bound, param_bounds, bound_copy, bound_send, bound_iface; export param_bound, param_bounds, bound_copy, bound_send, bound_iface;
export param_bounds_to_kind; export param_bounds_to_kind;
export default_arg_mode_for_ty;
// Data types // Data types
// TODO: really should be a separate type, or a refinement, // Note: after typeck, you should use resolved_mode() to convert this mode
// so that we don't have to handle the mode_infer case after // into an rmode, which will take into account the results of mode inference.
// typeck. but that's too hard right now.
type arg = {mode: ast::mode, ty: t}; type arg = {mode: ast::mode, ty: t};
type field = {ident: ast::ident, mt: mt}; type field = {ident: ast::ident, mt: mt};
...@@ -217,7 +220,8 @@ ...@@ -217,7 +220,8 @@
ast_ty_to_ty_cache: hashmap<@ast::ty, option<t>>, ast_ty_to_ty_cache: hashmap<@ast::ty, option<t>>,
enum_var_cache: hashmap<def_id, @[variant_info]>, enum_var_cache: hashmap<def_id, @[variant_info]>,
iface_method_cache: hashmap<def_id, @[method]>, iface_method_cache: hashmap<def_id, @[method]>,
ty_param_bounds: hashmap<ast::node_id, param_bounds>}; ty_param_bounds: hashmap<ast::node_id, param_bounds>,
inferred_modes: hashmap<ast::node_id, ast::mode>};
type ty_ctxt = ctxt; type ty_ctxt = ctxt;
...@@ -424,7 +428,8 @@ fn eq_raw_ty(&&a: @raw_t, &&b: @raw_t) -> bool { ...@@ -424,7 +428,8 @@ fn eq_raw_ty(&&a: @raw_t, &&b: @raw_t) -> bool {
map::mk_hashmap(ast_util::hash_ty, ast_util::eq_ty), map::mk_hashmap(ast_util::hash_ty, ast_util::eq_ty),
enum_var_cache: new_def_hash(), enum_var_cache: new_def_hash(),
iface_method_cache: new_def_hash(), iface_method_cache: new_def_hash(),
ty_param_bounds: map::new_int_hash()}; ty_param_bounds: map::new_int_hash(),
inferred_modes: map::new_int_hash()};
populate_type_store(cx); populate_type_store(cx);
ret cx; ret cx;
} }
...@@ -646,6 +651,12 @@ fn mk_named(cx: ctxt, base: t, name: @str) -> t { ...@@ -646,6 +651,12 @@ fn mk_named(cx: ctxt, base: t, name: @str) -> t {
} }
} }
fn default_arg_mode_for_ty(tcx: ty::ctxt, ty: ty::t) -> ast::rmode {
assert !ty::type_contains_vars(tcx, ty);
if ty::type_is_immediate(tcx, ty) { ast::by_val }
else { ast::by_ref }
}
fn walk_ty(cx: ctxt, ty: t, f: fn(t)) { fn walk_ty(cx: ctxt, ty: t, f: fn(t)) {
alt struct(cx, ty) { alt struct(cx, ty) {
ty_nil | ty_bot | ty_bool | ty_int(_) | ty_uint(_) | ty_float(_) | ty_nil | ty_bot | ty_bool | ty_int(_) | ty_uint(_) | ty_float(_) |
...@@ -684,13 +695,14 @@ enum fold_mode { ...@@ -684,13 +695,14 @@ enum fold_mode {
fn fold_ty(cx: ctxt, fld: fold_mode, ty_0: t) -> t { fn fold_ty(cx: ctxt, fld: fold_mode, ty_0: t) -> t {
let ty = ty_0; let ty = ty_0;
// Fast paths.
// Fast paths.
alt fld { alt fld {
fm_var(_) { if !type_contains_vars(cx, ty) { ret ty; } } fm_var(_) { if !type_contains_vars(cx, ty) { ret ty; } }
fm_param(_) { if !type_contains_params(cx, ty) { ret ty; } } fm_param(_) { if !type_contains_params(cx, ty) { ret ty; } }
fm_general(_) {/* no fast path */ } fm_general(_) {/* no fast path */ }
} }
alt interner::get(*cx.ts, ty).struct { alt interner::get(*cx.ts, ty).struct {
ty_nil | ty_bot | ty_bool | ty_int(_) | ty_uint(_) | ty_float(_) | ty_nil | ty_bot | ty_bool | ty_int(_) | ty_uint(_) | ty_float(_) |
ty_str | ty_type | ty_send_type | ty_opaque_closure_ptr(_) {} ty_str | ty_type | ty_send_type | ty_opaque_closure_ptr(_) {}
...@@ -1619,6 +1631,77 @@ fn occurs_check_fails(tcx: ctxt, sp: option<span>, vid: int, rt: t) -> ...@@ -1619,6 +1631,77 @@ fn occurs_check_fails(tcx: ctxt, sp: option<span>, vid: int, rt: t) ->
} else { ret false; } } else { ret false; }
} }
// Maintains a little union-set tree for inferred modes. `canon()` returns
// the current head value for `m0`.
fn canon<T:copy>(tbl: hashmap<ast::node_id, ast::inferable<T>>,
m0: ast::inferable<T>) -> ast::inferable<T> {
alt m0 {
ast::infer(id) {
alt tbl.find(id) {
none { m0 }
some(m1) {
let cm1 = canon(tbl, m1);
// path compression:
if cm1 != m1 { tbl.insert(id, cm1); }
cm1
}
}
}
_ { m0 }
}
}
// Maintains a little union-set tree for inferred modes. `resolve_mode()`
// returns the current head value for `m0`.
fn canon_mode(cx: ctxt, m0: ast::mode) -> ast::mode {
canon(cx.inferred_modes, m0)
}
// Returns the head value for mode, failing if `m` was a infer(_) that
// was never inferred. This should be safe for use after typeck.
fn resolved_mode(cx: ctxt, m: ast::mode) -> ast::rmode {
alt canon_mode(cx, m) {
ast::infer(_) {
cx.sess.bug(#fmt["mode %? was never resolved", m]);
}
ast::expl(m0) { m0 }
}
}
fn arg_mode(cx: ctxt, a: arg) -> ast::rmode { ty::resolved_mode(cx, a.mode) }
// Unifies `m1` and `m2`. Returns unified value or failure code.
fn unify_mode(cx: ctxt, m1: ast::mode, m2: ast::mode)
-> result::t<ast::mode, type_err> {
alt (canon_mode(cx, m1), canon_mode(cx, m2)) {
(m1, m2) if (m1 == m2) {
result::ok(m1)
}
(ast::infer(id1), ast::infer(id2)) {
cx.inferred_modes.insert(id2, m1);
result::ok(m1)
}
(ast::infer(id), m) | (m, ast::infer(id)) {
cx.inferred_modes.insert(id, m);
result::ok(m1)
}
(m1, m2) {
result::err(terr_mode_mismatch(m1, m2))
}
}
}
// If `m` was never unified, unifies it with `m_def`. Returns the final value
// for `m`.
fn set_default_mode(cx: ctxt, m: ast::mode, m_def: ast::rmode) {
alt canon_mode(cx, m) {
ast::infer(id) {
cx.inferred_modes.insert(id, ast::expl(m_def));
}
ast::expl(_) { }
}
}
// Type unification via Robinson's algorithm (Robinson 1965). Implemented as // Type unification via Robinson's algorithm (Robinson 1965). Implemented as
// described in Hoder and Voronkov: // described in Hoder and Voronkov:
// //
...@@ -1869,15 +1952,14 @@ fn unify_args(cx: @ctxt, e_args: [arg], a_args: [arg], variance: variance) ...@@ -1869,15 +1952,14 @@ fn unify_args(cx: @ctxt, e_args: [arg], a_args: [arg], variance: variance)
for expected_input in e_args { for expected_input in e_args {
let actual_input = a_args[i]; let actual_input = a_args[i];
i += 1u; i += 1u;
// Unify the result modes. // Unify the result modes.
let result_mode = if expected_input.mode == ast::mode_infer { let result_mode =
actual_input.mode alt unify_mode(cx.tcx, expected_input.mode,
} else if actual_input.mode == ast::mode_infer { actual_input.mode) {
expected_input.mode result::err(err) { ret either::left(ures_err(err)); }
} else if expected_input.mode != actual_input.mode { result::ok(m) { m }
ret either::left(ures_err(terr_mode_mismatch( };
expected_input.mode, actual_input.mode)));
} else { expected_input.mode };
alt unify_step(cx, expected_input.ty, actual_input.ty, alt unify_step(cx, expected_input.ty, actual_input.ty,
variance) { variance) {
...@@ -2446,8 +2528,8 @@ fn to_str(s: ast::ret_style) -> str { ...@@ -2446,8 +2528,8 @@ fn to_str(s: ast::ret_style) -> str {
} }
terr_arg_count { ret "incorrect number of function parameters"; } terr_arg_count { ret "incorrect number of function parameters"; }
terr_mode_mismatch(e_mode, a_mode) { terr_mode_mismatch(e_mode, a_mode) {
ret "expected argument mode " + mode_str(e_mode) + " but found " + ret "expected argument mode " + mode_to_str(e_mode) + " but found " +
mode_str(a_mode); mode_to_str(a_mode);
} }
terr_constr_len(e_len, a_len) { terr_constr_len(e_len, a_len) {
ret "Expected a type with " + uint::str(e_len) + ret "Expected a type with " + uint::str(e_len) +
......
...@@ -64,7 +64,6 @@ enum self_info { ...@@ -64,7 +64,6 @@ enum self_info {
var_bindings: @ty::unify::var_bindings, var_bindings: @ty::unify::var_bindings,
locals: hashmap<ast::node_id, int>, locals: hashmap<ast::node_id, int>,
next_var_id: @mutable int, next_var_id: @mutable int,
mutable fixups: [ast::node_id],
ccx: @crate_ctxt}; ccx: @crate_ctxt};
...@@ -215,27 +214,11 @@ fn type_is_c_like_enum(fcx: @fn_ctxt, sp: span, typ: ty::t) -> bool { ...@@ -215,27 +214,11 @@ fn type_is_c_like_enum(fcx: @fn_ctxt, sp: span, typ: ty::t) -> bool {
ret ty::type_is_c_like_enum(fcx.ccx.tcx, typ_s); ret ty::type_is_c_like_enum(fcx.ccx.tcx, typ_s);
} }
// Parses the programmer's textual representation of a type into our internal
// notion of a type. `getter` is a function that returns the type
// corresponding to a definition ID:
fn default_arg_mode_for_ty(tcx: ty::ctxt, m: ast::mode,
ty: ty::t) -> ast::mode {
alt m {
ast::mode_infer {
alt ty::struct(tcx, ty) {
ty::ty_var(_) { ast::mode_infer }
_ {
if ty::type_is_immediate(tcx, ty) { ast::by_val }
else { ast::by_ref }
}
}
}
_ { m }
}
}
enum mode { m_collect, m_check, m_check_tyvar(@fn_ctxt), } enum mode { m_collect, m_check, m_check_tyvar(@fn_ctxt), }
// Parses the programmer's textual representation of a type into our
// internal notion of a type. `getter` is a function that returns the type
// corresponding to a definition ID:
fn ast_ty_to_ty(tcx: ty::ctxt, mode: mode, &&ast_ty: @ast::ty) -> ty::t { fn ast_ty_to_ty(tcx: ty::ctxt, mode: mode, &&ast_ty: @ast::ty) -> ty::t {
fn getter(tcx: ty::ctxt, mode: mode, id: ast::def_id) fn getter(tcx: ty::ctxt, mode: mode, id: ast::def_id)
-> ty::ty_param_bounds_and_ty { -> ty::ty_param_bounds_and_ty {
...@@ -443,13 +426,38 @@ fn ty_of_native_item(tcx: ty::ctxt, mode: mode, it: @ast::native_item) ...@@ -443,13 +426,38 @@ fn ty_of_native_item(tcx: ty::ctxt, mode: mode, it: @ast::native_item)
} }
} }
fn ty_of_arg(tcx: ty::ctxt, mode: mode, a: ast::arg) -> ty::arg { fn ty_of_arg(tcx: ty::ctxt, mode: mode, a: ast::arg) -> ty::arg {
fn arg_mode(tcx: ty::ctxt, m: ast::mode, ty: ty::t) -> ast::mode {
alt m {
ast::infer(_) {
alt ty::struct(tcx, ty) {
// If the type is not specified, then this must be a fn expr.
// Leave the mode as infer(_), it will get inferred based
// on constraints elsewhere.
ty::ty_var(_) { m }
// If the type is known, then use the default for that type.
// Here we unify m and the default. This should update the
// tables in tcx but should never fail, because nothing else
// will have been unified with m yet:
_ {
let m1 = ast::expl(ty::default_arg_mode_for_ty(tcx, ty));
result::get(ty::unify_mode(tcx, m, m1))
}
}
}
ast::expl(_) { m }
}
}
let ty = ast_ty_to_ty(tcx, mode, a.ty); let ty = ast_ty_to_ty(tcx, mode, a.ty);
{mode: default_arg_mode_for_ty(tcx, a.mode, ty), ty: ty} let mode = arg_mode(tcx, a.mode, ty);
} {mode: mode, ty: ty}
fn ty_of_fn_decl(tcx: ty::ctxt, mode: mode, }
proto: ast::proto, decl: ast::fn_decl) -> ty::fn_ty { fn ty_of_fn_decl(tcx: ty::ctxt,
let input_tys = []; mode: mode,
for a: ast::arg in decl.inputs { input_tys += [ty_of_arg(tcx, mode, a)]; } proto: ast::proto,
decl: ast::fn_decl) -> ty::fn_ty {
let input_tys = vec::map(decl.inputs) {|a| ty_of_arg(tcx, mode, a) };
let output_ty = ast_ty_to_ty(tcx, mode, decl.output); let output_ty = ast_ty_to_ty(tcx, mode, decl.output);
let out_constrs = []; let out_constrs = [];
...@@ -472,7 +480,9 @@ fn ty_of_native_fn_decl(tcx: ty::ctxt, mode: mode, decl: ast::fn_decl, ...@@ -472,7 +480,9 @@ fn ty_of_native_fn_decl(tcx: ty::ctxt, mode: mode, decl: ast::fn_decl,
ty_params: [ast::ty_param], def_id: ast::def_id) ty_params: [ast::ty_param], def_id: ast::def_id)
-> ty::ty_param_bounds_and_ty { -> ty::ty_param_bounds_and_ty {
let input_tys = [], bounds = ty_param_bounds(tcx, mode, ty_params); let input_tys = [], bounds = ty_param_bounds(tcx, mode, ty_params);
for a: ast::arg in decl.inputs { input_tys += [ty_of_arg(tcx, mode, a)]; } for a: ast::arg in decl.inputs {
input_tys += [ty_of_arg(tcx, mode, a)];
}
let output_ty = ast_ty_to_ty(tcx, mode, decl.output); let output_ty = ast_ty_to_ty(tcx, mode, decl.output);
let t_fn = ty::mk_fn(tcx, {proto: ast::proto_bare, let t_fn = ty::mk_fn(tcx, {proto: ast::proto_bare,
...@@ -585,7 +595,9 @@ fn compare_impl_method(tcx: ty::ctxt, sp: span, impl_m: ty::method, ...@@ -585,7 +595,9 @@ fn compare_impl_method(tcx: ty::ctxt, sp: span, impl_m: ty::method,
} else { } else {
let auto_modes = vec::map2(impl_m.fty.inputs, if_m.fty.inputs, {|i, f| let auto_modes = vec::map2(impl_m.fty.inputs, if_m.fty.inputs, {|i, f|
alt ty::struct(tcx, f.ty) { alt ty::struct(tcx, f.ty) {
ty::ty_param(0u, _) { {mode: ast::by_ref with i} } ty::ty_param(0u, _) {
{mode: ast::expl(ast::by_ref) with i}
}
_ { i } _ { i }
} }
}); });
...@@ -641,7 +653,7 @@ fn get_enum_variant_types(cx: @ctxt, enum_ty: ty::t, ...@@ -641,7 +653,7 @@ fn get_enum_variant_types(cx: @ctxt, enum_ty: ty::t,
let args: [arg] = []; let args: [arg] = [];
for va: ast::variant_arg in variant.node.args { for va: ast::variant_arg in variant.node.args {
let arg_ty = ast_ty_to_ty(cx.tcx, m_collect, va.ty); let arg_ty = ast_ty_to_ty(cx.tcx, m_collect, va.ty);
args += [{mode: ast::by_copy, ty: arg_ty}]; args += [{mode: ast::expl(ast::by_copy), ty: arg_ty}];
} }
// FIXME: this will be different for constrained types // FIXME: this will be different for constrained types
ty::mk_fn(cx.tcx, ty::mk_fn(cx.tcx,
...@@ -716,7 +728,7 @@ fn convert(cx: @ctxt, it: @ast::item) { ...@@ -716,7 +728,7 @@ fn convert(cx: @ctxt, it: @ast::item) {
params); params);
let t_ctor = ty::mk_fn(cx.tcx, { let t_ctor = ty::mk_fn(cx.tcx, {
proto: ast::proto_box, proto: ast::proto_box,
inputs: [{mode: ast::by_copy with t_arg}], inputs: [{mode: ast::expl(ast::by_copy) with t_arg}],
output: t_res, output: t_res,
ret_style: ast::return_val, constraints: [] ret_style: ast::return_val, constraints: []
}); });
...@@ -925,9 +937,6 @@ fn variant_arg_types(ccx: @crate_ctxt, _sp: span, vid: ast::def_id, ...@@ -925,9 +937,6 @@ fn variant_arg_types(ccx: @crate_ctxt, _sp: span, vid: ast::def_id,
// Type resolution: the phase that finds all the types in the AST with // Type resolution: the phase that finds all the types in the AST with
// unresolved type variables and replaces "ty_var" types with their // unresolved type variables and replaces "ty_var" types with their
// substitutions. // substitutions.
//
// TODO: inefficient since not all types have vars in them. It would be better
// to maintain a list of fixups.
mod writeback { mod writeback {
export resolve_type_vars_in_block; export resolve_type_vars_in_block;
...@@ -946,24 +955,32 @@ fn resolve_type_vars_in_type(fcx: @fn_ctxt, sp: span, typ: ty::t) -> ...@@ -946,24 +955,32 @@ fn resolve_type_vars_in_type(fcx: @fn_ctxt, sp: span, typ: ty::t) ->
} }
} }
} }
fn resolve_type_vars_for_node(wbcx: wb_ctxt, sp: span, id: ast::node_id) { fn resolve_type_vars_for_node(wbcx: wb_ctxt, sp: span, id: ast::node_id)
-> option<ty::t> {
let fcx = wbcx.fcx, tcx = fcx.ccx.tcx; let fcx = wbcx.fcx, tcx = fcx.ccx.tcx;
alt resolve_type_vars_in_type(fcx, sp, ty::node_id_to_type(tcx, id)) { alt resolve_type_vars_in_type(fcx, sp, ty::node_id_to_type(tcx, id)) {
some(t) { write_ty(tcx, id, t); } none {
none { wbcx.success = false; ret } wbcx.success = false;
} ret none;
alt tcx.node_type_substs.find(id) { }
some(substs) {
let new_substs = []; some(t) {
for subst: ty::t in substs { write_ty(tcx, id, t);
alt resolve_type_vars_in_type(fcx, sp, subst) { alt tcx.node_type_substs.find(id) {
some(t) { new_substs += [t]; } some(substs) {
none { wbcx.success = false; ret; } let new_substs = [];
for subst: ty::t in substs {
alt resolve_type_vars_in_type(fcx, sp, subst) {
some(t) { new_substs += [t]; }
none { wbcx.success = false; ret none; }
}
} }
write_substs(tcx, id, new_substs);
}
none {}
} }
write_substs(tcx, id, new_substs); ret some(t);
} }
none {}
} }
} }
...@@ -984,8 +1001,19 @@ fn visit_expr(e: @ast::expr, wbcx: wb_ctxt, v: wb_vt) { ...@@ -984,8 +1001,19 @@ fn visit_expr(e: @ast::expr, wbcx: wb_ctxt, v: wb_vt) {
alt e.node { alt e.node {
ast::expr_fn(_, decl, _, _) | ast::expr_fn(_, decl, _, _) |
ast::expr_fn_block(decl, _) { ast::expr_fn_block(decl, _) {
for input in decl.inputs { vec::iter(decl.inputs) {|input|
resolve_type_vars_for_node(wbcx, e.span, input.id); let r_ty = resolve_type_vars_for_node(wbcx, e.span, input.id);
// Just in case we never constrained the mode to anything,
// constrain it to the default for the type in question.
alt (r_ty, input.mode) {
(some(t), ast::infer(_)) {
let tcx = wbcx.fcx.ccx.tcx;
let m_def = ty::default_arg_mode_for_ty(tcx, t);
ty::set_default_mode(tcx, input.mode, m_def);
}
_ {}
}
} }
} }
_ { } _ { }
...@@ -1541,8 +1569,8 @@ fn check_expr_fn_with_unifier(fcx: @fn_ctxt, ...@@ -1541,8 +1569,8 @@ fn check_expr_fn_with_unifier(fcx: @fn_ctxt,
unify: unifier, unify: unifier,
expected: ty::t) { expected: ty::t) {
let tcx = fcx.ccx.tcx; let tcx = fcx.ccx.tcx;
let fty = ty::mk_fn(tcx, ty_of_fn_decl(tcx, m_check_tyvar(fcx), let fty = ty::mk_fn(tcx,
proto, decl)); ty_of_fn_decl(tcx, m_check_tyvar(fcx), proto, decl));
#debug("check_expr_fn_with_unifier %s fty=%s", #debug("check_expr_fn_with_unifier %s fty=%s",
expr_to_str(expr), expr_to_str(expr),
...@@ -1600,7 +1628,8 @@ fn check_call_or_bind(fcx: @fn_ctxt, sp: span, fty: ty::t, ...@@ -1600,7 +1628,8 @@ fn check_call_or_bind(fcx: @fn_ctxt, sp: span, fty: ty::t,
}]); }]);
// HACK: build an arguments list with dummy arguments to // HACK: build an arguments list with dummy arguments to
// check against // check against
let dummy = {mode: ast::by_ref, ty: ty::mk_bot(fcx.ccx.tcx)}; let dummy = {mode: ast::expl(ast::by_ref),
ty: ty::mk_bot(fcx.ccx.tcx)};
arg_tys = vec::init_elt(supplied_arg_count, dummy); arg_tys = vec::init_elt(supplied_arg_count, dummy);
} }
...@@ -2027,7 +2056,6 @@ fn check_user_unop(fcx: @fn_ctxt, op_str: str, mname: str, ...@@ -2027,7 +2056,6 @@ fn check_user_unop(fcx: @fn_ctxt, op_str: str, mname: str,
ty_to_str(tcx, expected)); ty_to_str(tcx, expected));
check_expr_fn_with_unifier(fcx, expr, proto, decl, body, check_expr_fn_with_unifier(fcx, expr, proto, decl, body,
unify, expected); unify, expected);
write_ty(tcx, id, expected);
} }
ast::expr_block(b) { ast::expr_block(b) {
// If this is an unchecked block, turn off purity-checking // If this is an unchecked block, turn off purity-checking
...@@ -2428,7 +2456,6 @@ fn check_const(ccx: @crate_ctxt, _sp: span, e: @ast::expr, id: ast::node_id) { ...@@ -2428,7 +2456,6 @@ fn check_const(ccx: @crate_ctxt, _sp: span, e: @ast::expr, id: ast::node_id) {
// FIXME: this is kinda a kludge; we manufacture a fake function context // FIXME: this is kinda a kludge; we manufacture a fake function context
// and statement context for checking the initializer expression. // and statement context for checking the initializer expression.
let rty = node_id_to_type(ccx.tcx, id); let rty = node_id_to_type(ccx.tcx, id);
let fixups: [ast::node_id] = [];
let fcx: @fn_ctxt = let fcx: @fn_ctxt =
@{ret_ty: rty, @{ret_ty: rty,
purity: ast::pure_fn, purity: ast::pure_fn,
...@@ -2436,7 +2463,6 @@ fn check_const(ccx: @crate_ctxt, _sp: span, e: @ast::expr, id: ast::node_id) { ...@@ -2436,7 +2463,6 @@ fn check_const(ccx: @crate_ctxt, _sp: span, e: @ast::expr, id: ast::node_id) {
var_bindings: ty::unify::mk_var_bindings(), var_bindings: ty::unify::mk_var_bindings(),
locals: new_int_hash::<int>(), locals: new_int_hash::<int>(),
next_var_id: @mutable 0, next_var_id: @mutable 0,
mutable fixups: fixups,
ccx: ccx}; ccx: ccx};
check_expr(fcx, e); check_expr(fcx, e);
let cty = expr_ty(fcx.ccx.tcx, e); let cty = expr_ty(fcx.ccx.tcx, e);
...@@ -2449,7 +2475,6 @@ fn check_enum_variants(ccx: @crate_ctxt, sp: span, vs: [ast::variant], ...@@ -2449,7 +2475,6 @@ fn check_enum_variants(ccx: @crate_ctxt, sp: span, vs: [ast::variant],
// FIXME: this is kinda a kludge; we manufacture a fake function context // FIXME: this is kinda a kludge; we manufacture a fake function context
// and statement context for checking the initializer expression. // and statement context for checking the initializer expression.
let rty = node_id_to_type(ccx.tcx, id); let rty = node_id_to_type(ccx.tcx, id);
let fixups: [ast::node_id] = [];
let fcx: @fn_ctxt = let fcx: @fn_ctxt =
@{ret_ty: rty, @{ret_ty: rty,
purity: ast::pure_fn, purity: ast::pure_fn,
...@@ -2457,7 +2482,6 @@ fn check_enum_variants(ccx: @crate_ctxt, sp: span, vs: [ast::variant], ...@@ -2457,7 +2482,6 @@ fn check_enum_variants(ccx: @crate_ctxt, sp: span, vs: [ast::variant],
var_bindings: ty::unify::mk_var_bindings(), var_bindings: ty::unify::mk_var_bindings(),
locals: new_int_hash::<int>(), locals: new_int_hash::<int>(),
next_var_id: @mutable 0, next_var_id: @mutable 0,
mutable fixups: fixups,
ccx: ccx}; ccx: ccx};
let disr_vals: [int] = []; let disr_vals: [int] = [];
let disr_val = 0; let disr_val = 0;
...@@ -2630,7 +2654,6 @@ fn check_fn(ccx: @crate_ctxt, ...@@ -2630,7 +2654,6 @@ fn check_fn(ccx: @crate_ctxt,
}; };
let gather_result = gather_locals(ccx, decl, body, id, old_fcx); let gather_result = gather_locals(ccx, decl, body, id, old_fcx);
let fixups: [ast::node_id] = [];
let fcx: @fn_ctxt = let fcx: @fn_ctxt =
@{ret_ty: ty::ty_fn_ret(ccx.tcx, ty::node_id_to_type(ccx.tcx, id)), @{ret_ty: ty::ty_fn_ret(ccx.tcx, ty::node_id_to_type(ccx.tcx, id)),
purity: purity, purity: purity,
...@@ -2638,7 +2661,6 @@ fn check_fn(ccx: @crate_ctxt, ...@@ -2638,7 +2661,6 @@ fn check_fn(ccx: @crate_ctxt,
var_bindings: gather_result.var_bindings, var_bindings: gather_result.var_bindings,
locals: gather_result.locals, locals: gather_result.locals,
next_var_id: gather_result.next_var_id, next_var_id: gather_result.next_var_id,
mutable fixups: fixups,
ccx: ccx}; ccx: ccx};
check_constraints(fcx, decl.constraints, decl.inputs); check_constraints(fcx, decl.constraints, decl.inputs);
......
...@@ -160,7 +160,17 @@ enum unop { ...@@ -160,7 +160,17 @@ enum unop {
deref, not, neg, deref, not, neg,
} }
enum mode { by_ref, by_val, by_mut_ref, by_move, by_copy, mode_infer, } // Generally, after typeck you can get the inferred value
// using ty::resolved_T(...).
enum inferable<T> {
expl(T), infer(node_id)
}
// "resolved" mode: the real modes.
enum rmode { by_ref, by_val, by_mut_ref, by_move, by_copy }
// inferable mode.
type mode = inferable<rmode>;
type stmt = spanned<stmt_>; type stmt = spanned<stmt_>;
......
...@@ -521,14 +521,19 @@ fn parse_ty(p: parser, colons_before_params: bool) -> @ast::ty { ...@@ -521,14 +521,19 @@ fn parse_ty(p: parser, colons_before_params: bool) -> @ast::ty {
} }
fn parse_arg_mode(p: parser) -> ast::mode { fn parse_arg_mode(p: parser) -> ast::mode {
if eat(p, token::BINOP(token::AND)) { ast::by_mut_ref } if eat(p, token::BINOP(token::AND)) {
else if eat(p, token::BINOP(token::MINUS)) { ast::by_move } ast::expl(ast::by_mut_ref)
else if eat(p, token::ANDAND) { ast::by_ref } } else if eat(p, token::BINOP(token::MINUS)) {
else if eat(p, token::BINOP(token::PLUS)) { ast::expl(ast::by_move)
if eat(p, token::BINOP(token::PLUS)) { ast::by_val } } else if eat(p, token::ANDAND) {
else { ast::by_copy } ast::expl(ast::by_ref)
} } else if eat(p, token::BINOP(token::PLUS)) {
else { ast::mode_infer } if eat(p, token::BINOP(token::PLUS)) {
ast::expl(ast::by_val)
} else {
ast::expl(ast::by_copy)
}
} else { ast::infer(p.get_id()) }
} }
fn parse_arg(p: parser) -> ast::arg { fn parse_arg(p: parser) -> ast::arg {
...@@ -1984,8 +1989,8 @@ fn parse_item_res(p: parser, attrs: [ast::attribute]) -> @ast::item { ...@@ -1984,8 +1989,8 @@ fn parse_item_res(p: parser, attrs: [ast::attribute]) -> @ast::item {
let dtor = parse_block_no_value(p); let dtor = parse_block_no_value(p);
let decl = let decl =
{inputs: {inputs:
[{mode: ast::by_ref, ty: t, ident: arg_ident, [{mode: ast::expl(ast::by_ref), ty: t,
id: p.get_id()}], ident: arg_ident, id: p.get_id()}],
output: @spanned(lo, lo, ast::ty_nil), output: @spanned(lo, lo, ast::ty_nil),
purity: ast::impure_fn, purity: ast::impure_fn,
cf: ast::return_val, cf: ast::return_val,
......
...@@ -136,7 +136,7 @@ fn res_to_str(decl: ast::fn_decl, name: ast::ident, ...@@ -136,7 +136,7 @@ fn res_to_str(decl: ast::fn_decl, name: ast::ident,
fn test_res_to_str() { fn test_res_to_str() {
let decl: ast::fn_decl = { let decl: ast::fn_decl = {
inputs: [{ inputs: [{
mode: ast::by_val, mode: ast::expl(ast::by_val),
ty: @ast_util::respan(ast_util::dummy_sp(), ast::ty_bool), ty: @ast_util::respan(ast_util::dummy_sp(), ast::ty_bool),
ident: "b", ident: "b",
id: 0 id: 0
...@@ -1280,17 +1280,22 @@ fn print_arg(s: ps, x: ast::arg) { ...@@ -1280,17 +1280,22 @@ fn print_arg(s: ps, x: ast::arg) {
maybe_print_comment(s, decl.output.span.lo); maybe_print_comment(s, decl.output.span.lo);
} }
fn print_arg_mode(s: ps, m: ast::mode) { fn mode_to_str(m: ast::mode) -> str {
alt m { alt m {
ast::by_mut_ref { word(s.s, "&"); } ast::expl(ast::by_mut_ref) { "&" }
ast::by_move { word(s.s, "-"); } ast::expl(ast::by_move) { "-" }
ast::by_ref { word(s.s, "&&"); } ast::expl(ast::by_ref) { "&&" }
ast::by_val { word(s.s, "++"); } ast::expl(ast::by_val) { "++" }
ast::by_copy { word(s.s, "+"); } ast::expl(ast::by_copy) { "+" }
ast::mode_infer {} ast::infer(_) { "" }
} }
} }
fn print_arg_mode(s: ps, m: ast::mode) {
let ms = mode_to_str(m);
if ms != "" { word(s.s, ms); }
}
fn print_bounds(s: ps, bounds: @[ast::ty_param_bound]) { fn print_bounds(s: ps, bounds: @[ast::ty_param_bound]) {
if vec::len(*bounds) > 0u { if vec::len(*bounds) > 0u {
word(s.s, ":"); word(s.s, ":");
......
...@@ -4,32 +4,18 @@ ...@@ -4,32 +4,18 @@
import middle::ty::*; import middle::ty::*;
import metadata::encoder; import metadata::encoder;
import syntax::print::pprust; import syntax::print::pprust;
import syntax::print::pprust::{path_to_str, constr_args_to_str, proto_to_str}; import syntax::print::pprust::{path_to_str, constr_args_to_str, proto_to_str,
mode_to_str};
import syntax::{ast, ast_util}; import syntax::{ast, ast_util};
import middle::ast_map; import middle::ast_map;
fn mode_str(m: ast::mode) -> str {
alt m {
ast::by_ref { "&&" }
ast::by_val { "++" }
ast::by_mut_ref { "&" }
ast::by_move { "-" }
ast::by_copy { "+" }
_ { "" }
}
}
fn ty_to_str(cx: ctxt, typ: t) -> str { fn ty_to_str(cx: ctxt, typ: t) -> str {
fn fn_input_to_str(cx: ctxt, input: {mode: ast::mode, ty: t}) -> fn fn_input_to_str(cx: ctxt, input: {mode: ast::mode, ty: t}) ->
str { str {
let modestr = alt input.mode { let arg_mode = ty::arg_mode(cx, input);
ast::by_ref { let modestr = {
if ty::type_is_immediate(cx, input.ty) { "&&" } else { "" } if arg_mode == ty::default_arg_mode_for_ty(cx, input.ty) { "" }
} else { mode_to_str(input.mode) }
ast::by_val {
if ty::type_is_immediate(cx, input.ty) { "" } else { "++" }
}
_ { mode_str(input.mode) }
}; };
modestr + ty_to_str(cx, input.ty) modestr + ty_to_str(cx, input.ty)
} }
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册