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.rs987
1 files changed, 491 insertions, 496 deletions
diff --git a/crates/hir-ty/src/method_resolution.rs b/crates/hir-ty/src/method_resolution.rs
index a6150a9bc1..cec6356633 100644
--- a/crates/hir-ty/src/method_resolution.rs
+++ b/crates/hir-ty/src/method_resolution.rs
@@ -4,34 +4,44 @@
//! 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::{
- AssocItemId, BlockId, ConstId, FunctionId, HasModule, ImplId, ItemContainerId, Lookup,
- ModuleId, TraitId,
- nameres::{DefMap, assoc::ImplItems, block_def_map, crate_def_map},
+ AdtId, AssocItemId, BlockId, ConstId, FunctionId, HasModule, ImplId, ItemContainerId, Lookup,
+ ModuleId, TraitId, TypeAliasId,
+ nameres::{DefMap, block_def_map, crate_def_map},
signatures::{ConstFlags, EnumFlags, FnFlags, StructFlags, TraitFlags, TypeAliasFlags},
};
use hir_expand::name::Name;
use intern::sym;
+use rustc_ast_ir::Mutability;
use rustc_hash::{FxHashMap, FxHashSet};
+use rustc_type_ir::{
+ FloatTy, IntTy, TypeVisitableExt, UintTy,
+ inherent::{
+ AdtDef, BoundExistentialPredicates, GenericArgs as _, IntoKind, SliceLike, Ty as _,
+ },
+};
use smallvec::{SmallVec, smallvec};
use stdx::never;
use triomphe::Arc;
use crate::{
- AdtId, Canonical, CanonicalVarKinds, DebruijnIndex, DynTyExt, ForeignDefId, GenericArgData,
- Goal, Guidance, InEnvironment, Interner, Mutability, Scalar, Solution, Substitution,
- TraitEnvironment, TraitRef, TraitRefExt, Ty, TyBuilder, TyExt, TyKind, TyVariableKind,
- VariableKind, WhereClause,
+ TraitEnvironment,
autoderef::{self, AutoderefKind},
db::HirDatabase,
- error_lifetime, from_chalk_trait_id, from_foreign_def_id,
infer::{Adjust, Adjustment, OverloadedDeref, PointerCast, unify::InferenceTable},
lang_items::is_box,
- primitive::{FloatTy, IntTy, UintTy},
- to_chalk_trait_id,
+ next_solver::{
+ Canonical, DbInterner, ErrorGuaranteed, GenericArgs, Goal, Predicate, Region, SolverDefId,
+ TraitRef, Ty, TyKind, TypingMode,
+ infer::{
+ DbInternerInferExt, InferCtxt,
+ select::ImplSource,
+ traits::{Obligation, ObligationCause, PredicateObligation},
+ },
+ obligation_ctxt::ObligationCtxt,
+ },
+ traits::next_trait_solve_canonical_in_ctxt,
utils::all_super_traits,
};
@@ -43,12 +53,17 @@ pub enum TyFingerprint {
Slice,
Array,
Never,
+ Ref(Mutability),
RawPtr(Mutability),
- Scalar(Scalar),
+ Bool,
+ Char,
+ Int(IntTy),
+ Uint(UintTy),
+ Float(FloatTy),
// These can have user-defined impls:
Adt(hir_def::AdtId),
Dyn(TraitId),
- ForeignType(ForeignDefId),
+ ForeignType(TypeAliasId),
// These only exist for trait impls
Unit,
Unnameable,
@@ -60,81 +75,99 @@ impl TyFingerprint {
/// types can have inherent impls: if we have some `struct S`, we can have
/// an `impl S`, but not `impl &S`. Hence, this will return `None` for
/// reference types and such.
- pub fn for_inherent_impl(ty: &Ty) -> Option<TyFingerprint> {
- let fp = match ty.kind(Interner) {
+ pub fn for_inherent_impl<'db>(ty: Ty<'db>) -> Option<TyFingerprint> {
+ let fp = match ty.kind() {
TyKind::Str => TyFingerprint::Str,
TyKind::Never => TyFingerprint::Never,
TyKind::Slice(..) => TyFingerprint::Slice,
TyKind::Array(..) => TyFingerprint::Array,
- TyKind::Scalar(scalar) => TyFingerprint::Scalar(*scalar),
- TyKind::Adt(AdtId(adt), _) => TyFingerprint::Adt(*adt),
- TyKind::Raw(mutability, ..) => TyFingerprint::RawPtr(*mutability),
- TyKind::Foreign(alias_id, ..) => TyFingerprint::ForeignType(*alias_id),
- TyKind::Dyn(_) => ty.dyn_trait().map(TyFingerprint::Dyn)?,
+ TyKind::Bool => TyFingerprint::Bool,
+ TyKind::Char => TyFingerprint::Char,
+ TyKind::Int(int) => TyFingerprint::Int(int),
+ TyKind::Uint(int) => TyFingerprint::Uint(int),
+ TyKind::Float(float) => TyFingerprint::Float(float),
+ TyKind::Adt(adt_def, _) => TyFingerprint::Adt(adt_def.def_id().0),
+ TyKind::RawPtr(_, mutability) => TyFingerprint::RawPtr(mutability),
+ TyKind::Foreign(alias_id, ..) => TyFingerprint::ForeignType(alias_id.0),
+ TyKind::Dynamic(bounds, _) => {
+ bounds.principal_def_id().map(|trait_| TyFingerprint::Dyn(trait_.0))?
+ }
_ => return None,
};
Some(fp)
}
/// Creates a TyFingerprint for looking up a trait impl.
- pub fn for_trait_impl(ty: &Ty) -> Option<TyFingerprint> {
- let fp = match ty.kind(Interner) {
+ pub fn for_trait_impl<'db>(ty: Ty<'db>) -> Option<TyFingerprint> {
+ let fp = match ty.kind() {
TyKind::Str => TyFingerprint::Str,
TyKind::Never => TyFingerprint::Never,
TyKind::Slice(..) => TyFingerprint::Slice,
TyKind::Array(..) => TyFingerprint::Array,
- TyKind::Scalar(scalar) => TyFingerprint::Scalar(*scalar),
- TyKind::Adt(AdtId(adt), _) => TyFingerprint::Adt(*adt),
- TyKind::Raw(mutability, ..) => TyFingerprint::RawPtr(*mutability),
- TyKind::Foreign(alias_id, ..) => TyFingerprint::ForeignType(*alias_id),
- TyKind::Dyn(_) => ty.dyn_trait().map(TyFingerprint::Dyn)?,
- TyKind::Ref(_, _, ty) => return TyFingerprint::for_trait_impl(ty),
- TyKind::Tuple(_, subst) => {
- let first_ty = subst.interned().first().map(|arg| arg.assert_ty_ref(Interner));
+ TyKind::Bool => TyFingerprint::Bool,
+ TyKind::Char => TyFingerprint::Char,
+ TyKind::Int(int) => TyFingerprint::Int(int),
+ TyKind::Uint(int) => TyFingerprint::Uint(int),
+ TyKind::Float(float) => TyFingerprint::Float(float),
+ TyKind::Adt(adt_def, _) => TyFingerprint::Adt(adt_def.def_id().0),
+ TyKind::RawPtr(_, mutability) => TyFingerprint::RawPtr(mutability),
+ TyKind::Foreign(alias_id, ..) => TyFingerprint::ForeignType(alias_id.0),
+ TyKind::Dynamic(bounds, _) => {
+ bounds.principal_def_id().map(|trait_| TyFingerprint::Dyn(trait_.0))?
+ }
+ TyKind::Ref(_, _, mutability) => TyFingerprint::Ref(mutability),
+ TyKind::Tuple(subst) => {
+ let first_ty = subst.as_slice().first();
match first_ty {
- Some(ty) => return TyFingerprint::for_trait_impl(ty),
+ Some(ty) => return TyFingerprint::for_trait_impl(*ty),
None => TyFingerprint::Unit,
}
}
- TyKind::AssociatedType(_, _)
- | TyKind::OpaqueType(_, _)
+ // FIXME(next-solver): Putting `Alias` here is *probably* incorrect, AFAIK it should return `None`. But this breaks
+ // flyimport, which uses an incorrect but fast method resolution algorithm. Therefore we put it here,
+ // because this function is only called by flyimport, and anyway we should get rid of `TyFingerprint`
+ // and switch to `rustc_type_ir`'s `SimplifiedType`.
+ TyKind::Alias(..)
| TyKind::FnDef(_, _)
| TyKind::Closure(_, _)
| TyKind::Coroutine(..)
+ | TyKind::CoroutineClosure(..)
| TyKind::CoroutineWitness(..) => TyFingerprint::Unnameable,
- TyKind::Function(fn_ptr) => {
- TyFingerprint::Function(fn_ptr.substitution.0.len(Interner) as u32)
+ TyKind::FnPtr(sig, _) => {
+ TyFingerprint::Function(sig.skip_binder().inputs_and_output.inner().len() as u32)
}
- TyKind::Alias(_)
- | TyKind::Placeholder(_)
- | TyKind::BoundVar(_)
- | TyKind::InferenceVar(_, _)
- | TyKind::Error => return None,
+ TyKind::Param(_)
+ | TyKind::Bound(..)
+ | TyKind::Placeholder(..)
+ | TyKind::Infer(_)
+ | TyKind::Error(_)
+ | TyKind::Pat(..)
+ | TyKind::UnsafeBinder(..) => return None,
};
Some(fp)
}
}
pub(crate) const ALL_INT_FPS: [TyFingerprint; 12] = [
- TyFingerprint::Scalar(Scalar::Int(IntTy::I8)),
- TyFingerprint::Scalar(Scalar::Int(IntTy::I16)),
- TyFingerprint::Scalar(Scalar::Int(IntTy::I32)),
- TyFingerprint::Scalar(Scalar::Int(IntTy::I64)),
- TyFingerprint::Scalar(Scalar::Int(IntTy::I128)),
- TyFingerprint::Scalar(Scalar::Int(IntTy::Isize)),
- TyFingerprint::Scalar(Scalar::Uint(UintTy::U8)),
- TyFingerprint::Scalar(Scalar::Uint(UintTy::U16)),
- TyFingerprint::Scalar(Scalar::Uint(UintTy::U32)),
- TyFingerprint::Scalar(Scalar::Uint(UintTy::U64)),
- TyFingerprint::Scalar(Scalar::Uint(UintTy::U128)),
- TyFingerprint::Scalar(Scalar::Uint(UintTy::Usize)),
+ TyFingerprint::Int(IntTy::I8),
+ TyFingerprint::Int(IntTy::I16),
+ TyFingerprint::Int(IntTy::I32),
+ TyFingerprint::Int(IntTy::I64),
+ TyFingerprint::Int(IntTy::I128),
+ TyFingerprint::Int(IntTy::Isize),
+ TyFingerprint::Uint(UintTy::U8),
+ TyFingerprint::Uint(UintTy::U16),
+ TyFingerprint::Uint(UintTy::U32),
+ TyFingerprint::Uint(UintTy::U64),
+ TyFingerprint::Uint(UintTy::U128),
+ TyFingerprint::Uint(UintTy::Usize),
];
pub(crate) const ALL_FLOAT_FPS: [TyFingerprint; 4] = [
- TyFingerprint::Scalar(Scalar::Float(FloatTy::F16)),
- TyFingerprint::Scalar(Scalar::Float(FloatTy::F32)),
- TyFingerprint::Scalar(Scalar::Float(FloatTy::F64)),
- TyFingerprint::Scalar(Scalar::Float(FloatTy::F128)),
+ TyFingerprint::Float(FloatTy::F16),
+ TyFingerprint::Float(FloatTy::F32),
+ TyFingerprint::Float(FloatTy::F64),
+ TyFingerprint::Float(FloatTy::F128),
];
type TraitFpMap = FxHashMap<TraitId, FxHashMap<Option<TyFingerprint>, Box<[ImplId]>>>;
@@ -201,11 +234,11 @@ impl TraitImpls {
continue;
}
let target_trait = match db.impl_trait(impl_id) {
- Some(tr) => tr.skip_binders().hir_trait_id(),
+ Some(tr) => tr.skip_binder().def_id.0,
None => continue,
};
let self_ty = db.impl_self_ty(impl_id);
- let self_ty_fp = TyFingerprint::for_trait_impl(self_ty.skip_binders());
+ let self_ty_fp = TyFingerprint::for_trait_impl(self_ty.instantiate_identity());
map.entry(target_trait).or_default().entry(self_ty_fp).or_default().push(impl_id);
}
@@ -319,7 +352,7 @@ impl InherentImpls {
}
let self_ty = db.impl_self_ty(impl_id);
- let self_ty = self_ty.skip_binders();
+ let self_ty = self_ty.instantiate_identity();
match is_inherent_impl_coherent(db, def_map, impl_id, self_ty) {
true => {
@@ -343,7 +376,7 @@ impl InherentImpls {
}
}
- pub fn for_self_ty(&self, self_ty: &Ty) -> &[ImplId] {
+ pub fn for_self_ty<'db>(&self, self_ty: Ty<'db>) -> &[ImplId] {
match TyFingerprint::for_inherent_impl(self_ty) {
Some(fp) => self.map.get(&fp).map(|vec| vec.as_ref()).unwrap_or(&[]),
None => &[],
@@ -379,9 +412,14 @@ pub(crate) fn incoherent_inherent_impl_crates(
res
}
-pub fn def_crates(db: &dyn HirDatabase, ty: &Ty, cur_crate: Crate) -> Option<SmallVec<[Crate; 2]>> {
- match ty.kind(Interner) {
- &TyKind::Adt(AdtId(def_id), _) => {
+pub fn def_crates<'db>(
+ db: &'db dyn HirDatabase,
+ ty: Ty<'db>,
+ cur_crate: Crate,
+) -> Option<SmallVec<[Crate; 2]>> {
+ match ty.kind() {
+ TyKind::Adt(adt_def, _) => {
+ let def_id = adt_def.def_id().0;
let rustc_has_incoherent_inherent_impls = match def_id {
hir_def::AdtId::StructId(id) => db
.struct_signature(id)
@@ -402,22 +440,22 @@ pub fn def_crates(db: &dyn HirDatabase, ty: &Ty, cur_crate: Crate) -> Option<Sma
smallvec![def_id.module(db).krate()]
})
}
- &TyKind::Foreign(id) => {
- let alias = from_foreign_def_id(id);
+ TyKind::Foreign(alias) => {
+ let alias = alias.0;
Some(
if db
.type_alias_signature(alias)
.flags
.contains(TypeAliasFlags::RUSTC_HAS_INCOHERENT_INHERENT_IMPL)
{
- db.incoherent_inherent_impl_crates(cur_crate, TyFingerprint::ForeignType(id))
+ db.incoherent_inherent_impl_crates(cur_crate, TyFingerprint::ForeignType(alias))
} else {
smallvec![alias.module(db).krate()]
},
)
}
- TyKind::Dyn(_) => {
- let trait_id = ty.dyn_trait()?;
+ TyKind::Dynamic(bounds, _) => {
+ let trait_id = bounds.principal_def_id()?.0;
Some(
if db
.trait_signature(trait_id)
@@ -433,11 +471,15 @@ pub fn def_crates(db: &dyn HirDatabase, ty: &Ty, cur_crate: Crate) -> Option<Sma
// for primitives, there may be impls in various places (core and alloc
// mostly). We just check the whole crate graph for crates with impls
// (cached behind a query).
- TyKind::Scalar(_)
+ TyKind::Bool
+ | TyKind::Char
+ | TyKind::Int(_)
+ | TyKind::Uint(_)
+ | TyKind::Float(_)
| TyKind::Str
| TyKind::Slice(_)
| TyKind::Array(..)
- | TyKind::Raw(..) => Some(db.incoherent_inherent_impl_crates(
+ | TyKind::RawPtr(..) => Some(db.incoherent_inherent_impl_crates(
cur_crate,
TyFingerprint::for_inherent_impl(ty).expect("fingerprint for primitive"),
)),
@@ -446,10 +488,10 @@ pub fn def_crates(db: &dyn HirDatabase, ty: &Ty, cur_crate: Crate) -> Option<Sma
}
/// Look up the method with the given name.
-pub(crate) fn lookup_method(
- db: &dyn HirDatabase,
- ty: &Canonical<Ty>,
- env: Arc<TraitEnvironment>,
+pub(crate) fn lookup_method<'db>(
+ db: &'db dyn HirDatabase,
+ ty: &Canonical<'db, Ty<'db>>,
+ env: Arc<TraitEnvironment<'db>>,
traits_in_scope: &FxHashSet<TraitId>,
visible_from_module: VisibleFromModule,
name: &Name,
@@ -529,18 +571,23 @@ pub struct ReceiverAdjustments {
}
impl ReceiverAdjustments {
- pub(crate) fn apply(&self, table: &mut InferenceTable<'_>, ty: Ty) -> (Ty, Vec<Adjustment>) {
- let mut ty = table.resolve_ty_shallow(&ty);
+ pub(crate) fn apply<'db>(
+ &self,
+ table: &mut InferenceTable<'db>,
+ mut ty: Ty<'db>,
+ ) -> (Ty<'db>, Vec<Adjustment<'db>>) {
let mut adjust = Vec::new();
+ let mut autoderef = table.autoderef(ty);
+ autoderef.next();
for _ in 0..self.autoderefs {
- match autoderef::autoderef_step(table, ty.clone(), true, false) {
+ match autoderef.next() {
None => {
never!("autoderef not possible for {:?}", ty);
- ty = TyKind::Error.intern(Interner);
+ ty = Ty::new_error(table.interner(), ErrorGuaranteed);
break;
}
- Some((kind, new_ty)) => {
- ty = new_ty.clone();
+ Some((new_ty, _)) => {
+ ty = new_ty;
let mutbl = match self.autoref {
Some(AutorefOrPtrAdjustment::Autoref(m)) => Some(m),
Some(AutorefOrPtrAdjustment::ToConstPtr) => Some(Mutability::Not),
@@ -548,30 +595,30 @@ impl ReceiverAdjustments {
None => None,
};
adjust.push(Adjustment {
- kind: Adjust::Deref(match kind {
+ kind: Adjust::Deref(match autoderef.steps().last().unwrap().1 {
AutoderefKind::Overloaded => Some(OverloadedDeref(mutbl)),
AutoderefKind::Builtin => None,
}),
- target: new_ty,
+ target: ty,
});
}
}
}
if let Some(autoref) = &self.autoref {
- let lt = table.new_lifetime_var();
+ let lt = table.next_region_var();
match autoref {
AutorefOrPtrAdjustment::Autoref(m) => {
- let a = Adjustment::borrow(*m, ty, lt);
- ty = a.target.clone();
+ let a = Adjustment::borrow(table.interner(), *m, ty, lt);
+ ty = a.target;
adjust.push(a);
}
AutorefOrPtrAdjustment::ToConstPtr => {
- if let TyKind::Raw(Mutability::Mut, pointee) = ty.kind(Interner) {
+ if let TyKind::RawPtr(pointee, Mutability::Mut) = ty.kind() {
let a = Adjustment {
kind: Adjust::Pointer(PointerCast::MutToConstPointer),
- target: TyKind::Raw(Mutability::Not, pointee.clone()).intern(Interner),
+ target: Ty::new_ptr(table.interner(), pointee, Mutability::Not),
};
- ty = a.target.clone();
+ ty = a.target;
adjust.push(a);
} else {
never!("`ToConstPtr` target is not a raw mutable pointer");
@@ -581,23 +628,20 @@ impl ReceiverAdjustments {
}
if self.unsize_array {
ty = 'it: {
- if let TyKind::Ref(m, l, inner) = ty.kind(Interner) {
- if let TyKind::Array(inner, _) = inner.kind(Interner) {
- break 'it TyKind::Ref(
- *m,
- l.clone(),
- TyKind::Slice(inner.clone()).intern(Interner),
- )
- .intern(Interner);
- }
+ if let TyKind::Ref(l, inner, m) = ty.kind()
+ && let TyKind::Array(inner, _) = inner.kind()
+ {
+ break 'it Ty::new_ref(
+ table.interner(),
+ l,
+ Ty::new_slice(table.interner(), inner),
+ m,
+ );
}
// FIXME: report diagnostic if array unsizing happens without indirection.
ty
};
- adjust.push(Adjustment {
- kind: Adjust::Pointer(PointerCast::Unsize),
- target: ty.clone(),
- });
+ adjust.push(Adjustment { kind: Adjust::Pointer(PointerCast::Unsize), target: ty });
}
(ty, adjust)
}
@@ -610,10 +654,10 @@ impl ReceiverAdjustments {
// This would be nicer if it just returned an iterator, but that runs into
// lifetime problems, because we need to borrow temp `CrateImplDefs`.
// FIXME add a context type here?
-pub(crate) fn iterate_method_candidates<T>(
- ty: &Canonical<Ty>,
- db: &dyn HirDatabase,
- env: Arc<TraitEnvironment>,
+pub(crate) fn iterate_method_candidates<'db, T>(
+ ty: &Canonical<'db, Ty<'db>>,
+ db: &'db dyn HirDatabase,
+ env: Arc<TraitEnvironment<'db>>,
traits_in_scope: &FxHashSet<TraitId>,
visible_from_module: VisibleFromModule,
name: Option<&Name>,
@@ -641,18 +685,20 @@ pub(crate) fn iterate_method_candidates<T>(
slot
}
-pub fn lookup_impl_const(
- db: &dyn HirDatabase,
- env: Arc<TraitEnvironment>,
+pub fn lookup_impl_const<'db>(
+ infcx: &InferCtxt<'db>,
+ env: Arc<TraitEnvironment<'db>>,
const_id: ConstId,
- subs: Substitution,
-) -> (ConstId, Substitution) {
+ subs: GenericArgs<'db>,
+) -> (ConstId, GenericArgs<'db>) {
+ let interner = infcx.interner;
+ let db = interner.db;
+
let trait_id = match const_id.lookup(db).container {
ItemContainerId::TraitId(id) => id,
_ => return (const_id, subs),
};
- let substitution = Substitution::from_iter(Interner, subs.iter(Interner));
- let trait_ref = TraitRef { trait_id: to_chalk_trait_id(trait_id), substitution };
+ let trait_ref = TraitRef::new(interner, trait_id.into(), subs);
let const_signature = db.const_signature(const_id);
let name = match const_signature.name.as_ref() {
@@ -660,7 +706,7 @@ pub fn lookup_impl_const(
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 },
)
@@ -669,38 +715,31 @@ pub fn lookup_impl_const(
/// 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>,
+pub fn is_dyn_method<'db>(
+ interner: DbInterner<'db>,
+ _env: Arc<TraitEnvironment<'db>>,
func: FunctionId,
- fn_subst: Substitution,
+ fn_subst: GenericArgs<'db>,
) -> Option<usize> {
+ let db = interner.db;
+
let ItemContainerId::TraitId(trait_id) = func.lookup(db).container else {
return None;
};
let trait_params = db.generic_params(trait_id.into()).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).take(trait_params)),
- };
- let self_ty = trait_ref.self_type_parameter(Interner);
- if let TyKind::Dyn(d) = self_ty.kind(Interner) {
+ let fn_params = fn_subst.len() - trait_params;
+ let trait_ref = TraitRef::new(
+ interner,
+ trait_id.into(),
+ GenericArgs::new_from_iter(interner, fn_subst.iter().take(trait_params)),
+ );
+ let self_ty = trait_ref.self_ty();
+ if let TyKind::Dynamic(d, _) = self_ty.kind() {
+ // 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.
let is_my_trait_in_bounds = d
- .bounds
- .skip_binders()
- .as_slice(Interner)
- .iter()
- .map(|it| it.skip_binders())
- .flat_map(|it| match it {
- WhereClause::Implemented(tr) => {
- all_super_traits(db, from_chalk_trait_id(tr.trait_id))
- }
- _ => smallvec![],
- })
- // 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.
- .any(|x| x == trait_id);
+ .principal_def_id()
+ .is_some_and(|trait_| all_super_traits(db, trait_.0).contains(&trait_id));
if is_my_trait_in_bounds {
return Some(fn_params);
}
@@ -711,24 +750,28 @@ pub fn is_dyn_method(
/// 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.
-pub(crate) fn lookup_impl_method_query(
- db: &dyn HirDatabase,
- env: Arc<TraitEnvironment>,
+pub(crate) fn lookup_impl_method_query<'db>(
+ db: &'db dyn HirDatabase,
+ env: Arc<TraitEnvironment<'db>>,
func: FunctionId,
- fn_subst: Substitution,
-) -> (FunctionId, Substitution) {
+ 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);
};
let trait_params = db.generic_params(trait_id.into()).len();
- let trait_ref = TraitRef {
- trait_id: to_chalk_trait_id(trait_id),
- substitution: Substitution::from_iter(Interner, fn_subst.iter(Interner).take(trait_params)),
- };
+ let trait_ref = TraitRef::new(
+ interner,
+ trait_id.into(),
+ GenericArgs::new_from_iter(interner, fn_subst.iter().take(trait_params)),
+ );
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 {
@@ -737,123 +780,109 @@ pub(crate) fn lookup_impl_method_query(
(
impl_fn,
- Substitution::from_iter(
- Interner,
- impl_subst.iter(Interner).chain(fn_subst.iter(Interner).skip(trait_params)),
+ GenericArgs::new_from_iter(
+ interner,
+ impl_subst.iter().chain(fn_subst.iter().skip(trait_params)),
),
)
}
-fn lookup_impl_assoc_item_for_trait_ref(
- trait_ref: TraitRef,
- db: &dyn HirDatabase,
- env: Arc<TraitEnvironment>,
+fn lookup_impl_assoc_item_for_trait_ref<'db>(
+ infcx: &InferCtxt<'db>,
+ trait_ref: TraitRef<'db>,
+ env: Arc<TraitEnvironment<'db>>,
name: &Name,
-) -> Option<(AssocItemId, Substitution)> {
- let hir_trait_id = trait_ref.hir_trait_id();
- let self_ty = trait_ref.self_type_parameter(Interner);
- 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(from_foreign_def_id(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,
- })?;
+) -> Option<(AssocItemId, GenericArgs<'db>)> {
+ 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(
- mut impls: impl Iterator<Item = ImplId>,
- mut table: InferenceTable<'_>,
- actual_trait_ref: TraitRef,
-) -> Option<(&ImplItems, Substitution)> {
- let db = table.db;
- impls.find_map(|impl_| {
- table.run_in_snapshot(|table| {
- let impl_substs =
- TyBuilder::subst_for_def(db, impl_, None).fill_with_inference_vars(table).build();
- let trait_ref = db
- .impl_trait(impl_)
- .expect("non-trait method in find_matching_impl")
- .substitute(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()?;
- let wcs = crate::chalk_db::convert_where_clauses(db, impl_.into(), &impl_substs)
- .into_iter()
- .map(|b| b.cast(Interner));
- let goal = crate::Goal::all(Interner, wcs);
- table.try_obligation(goal.clone())?;
- table.register_obligation(goal);
- 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.evaluate_obligations_error_on_ambiguity();
+ 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: &dyn HirDatabase,
+fn is_inherent_impl_coherent<'db>(
+ db: &'db dyn HirDatabase,
def_map: &DefMap,
impl_id: ImplId,
- self_ty: &Ty,
+ self_ty: Ty<'db>,
) -> bool {
- let self_ty = self_ty.kind(Interner);
+ let self_ty = self_ty.kind();
let impl_allowed = match self_ty {
- TyKind::Tuple(_, _)
+ TyKind::Tuple(_)
| TyKind::FnDef(_, _)
| TyKind::Array(_, _)
| TyKind::Never
- | TyKind::Raw(_, _)
+ | TyKind::RawPtr(_, _)
| TyKind::Ref(_, _, _)
| TyKind::Slice(_)
| TyKind::Str
- | TyKind::Scalar(_) => def_map.is_rustc_coherence_is_core(),
+ | TyKind::Bool
+ | TyKind::Char
+ | TyKind::Int(_)
+ | TyKind::Uint(_)
+ | TyKind::Float(_) => def_map.is_rustc_coherence_is_core(),
- &TyKind::Adt(AdtId(adt), _) => adt.module(db).krate() == def_map.krate(),
- TyKind::Dyn(it) => it.principal_id().is_some_and(|trait_id| {
- from_chalk_trait_id(trait_id).module(db).krate() == def_map.krate()
- }),
+ TyKind::Adt(adt_def, _) => adt_def.def_id().0.module(db).krate() == def_map.krate(),
+ TyKind::Dynamic(it, _) => it
+ .principal_def_id()
+ .is_some_and(|trait_id| trait_id.0.module(db).krate() == def_map.krate()),
_ => true,
};
impl_allowed || {
let rustc_has_incoherent_inherent_impls = match self_ty {
- TyKind::Tuple(_, _)
+ TyKind::Tuple(_)
| TyKind::FnDef(_, _)
| TyKind::Array(_, _)
| TyKind::Never
- | TyKind::Raw(_, _)
+ | TyKind::RawPtr(_, _)
| TyKind::Ref(_, _, _)
| TyKind::Slice(_)
| TyKind::Str
- | TyKind::Scalar(_) => true,
+ | TyKind::Bool
+ | TyKind::Char
+ | TyKind::Int(_)
+ | TyKind::Uint(_)
+ | TyKind::Float(_) => true,
- &TyKind::Adt(AdtId(adt), _) => match adt {
+ TyKind::Adt(adt_def, _) => match adt_def.def_id().0 {
hir_def::AdtId::StructId(id) => db
.struct_signature(id)
.flags
@@ -867,8 +896,8 @@ fn is_inherent_impl_coherent(
.flags
.contains(EnumFlags::RUSTC_HAS_INCOHERENT_INHERENT_IMPLS),
},
- TyKind::Dyn(it) => it.principal_id().is_some_and(|trait_id| {
- db.trait_signature(from_chalk_trait_id(trait_id))
+ TyKind::Dynamic(it, _) => it.principal_def_id().is_some_and(|trait_id| {
+ db.trait_signature(trait_id.0)
.flags
.contains(TraitFlags::RUSTC_HAS_INCOHERENT_INHERENT_IMPLS)
}),
@@ -900,8 +929,7 @@ fn is_inherent_impl_coherent(
/// - All of
/// - At least one of the types `T0..=Tn`` must be a local type. Let `Ti`` be the first such type.
/// - No uncovered type parameters `P1..=Pn` may appear in `T0..Ti`` (excluding `Ti`)
-pub fn check_orphan_rules(db: &dyn HirDatabase, impl_: ImplId) -> bool {
- let substs = TyBuilder::placeholder_subst(db, impl_);
+pub fn check_orphan_rules<'db>(db: &'db dyn HirDatabase, impl_: ImplId) -> bool {
let Some(impl_trait) = db.impl_trait(impl_) else {
// not a trait impl
return true;
@@ -910,22 +938,25 @@ pub fn check_orphan_rules(db: &dyn HirDatabase, impl_: ImplId) -> bool {
let local_crate = impl_.lookup(db).container.krate();
let is_local = |tgt_crate| tgt_crate == local_crate;
- let trait_ref = impl_trait.substitute(Interner, &substs);
- let trait_id = from_chalk_trait_id(trait_ref.trait_id);
+ let trait_ref = impl_trait.instantiate_identity();
+ let trait_id = trait_ref.def_id.0;
if is_local(trait_id.module(db).krate()) {
// trait to be implemented is local
return true;
}
- let unwrap_fundamental = |mut ty: Ty| {
+ let unwrap_fundamental = |mut ty: Ty<'db>| {
// Unwrap all layers of fundamental types with a loop.
loop {
- match ty.kind(Interner) {
- TyKind::Ref(_, _, referenced) => ty = referenced.clone(),
- &TyKind::Adt(AdtId(hir_def::AdtId::StructId(s)), ref subs) => {
+ match ty.kind() {
+ TyKind::Ref(_, referenced, _) => ty = referenced,
+ TyKind::Adt(adt_def, subs) => {
+ let AdtId::StructId(s) = adt_def.def_id().0 else {
+ break ty;
+ };
let struct_signature = db.struct_signature(s);
if struct_signature.flags.contains(StructFlags::FUNDAMENTAL) {
- let next = subs.type_parameters(Interner).next();
+ let next = subs.types().next();
match next {
Some(it) => ty = it,
None => break ty,
@@ -942,24 +973,22 @@ pub fn check_orphan_rules(db: &dyn HirDatabase, impl_: ImplId) -> bool {
// FIXME: param coverage
// - No uncovered type parameters `P1..=Pn` may appear in `T0..Ti`` (excluding `Ti`)
- let is_not_orphan = trait_ref.substitution.type_parameters(Interner).any(|ty| {
- match unwrap_fundamental(ty).kind(Interner) {
- &TyKind::Adt(AdtId(id), _) => is_local(id.module(db).krate()),
- TyKind::Error => true,
- TyKind::Dyn(it) => it
- .principal_id()
- .is_some_and(|trait_id| is_local(from_chalk_trait_id(trait_id).module(db).krate())),
- _ => false,
+ let is_not_orphan = trait_ref.args.types().any(|ty| match unwrap_fundamental(ty).kind() {
+ TyKind::Adt(adt_def, _) => is_local(adt_def.def_id().0.module(db).krate()),
+ TyKind::Error(_) => true,
+ TyKind::Dynamic(it, _) => {
+ it.principal_def_id().is_some_and(|trait_id| is_local(trait_id.0.module(db).krate()))
}
+ _ => false,
});
#[allow(clippy::let_and_return)]
is_not_orphan
}
-pub fn iterate_path_candidates(
- ty: &Canonical<Ty>,
- db: &dyn HirDatabase,
- env: Arc<TraitEnvironment>,
+pub fn iterate_path_candidates<'db>(
+ ty: &Canonical<'db, Ty<'db>>,
+ db: &'db dyn HirDatabase,
+ env: Arc<TraitEnvironment<'db>>,
traits_in_scope: &FxHashSet<TraitId>,
visible_from_module: VisibleFromModule,
name: Option<&Name>,
@@ -978,10 +1007,10 @@ pub fn iterate_path_candidates(
)
}
-pub fn iterate_method_candidates_dyn(
- ty: &Canonical<Ty>,
- db: &dyn HirDatabase,
- env: Arc<TraitEnvironment>,
+pub fn iterate_method_candidates_dyn<'db>(
+ ty: &Canonical<'db, Ty<'db>>,
+ db: &'db dyn HirDatabase,
+ env: Arc<TraitEnvironment<'db>>,
traits_in_scope: &FxHashSet<TraitId>,
visible_from_module: VisibleFromModule,
name: Option<&Name>,
@@ -1018,7 +1047,7 @@ pub fn iterate_method_candidates_dyn(
// types*.
let mut table = InferenceTable::new(db, env);
- let ty = table.instantiate_canonical(ty.clone());
+ let ty = table.instantiate_canonical(*ty);
let deref_chain = autoderef_method_receiver(&mut table, ty);
deref_chain.into_iter().try_for_each(|(receiver_ty, adj)| {
@@ -1049,19 +1078,16 @@ pub fn iterate_method_candidates_dyn(
}
#[tracing::instrument(skip_all, fields(name = ?name))]
-fn iterate_method_candidates_with_autoref(
- table: &mut InferenceTable<'_>,
- receiver_ty: Canonical<Ty>,
+fn iterate_method_candidates_with_autoref<'db>(
+ table: &mut InferenceTable<'db>,
+ receiver_ty: Canonical<'db, Ty<'db>>,
first_adjustment: ReceiverAdjustments,
traits_in_scope: &FxHashSet<TraitId>,
visible_from_module: VisibleFromModule,
name: Option<&Name>,
callback: &mut dyn MethodCandidateCallback,
) -> ControlFlow<()> {
- if receiver_ty.value.is_general_var(Interner, &receiver_ty.binders) {
- // don't try to resolve methods on unknown types
- return ControlFlow::Continue(());
- }
+ let interner = table.interner();
let mut iterate_method_candidates_by_receiver = move |receiver_ty, first_adjustment| {
iterate_method_candidates_by_receiver(
@@ -1076,18 +1102,18 @@ fn iterate_method_candidates_with_autoref(
};
let mut maybe_reborrowed = first_adjustment.clone();
- if let Some((_, _, m)) = receiver_ty.value.as_reference() {
+ if let TyKind::Ref(_, _, m) = receiver_ty.value.kind() {
// Prefer reborrow of references to move
maybe_reborrowed.autoref = Some(AutorefOrPtrAdjustment::Autoref(m));
maybe_reborrowed.autoderefs += 1;
}
- iterate_method_candidates_by_receiver(receiver_ty.clone(), maybe_reborrowed)?;
+ iterate_method_candidates_by_receiver(receiver_ty, maybe_reborrowed)?;
let refed = Canonical {
- value: TyKind::Ref(Mutability::Not, error_lifetime(), receiver_ty.value.clone())
- .intern(Interner),
- binders: receiver_ty.binders.clone(),
+ max_universe: receiver_ty.max_universe,
+ variables: receiver_ty.variables,
+ value: Ty::new_ref(interner, Region::error(interner), receiver_ty.value, Mutability::Not),
};
iterate_method_candidates_by_receiver(
@@ -1096,9 +1122,9 @@ fn iterate_method_candidates_with_autoref(
)?;
let ref_muted = Canonical {
- value: TyKind::Ref(Mutability::Mut, error_lifetime(), receiver_ty.value.clone())
- .intern(Interner),
- binders: receiver_ty.binders.clone(),
+ max_universe: receiver_ty.max_universe,
+ variables: receiver_ty.variables,
+ value: Ty::new_ref(interner, Region::error(interner), receiver_ty.value, Mutability::Mut),
};
iterate_method_candidates_by_receiver(
@@ -1106,10 +1132,11 @@ fn iterate_method_candidates_with_autoref(
first_adjustment.with_autoref(AutorefOrPtrAdjustment::Autoref(Mutability::Mut)),
)?;
- if let Some((ty, Mutability::Mut)) = receiver_ty.value.as_raw_ptr() {
- let const_ptr_ty = Canonical {
- value: TyKind::Raw(Mutability::Not, ty.clone()).intern(Interner),
- binders: receiver_ty.binders,
+ if let TyKind::RawPtr(ty, Mutability::Mut) = receiver_ty.value.kind() {
+ let const_ptr_ty = rustc_type_ir::Canonical {
+ max_universe: rustc_type_ir::UniverseIndex::ZERO,
+ value: Ty::new_ptr(interner, ty, Mutability::Not),
+ variables: receiver_ty.variables,
};
iterate_method_candidates_by_receiver(
const_ptr_ty,
@@ -1160,9 +1187,9 @@ where
}
#[tracing::instrument(skip_all, fields(name = ?name))]
-fn iterate_method_candidates_by_receiver(
- table: &mut InferenceTable<'_>,
- receiver_ty: Canonical<Ty>,
+fn iterate_method_candidates_by_receiver<'db>(
+ table: &mut InferenceTable<'db>,
+ receiver_ty: Canonical<'db, Ty<'db>>,
receiver_adjustments: ReceiverAdjustments,
traits_in_scope: &FxHashSet<TraitId>,
visible_from_module: VisibleFromModule,
@@ -1174,16 +1201,18 @@ fn iterate_method_candidates_by_receiver(
// be found in any of the derefs of receiver_ty, so we have to go through
// that, including raw derefs.
table.run_in_snapshot(|table| {
- let mut autoderef =
- autoderef::Autoderef::new_no_tracking(table, receiver_ty.clone(), true, true);
+ let mut autoderef = autoderef::Autoderef::new_no_tracking(table, receiver_ty)
+ .include_raw_pointers()
+ .use_receiver_trait();
while let Some((self_ty, _)) = autoderef.next() {
iterate_inherent_methods(
- &self_ty,
+ self_ty,
autoderef.table,
name,
- Some(&receiver_ty),
+ Some(receiver_ty),
Some(receiver_adjustments.clone()),
visible_from_module,
+ LookupMode::MethodCall,
&mut |adjustments, item, is_visible| {
callback.on_inherent_method(adjustments, item, is_visible)
},
@@ -1192,21 +1221,23 @@ fn iterate_method_candidates_by_receiver(
ControlFlow::Continue(())
})?;
table.run_in_snapshot(|table| {
- let mut autoderef =
- autoderef::Autoderef::new_no_tracking(table, receiver_ty.clone(), true, true);
+ let mut autoderef = autoderef::Autoderef::new_no_tracking(table, receiver_ty)
+ .include_raw_pointers()
+ .use_receiver_trait();
while let Some((self_ty, _)) = autoderef.next() {
- if matches!(self_ty.kind(Interner), TyKind::InferenceVar(_, TyVariableKind::General)) {
+ if matches!(self_ty.kind(), TyKind::Infer(rustc_type_ir::TyVar(_))) {
// don't try to resolve methods on unknown types
return ControlFlow::Continue(());
}
iterate_trait_method_candidates(
- &self_ty,
+ self_ty,
autoderef.table,
traits_in_scope,
name,
- Some(&receiver_ty),
+ Some(receiver_ty),
Some(receiver_adjustments.clone()),
+ LookupMode::MethodCall,
&mut |adjustments, item, is_visible| {
callback.on_trait_method(adjustments, item, is_visible)
},
@@ -1217,35 +1248,37 @@ fn iterate_method_candidates_by_receiver(
}
#[tracing::instrument(skip_all, fields(name = ?name))]
-fn iterate_method_candidates_for_self_ty(
- self_ty: &Canonical<Ty>,
- db: &dyn HirDatabase,
- env: Arc<TraitEnvironment>,
+fn iterate_method_candidates_for_self_ty<'db>(
+ self_ty: &Canonical<'db, Ty<'db>>,
+ db: &'db dyn HirDatabase,
+ env: Arc<TraitEnvironment<'db>>,
traits_in_scope: &FxHashSet<TraitId>,
visible_from_module: VisibleFromModule,
name: Option<&Name>,
callback: &mut dyn MethodCandidateCallback,
) -> ControlFlow<()> {
let mut table = InferenceTable::new(db, env);
- let self_ty = table.instantiate_canonical(self_ty.clone());
+ let self_ty = table.instantiate_canonical(*self_ty);
iterate_inherent_methods(
- &self_ty,
+ self_ty,
&mut table,
name,
None,
None,
visible_from_module,
+ LookupMode::Path,
&mut |adjustments, item, is_visible| {
callback.on_inherent_method(adjustments, item, is_visible)
},
)?;
iterate_trait_method_candidates(
- &self_ty,
+ self_ty,
&mut table,
traits_in_scope,
name,
None,
None,
+ LookupMode::Path,
&mut |adjustments, item, is_visible| {
callback.on_trait_method(adjustments, item, is_visible)
},
@@ -1253,19 +1286,20 @@ fn iterate_method_candidates_for_self_ty(
}
#[tracing::instrument(skip_all, fields(name = ?name, visible_from_module, receiver_ty))]
-fn iterate_trait_method_candidates(
- self_ty: &Ty,
- table: &mut InferenceTable<'_>,
+fn iterate_trait_method_candidates<'db>(
+ self_ty: Ty<'db>,
+ table: &mut InferenceTable<'db>,
traits_in_scope: &FxHashSet<TraitId>,
name: Option<&Name>,
- receiver_ty: Option<&Ty>,
+ receiver_ty: Option<Ty<'db>>,
receiver_adjustments: Option<ReceiverAdjustments>,
+ mode: LookupMode,
callback: &mut dyn FnMut(ReceiverAdjustments, AssocItemId, bool) -> ControlFlow<()>,
) -> ControlFlow<()> {
let db = table.db;
- let canonical_self_ty = table.canonicalize(self_ty.clone());
- let TraitEnvironment { krate, block, .. } = *table.trait_env;
+ let canonical_self_ty = table.canonicalize(self_ty);
+ let krate = table.trait_env.krate;
'traits: for &t in traits_in_scope {
let data = db.trait_signature(t);
@@ -1276,7 +1310,7 @@ fn iterate_trait_method_candidates(
// This is to make `[a].into_iter()` not break code with the new `IntoIterator` impl for
// arrays.
if data.flags.contains(TraitFlags::SKIP_ARRAY_DURING_METHOD_DISPATCH)
- && matches!(self_ty.kind(Interner), TyKind::Array(..))
+ && matches!(self_ty.kind(), TyKind::Array(..))
{
// FIXME: this should really be using the edition of the method name's span, in case it
// comes from a macro
@@ -1286,9 +1320,9 @@ fn iterate_trait_method_candidates(
}
if data.flags.contains(TraitFlags::SKIP_BOXED_SLICE_DURING_METHOD_DISPATCH)
&& matches!(
- self_ty.kind(Interner), TyKind::Adt(AdtId(def), subst)
- if is_box(table.db, *def)
- && matches!(subst.at(Interner, 0).assert_ty_ref(Interner).kind(Interner), TyKind::Slice(..))
+ self_ty.kind(), TyKind::Adt(adt_def, subst)
+ if is_box(table.db, adt_def.def_id().0)
+ && matches!(subst.type_at(0).kind(), TyKind::Slice(..))
)
{
// FIXME: this should really be using the edition of the method name's span, in case it
@@ -1305,15 +1339,22 @@ fn iterate_trait_method_candidates(
for &(_, item) in t.trait_items(db).items.iter() {
// Don't pass a `visible_from_module` down to `is_valid_candidate`,
// since only inherent methods should be included into visibility checking.
- let visible =
- match is_valid_trait_method_candidate(table, t, name, receiver_ty, item, self_ty) {
- IsValidCandidate::Yes => true,
- IsValidCandidate::NotVisible => false,
- IsValidCandidate::No => continue,
- };
+ let visible = match is_valid_trait_method_candidate(
+ table,
+ t,
+ name,
+ receiver_ty,
+ item,
+ self_ty,
+ mode,
+ ) {
+ IsValidCandidate::Yes => true,
+ IsValidCandidate::NotVisible => false,
+ IsValidCandidate::No => continue,
+ };
if !known_implemented {
- let goal = generic_implements_goal(db, &table.trait_env, t, &canonical_self_ty);
- if db.trait_solve(krate, block, goal.cast(Interner)).is_none() {
+ let goal = generic_implements_goal_ns(table, t, canonical_self_ty);
+ if next_trait_solve_canonical_in_ctxt(&table.infer_ctxt, goal).no_solution() {
continue 'traits;
}
}
@@ -1325,13 +1366,14 @@ fn iterate_trait_method_candidates(
}
#[tracing::instrument(skip_all, fields(name = ?name, visible_from_module, receiver_ty))]
-fn iterate_inherent_methods(
- self_ty: &Ty,
- table: &mut InferenceTable<'_>,
+fn iterate_inherent_methods<'db>(
+ self_ty: Ty<'db>,
+ table: &mut InferenceTable<'db>,
name: Option<&Name>,
- receiver_ty: Option<&Ty>,
+ receiver_ty: Option<Ty<'db>>,
receiver_adjustments: Option<ReceiverAdjustments>,
visible_from_module: VisibleFromModule,
+ mode: LookupMode,
callback: &mut dyn FnMut(ReceiverAdjustments, AssocItemId, bool) -> ControlFlow<()>,
) -> ControlFlow<()> {
let db = table.db;
@@ -1341,12 +1383,11 @@ fn iterate_inherent_methods(
// its super traits are considered inherent methods. This matters because these methods have
// higher priority than the other traits' methods, which would be considered in
// `iterate_trait_method_candidates()` only after this function.
- match self_ty.kind(Interner) {
- TyKind::Placeholder(_) => {
+ match self_ty.kind() {
+ TyKind::Param(_) => {
let env = table.trait_env.clone();
- let traits = env
- .traits_in_scope_from_clauses(self_ty.clone())
- .flat_map(|t| all_super_traits(db, t));
+ let traits =
+ env.traits_in_scope_from_clauses(self_ty).flat_map(|t| all_super_traits(db, t));
iterate_inherent_trait_methods(
self_ty,
table,
@@ -1355,11 +1396,12 @@ fn iterate_inherent_methods(
receiver_adjustments.clone(),
callback,
traits,
+ mode,
)?;
}
- TyKind::Dyn(_) => {
- if let Some(principal_trait) = self_ty.dyn_trait() {
- let traits = all_super_traits(db, principal_trait);
+ TyKind::Dynamic(bounds, _) => {
+ if let Some(principal_trait) = bounds.principal_def_id() {
+ let traits = all_super_traits(db, principal_trait.0);
iterate_inherent_trait_methods(
self_ty,
table,
@@ -1368,6 +1410,7 @@ fn iterate_inherent_methods(
receiver_adjustments.clone(),
callback,
traits.into_iter(),
+ mode,
)?;
}
}
@@ -1418,14 +1461,15 @@ fn iterate_inherent_methods(
return ControlFlow::Continue(());
#[tracing::instrument(skip_all, fields(name = ?name, visible_from_module, receiver_ty))]
- fn iterate_inherent_trait_methods(
- self_ty: &Ty,
- table: &mut InferenceTable<'_>,
+ fn iterate_inherent_trait_methods<'db>(
+ self_ty: Ty<'db>,
+ table: &mut InferenceTable<'db>,
name: Option<&Name>,
- receiver_ty: Option<&Ty>,
+ receiver_ty: Option<Ty<'db>>,
receiver_adjustments: Option<ReceiverAdjustments>,
callback: &mut dyn FnMut(ReceiverAdjustments, AssocItemId, bool) -> ControlFlow<()>,
traits: impl Iterator<Item = TraitId>,
+ mode: LookupMode,
) -> ControlFlow<()> {
let db = table.db;
for t in traits {
@@ -1439,6 +1483,7 @@ fn iterate_inherent_methods(
receiver_ty,
item,
self_ty,
+ mode,
) {
IsValidCandidate::Yes => true,
IsValidCandidate::NotVisible => false,
@@ -1451,12 +1496,12 @@ fn iterate_inherent_methods(
}
#[tracing::instrument(skip_all, fields(name = ?name, visible_from_module, receiver_ty))]
- fn impls_for_self_ty(
+ fn impls_for_self_ty<'db>(
impls: &InherentImpls,
- self_ty: &Ty,
- table: &mut InferenceTable<'_>,
+ self_ty: Ty<'db>,
+ table: &mut InferenceTable<'db>,
name: Option<&Name>,
- receiver_ty: Option<&Ty>,
+ receiver_ty: Option<Ty<'db>>,
receiver_adjustments: Option<ReceiverAdjustments>,
visible_from_module: Option<ModuleId>,
callback: &mut dyn FnMut(ReceiverAdjustments, AssocItemId, bool) -> ControlFlow<()>,
@@ -1485,21 +1530,16 @@ fn iterate_inherent_methods(
}
/// Returns the receiver type for the index trait call.
-pub(crate) fn resolve_indexing_op(
- db: &dyn HirDatabase,
- env: Arc<TraitEnvironment>,
- ty: Canonical<Ty>,
+pub(crate) fn resolve_indexing_op<'db>(
+ table: &mut InferenceTable<'db>,
+ ty: Canonical<'db, Ty<'db>>,
index_trait: TraitId,
) -> Option<ReceiverAdjustments> {
- let mut table = InferenceTable::new(db, env);
let ty = table.instantiate_canonical(ty);
- let deref_chain = autoderef_method_receiver(&mut table, ty);
+ let deref_chain = autoderef_method_receiver(table, ty);
for (ty, adj) in deref_chain {
- let goal = generic_implements_goal(db, &table.trait_env, index_trait, &ty);
- if db
- .trait_solve(table.trait_env.krate, table.trait_env.block, goal.cast(Interner))
- .is_some()
- {
+ let goal = generic_implements_goal_ns(table, index_trait, ty);
+ if !next_trait_solve_canonical_in_ctxt(&table.infer_ctxt, goal).no_solution() {
return Some(adj);
}
}
@@ -1523,10 +1563,10 @@ enum IsValidCandidate {
}
#[tracing::instrument(skip_all, fields(name))]
-fn is_valid_impl_method_candidate(
- table: &mut InferenceTable<'_>,
- self_ty: &Ty,
- receiver_ty: Option<&Ty>,
+fn is_valid_impl_method_candidate<'db>(
+ table: &mut InferenceTable<'db>,
+ self_ty: Ty<'db>,
+ receiver_ty: Option<Ty<'db>>,
visible_from_module: Option<ModuleId>,
name: Option<&Name>,
impl_id: ImplId,
@@ -1549,16 +1589,17 @@ fn is_valid_impl_method_candidate(
check_that!(receiver_ty.is_none());
check_that!(name.is_none_or(|n| n == item_name));
- if let Some(from_module) = visible_from_module {
- if !db.assoc_visibility(c.into()).is_visible_from(db, from_module) {
- cov_mark::hit!(const_candidate_not_visible);
- return IsValidCandidate::NotVisible;
- }
+ if let Some(from_module) = visible_from_module
+ && !db.assoc_visibility(c.into()).is_visible_from(db, from_module)
+ {
+ cov_mark::hit!(const_candidate_not_visible);
+ return IsValidCandidate::NotVisible;
}
let self_ty_matches = table.run_in_snapshot(|table| {
+ let impl_args = table.fresh_args_for_item(impl_id.into());
let expected_self_ty =
- TyBuilder::impl_self_ty(db, impl_id).fill_with_inference_vars(table).build();
- table.unify(&expected_self_ty, self_ty)
+ db.impl_self_ty(impl_id).instantiate(table.interner(), impl_args);
+ table.unify(expected_self_ty, self_ty)
});
if !self_ty_matches {
cov_mark::hit!(const_candidate_self_type_mismatch);
@@ -1572,13 +1613,14 @@ fn is_valid_impl_method_candidate(
/// Checks whether a given `AssocItemId` is applicable for `receiver_ty`.
#[tracing::instrument(skip_all, fields(name))]
-fn is_valid_trait_method_candidate(
- table: &mut InferenceTable<'_>,
+fn is_valid_trait_method_candidate<'db>(
+ table: &mut InferenceTable<'db>,
trait_id: TraitId,
name: Option<&Name>,
- receiver_ty: Option<&Ty>,
+ receiver_ty: Option<Ty<'db>>,
item: AssocItemId,
- self_ty: &Ty,
+ self_ty: Ty<'db>,
+ mode: LookupMode,
) -> IsValidCandidate {
let db = table.db;
match item {
@@ -1588,25 +1630,42 @@ fn is_valid_trait_method_candidate(
check_that!(name.is_none_or(|n| n == &data.name));
table.run_in_snapshot(|table| {
- let impl_subst = TyBuilder::subst_for_def(db, trait_id, None)
- .fill_with_inference_vars(table)
- .build();
- let expect_self_ty = impl_subst.at(Interner, 0).assert_ty_ref(Interner).clone();
+ let impl_subst = table.fresh_args_for_item(trait_id.into());
+ let expect_self_ty = impl_subst.type_at(0);
- check_that!(table.unify(&expect_self_ty, self_ty));
+ check_that!(table.unify(expect_self_ty, self_ty));
if let Some(receiver_ty) = receiver_ty {
check_that!(data.has_self_param());
- let fn_subst = TyBuilder::subst_for_def(db, fn_id, Some(impl_subst))
- .fill_with_inference_vars(table)
- .build();
+ let args = table.fill_rest_fresh_args(fn_id.into(), impl_subst);
let sig = db.callable_item_signature(fn_id.into());
- let expected_receiver =
- sig.map(|s| s.params()[0].clone()).substitute(Interner, &fn_subst);
+ let expected_receiver = sig
+ .map_bound(|s| s.skip_binder().inputs_and_output.as_slice()[0])
+ .instantiate(table.interner(), args);
+
+ // FIXME: Clean up this mess with some context struct like rustc's `ProbeContext`
+ let variance = match mode {
+ LookupMode::MethodCall => rustc_type_ir::Variance::Covariant,
+ LookupMode::Path => rustc_type_ir::Variance::Invariant,
+ };
+ let res = table
+ .infer_ctxt
+ .at(&ObligationCause::dummy(), table.trait_env.env)
+ .relate(expected_receiver, variance, receiver_ty);
+ let Ok(infer_ok) = res else {
+ return IsValidCandidate::No;
+ };
+
+ if !infer_ok.obligations.is_empty() {
+ let mut ctxt = ObligationCtxt::new(&table.infer_ctxt);
+ ctxt.register_obligations(infer_ok.into_obligations());
+ // FIXME: Are we doing this correctly? Probably better to follow rustc more closely.
+ check_that!(ctxt.try_evaluate_obligations().is_empty());
+ }
- check_that!(table.unify(receiver_ty, &expected_receiver));
+ check_that!(table.unify(receiver_ty, expected_receiver));
}
IsValidCandidate::Yes
@@ -1623,13 +1682,13 @@ fn is_valid_trait_method_candidate(
}
#[tracing::instrument(skip_all, fields(name))]
-fn is_valid_impl_fn_candidate(
- table: &mut InferenceTable<'_>,
+fn is_valid_impl_fn_candidate<'db>(
+ table: &mut InferenceTable<'db>,
impl_id: ImplId,
fn_id: FunctionId,
name: Option<&Name>,
- receiver_ty: Option<&Ty>,
- self_ty: &Ty,
+ receiver_ty: Option<Ty<'db>>,
+ self_ty: Ty<'db>,
visible_from_module: Option<ModuleId>,
item_name: &Name,
) -> IsValidCandidate {
@@ -1638,148 +1697,84 @@ fn is_valid_impl_fn_candidate(
let db = table.db;
let data = db.function_signature(fn_id);
- if let Some(from_module) = visible_from_module {
- if !db.assoc_visibility(fn_id.into()).is_visible_from(db, from_module) {
- cov_mark::hit!(autoderef_candidate_not_visible);
- return IsValidCandidate::NotVisible;
- }
+ if let Some(from_module) = visible_from_module
+ && !db.assoc_visibility(fn_id.into()).is_visible_from(db, from_module)
+ {
+ cov_mark::hit!(autoderef_candidate_not_visible);
+ return IsValidCandidate::NotVisible;
}
table.run_in_snapshot(|table| {
let _p = tracing::info_span!("subst_for_def").entered();
- let impl_subst =
- TyBuilder::subst_for_def(db, impl_id, None).fill_with_inference_vars(table).build();
- let expect_self_ty = db.impl_self_ty(impl_id).substitute(Interner, &impl_subst);
+ let impl_subst = table.infer_ctxt.fresh_args_for_item(impl_id.into());
+ let expect_self_ty = db.impl_self_ty(impl_id).instantiate(table.interner(), &impl_subst);
- check_that!(table.unify(&expect_self_ty, self_ty));
+ check_that!(table.unify(expect_self_ty, self_ty));
if let Some(receiver_ty) = receiver_ty {
let _p = tracing::info_span!("check_receiver_ty").entered();
check_that!(data.has_self_param());
- let fn_subst = TyBuilder::subst_for_def(db, fn_id, Some(impl_subst.clone()))
- .fill_with_inference_vars(table)
- .build();
+ let args = table.infer_ctxt.fresh_args_for_item(fn_id.into());
let sig = db.callable_item_signature(fn_id.into());
- let expected_receiver =
- sig.map(|s| s.params()[0].clone()).substitute(Interner, &fn_subst);
+ let expected_receiver = sig
+ .map_bound(|s| s.skip_binder().inputs_and_output.as_slice()[0])
+ .instantiate(table.interner(), args);
- check_that!(table.unify(receiver_ty, &expected_receiver));
+ check_that!(table.unify(receiver_ty, expected_receiver));
}
// We need to consider the bounds on the impl to distinguish functions of the same name
// for a type.
let predicates = db.generic_predicates(impl_id.into());
- let goals = predicates.iter().map(|p| {
- let (p, b) = p
- .clone()
- .substitute(Interner, &impl_subst)
- // Skipping the inner binders is ok, as we don't handle quantified where
- // clauses yet.
- .into_value_and_skipped_binders();
- stdx::always!(b.len(Interner) == 0);
-
- p.cast::<Goal>(Interner)
- });
-
- for goal in goals.clone() {
- let in_env = InEnvironment::new(&table.trait_env.env, goal);
- let canonicalized = table.canonicalize_with_free_vars(in_env);
- let solution = table.db.trait_solve(
- table.trait_env.krate,
- table.trait_env.block,
- canonicalized.value.clone(),
- );
-
- match solution {
- Some(Solution::Unique(canonical_subst)) => {
- canonicalized.apply_solution(
- table,
- Canonical {
- binders: canonical_subst.binders,
- value: canonical_subst.value.subst,
- },
- );
- }
- Some(Solution::Ambig(Guidance::Definite(substs))) => {
- canonicalized.apply_solution(table, substs);
- }
- Some(_) => (),
- None => return IsValidCandidate::No,
- }
- }
-
- for goal in goals {
- if table.try_obligation(goal).is_none() {
- return IsValidCandidate::No;
- }
- }
-
- IsValidCandidate::Yes
- })
-}
-
-pub fn implements_trait(
- ty: &Canonical<Ty>,
- db: &dyn HirDatabase,
- env: &TraitEnvironment,
- trait_: TraitId,
-) -> bool {
- let goal = generic_implements_goal(db, env, trait_, ty);
- let solution = db.trait_solve(env.krate, env.block, goal.cast(Interner));
+ let Some(predicates) = predicates.instantiate(table.interner(), impl_subst) else {
+ return IsValidCandidate::Yes;
+ };
- solution.is_some()
-}
+ let mut ctxt = ObligationCtxt::new(&table.infer_ctxt);
-pub fn implements_trait_unique(
- ty: &Canonical<Ty>,
- db: &dyn HirDatabase,
- env: &TraitEnvironment,
- trait_: TraitId,
-) -> bool {
- let goal = generic_implements_goal(db, env, trait_, ty);
- let solution = db.trait_solve(env.krate, env.block, goal.cast(Interner));
+ ctxt.register_obligations(predicates.into_iter().map(|p| {
+ PredicateObligation::new(
+ table.interner(),
+ ObligationCause::new(),
+ table.trait_env.env,
+ p.0,
+ )
+ }));
- matches!(solution, Some(crate::Solution::Unique(_)))
+ if ctxt.try_evaluate_obligations().is_empty() {
+ IsValidCandidate::Yes
+ } else {
+ IsValidCandidate::No
+ }
+ })
}
/// This creates Substs for a trait with the given Self type and type variables
-/// for all other parameters, to query Chalk with it.
+/// for all other parameters, to query the trait solver with it.
#[tracing::instrument(skip_all)]
-fn generic_implements_goal(
- db: &dyn HirDatabase,
- env: &TraitEnvironment,
+fn generic_implements_goal_ns<'db>(
+ table: &mut InferenceTable<'db>,
trait_: TraitId,
- self_ty: &Canonical<Ty>,
-) -> Canonical<InEnvironment<super::DomainGoal>> {
- let binders = self_ty.binders.interned();
- let trait_ref = TyBuilder::trait_ref(db, trait_)
- .push(self_ty.value.clone())
- .fill_with_bound_vars(DebruijnIndex::INNERMOST, binders.len())
- .build();
-
- let kinds =
- binders.iter().cloned().chain(trait_ref.substitution.iter(Interner).skip(1).map(|it| {
- let vk = match it.data(Interner) {
- GenericArgData::Ty(_) => VariableKind::Ty(chalk_ir::TyVariableKind::General),
- GenericArgData::Lifetime(_) => VariableKind::Lifetime,
- GenericArgData::Const(c) => VariableKind::Const(c.data(Interner).ty.clone()),
- };
- WithKind::new(vk, UniverseIndex::ROOT)
- }));
- let binders = CanonicalVarKinds::from_iter(Interner, kinds);
-
- let obligation = trait_ref.cast(Interner);
- let value = InEnvironment::new(&env.env, obligation);
- Canonical { binders, value }
+ self_ty: Canonical<'db, Ty<'db>>,
+) -> Canonical<'db, Goal<'db, Predicate<'db>>> {
+ let args = table.infer_ctxt.fresh_args_for_item(SolverDefId::TraitId(trait_));
+ let self_ty = table.instantiate_canonical(self_ty);
+ let trait_ref =
+ rustc_type_ir::TraitRef::new_from_args(table.infer_ctxt.interner, trait_.into(), args)
+ .with_replaced_self_ty(table.infer_ctxt.interner, self_ty);
+ let goal = Goal::new(table.infer_ctxt.interner, table.trait_env.env, trait_ref);
+
+ table.canonicalize(goal)
}
-fn autoderef_method_receiver(
- table: &mut InferenceTable<'_>,
- ty: Ty,
-) -> Vec<(Canonical<Ty>, ReceiverAdjustments)> {
- let mut deref_chain: Vec<_> = Vec::new();
- let mut autoderef = autoderef::Autoderef::new_no_tracking(table, ty, false, true);
+fn autoderef_method_receiver<'db>(
+ table: &mut InferenceTable<'db>,
+ ty: Ty<'db>,
+) -> Vec<(Canonical<'db, Ty<'db>>, ReceiverAdjustments)> {
+ let interner = table.interner();
+ let mut deref_chain = Vec::new();
+ let mut autoderef = autoderef::Autoderef::new_no_tracking(table, ty).use_receiver_trait();
while let Some((ty, derefs)) = autoderef.next() {
deref_chain.push((
autoderef.table.canonicalize(ty),
@@ -1787,12 +1782,12 @@ fn autoderef_method_receiver(
));
}
// As a last step, we can do array unsizing (that's the only unsizing that rustc does for method receivers!)
- if let Some((TyKind::Array(parameters, _), binders, adj)) =
- deref_chain.last().map(|(ty, adj)| (ty.value.kind(Interner), ty.binders.clone(), adj))
+ if let Some((rustc_type_ir::Array(parameters, _), variables, max_universe, adj)) =
+ deref_chain.last().map(|d| (d.0.value.kind(), d.0.variables, d.0.max_universe, d.1.clone()))
{
- let unsized_ty = TyKind::Slice(parameters.clone()).intern(Interner);
+ let unsized_ty = Ty::new_slice(interner, parameters);
deref_chain.push((
- Canonical { value: unsized_ty, binders },
+ Canonical { max_universe, value: unsized_ty, variables },
ReceiverAdjustments { unsize_array: true, ..adj.clone() },
));
}