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.rs424
1 files changed, 297 insertions, 127 deletions
diff --git a/crates/hir-ty/src/method_resolution.rs b/crates/hir-ty/src/method_resolution.rs
index b22781e947..7fa3d31fe5 100644
--- a/crates/hir-ty/src/method_resolution.rs
+++ b/crates/hir-ty/src/method_resolution.rs
@@ -16,22 +16,29 @@ use hir_def::{
use hir_expand::name::Name;
use intern::sym;
use rustc_hash::{FxHashMap, FxHashSet};
+use rustc_type_ir::inherent::{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,
+ Goal, InEnvironment, Interner, Mutability, Scalar, Substitution, TraitEnvironment, TraitRef,
+ TraitRefExt, Ty, TyBuilder, TyExt, TyKind, VariableKind, WhereClause,
autoderef::{self, AutoderefKind},
db::HirDatabase,
- error_lifetime, from_chalk_trait_id, from_foreign_def_id,
+ from_chalk_trait_id, from_foreign_def_id,
infer::{Adjust, Adjustment, OverloadedDeref, PointerCast, unify::InferenceTable},
lang_items::is_box,
+ next_solver::{
+ self, SolverDefId,
+ fulfill::FulfillmentCtxt,
+ infer::DefineOpaqueTypes,
+ mapping::{ChalkToNextSolver, NextSolverToChalk},
+ },
primitive::{FloatTy, IntTy, UintTy},
to_chalk_trait_id,
+ traits::next_trait_solve_canonical_in_ctxt,
utils::all_super_traits,
};
@@ -43,6 +50,7 @@ pub enum TyFingerprint {
Slice,
Array,
Never,
+ Ref(Mutability),
RawPtr(Mutability),
Scalar(Scalar),
// These can have user-defined impls:
@@ -88,7 +96,7 @@ impl TyFingerprint {
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::Ref(mutability, _, _) => TyFingerprint::Ref(*mutability),
TyKind::Tuple(_, subst) => {
let first_ty = subst.interned().first().map(|arg| arg.assert_ty_ref(Interner));
match first_ty {
@@ -97,6 +105,11 @@ impl TyFingerprint {
}
}
TyKind::AssociatedType(_, _)
+ // 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::OpaqueType(_, _)
| TyKind::FnDef(_, _)
| TyKind::Closure(_, _)
@@ -105,14 +118,94 @@ impl TyFingerprint {
TyKind::Function(fn_ptr) => {
TyFingerprint::Function(fn_ptr.substitution.0.len(Interner) as u32)
}
- TyKind::Alias(_)
- | TyKind::Placeholder(_)
+ TyKind::Placeholder(_)
| TyKind::BoundVar(_)
| TyKind::InferenceVar(_, _)
| TyKind::Error => return None,
};
Some(fp)
}
+
+ /// Creates a TyFingerprint for looking up a trait impl.
+ pub fn for_trait_impl_ns<'db>(ty: &next_solver::Ty<'db>) -> Option<TyFingerprint> {
+ use rustc_type_ir::TyKind;
+ let fp = match (*ty).kind() {
+ TyKind::Str => TyFingerprint::Str,
+ TyKind::Never => TyFingerprint::Never,
+ TyKind::Slice(..) => TyFingerprint::Slice,
+ TyKind::Array(..) => TyFingerprint::Array,
+ TyKind::Int(int) => TyFingerprint::Scalar(Scalar::Int(match int {
+ rustc_type_ir::IntTy::Isize => IntTy::Isize,
+ rustc_type_ir::IntTy::I8 => IntTy::I8,
+ rustc_type_ir::IntTy::I16 => IntTy::I16,
+ rustc_type_ir::IntTy::I32 => IntTy::I32,
+ rustc_type_ir::IntTy::I64 => IntTy::I64,
+ rustc_type_ir::IntTy::I128 => IntTy::I128,
+ })),
+ TyKind::Uint(uint) => TyFingerprint::Scalar(Scalar::Uint(match uint {
+ rustc_type_ir::UintTy::Usize => UintTy::Usize,
+ rustc_type_ir::UintTy::U8 => UintTy::U8,
+ rustc_type_ir::UintTy::U16 => UintTy::U16,
+ rustc_type_ir::UintTy::U32 => UintTy::U32,
+ rustc_type_ir::UintTy::U64 => UintTy::U64,
+ rustc_type_ir::UintTy::U128 => UintTy::U128,
+ })),
+ TyKind::Float(float) => TyFingerprint::Scalar(Scalar::Float(match float {
+ rustc_type_ir::FloatTy::F16 => FloatTy::F16,
+ rustc_type_ir::FloatTy::F32 => FloatTy::F32,
+ rustc_type_ir::FloatTy::F64 => FloatTy::F64,
+ rustc_type_ir::FloatTy::F128 => FloatTy::F128,
+ })),
+ TyKind::Bool => TyFingerprint::Scalar(Scalar::Bool),
+ TyKind::Char => TyFingerprint::Scalar(Scalar::Char),
+ TyKind::Adt(def, _) => TyFingerprint::Adt(def.inner().id),
+ TyKind::RawPtr(.., mutability) => match mutability {
+ rustc_ast_ir::Mutability::Mut => TyFingerprint::RawPtr(Mutability::Mut),
+ rustc_ast_ir::Mutability::Not => TyFingerprint::RawPtr(Mutability::Not),
+ },
+ TyKind::Foreign(def) => TyFingerprint::ForeignType(crate::to_foreign_def_id(def.0)),
+ TyKind::Dynamic(bounds, _) => {
+ let trait_ref = bounds
+ .as_slice()
+ .iter()
+ .map(|b| (*b).skip_binder())
+ .filter_map(|b| match b {
+ rustc_type_ir::ExistentialPredicate::Trait(t) => Some(t.def_id),
+ _ => None,
+ })
+ .next()?;
+ TyFingerprint::Dyn(trait_ref.0)
+ }
+ TyKind::Ref(_, _, mutability) => match mutability {
+ rustc_ast_ir::Mutability::Mut => TyFingerprint::Ref(Mutability::Mut),
+ rustc_ast_ir::Mutability::Not => TyFingerprint::Ref(Mutability::Not),
+ },
+ TyKind::Tuple(tys) => {
+ let first_ty = tys.as_slice().iter().next();
+ match first_ty {
+ Some(ty) => return TyFingerprint::for_trait_impl_ns(ty),
+ None => TyFingerprint::Unit,
+ }
+ }
+ TyKind::FnDef(_, _)
+ | TyKind::Closure(_, _)
+ | TyKind::Coroutine(..)
+ | TyKind::CoroutineWitness(..)
+ | TyKind::Pat(..)
+ | TyKind::CoroutineClosure(..) => TyFingerprint::Unnameable,
+ TyKind::FnPtr(sig, _) => {
+ TyFingerprint::Function(sig.inputs().skip_binder().len() as u32)
+ }
+ TyKind::Alias(..)
+ | TyKind::Placeholder(_)
+ | TyKind::Bound(..)
+ | TyKind::Infer(_)
+ | TyKind::Error(_)
+ | TyKind::Param(..)
+ | TyKind::UnsafeBinder(..) => return None,
+ };
+ Some(fp)
+ }
}
pub(crate) const ALL_INT_FPS: [TyFingerprint; 12] = [
@@ -446,9 +539,9 @@ 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>,
+pub(crate) fn lookup_method<'db>(
+ db: &'db dyn HirDatabase,
+ ty: &next_solver::Canonical<'db, crate::next_solver::Ty<'db>>,
env: Arc<TraitEnvironment>,
traits_in_scope: &FxHashSet<TraitId>,
visible_from_module: VisibleFromModule,
@@ -529,18 +622,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(
+ &self,
+ table: &mut InferenceTable<'_>,
+ mut ty: Ty,
+ ) -> (Ty, Vec<Adjustment>) {
let mut adjust = Vec::new();
+ let mut autoderef = table.autoderef(ty.to_nextsolver(table.interner));
+ 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);
break;
}
- Some((kind, new_ty)) => {
- ty = new_ty.clone();
+ Some((new_ty, _)) => {
+ ty = new_ty.to_chalk(autoderef.table.interner);
let mutbl = match self.autoref {
Some(AutorefOrPtrAdjustment::Autoref(m)) => Some(m),
Some(AutorefOrPtrAdjustment::ToConstPtr) => Some(Mutability::Not),
@@ -548,11 +646,11 @@ 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.clone(),
});
}
}
@@ -610,9 +708,9 @@ 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,
+pub(crate) fn iterate_method_candidates<'db, T>(
+ ty: &next_solver::Canonical<'db, crate::next_solver::Ty<'db>>,
+ db: &'db dyn HirDatabase,
env: Arc<TraitEnvironment>,
traits_in_scope: &FxHashSet<TraitId>,
visible_from_module: VisibleFromModule,
@@ -807,11 +905,17 @@ fn find_matching_impl(
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)))
+ .map(|b| -> Goal { b.cast(Interner) });
+ for goal in wcs {
+ if table.try_obligation(goal.clone()).no_solution() {
+ return None;
+ }
+ table.register_obligation(goal.to_nextsolver(table.interner));
+ }
+ Some((
+ impl_.impl_items(db),
+ table.resolve_completely::<_, crate::next_solver::GenericArgs<'_>>(impl_substs),
+ ))
})
})
}
@@ -956,9 +1060,9 @@ pub fn check_orphan_rules(db: &dyn HirDatabase, impl_: ImplId) -> bool {
is_not_orphan
}
-pub fn iterate_path_candidates(
- ty: &Canonical<Ty>,
- db: &dyn HirDatabase,
+pub fn iterate_path_candidates<'db>(
+ ty: &next_solver::Canonical<'db, crate::next_solver::Ty<'db>>,
+ db: &'db dyn HirDatabase,
env: Arc<TraitEnvironment>,
traits_in_scope: &FxHashSet<TraitId>,
visible_from_module: VisibleFromModule,
@@ -978,9 +1082,9 @@ pub fn iterate_path_candidates(
)
}
-pub fn iterate_method_candidates_dyn(
- ty: &Canonical<Ty>,
- db: &dyn HirDatabase,
+pub fn iterate_method_candidates_dyn<'db>(
+ ty: &next_solver::Canonical<'db, crate::next_solver::Ty<'db>>,
+ db: &'db dyn HirDatabase,
env: Arc<TraitEnvironment>,
traits_in_scope: &FxHashSet<TraitId>,
visible_from_module: VisibleFromModule,
@@ -1018,7 +1122,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_ns(*ty);
let deref_chain = autoderef_method_receiver(&mut table, ty);
deref_chain.into_iter().try_for_each(|(receiver_ty, adj)| {
@@ -1049,19 +1153,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: next_solver::Canonical<'db, crate::next_solver::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 +1177,27 @@ fn iterate_method_candidates_with_autoref(
};
let mut maybe_reborrowed = first_adjustment.clone();
- if let Some((_, _, m)) = receiver_ty.value.as_reference() {
+ if let rustc_type_ir::TyKind::Ref(_, _, m) = receiver_ty.value.kind() {
+ let m = match m {
+ rustc_ast_ir::Mutability::Mut => chalk_ir::Mutability::Mut,
+ rustc_ast_ir::Mutability::Not => chalk_ir::Mutability::Not,
+ };
// 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(),
+ let refed = next_solver::Canonical {
+ max_universe: receiver_ty.max_universe,
+ variables: receiver_ty.variables,
+ value: next_solver::Ty::new_ref(
+ interner,
+ next_solver::Region::error(interner),
+ receiver_ty.value,
+ rustc_ast_ir::Mutability::Not,
+ ),
};
iterate_method_candidates_by_receiver(
@@ -1095,10 +1205,15 @@ fn iterate_method_candidates_with_autoref(
first_adjustment.with_autoref(AutorefOrPtrAdjustment::Autoref(Mutability::Not)),
)?;
- let ref_muted = Canonical {
- value: TyKind::Ref(Mutability::Mut, error_lifetime(), receiver_ty.value.clone())
- .intern(Interner),
- binders: receiver_ty.binders.clone(),
+ let ref_muted = next_solver::Canonical {
+ max_universe: receiver_ty.max_universe,
+ variables: receiver_ty.variables,
+ value: next_solver::Ty::new_ref(
+ interner,
+ next_solver::Region::error(interner),
+ receiver_ty.value,
+ rustc_ast_ir::Mutability::Mut,
+ ),
};
iterate_method_candidates_by_receiver(
@@ -1106,10 +1221,13 @@ 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 rustc_type_ir::TyKind::RawPtr(ty, rustc_ast_ir::Mutability::Mut) =
+ receiver_ty.value.kind()
+ {
+ let const_ptr_ty = rustc_type_ir::Canonical {
+ max_universe: rustc_type_ir::UniverseIndex::ZERO,
+ value: next_solver::Ty::new_ptr(interner, ty, rustc_ast_ir::Mutability::Not),
+ variables: receiver_ty.variables,
};
iterate_method_candidates_by_receiver(
const_ptr_ty,
@@ -1160,30 +1278,35 @@ 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: next_solver::Canonical<'db, crate::next_solver::Ty<'db>>,
receiver_adjustments: ReceiverAdjustments,
traits_in_scope: &FxHashSet<TraitId>,
visible_from_module: VisibleFromModule,
name: Option<&Name>,
callback: &mut dyn MethodCandidateCallback,
) -> ControlFlow<()> {
- let receiver_ty = table.instantiate_canonical(receiver_ty);
+ let interner = table.interner;
+ let receiver_ty = table.instantiate_canonical_ns(receiver_ty);
+ let receiver_ty: crate::Ty = receiver_ty.to_chalk(interner);
// We're looking for methods with *receiver* type receiver_ty. These could
// 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);
+ autoderef::Autoderef::new_no_tracking(table, receiver_ty.to_nextsolver(interner))
+ .include_raw_pointers()
+ .use_receiver_trait();
while let Some((self_ty, _)) = autoderef.next() {
iterate_inherent_methods(
- &self_ty,
+ &self_ty.to_chalk(interner),
autoderef.table,
name,
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)
},
@@ -1193,20 +1316,24 @@ fn iterate_method_candidates_by_receiver(
})?;
table.run_in_snapshot(|table| {
let mut autoderef =
- autoderef::Autoderef::new_no_tracking(table, receiver_ty.clone(), true, true);
+ autoderef::Autoderef::new_no_tracking(table, receiver_ty.to_nextsolver(interner))
+ .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(), crate::next_solver::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.to_chalk(interner),
autoderef.table,
traits_in_scope,
name,
Some(&receiver_ty),
Some(receiver_adjustments.clone()),
+ LookupMode::MethodCall,
&mut |adjustments, item, is_visible| {
callback.on_trait_method(adjustments, item, is_visible)
},
@@ -1217,9 +1344,9 @@ 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,
+fn iterate_method_candidates_for_self_ty<'db>(
+ self_ty: &next_solver::Canonical<'db, crate::next_solver::Ty<'db>>,
+ db: &'db dyn HirDatabase,
env: Arc<TraitEnvironment>,
traits_in_scope: &FxHashSet<TraitId>,
visible_from_module: VisibleFromModule,
@@ -1227,7 +1354,7 @@ fn iterate_method_candidates_for_self_ty(
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_ns(*self_ty).to_chalk(table.interner);
iterate_inherent_methods(
&self_ty,
&mut table,
@@ -1235,6 +1362,7 @@ fn iterate_method_candidates_for_self_ty(
None,
None,
visible_from_module,
+ LookupMode::Path,
&mut |adjustments, item, is_visible| {
callback.on_inherent_method(adjustments, item, is_visible)
},
@@ -1246,6 +1374,7 @@ fn iterate_method_candidates_for_self_ty(
name,
None,
None,
+ LookupMode::Path,
&mut |adjustments, item, is_visible| {
callback.on_trait_method(adjustments, item, is_visible)
},
@@ -1260,12 +1389,13 @@ fn iterate_trait_method_candidates(
name: Option<&Name>,
receiver_ty: Option<&Ty>,
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.clone().to_nextsolver(table.interner));
+ let TraitEnvironment { krate, .. } = *table.trait_env;
'traits: for &t in traits_in_scope {
let data = db.trait_signature(t);
@@ -1305,15 +1435,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;
}
}
@@ -1332,6 +1469,7 @@ fn iterate_inherent_methods(
receiver_ty: Option<&Ty>,
receiver_adjustments: Option<ReceiverAdjustments>,
visible_from_module: VisibleFromModule,
+ mode: LookupMode,
callback: &mut dyn FnMut(ReceiverAdjustments, AssocItemId, bool) -> ControlFlow<()>,
) -> ControlFlow<()> {
let db = table.db;
@@ -1355,6 +1493,7 @@ fn iterate_inherent_methods(
receiver_adjustments.clone(),
callback,
traits,
+ mode,
)?;
}
TyKind::Dyn(_) => {
@@ -1368,6 +1507,7 @@ fn iterate_inherent_methods(
receiver_adjustments.clone(),
callback,
traits.into_iter(),
+ mode,
)?;
}
}
@@ -1426,6 +1566,7 @@ fn iterate_inherent_methods(
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 +1580,7 @@ fn iterate_inherent_methods(
receiver_ty,
item,
self_ty,
+ mode,
) {
IsValidCandidate::Yes => true,
IsValidCandidate::NotVisible => false,
@@ -1485,21 +1627,17 @@ 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: next_solver::Canonical<'db, next_solver::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 ty = table.instantiate_canonical_ns(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(db, &table.trait_env, index_trait, &ty);
+ 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);
}
}
@@ -1579,6 +1717,7 @@ fn is_valid_trait_method_candidate(
receiver_ty: Option<&Ty>,
item: AssocItemId,
self_ty: &Ty,
+ mode: LookupMode,
) -> IsValidCandidate {
let db = table.db;
match item {
@@ -1606,6 +1745,36 @@ fn is_valid_trait_method_candidate(
let expected_receiver =
sig.map(|s| s.params()[0].clone()).substitute(Interner, &fn_subst);
+ // 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(
+ &next_solver::infer::traits::ObligationCause::dummy(),
+ table.trait_env.env.to_nextsolver(table.interner),
+ )
+ .relate(
+ DefineOpaqueTypes::No,
+ expected_receiver.to_nextsolver(table.interner),
+ variance,
+ receiver_ty.to_nextsolver(table.interner),
+ );
+ let Ok(infer_ok) = res else {
+ return IsValidCandidate::No;
+ };
+
+ if !infer_ok.obligations.is_empty() {
+ let mut ctxt = FulfillmentCtxt::new(&table.infer_ctxt);
+ for pred in infer_ok.into_obligations() {
+ ctxt.register_predicate_obligation(&table.infer_ctxt, pred);
+ }
+ // FIXME: Are we doing this correctly? Probably better to follow rustc more closely.
+ check_that!(ctxt.select_where_possible(&table.infer_ctxt).is_empty());
+ }
+
check_that!(table.unify(receiver_ty, &expected_receiver));
}
@@ -1683,34 +1852,16 @@ fn is_valid_impl_fn_candidate(
});
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,
- },
- );
+ match table.solve_obligation(goal) {
+ Ok(_) => {}
+ Err(_) => {
+ return IsValidCandidate::No;
}
- 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() {
+ if table.try_obligation(goal).no_solution() {
return IsValidCandidate::No;
}
}
@@ -1726,9 +1877,7 @@ pub fn implements_trait(
trait_: TraitId,
) -> bool {
let goal = generic_implements_goal(db, env, trait_, ty);
- let solution = db.trait_solve(env.krate, env.block, goal.cast(Interner));
-
- solution.is_some()
+ !db.trait_solve(env.krate, env.block, goal.cast(Interner)).no_solution()
}
pub fn implements_trait_unique(
@@ -1738,9 +1887,7 @@ pub fn implements_trait_unique(
trait_: TraitId,
) -> bool {
let goal = generic_implements_goal(db, env, trait_, ty);
- let solution = db.trait_solve(env.krate, env.block, goal.cast(Interner));
-
- matches!(solution, Some(crate::Solution::Unique(_)))
+ db.trait_solve(env.krate, env.block, goal.cast(Interner)).certain()
}
/// This creates Substs for a trait with the given Self type and type variables
@@ -1774,12 +1921,35 @@ fn generic_implements_goal(
Canonical { binders, value }
}
-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);
+/// This creates Substs for a trait with the given Self type and type variables
+/// for all other parameters, to query the trait solver with it.
+#[tracing::instrument(skip_all)]
+fn generic_implements_goal_ns<'db>(
+ table: &mut InferenceTable<'db>,
+ trait_: TraitId,
+ self_ty: next_solver::Canonical<'db, crate::next_solver::Ty<'db>>,
+) -> next_solver::Canonical<'db, next_solver::Goal<'db, crate::next_solver::Predicate<'db>>> {
+ let args = table.infer_ctxt.fresh_args_for_item(SolverDefId::TraitId(trait_));
+ let self_ty = table.instantiate_canonical_ns(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 = next_solver::Goal::new(
+ table.infer_ctxt.interner,
+ table.trait_env.env.to_nextsolver(table.infer_ctxt.interner),
+ trait_ref,
+ );
+
+ table.canonicalize(goal)
+}
+
+fn autoderef_method_receiver<'db>(
+ table: &mut InferenceTable<'db>,
+ ty: next_solver::Ty<'db>,
+) -> Vec<(next_solver::Canonical<'db, crate::next_solver::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 +1957,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 = next_solver::Ty::new_slice(interner, parameters);
deref_chain.push((
- Canonical { value: unsized_ty, binders },
+ next_solver::Canonical { max_universe, value: unsized_ty, variables },
ReceiverAdjustments { unsize_array: true, ..adj.clone() },
));
}