From 2b45da8a339d1e2935d250cfae63b44a3b16688f Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 28 Mar 2012 12:54:06 -0700 Subject: [PATCH] refactor to store the types during inference in tables in the fcx this is a step towards separating out the repr. of types during inference from the repr. in later stages. --- src/librustsyntax/visit.rs | 10 +- src/rustc/middle/ast_map.rs | 52 ++++ src/rustc/middle/ty.rs | 3 +- src/rustc/middle/typeck.rs | 473 ++++++++++++++++++++++-------------- 4 files changed, 358 insertions(+), 180 deletions(-) diff --git a/src/librustsyntax/visit.rs b/src/librustsyntax/visit.rs index b4bcb3aaa31..a27293ea19e 100644 --- a/src/librustsyntax/visit.rs +++ b/src/librustsyntax/visit.rs @@ -130,7 +130,7 @@ fn visit_item(i: @item, e: E, v: vt) { } item_impl(tps, ifce, ty, methods) { v.visit_ty_params(tps, e, v); - alt ifce { some(ty) { v.visit_ty(ty, e, v); } _ {} } + alt ifce { some(ty) { v.visit_ty(ty, e, v); } none {} } v.visit_ty(ty, e, v); for m in methods { visit_method_helper(m, e, v) @@ -193,7 +193,11 @@ fn visit_ty(t: @ty, e: E, v: vt) { v.visit_constr(tc.node.path, tc.span, tc.node.id, e, v); } } - _ {} + ty_nil | + ty_bot | + ty_mac(_) | + ty_infer { + } } } @@ -243,7 +247,7 @@ fn visit_ty_params(tps: [ty_param], e: E, v: vt) { for bound in *tp.bounds { alt bound { bound_iface(t) { v.visit_ty(t, e, v); } - _ {} + bound_copy | bound_send { } } } } diff --git a/src/rustc/middle/ast_map.rs b/src/rustc/middle/ast_map.rs index 18a7f42f332..070787737a6 100644 --- a/src/rustc/middle/ast_map.rs +++ b/src/rustc/middle/ast_map.rs @@ -1,6 +1,7 @@ import std::map; import std::map::hashmap; import syntax::ast::*; +import syntax::print::pprust; import syntax::ast_util; import syntax::ast_util::inlined_item_methods; import syntax::{visit, codemap}; @@ -20,6 +21,14 @@ fn path_to_str_with_sep(p: path, sep: str) -> str { str::connect(strs, sep) } +fn path_ident_to_str(p: path, i: ident) -> str { + if vec::is_empty(p) { + i + } else { + #fmt["%s::%s", path_to_str(p), i] + } +} + fn path_to_str(p: path) -> str { path_to_str_with_sep(p, "::") } @@ -224,6 +233,49 @@ fn map_expr(ex: @expr, cx: ctx, v: vt) { visit::visit_expr(ex, cx, v); } +fn node_id_to_str(map: map, id: node_id) -> str { + alt map.find(id) { + none { + #fmt["unknown node (id=%d)", id] + } + some(node_item(item, path)) { + #fmt["item %s (id=%?)", path_ident_to_str(*path, item.ident), id] + } + some(node_native_item(item, abi, path)) { + #fmt["native item %s with abi %? (id=%?)", + path_ident_to_str(*path, item.ident), abi, id] + } + some(node_method(m, impl_did, path)) { + #fmt["method %s in %s (id=%?)", + m.ident, path_to_str(*path), id] + } + some(node_variant(variant, def_id, path)) { + #fmt["variant %s in %s (id=%?)", + variant.node.name, path_to_str(*path), id] + } + some(node_expr(expr)) { + #fmt["expr %s (id=%?)", + pprust::expr_to_str(expr), id] + } + some(node_export(_, path)) { + #fmt["export %s (id=%?)", // FIXME: add more info here + path_to_str(*path), id] + } + some(node_arg(_, _)) { // FIXME: add more info here + #fmt["arg (id=%?)", id] + } + some(node_local(_)) { // FIXME: add more info here + #fmt["local (id=%?)", id] + } + some(node_ctor(_, _)) { // FIXME: add more info here + #fmt["node_ctor (id=%?)", id] + } + some(node_block(_)) { + #fmt["block"] + } + } +} + // Local Variables: // mode: rust // fill-column: 78; diff --git a/src/rustc/middle/ty.rs b/src/rustc/middle/ty.rs index 50730d0ed86..ad4d0ec58b2 100644 --- a/src/rustc/middle/ty.rs +++ b/src/rustc/middle/ty.rs @@ -1561,7 +1561,8 @@ fn constrs_eq(cs: [@constr], ds: [@constr]) -> bool { fn node_id_to_type(cx: ctxt, id: ast::node_id) -> t { alt smallintmap::find(*cx.node_types, id as uint) { some(t) { t } - none { cx.sess.bug(#fmt("node_id_to_type: unbound node ID %?", id)); } + none { cx.sess.bug(#fmt("node_id_to_type: unbound node ID %s", + ast_map::node_id_to_str(cx.items, id))); } } } diff --git a/src/rustc/middle/typeck.rs b/src/rustc/middle/typeck.rs index 9f5f66cc149..12c81361c6b 100644 --- a/src/rustc/middle/typeck.rs +++ b/src/rustc/middle/typeck.rs @@ -9,11 +9,12 @@ import util::common::*; import syntax::codemap::span; import pat_util::*; import middle::ty; -import middle::ty::{node_id_to_type, arg, block_ty, - expr_ty, field, node_type_table, mk_nil, +import middle::ty::{arg, field, node_type_table, mk_nil, ty_param_bounds_and_ty, lookup_public_fields}; import util::ppaux::ty_to_str; import std::smallintmap; +import std::smallintmap::map; +import std::map; import std::map::{hashmap, int_hash}; import std::serialization::{serialize_uint, deserialize_uint}; import std::ufind; @@ -81,6 +82,8 @@ type fn_ctxt = locals: hashmap, next_var_id: @mut int, next_region_var_id: @mut int, + node_types: smallintmap::smallintmap, + node_type_substs: hashmap, ccx: @crate_ctxt}; // Determines whether the given node ID is a use of the def of @@ -202,12 +205,12 @@ fn instantiate_path(fcx: @fn_ctxt, pth: @ast::path, let substs = vec::map(pth.node.types, {|aty| ast_ty_to_ty_crate(fcx.ccx, aty) }); - write_ty_substs(fcx.ccx.tcx, id, tpt.ty, substs); + fcx.write_ty_substs(id, tpt.ty, substs); } else if ty_param_count > 0u { let vars = vec::from_fn(ty_param_count, {|_i| next_ty_var(fcx)}); - write_ty_substs(fcx.ccx.tcx, id, tpt.ty, vars); + fcx.write_ty_substs(id, tpt.ty, vars); } else { - write_ty(fcx.ccx.tcx, id, tpt.ty); + fcx.write_ty(id, tpt.ty); } } @@ -308,7 +311,7 @@ fn ast_ty_to_ty(tcx: ty::ctxt, mode: mode, &&ast_ty: @ast::ty) -> ty::t { let typ = ty::substitute_type_params(tcx, param_bindings, ty_param_bounds_and_ty.ty); - write_substs(tcx, path_id, param_bindings); + write_substs_to_tcx(tcx, path_id, param_bindings); ret typ; } fn do_ast_ty_to_ty(tcx: ty::ctxt, mode: mode, &&ast_ty: @ast::ty) @@ -738,25 +741,83 @@ fn ast_ty_to_ty_crate_infer(ccx: @crate_ctxt, &&ast_ty: @ast::ty) -> // Functions that write types into the node type table -fn write_ty(tcx: ty::ctxt, node_id: ast::node_id, ty: ty::t) { +fn write_ty_to_tcx(tcx: ty::ctxt, node_id: ast::node_id, ty: ty::t) { smallintmap::insert(*tcx.node_types, node_id as uint, ty); } -fn write_substs(tcx: ty::ctxt, node_id: ast::node_id, +substs: [ty::t]) { +fn write_substs_to_tcx(tcx: ty::ctxt, node_id: ast::node_id, + +substs: [ty::t]) { tcx.node_type_substs.insert(node_id, substs); } -fn write_ty_substs(tcx: ty::ctxt, node_id: ast::node_id, ty: ty::t, +fn write_ty_substs_to_tcx(tcx: ty::ctxt, node_id: ast::node_id, ty: ty::t, +substs: [ty::t]) { let ty = if ty::type_has_params(ty) { ty::substitute_type_params(tcx, substs, ty) } else { ty }; - write_ty(tcx, node_id, ty); - write_substs(tcx, node_id, substs); + write_ty_to_tcx(tcx, node_id, ty); + write_substs_to_tcx(tcx, node_id, substs); } -fn write_nil(tcx: ty::ctxt, node_id: ast::node_id) { - write_ty(tcx, node_id, ty::mk_nil(tcx)); -} -fn write_bot(tcx: ty::ctxt, node_id: ast::node_id) { - write_ty(tcx, node_id, ty::mk_bot(tcx)); + +impl methods for @fn_ctxt { + fn tcx() -> ty::ctxt { self.ccx.tcx } + fn tag() -> str { #fmt["%x", ptr::addr_of(*self) as uint] } + fn write_ty(node_id: ast::node_id, ty: ty::t) { + #debug["write_ty(%d, %s) in fcx %s", + node_id, ty_to_str(self.tcx(), ty), self.tag()]; + self.node_types.insert(node_id as uint, ty); + } + fn write_substs(node_id: ast::node_id, +substs: [ty::t]) { + self.node_type_substs.insert(node_id, substs); + } + fn write_ty_substs(node_id: ast::node_id, ty: ty::t, +substs: [ty::t]) { + if substs.len() == 0u { + self.write_ty(node_id, ty) + } else { + let ty = ty::substitute_type_params(self.tcx(), substs, ty); + self.write_ty(node_id, ty); + self.write_substs(node_id, substs); + } + } + fn write_nil(node_id: ast::node_id) { + self.write_ty(node_id, ty::mk_nil(self.tcx())); + } + fn write_bot(node_id: ast::node_id) { + self.write_ty(node_id, ty::mk_bot(self.tcx())); + } + + fn expr_ty(ex: @ast::expr) -> ty::t { + alt self.node_types.find(ex.id as uint) { + some(t) { t } + none { + self.tcx().sess.bug(#fmt["no type for expr %d (%s) in fcx %s", + ex.id, expr_to_str(ex), self.tag()]); + } + } + } + fn node_ty(id: ast::node_id) -> ty::t { + alt self.node_types.find(id as uint) { + some(t) { t } + none { + self.tcx().sess.bug( + #fmt["no type for node %d: %s in fcx %s", + id, ast_map::node_id_to_str(self.tcx().items, id), + self.tag()]); + } + } + } + fn node_ty_substs(id: ast::node_id) -> [ty::t] { + alt self.node_type_substs.find(id) { + some(ts) { ts } + none { + self.tcx().sess.bug( + #fmt["no type substs for node %d: %s in fcx %s", + id, ast_map::node_id_to_str(self.tcx().items, id), + self.tag()]); + } + } + } + fn opt_node_ty_substs(id: ast::node_id) -> option<[ty::t]> { + self.node_type_substs.find(id) + } } fn mk_ty_params(tcx: ty::ctxt, atps: [ast::ty_param]) @@ -926,7 +987,7 @@ mod collect { let tpt = {bounds: ty_param_bounds(tcx, m_collect, ty_params), ty: result_ty}; tcx.tcache.insert(local_def(variant.node.id), tpt); - write_ty(tcx, variant.node.id, result_ty); + write_ty_to_tcx(tcx, variant.node.id, result_ty); } } fn ensure_iface_methods(tcx: ty::ctxt, id: ast::node_id) { @@ -958,7 +1019,7 @@ mod collect { class. outside the class, it's done with expr_field */ let tt = ast_ty_to_ty(tcx, m_collect, v.ty); #debug("convert_class_item: %s %?", v.ident, v.id); - write_ty(tcx, v.id, tt); + write_ty_to_tcx(tcx, v.id, tt); } fn convert_methods(tcx: ty::ctxt, ms: [@ast::method], i_bounds: @[ty::param_bounds], maybe_self: option) @@ -967,7 +1028,7 @@ mod collect { for m in ms { alt maybe_self { some(selfty) { - write_ty(tcx, m.self_id, selfty); + write_ty_to_tcx(tcx, m.self_id, selfty); } _ {} } @@ -978,7 +1039,7 @@ mod collect { tcx.tcache.insert(local_def(m.id), {bounds: @(*i_bounds + *bounds), ty: fty}); - write_ty(tcx, m.id, fty); + write_ty_to_tcx(tcx, m.id, fty); } my_methods } @@ -994,13 +1055,13 @@ mod collect { } ast::item_enum(variants, ty_params) { let tpt = ty_of_item(tcx, m_collect, it); - write_ty(tcx, it.id, tpt.ty); + write_ty_to_tcx(tcx, it.id, tpt.ty); get_enum_variant_types(tcx, tpt.ty, variants, ty_params); } ast::item_impl(tps, ifce, selfty, ms) { let i_bounds = ty_param_bounds(tcx, m_collect, tps); let selfty = ast_ty_to_ty(tcx, m_collect, selfty); - write_ty(tcx, it.id, selfty); + write_ty_to_tcx(tcx, it.id, selfty); tcx.tcache.insert(local_def(it.id), {bounds: i_bounds, ty: selfty}); let my_methods = convert_methods(tcx, ms, i_bounds, some(selfty)); @@ -1011,7 +1072,9 @@ mod collect { ty::ty_iface(did, tys) { // Store the iface type in the type node alt check t.node { - ast::ty_path(_, t_id) { write_ty(tcx, t_id, iface_ty); } + ast::ty_path(_, t_id) { + write_ty_to_tcx(tcx, t_id, iface_ty); + } } if did.crate == ast::local_crate { ensure_iface_methods(tcx, did.node); @@ -1034,7 +1097,7 @@ mod collect { tcx.tcache.insert(local_def(id), {bounds: old.bounds, ty: mt}); - write_ty(tcx, id, mt); + write_ty_to_tcx(tcx, id, mt); } } none { @@ -1069,27 +1132,27 @@ mod collect { inputs: [t_arg], output: ty::mk_nil(tcx), ret_style: ast::return_val, constraints: [] }); - write_ty(tcx, it.id, t_res); - write_ty(tcx, ctor_id, t_ctor); + write_ty_to_tcx(tcx, it.id, t_res); + write_ty_to_tcx(tcx, ctor_id, t_ctor); tcx.tcache.insert(local_def(ctor_id), {bounds: bounds, ty: t_ctor}); tcx.tcache.insert(def_id, {bounds: bounds, ty: t_res}); - write_ty(tcx, dtor_id, t_dtor); + write_ty_to_tcx(tcx, dtor_id, t_dtor); } ast::item_iface(_, ms) { let tpt = ty_of_item(tcx, m_collect, it); - write_ty(tcx, it.id, tpt.ty); + write_ty_to_tcx(tcx, it.id, tpt.ty); ensure_iface_methods(tcx, it.id); } ast::item_class(tps, members, ctor) { // Write the class type let tpt = ty_of_item(tcx, m_collect, it); - write_ty(tcx, it.id, tpt.ty); + write_ty_to_tcx(tcx, it.id, tpt.ty); // Write the ctor type let t_ctor = ty::mk_fn(tcx, ty_of_fn_decl(tcx, m_collect, ast::proto_any, ctor.node.dec)); - write_ty(tcx, ctor.node.id, t_ctor); + write_ty_to_tcx(tcx, ctor.node.id, t_ctor); tcx.tcache.insert(local_def(ctor.node.id), {bounds: tpt.bounds, ty: t_ctor}); ensure_iface_methods(tcx, it.id); @@ -1111,7 +1174,7 @@ mod collect { // of the item in passing. All we have to do here is to write // it into the node type table. let tpt = ty_of_item(tcx, m_collect, it); - write_ty(tcx, it.id, tpt.ty); + write_ty_to_tcx(tcx, it.id, tpt.ty); } } } @@ -1121,7 +1184,9 @@ mod collect { // table. let tpt = ty_of_native_item(tcx, m_collect, i); alt i.node { - ast::native_item_fn(_, _) { write_ty(tcx, i.id, tpt.ty); } + ast::native_item_fn(_, _) { + write_ty_to_tcx(tcx, i.id, tpt.ty); + } } } fn collect_item_types(tcx: ty::ctxt, crate: @ast::crate) { @@ -1327,7 +1392,7 @@ fn variant_arg_types(ccx: @crate_ctxt, _sp: span, vid: ast::def_id, // substitutions. mod writeback { - export resolve_type_vars_in_block; + export resolve_type_vars_in_fn; export resolve_type_vars_in_expr; fn resolve_type_vars_in_type(fcx: @fn_ctxt, sp: span, typ: ty::t) -> @@ -1353,15 +1418,15 @@ mod writeback { fn resolve_type_vars_for_node(wbcx: wb_ctxt, sp: span, id: ast::node_id) -> option { 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, fcx.node_ty(id)) { none { wbcx.success = false; ret none; } some(t) { - write_ty(tcx, id, t); - alt tcx.node_type_substs.find(id) { + write_ty_to_tcx(tcx, id, t); + alt fcx.opt_node_ty_substs(id) { some(substs) { let mut new_substs = []; for subst: ty::t in substs { @@ -1370,7 +1435,7 @@ mod writeback { none { wbcx.success = false; ret none; } } } - write_substs(tcx, id, new_substs); + write_substs_to_tcx(tcx, id, new_substs); } none {} } @@ -1379,6 +1444,16 @@ mod writeback { } } + fn maybe_resolve_type_vars_for_node(wbcx: wb_ctxt, sp: span, + id: ast::node_id) + -> option { + if wbcx.fcx.node_types.contains_key(id as uint) { + resolve_type_vars_for_node(wbcx, sp, id) + } else { + none + } + } + type wb_ctxt = // As soon as we hit an error we have to stop resolving // the entire function @@ -1411,6 +1486,17 @@ mod writeback { } } } + + ast::expr_new(_, alloc_id, _) { + resolve_type_vars_for_node(wbcx, e.span, alloc_id); + } + + ast::expr_binary(_, _, _) | ast::expr_unary(_, _) | + ast::expr_assign_op(_, _, _) | ast::expr_index(_, _) { + maybe_resolve_type_vars_for_node(wbcx, e.span, + ast_util::op_expr_callee_id(e)); + } + _ { } } visit::visit_expr(e, wbcx, v); @@ -1438,7 +1524,7 @@ mod writeback { #debug["Type for local %s (id %d) resolved to %s", pat_to_str(l.node.pat), l.node.id, ty_to_str(wbcx.fcx.ccx.tcx, lty)]; - write_ty(wbcx.fcx.ccx.tcx, l.node.id, lty); + write_ty_to_tcx(wbcx.fcx.ccx.tcx, l.node.id, lty); } result::err(-1) { wbcx.fcx.ccx.tcx.sess.span_err( @@ -1469,11 +1555,13 @@ mod writeback { visit_pat: visit_pat, visit_local: visit_local with *visit::default_visitor()}); - visit::visit_expr(e, wbcx, visit); + visit.visit_expr(e, wbcx, visit); ret wbcx.success; } - fn resolve_type_vars_in_block(fcx: @fn_ctxt, blk: ast::blk) -> bool { + fn resolve_type_vars_in_fn(fcx: @fn_ctxt, + decl: ast::fn_decl, + blk: ast::blk) -> bool { let wbcx = {fcx: fcx, mut success: true}; let visit = visit::mk_vt(@{visit_item: visit_item, @@ -1484,8 +1572,12 @@ mod writeback { visit_local: visit_local with *visit::default_visitor()}); visit.visit_block(blk, wbcx, visit); + for arg in decl.inputs { + resolve_type_vars_for_node(wbcx, arg.ty.span, arg.id); + } ret wbcx.success; } + } fn check_intrinsic_type(tcx: ty::ctxt, it: @ast::native_item) { @@ -1541,7 +1633,7 @@ type gather_result = fn gather_locals(ccx: @crate_ctxt, decl: ast::fn_decl, body: ast::blk, - id: ast::node_id, + arg_tys: [ty::t], old_fcx: option<@fn_ctxt>) -> gather_result { let {infcx, locals, nvi} = alt old_fcx { none { @@ -1571,13 +1663,10 @@ fn gather_locals(ccx: @crate_ctxt, }; // Add formal parameters. - let args = ty::ty_fn_args(ty::node_id_to_type(ccx.tcx, id)); - let mut i = 0u; - for arg: ty::arg in args { - assign(decl.inputs[i].id, some(arg.ty)); + vec::iter2(arg_tys, decl.inputs) {|arg_ty, input| + assign(input.id, some(arg_ty)); #debug["Argument %s is assigned to ", - decl.inputs[i].ident, locals.get(decl.inputs[i].id)]; - i += 1u; + input.ident, locals.get(input.id)]; } // Add explicitly-declared locals. @@ -1724,6 +1813,7 @@ fn universally_quantify_regions(fcx: @fn_ctxt, renv: @region_env, ty: ty::t) fn check_pat_variant(pcx: pat_ctxt, pat: @ast::pat, path: @ast::path, subpats: [@ast::pat], expected: ty::t) { // Typecheck the path. + let fcx = pcx.fcx; let tcx = pcx.fcx.ccx.tcx; let v_def = lookup_def(pcx.fcx, path.span, pat.id); let v_def_ids = ast_util::variant_def_ids(v_def); @@ -1733,7 +1823,7 @@ fn check_pat_variant(pcx: pat_ctxt, pat: @ast::pat, path: @ast::path, // Take the enum type params out of `expected`. alt structure_of(pcx.fcx, pat.span, expected) { ty::ty_enum(_, expected_tps) { - let ctor_ty = ty::node_id_to_type(tcx, pat.id); + let ctor_ty = fcx.node_ty(pat.id); demand::with_substs(pcx.fcx, pat.span, expected, ctor_ty, expected_tps); // Get the number of arguments in this enum variant. @@ -1780,24 +1870,25 @@ fn check_pat_variant(pcx: pat_ctxt, pat: @ast::pat, path: @ast::path, // Pattern checking is top-down rather than bottom-up so that bindings get // their types immediately. fn check_pat(pcx: pat_ctxt, pat: @ast::pat, expected: ty::t) { + let fcx = pcx.fcx; let tcx = pcx.fcx.ccx.tcx; alt pat.node { ast::pat_wild { - write_ty(tcx, pat.id, expected); + fcx.write_ty(pat.id, expected); } ast::pat_lit(lt) { check_expr_with(pcx.fcx, lt, expected); - write_ty(tcx, pat.id, expr_ty(tcx, lt)); + fcx.write_ty(pat.id, fcx.expr_ty(lt)); } ast::pat_range(begin, end) { check_expr_with(pcx.fcx, begin, expected); check_expr_with(pcx.fcx, end, expected); let b_ty = resolve_type_vars_if_possible(pcx.fcx, - expr_ty(tcx, begin)); + fcx.expr_ty(begin)); if !require_same_types( tcx, pat.span, b_ty, resolve_type_vars_if_possible( - pcx.fcx, expr_ty(tcx, end)), + pcx.fcx, fcx.expr_ty(end)), {|| "mismatched types in range" }) { // no-op } else if !ty::type_is_numeric(b_ty) { @@ -1806,7 +1897,7 @@ fn check_pat(pcx: pat_ctxt, pat: @ast::pat, expected: ty::t) { tcx.sess.span_err(begin.span, "lower range bound must be less \ than upper"); } - write_ty(tcx, pat.id, b_ty); + fcx.write_ty(pat.id, b_ty); } ast::pat_ident(name, sub) if !pat_util::pat_is_variant(tcx.def_map, pat) { @@ -1819,7 +1910,7 @@ fn check_pat(pcx: pat_ctxt, pat: @ast::pat, expected: ty::t) { let ct = ty::mk_var(tcx, tv_id); typ = demand::simple(pcx.fcx, pat.span, ct, typ); } - write_ty(tcx, pat.id, typ); + fcx.write_ty(pat.id, typ); alt sub { some(p) { check_pat(pcx, p, expected); } _ {} @@ -1866,7 +1957,7 @@ fn check_pat(pcx: pat_ctxt, pat: @ast::pat, expected: ty::t) { } } } - write_ty(tcx, pat.id, expected); + fcx.write_ty(pat.id, expected); } ast::pat_tup(elts) { let ex_elts = alt structure_of(pcx.fcx, pat.span, expected) { @@ -1891,13 +1982,13 @@ fn check_pat(pcx: pat_ctxt, pat: @ast::pat, expected: ty::t) { i += 1u; } - write_ty(tcx, pat.id, expected); + fcx.write_ty(pat.id, expected); } ast::pat_box(inner) { alt structure_of(pcx.fcx, pat.span, expected) { ty::ty_box(e_inner) { check_pat(pcx, inner, e_inner.ty); - write_ty(tcx, pat.id, expected); + fcx.write_ty(pat.id, expected); } _ { tcx.sess.span_fatal(pat.span, @@ -1911,7 +2002,7 @@ fn check_pat(pcx: pat_ctxt, pat: @ast::pat, expected: ty::t) { alt structure_of(pcx.fcx, pat.span, expected) { ty::ty_uniq(e_inner) { check_pat(pcx, inner, e_inner.ty); - write_ty(tcx, pat.id, expected); + fcx.write_ty(pat.id, expected); } _ { tcx.sess.span_fatal(pat.span, @@ -2036,24 +2127,24 @@ fn lookup_method(fcx: @fn_ctxt, expr: @ast::expr, node_id: ast::node_id, } else { substs += tps; } - write_ty_substs(tcx, node_id, fty, substs); + fcx.write_ty_substs(node_id, fty, substs); } else { if n_tys > 0u { tcx.sess.span_err(expr.span, "this method does not take type \ parameters"); } - write_ty(tcx, node_id, fty); + fcx.write_ty(node_id, fty); } if has_self && !option::is_none(self_sub) { - let fty = ty::node_id_to_type(tcx, node_id); + let fty = fcx.node_ty(node_id); let fty = fixup_self_in_method_ty( tcx, fty, substs, option::get(self_sub)); - write_ty(tcx, node_id, fty); + fcx.write_ty(node_id, fty); } if ty::type_has_rptrs(ty::ty_fn_ret(fty)) { - let fty = ty::node_id_to_type(tcx, node_id); + let fty = fcx.node_ty(node_id); let fty = fixup_self_region_in_method_ty(fcx, fty, expr); - write_ty(tcx, node_id, fty); + fcx.write_ty(node_id, fty); } some(origin) } @@ -2286,7 +2377,7 @@ fn region_of(fcx: @fn_ctxt, expr: @ast::expr) -> ty::region { "regions of index operations"); } ast::expr_unary(ast::deref, base) { - let expr_ty = ty::expr_ty(fcx.ccx.tcx, base); + let expr_ty = fcx.expr_ty(base); let expr_ty = structurally_resolved_type(fcx, expr.span, expr_ty); alt ty::get(expr_ty).struct { ty::ty_rptr(region, _) { region } @@ -2319,7 +2410,7 @@ fn check_expr_fn_with_unifier(fcx: @fn_ctxt, expr_to_str(expr), ty_to_str(tcx, fty)); - write_ty(tcx, expr.id, fty); + fcx.write_ty(expr.id, fty); // Unify the type of the function with the expected type before we // typecheck the body so that we have more information about the @@ -2327,7 +2418,11 @@ fn check_expr_fn_with_unifier(fcx: @fn_ctxt, // record projection work on type inferred arguments. unify(fcx, expr.span, expected, fty); - check_fn(fcx.ccx, proto, decl, body, expr.id, is_loop_body, some(fcx)); + let ret_ty = ty::ty_fn_ret(fty); + let arg_tys = vec::map(ty::ty_fn_args(fty)) {|a| a.ty }; + + check_fn(fcx.ccx, proto, decl, body, + ret_ty, arg_tys, is_loop_body, some(fcx)); } fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier, @@ -2415,8 +2510,8 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier, fn check_assignment(fcx: @fn_ctxt, _sp: span, lhs: @ast::expr, rhs: @ast::expr, id: ast::node_id) -> bool { let mut bot = check_expr(fcx, lhs); - bot |= check_expr_with(fcx, rhs, expr_ty(fcx.ccx.tcx, lhs)); - write_ty(fcx.ccx.tcx, id, ty::mk_nil(fcx.ccx.tcx)); + bot |= check_expr_with(fcx, rhs, fcx.expr_ty(lhs)); + fcx.write_ty(id, ty::mk_nil(fcx.ccx.tcx)); ret bot; } @@ -2430,7 +2525,7 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier, let bot = check_expr(fcx, f); - let mut fn_ty = expr_ty(fcx.ccx.tcx, f); + let mut fn_ty = fcx.expr_ty(f); fn_ty = universally_quantify_regions(fcx, region_env(), fn_ty); // Call the generic checker. @@ -2446,7 +2541,7 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier, require_pure_call(fcx.ccx, fcx.purity, f, sp); // Pull the return type out of the type of the function. - let fty = ty::expr_ty(fcx.ccx.tcx, f); + let fty = fcx.expr_ty(f); let mut rt_1 = alt structure_of(fcx, sp, fty) { ty::ty_fn(f) { bot |= f.ret_style == ast::noreturn; @@ -2454,7 +2549,7 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier, } _ { fcx.ccx.tcx.sess.span_fatal(sp, "calling non-function"); } }; - write_ty(fcx.ccx.tcx, id, rt_1); + fcx.write_ty(id, rt_1); ret bot; } @@ -2468,7 +2563,7 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier, element_ty); let bot = check_decl_local(fcx, local); check_block_no_value(fcx, body); - write_nil(fcx.ccx.tcx, node_id); + fcx.write_nil(node_id); ret bot; } @@ -2482,7 +2577,7 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier, some(els) { let if_t = next_ty_var(fcx); let thn_bot = check_block(fcx, thn); - let thn_t = block_ty(fcx.ccx.tcx, thn); + let thn_t = fcx.node_ty(thn.node.id); demand::simple(fcx, thn.span, if_t, thn_t); let els_bot = check_expr_with(fcx, els, if_t); (if_t, thn_bot & els_bot) @@ -2492,7 +2587,7 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier, (ty::mk_nil(fcx.ccx.tcx), false) } }; - write_ty(fcx.ccx.tcx, id, if_t); + fcx.write_ty(id, if_t); ret if_bot; } @@ -2510,8 +2605,8 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier, let callee_id = ast_util::op_expr_callee_id(op_ex); alt lookup_method(fcx, op_ex, callee_id, opname, self_t, [], false) { some(origin) { - let mut method_ty = ty::node_id_to_type(fcx.ccx.tcx, callee_id); - method_ty = universally_quantify_regions(fcx, region_env(), + let method_ty = fcx.node_ty(callee_id); + let method_ty = universally_quantify_regions(fcx, region_env(), method_ty); let bot = check_call_or_bind(fcx, op_ex.span, method_ty, args); fcx.ccx.method_map.insert(op_ex.id, origin); @@ -2527,7 +2622,7 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier, rhs: @ast::expr) -> bool { let tcx = fcx.ccx.tcx; let lhs_bot = check_expr(fcx, lhs); - let lhs_t = expr_ty(tcx, lhs); + let lhs_t = fcx.expr_ty(lhs); let lhs_t = structurally_resolved_type(fcx, lhs.span, lhs_t); ret alt (op, ty::get(lhs_t).struct) { (ast::add, ty::ty_vec(lhs_mt)) { @@ -2545,7 +2640,7 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier, let rhs_bot = check_expr_with(fcx, rhs, const_vec_t); let result_var = next_ty_var(fcx); demand::simple(fcx, lhs.span, const_vec_t, result_var); - write_ty(tcx, expr.id, result_var); + fcx.write_ty(expr.id, result_var); lhs_bot | rhs_bot } @@ -2553,9 +2648,9 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier, ast_util::is_shift_binop(op) { // Shift is a special case: rhs can be any integral type let rhs_bot = check_expr(fcx, rhs); - let rhs_t = expr_ty(tcx, rhs); + let rhs_t = fcx.expr_ty(rhs); require_integral(fcx, rhs.span, rhs_t); - write_ty(tcx, expr.id, lhs_t); + fcx.write_ty(expr.id, lhs_t); lhs_bot | rhs_bot } @@ -2575,7 +2670,7 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier, } _ { lhs_t } }; - write_ty(tcx, expr.id, rhs_t); + fcx.write_ty(expr.id, rhs_t); if !ast_util::lazy_binop(op) { lhs_bot | rhs_bot } else { lhs_bot } } @@ -2583,7 +2678,7 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier, (_, _) { let (result, rhs_bot) = check_user_binop(fcx, expr, lhs_t, op, rhs); - write_ty(tcx, expr.id, result); + fcx.write_ty(expr.id, result); lhs_bot | rhs_bot } }; @@ -2627,7 +2722,7 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier, alt expr.node { ast::expr_lit(lit) { let typ = check_lit(fcx.ccx, lit); - write_ty(tcx, id, typ); + fcx.write_ty(id, typ); } // Something of a hack: special rules for comparison operators that @@ -2646,7 +2741,7 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier, let tvar = next_ty_var(fcx); bot |= check_expr_with(fcx, lhs, tvar); bot |= check_expr_with(fcx, rhs, tvar); - write_ty(tcx, id, ty::mk_bool(tcx)); + fcx.write_ty(id, ty::mk_bool(tcx)); } ast::expr_binary(op, lhs, rhs) { bot |= check_binop(fcx, expr, op, lhs, rhs); @@ -2654,18 +2749,18 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier, ast::expr_assign_op(op, lhs, rhs) { require_impure(tcx.sess, fcx.purity, expr.span); bot |= check_binop(fcx, expr, op, lhs, rhs); - let lhs_t = ty::expr_ty(tcx, lhs); - let result_t = ty::expr_ty(tcx, expr); + let lhs_t = fcx.expr_ty(lhs); + let result_t = fcx.expr_ty(expr); demand::simple(fcx, expr.span, result_t, lhs_t); // Overwrite result of check_binop...this preserves existing behavior // but seems quite dubious with regard to user-defined methods // and so forth. - Niko - write_nil(tcx, expr.id); + fcx.write_nil(expr.id); } ast::expr_unary(unop, oper) { bot = check_expr(fcx, oper); - let mut oper_t = expr_ty(tcx, oper); + let mut oper_t = fcx.expr_ty(oper); alt unop { ast::box(mutbl) { oper_t = ty::mk_box(tcx, {ty: oper_t, mutbl: mutbl}); @@ -2717,16 +2812,16 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier, } } } - write_ty(tcx, id, oper_t); + fcx.write_ty(id, oper_t); } ast::expr_addr_of(mutbl, oper) { bot = check_expr(fcx, oper); - let mut oper_t = expr_ty(tcx, oper); + let mut oper_t = fcx.expr_ty(oper); let region = region_of(fcx, oper); let tm = { ty: oper_t, mutbl: mutbl }; oper_t = ty::mk_rptr(tcx, region, tm); - write_ty(tcx, id, oper_t); + fcx.write_ty(id, oper_t); } ast::expr_path(pth) { let defn = lookup_def(fcx, pth.span, id); @@ -2742,7 +2837,7 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier, "this kind of value does not \ take type parameters"); } - write_ty(tcx, id, tpt.ty); + fcx.write_ty(id, tpt.ty); } } ast::expr_mac(_) { tcx.sess.bug("unexpanded macro"); } @@ -2752,10 +2847,10 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier, none {/* do nothing */ } some(e) { check_expr_with(fcx, e, ty::mk_str(tcx)); } } - write_bot(tcx, id); + fcx.write_bot(id); } - ast::expr_break { write_bot(tcx, id); bot = true; } - ast::expr_cont { write_bot(tcx, id); bot = true; } + ast::expr_break { fcx.write_bot(id); bot = true; } + ast::expr_cont { fcx.write_bot(id); bot = true; } ast::expr_ret(expr_opt) { bot = true; let ret_ty = alt fcx.indirect_ret_ty { @@ -2771,24 +2866,24 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier, } some(e) { check_expr_with(fcx, e, ret_ty); } } - write_bot(tcx, id); + fcx.write_bot(id); } ast::expr_be(e) { // FIXME: prove instead of assert assert (ast_util::is_call_expr(e)); check_expr_with(fcx, e, fcx.ret_ty); bot = true; - write_nil(tcx, id); + fcx.write_nil(id); } ast::expr_log(_, lv, e) { bot = check_expr_with(fcx, lv, ty::mk_mach_uint(tcx, ast::ty_u32)); // Note: this does not always execute, so do not propagate bot: check_expr(fcx, e); - write_nil(tcx, id); + fcx.write_nil(id); } ast::expr_check(_, e) { bot = check_pred_expr(fcx, e); - write_nil(tcx, id); + fcx.write_nil(id); } ast::expr_if_check(cond, thn, elsopt) { bot = @@ -2797,11 +2892,11 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier, } ast::expr_assert(e) { bot = check_expr_with(fcx, e, ty::mk_bool(tcx)); - write_nil(tcx, id); + fcx.write_nil(id); } ast::expr_copy(a) { bot = check_expr_with_unifier(fcx, a, unify, expected); - write_ty(tcx, id, ty::node_id_to_type(tcx, a.id)); + fcx.write_ty(id, fcx.expr_ty(a)); } ast::expr_move(lhs, rhs) { require_impure(tcx.sess, fcx.purity, expr.span); @@ -2823,7 +2918,7 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier, ast::expr_for(decl, seq, body) { bot = check_expr(fcx, seq); let mut elt_ty; - let ety = expr_ty(tcx, seq); + let ety = fcx.expr_ty(seq); alt structure_of(fcx, expr.span, ety) { ty::ty_vec(vec_elt_ty) { elt_ty = vec_elt_ty.ty; } ty::ty_str { elt_ty = ty::mk_mach_uint(tcx, ast::ty_u8); } @@ -2838,16 +2933,16 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier, ast::expr_while(cond, body) { bot = check_expr_with(fcx, cond, ty::mk_bool(tcx)); check_block_no_value(fcx, body); - write_ty(tcx, id, ty::mk_nil(tcx)); + fcx.write_ty(id, ty::mk_nil(tcx)); } ast::expr_do_while(body, cond) { bot = check_expr_with(fcx, cond, ty::mk_bool(tcx)) | check_block_no_value(fcx, body); - write_ty(tcx, id, block_ty(tcx, body)); + fcx.write_ty(id, fcx.node_ty(body.node.id)); } ast::expr_loop(body) { check_block_no_value(fcx, body); - write_ty(tcx, id, ty::mk_nil(tcx)); + fcx.write_ty(id, ty::mk_nil(tcx)); bot = !may_break(body); } ast::expr_alt(discrim, arms, _) { @@ -2858,7 +2953,7 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier, // Typecheck the patterns first, so that we get types for all the // bindings. - //let pattern_ty = ty::expr_ty(tcx, discrim); + //let pattern_ty = fcx.expr_ty(discrim); for arm: ast::arm in arms { let pcx = { fcx: fcx, @@ -2881,12 +2976,12 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier, none { } } if !check_block(fcx, arm.body) { arm_non_bot = true; } - let bty = block_ty(tcx, arm.body); + let bty = fcx.node_ty(arm.body.node.id); result_ty = demand::simple(fcx, arm.body.span, result_ty, bty); } bot |= !arm_non_bot; if !arm_non_bot { result_ty = ty::mk_bot(tcx); } - write_ty(tcx, id, result_ty); + fcx.write_ty(id, result_ty); } ast::expr_fn(proto, decl, body, captures) { check_expr_fn_with_unifier(fcx, expr, proto, decl, body, @@ -2921,11 +3016,11 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier, } } let block_ty = structurally_resolved_type( - fcx, expr.span, ty::node_id_to_type(tcx, b.id)); + fcx, expr.span, fcx.node_ty(b.id)); alt check ty::get(block_ty).struct { ty::ty_fn(fty) { - write_ty(tcx, expr.id, ty::mk_fn(tcx, {output: ty::mk_bool(tcx) - with fty})); + fcx.write_ty(expr.id, ty::mk_fn(tcx, {output: ty::mk_bool(tcx) + with fty})); } } } @@ -2934,16 +3029,16 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier, bot = check_block(fcx, b); let typ = alt b.node.expr { - some(expr) { expr_ty(tcx, expr) } + some(expr) { fcx.expr_ty(expr) } none { ty::mk_nil(tcx) } }; - write_ty(tcx, id, typ); + fcx.write_ty(id, typ); } ast::expr_bind(f, args) { // Call the generic checker. bot = check_expr(fcx, f); - let mut fn_ty = expr_ty(fcx.ccx.tcx, f); + let mut fn_ty = fcx.expr_ty(f); fn_ty = universally_quantify_regions(fcx, region_env(), fn_ty); let ccob_bot = check_call_or_bind(fcx, expr.span, fn_ty, args); @@ -2953,7 +3048,7 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier, // Pull the argument and return types out. let mut proto, arg_tys, rt, cf, constrs; - alt structure_of(fcx, expr.span, expr_ty(tcx, f)) { + alt structure_of(fcx, expr.span, fcx.expr_ty(f)) { // FIXME: // probably need to munge the constrs to drop constraints // for any bound args @@ -2994,7 +3089,7 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier, let ft = ty::mk_fn(tcx, {proto: proto, inputs: out_args, output: rt, ret_style: cf, constraints: constrs}); - write_ty(tcx, id, ft); + fcx.write_ty(id, ft); } ast::expr_call(f, args, _) { bot = check_call_full(fcx, expr.span, expr.id, f, args); @@ -3002,7 +3097,7 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier, ast::expr_cast(e, t) { bot = check_expr(fcx, e); let t_1 = ast_ty_to_ty_crate(fcx.ccx, t); - let t_e = ty::expr_ty(tcx, e); + let t_e = fcx.expr_ty(e); alt ty::get(t_1).struct { // This will be looked up later on @@ -3030,30 +3125,30 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier, } } } - write_ty(tcx, id, t_1); + fcx.write_ty(id, t_1); } ast::expr_vec(args, mutbl) { let t: ty::t = next_ty_var(fcx); for e: @ast::expr in args { bot |= check_expr_with(fcx, e, t); } let typ = ty::mk_vec(tcx, {ty: t, mutbl: mutbl}); - write_ty(tcx, id, typ); + fcx.write_ty(id, typ); } ast::expr_tup(elts) { let mut elt_ts = []; vec::reserve(elt_ts, vec::len(elts)); for e in elts { check_expr(fcx, e); - let ety = expr_ty(tcx, e); + let ety = fcx.expr_ty(e); elt_ts += [ety]; } let typ = ty::mk_tup(tcx, elt_ts); - write_ty(tcx, id, typ); + fcx.write_ty(id, typ); } ast::expr_rec(fields, base) { option::may(base) {|b| check_expr(fcx, b); } let fields_t = vec::map(fields, {|f| bot |= check_expr(fcx, f.node.expr); - let expr_t = expr_ty(tcx, f.node.expr); + let expr_t = fcx.expr_ty(f.node.expr); let expr_mt = {ty: expr_t, mutbl: f.node.mutbl}; // for the most precise error message, // should be f.node.expr.span, not f.span @@ -3063,11 +3158,11 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier, none { fn get_node(f: spanned) -> field { f.node } let typ = ty::mk_rec(tcx, vec::map(fields_t, get_node)); - write_ty(tcx, id, typ); + fcx.write_ty(id, typ); } some(bexpr) { bot |= check_expr(fcx, bexpr); - let bexpr_t = expr_ty(tcx, bexpr); + let bexpr_t = fcx.expr_ty(bexpr); let mut base_fields: [field] = []; alt structure_of(fcx, expr.span, bexpr_t) { ty::ty_rec(flds) { base_fields = flds; } @@ -3076,7 +3171,7 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier, "record update has non-record base"); } } - write_ty(tcx, id, bexpr_t); + fcx.write_ty(id, bexpr_t); for f: spanned in fields_t { let mut found = false; for bf: ty::field in base_fields { @@ -3097,7 +3192,7 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier, ast::expr_field(base, field, tys) { bot |= check_expr(fcx, base); let expr_t = structurally_resolved_type(fcx, expr.span, - expr_ty(tcx, base)); + fcx.expr_ty(base)); let base_t = do_autoderef(fcx, expr.span, expr_t); let mut handled = false; let n_tys = vec::len(tys); @@ -3110,7 +3205,7 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier, "can't provide type parameters \ to a field access"); } - write_ty(tcx, id, fields[ix].mt.ty); + fcx.write_ty(id, fields[ix].mt.ty); handled = true; } _ {} @@ -3139,7 +3234,7 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier, some(field_ty) { // (2) look up what field's type is, and return it // FIXME: actually instantiate any type params - write_ty(tcx, id, field_ty); + fcx.write_ty(id, field_ty); handled = true; } none {} @@ -3161,33 +3256,33 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier, field, ty_to_str(tcx, t_err)]; tcx.sess.span_err(expr.span, msg); // NB: Adding a bogus type to allow typechecking to continue - write_ty(tcx, id, next_ty_var(fcx)); + fcx.write_ty(id, next_ty_var(fcx)); } } } } ast::expr_index(base, idx) { bot |= check_expr(fcx, base); - let raw_base_t = expr_ty(tcx, base); + let raw_base_t = fcx.expr_ty(base); let base_t = do_autoderef(fcx, expr.span, raw_base_t); bot |= check_expr(fcx, idx); - let idx_t = expr_ty(tcx, idx); + let idx_t = fcx.expr_ty(idx); alt structure_of(fcx, expr.span, base_t) { ty::ty_vec(mt) { require_integral(fcx, idx.span, idx_t); - write_ty(tcx, id, mt.ty); + fcx.write_ty(id, mt.ty); } ty::ty_str { require_integral(fcx, idx.span, idx_t); let typ = ty::mk_mach_uint(tcx, ast::ty_u8); - write_ty(tcx, id, typ); + fcx.write_ty(id, typ); } _ { let resolved = structurally_resolved_type(fcx, expr.span, raw_base_t); alt lookup_op_method(fcx, expr, resolved, "[]", [some(idx)]) { - some((ret_ty, _)) { write_ty(tcx, id, ret_ty); } + some((ret_ty, _)) { fcx.write_ty(id, ret_ty); } _ { tcx.sess.span_fatal( expr.span, "cannot index a value of type `" + @@ -3201,7 +3296,7 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier, bot |= check_expr(fcx, p); bot |= check_expr(fcx, v); - let p_ty = expr_ty(tcx, p); + let p_ty = fcx.expr_ty(p); alt lookup_method(fcx, p, alloc_id, "alloc", p_ty, [], false) { some(origin) { @@ -3223,7 +3318,7 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier, }; demand::simple(fcx, expr.span, - expected_ty, node_id_to_type(tcx, alloc_id)); + expected_ty, fcx.node_ty(alloc_id)); } none { @@ -3237,20 +3332,20 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier, // The region value must have a type like &r.T. The resulting // memory will be allocated into the region `r`. let pool_region = region_of(fcx, p); - let v_ty = expr_ty(tcx, v); + let v_ty = fcx.expr_ty(v); let res_ty = ty::mk_rptr(tcx, pool_region, {ty: v_ty, mutbl: ast::m_imm}); - write_ty(tcx, expr.id, res_ty); + fcx.write_ty(expr.id, res_ty); } } - if bot { write_ty(tcx, expr.id, ty::mk_bot(tcx)); } + if bot { fcx.write_bot(expr.id); } #debug("type of expr %s is %s, expected is %s", syntax::print::pprust::expr_to_str(expr), - ty_to_str(tcx, expr_ty(tcx, expr)), + ty_to_str(tcx, fcx.expr_ty(expr)), ty_to_str(tcx, expected)); - unify(fcx, expr.span, expected, expr_ty(tcx, expr)); + unify(fcx, expr.span, expected, fcx.expr_ty(expr)); ret bot; } @@ -3302,7 +3397,7 @@ fn check_decl_local(fcx: @fn_ctxt, local: @ast::local) -> bool { let mut bot = false; let t = ty::mk_var(fcx.ccx.tcx, fcx.locals.get(local.node.id)); - write_ty(fcx.ccx.tcx, local.node.id, t); + fcx.write_ty(local.node.id, t); alt local.node.init { some(init) { bot = check_decl_initializer(fcx, local.node.id, init); @@ -3346,14 +3441,14 @@ fn check_stmt(fcx: @fn_ctxt, stmt: @ast::stmt) -> bool { bot = check_expr(fcx, expr); } } - write_nil(fcx.ccx.tcx, node_id); + fcx.write_nil(node_id); ret bot; } fn check_block_no_value(fcx: @fn_ctxt, blk: ast::blk) -> bool { let bot = check_block(fcx, blk); if !bot { - let blkty = ty::node_id_to_type(fcx.ccx.tcx, blk.node.id); + let blkty = fcx.node_ty(blk.node.id); let nilty = ty::mk_nil(fcx.ccx.tcx); demand::simple(fcx, blk.span, nilty, blkty); } @@ -3383,18 +3478,18 @@ fn check_block(fcx0: @fn_ctxt, blk: ast::blk) -> bool { bot |= check_stmt(fcx, s); } alt blk.node.expr { - none { write_nil(fcx.ccx.tcx, blk.node.id); } + none { fcx.write_nil(blk.node.id); } some(e) { if bot && !warned { fcx.ccx.tcx.sess.span_warn(e.span, "unreachable expression"); } bot |= check_expr(fcx, e); - let ety = expr_ty(fcx.ccx.tcx, e); - write_ty(fcx.ccx.tcx, blk.node.id, ety); + let ety = fcx.expr_ty(e); + fcx.write_ty(blk.node.id, ety); } } if bot { - write_ty(fcx.ccx.tcx, blk.node.id, ty::mk_bot(fcx.ccx.tcx)); + fcx.write_bot(blk.node.id); } ret bot; } @@ -3402,7 +3497,7 @@ fn check_block(fcx0: @fn_ctxt, blk: ast::blk) -> bool { 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 rty = ty::node_id_to_type(ccx.tcx, id); let fcx: @fn_ctxt = @{ret_ty: rty, indirect_ret_ty: none, @@ -3412,11 +3507,14 @@ fn check_const(ccx: @crate_ctxt, _sp: span, e: @ast::expr, id: ast::node_id) { locals: int_hash::(), next_var_id: @mut 0, next_region_var_id: @mut 0, + node_types: smallintmap::mk(), + node_type_substs: map::int_hash(), ccx: ccx}; check_expr(fcx, e); - let cty = expr_ty(fcx.ccx.tcx, e); + let cty = fcx.expr_ty(e); let declty = fcx.ccx.tcx.tcache.get(local_def(id)).ty; demand::simple(fcx, e.span, declty, cty); + writeback::resolve_type_vars_in_expr(fcx, e); } fn check_instantiable(tcx: ty::ctxt, @@ -3435,7 +3533,7 @@ fn check_enum_variants(ccx: @crate_ctxt, sp: span, vs: [ast::variant], 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 rty = ty::node_id_to_type(ccx.tcx, id); let fcx: @fn_ctxt = @{ret_ty: rty, indirect_ret_ty: none, @@ -3445,6 +3543,8 @@ fn check_enum_variants(ccx: @crate_ctxt, sp: span, vs: [ast::variant], locals: int_hash::(), next_var_id: @mut 0, next_region_var_id: @mut 0, + node_types: smallintmap::mk(), + node_type_substs: map::int_hash(), ccx: ccx}; let mut disr_vals: [int] = []; let mut disr_val = 0; @@ -3452,7 +3552,7 @@ fn check_enum_variants(ccx: @crate_ctxt, sp: span, vs: [ast::variant], alt v.node.disr_expr { some(e) { check_expr(fcx, e); - let cty = expr_ty(ccx.tcx, e); + let cty = fcx.expr_ty(e); let declty = ty::mk_int(ccx.tcx); demand::simple(fcx, e.span, declty, cty); // FIXME: issue #1417 @@ -3508,7 +3608,7 @@ fn check_pred_expr(fcx: @fn_ctxt, e: @ast::expr) -> bool { literals or slots */ alt e.node { ast::expr_call(operator, operands, _) { - if !ty::is_pred_ty(expr_ty(fcx.ccx.tcx, operator)) { + if !ty::is_pred_ty(fcx.expr_ty(operator)) { fcx.ccx.tcx.sess.span_err (operator.span, "operator in constraint has non-boolean return type"); @@ -3607,21 +3707,42 @@ fn check_constraints(fcx: @fn_ctxt, cs: [@ast::constr], args: [ast::arg]) { } } +fn check_bare_fn(ccx: @crate_ctxt, + decl: ast::fn_decl, + body: ast::blk, + id: ast::node_id) { + let fty = ty::node_id_to_type(ccx.tcx, id); + let ret_ty = ty::ty_fn_ret(fty); + let arg_tys = vec::map(ty::ty_fn_args(fty)) {|a| a.ty }; + check_fn(ccx, ast::proto_bare, decl, body, + ret_ty, arg_tys, false, none); +} + fn check_fn(ccx: @crate_ctxt, proto: ast::proto, decl: ast::fn_decl, body: ast::blk, - id: ast::node_id, + ret_ty: ty::t, + arg_tys: [ty::t], indirect_ret: bool, old_fcx: option<@fn_ctxt>) { // If old_fcx is some(...), this is a block fn { |x| ... }. // In that case, the purity is inherited from the context. - let purity = alt old_fcx { - none { decl.purity } - some(f) { assert decl.purity == ast::impure_fn; f.purity } + let {purity, node_types, node_type_substs} = alt old_fcx { + none { + {purity: decl.purity, + node_types: smallintmap::mk(), + node_type_substs: map::int_hash()} + } + some(f) { + assert decl.purity == ast::impure_fn; + {purity: f.purity, + node_types: f.node_types, + node_type_substs: f.node_type_substs} + } }; - let gather_result = gather_locals(ccx, decl, body, id, old_fcx); + let gather_result = gather_locals(ccx, decl, body, arg_tys, old_fcx); let indirect_ret_ty = if indirect_ret { let ofcx = option::get(old_fcx); alt ofcx.indirect_ret_ty { @@ -3630,7 +3751,7 @@ fn check_fn(ccx: @crate_ctxt, } } else { none }; let fcx: @fn_ctxt = - @{ret_ty: ty::ty_fn_ret(ty::node_id_to_type(ccx.tcx, id)), + @{ret_ty: ret_ty, indirect_ret_ty: indirect_ret_ty, purity: purity, proto: proto, @@ -3638,6 +3759,8 @@ fn check_fn(ccx: @crate_ctxt, locals: gather_result.locals, next_var_id: gather_result.next_var_id, next_region_var_id: @mut 0, + node_types: node_types, + node_type_substs: node_type_substs, ccx: ccx}; check_constraints(fcx, decl.constraints, decl.inputs); @@ -3647,16 +3770,15 @@ fn check_fn(ccx: @crate_ctxt, // function result type, if there is a tail expr. alt body.node.expr { some(tail_expr) { - let tail_expr_ty = expr_ty(ccx.tcx, tail_expr); + let tail_expr_ty = fcx.expr_ty(tail_expr); demand::simple(fcx, tail_expr.span, fcx.ret_ty, tail_expr_ty); } none { } } - let args = ty::ty_fn_args(ty::node_id_to_type(ccx.tcx, id)); let mut i = 0u; - for arg: ty::arg in args { - write_ty(ccx.tcx, decl.inputs[i].id, arg.ty); + vec::iter(arg_tys) {|arg| + fcx.write_ty(decl.inputs[i].id, arg); i += 1u; } @@ -3666,13 +3788,12 @@ fn check_fn(ccx: @crate_ctxt, // resolved when the enclosing scope finishes up. if option::is_none(old_fcx) { vtable::resolve_in_block(fcx, body); - writeback::resolve_type_vars_in_block(fcx, body); + writeback::resolve_type_vars_in_fn(fcx, decl, body); } } fn check_method(ccx: @crate_ctxt, method: @ast::method) { - check_fn(ccx, ast::proto_bare, method.decl, method.body, method.id, - false, none); + check_bare_fn(ccx, method.decl, method.body, method.id); } fn class_types(ccx: @crate_ctxt, members: [@ast::class_member]) -> class_map { @@ -3708,11 +3829,11 @@ fn check_item(ccx: @crate_ctxt, it: @ast::item) { ast::item_const(_, e) { check_const(ccx, it.span, e, it.id); } ast::item_enum(vs, _) { check_enum_variants(ccx, it.span, vs, it.id); } ast::item_fn(decl, tps, body) { - check_fn(ccx, ast::proto_bare, decl, body, it.id, false, none); + check_bare_fn(ccx, decl, body, it.id); } ast::item_res(decl, tps, body, dtor_id, _) { check_instantiable(ccx.tcx, it.span, it.id); - check_fn(ccx, ast::proto_bare, decl, body, dtor_id, false, none); + check_bare_fn(ccx, decl, body, dtor_id); } ast::item_impl(tps, _, ty, ms) { let mut self_ty = ast_ty_to_ty(ccx.tcx, m_check, ty); @@ -3726,7 +3847,7 @@ fn check_item(ccx: @crate_ctxt, it: @ast::item) { } ast::item_class(tps, members, ctor) { let cid = some(it.id); - let class_t = node_id_to_type(ccx.tcx, it.id); + let class_t = ty::node_id_to_type(ccx.tcx, it.id); let members_info = class_types(ccx, members); // can also ditch the enclosing_class stuff once we move to self // FIXME @@ -3734,8 +3855,8 @@ fn check_item(ccx: @crate_ctxt, it: @ast::item) { enclosing_class:members_info with *ccx}; class_ccx.self_infos += [self_impl(class_t, ctor.node.self_id)]; // typecheck the ctor - check_fn(class_ccx, ast::proto_bare, ctor.node.dec, - ctor.node.body, ctor.node.id, false, none); + check_bare_fn(class_ccx, ctor.node.dec, + ctor.node.body, ctor.node.id); vec::pop(class_ccx.self_infos); // typecheck the members for m in members { check_class_member(class_ccx, class_t, m); } @@ -3965,7 +4086,7 @@ mod vtable { let cx = fcx.ccx; alt ex.node { ast::expr_path(_) { - alt cx.tcx.node_type_substs.find(ex.id) { + alt fcx.opt_node_ty_substs(ex.id) { some(ts) { let did = ast_util::def_id_of_def(cx.tcx.def_map.get(ex.id)); let item_ty = ty::lookup_item_type(cx.tcx, did); @@ -3990,7 +4111,7 @@ mod vtable { ast::expr_field(_, _, _) { ex.id } _ { ast_util::op_expr_callee_id(ex) } }; - let ts = ty::node_id_to_type_params(cx.tcx, callee_id); + let ts = fcx.node_ty_substs(callee_id); let iscs = cx.impl_map.get(ex.id); cx.vtable_map.insert(callee_id, lookup_vtables( fcx, iscs, ex.span, bounds, ts, false)); @@ -4000,12 +4121,12 @@ mod vtable { } } ast::expr_cast(src, _) { - let target_ty = expr_ty(cx.tcx, ex); + let target_ty = fcx.expr_ty(ex); alt ty::get(target_ty).struct { ty::ty_iface(_, _) { let impls = cx.impl_map.get(ex.id); let vtable = lookup_vtable(fcx, impls, ex.span, - expr_ty(cx.tcx, src), target_ty, + fcx.expr_ty(src), target_ty, true); cx.vtable_map.insert(ex.id, @[vtable]); }