]> git.lizzy.rs Git - rust.git/commitdiff
Call default methods on bound typarams more correctly
authorBrian Anderson <banderson@mozilla.com>
Mon, 3 Dec 2012 02:29:22 +0000 (18:29 -0800)
committerBrian Anderson <banderson@mozilla.com>
Mon, 3 Dec 2012 02:29:22 +0000 (18:29 -0800)
src/librustc/middle/trans/meth.rs
src/librustc/middle/ty.rs
src/librustc/middle/typeck/check/method.rs
src/librustc/middle/typeck/coherence.rs
src/librustc/middle/typeck/mod.rs
src/test/run-pass/trait-default-method-bound-subst.rs [new file with mode: 0644]
src/test/run-pass/trait-default-method-bound-subst2.rs [new file with mode: 0644]
src/test/run-pass/trait-default-method-bound-subst3.rs [new file with mode: 0644]
src/test/run-pass/trait-default-method-bound-subst4.rs [new file with mode: 0644]
src/test/run-pass/trait-default-method-bound.rs [new file with mode: 0644]

index ba6ec2a44c99e4c7dd9892437dc852479fa6c4dd..1943bbfc4aea1c83ac10c2c8bc98a31180b25a5d 100644 (file)
@@ -294,8 +294,8 @@ fn trans_static_method_callee(bcx: block,
 }
 
 fn method_from_methods(ms: ~[@ast::method], name: ast::ident)
-    -> ast::def_id {
-  local_def(option::get(vec::find(ms, |m| m.ident == name)).id)
+    -> Option<ast::def_id> {
+    ms.find(|m| m.ident == name).map(|m| local_def(m.id))
 }
 
 fn method_with_name(ccx: @crate_ctxt, impl_id: ast::def_id,
@@ -303,11 +303,43 @@ fn method_with_name(ccx: @crate_ctxt, impl_id: ast::def_id,
     if impl_id.crate == ast::local_crate {
         match ccx.tcx.items.get(impl_id.node) {
           ast_map::node_item(@{node: ast::item_impl(_, _, _, ms), _}, _) => {
-            method_from_methods(ms, name)
+            method_from_methods(ms, name).get()
           }
           ast_map::node_item(@{node:
               ast::item_class(struct_def, _), _}, _) => {
-            method_from_methods(struct_def.methods, name)
+            method_from_methods(struct_def.methods, name).get()
+          }
+          _ => fail ~"method_with_name"
+        }
+    } else {
+        csearch::get_impl_method(ccx.sess.cstore, impl_id, name)
+    }
+}
+
+fn method_with_name_or_default(ccx: @crate_ctxt, impl_id: ast::def_id,
+                               name: ast::ident) -> ast::def_id {
+    if impl_id.crate == ast::local_crate {
+        match ccx.tcx.items.get(impl_id.node) {
+          ast_map::node_item(@{node: ast::item_impl(_, _, _, ms), _}, _) => {
+              let did = method_from_methods(ms, name);
+              if did.is_some() {
+                  return did.get();
+              } else {
+                  // Look for a default method
+                  let pmm = ccx.tcx.provided_methods;
+                  match pmm.find(impl_id) {
+                      Some(pmis) => {
+                          for pmis.each |pmi| {
+                              if pmi.method_info.ident == name {
+                                  debug!("XXX %?", pmi.method_info.did);
+                                  return pmi.method_info.did;
+                              }
+                          }
+                          fail
+                      }
+                      None => fail
+                  }
+              }
           }
           _ => fail ~"method_with_name"
         }
@@ -318,10 +350,22 @@ fn method_with_name(ccx: @crate_ctxt, impl_id: ast::def_id,
 
 fn method_ty_param_count(ccx: @crate_ctxt, m_id: ast::def_id,
                          i_id: ast::def_id) -> uint {
+    debug!("mythod_ty_param_count: m_id: %?, i_id: %?", m_id, i_id);
     if m_id.crate == ast::local_crate {
-        match ccx.tcx.items.get(m_id.node) {
-          ast_map::node_method(m, _, _) => vec::len(m.tps),
-          _ => fail ~"method_ty_param_count"
+        match ccx.tcx.items.find(m_id.node) {
+            Some(ast_map::node_method(m, _, _)) => m.tps.len(),
+            None => {
+                match ccx.tcx.provided_method_sources.find(m_id) {
+                    Some(source) => {
+                        method_ty_param_count(ccx, source.method_id, source.impl_id)
+                    }
+                    None => fail
+                }
+            }
+            Some(ast_map::node_trait_method(@ast::provided(@m), _, _)) => {
+                m.tps.len()
+            }
+            e => fail fmt!("method_ty_param_count %?", e)
         }
     } else {
         csearch::get_type_param_count(ccx.sess.cstore, m_id) -
@@ -343,7 +387,8 @@ fn trans_monomorphized_callee(bcx: block,
       typeck::vtable_static(impl_did, rcvr_substs, rcvr_origins) => {
           let ccx = bcx.ccx();
           let mname = ty::trait_methods(ccx.tcx, trait_id)[n_method].ident;
-          let mth_id = method_with_name(bcx.ccx(), impl_did, mname);
+          let mth_id = method_with_name_or_default(
+              bcx.ccx(), impl_did, mname);
 
           // obtain the `self` value:
           let Result {bcx, val: llself_val} =
index cd70f7b19586d939bcd3ba1a770db42adf09a51a..725d3bc37f5606fb9ce291d513a241d9617f7058 100644 (file)
@@ -1,5 +1,6 @@
 #[warn(deprecated_pattern)];
 
+use core::dvec::DVec;
 use std::{map, smallintmap};
 use result::Result;
 use std::map::HashMap;
 use syntax::ast::*;
 use syntax::print::pprust::*;
 use util::ppaux::{ty_to_str, proto_ty_to_str, tys_to_str};
+use middle::resolve::{Impl, MethodInfo};
 
 export ProvidedMethodSource;
+export ProvidedMethodInfo;
+export ProvidedMethodsMap;
 export InstantiatedTraitRef;
 export TyVid, IntVid, FloatVid, FnVid, RegionVid, vid;
 export br_hashmap;
@@ -331,6 +335,21 @@ enum AutoRefKind {
     AutoBorrowFn,
 }
 
+// Stores information about provided methods (a.k.a. default methods) in
+// implementations.
+//
+// This is a map from ID of each implementation to the method info and trait
+// method ID of each of the default methods belonging to the trait that that
+// implementation implements.
+type ProvidedMethodsMap = HashMap<def_id,@DVec<@ProvidedMethodInfo>>;
+
+// Stores the method info and definition ID of the associated trait method for
+// each instantiation of each provided method.
+struct ProvidedMethodInfo {
+    method_info: @MethodInfo,
+    trait_method_def_id: def_id
+}
+
 struct ProvidedMethodSource {
     method_id: ast::def_id,
     impl_id: ast::def_id
@@ -395,6 +414,10 @@ struct DerivedFieldInfo {
       normalized_cache: HashMap<t, t>,
       lang_items: middle::lang_items::LanguageItems,
       legacy_boxed_traits: HashMap<node_id, ()>,
+      // A mapping from an implementation ID to the method info and trait method
+      // ID of the provided (a.k.a. default) methods in the traits that that
+      // implementation implements.
+      provided_methods: ProvidedMethodsMap,
       provided_method_sources: HashMap<ast::def_id, ProvidedMethodSource>,
       supertraits: HashMap<ast::def_id, @~[InstantiatedTraitRef]>,
       deriving_struct_methods: HashMap<ast::def_id, @~[DerivedFieldInfo]>,
@@ -951,6 +974,7 @@ fn mk_ctxt(s: session::Session,
       normalized_cache: new_ty_hash(),
       lang_items: move lang_items,
       legacy_boxed_traits: HashMap(),
+      provided_methods: HashMap(),
       provided_method_sources: HashMap(),
       supertraits: HashMap(),
       deriving_struct_methods: HashMap(),
index b4f5441c981a79509ca9f14fad5914441a1740fb..ff0128e34b704e05c80511068cc0dba553ceb914 100644 (file)
@@ -69,7 +69,7 @@ trait `ToStr` imported, and I call `to_str()` on a value of type `T`,
 
 */
 
-use coherence::{ProvidedMethodInfo, get_base_type_def_id};
+use coherence::get_base_type_def_id;
 use middle::resolve::{Impl, MethodInfo};
 use middle::ty::*;
 use syntax::ast::{def_id, sty_by_ref, sty_value, sty_region, sty_box,
@@ -293,7 +293,7 @@ fn push_extension_candidates(&self, self_ty: ty::t) {
                 }
 
                 // Look for default methods.
-                match coherence_info.provided_methods.find(*trait_did) {
+                match self.tcx().provided_methods.find(*trait_did) {
                     Some(methods) => {
                         self.push_candidates_from_provided_methods(
                             &self.extension_candidates, self_ty, *trait_did,
index d441f11959d07d0a0127f05584ab9ae36cfa1ab3..227fe245baae633bbafd1be214abcbcf2cdff050 100644 (file)
@@ -9,7 +9,7 @@
 use metadata::cstore::{CStore, iter_crate_data};
 use metadata::decoder::{dl_def, dl_field, dl_impl};
 use middle::resolve::{Impl, MethodInfo};
-use middle::ty::{DerivedMethodInfo, ProvidedMethodSource, get};
+use middle::ty::{DerivedMethodInfo, ProvidedMethodSource, ProvidedMethodInfo, get};
 use middle::ty::{lookup_item_type, subst, t, ty_bot, ty_box, ty_class};
 use middle::ty::{ty_bool, ty_enum, ty_int, ty_nil, ty_ptr, ty_rptr, ty_uint};
 use middle::ty::{ty_float, ty_estr, ty_evec, ty_rec, ty_uniq};
@@ -120,21 +120,6 @@ fn method_to_MethodInfo(ast_method: @method) -> @MethodInfo {
     }
 }
 
-// Stores the method info and definition ID of the associated trait method for
-// each instantiation of each provided method.
-struct ProvidedMethodInfo {
-    method_info: @MethodInfo,
-    trait_method_def_id: def_id
-}
-
-// Stores information about provided methods (a.k.a. default methods) in
-// implementations.
-//
-// This is a map from ID of each implementation to the method info and trait
-// method ID of each of the default methods belonging to the trait that that
-// implementation implements.
-type ProvidedMethodsMap = HashMap<def_id,@DVec<@ProvidedMethodInfo>>;
-
 struct CoherenceInfo {
     // Contains implementations of methods that are inherent to a type.
     // Methods in these implementations don't need to be exported.
@@ -144,17 +129,12 @@ struct CoherenceInfo {
     // the associated trait must be imported at the call site.
     extension_methods: HashMap<def_id,@DVec<@Impl>>,
 
-    // A mapping from an implementation ID to the method info and trait method
-    // ID of the provided (a.k.a. default) methods in the traits that that
-    // implementation implements.
-    provided_methods: ProvidedMethodsMap,
 }
 
 fn CoherenceInfo() -> CoherenceInfo {
     CoherenceInfo {
         inherent_methods: HashMap(),
         extension_methods: HashMap(),
-        provided_methods: HashMap(),
     }
 }
 
@@ -340,7 +320,7 @@ fn instantiate_default_methods(impl_id: ast::node_id,
                     trait_method_def_id: trait_method.def_id
                 };
 
-            let pmm = self.crate_context.coherence_info.provided_methods;
+            let pmm = self.crate_context.tcx.provided_methods;
             match pmm.find(local_def(impl_id)) {
                 Some(mis) => {
                     // If the trait already has an entry in the
@@ -755,8 +735,7 @@ fn add_provided_methods(all_methods: &mut ~[@MethodInfo],
                     let trait_did =
                         self.trait_ref_to_trait_def_id(*trait_ref);
 
-                    match self.crate_context
-                              .coherence_info
+                    match self.crate_context.tcx
                               .provided_methods
                               .find(local_def(item.id)) {
                         None => {
@@ -915,7 +894,7 @@ fn add_impls_for_module(impls_seen: HashMap<def_id,()>,
 
     fn add_default_methods_for_external_trait(trait_def_id: ast::def_id) {
         let tcx = self.crate_context.tcx;
-        let pmm = self.crate_context.coherence_info.provided_methods;
+        let pmm = tcx.provided_methods;
 
         if pmm.contains_key(trait_def_id) { return; }
 
index eb82b95389da1dc8ff2d8bbce509a04c5fe3bc3e..044b04188475b3f9121cb08e7daed695a041f127 100644 (file)
@@ -78,6 +78,7 @@
 export method_static, method_param, method_trait, method_self;
 export vtable_static, vtable_param, vtable_trait;
 export provided_methods_map;
+export coherence;
 
 #[legacy_exports]
 #[path = "check/mod.rs"]
@@ -367,7 +368,7 @@ fn check_for_main_fn(ccx: @crate_ctxt) {
 fn check_crate(tcx: ty::ctxt,
                trait_map: resolve::TraitMap,
                crate: @ast::crate)
-            -> (method_map, vtable_map) {
+    -> (method_map, vtable_map) {
 
     let ccx = @crate_ctxt_({trait_map: trait_map,
                             method_map: std::map::HashMap(),
diff --git a/src/test/run-pass/trait-default-method-bound-subst.rs b/src/test/run-pass/trait-default-method-bound-subst.rs
new file mode 100644 (file)
index 0000000..9fbb356
--- /dev/null
@@ -0,0 +1,15 @@
+// xfail-test
+
+trait A<T> {
+    fn g<U>(x: T, y: U) -> (T, U) { (move x, move y) }
+}
+
+impl int: A<int> { }
+
+fn f<T, U, V: A<T>>(i: V, j: T, k: U) -> (T, U) {
+    i.g(move j, move k)
+}
+
+fn main () {
+    assert f(0, 1, 2) == (1, 2);
+}
diff --git a/src/test/run-pass/trait-default-method-bound-subst2.rs b/src/test/run-pass/trait-default-method-bound-subst2.rs
new file mode 100644 (file)
index 0000000..1cc35b8
--- /dev/null
@@ -0,0 +1,15 @@
+// xfail-test
+
+trait A<T> {
+    fn g(x: T) -> T { move x }
+}
+
+impl int: A<int> { }
+
+fn f<T, V: A<T>>(i: V, j: T) -> T {
+    i.g(move j)
+}
+
+fn main () {
+    assert f(0, 2) == 2;
+}
diff --git a/src/test/run-pass/trait-default-method-bound-subst3.rs b/src/test/run-pass/trait-default-method-bound-subst3.rs
new file mode 100644 (file)
index 0000000..dafee14
--- /dev/null
@@ -0,0 +1,14 @@
+trait A {
+    fn g<T>(x: T, y: T) -> (T, T) { (move x, move y) }
+}
+
+impl int: A { }
+
+fn f<T, V: A>(i: V, j: T, k: T) -> (T, T) {
+    i.g(move j, move k)
+}
+
+fn main () {
+    assert f(0, 1, 2) == (1, 2);
+    assert f(0, 1u8, 2u8) == (1u8, 2u8);
+}
diff --git a/src/test/run-pass/trait-default-method-bound-subst4.rs b/src/test/run-pass/trait-default-method-bound-subst4.rs
new file mode 100644 (file)
index 0000000..eeeefd0
--- /dev/null
@@ -0,0 +1,14 @@
+trait A<T> {
+    fn g(x: uint) -> uint { move x }
+}
+
+impl<T> int: A<T> { }
+
+fn f<T, V: A<T>>(i: V, j: uint) -> uint {
+    i.g(move j)
+}
+
+fn main () {
+    assert f::<float, int>(0, 2u) == 2u;
+    assert f::<uint, int>(0, 2u) == 2u;
+}
diff --git a/src/test/run-pass/trait-default-method-bound.rs b/src/test/run-pass/trait-default-method-bound.rs
new file mode 100644 (file)
index 0000000..3d22a3f
--- /dev/null
@@ -0,0 +1,13 @@
+trait A {
+    fn g() -> int { 10 }
+}
+
+impl int: A { }
+
+fn f<T: A>(i: T) {
+    assert i.g() == 10;
+}
+
+fn main () {
+    f(0);
+}