diff options
| author | Niko Matsakis <niko@alum.mit.edu> | 2012-02-02 16:50:17 -0800 |
|---|---|---|
| committer | Niko Matsakis <niko@alum.mit.edu> | 2012-02-05 09:12:44 -0800 |
| commit | 77b06d24cd76bf808138f1f7df4dcff40260ff38 (patch) | |
| tree | 1830c6000f2c4a02be320e088389979cefb1414f /src/comp | |
| parent | 5163606d060ccb2c6462d34f590e2a1f30ce4a1f (diff) | |
| download | rust-77b06d24cd76bf808138f1f7df4dcff40260ff38.tar.gz rust-77b06d24cd76bf808138f1f7df4dcff40260ff38.zip | |
infer modes rather than overwriting with expected ty
Diffstat (limited to 'src/comp')
| -rw-r--r-- | src/comp/front/test.rs | 2 | ||||
| -rw-r--r-- | src/comp/metadata/tydecode.rs | 2 | ||||
| -rw-r--r-- | src/comp/metadata/tyencode.rs | 6 | ||||
| -rw-r--r-- | src/comp/middle/alias.rs | 25 | ||||
| -rw-r--r-- | src/comp/middle/block_use.rs | 2 | ||||
| -rw-r--r-- | src/comp/middle/kind.rs | 5 | ||||
| -rw-r--r-- | src/comp/middle/last_use.rs | 16 | ||||
| -rw-r--r-- | src/comp/middle/mut.rs | 12 | ||||
| -rw-r--r-- | src/comp/middle/trans/base.rs | 33 | ||||
| -rw-r--r-- | src/comp/middle/trans/closure.rs | 11 | ||||
| -rw-r--r-- | src/comp/middle/trans/common.rs | 3 | ||||
| -rw-r--r-- | src/comp/middle/trans/impl.rs | 3 | ||||
| -rw-r--r-- | src/comp/middle/tstate/auxiliary.rs | 8 | ||||
| -rw-r--r-- | src/comp/middle/tstate/pre_post_conditions.rs | 9 | ||||
| -rw-r--r-- | src/comp/middle/ty.rs | 116 | ||||
| -rw-r--r-- | src/comp/middle/typeck.rs | 138 | ||||
| -rw-r--r-- | src/comp/syntax/ast.rs | 12 | ||||
| -rw-r--r-- | src/comp/syntax/parse/parser.rs | 25 | ||||
| -rw-r--r-- | src/comp/syntax/print/pprust.rs | 21 | ||||
| -rw-r--r-- | src/comp/util/ppaux.rs | 26 |
20 files changed, 309 insertions, 166 deletions
diff --git a/src/comp/front/test.rs b/src/comp/front/test.rs index 0e84930658a..5d74165c4b6 100644 --- a/src/comp/front/test.rs +++ b/src/comp/front/test.rs @@ -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()}; diff --git a/src/comp/metadata/tydecode.rs b/src/comp/metadata/tydecode.rs index 92e6da125ef..dc7496dddb3 100644 --- a/src/comp/metadata/tydecode.rs +++ b/src/comp/metadata/tydecode.rs @@ -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); diff --git a/src/comp/metadata/tyencode.rs b/src/comp/metadata/tyencode.rs index 84f77842a58..a9baa4f7470 100644 --- a/src/comp/metadata/tyencode.rs +++ b/src/comp/metadata/tyencode.rs @@ -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); } diff --git a/src/comp/middle/alias.rs b/src/comp/middle/alias.rs index 7aa675c9e8d..388fcb20c47 100644 --- a/src/comp/middle/alias.rs +++ b/src/comp/middle/alias.rs @@ -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) && diff --git a/src/comp/middle/block_use.rs b/src/comp/middle/block_use.rs index 4357f754a58..9d31e089e10 100644 --- a/src/comp/middle/block_use.rs +++ b/src/comp/middle/block_use.rs @@ -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; } diff --git a/src/comp/middle/kind.rs b/src/comp/middle/kind.rs index e06ce29add8..8e02389f2d2 100644 --- a/src/comp/middle/kind.rs +++ b/src/comp/middle/kind.rs @@ -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; } } diff --git a/src/comp/middle/last_use.rs b/src/comp/middle/last_use.rs index 27968048a57..9c7fd7c0bc1 100644 --- a/src/comp/middle/last_use.rs +++ b/src/comp/middle/last_use.rs @@ -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 } diff --git a/src/comp/middle/mut.rs b/src/comp/middle/mut.rs index 42f658ff8d6..8ea39d33de1 100644 --- a/src/comp/middle/mut.rs +++ b/src/comp/middle/mut.rs @@ -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); diff --git a/src/comp/middle/trans/base.rs b/src/comp/middle/trans/base.rs index 33ef3230a23..cc3572e28f1 100644 --- a/src/comp/middle/trans/base.rs +++ b/src/comp/middle/trans/base.rs @@ -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 copy_args_to_allocas(fcx: @fn_ctxt, bcx: @block_ctxt, args: [ast::arg], 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 copy_args_to_allocas(fcx: @fn_ctxt, bcx: @block_ctxt, args: [ast::arg], } } 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_wrapper(ccx: @crate_ctxt, sp: span, 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); diff --git a/src/comp/middle/trans/closure.rs b/src/comp/middle/trans/closure.rs index 43d8c675b22..12997f0e539 100644 --- a/src/comp/middle/trans/closure.rs +++ b/src/comp/middle/trans/closure.rs @@ -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) { diff --git a/src/comp/middle/trans/common.rs b/src/comp/middle/trans/common.rs index 2fb83e0d77e..4f8a6402da3 100644 --- a/src/comp/middle/trans/common.rs +++ b/src/comp/middle/trans/common.rs @@ -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, diff --git a/src/comp/middle/trans/impl.rs b/src/comp/middle/trans/impl.rs index a0bc1a582fa..18ee215b2dc 100644 --- a/src/comp/middle/trans/impl.rs +++ b/src/comp/middle/trans/impl.rs @@ -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)))) diff --git a/src/comp/middle/tstate/auxiliary.rs b/src/comp/middle/tstate/auxiliary.rs index 3ca8a0b89fb..222006f3fa8 100644 --- a/src/comp/middle/tstate/auxiliary.rs +++ b/src/comp/middle/tstate/auxiliary.rs @@ -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] { diff --git a/src/comp/middle/tstate/pre_post_conditions.rs b/src/comp/middle/tstate/pre_post_conditions.rs index 02e5a33545c..0ca3a6ee294 100644 --- a/src/comp/middle/tstate/pre_post_conditions.rs +++ b/src/comp/middle/tstate/pre_post_conditions.rs @@ -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; } } diff --git a/src/comp/middle/ty.rs b/src/comp/middle/ty.rs index 9c507d296c6..02f687cb615 100644 --- a/src/comp/middle/ty.rs +++ b/src/comp/middle/ty.rs @@ -19,7 +19,6 @@ import util::common::*; 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; 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_box; 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 @@ type ctxt = 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 mk_ctxt(s: session::session, dm: resolve::def_map, amap: ast_map::map, 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 @@ pure fn ty_name(cx: ctxt, typ: t) -> option<@str> { } } +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 @@ mod unify { 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 type_err_to_str(err: ty::type_err) -> 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) + diff --git a/src/comp/middle/typeck.rs b/src/comp/middle/typeck.rs index 90dfd5ccd95..148222d95f0 100644 --- a/src/comp/middle/typeck.rs +++ b/src/comp/middle/typeck.rs @@ -64,7 +64,6 @@ type fn_ctxt = 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 @@ mod collect { 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 @@ mod collect { 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 @@ mod writeback { } } } - 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 @@ mod writeback { 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_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier, }]); // 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_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier, 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); diff --git a/src/comp/syntax/ast.rs b/src/comp/syntax/ast.rs index b8e44257f52..8db4573c2b4 100644 --- a/src/comp/syntax/ast.rs +++ b/src/comp/syntax/ast.rs @@ -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_>; diff --git a/src/comp/syntax/parse/parser.rs b/src/comp/syntax/parse/parser.rs index a4ed54f2675..0b321b17b92 100644 --- a/src/comp/syntax/parse/parser.rs +++ b/src/comp/syntax/parse/parser.rs @@ -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, diff --git a/src/comp/syntax/print/pprust.rs b/src/comp/syntax/print/pprust.rs index f4a04c145d7..864702d2ba1 100644 --- a/src/comp/syntax/print/pprust.rs +++ b/src/comp/syntax/print/pprust.rs @@ -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_fn_block_args(s: ps, decl: ast::fn_decl) { 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, ":"); diff --git a/src/comp/util/ppaux.rs b/src/comp/util/ppaux.rs index 4772bbc4fc3..512b02ca734 100644 --- a/src/comp/util/ppaux.rs +++ b/src/comp/util/ppaux.rs @@ -4,32 +4,18 @@ import middle::ty; 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) } |
