Skip to content

Commit 7a704f2

Browse files
committed
Auto merge of #13147 - lowr:fix/dyn-ty-inherent-methods, r=Veykril
fix: handle trait methods as inherent methods for trait-related types Fixes #10677 When resolving methods for trait object types and placeholder types that are bounded by traits, we need to count the methods of the trait and its super traits as inherent methods. This matters because these trait methods have higher priority than the other traits' methods. Relevant code in rustc: [`assemble_inherent_candidates_from_object()`](https://github.com/rust-lang/rust/blob/0631ea5d73f4a3199c776687b12c20c50a91f0d2/compiler/rustc_typeck/src/check/method/probe.rs#L783-L792) for trait object types, [`assemble_inherent_candidates_from_param()`](https://github.com/rust-lang/rust/blob/0631ea5d73f4a3199c776687b12c20c50a91f0d2/compiler/rustc_typeck/src/check/method/probe.rs#L838-L847) for placeholder types. Notice the second arg of `push_candidate()` is `is_inherent`.
2 parents e38dfe5 + 484d5b6 commit 7a704f2

File tree

2 files changed

+94
-13
lines changed

2 files changed

+94
-13
lines changed

crates/hir-ty/src/method_resolution.rs

+60-13
Original file line numberDiff line numberDiff line change
@@ -914,22 +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-
// if ty is `dyn Trait`, the trait doesn't need to be in scope
918-
let inherent_trait =
919-
self_ty.dyn_trait().into_iter().flat_map(|t| all_super_traits(db.upcast(), t));
920-
let env_traits = matches!(self_ty.kind(Interner), TyKind::Placeholder(_))
921-
// if we have `T: Trait` in the param env, the trait doesn't need to be in scope
922-
.then(|| {
923-
env.traits_in_scope_from_clauses(self_ty.clone())
924-
.flat_map(|t| all_super_traits(db.upcast(), t))
925-
})
926-
.into_iter()
927-
.flatten();
928-
let traits = inherent_trait.chain(env_traits).chain(traits_in_scope.iter().copied());
929917

930918
let canonical_self_ty = table.canonicalize(self_ty.clone()).value;
931919

932-
'traits: for t in traits {
920+
'traits: for &t in traits_in_scope {
933921
let data = db.trait_data(t);
934922

935923
// Traits annotated with `#[rustc_skip_array_during_method_dispatch]` are skipped during
@@ -979,6 +967,43 @@ fn iterate_inherent_methods(
979967
) -> ControlFlow<()> {
980968
let db = table.db;
981969
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+
9821007
let def_crates = match def_crates(db, self_ty, env.krate) {
9831008
Some(k) => k,
9841009
None => return ControlFlow::Continue(()),
@@ -1020,6 +1045,28 @@ fn iterate_inherent_methods(
10201045
}
10211046
return ControlFlow::Continue(());
10221047

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+
10231070
fn impls_for_self_ty(
10241071
impls: &InherentImpls,
10251072
self_ty: &Ty,

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

+34
Original file line numberDiff line numberDiff line change
@@ -1218,6 +1218,40 @@ fn main() {
12181218
);
12191219
}
12201220

1221+
#[test]
1222+
fn dyn_trait_method_priority() {
1223+
check_types(
1224+
r#"
1225+
//- minicore: from
1226+
trait Trait {
1227+
fn into(&self) -> usize { 0 }
1228+
}
1229+
1230+
fn foo(a: &dyn Trait) {
1231+
let _ = a.into();
1232+
//^usize
1233+
}
1234+
"#,
1235+
);
1236+
}
1237+
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+
12211255
#[test]
12221256
fn autoderef_visibility_field() {
12231257
check(

0 commit comments

Comments
 (0)