Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/hir-ty/src/method_resolution.rs')
-rw-r--r--crates/hir-ty/src/method_resolution.rs48
1 files changed, 40 insertions, 8 deletions
diff --git a/crates/hir-ty/src/method_resolution.rs b/crates/hir-ty/src/method_resolution.rs
index f3a27632bf..2003d24038 100644
--- a/crates/hir-ty/src/method_resolution.rs
+++ b/crates/hir-ty/src/method_resolution.rs
@@ -5,7 +5,7 @@
use std::{ops::ControlFlow, sync::Arc};
use base_db::{CrateId, Edition};
-use chalk_ir::{cast::Cast, Mutability, TyKind, UniverseIndex};
+use chalk_ir::{cast::Cast, Mutability, TyKind, UniverseIndex, WhereClause};
use hir_def::{
data::ImplData, item_scope::ItemScope, lang_item::LangItem, nameres::DefMap, AssocItemId,
BlockId, ConstId, FunctionId, HasModule, ImplId, ItemContainerId, Lookup, ModuleDefId,
@@ -20,7 +20,7 @@ use crate::{
autoderef::{self, AutoderefKind},
db::HirDatabase,
from_chalk_trait_id, from_foreign_def_id,
- infer::{unify::InferenceTable, Adjust, Adjustment, AutoBorrow, OverloadedDeref, PointerCast},
+ infer::{unify::InferenceTable, Adjust, Adjustment, OverloadedDeref, PointerCast},
primitive::{FloatTy, IntTy, UintTy},
static_lifetime, to_chalk_trait_id,
utils::all_super_traits,
@@ -600,9 +600,9 @@ impl ReceiverAdjustments {
}
}
if let Some(m) = self.autoref {
- ty = TyKind::Ref(m, static_lifetime(), ty).intern(Interner);
- adjust
- .push(Adjustment { kind: Adjust::Borrow(AutoBorrow::Ref(m)), target: ty.clone() });
+ let a = Adjustment::borrow(m, ty);
+ ty = a.target.clone();
+ adjust.push(a);
}
if self.unsize_array {
ty = 'x: {
@@ -692,6 +692,39 @@ pub fn lookup_impl_const(
.unwrap_or((const_id, subs))
}
+/// Checks if the self parameter of `Trait` method is the `dyn Trait` and we should
+/// call the method using the vtable.
+pub fn is_dyn_method(
+ db: &dyn HirDatabase,
+ _env: Arc<TraitEnvironment>,
+ func: FunctionId,
+ fn_subst: Substitution,
+) -> Option<usize> {
+ let ItemContainerId::TraitId(trait_id) = func.lookup(db.upcast()).container else {
+ return None;
+ };
+ let trait_params = db.generic_params(trait_id.into()).type_or_consts.len();
+ let fn_params = fn_subst.len(Interner) - trait_params;
+ let trait_ref = TraitRef {
+ trait_id: to_chalk_trait_id(trait_id),
+ substitution: Substitution::from_iter(Interner, fn_subst.iter(Interner).skip(fn_params)),
+ };
+ let self_ty = trait_ref.self_type_parameter(Interner);
+ if let TyKind::Dyn(d) = self_ty.kind(Interner) {
+ let is_my_trait_in_bounds =
+ d.bounds.skip_binders().as_slice(Interner).iter().any(|x| match x.skip_binders() {
+ // rustc doesn't accept `impl Foo<2> for dyn Foo<5>`, so if the trait id is equal, no matter
+ // what the generics are, we are sure that the method is come from the vtable.
+ WhereClause::Implemented(tr) => tr.trait_id == trait_ref.trait_id,
+ _ => false,
+ });
+ if is_my_trait_in_bounds {
+ return Some(fn_params);
+ }
+ }
+ None
+}
+
/// Looks up the impl method that actually runs for the trait method `func`.
///
/// Returns `func` if it's not a method defined in a trait or the lookup failed.
@@ -701,9 +734,8 @@ pub fn lookup_impl_method(
func: FunctionId,
fn_subst: Substitution,
) -> (FunctionId, Substitution) {
- let trait_id = match func.lookup(db.upcast()).container {
- ItemContainerId::TraitId(id) => id,
- _ => return (func, fn_subst),
+ let ItemContainerId::TraitId(trait_id) = func.lookup(db.upcast()).container else {
+ return (func, fn_subst)
};
let trait_params = db.generic_params(trait_id.into()).type_or_consts.len();
let fn_params = fn_subst.len(Interner) - trait_params;