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.rs124
1 files changed, 51 insertions, 73 deletions
diff --git a/crates/hir-ty/src/method_resolution.rs b/crates/hir-ty/src/method_resolution.rs
index 086abc9591..110fee824c 100644
--- a/crates/hir-ty/src/method_resolution.rs
+++ b/crates/hir-ty/src/method_resolution.rs
@@ -4,13 +4,12 @@
//! and the corresponding code mostly in rustc_hir_analysis/check/method/probe.rs.
use std::ops::ControlFlow;
-use arrayvec::ArrayVec;
use base_db::Crate;
use chalk_ir::{UniverseIndex, WithKind, cast::Cast};
use hir_def::{
AdtId, AssocItemId, BlockId, ConstId, FunctionId, HasModule, ImplId, ItemContainerId, Lookup,
ModuleId, TraitId, TypeAliasId,
- nameres::{DefMap, assoc::ImplItems, block_def_map, crate_def_map},
+ nameres::{DefMap, block_def_map, crate_def_map},
signatures::{ConstFlags, EnumFlags, FnFlags, StructFlags, TraitFlags, TypeAliasFlags},
};
use hir_expand::name::Name;
@@ -18,7 +17,7 @@ use intern::sym;
use rustc_ast_ir::Mutability;
use rustc_hash::{FxHashMap, FxHashSet};
use rustc_type_ir::{
- FloatTy, IntTy, UintTy,
+ FloatTy, IntTy, TypeVisitableExt, UintTy,
inherent::{
AdtDef, BoundExistentialPredicates, GenericArgs as _, IntoKind, SliceLike, Ty as _,
},
@@ -27,6 +26,8 @@ use smallvec::{SmallVec, smallvec};
use stdx::never;
use triomphe::Arc;
+use crate::next_solver::infer::InferCtxt;
+use crate::next_solver::infer::select::ImplSource;
use crate::{
CanonicalVarKinds, DebruijnIndex, GenericArgData, InEnvironment, Interner, TraitEnvironment,
TyBuilder, VariableKind,
@@ -36,10 +37,10 @@ use crate::{
lang_items::is_box,
next_solver::{
Canonical, DbInterner, ErrorGuaranteed, GenericArgs, Goal, Predicate, Region, SolverDefId,
- TraitRef, Ty, TyKind,
+ TraitRef, Ty, TyKind, TypingMode,
infer::{
- DefineOpaqueTypes,
- traits::{ObligationCause, PredicateObligation},
+ DbInternerInferExt, DefineOpaqueTypes,
+ traits::{Obligation, ObligationCause, PredicateObligation},
},
mapping::NextSolverToChalk,
obligation_ctxt::ObligationCtxt,
@@ -689,11 +690,12 @@ pub(crate) fn iterate_method_candidates<'db, T>(
}
pub fn lookup_impl_const<'db>(
- interner: DbInterner<'db>,
+ infcx: &InferCtxt<'db>,
env: Arc<TraitEnvironment<'db>>,
const_id: ConstId,
subs: GenericArgs<'db>,
) -> (ConstId, GenericArgs<'db>) {
+ let interner = infcx.interner;
let db = interner.db;
let trait_id = match const_id.lookup(db).container {
@@ -708,7 +710,7 @@ pub fn lookup_impl_const<'db>(
None => return (const_id, subs),
};
- lookup_impl_assoc_item_for_trait_ref(trait_ref, db, env, name)
+ lookup_impl_assoc_item_for_trait_ref(infcx, trait_ref, env, name)
.and_then(
|assoc| if let (AssocItemId::ConstId(id), s) = assoc { Some((id, s)) } else { None },
)
@@ -759,6 +761,7 @@ pub(crate) fn lookup_impl_method_query<'db>(
fn_subst: GenericArgs<'db>,
) -> (FunctionId, GenericArgs<'db>) {
let interner = DbInterner::new_with(db, Some(env.krate), env.block);
+ let infcx = interner.infer_ctxt().build(TypingMode::PostAnalysis);
let ItemContainerId::TraitId(trait_id) = func.lookup(db).container else {
return (func, fn_subst);
@@ -772,7 +775,7 @@ pub(crate) fn lookup_impl_method_query<'db>(
let name = &db.function_signature(func).name;
let Some((impl_fn, impl_subst)) =
- lookup_impl_assoc_item_for_trait_ref(trait_ref, db, env, name).and_then(|assoc| {
+ lookup_impl_assoc_item_for_trait_ref(&infcx, trait_ref, env, name).and_then(|assoc| {
if let (AssocItemId::FunctionId(id), subst) = assoc { Some((id, subst)) } else { None }
})
else {
@@ -789,78 +792,53 @@ pub(crate) fn lookup_impl_method_query<'db>(
}
fn lookup_impl_assoc_item_for_trait_ref<'db>(
+ infcx: &InferCtxt<'db>,
trait_ref: TraitRef<'db>,
- db: &'db dyn HirDatabase,
env: Arc<TraitEnvironment<'db>>,
name: &Name,
) -> Option<(AssocItemId, GenericArgs<'db>)> {
- let hir_trait_id = trait_ref.def_id.0;
- let self_ty = trait_ref.self_ty();
- let self_ty_fp = TyFingerprint::for_trait_impl(self_ty)?;
- let impls = db.trait_impls_in_deps(env.krate);
-
- let trait_module = hir_trait_id.module(db);
- let type_module = match self_ty_fp {
- TyFingerprint::Adt(adt_id) => Some(adt_id.module(db)),
- TyFingerprint::ForeignType(type_id) => Some(type_id.module(db)),
- TyFingerprint::Dyn(trait_id) => Some(trait_id.module(db)),
- _ => None,
- };
-
- let def_blocks: ArrayVec<_, 2> =
- [trait_module.containing_block(), type_module.and_then(|it| it.containing_block())]
- .into_iter()
- .flatten()
- .filter_map(|block_id| db.trait_impls_in_block(block_id))
- .collect();
-
- let impls = impls
- .iter()
- .chain(&def_blocks)
- .flat_map(|impls| impls.for_trait_and_self_ty(hir_trait_id, self_ty_fp));
-
- let table = InferenceTable::new(db, env);
-
- let (impl_data, impl_subst) = find_matching_impl(impls, table, trait_ref)?;
- let item = impl_data.items.iter().find_map(|(n, it)| match *it {
- AssocItemId::FunctionId(f) => (n == name).then_some(AssocItemId::FunctionId(f)),
- AssocItemId::ConstId(c) => (n == name).then_some(AssocItemId::ConstId(c)),
- AssocItemId::TypeAliasId(_) => None,
- })?;
+ let (impl_id, impl_subst) = find_matching_impl(infcx, &env, trait_ref)?;
+ let item =
+ impl_id.impl_items(infcx.interner.db).items.iter().find_map(|(n, it)| match *it {
+ AssocItemId::FunctionId(f) => (n == name).then_some(AssocItemId::FunctionId(f)),
+ AssocItemId::ConstId(c) => (n == name).then_some(AssocItemId::ConstId(c)),
+ AssocItemId::TypeAliasId(_) => None,
+ })?;
Some((item, impl_subst))
}
-fn find_matching_impl<'db>(
- mut impls: impl Iterator<Item = ImplId>,
- mut table: InferenceTable<'db>,
- actual_trait_ref: TraitRef<'db>,
-) -> Option<(&'db ImplItems, GenericArgs<'db>)> {
- let db = table.db;
- impls.find_map(|impl_| {
- table.run_in_snapshot(|table| {
- let impl_substs = table.fresh_args_for_item(impl_.into());
- let trait_ref = db
- .impl_trait(impl_)
- .expect("non-trait method in find_matching_impl")
- .instantiate(table.interner(), impl_substs);
-
- if !table.unify(trait_ref, actual_trait_ref) {
- return None;
- }
+pub(crate) fn find_matching_impl<'db>(
+ infcx: &InferCtxt<'db>,
+ env: &TraitEnvironment<'db>,
+ trait_ref: TraitRef<'db>,
+) -> Option<(ImplId, GenericArgs<'db>)> {
+ let trait_ref =
+ infcx.at(&ObligationCause::dummy(), env.env).deeply_normalize(trait_ref).ok()?;
- if let Some(predicates) =
- db.generic_predicates_ns(impl_.into()).instantiate(table.interner(), impl_substs)
- {
- for predicate in predicates {
- if table.try_obligation(predicate.0).no_solution() {
- return None;
- }
- table.register_obligation(predicate.0);
- }
- }
- Some((impl_.impl_items(db), table.resolve_completely(impl_substs)))
- })
- })
+ let obligation = Obligation::new(infcx.interner, ObligationCause::dummy(), env.env, trait_ref);
+
+ let selection = infcx.select(&obligation).ok()??;
+
+ // Currently, we use a fulfillment context to completely resolve
+ // all nested obligations. This is because they can inform the
+ // inference of the impl's type parameters.
+ let mut ocx = ObligationCtxt::new(infcx);
+ let impl_source = selection.map(|obligation| ocx.register_obligation(obligation));
+
+ let errors = ocx.select_all_or_error();
+ if !errors.is_empty() {
+ return None;
+ }
+
+ let impl_source = infcx.resolve_vars_if_possible(impl_source);
+ if impl_source.has_non_region_infer() {
+ return None;
+ }
+
+ match impl_source {
+ ImplSource::UserDefined(impl_source) => Some((impl_source.impl_def_id, impl_source.args)),
+ ImplSource::Param(_) | ImplSource::Builtin(..) => None,
+ }
}
fn is_inherent_impl_coherent<'db>(