Allow classes to be cast to ifaces that are in the same crate

I had to xfail one existing test case (class-implements-int) because,
I think, of the same bug described in #2272.
This commit is contained in:
Tim Chevalier
2012-04-13 12:22:35 -07:00
parent 1c39fda0ea
commit f7641286b2
23 changed files with 562 additions and 162 deletions

View File

@@ -160,8 +160,9 @@ fn get_field_type(tcx: ty::ctxt, class_id: ast::def_id,
ret {bounds: @[], rp: ast::rp_none, ty: ty};
}
fn get_impl_iface(tcx: ty::ctxt, def: ast::def_id)
-> option<ty::t> {
// Given a def_id for an impl or class, return the iface it implements,
// or none if it's not for an impl or for a class that implements ifaces
fn get_impl_iface(tcx: ty::ctxt, def: ast::def_id) -> option<ty::t> {
let cstore = tcx.sess.cstore;
let cdata = cstore::get_crate_data(cstore, def.crate);
decoder::get_impl_iface(cdata, def.node, tcx)

View File

@@ -27,7 +27,6 @@ export get_class_method;
export get_impl_method;
export lookup_def;
export lookup_item_name;
export get_impl_iface;
export resolve_path;
export get_crate_attributes;
export list_crate_metadata;
@@ -157,11 +156,9 @@ fn item_impl_iface(item: ebml::doc, tcx: ty::ctxt, cdata: cmd)
-> option<ty::t> {
let mut result = none;
ebml::tagged_docs(item, tag_impl_iface) {|ity|
let t = parse_ty_data(ity.data, cdata.cnum, ity.start, tcx, {|did|
translate_def_id(cdata, did)
});
result = some(t);
}
result = some(parse_ty_data(ity.data, cdata.cnum, ity.start, tcx,
{|did| translate_def_id(cdata, did)}));
};
result
}

View File

@@ -659,9 +659,7 @@ fn encode_info_for_item(ecx: @encode_ctxt, ebml_w: ebml::writer, item: @item,
}
alt ifce {
some(t) {
let i_ty = alt check t.node {
ty_path(_, id) { ty::node_id_to_type(tcx, id) }
};
let i_ty = ty::node_id_to_type(tcx, t.id);
ebml_w.start_tag(tag_impl_iface);
write_type(ecx, ebml_w, i_ty);
ebml_w.end_tag();

View File

@@ -204,16 +204,16 @@ fn map_item(i: @item, cx: ctx, v: vt) {
cx.map.insert(nitem.id, node_native_item(nitem, abi, @cx.path));
}
}
item_class(_, _, items, ctor, _) {
item_class(tps, ifces, items, ctor, _) {
let (_, ms) = ast_util::split_class_items(items);
// Map iface refs to their parent classes. This is
// so we can find the self_ty
vec::iter(ifces) {|p| cx.map.insert(p.id,
node_item(i, item_path)); };
let d_id = ast_util::local_def(i.id);
let p = extend(cx, i.ident);
for items.each {|ci|
// only need to handle methods
alt ci.node {
class_method(m) { map_method(d_id, p, m, cx); }
_ {}
}
}
vec::iter(ms) {|m| map_method(d_id, p, m, cx); }
}
_ { }
}

View File

@@ -9,6 +9,7 @@ import metadata::{csearch, cstore};
import driver::session::session;
import util::common::*;
import std::map::{int_hash, str_hash, hashmap};
import vec::each;
import syntax::codemap::span;
import syntax::visit;
import visit::vt;
@@ -402,6 +403,11 @@ fn maybe_insert(e: @env, id: node_id, def: option<def>) {
}
}
fn resolve_iface_ref(p: @iface_ref, sc: scopes, e: @env) {
maybe_insert(e, p.id,
lookup_path_strict(*e, sc, p.path.span, p.path, ns_type));
}
fn resolve_names(e: @env, c: @ast::crate) {
e.used_imports.track = true;
let v =
@@ -431,9 +437,10 @@ fn resolve_names(e: @env, c: @ast::crate) {
alt i.node {
ast::item_class(_, ifaces, _, _, _) {
/* visit the iface paths... */
for ifaces.each {|p|
maybe_insert(e, p.id,
lookup_path_strict(*e, sc, p.path.span, p.path, ns_type))};
for ifaces.each {|p| resolve_iface_ref(p, sc, e)};
}
ast::item_impl(_, ifce, _, _) {
option::iter(ifce, {|p| resolve_iface_ref(p, sc, e)});
}
_ {}
}
@@ -535,7 +542,7 @@ fn visit_item_with_scope(e: @env, i: @ast::item, sc: scopes, v: vt<scopes>) {
alt i.node {
ast::item_impl(tps, ifce, sty, methods) {
visit::visit_ty_params(tps, sc, v);
alt ifce { some(ty) { v.visit_ty(ty, sc, v); } _ {} }
option::iter(ifce) {|p| visit::visit_path(p.path, sc, v)};
v.visit_ty(sty, sc, v);
for methods.each {|m|
v.visit_ty_params(m.tps, sc, v);
@@ -1109,11 +1116,11 @@ fn lookup_in_scope(e: env, sc: scopes, sp: span, name: ident, ns: namespace,
}
ret some(df);
}
_ {}
}
if left_fn {
left_fn_level2 = true;
} else if ns != ns_module {
_ {}
}
if left_fn {
left_fn_level2 = true;
} else if ns != ns_module {
left_fn = scope_is_fn(hd);
alt scope_closes(hd) {
some(node_id) { closing += [node_id]; }
@@ -1121,8 +1128,8 @@ fn lookup_in_scope(e: env, sc: scopes, sp: span, name: ident, ns: namespace,
}
}
sc = *tl;
}
}
}
};
}
@@ -2103,6 +2110,8 @@ fn check_exports(e: @env) {
// Impl resolution
type method_info = {did: def_id, n_tps: uint, ident: ast::ident};
/* what are the did and ident here? */
/* ident = the name of the impl */
type _impl = {did: def_id, ident: ast::ident, methods: [@method_info]};
type iscopes = list<@[@_impl]>;
@@ -2177,6 +2186,12 @@ fn find_impls_in_view_item(e: env, vi: @ast::view_item,
}
}
/*
Given an item <i>, adds one record to the mutable vec
<impls> if the item is an impl; zero or more records if the
item is a class; and none otherwise. Each record describes
one interface implemented by i.
*/
fn find_impls_in_item(e: env, i: @ast::item, &impls: [@_impl],
name: option<ident>,
ck_exports: option<@indexed_mod>) {
@@ -2196,6 +2211,20 @@ fn find_impls_in_item(e: env, i: @ast::item, &impls: [@_impl],
})}];
}
}
ast::item_class(tps, ifces, items, _, _) {
let (_, mthds) = ast_util::split_class_items(items);
let n_tps = tps.len();
vec::iter(ifces) {|p|
// The def_id, in this case, identifies the combination of
// class and iface
impls += [@{did: local_def(p.id),
ident: i.ident,
methods: vec::map(mthds, {|m|
@{did: local_def(m.id),
n_tps: n_tps + m.tps.len(),
ident: m.ident}})}];
}
}
_ {}
}
}

View File

@@ -164,7 +164,7 @@ fn enter_opt(tcx: ty::ctxt, m: match, opt: opt, col: uint,
alt p.node {
ast::pat_enum(_, subpats) {
if opt_eq(tcx, variant_opt(tcx, p.id), opt) {
some(option::get_or_default(subpats,
some(option::get_default(subpats,
vec::from_elem(variant_size, dummy))) }
else { none }
}

View File

@@ -1963,7 +1963,7 @@ fn monomorphic_fn(ccx: @crate_ctxt, fn_id: ast::def_id, real_substs: [ty::t],
let mono_ty = ty::subst_tps(ccx.tcx, substs, item_ty);
let llfty = type_of_fn_from_ty(ccx, mono_ty);
let depth = option::get_or_default(ccx.monomorphizing.find(fn_id), 0u);
let depth = option::get_default(ccx.monomorphizing.find(fn_id), 0u);
// Random cut-off -- code that needs to instantiate the same function
// recursively more than ten times can probably safely be assumed to be
// causing an infinite expansion.

View File

@@ -5,13 +5,13 @@ import type_of::*;
import build::*;
import driver::session::session;
import syntax::ast;
import syntax::ast_util::local_def;
import syntax::ast_util::{local_def, split_class_items};
import metadata::csearch;
import back::{link, abi};
import lib::llvm::llvm;
import lib::llvm::{ValueRef, TypeRef};
import lib::llvm::llvm::LLVMGetParam;
import ast_map::{path, path_mod, path_name};
import ast_map::{path, path_mod, path_name, node_id_to_str};
import std::map::hashmap;
fn trans_impl(ccx: @crate_ctxt, path: path, name: ast::ident,
@@ -82,12 +82,21 @@ fn trans_vtable_callee(bcx: block, env: callee_env, vtable: ValueRef,
{bcx: bcx, val: mptr, kind: owned, env: env}
}
fn method_from_methods(ms: [@ast::method], name: ast::ident) -> ast::def_id {
local_def(option::get(vec::find(ms, {|m| m.ident == name})).id)
}
fn method_with_name(ccx: @crate_ctxt, impl_id: ast::def_id,
name: ast::ident) -> ast::def_id {
if impl_id.crate == ast::local_crate {
alt check ccx.tcx.items.get(impl_id.node) {
ast_map::node_item(@{node: ast::item_impl(_, _, _, ms), _}, _) {
local_def(option::get(vec::find(ms, {|m| m.ident == name})).id)
method_from_methods(ms, name)
}
ast_map::node_item(@{node:
ast::item_class(_, _, items, _, _), _}, _) {
let (_,ms) = split_class_items(items);
method_from_methods(ms, name)
}
}
} else {
@@ -245,9 +254,8 @@ fn make_impl_vtable(ccx: @crate_ctxt, impl_id: ast::def_id, substs: [ty::t],
let tcx = ccx.tcx;
let ifce_id = ty::ty_to_def_id(option::get(ty::impl_iface(tcx, impl_id)));
let has_tps = (*ty::lookup_item_type(ccx.tcx, impl_id).bounds).len() > 0u;
make_vtable(ccx, vec::map(*ty::iface_methods(tcx, ifce_id), {|im|
let fty = ty::subst_tps(tcx, substs,
ty::mk_fn(tcx, im.fty));
make_vtable(ccx, vec::map(*ty::iface_methods(tcx, ifce_id)) {|im|
let fty = ty::subst_tps(tcx, substs, ty::mk_fn(tcx, im.fty));
if (*im.tps).len() > 0u || ty::type_has_vars(fty) {
C_null(T_ptr(T_nil()))
} else {
@@ -260,7 +268,7 @@ fn make_impl_vtable(ccx: @crate_ctxt, impl_id: ast::def_id, substs: [ty::t],
trans_external_path(ccx, m_id, fty)
}
}
}))
})
}
fn trans_cast(bcx: block, val: @ast::expr, id: ast::node_id, dest: dest)

View File

@@ -1326,6 +1326,17 @@ fn type_kind(cx: ctxt, ty: t) -> kind {
}
lowest
}
// FIXME: (tjc) there are rules about when classes are copyable/
// sendable, but I'm just treating them like records (#1726)
ty_class(did, substs) {
// also factor out this code, copied from the records case
let mut lowest = kind_sendable;
let flds = class_items_as_fields(cx, did, substs);
for flds.each {|f|
lowest = lower_kind(lowest, type_kind(cx, f.mt.ty));
}
lowest
}
// Tuples lower to the lowest of their members.
ty_tup(tys) {
let mut lowest = kind_sendable;
@@ -1356,7 +1367,6 @@ fn type_kind(cx: ctxt, ty: t) -> kind {
param_bounds_to_kind(cx.ty_param_bounds.get(did.node))
}
ty_constr(t, _) { type_kind(cx, t) }
ty_class(_, _) { fail "FIXME"; }
ty_var(_) { fail "FIXME"; }
ty_self(_) { kind_noncopyable }
};
@@ -2248,12 +2258,24 @@ fn iface_methods(cx: ctxt, id: ast::def_id) -> @[method] {
fn impl_iface(cx: ctxt, id: ast::def_id) -> option<t> {
if id.crate == ast::local_crate {
alt cx.items.get(id.node) {
ast_map::node_item(@{node: ast::item_impl(
_, some(@{node: ast::ty_path(_, id), _}), _, _), _}, _) {
some(node_id_to_type(cx, id))
}
_ { none }
alt cx.items.find(id.node) {
some(ast_map::node_item(@{node: ast::item_impl(
_, some(@{id: id, _}), _, _), _}, _)) {
some(node_id_to_type(cx, id))
}
some(ast_map::node_item(@{node: ast::item_class(_, _, _, _, _),
_},_)) {
alt cx.def_map.find(id.node) {
some(def_ty(iface_id)) {
some(node_id_to_type(cx, id.node))
}
_ {
cx.sess.bug("impl_iface: iface ref isn't in iface map \
and isn't bound to a def_ty");
}
}
}
_ { none }
}
} else {
csearch::get_impl_iface(cx, id)

View File

@@ -20,6 +20,7 @@ import std::map;
import std::map::{hashmap, int_hash};
import std::serialization::{serialize_uint, deserialize_uint};
import std::ufind;
import vec::each;
import syntax::print::pprust::*;
import util::common::indent;
import std::list;
@@ -43,10 +44,27 @@ type method_map = hashmap<ast::node_id, method_origin>;
// Resolutions for bounds of all parameters, left to right, for a given path.
type vtable_res = @[vtable_origin];
enum vtable_origin {
/*
Statically known vtable. def_id gives the class or impl item
from whence comes the vtable, and tys are the type substs.
vtable_res is the vtable itself
*/
vtable_static(ast::def_id, [ty::t], vtable_res),
// Param number, bound number
/*
Dynamic vtable, comes from a parameter that has a bound on it:
fn foo<T: quux, baz, bar>(a: T) -- a's vtable would have a
vtable_param origin
The first uint is the param number (identifying T in the example),
and the second is the bound number (identifying baz)
*/
vtable_param(uint, uint),
/*
Dynamic vtable, comes from something known to have an interface
type. def_id refers to the iface item, tys are the substs
*/
vtable_iface(ast::def_id, [ty::t]),
}
@@ -119,12 +137,12 @@ type fn_ctxt =
// Determines whether the given node ID is a use of the def of
// the self ID for the current method, if there is one
// self IDs in an outer scope count. so that means that you can
// call your own private methods from nested functions inside
// class methods
fn self_ref(fcx: @fn_ctxt, id: ast::node_id) -> bool {
// check what def `id` was resolved to (if anything)
alt fcx.ccx.tcx.def_map.find(id) {
some(ast::def_self(_)) { true }
_ { false }
}
option::map_default(fcx.ccx.tcx.def_map.find(id), false,
ast_util::is_self)
}
fn lookup_local(fcx: @fn_ctxt, sp: span, id: ast::node_id) -> ty_vid {
@@ -465,19 +483,7 @@ fn ast_region_to_region<AC: ast_conv, RS: region_scope>(
get_region_reporting_err(self.tcx(), span, res)
}
// 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<AC: ast_conv, RS: region_scope copy>(
self: AC, rscope: RS, &&ast_ty: @ast::ty) -> ty::t {
fn ast_mt_to_mt<AC: ast_conv, RS: region_scope copy>(
self: AC, rscope: RS, mt: ast::mt) -> ty::mt {
ret {ty: ast_ty_to_ty(self, rscope, mt.ty), mutbl: mt.mutbl};
}
fn instantiate<AC: ast_conv, RS: region_scope copy>(
fn instantiate<AC: ast_conv, RS: region_scope copy>(
self: AC, rscope: RS, sp: span, id: ast::def_id,
path_id: ast::node_id, args: [@ast::ty]) -> ty::t {
@@ -511,6 +517,40 @@ fn ast_ty_to_ty<AC: ast_conv, RS: region_scope copy>(
let ty = ty::subst(tcx, substs, ty);
write_substs_to_tcx(tcx, path_id, substs.tps);
ret ty;
}
/*
Instantiates the path for the given iface reference, assuming that
it's bound to a valid iface type. Returns the def_id for the defining
iface
*/
fn instantiate_iface_ref(ccx: @crate_ctxt, t: @ast::iface_ref)
-> ast::def_id {
alt lookup_def_tcx(ccx.tcx, t.path.span, t.id) {
ast::def_ty(t_id) {
// tjc: will probably need to refer to
// impl or class ty params too
instantiate(ccx, empty_rscope, t.path.span, t_id, t.id,
t.path.types);
t_id
}
_ {
ccx.tcx.sess.span_fatal(t.path.span,
"can only implement interface types");
}
}
}
// 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<AC: ast_conv, RS: region_scope copy>(
self: AC, rscope: RS, &&ast_ty: @ast::ty) -> ty::t {
fn ast_mt_to_mt<AC: ast_conv, RS: region_scope copy>(
self: AC, rscope: RS, mt: ast::mt) -> ty::mt {
ret {ty: ast_ty_to_ty(self, rscope, mt.ty), mutbl: mt.mutbl};
}
fn mk_bounded<AC: ast_conv, RS: region_scope copy>(
@@ -1169,6 +1209,7 @@ fn mk_substs(ccx: @crate_ctxt, atps: [ast::ty_param], rp: ast::region_param)
fn compare_impl_method(tcx: ty::ctxt, sp: span, impl_m: ty::method,
impl_tps: uint, if_m: ty::method, substs: [ty::t],
self_ty: ty::t) -> ty::t {
if impl_m.tps != if_m.tps {
tcx.sess.span_err(sp, "method `" + if_m.ident +
"` has an incompatible set of type parameters");
@@ -1371,39 +1412,37 @@ mod collect {
tps: [ast::ty_param],
rp: ast::region_param,
selfty: ty::t,
t: @ast::ty,
ms: [@ast::method]) {
t: @ast::iface_ref,
ms: [@ast::method]) -> ast::def_id {
let tcx = ccx.tcx;
let i_bounds = ty_param_bounds(ccx, tps);
let my_methods = convert_methods(ccx, ms, rp, i_bounds, selfty);
let iface_ty = ccx.to_ty(empty_rscope, t);
alt ty::get(iface_ty).struct {
ty::ty_iface(did, tys) {
// Store the iface type in the type node
alt check t.node {
ast::ty_path(_, t_id) {
write_ty_to_tcx(tcx, t_id, iface_ty);
}
}
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 \
let did = instantiate_iface_ref(ccx, t);
// not sure whether it's correct to use empty_rscope
// -- tjc
let tys = vec::map(t.path.types,
{|t| ccx.to_ty(empty_rscope,t)});
// Store the iface type in the type node
write_ty_to_tcx(tcx, t.id, ty::mk_iface(ccx.tcx, did, tys));
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(
}
let mt = compare_impl_method(
ccx.tcx, span, m, vec::len(tps),
if_m, tys, selfty);
let old = tcx.tcache.get(local_def(id));
if old.ty != mt {
let old = tcx.tcache.get(local_def(id));
if old.ty != mt {
tcx.tcache.insert(
local_def(id),
{bounds: old.bounds,
@@ -1412,27 +1451,24 @@ mod collect {
write_ty_to_tcx(tcx, id, mt);
}
}
none {
tcx.sess.span_err(t.span, "missing method `" +
none {
tcx.sess.span_err(t.path.span, "missing method `" +
if_m.ident + "`");
}
} // alt
} // |if_m|
} // for
_ {
tcx.sess.span_fatal(t.span, "can only implement \
interface types");
}
}
}
}
} // alt
} // |if_m|
did
} // 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);
#debug("convert_class_item: %s %?", v.ident, v.id);
write_ty_to_tcx(ccx.tcx, v.id, tt);
}
@@ -1485,7 +1521,7 @@ mod collect {
ty: selfty});
alt ifce {
some(t) {
check_methods_against_iface(
check_methods_against_iface(
ccx, tps, ast::rp_none, // NDM iface/impl regions
selfty, t, ms);
}
@@ -1569,29 +1605,16 @@ mod collect {
that it claims to implement.
*/
for ifaces.each { |ifce|
alt lookup_def_tcx(tcx, it.span, ifce.id) {
ast::def_ty(t_id) {
let t = ty::lookup_item_type(tcx, t_id).ty;
alt ty::get(t).struct {
ty::ty_iface(_,_) {
write_ty_to_tcx(tcx, ifce.id, t);
check_methods_against_iface(
ccx, tps, rp, selfty,
@{id: ifce.id,
node: ast::ty_path(ifce.path, ifce.id),
span: ifce.path.span},
methods);
}
_ {
tcx.sess.span_fatal(
ifce.path.span,
"can only implement interface types");
}
}
}
_ { tcx.sess.span_err(ifce.path.span, "not an interface \
type"); }
}
let t_id = check_methods_against_iface(ccx, tps, rp, selfty,
ifce, methods);
// FIXME: This assumes classes only implement
// non-parameterized ifaces. add a test case for
// a class implementing a parameterized iface.
// -- tjc (#1726)
let t = ty::mk_iface(tcx, t_id, []);
write_ty_to_tcx(tcx, ifce.id, t);
// FIXME: likewise, assuming no bounds -- tjc
tcx.tcache.insert(local_def(ifce.id), no_params(t));
}
}
_ {
@@ -1601,7 +1624,7 @@ mod collect {
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
@@ -1696,8 +1719,7 @@ fn require_same_types(
alt infer::compare_tys(tcx, t1, t2) {
result::ok(()) { true }
result::err(terr) {
tcx.sess.span_err(
span, msg() + ": " +
tcx.sess.span_err(span, msg() + ": " +
ty::type_err_to_str(tcx, terr));
false
}
@@ -2368,12 +2390,28 @@ fn impl_self_ty(fcx: @fn_ctxt, did: ast::def_id) -> ty_param_substs_and_ty {
let tcx = fcx.ccx.tcx;
let {n_tps, raw_ty} = if did.crate == ast::local_crate {
alt check tcx.items.get(did.node) {
ast_map::node_item(@{node: ast::item_impl(ts, _, st, _),
_}, _) {
{n_tps: vec::len(ts),
alt check tcx.items.find(did.node) {
some(ast_map::node_item(@{node: ast::item_impl(ts, _, st, _),
_}, _)) {
{n_tps: ts.len(),
raw_ty: fcx.to_ty(st)}
}
// Node doesn't map to an impl. It might map to a class.
some(ast_map::node_item(@{node: ast::item_class(ts,
_,_,_,rp), id: class_id, _},_)) {
/* If the impl is a class, the self ty is just the class ty
(doing a no-op subst for the ty params; in the next step,
we substitute in fresh vars for them)
*/
{n_tps: ts.len(),
raw_ty: ty::mk_class(tcx, local_def(class_id),
{self_r: alt rp {
ast::rp_self { some(fcx.next_region_var()) }
ast::rp_none { none }},
tps: ty::ty_params_to_tys(tcx, ts)})}
}
_ { tcx.sess.bug("impl_self_ty: unbound item or item that \
doesn't have a self_ty"); }
}
} else {
let ity = ty::lookup_item_type(tcx, did);
@@ -4300,6 +4338,8 @@ fn check_item(ccx: @crate_ctxt, it: @ast::item) {
check_bare_fn(class_ccx, ctor.node.dec,
ctor.node.body, ctor.node.id,
some(class_t));
// Write the ctor's self's type
write_ty_to_tcx(tcx, ctor.node.self_id, class_t);
// typecheck the members
for members.each {|m| check_class_member(class_ccx, class_t, m); }
@@ -4403,6 +4443,10 @@ mod vtable {
@result
}
/*
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 {
@@ -4449,14 +4493,17 @@ mod vtable {
for list::each(isc) {|impls|
let mut found = none;
for vec::each(*impls) {|im|
/* What iface does this item implement? */
let match = alt ty::impl_iface(tcx, im.did) {
some(ity) {
alt check ty::get(ity).struct {
/* Does it match the one we're searching for? */
ty::ty_iface(id, _) { id == iface_id }
}
}
_ { false }
};
/* Found a matching iface */
if match {
let {substs: substs, ty: self_ty} =
impl_self_ty(fcx, im.did);
@@ -4566,10 +4613,21 @@ mod vtable {
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]);
}
_ {}