about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--crates/hir-ty/src/method_resolution.rs73
-rw-r--r--crates/hir-ty/src/tests/method_resolution.rs34
2 files changed, 94 insertions, 13 deletions
diff --git a/crates/hir-ty/src/method_resolution.rs b/crates/hir-ty/src/method_resolution.rs
index 9a63d5013b4..dbf27500320 100644
--- a/crates/hir-ty/src/method_resolution.rs
+++ b/crates/hir-ty/src/method_resolution.rs
@@ -914,22 +914,10 @@ 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(|| {
-            env.traits_in_scope_from_clauses(self_ty.clone())
-                .flat_map(|t| all_super_traits(db.upcast(), t))
-        })
-        .into_iter()
-        .flatten();
-    let traits = inherent_trait.chain(env_traits).chain(traits_in_scope.iter().copied());
 
     let canonical_self_ty = table.canonicalize(self_ty.clone()).value;
 
-    'traits: for t in traits {
+    'traits: for &t in traits_in_scope {
         let data = db.trait_data(t);
 
         // Traits annotated with `#[rustc_skip_array_during_method_dispatch]` are skipped during
@@ -979,6 +967,43 @@ fn iterate_inherent_methods(
 ) -> ControlFlow<()> {
     let db = table.db;
     let env = table.trait_env.clone();
+
+    // For trait object types and placeholder types with trait bounds, the methods of the trait and
+    // its super traits are considered inherent methods. This matters because these methods have
+    // higher priority than the other traits' methods, which would be considered in
+    // `iterate_trait_method_candidates()` only after this function.
+    match self_ty.kind(Interner) {
+        TyKind::Placeholder(_) => {
+            let env = table.trait_env.clone();
+            let traits = env
+                .traits_in_scope_from_clauses(self_ty.clone())
+                .flat_map(|t| all_super_traits(db.upcast(), t));
+            iterate_inherent_trait_methods(
+                self_ty,
+                table,
+                name,
+                receiver_ty,
+                receiver_adjustments.clone(),
+                callback,
+                traits,
+            )?;
+        }
+        TyKind::Dyn(_) => {
+            let principal_trait = self_ty.dyn_trait().unwrap();
+            let traits = all_super_traits(db.upcast(), principal_trait);
+            iterate_inherent_trait_methods(
+                self_ty,
+                table,
+                name,
+                receiver_ty,
+                receiver_adjustments.clone(),
+                callback,
+                traits.into_iter(),
+            )?;
+        }
+        _ => {}
+    }
+
     let def_crates = match def_crates(db, self_ty, env.krate) {
         Some(k) => k,
         None => return ControlFlow::Continue(()),
@@ -1020,6 +1045,28 @@ fn iterate_inherent_methods(
     }
     return ControlFlow::Continue(());
 
+    fn iterate_inherent_trait_methods(
+        self_ty: &Ty,
+        table: &mut InferenceTable<'_>,
+        name: Option<&Name>,
+        receiver_ty: Option<&Ty>,
+        receiver_adjustments: Option<ReceiverAdjustments>,
+        callback: &mut dyn FnMut(ReceiverAdjustments, AssocItemId) -> ControlFlow<()>,
+        traits: impl Iterator<Item = TraitId>,
+    ) -> ControlFlow<()> {
+        let db = table.db;
+        for t in 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.
+                if is_valid_candidate(table, name, receiver_ty, item, self_ty, None) {
+                    callback(receiver_adjustments.clone().unwrap_or_default(), item)?;
+                }
+            }
+        }
+        ControlFlow::Continue(())
+    }
+
     fn impls_for_self_ty(
         impls: &InherentImpls,
         self_ty: &Ty,
diff --git a/crates/hir-ty/src/tests/method_resolution.rs b/crates/hir-ty/src/tests/method_resolution.rs
index 81588a7c4ff..ac8edb841a5 100644
--- a/crates/hir-ty/src/tests/method_resolution.rs
+++ b/crates/hir-ty/src/tests/method_resolution.rs
@@ -1219,6 +1219,40 @@ 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 trait_method_priority_for_placeholder_type() {
+    check_types(
+        r#"
+//- minicore: from
+trait Trait {
+    fn into(&self) -> usize { 0 }
+}
+
+fn foo<T: Trait>(a: &T) {
+    let _ = a.into();
+      //^usize
+}
+        "#,
+    );
+}
+
+#[test]
 fn autoderef_visibility_field() {
     check(
         r#"