diff options
| author | Ryo Yoshida <low.ryoshida@gmail.com> | 2022-08-30 20:10:59 +0900 |
|---|---|---|
| committer | Ryo Yoshida <low.ryoshida@gmail.com> | 2022-08-30 20:44:31 +0900 |
| commit | f9e2ac56e56cd011929b28d20edda8bed33e9a76 (patch) | |
| tree | 8cc5787a9f3554b9417ff05887a96674631cdc1b | |
| parent | f02cd0a41d7381b1ef454b0141adacc188d3eee8 (diff) | |
| download | rust-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.rs | 22 | ||||
| -rw-r--r-- | crates/hir-ty/src/tests/method_resolution.rs | 17 |
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#" |
