about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorPatrick Walton <pcwalton@mimiga.net>2012-11-01 15:08:36 -0700
committerPatrick Walton <pcwalton@mimiga.net>2012-11-01 15:10:41 -0700
commit94f05c1936e85d4805e7177fe546d4c6f40340d8 (patch)
tree06d3875f263ce585c99a3e031c2e284a8533fa28 /src
parent3d8df9947fae1c55a1de9b461ae142059c1edcac (diff)
downloadrust-94f05c1936e85d4805e7177fe546d4c6f40340d8.tar.gz
rust-94f05c1936e85d4805e7177fe546d4c6f40340d8.zip
rustc: Stop overwriting trait static method types when checking generic trait refs. Closes #3903. rs=blocking-burg
Diffstat (limited to 'src')
-rw-r--r--src/rustc/middle/typeck/check/vtable.rs13
-rw-r--r--src/rustc/middle/typeck/collect.rs27
-rw-r--r--src/test/run-pass/trait-static-method-overwriting.rs32
3 files changed, 66 insertions, 6 deletions
diff --git a/src/rustc/middle/typeck/check/vtable.rs b/src/rustc/middle/typeck/check/vtable.rs
index 85a65d7432f..bfd6d5a44e8 100644
--- a/src/rustc/middle/typeck/check/vtable.rs
+++ b/src/rustc/middle/typeck/check/vtable.rs
@@ -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); }
diff --git a/src/rustc/middle/typeck/collect.rs b/src/rustc/middle/typeck/collect.rs
index ed0cd48504b..ca12e355636 100644
--- a/src/rustc/middle/typeck/collect.rs
+++ b/src/rustc/middle/typeck/collect.rs
@@ -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) => {
diff --git a/src/test/run-pass/trait-static-method-overwriting.rs b/src/test/run-pass/trait-static-method-overwriting.rs
new file mode 100644
index 00000000000..a47e27d2451
--- /dev/null
+++ b/src/test/run-pass/trait-static-method-overwriting.rs
@@ -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>();
+}