mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-29 18:23:49 +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);
|
ebml_w.start_tag(tag_item_iface_method);
|
||||||
encode_family(ebml_w, purity_fn_family(m.decl.purity));
|
encode_family(ebml_w, purity_fn_family(m.decl.purity));
|
||||||
encode_name(ebml_w, m.ident);
|
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_type(ecx, ebml_w, node_id_to_type(tcx, m.id));
|
||||||
encode_def_id(ebml_w, local_def(m.id));
|
encode_def_id(ebml_w, local_def(m.id));
|
||||||
ebml_w.end_tag();
|
ebml_w.end_tag();
|
||||||
|
@ -254,29 +254,16 @@ fn check_expr(e: @expr, cx: ctx, v: visit::vt<ctx>) {
|
|||||||
expr_field(base, _, _) {
|
expr_field(base, _, _) {
|
||||||
alt cx.method_map.get(e.id) {
|
alt cx.method_map.get(e.id) {
|
||||||
typeck::method_static(did) {
|
typeck::method_static(did) {
|
||||||
/*
|
// n.b.: When we encode class/impl methods, the bounds
|
||||||
If this is a class method, we want to use the
|
// that we encode include both the class/impl bounds
|
||||||
class bounds plus the method bounds -- otherwise the
|
// and then the method bounds themselves...
|
||||||
indices come out wrong. So we check base's type...
|
ty::lookup_item_type(cx.tcx, did).bounds
|
||||||
*/
|
|
||||||
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
|
|
||||||
}
|
}
|
||||||
typeck::method_param(ifce_id, n_mth, _, _) |
|
typeck::method_param(ifce_id, n_mth, _, _) |
|
||||||
typeck::method_iface(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 =
|
let ifce_bounds =
|
||||||
ty::lookup_item_type(cx.tcx, ifce_id).bounds;
|
ty::lookup_item_type(cx.tcx, ifce_id).bounds;
|
||||||
let mth = ty::iface_methods(cx.tcx, ifce_id)[n_mth];
|
let mth = ty::iface_methods(cx.tcx, ifce_id)[n_mth];
|
||||||
|
@ -18,6 +18,9 @@ enum lookup = {
|
|||||||
impl methods for lookup {
|
impl methods for lookup {
|
||||||
// Entrypoint:
|
// Entrypoint:
|
||||||
fn method() -> option<method_origin> {
|
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
|
// First, see whether this is an interface-bounded parameter
|
||||||
let pass1 = alt ty::get(self.self_ty).struct {
|
let pass1 = alt ty::get(self.self_ty).struct {
|
||||||
ty::ty_param(n, did) {
|
ty::ty_param(n, did) {
|
||||||
@ -288,6 +291,11 @@ impl methods for lookup {
|
|||||||
|
|
||||||
let tcx = self.fcx.ccx.tcx;
|
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
|
// 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.
|
// 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,
|
rp: ast::region_param,
|
||||||
selfty: ty::t,
|
selfty: ty::t,
|
||||||
a_ifacety: @ast::iface_ref,
|
a_ifacety: @ast::iface_ref,
|
||||||
ms: [@ast::method]) {
|
ms: [converted_method]) {
|
||||||
|
|
||||||
let tcx = ccx.tcx;
|
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);
|
let (did, tpt) = instantiate_iface_ref(ccx, a_ifacety, rp);
|
||||||
if did.crate == ast::local_crate {
|
if did.crate == ast::local_crate {
|
||||||
ensure_iface_methods(ccx, did.node);
|
ensure_iface_methods(ccx, did.node);
|
||||||
}
|
}
|
||||||
for vec::each(*ty::iface_methods(tcx, did)) {|if_m|
|
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}) {
|
some({mty: m, id, span}) {
|
||||||
if m.purity != if_m.purity {
|
if m.purity != if_m.purity {
|
||||||
ccx.tcx.sess.span_err(
|
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});
|
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,
|
fn convert_methods(ccx: @crate_ctxt,
|
||||||
ms: [@ast::method],
|
ms: [@ast::method],
|
||||||
rp: ast::region_param,
|
rp: ast::region_param,
|
||||||
i_bounds: @[ty::param_bounds],
|
rcvr_bounds: @[ty::param_bounds],
|
||||||
self_ty: ty::t)
|
self_ty: ty::t) -> [converted_method] {
|
||||||
-> [{mty: ty::method, id: ast::node_id, span: span}] {
|
|
||||||
|
|
||||||
let tcx = ccx.tcx;
|
let tcx = ccx.tcx;
|
||||||
vec::map(ms) { |m|
|
vec::map(ms) { |m|
|
||||||
@ -289,9 +288,10 @@ fn convert_methods(ccx: @crate_ctxt,
|
|||||||
let fty = ty::mk_fn(tcx, mty.fty);
|
let fty = ty::mk_fn(tcx, mty.fty);
|
||||||
tcx.tcache.insert(
|
tcx.tcache.insert(
|
||||||
local_def(m.id),
|
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
|
// n.b.: the type of a method is parameterized by both
|
||||||
{bounds: @(*i_bounds + *bounds), rp: rp, ty: fty});
|
// 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);
|
write_ty_to_tcx(tcx, m.id, fty);
|
||||||
{mty: mty, id: m.id, span: m.span}
|
{mty: mty, id: m.id, span: m.span}
|
||||||
}
|
}
|
||||||
@ -316,19 +316,10 @@ fn convert(ccx: @crate_ctxt, it: @ast::item) {
|
|||||||
{bounds: i_bounds,
|
{bounds: i_bounds,
|
||||||
rp: rp,
|
rp: rp,
|
||||||
ty: selfty});
|
ty: selfty});
|
||||||
alt ifce {
|
|
||||||
some(t) {
|
let cms = convert_methods(ccx, ms, rp, i_bounds, selfty);
|
||||||
check_methods_against_iface(
|
for ifce.each { |t|
|
||||||
ccx, tps, rp,
|
check_methods_against_iface(ccx, tps, rp, selfty, t, cms);
|
||||||
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) {
|
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|
|
for fields.each {|f|
|
||||||
convert_class_item(ccx, rp, tpt.bounds, 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);
|
let selfty = ty::mk_class(tcx, local_def(it.id), substs);
|
||||||
// Need to convert all methods so we can check internal
|
let cms = convert_methods(ccx, methods, rp, bounds, selfty);
|
||||||
// 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|
|
for ifaces.each { |ifce|
|
||||||
check_methods_against_iface(ccx, tps, rp, selfty,
|
check_methods_against_iface(ccx, tps, rp, selfty, ifce, cms);
|
||||||
ifce, methods);
|
|
||||||
|
|
||||||
// FIXME #2434---this is somewhat bogus, but it seems that
|
// FIXME #2434---this is somewhat bogus, but it seems that
|
||||||
// the id of iface_ref is also the id of the impl, and so
|
// 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)
|
// xfail-fast (compile-flags unsupported on windows)
|
||||||
// compile-flags:--borrowck=err
|
// compile-flags:--borrowck=err
|
||||||
// exec-env:RUST_POISON_ON_FREE=1
|
// exec-env:RUST_POISON_ON_FREE=1
|
||||||
|
@ -1,5 +1,3 @@
|
|||||||
// xfail-test
|
|
||||||
// xfail-fast
|
|
||||||
use std;
|
use std;
|
||||||
import std::map::*;
|
import std::map::*;
|
||||||
|
|
||||||
@ -59,7 +57,7 @@ class cat<T: copy> implements map<int, T> {
|
|||||||
}
|
}
|
||||||
else { none }
|
else { none }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn remove(&&k:int) -> option<T> {
|
fn remove(&&k:int) -> option<T> {
|
||||||
alt self.find(k) {
|
alt self.find(k) {
|
||||||
some(x) {
|
some(x) {
|
||||||
@ -76,7 +74,7 @@ class cat<T: copy> implements map<int, T> {
|
|||||||
n -= 1;
|
n -= 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn each_key(&&f: fn(&&int) -> bool) {
|
fn each_key(&&f: fn(&&int) -> bool) {
|
||||||
for self.each {|k, _v| if !f(k) { break; } cont;};
|
for self.each {|k, _v| if !f(k) { break; } cont;};
|
||||||
}
|
}
|
||||||
@ -88,11 +86,11 @@ class cat<T: copy> implements map<int, T> {
|
|||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let nyan : cat<str> = cat(0, 2, "nyan");
|
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(1) == some("nyan"));
|
||||||
assert(nyan.find(10) == none);
|
assert(nyan.find(10) == none);
|
||||||
let spotty : cat<cat_type> = cat(2, 57, tuxedo);
|
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.size() == 8u);
|
||||||
assert(spotty.contains_key(2));
|
assert(spotty.contains_key(2));
|
||||||
assert(spotty.get(3) == tuxedo);
|
assert(spotty.get(3) == tuxedo);
|
||||||
|
@ -1,5 +1,3 @@
|
|||||||
// xfail-test
|
|
||||||
|
|
||||||
// xfail-fast
|
// xfail-fast
|
||||||
// aux-build:cci_class_6.rs
|
// aux-build:cci_class_6.rs
|
||||||
use cci_class_6;
|
use cci_class_6;
|
||||||
|
@ -1,5 +1,3 @@
|
|||||||
// xfail-test
|
|
||||||
// needs metadata encoding on Windows
|
|
||||||
class cat<U> {
|
class cat<U> {
|
||||||
priv {
|
priv {
|
||||||
let mut meows : uint;
|
let mut meows : uint;
|
||||||
|
Loading…
Reference in New Issue
Block a user