rustc: Stop overwriting trait static method types when checking generic trait refs. Closes #3903. rs=blocking-burg

This commit is contained in:
Patrick Walton 2012-11-01 15:08:36 -07:00
parent 3d8df9947f
commit 94f05c1936
3 changed files with 66 additions and 6 deletions

View File

@ -100,6 +100,10 @@ fn lookup_vtable_covariant(fcx: @fn_ctxt,
allow_unsafe: bool,
is_early: bool)
-> Option<vtable_origin> {
debug!("lookup_vtable_covariant(ty: %s, trait_ty=%s)",
fcx.infcx().ty_to_str(ty),
fcx.infcx().ty_to_str(trait_ty));
let worklist = dvec::DVec();
worklist.push(trait_ty);
while worklist.len() > 0 {
@ -475,9 +479,16 @@ fn early_resolve_expr(ex: @ast::expr, &&fcx: @fn_ctxt, is_early: bool) {
ast::expr_path(*) => {
match fcx.opt_node_ty_substs(ex.id) {
Some(ref substs) => {
let did = ast_util::def_id_of_def(cx.tcx.def_map.get(ex.id));
let def = cx.tcx.def_map.get(ex.id);
let did = ast_util::def_id_of_def(def);
debug!("early resolve expr: def %?", def);
let item_ty = ty::lookup_item_type(cx.tcx, did);
if has_trait_bounds(*item_ty.bounds) {
for item_ty.bounds.each |bounds| {
debug!("early_resolve_expr: looking up vtables for bound \
%s",
ty::param_bounds_to_str(fcx.tcx(), *bounds));
}
let vtbls = lookup_vtables(fcx, ex, item_ty.bounds,
substs, false, is_early);
if !is_early { cx.vtable_map.insert(ex.id, vtbls); }

View File

@ -231,10 +231,11 @@ fn ensure_trait_methods(ccx: @crate_ctxt, id: ast::node_id, trait_ty: ty::t) {
let trait_bounds = ty_param_bounds(ccx, params);
let ty_m = trait_method_to_ty_method(*m);
let method_ty = ty_of_ty_method(ccx, ty_m, region_paramd, def_id);
if ty_m.self_ty.node == ast::sty_static {
make_static_method_ty(ccx, ty_m, region_paramd,
method_ty, trait_ty, trait_bounds);
}
if ty_m.self_ty.node == ast::sty_static {
make_static_method_ty(ccx, ty_m, region_paramd,
method_ty, trait_ty,
trait_bounds);
}
method_ty
});
}
@ -420,9 +421,25 @@ fn check_methods_against_trait(ccx: @crate_ctxt,
let tcx = ccx.tcx;
let (did, tpt) = instantiate_trait_ref(ccx, a_trait_ty, rp);
if did.crate == ast::local_crate {
ensure_trait_methods(ccx, did.node, tpt.ty);
// NB: This is subtle. We need to do this on the type of the trait
// item *itself*, not on the type that includes the parameter
// substitutions provided by the programmer at this particular
// trait ref. Otherwise, we will potentially overwrite the types of
// the methods within the trait with bogus results. (See issue #3903.)
match tcx.items.find(did.node) {
Some(ast_map::node_item(item, _)) => {
let tpt = ty_of_item(ccx, item);
ensure_trait_methods(ccx, did.node, tpt.ty);
}
_ => {
tcx.sess.bug(~"trait ref didn't resolve to trait");
}
}
}
for vec::each(*ty::trait_methods(tcx, did)) |trait_m| {
match vec::find(impl_ms, |impl_m| trait_m.ident == impl_m.mty.ident) {
Some(ref cm) => {

View File

@ -0,0 +1,32 @@
mod base {
pub trait HasNew<T> {
static pure fn new() -> T;
}
pub struct Foo {
dummy: (),
}
pub impl Foo : base::HasNew<Foo> {
static pure fn new() -> Foo {
unsafe { io::println("Foo"); }
Foo { dummy: () }
}
}
pub struct Bar {
dummy: (),
}
pub impl Bar : base::HasNew<Bar> {
static pure fn new() -> Bar {
unsafe { io::println("Bar"); }
Bar { dummy: () }
}
}
}
fn main() {
let f: base::Foo = base::new::<base::Foo, base::Foo>();
let b: base::Bar = base::new::<base::Bar, base::Bar>();
}