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:
@@ -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)
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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); }
|
||||
}
|
||||
_ { }
|
||||
}
|
||||
|
||||
@@ -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}})}];
|
||||
}
|
||||
}
|
||||
_ {}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 }
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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]);
|
||||
}
|
||||
_ {}
|
||||
|
||||
Reference in New Issue
Block a user