Skip to content

Commit 484d5b6

Browse files
committed
fix: handle trait methods as inherent methods for placeholders
1 parent f9e2ac5 commit 484d5b6

File tree

2 files changed

+77
-27
lines changed

2 files changed

+77
-27
lines changed

crates/hir-ty/src/method_resolution.rs

+60-27
Original file line numberDiff line numberDiff line change
@@ -914,19 +914,10 @@ fn iterate_trait_method_candidates(
914914
let db = table.db;
915915
let env = table.trait_env.clone();
916916
let self_is_array = matches!(self_ty.kind(Interner), chalk_ir::TyKind::Array(..));
917-
let env_traits = matches!(self_ty.kind(Interner), TyKind::Placeholder(_))
918-
// if we have `T: Trait` in the param env, the trait doesn't need to be in scope
919-
.then(|| {
920-
env.traits_in_scope_from_clauses(self_ty.clone())
921-
.flat_map(|t| all_super_traits(db.upcast(), t))
922-
})
923-
.into_iter()
924-
.flatten();
925-
let traits = env_traits.chain(traits_in_scope.iter().copied());
926917

927918
let canonical_self_ty = table.canonicalize(self_ty.clone()).value;
928919

929-
'traits: for t in traits {
920+
'traits: for &t in traits_in_scope {
930921
let data = db.trait_data(t);
931922

932923
// Traits annotated with `#[rustc_skip_array_during_method_dispatch]` are skipped during
@@ -976,6 +967,43 @@ fn iterate_inherent_methods(
976967
) -> ControlFlow<()> {
977968
let db = table.db;
978969
let env = table.trait_env.clone();
970+
971+
// For trait object types and placeholder types with trait bounds, the methods of the trait and
972+
// its super traits are considered inherent methods. This matters because these methods have
973+
// higher priority than the other traits' methods, which would be considered in
974+
// `iterate_trait_method_candidates()` only after this function.
975+
match self_ty.kind(Interner) {
976+
TyKind::Placeholder(_) => {
977+
let env = table.trait_env.clone();
978+
let traits = env
979+
.traits_in_scope_from_clauses(self_ty.clone())
980+
.flat_map(|t| all_super_traits(db.upcast(), t));
981+
iterate_inherent_trait_methods(
982+
self_ty,
983+
table,
984+
name,
985+
receiver_ty,
986+
receiver_adjustments.clone(),
987+
callback,
988+
traits,
989+
)?;
990+
}
991+
TyKind::Dyn(_) => {
992+
let principal_trait = self_ty.dyn_trait().unwrap();
993+
let traits = all_super_traits(db.upcast(), principal_trait);
994+
iterate_inherent_trait_methods(
995+
self_ty,
996+
table,
997+
name,
998+
receiver_ty,
999+
receiver_adjustments.clone(),
1000+
callback,
1001+
traits.into_iter(),
1002+
)?;
1003+
}
1004+
_ => {}
1005+
}
1006+
9791007
let def_crates = match def_crates(db, self_ty, env.krate) {
9801008
Some(k) => k,
9811009
None => return ControlFlow::Continue(()),
@@ -987,23 +1015,6 @@ fn iterate_inherent_methods(
9871015
VisibleFromModule::None => (None, None),
9881016
};
9891017

990-
// For trait object types, methods of the trait and its super traits are considered inherent
991-
// methods. This matters because these trait methods have higher priority than the other
992-
// traits' methods, which would be considered in `iterate_trait_method_candidates()` after this
993-
// function.
994-
let inherent_traits =
995-
self_ty.dyn_trait().into_iter().flat_map(|t| all_super_traits(db.upcast(), t));
996-
for t in inherent_traits {
997-
let data = db.trait_data(t);
998-
for &(_, item) in data.items.iter() {
999-
// We don't pass `visible_from_module` as all trait items should be visible from the
1000-
// trait object.
1001-
if is_valid_candidate(table, name, receiver_ty, item, self_ty, None) {
1002-
callback(receiver_adjustments.clone().unwrap_or_default(), item)?;
1003-
}
1004-
}
1005-
}
1006-
10071018
if let Some(block_id) = block {
10081019
if let Some(impls) = db.inherent_impls_in_block(block_id) {
10091020
impls_for_self_ty(
@@ -1034,6 +1045,28 @@ fn iterate_inherent_methods(
10341045
}
10351046
return ControlFlow::Continue(());
10361047

1048+
fn iterate_inherent_trait_methods(
1049+
self_ty: &Ty,
1050+
table: &mut InferenceTable<'_>,
1051+
name: Option<&Name>,
1052+
receiver_ty: Option<&Ty>,
1053+
receiver_adjustments: Option<ReceiverAdjustments>,
1054+
callback: &mut dyn FnMut(ReceiverAdjustments, AssocItemId) -> ControlFlow<()>,
1055+
traits: impl Iterator<Item = TraitId>,
1056+
) -> ControlFlow<()> {
1057+
let db = table.db;
1058+
for t in traits {
1059+
let data = db.trait_data(t);
1060+
for &(_, item) in data.items.iter() {
1061+
// We don't pass `visible_from_module` as all trait items should be visible.
1062+
if is_valid_candidate(table, name, receiver_ty, item, self_ty, None) {
1063+
callback(receiver_adjustments.clone().unwrap_or_default(), item)?;
1064+
}
1065+
}
1066+
}
1067+
ControlFlow::Continue(())
1068+
}
1069+
10371070
fn impls_for_self_ty(
10381071
impls: &InherentImpls,
10391072
self_ty: &Ty,

crates/hir-ty/src/tests/method_resolution.rs

+17
Original file line numberDiff line numberDiff line change
@@ -1235,6 +1235,23 @@ fn foo(a: &dyn Trait) {
12351235
);
12361236
}
12371237

1238+
#[test]
1239+
fn trait_method_priority_for_placeholder_type() {
1240+
check_types(
1241+
r#"
1242+
//- minicore: from
1243+
trait Trait {
1244+
fn into(&self) -> usize { 0 }
1245+
}
1246+
1247+
fn foo<T: Trait>(a: &T) {
1248+
let _ = a.into();
1249+
//^usize
1250+
}
1251+
"#,
1252+
);
1253+
}
1254+
12381255
#[test]
12391256
fn autoderef_visibility_field() {
12401257
check(

0 commit comments

Comments
 (0)