rustc: Stop overwriting trait static method types when checking generic trait refs. Closes #3903. rs=blocking-burg
This commit is contained in:
parent
3d8df9947f
commit
94f05c1936
@ -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); }
|
||||
|
@ -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) => {
|
||||
|
32
src/test/run-pass/trait-static-method-overwriting.rs
Normal file
32
src/test/run-pass/trait-static-method-overwriting.rs
Normal 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>();
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user