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.rs | 48 |
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; |