mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-26 08:44:35 +00:00
better support for classes with polymorphic methods
This commit is contained in:
parent
7213274e57
commit
3c4baf694e
@ -664,7 +664,7 @@ fn encode_info_for_item(ecx: @encode_ctxt, ebml_w: ebml::writer, item: @item,
|
||||
ebml_w.start_tag(tag_item_iface_method);
|
||||
encode_family(ebml_w, purity_fn_family(m.decl.purity));
|
||||
encode_name(ebml_w, m.ident);
|
||||
encode_type_param_bounds(ebml_w, ecx, tps + m.tps);
|
||||
encode_type_param_bounds(ebml_w, ecx, m.tps);
|
||||
encode_type(ecx, ebml_w, node_id_to_type(tcx, m.id));
|
||||
encode_def_id(ebml_w, local_def(m.id));
|
||||
ebml_w.end_tag();
|
||||
|
@ -254,29 +254,16 @@ fn check_expr(e: @expr, cx: ctx, v: visit::vt<ctx>) {
|
||||
expr_field(base, _, _) {
|
||||
alt cx.method_map.get(e.id) {
|
||||
typeck::method_static(did) {
|
||||
/*
|
||||
If this is a class method, we want to use the
|
||||
class bounds plus the method bounds -- otherwise the
|
||||
indices come out wrong. So we check base's type...
|
||||
*/
|
||||
let mut bounds = ty::lookup_item_type(cx.tcx, did).bounds;
|
||||
alt ty::get(ty::node_id_to_type(cx.tcx, base.id)).struct {
|
||||
ty::ty_class(parent_id, ts) {
|
||||
/* ...and if it has a class type, prepend the
|
||||
class bounds onto the method bounds */
|
||||
/* n.b. this code is very likely sketchy --
|
||||
currently, class-impl-very-parameterized-iface
|
||||
fails here and is thus xfailed */
|
||||
bounds =
|
||||
@(*ty::lookup_item_type(cx.tcx, parent_id).bounds
|
||||
+ *bounds);
|
||||
}
|
||||
_ { }
|
||||
}
|
||||
bounds
|
||||
// n.b.: When we encode class/impl methods, the bounds
|
||||
// that we encode include both the class/impl bounds
|
||||
// and then the method bounds themselves...
|
||||
ty::lookup_item_type(cx.tcx, did).bounds
|
||||
}
|
||||
typeck::method_param(ifce_id, n_mth, _, _) |
|
||||
typeck::method_iface(ifce_id, n_mth) {
|
||||
// ...iface methods bounds, in contrast, include only the
|
||||
// method bounds, so we must preprend the tps from the
|
||||
// iface itself. This ought to be harmonized.
|
||||
let ifce_bounds =
|
||||
ty::lookup_item_type(cx.tcx, ifce_id).bounds;
|
||||
let mth = ty::iface_methods(cx.tcx, ifce_id)[n_mth];
|
||||
|
@ -18,6 +18,9 @@ enum lookup = {
|
||||
impl methods for lookup {
|
||||
// Entrypoint:
|
||||
fn method() -> option<method_origin> {
|
||||
#debug["method lookup(m_name=%s, self_ty=%s)",
|
||||
self.m_name, self.fcx.infcx.ty_to_str(self.self_ty)];
|
||||
|
||||
// First, see whether this is an interface-bounded parameter
|
||||
let pass1 = alt ty::get(self.self_ty).struct {
|
||||
ty::ty_param(n, did) {
|
||||
@ -288,6 +291,11 @@ impl methods for lookup {
|
||||
|
||||
let tcx = self.fcx.ccx.tcx;
|
||||
|
||||
#debug["write_mty_from_fty(n_tps_m=%u, fty=%s, origin=%?)",
|
||||
n_tps_m,
|
||||
self.fcx.infcx.ty_to_str(fty),
|
||||
origin];
|
||||
|
||||
// Here I will use the "c_" prefix to refer to the method's
|
||||
// owner. You can read it as class, but it may also be an iface.
|
||||
|
||||
|
@ -228,17 +228,15 @@ fn check_methods_against_iface(ccx: @crate_ctxt,
|
||||
rp: ast::region_param,
|
||||
selfty: ty::t,
|
||||
a_ifacety: @ast::iface_ref,
|
||||
ms: [@ast::method]) {
|
||||
ms: [converted_method]) {
|
||||
|
||||
let tcx = ccx.tcx;
|
||||
let i_bounds = 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}) {
|
||||
alt vec::find(ms, {|m| if_m.ident == m.mty.ident}) {
|
||||
some({mty: m, id, span}) {
|
||||
if m.purity != if_m.purity {
|
||||
ccx.tcx.sess.span_err(
|
||||
@ -274,12 +272,13 @@ fn convert_class_item(ccx: @crate_ctxt,
|
||||
ccx.tcx.tcache.insert(local_def(v.id), {bounds: bounds, rp: rp, ty: tt});
|
||||
}
|
||||
|
||||
type converted_method = {mty: ty::method, id: ast::node_id, span: span};
|
||||
|
||||
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}] {
|
||||
rcvr_bounds: @[ty::param_bounds],
|
||||
self_ty: ty::t) -> [converted_method] {
|
||||
|
||||
let tcx = ccx.tcx;
|
||||
vec::map(ms) { |m|
|
||||
@ -289,9 +288,10 @@ fn convert_methods(ccx: @crate_ctxt,
|
||||
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});
|
||||
|
||||
// n.b.: the type of a method is parameterized by both
|
||||
// the tps on the receiver and those on the method itself
|
||||
{bounds: @(*rcvr_bounds + *bounds), rp: rp, ty: fty});
|
||||
write_ty_to_tcx(tcx, m.id, fty);
|
||||
{mty: mty, id: m.id, span: m.span}
|
||||
}
|
||||
@ -316,19 +316,10 @@ fn convert(ccx: @crate_ctxt, it: @ast::item) {
|
||||
{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);
|
||||
}
|
||||
|
||||
let cms = convert_methods(ccx, ms, rp, i_bounds, selfty);
|
||||
for ifce.each { |t|
|
||||
check_methods_against_iface(ccx, tps, rp, selfty, t, cms);
|
||||
}
|
||||
}
|
||||
ast::item_res(decl, tps, _, dtor_id, ctor_id, rp) {
|
||||
@ -412,23 +403,11 @@ fn convert(ccx: @crate_ctxt, it: @ast::item) {
|
||||
for fields.each {|f|
|
||||
convert_class_item(ccx, rp, tpt.bounds, f);
|
||||
}
|
||||
// The selfty is just the class type
|
||||
let {bounds:_, substs} = mk_substs(ccx, tps, rp);
|
||||
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.
|
||||
*/
|
||||
let cms = convert_methods(ccx, methods, rp, bounds, selfty);
|
||||
for ifaces.each { |ifce|
|
||||
check_methods_against_iface(ccx, tps, rp, selfty,
|
||||
ifce, methods);
|
||||
check_methods_against_iface(ccx, tps, rp, selfty, ifce, cms);
|
||||
|
||||
// FIXME #2434---this is somewhat bogus, but it seems that
|
||||
// the id of iface_ref is also the id of the impl, and so
|
||||
|
@ -1,4 +1,3 @@
|
||||
// xfail-test (still buggy)
|
||||
// xfail-fast (compile-flags unsupported on windows)
|
||||
// compile-flags:--borrowck=err
|
||||
// exec-env:RUST_POISON_ON_FREE=1
|
||||
|
@ -1,5 +1,3 @@
|
||||
// xfail-test
|
||||
// xfail-fast
|
||||
use std;
|
||||
import std::map::*;
|
||||
|
||||
@ -59,7 +57,7 @@ class cat<T: copy> implements map<int, T> {
|
||||
}
|
||||
else { none }
|
||||
}
|
||||
|
||||
|
||||
fn remove(&&k:int) -> option<T> {
|
||||
alt self.find(k) {
|
||||
some(x) {
|
||||
@ -76,7 +74,7 @@ class cat<T: copy> implements map<int, T> {
|
||||
n -= 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fn each_key(&&f: fn(&&int) -> bool) {
|
||||
for self.each {|k, _v| if !f(k) { break; } cont;};
|
||||
}
|
||||
@ -88,11 +86,11 @@ class cat<T: copy> implements map<int, T> {
|
||||
|
||||
fn main() {
|
||||
let nyan : cat<str> = cat(0, 2, "nyan");
|
||||
uint::range(1u, 5u) {|_i| nyan.speak(); }
|
||||
for uint::range(1u, 5u) {|_i| nyan.speak(); }
|
||||
assert(nyan.find(1) == some("nyan"));
|
||||
assert(nyan.find(10) == none);
|
||||
let spotty : cat<cat_type> = cat(2, 57, tuxedo);
|
||||
uint::range(0u, 6u) {|_i| spotty.speak(); }
|
||||
for uint::range(0u, 6u) {|_i| spotty.speak(); }
|
||||
assert(spotty.size() == 8u);
|
||||
assert(spotty.contains_key(2));
|
||||
assert(spotty.get(3) == tuxedo);
|
||||
|
@ -1,5 +1,3 @@
|
||||
// xfail-test
|
||||
|
||||
// xfail-fast
|
||||
// aux-build:cci_class_6.rs
|
||||
use cci_class_6;
|
||||
|
@ -1,5 +1,3 @@
|
||||
// xfail-test
|
||||
// needs metadata encoding on Windows
|
||||
class cat<U> {
|
||||
priv {
|
||||
let mut meows : uint;
|
||||
|
Loading…
Reference in New Issue
Block a user