提交 26dc48d6 编写于 作者: N Niko Matsakis

break apart typeck a little (more to come)

上级 adb61e3e
此差异已折叠。
此差异已折叠。
import astconv::{type_rscope, instantiate_iface_ref, ty_of_item,
empty_rscope, ty_of_native_item, ast_conv};
// Item collection - a pair of bootstrap passes:
//
// (1) Collect the IDs of all type items (typedefs) and store them in a table.
//
// (2) Translate the AST fragments that describe types to determine a type for
// each item. When we encounter a named type, we consult the table built
// in pass 1 to find its item, and recursively translate it.
//
// We then annotate the AST with the resulting types and return the annotated
// AST, along with a table mapping item IDs to their types.
fn get_enum_variant_types(ccx: @crate_ctxt,
enum_ty: ty::t,
variants: [ast::variant],
ty_params: [ast::ty_param],
rp: ast::region_param) {
let tcx = ccx.tcx;
// Create a set of parameter types shared among all the variants.
for variants.each {|variant|
// Nullary enum constructors get turned into constants; n-ary enum
// constructors get turned into functions.
let result_ty = if vec::len(variant.node.args) == 0u {
enum_ty
} else {
let rs = type_rscope(rp);
let args = variant.node.args.map { |va|
let arg_ty = ccx.to_ty(rs, va.ty);
{mode: ast::expl(ast::by_copy), ty: arg_ty}
};
ty::mk_fn(tcx, {proto: ast::proto_box,
inputs: args,
output: enum_ty,
ret_style: ast::return_val,
constraints: []})
};
let tpt = {bounds: astconv::ty_param_bounds(ccx, ty_params),
rp: rp,
ty: result_ty};
tcx.tcache.insert(local_def(variant.node.id), tpt);
write_ty_to_tcx(tcx, variant.node.id, result_ty);
}
}
fn ensure_iface_methods(ccx: @crate_ctxt, id: ast::node_id) {
fn store_methods<T>(ccx: @crate_ctxt, id: ast::node_id,
stuff: [T], f: fn@(T) -> ty::method) {
ty::store_iface_methods(ccx.tcx, id, @vec::map(stuff, f));
}
let tcx = ccx.tcx;
alt check tcx.items.get(id) {
ast_map::node_item(@{node: ast::item_iface(_, rp, ms), _}, _) {
store_methods::<ast::ty_method>(ccx, id, ms) {|m|
ty_of_ty_method(ccx, m, rp)
};
}
ast_map::node_item(@{node: ast::item_class(_,_,its,_,_,rp), _}, _) {
let (_,ms) = split_class_items(its);
// All methods need to be stored, since lookup_method
// relies on the same method cache for self-calls
store_methods::<@ast::method>(ccx, id, ms) {|m|
ty_of_method(ccx, m, rp)
};
}
}
}
fn check_methods_against_iface(ccx: @crate_ctxt,
tps: [ast::ty_param],
rp: ast::region_param,
selfty: ty::t,
a_ifacety: @ast::iface_ref,
ms: [@ast::method]) {
let tcx = ccx.tcx;
let i_bounds = astconv::ty_param_bounds(ccx, tps);
let my_methods = convert_methods(ccx, ms, rp, i_bounds, selfty);
let (did, tpt) = instantiate_iface_ref(ccx, a_ifacety, rp);
if did.crate == ast::local_crate {
ensure_iface_methods(ccx, did.node);
}
for vec::each(*ty::iface_methods(tcx, did)) {|if_m|
alt vec::find(my_methods, {|m| if_m.ident == m.mty.ident}) {
some({mty: m, id, span}) {
if m.purity != if_m.purity {
ccx.tcx.sess.span_err(
span, #fmt["method `%s`'s purity \
not match the iface method's \
purity", m.ident]);
}
let mt = compare_impl_method(
ccx.tcx, span, m, vec::len(tps),
if_m, tpt.substs, selfty);
let old = tcx.tcache.get(local_def(id));
if old.ty != mt {
tcx.tcache.insert(
local_def(id),
{bounds: old.bounds,
rp: old.rp,
ty: mt});
write_ty_to_tcx(tcx, id, mt);
}
}
none {
tcx.sess.span_err(
a_ifacety.path.span,
#fmt["missing method `%s`", if_m.ident]);
}
} // alt
} // |if_m|
} // fn
fn convert_class_item(ccx: @crate_ctxt,
rp: ast::region_param,
v: ast_util::ivar) {
/* we want to do something here, b/c within the
scope of the class, it's ok to refer to fields &
methods unqualified */
/* they have these types *within the scope* of the
class. outside the class, it's done with expr_field */
let tt = ccx.to_ty(type_rscope(rp), v.ty);
write_ty_to_tcx(ccx.tcx, v.id, tt);
}
fn convert_methods(ccx: @crate_ctxt,
ms: [@ast::method],
rp: ast::region_param,
i_bounds: @[ty::param_bounds],
self_ty: ty::t)
-> [{mty: ty::method, id: ast::node_id, span: span}] {
let tcx = ccx.tcx;
vec::map(ms) { |m|
write_ty_to_tcx(tcx, m.self_id, self_ty);
let bounds = astconv::ty_param_bounds(ccx, m.tps);
let mty = ty_of_method(ccx, m, rp);
let fty = ty::mk_fn(tcx, mty.fty);
tcx.tcache.insert(
local_def(m.id),
// n.b. This code is kind of sketchy (concat'ing i_bounds
// with bounds), but removing *i_bounds breaks other stuff
{bounds: @(*i_bounds + *bounds), rp: rp, ty: fty});
write_ty_to_tcx(tcx, m.id, fty);
{mty: mty, id: m.id, span: m.span}
}
}
fn convert(ccx: @crate_ctxt, it: @ast::item) {
let tcx = ccx.tcx;
alt it.node {
// These don't define types.
ast::item_mod(_) {}
ast::item_native_mod(m) {
if syntax::attr::native_abi(it.attrs) ==
either::right(ast::native_abi_rust_intrinsic) {
for m.items.each { |item| check_intrinsic_type(ccx, item); }
}
}
ast::item_enum(variants, ty_params, rp) {
let tpt = ty_of_item(ccx, it);
write_ty_to_tcx(tcx, it.id, tpt.ty);
get_enum_variant_types(ccx, tpt.ty, variants,
ty_params, rp);
}
ast::item_impl(tps, rp, ifce, selfty, ms) {
let i_bounds = astconv::ty_param_bounds(ccx, tps);
let selfty = ccx.to_ty(type_rscope(rp), selfty);
write_ty_to_tcx(tcx, it.id, selfty);
tcx.tcache.insert(local_def(it.id),
{bounds: i_bounds,
rp: rp,
ty: selfty});
alt ifce {
some(t) {
check_methods_against_iface(
ccx, tps, rp,
selfty, t, ms);
}
_ {
// Still have to do this to write method types
// into the table
convert_methods(
ccx, ms, rp,
i_bounds, selfty);
}
}
}
ast::item_res(decl, tps, _, dtor_id, ctor_id, rp) {
let {bounds, substs} = mk_substs(ccx, tps, rp);
let def_id = local_def(it.id);
let t_arg = astconv::ty_of_arg(ccx, type_rscope(rp),
decl.inputs[0], none);
let t_res = ty::mk_res(tcx, def_id, t_arg.ty, substs);
let t_ctor = ty::mk_fn(tcx, {
proto: ast::proto_box,
inputs: [{mode: ast::expl(ast::by_copy), ty: t_arg.ty}],
output: t_res,
ret_style: ast::return_val, constraints: []
});
let t_dtor = ty::mk_fn(tcx, {
proto: ast::proto_box,
inputs: [t_arg], output: ty::mk_nil(tcx),
ret_style: ast::return_val, constraints: []
});
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,
rp: rp,
ty: t_ctor});
tcx.tcache.insert(def_id, {bounds: bounds,
rp: rp,
ty: t_res});
write_ty_to_tcx(tcx, dtor_id, t_dtor);
}
ast::item_iface(*) {
let tpt = ty_of_item(ccx, it);
#debug["item_iface(it.id=%d, tpt.ty=%s)",
it.id, ty_to_str(tcx, tpt.ty)];
write_ty_to_tcx(tcx, it.id, tpt.ty);
ensure_iface_methods(ccx, it.id);
}
ast::item_class(tps, ifaces, members, ctor, m_dtor, rp) {
// Write the class type
let tpt = ty_of_item(ccx, it);
write_ty_to_tcx(tcx, it.id, tpt.ty);
// Write the ctor type
let t_ctor =
ty::mk_fn(
tcx,
astconv::ty_of_fn_decl(ccx,
empty_rscope,
ast::proto_any,
ctor.node.dec,
none));
write_ty_to_tcx(tcx, ctor.node.id, t_ctor);
tcx.tcache.insert(local_def(ctor.node.id),
{bounds: tpt.bounds,
rp: ast::rp_none,
ty: t_ctor});
option::iter(m_dtor) {|dtor|
// Write the dtor type
let t_dtor = ty::mk_fn(
tcx,
// not sure about empty_rscope
// FIXME
astconv::ty_of_fn_decl(ccx,
empty_rscope,
ast::proto_any,
ast_util::dtor_dec(),
none));
write_ty_to_tcx(tcx, dtor.node.id, t_dtor);
tcx.tcache.insert(local_def(dtor.node.id),
{bounds: tpt.bounds,
rp: ast::rp_none,
ty: t_dtor});
};
ensure_iface_methods(ccx, it.id);
/* FIXME: check for proper public/privateness */
// Write the type of each of the members
let (fields, methods) = split_class_items(members);
for fields.each {|f|
convert_class_item(ccx, rp, f);
}
// The selfty is just the class type
let {bounds:_, substs} = mk_substs(ccx, tps, rp);
let selfty = ty::mk_class(tcx, local_def(it.id), substs);
// Need to convert all methods so we can check internal
// references to private methods
// NDM to TJC---I think we ought to be using bounds here, not @[].
// But doing so causes errors later on.
convert_methods(ccx, methods, rp, @[], selfty);
/*
Finally, check that the class really implements the ifaces
that it claims to implement.
*/
for ifaces.each { |ifce|
check_methods_against_iface(ccx, tps, rp, selfty,
ifce, methods);
let t = ty::node_id_to_type(tcx, ifce.id);
// FIXME: This assumes classes only implement
// non-parameterized ifaces. add a test case for
// a class implementing a parameterized iface.
// -- tjc (#1726)
tcx.tcache.insert(local_def(ifce.id), no_params(t));
}
}
_ {
// This call populates the type cache with the converted type
// 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(ccx, it);
write_ty_to_tcx(tcx, it.id, tpt.ty);
}
}
}
fn convert_native(ccx: @crate_ctxt, i: @ast::native_item) {
// As above, this call populates the type table with the converted
// type of the native item. We simply write it into the node type
// table.
let tpt = ty_of_native_item(ccx, i);
alt i.node {
ast::native_item_fn(_, _) {
write_ty_to_tcx(ccx.tcx, i.id, tpt.ty);
}
}
}
fn collect_item_types(ccx: @crate_ctxt, crate: @ast::crate) {
visit::visit_crate(*crate, (), visit::mk_simple_visitor(@{
visit_item: bind convert(ccx, _),
visit_native_item: bind convert_native(ccx, _)
with *visit::default_simple_visitor()
}));
}
fn ty_of_method(ccx: @crate_ctxt,
m: @ast::method,
rp: ast::region_param) -> ty::method {
{ident: m.ident,
tps: astconv::ty_param_bounds(ccx, m.tps),
fty: astconv::ty_of_fn_decl(ccx, type_rscope(rp), ast::proto_bare,
m.decl, none),
purity: m.decl.purity,
vis: m.vis}
}
fn ty_of_ty_method(self: @crate_ctxt,
m: ast::ty_method,
rp: ast::region_param) -> ty::method {
{ident: m.ident,
tps: astconv::ty_param_bounds(self, m.tps),
fty: astconv::ty_of_fn_decl(self, type_rscope(rp), ast::proto_bare,
m.decl, none),
// assume public, because this is only invoked on iface methods
purity: m.decl.purity, vis: ast::public}
}
fn has_iface_bounds(tps: [ty::param_bounds]) -> bool {
vec::any(tps, {|bs|
vec::any(*bs, {|b|
alt b { ty::bound_iface(_) { true } _ { false } }
})
})
}
fn lookup_vtables(fcx: @fn_ctxt, isc: resolve::iscopes, sp: span,
bounds: @[ty::param_bounds], substs: ty::substs,
allow_unsafe: bool) -> vtable_res {
let tcx = fcx.ccx.tcx;
let mut result = [], i = 0u;
for substs.tps.each {|ty|
for vec::each(*bounds[i]) {|bound|
alt bound {
ty::bound_iface(i_ty) {
let i_ty = ty::subst(tcx, substs, i_ty);
result += [lookup_vtable(fcx, isc, sp, ty, i_ty,
allow_unsafe)];
}
_ {}
}
}
i += 1u;
}
@result
}
fn fixup_substs(fcx: @fn_ctxt, sp: span,
id: ast::def_id, substs: ty::substs) -> ty::substs {
let tcx = fcx.ccx.tcx;
// use a dummy type just to package up the substs that need fixing up
let t = ty::mk_iface(tcx, id, substs);
let t_f = fixup_ty(fcx, sp, t);
alt check ty::get(t_f).struct {
ty::ty_iface(_, substs_f) { substs_f }
}
}
fn relate_iface_tys(fcx: @fn_ctxt, sp: span,
exp_iface_ty: ty::t, act_iface_ty: ty::t) {
demand::suptype(fcx, sp, exp_iface_ty, act_iface_ty)
}
/*
Look up the vtable to use when treating an item of type <t>
as if it has type <iface_ty>
*/
fn lookup_vtable(fcx: @fn_ctxt, isc: resolve::iscopes, sp: span,
ty: ty::t, iface_ty: ty::t, allow_unsafe: bool)
-> vtable_origin {
#debug["lookup_vtable(ty=%s, iface_ty=%s)",
fcx.ty_to_str(ty), fcx.ty_to_str(iface_ty)];
let _i = indenter();
let tcx = fcx.ccx.tcx;
let (iface_id, iface_substs) = alt check ty::get(iface_ty).struct {
ty::ty_iface(did, substs) { (did, substs) }
};
let ty = fixup_ty(fcx, sp, ty);
alt ty::get(ty).struct {
ty::ty_param(n, did) {
let mut n_bound = 0u;
for vec::each(*tcx.ty_param_bounds.get(did.node)) { |bound|
alt bound {
ty::bound_send | ty::bound_copy { /* ignore */ }
ty::bound_iface(ity) {
alt check ty::get(ity).struct {
ty::ty_iface(idid, substs) {
if iface_id == idid {
relate_iface_tys(fcx, sp, iface_ty, ity);
ret vtable_param(n, n_bound);
}
}
}
n_bound += 1u;
}
}
}
}
ty::ty_iface(did, substs) if iface_id == did {
relate_iface_tys(fcx, sp, iface_ty, ty);
if !allow_unsafe {
for vec::each(*ty::iface_methods(tcx, did)) {|m|
if ty::type_has_self(ty::mk_fn(tcx, m.fty)) {
tcx.sess.span_err(
sp, "a boxed iface with self types may not be \
passed as a bounded type");
} else if (*m.tps).len() > 0u {
tcx.sess.span_err(
sp, "a boxed iface with generic methods may not \
be passed as a bounded type");
}
}
}
ret vtable_iface(did, substs.tps);
}
_ {
let mut found = [];
for list::each(isc) {|impls|
/* For each impl in scope... */
for vec::each(*impls) {|im|
// im = one specific impl
// find the iface that im implements (if any)
let of_ty = alt ty::impl_iface(tcx, im.did) {
some(of_ty) { of_ty }
_ { cont; }
};
// it must have the same id as the expected one
alt ty::get(of_ty).struct {
ty::ty_iface(id, _) if id != iface_id { cont; }
_ { /* ok */ }
}
// check whether the type unifies with the type
// that the impl is for, and continue if not
let {substs: substs, ty: for_ty} =
impl_self_ty(fcx, im.did);
let im_bs = ty::lookup_item_type(tcx, im.did).bounds;
alt fcx.mk_subty(ty, for_ty) {
result::err(_) { cont; }
result::ok(()) { }
}
// check that desired iface type unifies
let of_ty = ty::subst(tcx, substs, of_ty);
relate_iface_tys(fcx, sp, iface_ty, of_ty);
// recursively process the bounds
let iface_tps = iface_substs.tps;
let substs_f = fixup_substs(fcx, sp, iface_id, substs);
connect_iface_tps(fcx, sp, substs_f.tps,
iface_tps, im.did);
let subres = lookup_vtables(fcx, isc, sp,
im_bs, substs_f, false);
found += [vtable_static(im.did, substs_f.tps, subres)];
}
alt found.len() {
0u { /* fallthrough */ }
1u { ret found[0]; }
_ {
fcx.ccx.tcx.sess.span_err(
sp, "multiple applicable methods in scope");
ret found[0];
}
}
}
}
}
tcx.sess.span_fatal(
sp, "failed to find an implementation of interface " +
ty_to_str(tcx, iface_ty) + " for " +
ty_to_str(tcx, ty));
}
fn fixup_ty(fcx: @fn_ctxt, sp: span, ty: ty::t) -> ty::t {
let tcx = fcx.ccx.tcx;
alt infer::resolve_deep(fcx.infcx, ty, true) {
result::ok(new_type) { new_type }
result::err(e) {
tcx.sess.span_fatal(
sp,
#fmt["cannot determine a type \
for this bounded type parameter: %s",
infer::fixup_err_to_str(e)])
}
}
}
fn connect_iface_tps(fcx: @fn_ctxt, sp: span, impl_tys: [ty::t],
iface_tys: [ty::t], impl_did: ast::def_id) {
let tcx = fcx.ccx.tcx;
let ity = option::get(ty::impl_iface(tcx, impl_did));
let iface_ty = ty::subst_tps(tcx, impl_tys, ity);
alt check ty::get(iface_ty).struct {
ty::ty_iface(_, substs) {
vec::iter2(substs.tps, iface_tys,
{|a, b| demand::suptype(fcx, sp, a, b);});
}
}
}
fn resolve_expr(ex: @ast::expr, &&fcx: @fn_ctxt, v: visit::vt<@fn_ctxt>) {
let cx = fcx.ccx;
alt ex.node {
ast::expr_path(*) {
alt fcx.opt_node_ty_substs(ex.id) {
some(substs) {
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);
if has_iface_bounds(*item_ty.bounds) {
let impls = cx.impl_map.get(ex.id);
cx.vtable_map.insert(ex.id, lookup_vtables(
fcx, impls, ex.span,
item_ty.bounds, substs, false));
}
}
_ {}
}
}
// Must resolve bounds on methods with bounded params
ast::expr_field(*) | ast::expr_binary(*) |
ast::expr_unary(*) | ast::expr_assign_op(*) |
ast::expr_index(*) {
alt cx.method_map.find(ex.id) {
some(method_static(did)) {
let bounds = ty::lookup_item_type(cx.tcx, did).bounds;
if has_iface_bounds(*bounds) {
let callee_id = alt ex.node {
ast::expr_field(_, _, _) { ex.id }
_ { ast_util::op_expr_callee_id(ex) }
};
let substs = 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, substs, false));
}
}
_ {}
}
}
ast::expr_cast(src, _) {
let target_ty = fcx.expr_ty(ex);
alt ty::get(target_ty).struct {
ty::ty_iface(*) {
/* Casting to an interface type.
Look up all impls for the cast expr...
*/
let impls = cx.impl_map.get(ex.id);
/*
Look up vtables for the type we're casting to,
passing in the source and target type
*/
let vtable = lookup_vtable(fcx, impls, ex.span,
fcx.expr_ty(src), target_ty,
true);
/*
Map this expression to that vtable (that is: "ex has
vtable <vtable>")
*/
cx.vtable_map.insert(ex.id, @[vtable]);
}
_ {}
}
}
_ {}
}
visit::visit_expr(ex, fcx, v);
}
// Detect points where an interface-bounded type parameter is
// instantiated, resolve the impls for the parameters.
fn resolve_in_block(fcx: @fn_ctxt, bl: ast::blk) {
visit::visit_block(bl, fcx, visit::mk_vt(@{
visit_expr: resolve_expr,
visit_item: fn@(_i: @ast::item, &&_e: @fn_ctxt,
_v: visit::vt<@fn_ctxt>) {}
with *visit::default_visitor()
}));
}
// Type resolution: the phase that finds all the types in the AST with
// unresolved type variables and replaces "ty_var" types with their
// substitutions.
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) ->
option<ty::t> {
if !ty::type_needs_infer(typ) { ret some(typ); }
alt infer::resolve_deep(fcx.infcx, typ, true) {
result::ok(new_type) { ret some(new_type); }
result::err(e) {
if !fcx.ccx.tcx.sess.has_errors() {
fcx.ccx.tcx.sess.span_err(
sp,
#fmt["cannot determine a type \
for this expression: %s",
infer::fixup_err_to_str(e)])
}
ret none;
}
}
}
fn resolve_type_vars_for_node(wbcx: wb_ctxt, sp: span, id: ast::node_id)
-> option<ty::t> {
let fcx = wbcx.fcx, tcx = fcx.ccx.tcx;
let n_ty = fcx.node_ty(id);
alt resolve_type_vars_in_type(fcx, sp, n_ty) {
none {
wbcx.success = false;
ret none;
}
some(t) {
#debug["resolve_type_vars_for_node(id=%d, n_ty=%s, t=%s)",
id, ty_to_str(tcx, n_ty), ty_to_str(tcx, t)];
write_ty_to_tcx(tcx, id, t);
alt fcx.opt_node_ty_substs(id) {
some(substs) {
let mut new_tps = [];
for substs.tps.each {|subst|
alt resolve_type_vars_in_type(fcx, sp, subst) {
some(t) { new_tps += [t]; }
none { wbcx.success = false; ret none; }
}
}
write_substs_to_tcx(tcx, id, new_tps);
}
none {}
}
ret some(t);
}
}
}
fn maybe_resolve_type_vars_for_node(wbcx: wb_ctxt, sp: span,
id: ast::node_id)
-> option<ty::t> {
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
{fcx: @fn_ctxt, mut success: bool};
type wb_vt = visit::vt<wb_ctxt>;
fn visit_stmt(s: @ast::stmt, wbcx: wb_ctxt, v: wb_vt) {
if !wbcx.success { ret; }
resolve_type_vars_for_node(wbcx, s.span, ty::stmt_node_id(s));
visit::visit_stmt(s, wbcx, v);
}
fn visit_expr(e: @ast::expr, wbcx: wb_ctxt, v: wb_vt) {
if !wbcx.success { ret; }
resolve_type_vars_for_node(wbcx, e.span, e.id);
alt e.node {
ast::expr_fn(_, decl, _, _) |
ast::expr_fn_block(decl, _, _) {
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(t);
ty::set_default_mode(tcx, input.mode, m_def);
}
_ {}
}
}
}
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);
}
fn visit_block(b: ast::blk, wbcx: wb_ctxt, v: wb_vt) {
if !wbcx.success { ret; }
resolve_type_vars_for_node(wbcx, b.span, b.node.id);
visit::visit_block(b, wbcx, v);
}
fn visit_pat(p: @ast::pat, wbcx: wb_ctxt, v: wb_vt) {
if !wbcx.success { ret; }
resolve_type_vars_for_node(wbcx, p.span, p.id);
#debug["Type for pattern binding %s (id %d) resolved to %s",
pat_to_str(p), p.id,
wbcx.fcx.ty_to_str(
ty::node_id_to_type(wbcx.fcx.ccx.tcx,
p.id))];
visit::visit_pat(p, wbcx, v);
}
fn visit_local(l: @ast::local, wbcx: wb_ctxt, v: wb_vt) {
if !wbcx.success { ret; }
let var_id = lookup_local(wbcx.fcx, l.span, l.node.id);
alt infer::resolve_deep_var(wbcx.fcx.infcx, var_id, true) {
result::ok(lty) {
#debug["Type for local %s (id %d) resolved to %s",
pat_to_str(l.node.pat), l.node.id,
wbcx.fcx.ty_to_str(lty)];
write_ty_to_tcx(wbcx.fcx.ccx.tcx, l.node.id, lty);
}
result::err(e) {
wbcx.fcx.ccx.tcx.sess.span_err(
l.span,
#fmt["cannot determine a type \
for this local variable: %s",
infer::fixup_err_to_str(e)]);
wbcx.success = false;
}
}
visit::visit_local(l, wbcx, v);
}
fn visit_item(_item: @ast::item, _wbcx: wb_ctxt, _v: wb_vt) {
// Ignore items
}
fn resolve_type_vars_in_expr(fcx: @fn_ctxt, e: @ast::expr) -> bool {
let wbcx = {fcx: fcx, mut success: true};
let visit =
visit::mk_vt(@{visit_item: visit_item,
visit_stmt: visit_stmt,
visit_expr: visit_expr,
visit_block: visit_block,
visit_pat: visit_pat,
visit_local: visit_local
with *visit::default_visitor()});
visit.visit_expr(e, wbcx, visit);
ret wbcx.success;
}
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,
visit_stmt: visit_stmt,
visit_expr: visit_expr,
visit_block: visit_block,
visit_pat: visit_pat,
visit_local: visit_local
with *visit::default_visitor()});
visit.visit_block(blk, wbcx, visit);
for decl.inputs.each {|arg|
resolve_type_vars_for_node(wbcx, arg.ty.span, arg.id);
}
ret wbcx.success;
}
......@@ -52,7 +52,12 @@ mod middle {
mod infer;
mod ast_map;
mod resolve;
mod typeck;
mod typeck {
mod astconv;
mod collect;
mod vtable;
mod writeback;
}
mod check_loop;
mod check_alt;
mod check_const;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册