提交 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 {
let args_ty: ast::ty = nospan(ast::ty_vec(args_mt));
let args_arg: ast::arg =
{mode: ast::by_val,
{mode: ast::expl(ast::by_val),
ty: @args_ty,
ident: "args",
id: cx.sess.next_node_id()};
......
......@@ -353,7 +353,7 @@ fn parse_ty_fn(st: @pstate, conv: conv_did) -> ty::fn_ty {
'#' { ast::by_val }
};
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 ']'
let cs = parse_constrs(st, conv);
......
......@@ -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) {
w.write_char('[');
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_move { w.write_char('-'); }
by_copy { w.write_char('+'); }
by_ref { 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);
}
......
......@@ -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 args = ty::ty_fn_args(cx.tcx, fty);
for arg in args {
if arg.mode == ast::by_val &&
ty::type_has_dynamic_size(cx.tcx, arg.ty) {
alt ty::resolved_mode(cx.tcx, arg.mode) {
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");
}
_ { /* fallthrough */ }
}
}
......@@ -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 {
let arg = args[i];
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) {
some(def) {
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])
}
_ { }
}
}
ast::by_ref | ast::by_val | ast::by_move | ast::by_copy { }
}
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,
span: arg.span,
root_var: root_var,
local_id: 0u,
unsafe_tys: unsafe_set(root.mut),
mutable copied: alt arg_t.mode {
ast::by_move | ast::by_copy { copied }
ast::by_mut_ref { not_allowed }
_ { not_copied }
}}];
mutable copied: arg_copied}];
i += 1u;
}
let f_may_close =
......@@ -279,7 +285,8 @@ fn check_call(cx: ctx, sc: scope, f: @ast::expr, args: [@ast::expr])
for unsafe_ty in b.unsafe_tys {
let i = 0u;
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 &&
ty_can_unsafely_include(cx, unsafe_ty, arg_t.ty,
mut_alias) &&
......
......@@ -28,7 +28,7 @@ fn visit_expr(ex: @expr, cx: ctx, v: visit::vt<ctx>) {
v.visit_expr(f, cx, v);
let i = 0u;
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);
i += 1u;
}
......
......@@ -165,7 +165,10 @@ fn check_expr(e: @expr, cx: ctx, v: visit::vt<ctx>) {
expr_call(f, args, _) {
let i = 0u;
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;
}
}
......
......@@ -157,7 +157,7 @@ fn visit_expr(ex: @expr, cx: ctx, v: visit::vt<ctx>) {
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); }
_ { v.visit_expr(arg, cx, v); }
}
......@@ -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)
-> option<node_id> {
alt d {
def_local(def_id, let_copy) | def_arg(def_id, by_copy) |
def_arg(def_id, by_move) {
def_local(def_id, let_copy) {
clear_in_current(cx, def_id.node, to);
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
}
......
......@@ -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 i = 0u;
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_move { check_lval(cx, args[i], msg_move_out); }
_ {}
by_ref | by_val | by_copy { }
}
i += 1u;
}
......@@ -267,8 +267,12 @@ fn is_immutable_def(cx: @ctx, def: def) -> option<str> {
def_use(_) {
some("static item")
}
def_arg(_, by_ref) | def_arg(_, by_val) |
def_arg(_, mode_infer) { some("argument") }
def_arg(_, m) {
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_upvar(_, inner, 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)
fn type_of_explicit_args(cx: @crate_ctxt, inputs: [ty::arg]) ->
[TypeRef] {
let atys = [];
for arg in inputs {
let tcx = ccx_tcx(cx);
vec::map(inputs) {|arg|
let arg_ty = arg.ty;
// FIXME: would be nice to have a constraint on arg
// that would obviate the need for this check
check non_ty_var(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,
let lv = trans_temp_lval(cx, e);
let bcx = lv.bcx;
let val = lv.val;
let arg_mode = ty::resolved_mode(ccx.tcx, arg.mode);
if is_bot {
// For values of type _|_, we generate an
// "undef" value, as such a value should never
// be inspected. It's important for the value
// to have type lldestty (the callee's expected type).
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);
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);
copied = true;
}
......@@ -3002,10 +3005,10 @@ fn trans_arg_expr(cx: @block_ctxt, arg: ty::arg, lldestty: TypeRef,
} else { bcx = take_ty(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);
}
} 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 last_use = ccx.last_uses.contains_key(e.id);
bcx = cx;
......@@ -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.
if arg.mode == ast::by_move {
if arg_mode == ast::by_move {
if lv.kind == owned {
// Use actual ty, not declared ty -- anything else doesn't make
// 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,
fn copy_args_to_allocas(fcx: @fn_ctxt, bcx: @block_ctxt, args: [ast::arg],
arg_tys: [ty::arg]) -> @block_ctxt {
let tcx = bcx_tcx(bcx);
let arg_n: uint = 0u, bcx = bcx;
fn epic_fail_(bcx: @block_ctxt) -> ! {
bcx_tcx(bcx).sess.bug("Someone forgot\
let epic_fail = fn@() -> ! {
tcx.sess.bug("Someone forgot\
to document an invariant in copy_args_to_allocas!");
}
let epic_fail = bind epic_fail_(bcx);
......@@ -4424,7 +4428,7 @@ fn epic_fail_(bcx: @block_ctxt) -> ! {
let id = args[arg_n].id;
let argval = alt fcx.llargs.get(id) { local_mem(v) { v }
_ { epic_fail() } };
alt arg.mode {
alt ty::resolved_mode(tcx, arg.mode) {
ast::by_mut_ref { }
ast::by_move | ast::by_copy { add_clean(bcx, argval, arg.ty); }
ast::by_val {
......@@ -4438,7 +4442,6 @@ fn epic_fail_(bcx: @block_ctxt) -> ! {
}
}
ast::by_ref {}
_ { epic_fail(); }
}
if fcx_ccx(fcx).sess.opts.extra_debuginfo {
debuginfo::create_arg(bcx, args[arg_n], args[arg_n].ty.span);
......@@ -4585,7 +4588,7 @@ fn trans_enum_variant(ccx: @crate_ctxt,
// Translate variant arguments to function arguments.
let fn_args = [], i = 0u;
for varg in variant.node.args {
fn_args += [{mode: ast::by_copy,
fn_args += [{mode: ast::expl(ast::by_copy),
ty: varg.ty,
ident: "arg" + uint::to_str(i, 10u),
id: varg.id}];
......@@ -5039,7 +5042,7 @@ fn create_main(ccx: @crate_ctxt, main_llfn: ValueRef,
takes_argv: bool) -> ValueRef {
let unit_ty = ty::mk_str(ccx.tcx);
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})};
// FIXME: mk_nil should have a postcondition
let nt = ty::mk_nil(ccx.tcx);
......
......@@ -895,13 +895,20 @@ fn trans_bind_thunk(ccx: @crate_ctxt,
[0, abi::closure_body_bindings, b]);
bcx = bound_arg.bcx;
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);
bcx = memmove_ty(cx, alloc, val, out_arg.ty);
bcx = take_ty(bcx, alloc, out_arg.ty);
val = alloc;
}
ast::by_ref | ast::by_mut_ref | ast::by_move { }
}
// If the type is parameterized, then we need to cast the
// type we actually have to the parameterized out type.
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)
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, [{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);
ret base::get_extern_const(ccx.externs, ccx.llmod,
csearch::get_symbol(ccx.sess.cstore,
......
......@@ -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 {
let tz = [], tr = [];
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,
tr, base);
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] {
}
fn callee_arg_init_ops(fcx: fn_ctxt, callee: node_id) -> [init_op] {
fn mode_to_op(m: mode) -> init_op {
alt m { by_move { init_move } _ { init_assign } }
vec::map(callee_modes(fcx, callee)) {|m|
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] {
......
......@@ -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],
operands: [@expr]) {
let i = 0u;
for mode: mode in modes {
if mode == by_move {
forget_in_postcond(fcx, parent.id, operands[i].id);
vec::iteri(modes) {|i,mode|
alt ty::resolved_mode(fcx.ccx.tcx, mode) {
by_move { forget_in_postcond(fcx, parent.id, operands[i].id); }
by_ref | by_val | by_mut_ref | by_copy { }
}
i += 1u;
}
}
......
......@@ -19,7 +19,6 @@
import syntax::util::interner;
import util::ppaux::ty_to_str;
import util::ppaux::ty_constr_to_str;
import util::ppaux::mode_str;
import syntax::print::pprust::*;
export node_id_to_type;
......@@ -168,6 +167,10 @@
export type_structurally_contains_uniques;
export type_autoderef;
export type_param;
export resolved_mode;
export arg_mode;
export unify_mode;
export set_default_mode;
export unify;
export variant_info;
export walk_ty;
......@@ -178,12 +181,12 @@
export ck_uniq;
export param_bound, param_bounds, bound_copy, bound_send, bound_iface;
export param_bounds_to_kind;
export default_arg_mode_for_ty;
// Data types
// TODO: really should be a separate type, or a refinement,
// so that we don't have to handle the mode_infer case after
// typeck. but that's too hard right now.
// Note: after typeck, you should use resolved_mode() to convert this mode
// into an rmode, which will take into account the results of mode inference.
type arg = {mode: ast::mode, ty: t};
type field = {ident: ast::ident, mt: mt};
......@@ -217,7 +220,8 @@
ast_ty_to_ty_cache: hashmap<@ast::ty, option<t>>,
enum_var_cache: hashmap<def_id, @[variant_info]>,
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;
......@@ -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),
enum_var_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);
ret cx;
}
......@@ -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)) {
alt struct(cx, ty) {
ty_nil | ty_bot | ty_bool | ty_int(_) | ty_uint(_) | ty_float(_) |
......@@ -684,13 +695,14 @@ enum fold_mode {
fn fold_ty(cx: ctxt, fld: fold_mode, ty_0: t) -> t {
let ty = ty_0;
// Fast paths.
// Fast paths.
alt fld {
fm_var(_) { if !type_contains_vars(cx, ty) { ret ty; } }
fm_param(_) { if !type_contains_params(cx, ty) { ret ty; } }
fm_general(_) {/* no fast path */ }
}
alt interner::get(*cx.ts, ty).struct {
ty_nil | ty_bot | ty_bool | ty_int(_) | ty_uint(_) | ty_float(_) |
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) ->
} 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
// described in Hoder and Voronkov:
//
......@@ -1869,15 +1952,14 @@ fn unify_args(cx: @ctxt, e_args: [arg], a_args: [arg], variance: variance)
for expected_input in e_args {
let actual_input = a_args[i];
i += 1u;
// Unify the result modes.
let result_mode = if expected_input.mode == ast::mode_infer {
actual_input.mode
} else if actual_input.mode == ast::mode_infer {
expected_input.mode
} else if expected_input.mode != actual_input.mode {
ret either::left(ures_err(terr_mode_mismatch(
expected_input.mode, actual_input.mode)));
} else { expected_input.mode };
let result_mode =
alt unify_mode(cx.tcx, expected_input.mode,
actual_input.mode) {
result::err(err) { ret either::left(ures_err(err)); }
result::ok(m) { m }
};
alt unify_step(cx, expected_input.ty, actual_input.ty,
variance) {
......@@ -2446,8 +2528,8 @@ fn to_str(s: ast::ret_style) -> str {
}
terr_arg_count { ret "incorrect number of function parameters"; }
terr_mode_mismatch(e_mode, a_mode) {
ret "expected argument mode " + mode_str(e_mode) + " but found " +
mode_str(a_mode);
ret "expected argument mode " + mode_to_str(e_mode) + " but found " +
mode_to_str(a_mode);
}
terr_constr_len(e_len, a_len) {
ret "Expected a type with " + uint::str(e_len) +
......
......@@ -64,7 +64,6 @@ enum self_info {
var_bindings: @ty::unify::var_bindings,
locals: hashmap<ast::node_id, int>,
next_var_id: @mutable int,
mutable fixups: [ast::node_id],
ccx: @crate_ctxt};
......@@ -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);
}
// 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), }
// 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 getter(tcx: ty::ctxt, mode: mode, id: ast::def_id)
-> ty::ty_param_bounds_and_ty {
......@@ -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 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);
{mode: default_arg_mode_for_ty(tcx, a.mode, ty), ty: ty}
}
fn ty_of_fn_decl(tcx: ty::ctxt, mode: mode,
proto: ast::proto, decl: ast::fn_decl) -> ty::fn_ty {
let input_tys = [];
for a: ast::arg in decl.inputs { input_tys += [ty_of_arg(tcx, mode, a)]; }
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 {
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 out_constrs = [];
......@@ -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::ty_param_bounds_and_ty {
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 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,
} else {
let auto_modes = vec::map2(impl_m.fty.inputs, if_m.fty.inputs, {|i, f|
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 }
}
});
......@@ -641,7 +653,7 @@ fn get_enum_variant_types(cx: @ctxt, enum_ty: ty::t,
let args: [arg] = [];
for va: ast::variant_arg in variant.node.args {
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
ty::mk_fn(cx.tcx,
......@@ -716,7 +728,7 @@ fn convert(cx: @ctxt, it: @ast::item) {
params);
let t_ctor = ty::mk_fn(cx.tcx, {
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,
ret_style: ast::return_val, constraints: []
});
......@@ -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
// unresolved type variables and replaces "ty_var" types with their
// substitutions.
//
// TODO: inefficient since not all types have vars in them. It would be better
// to maintain a list of fixups.
mod writeback {
export resolve_type_vars_in_block;
......@@ -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;
alt resolve_type_vars_in_type(fcx, sp, ty::node_id_to_type(tcx, id)) {
some(t) { write_ty(tcx, id, t); }
none { wbcx.success = false; ret }
}
alt tcx.node_type_substs.find(id) {
some(substs) {
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 {
wbcx.success = false;
ret none;
}
some(t) {
write_ty(tcx, id, t);
alt tcx.node_type_substs.find(id) {
some(substs) {
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) {
alt e.node {
ast::expr_fn(_, decl, _, _) |
ast::expr_fn_block(decl, _) {
for input in decl.inputs {
resolve_type_vars_for_node(wbcx, e.span, input.id);
vec::iter(decl.inputs) {|input|
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,
unify: unifier,
expected: ty::t) {
let tcx = fcx.ccx.tcx;
let fty = ty::mk_fn(tcx, ty_of_fn_decl(tcx, m_check_tyvar(fcx),
proto, decl));
let fty = ty::mk_fn(tcx,
ty_of_fn_decl(tcx, m_check_tyvar(fcx), proto, decl));
#debug("check_expr_fn_with_unifier %s fty=%s",
expr_to_str(expr),
......@@ -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
// 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);
}
......@@ -2027,7 +2056,6 @@ fn check_user_unop(fcx: @fn_ctxt, op_str: str, mname: str,
ty_to_str(tcx, expected));
check_expr_fn_with_unifier(fcx, expr, proto, decl, body,
unify, expected);
write_ty(tcx, id, expected);
}
ast::expr_block(b) {
// 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) {
// FIXME: this is kinda a kludge; we manufacture a fake function context
// and statement context for checking the initializer expression.
let rty = node_id_to_type(ccx.tcx, id);
let fixups: [ast::node_id] = [];
let fcx: @fn_ctxt =
@{ret_ty: rty,
purity: ast::pure_fn,
......@@ -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(),
locals: new_int_hash::<int>(),
next_var_id: @mutable 0,
mutable fixups: fixups,
ccx: ccx};
check_expr(fcx, 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],
// FIXME: this is kinda a kludge; we manufacture a fake function context
// and statement context for checking the initializer expression.
let rty = node_id_to_type(ccx.tcx, id);
let fixups: [ast::node_id] = [];
let fcx: @fn_ctxt =
@{ret_ty: rty,
purity: ast::pure_fn,
......@@ -2457,7 +2482,6 @@ fn check_enum_variants(ccx: @crate_ctxt, sp: span, vs: [ast::variant],
var_bindings: ty::unify::mk_var_bindings(),
locals: new_int_hash::<int>(),
next_var_id: @mutable 0,
mutable fixups: fixups,
ccx: ccx};
let disr_vals: [int] = [];
let disr_val = 0;
......@@ -2630,7 +2654,6 @@ fn check_fn(ccx: @crate_ctxt,
};
let gather_result = gather_locals(ccx, decl, body, id, old_fcx);
let fixups: [ast::node_id] = [];
let fcx: @fn_ctxt =
@{ret_ty: ty::ty_fn_ret(ccx.tcx, ty::node_id_to_type(ccx.tcx, id)),
purity: purity,
......@@ -2638,7 +2661,6 @@ fn check_fn(ccx: @crate_ctxt,
var_bindings: gather_result.var_bindings,
locals: gather_result.locals,
next_var_id: gather_result.next_var_id,
mutable fixups: fixups,
ccx: ccx};
check_constraints(fcx, decl.constraints, decl.inputs);
......
......@@ -160,7 +160,17 @@ enum unop {
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_>;
......
......@@ -521,14 +521,19 @@ fn parse_ty(p: parser, colons_before_params: bool) -> @ast::ty {
}
fn parse_arg_mode(p: parser) -> ast::mode {
if eat(p, token::BINOP(token::AND)) { ast::by_mut_ref }
else if eat(p, token::BINOP(token::MINUS)) { ast::by_move }
else if eat(p, token::ANDAND) { ast::by_ref }
else if eat(p, token::BINOP(token::PLUS)) {
if eat(p, token::BINOP(token::PLUS)) { ast::by_val }
else { ast::by_copy }
}
else { ast::mode_infer }
if eat(p, token::BINOP(token::AND)) {
ast::expl(ast::by_mut_ref)
} else if eat(p, token::BINOP(token::MINUS)) {
ast::expl(ast::by_move)
} else if eat(p, token::ANDAND) {
ast::expl(ast::by_ref)
} else if eat(p, token::BINOP(token::PLUS)) {
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 {
......@@ -1984,8 +1989,8 @@ fn parse_item_res(p: parser, attrs: [ast::attribute]) -> @ast::item {
let dtor = parse_block_no_value(p);
let decl =
{inputs:
[{mode: ast::by_ref, ty: t, ident: arg_ident,
id: p.get_id()}],
[{mode: ast::expl(ast::by_ref), ty: t,
ident: arg_ident, id: p.get_id()}],
output: @spanned(lo, lo, ast::ty_nil),
purity: ast::impure_fn,
cf: ast::return_val,
......
......@@ -136,7 +136,7 @@ fn res_to_str(decl: ast::fn_decl, name: ast::ident,
fn test_res_to_str() {
let decl: ast::fn_decl = {
inputs: [{
mode: ast::by_val,
mode: ast::expl(ast::by_val),
ty: @ast_util::respan(ast_util::dummy_sp(), ast::ty_bool),
ident: "b",
id: 0
......@@ -1280,17 +1280,22 @@ fn print_arg(s: ps, x: ast::arg) {
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 {
ast::by_mut_ref { word(s.s, "&"); }
ast::by_move { word(s.s, "-"); }
ast::by_ref { word(s.s, "&&"); }
ast::by_val { word(s.s, "++"); }
ast::by_copy { word(s.s, "+"); }
ast::mode_infer {}
ast::expl(ast::by_mut_ref) { "&" }
ast::expl(ast::by_move) { "-" }
ast::expl(ast::by_ref) { "&&" }
ast::expl(ast::by_val) { "++" }
ast::expl(ast::by_copy) { "+" }
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]) {
if vec::len(*bounds) > 0u {
word(s.s, ":");
......
......@@ -4,32 +4,18 @@
import middle::ty::*;
import metadata::encoder;
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 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 fn_input_to_str(cx: ctxt, input: {mode: ast::mode, ty: t}) ->
str {
let modestr = alt input.mode {
ast::by_ref {
if ty::type_is_immediate(cx, input.ty) { "&&" } else { "" }
}
ast::by_val {
if ty::type_is_immediate(cx, input.ty) { "" } else { "++" }
}
_ { mode_str(input.mode) }
let arg_mode = ty::arg_mode(cx, input);
let modestr = {
if arg_mode == ty::default_arg_mode_for_ty(cx, input.ty) { "" }
else { mode_to_str(input.mode) }
};
modestr + ty_to_str(cx, input.ty)
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册