Parse and typecheck by-value and by-ref arg specs
Add sprinkle && throughout the compiler to make it typecheck again. Issue #1008
This commit is contained in:
parent
4709038d64
commit
f9fbd86f52
32 changed files with 230 additions and 197 deletions
|
|
@ -251,10 +251,8 @@ fn check_call(cx: ctx, f: @ast::expr, args: [@ast::expr]) -> [binding] {
|
|||
mutable ok: valid,
|
||||
mutable copied: alt arg_t.mode {
|
||||
ast::by_move. { copied }
|
||||
ast::by_ref. {
|
||||
i + 1u == by_ref ? not_allowed : not_copied
|
||||
}
|
||||
ast::by_mut_ref. { not_allowed }
|
||||
_ { i + 1u == by_ref ? not_allowed : not_copied }
|
||||
}}];
|
||||
i += 1u;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -76,7 +76,7 @@ fn map_expr(cx: ctx, ex: @expr) {
|
|||
}
|
||||
|
||||
fn new_smallintmap_int_adapter<@V>() -> std::map::hashmap<int, V> {
|
||||
let key_idx = fn (key: int) -> uint { key as uint };
|
||||
let key_idx = fn (&&key: int) -> uint { key as uint };
|
||||
let idx_key = fn (idx: uint) -> int { idx as int };
|
||||
ret new_smallintmap_adapter(key_idx, idx_key);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ fn check_crate(tcx: ty::ctxt, crate: @crate) {
|
|||
tcx.sess.abort_if_errors();
|
||||
}
|
||||
|
||||
fn check_expr(tcx: ty::ctxt, ex: @expr, s: (), v: visit::vt<()>) {
|
||||
fn check_expr(tcx: ty::ctxt, ex: @expr, &&s: (), v: visit::vt<()>) {
|
||||
visit::visit_expr(ex, s, v);
|
||||
alt ex.node { expr_alt(_, arms) { check_arms(tcx, arms); } _ { } }
|
||||
}
|
||||
|
|
@ -123,7 +123,7 @@ fn pattern_supersedes(tcx: ty::ctxt, a: @pat, b: @pat) -> bool {
|
|||
}
|
||||
}
|
||||
|
||||
fn check_local(tcx: ty::ctxt, loc: @local, s: (), v: visit::vt<()>) {
|
||||
fn check_local(tcx: ty::ctxt, loc: @local, &&s: (), v: visit::vt<()>) {
|
||||
visit::visit_local(loc, s, v);
|
||||
if is_refutable(tcx, loc.node.pat) {
|
||||
tcx.sess.span_err(loc.node.pat.span,
|
||||
|
|
|
|||
|
|
@ -29,10 +29,10 @@ fn collect_freevars(def_map: resolve::def_map, walker: fn(visit::vt<int>)) ->
|
|||
let seen = new_int_hash();
|
||||
let refs = @mutable [];
|
||||
|
||||
fn ignore_item(_i: @ast::item, _depth: int, _v: visit::vt<int>) { }
|
||||
fn ignore_item(_i: @ast::item, &&_depth: int, _v: visit::vt<int>) { }
|
||||
|
||||
let walk_expr =
|
||||
lambda (expr: @ast::expr, depth: int, v: visit::vt<int>) {
|
||||
lambda (expr: @ast::expr, &&depth: int, v: visit::vt<int>) {
|
||||
alt expr.node {
|
||||
ast::expr_fn(f) {
|
||||
if f.proto == ast::proto_block ||
|
||||
|
|
|
|||
|
|
@ -131,7 +131,7 @@ fn mk_err(cx: @ctx, span: syntax::codemap::span, msg: msg, name: str) {
|
|||
});
|
||||
}
|
||||
|
||||
fn visit_decl(cx: @ctx, d: @decl, e: (), v: visit::vt<()>) {
|
||||
fn visit_decl(cx: @ctx, d: @decl, &&e: (), v: visit::vt<()>) {
|
||||
visit::visit_decl(d, e, v);
|
||||
alt d.node {
|
||||
decl_local(locs) {
|
||||
|
|
@ -148,7 +148,7 @@ fn visit_decl(cx: @ctx, d: @decl, e: (), v: visit::vt<()>) {
|
|||
}
|
||||
}
|
||||
|
||||
fn visit_expr(cx: @ctx, ex: @expr, e: (), v: visit::vt<()>) {
|
||||
fn visit_expr(cx: @ctx, ex: @expr, &&e: (), v: visit::vt<()>) {
|
||||
alt ex.node {
|
||||
expr_call(f, args) { check_call(cx, f, args); }
|
||||
expr_swap(lhs, rhs) {
|
||||
|
|
@ -225,7 +225,7 @@ fn check_call(cx: @ctx, f: @expr, args: [@expr]) {
|
|||
alt 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. {}
|
||||
_ {}
|
||||
}
|
||||
i += 1u;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1239,7 +1239,7 @@ fn mie_span(mie: mod_index_entry) -> span {
|
|||
};
|
||||
}
|
||||
|
||||
fn check_item(e: @env, i: @ast::item, x: (), v: vt<()>) {
|
||||
fn check_item(e: @env, i: @ast::item, &&x: (), v: vt<()>) {
|
||||
fn typaram_names(tps: [ast::ty_param]) -> [ident] {
|
||||
let x: [ast::ident] = [];
|
||||
for tp: ast::ty_param in tps { x += [tp.ident]; }
|
||||
|
|
@ -1276,7 +1276,7 @@ fn check_pat(ch: checker, p: @ast::pat) {
|
|||
}
|
||||
}
|
||||
|
||||
fn check_arm(e: @env, a: ast::arm, x: (), v: vt<()>) {
|
||||
fn check_arm(e: @env, a: ast::arm, &&x: (), v: vt<()>) {
|
||||
visit::visit_arm(a, x, v);
|
||||
let ch0 = checker(*e, "binding");
|
||||
check_pat(ch0, a.pats[0]);
|
||||
|
|
@ -1306,7 +1306,7 @@ fn check_arm(e: @env, a: ast::arm, x: (), v: vt<()>) {
|
|||
}
|
||||
}
|
||||
|
||||
fn check_block(e: @env, b: ast::blk, x: (), v: vt<()>) {
|
||||
fn check_block(e: @env, b: ast::blk, &&x: (), v: vt<()>) {
|
||||
visit::visit_block(b, x, v);
|
||||
let values = checker(*e, "value");
|
||||
let types = checker(*e, "type");
|
||||
|
|
@ -1359,7 +1359,7 @@ fn check_fn(e: env, sp: span, f: ast::_fn) {
|
|||
ensure_unique(e, sp, f.decl.inputs, arg_name, "argument");
|
||||
}
|
||||
|
||||
fn check_expr(e: @env, ex: @ast::expr, x: (), v: vt<()>) {
|
||||
fn check_expr(e: @env, ex: @ast::expr, &&x: (), v: vt<()>) {
|
||||
alt ex.node {
|
||||
ast::expr_rec(fields, _) {
|
||||
fn field_name(f: ast::field) -> ident { ret f.node.ident; }
|
||||
|
|
@ -1370,7 +1370,7 @@ fn check_expr(e: @env, ex: @ast::expr, x: (), v: vt<()>) {
|
|||
visit::visit_expr(ex, x, v);
|
||||
}
|
||||
|
||||
fn check_ty(e: @env, ty: @ast::ty, x: (), v: vt<()>) {
|
||||
fn check_ty(e: @env, ty: @ast::ty, &&x: (), v: vt<()>) {
|
||||
alt ty.node {
|
||||
ast::ty_rec(fields) {
|
||||
fn field_name(f: ast::ty_field) -> ident { ret f.node.ident; }
|
||||
|
|
|
|||
|
|
@ -3699,7 +3699,7 @@ fn trans_arg_expr(cx: @block_ctxt, arg: ty::arg, lldestty0: TypeRef,
|
|||
// be inspected. It's important for the value
|
||||
// to have type lldestty0 (the callee's expected type).
|
||||
val = llvm::LLVMGetUndef(lldestty0);
|
||||
} else if arg.mode == ast::by_ref {
|
||||
} else if arg.mode == ast::by_ref || arg.mode == ast::by_val {
|
||||
let copied = false;
|
||||
if !lv.is_mem && type_is_immediate(ccx, e_ty) {
|
||||
val = do_spill_noroot(bcx, val);
|
||||
|
|
@ -4439,9 +4439,9 @@ fn lval_to_dps(bcx: @block_ctxt, e: @ast::expr, dest: dest) -> @block_ctxt {
|
|||
// latter group "immediates" and, in some circumstances when we know we have a
|
||||
// pointer (or need one), perform load/store operations based on the
|
||||
// immediate-ness of the type.
|
||||
// FIXME simply call the version in ty.rs immediately
|
||||
fn type_is_immediate(ccx: @crate_ctxt, t: ty::t) -> bool {
|
||||
ret ty::type_is_scalar(ccx.tcx, t) || ty::type_is_boxed(ccx.tcx, t) ||
|
||||
ty::type_is_unique_box(ccx.tcx, t) || ty::type_is_native(ccx.tcx, t);
|
||||
ty::type_is_immediate(ccx.tcx, t)
|
||||
}
|
||||
|
||||
fn do_spill(cx: @block_ctxt, v: ValueRef, t: ty::t) -> result {
|
||||
|
|
@ -5144,7 +5144,11 @@ fn copy_args_to_allocas(fcx: @fn_ctxt, bcx: @block_ctxt, args: [ast::arg],
|
|||
for aarg: ast::arg in args {
|
||||
let arg_ty = arg_tys[arg_n].ty;
|
||||
alt aarg.mode {
|
||||
ast::by_ref. {
|
||||
ast::by_move. {
|
||||
add_clean(bcx, fcx.llargs.get(aarg.id), arg_ty);
|
||||
}
|
||||
ast::by_mut_ref. { }
|
||||
_ {
|
||||
let mutated =
|
||||
!ignore_mut && fcx.lcx.ccx.mut_map.contains_key(aarg.id);
|
||||
|
||||
|
|
@ -5160,10 +5164,6 @@ fn copy_args_to_allocas(fcx: @fn_ctxt, bcx: @block_ctxt, args: [ast::arg],
|
|||
add_clean(bcx, alloc, arg_ty);
|
||||
}
|
||||
}
|
||||
ast::by_move. {
|
||||
add_clean(bcx, fcx.llargs.get(aarg.id), arg_ty);
|
||||
}
|
||||
_ { }
|
||||
}
|
||||
arg_n += 1u;
|
||||
}
|
||||
|
|
@ -5790,7 +5790,7 @@ fn register_native_fn(ccx: @crate_ctxt, sp: span, path: [str], name: str,
|
|||
}
|
||||
fn convert_arg_to_i32(cx: @block_ctxt, v: ValueRef, t: ty::t,
|
||||
mode: ty::mode) -> ValueRef {
|
||||
if mode == ast::by_ref {
|
||||
if mode == ast::by_ref || mode == ast::by_val {
|
||||
if ty::type_is_integral(bcx_tcx(cx), t) {
|
||||
// FIXME: would be nice to have a postcondition that says
|
||||
// if a type is integral, then it has static size (#586)
|
||||
|
|
@ -5845,7 +5845,7 @@ fn register_native_fn(ccx: @crate_ctxt, sp: span, path: [str], name: str,
|
|||
let i = arg_n;
|
||||
for arg: ty::arg in args {
|
||||
let llarg = llvm::LLVMGetParam(fcx.llfn, i);
|
||||
if arg.mode == ast::by_ref {
|
||||
if arg.mode == ast::by_ref || arg.mode == ast::by_val {
|
||||
llarg = load_if_immediate(bcx, llarg, arg.ty);
|
||||
}
|
||||
assert (llarg as int != 0);
|
||||
|
|
|
|||
|
|
@ -41,7 +41,8 @@ fn trans_obj(cx: @local_ctxt, sp: span, ob: ast::_obj, ctor_id: ast::node_id,
|
|||
// we're creating.
|
||||
let fn_args: [ast::arg] = [];
|
||||
for f: ast::obj_field in ob.fields {
|
||||
fn_args += [{mode: ast::by_ref, ty: f.ty, ident: f.ident, id: f.id}];
|
||||
fn_args += [{mode: ast::by_ref, ty: f.ty, ident: f.ident,
|
||||
id: f.id}];
|
||||
}
|
||||
let fcx = new_fn_ctxt(cx, sp, llctor_decl);
|
||||
|
||||
|
|
@ -397,7 +398,7 @@ tag vtbl_mthd {
|
|||
}
|
||||
|
||||
// Alphabetize ast::methods by ident. A helper for create_vtbl.
|
||||
fn ast_mthd_lteq(a: @ast::method, b: @ast::method) -> bool {
|
||||
fn ast_mthd_lteq(&&a: @ast::method, &&b: @ast::method) -> bool {
|
||||
ret str::lteq(a.node.ident, b.node.ident);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -99,10 +99,10 @@ fn find_pre_post_exprs(fcx: fn_ctxt, args: [@expr], id: node_id) {
|
|||
fn get_pp(ccx: crate_ctxt, e: @expr) -> pre_and_post {
|
||||
ret expr_pp(ccx, e);
|
||||
}
|
||||
let pps = vec::map::<@expr, pre_and_post>(bind get_pp(fcx.ccx, _), args);
|
||||
let pps = vec::map_imm(bind get_pp(fcx.ccx, _), args);
|
||||
|
||||
set_pre_and_post(fcx.ccx, id, seq_preconds(fcx, pps),
|
||||
seq_postconds(fcx, vec::map(get_post, pps)));
|
||||
seq_postconds(fcx, vec::map_imm(get_post, pps)));
|
||||
}
|
||||
|
||||
fn find_pre_post_loop(fcx: fn_ctxt, l: @local, index: @expr, body: blk,
|
||||
|
|
@ -476,8 +476,8 @@ fn find_pre_post_expr(fcx: fn_ctxt, e: @expr) {
|
|||
}
|
||||
let alt_pps = [];
|
||||
for a: arm in alts { alt_pps += [do_an_alt(fcx, a)]; }
|
||||
fn combine_pp(antec: pre_and_post, fcx: fn_ctxt, pp: pre_and_post,
|
||||
next: pre_and_post) -> pre_and_post {
|
||||
fn combine_pp(antec: pre_and_post, fcx: fn_ctxt, &&pp: pre_and_post,
|
||||
&&next: pre_and_post) -> pre_and_post {
|
||||
union(pp.precondition, seq_preconds(fcx, [antec, next]));
|
||||
intersect(pp.postcondition, next.postcondition);
|
||||
ret pp;
|
||||
|
|
@ -694,7 +694,7 @@ fn find_pre_post_block(fcx: fn_ctxt, b: blk) {
|
|||
*/
|
||||
}
|
||||
for s: @stmt in b.node.stmts { do_one_(fcx, s); }
|
||||
fn do_inner_(fcx: fn_ctxt, e: @expr) { find_pre_post_expr(fcx, e); }
|
||||
fn do_inner_(fcx: fn_ctxt, &&e: @expr) { find_pre_post_expr(fcx, e); }
|
||||
let do_inner = bind do_inner_(fcx, _);
|
||||
option::map::<@expr, ()>(do_inner, b.node.expr);
|
||||
|
||||
|
|
|
|||
|
|
@ -160,6 +160,7 @@ export type_is_native;
|
|||
export type_is_nil;
|
||||
export type_is_pod;
|
||||
export type_is_scalar;
|
||||
export type_is_immediate;
|
||||
export type_is_sequence;
|
||||
export type_is_signed;
|
||||
export type_is_structural;
|
||||
|
|
@ -916,6 +917,12 @@ pure fn type_is_scalar(cx: ctxt, ty: t) -> bool {
|
|||
}
|
||||
}
|
||||
|
||||
// FIXME maybe inline this for speed?
|
||||
fn type_is_immediate(cx: ctxt, ty: t) -> bool {
|
||||
ret type_is_scalar(cx, ty) || type_is_boxed(cx, ty) ||
|
||||
type_is_unique_box(cx, ty) || type_is_native(cx, ty);
|
||||
}
|
||||
|
||||
fn type_has_pointers(cx: ctxt, ty: t) -> bool {
|
||||
alt cx.has_pointer_cache.find(ty) {
|
||||
some(result) { ret result; }
|
||||
|
|
@ -924,14 +931,8 @@ fn type_has_pointers(cx: ctxt, ty: t) -> bool {
|
|||
|
||||
let result = false;
|
||||
alt struct(cx, ty) {
|
||||
|
||||
|
||||
|
||||
// scalar types
|
||||
ty_nil. {
|
||||
/* no-op */
|
||||
|
||||
}
|
||||
ty_nil. {/* no-op */ }
|
||||
ty_bot. {/* no-op */ }
|
||||
ty_bool. {/* no-op */ }
|
||||
ty_int. {/* no-op */ }
|
||||
|
|
@ -1446,14 +1447,14 @@ fn hash_type_info(st: sty, cname_opt: option::t<str>) -> uint {
|
|||
ret h;
|
||||
}
|
||||
|
||||
fn hash_raw_ty(rt: @raw_t) -> uint { ret rt.hash; }
|
||||
fn hash_raw_ty(&&rt: @raw_t) -> uint { ret rt.hash; }
|
||||
|
||||
fn hash_ty(typ: t) -> uint { ret typ; }
|
||||
fn hash_ty(&&typ: t) -> uint { ret typ; }
|
||||
|
||||
|
||||
// Type equality. This function is private to this module (and slow); external
|
||||
// users should use `eq_ty()` instead.
|
||||
fn eq_int(x: uint, y: uint) -> bool { ret x == y; }
|
||||
fn eq_int(&&x: uint, &&y: uint) -> bool { ret x == y; }
|
||||
|
||||
fn arg_eq<T>(eq: fn(T, T) -> bool, a: @sp_constr_arg<T>, b: @sp_constr_arg<T>)
|
||||
-> bool {
|
||||
|
|
@ -1495,7 +1496,7 @@ fn constrs_eq(cs: [@constr], ds: [@constr]) -> bool {
|
|||
|
||||
// An expensive type equality function. This function is private to this
|
||||
// module.
|
||||
fn eq_raw_ty(a: @raw_t, b: @raw_t) -> bool {
|
||||
fn eq_raw_ty(&&a: @raw_t, &&b: @raw_t) -> bool {
|
||||
// Check hashes (fast path).
|
||||
|
||||
if a.hash != b.hash { ret false; }
|
||||
|
|
@ -1518,7 +1519,7 @@ fn eq_raw_ty(a: @raw_t, b: @raw_t) -> bool {
|
|||
|
||||
// This is the equality function the public should use. It works as long as
|
||||
// the types are interned.
|
||||
fn eq_ty(a: t, b: t) -> bool { ret a == b; }
|
||||
fn eq_ty(&&a: t, &&b: t) -> bool { ret a == b; }
|
||||
|
||||
|
||||
// Type lookups
|
||||
|
|
@ -1954,12 +1955,15 @@ mod unify {
|
|||
let actual_input = actual_inputs[i];
|
||||
// Unify the result modes.
|
||||
|
||||
let result_mode;
|
||||
if expected_input.mode != actual_input.mode {
|
||||
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 fn_common_res_err
|
||||
(ures_err(terr_mode_mismatch(expected_input.mode,
|
||||
actual_input.mode)));
|
||||
} else { result_mode = expected_input.mode; }
|
||||
} else { expected_input.mode };
|
||||
let result = unify_step(cx, expected_input.ty, actual_input.ty);
|
||||
alt result {
|
||||
ures_ok(rty) { result_ins += [{mode: result_mode, ty: rty}]; }
|
||||
|
|
|
|||
|
|
@ -224,7 +224,27 @@ fn type_is_scalar(fcx: @fn_ctxt, sp: span, typ: ty::t) -> bool {
|
|||
// 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 }
|
||||
}
|
||||
}
|
||||
fn ast_ty_to_ty(tcx: ty::ctxt, getter: ty_getter, ast_ty: @ast::ty) -> ty::t {
|
||||
fn ast_arg_to_arg(tcx: ty::ctxt, getter: ty_getter, arg: ast::ty_arg)
|
||||
-> {mode: ty::mode, ty: ty::t} {
|
||||
let ty = ast_ty_to_ty(tcx, getter, arg.node.ty);
|
||||
ret {mode: default_arg_mode_for_ty(tcx, arg.node.mode, ty), ty: ty};
|
||||
}
|
||||
alt tcx.ast_ty_to_ty_cache.find(ast_ty) {
|
||||
some(some(ty)) { ret ty; }
|
||||
some(none.) {
|
||||
|
|
@ -237,10 +257,6 @@ fn ast_ty_to_ty(tcx: ty::ctxt, getter: ty_getter, ast_ty: @ast::ty) -> ty::t {
|
|||
} /* go on */
|
||||
|
||||
tcx.ast_ty_to_ty_cache.insert(ast_ty, none::<ty::t>);
|
||||
fn ast_arg_to_arg(tcx: ty::ctxt, getter: ty_getter, arg: ast::ty_arg) ->
|
||||
{mode: ty::mode, ty: ty::t} {
|
||||
ret {mode: arg.node.mode, ty: ast_ty_to_ty(tcx, getter, arg.node.ty)};
|
||||
}
|
||||
fn ast_mt_to_mt(tcx: ty::ctxt, getter: ty_getter, mt: ast::mt) -> ty::mt {
|
||||
ret {ty: ast_ty_to_ty(tcx, getter, mt.ty), mut: mt.mut};
|
||||
}
|
||||
|
|
@ -295,7 +311,7 @@ fn ast_ty_to_ty(tcx: ty::ctxt, getter: ty_getter, ast_ty: @ast::ty) -> ty::t {
|
|||
typ = ty::mk_ptr(tcx, ast_mt_to_mt(tcx, getter, mt));
|
||||
}
|
||||
ast::ty_tup(fields) {
|
||||
let flds = vec::map(bind ast_ty_to_ty(tcx, getter, _), fields);
|
||||
let flds = vec::map_imm(bind ast_ty_to_ty(tcx, getter, _), fields);
|
||||
typ = ty::mk_tup(tcx, flds);
|
||||
}
|
||||
ast::ty_rec(fields) {
|
||||
|
|
@ -550,9 +566,8 @@ mod collect {
|
|||
ret tpt;
|
||||
}
|
||||
fn ty_of_arg(cx: @ctxt, a: ast::arg) -> ty::arg {
|
||||
let f = bind getter(cx, _);
|
||||
let tt = ast_ty_to_ty(cx.tcx, f, a.ty);
|
||||
ret {mode: a.mode, ty: tt};
|
||||
let ty = ast_ty_to_ty(cx.tcx, bind getter(cx, _), a.ty);
|
||||
{mode: default_arg_mode_for_ty(cx.tcx, a.mode, ty), ty: ty}
|
||||
}
|
||||
fn ty_of_method(cx: @ctxt, m: @ast::method) -> ty::method {
|
||||
let get = bind getter(cx, _);
|
||||
|
|
@ -1216,7 +1231,7 @@ fn gather_locals(ccx: @crate_ctxt, f: ast::_fn, id: ast::node_id,
|
|||
|
||||
// Add explicitly-declared locals.
|
||||
let visit_local =
|
||||
lambda (local: @ast::local, e: (), v: visit::vt<()>) {
|
||||
lambda (local: @ast::local, &&e: (), v: visit::vt<()>) {
|
||||
let local_ty = ast_ty_to_ty_crate_infer(ccx, local.node.ty);
|
||||
assign(local.node.id, ident_for_local(local), local_ty);
|
||||
visit::visit_local(local, e, v);
|
||||
|
|
@ -1224,7 +1239,7 @@ fn gather_locals(ccx: @crate_ctxt, f: ast::_fn, id: ast::node_id,
|
|||
|
||||
// Add pattern bindings.
|
||||
let visit_pat =
|
||||
lambda (p: @ast::pat, e: (), v: visit::vt<()>) {
|
||||
lambda (p: @ast::pat, &&e: (), v: visit::vt<()>) {
|
||||
alt p.node {
|
||||
ast::pat_bind(ident) { assign(p.id, ident, none); }
|
||||
_ {/* no-op */ }
|
||||
|
|
@ -2022,16 +2037,16 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier,
|
|||
write::ty_only_fixup(fcx, id, result_ty);
|
||||
}
|
||||
ast::expr_fn(f) {
|
||||
let cx = @{tcx: tcx};
|
||||
let convert = bind ast_ty_to_ty_crate_tyvar(fcx, _);
|
||||
let ty_of_arg =
|
||||
lambda (a: ast::arg) -> ty::arg {
|
||||
let tt = ast_ty_to_ty_crate_tyvar(fcx, a.ty);
|
||||
ret {mode: a.mode, ty: tt};
|
||||
};
|
||||
let fty =
|
||||
collect::ty_of_fn_decl(cx, convert, ty_of_arg, f.decl, f.proto,
|
||||
[], none).ty;
|
||||
let ty_of_arg = lambda (a: ast::arg) -> ty::arg {
|
||||
let tt = ast_ty_to_ty_crate_tyvar(fcx, a.ty);
|
||||
ret {mode: default_arg_mode_for_ty(fcx.ccx.tcx, a.mode, tt),
|
||||
ty: tt};
|
||||
};
|
||||
let cx = @{tcx: tcx};
|
||||
let fty = collect::ty_of_fn_decl(cx, convert, ty_of_arg, f.decl,
|
||||
f.proto, [], none).ty;
|
||||
|
||||
write::ty_only_fixup(fcx, id, fty);
|
||||
|
||||
// Unify the type of the function with the expected type before we
|
||||
|
|
@ -2041,6 +2056,9 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier,
|
|||
unify(fcx, expr.span, expected, fty);
|
||||
|
||||
check_fn(fcx.ccx, f, id, some(fcx));
|
||||
if f.proto == ast::proto_block {
|
||||
write::ty_only_fixup(fcx, id, expected);
|
||||
}
|
||||
}
|
||||
ast::expr_block(b) {
|
||||
// If this is an unchecked block, turn off purity-checking
|
||||
|
|
@ -2301,7 +2319,8 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier,
|
|||
// FIXME: These next three functions are largely ripped off from
|
||||
// similar ones in collect::. Is there a better way to do this?
|
||||
fn ty_of_arg(ccx: @crate_ctxt, a: ast::arg) -> ty::arg {
|
||||
ret {mode: a.mode, ty: ast_ty_to_ty_crate(ccx, a.ty)};
|
||||
let ty = ast_ty_to_ty_crate(ccx, a.ty);
|
||||
ret {mode: default_arg_mode_for_ty(ccx.tcx, a.mode, ty), ty: ty};
|
||||
}
|
||||
|
||||
fn ty_of_method(ccx: @crate_ctxt, m: @ast::method) -> ty::method {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue