about summary refs log tree commit diff
diff options
context:
space:
mode:
authorRyo Yoshida <low.ryoshida@gmail.com>2022-08-30 20:10:59 +0900
committerRyo Yoshida <low.ryoshida@gmail.com>2022-08-30 20:44:31 +0900
commitf9e2ac56e56cd011929b28d20edda8bed33e9a76 (patch)
tree8cc5787a9f3554b9417ff05887a96674631cdc1b
parentf02cd0a41d7381b1ef454b0141adacc188d3eee8 (diff)
downloadrust-f9e2ac56e56cd011929b28d20edda8bed33e9a76.tar.gz
rust-f9e2ac56e56cd011929b28d20edda8bed33e9a76.zip
fix: handle trait methods as inherent methods for trait object types
-rw-r--r--crates/hir-ty/src/method_resolution.rs22
-rw-r--r--crates/hir-ty/src/tests/method_resolution.rs17
2 files changed, 35 insertions, 4 deletions
diff --git a/crates/hir-ty/src/method_resolution.rs b/crates/hir-ty/src/method_resolution.rs
index 9a63d5013b4..c0ef4b2a9dc 100644
--- a/crates/hir-ty/src/method_resolution.rs
+++ b/crates/hir-ty/src/method_resolution.rs
@@ -914,9 +914,6 @@ fn iterate_trait_method_candidates(
     let db = table.db;
     let env = table.trait_env.clone();
     let self_is_array = matches!(self_ty.kind(Interner), chalk_ir::TyKind::Array(..));
-    // if ty is `dyn Trait`, the trait doesn't need to be in scope
-    let inherent_trait =
-        self_ty.dyn_trait().into_iter().flat_map(|t| all_super_traits(db.upcast(), t));
     let env_traits = matches!(self_ty.kind(Interner), TyKind::Placeholder(_))
         // if we have `T: Trait` in the param env, the trait doesn't need to be in scope
         .then(|| {
@@ -925,7 +922,7 @@ fn iterate_trait_method_candidates(
         })
         .into_iter()
         .flatten();
-    let traits = inherent_trait.chain(env_traits).chain(traits_in_scope.iter().copied());
+    let traits = env_traits.chain(traits_in_scope.iter().copied());
 
     let canonical_self_ty = table.canonicalize(self_ty.clone()).value;
 
@@ -990,6 +987,23 @@ fn iterate_inherent_methods(
         VisibleFromModule::None => (None, None),
     };
 
+    // For trait object types, methods of the trait and its super traits are considered inherent
+    // methods. This matters because these trait methods have higher priority than the other
+    // traits' methods, which would be considered in `iterate_trait_method_candidates()` after this
+    // function.
+    let inherent_traits =
+        self_ty.dyn_trait().into_iter().flat_map(|t| all_super_traits(db.upcast(), t));
+    for t in inherent_traits {
+        let data = db.trait_data(t);
+        for &(_, item) in data.items.iter() {
+            // We don't pass `visible_from_module` as all trait items should be visible from the
+            // trait object.
+            if is_valid_candidate(table, name, receiver_ty, item, self_ty, None) {
+                callback(receiver_adjustments.clone().unwrap_or_default(), item)?;
+            }
+        }
+    }
+
     if let Some(block_id) = block {
         if let Some(impls) = db.inherent_impls_in_block(block_id) {
             impls_for_self_ty(
diff --git a/crates/hir-ty/src/tests/method_resolution.rs b/crates/hir-ty/src/tests/method_resolution.rs
index 81588a7c4ff..fb2fc9369a7 100644
--- a/crates/hir-ty/src/tests/method_resolution.rs
+++ b/crates/hir-ty/src/tests/method_resolution.rs
@@ -1219,6 +1219,23 @@ fn main() {
 }
 
 #[test]
+fn dyn_trait_method_priority() {
+    check_types(
+        r#"
+//- minicore: from
+trait Trait {
+    fn into(&self) -> usize { 0 }
+}
+
+fn foo(a: &dyn Trait) {
+    let _ = a.into();
+      //^usize
+}
+        "#,
+    );
+}
+
+#[test]
 fn autoderef_visibility_field() {
     check(
         r#"