Remove some unnecessary cloning in method_resolution

This commit is contained in:
Lukas Wirth 2024-03-04 16:04:19 +01:00
parent 593156a357
commit d21f88883b
8 changed files with 76 additions and 78 deletions

View file

@ -105,6 +105,10 @@ anyhow = "1.0.75"
arrayvec = "0.7.4" arrayvec = "0.7.4"
bitflags = "2.4.1" bitflags = "2.4.1"
cargo_metadata = "0.18.1" cargo_metadata = "0.18.1"
chalk-solve = { version = "0.96.0", default-features = false }
chalk-ir = "0.96.0"
chalk-recursive = { version = "0.96.0", default-features = false }
chalk-derive = "0.96.0"
command-group = "2.0.1" command-group = "2.0.1"
crossbeam-channel = "0.5.8" crossbeam-channel = "0.5.8"
dissimilar = "1.0.7" dissimilar = "1.0.7"

View file

@ -23,10 +23,10 @@ oorandom = "11.1.3"
tracing.workspace = true tracing.workspace = true
rustc-hash.workspace = true rustc-hash.workspace = true
scoped-tls = "1.0.0" scoped-tls = "1.0.0"
chalk-solve = { version = "0.96.0", default-features = false } chalk-solve.workspace = true
chalk-ir = "0.96.0" chalk-ir.workspace = true
chalk-recursive = { version = "0.96.0", default-features = false } chalk-recursive.workspace = true
chalk-derive = "0.96.0" chalk-derive.workspace = true
la-arena.workspace = true la-arena.workspace = true
once_cell = "1.17.0" once_cell = "1.17.0"
triomphe.workspace = true triomphe.workspace = true

View file

@ -647,7 +647,7 @@ impl InferenceTable<'_> {
let goal: InEnvironment<DomainGoal> = let goal: InEnvironment<DomainGoal> =
InEnvironment::new(&self.trait_env.env, coerce_unsized_tref.cast(Interner)); InEnvironment::new(&self.trait_env.env, coerce_unsized_tref.cast(Interner));
let canonicalized = self.canonicalize(goal); let canonicalized = self.canonicalize_with_free_vars(goal);
// FIXME: rustc's coerce_unsized is more specialized -- it only tries to // FIXME: rustc's coerce_unsized is more specialized -- it only tries to
// solve `CoerceUnsized` and `Unsize` goals at this point and leaves the // solve `CoerceUnsized` and `Unsize` goals at this point and leaves the

View file

@ -774,7 +774,7 @@ impl InferenceContext<'_> {
let receiver_adjustments = method_resolution::resolve_indexing_op( let receiver_adjustments = method_resolution::resolve_indexing_op(
self.db, self.db,
self.table.trait_env.clone(), self.table.trait_env.clone(),
canonicalized.value, canonicalized,
index_trait, index_trait,
); );
let (self_ty, mut adj) = receiver_adjustments let (self_ty, mut adj) = receiver_adjustments
@ -1559,7 +1559,7 @@ impl InferenceContext<'_> {
let canonicalized_receiver = self.canonicalize(receiver_ty.clone()); let canonicalized_receiver = self.canonicalize(receiver_ty.clone());
let resolved = method_resolution::lookup_method( let resolved = method_resolution::lookup_method(
self.db, self.db,
&canonicalized_receiver.value, &canonicalized_receiver,
self.table.trait_env.clone(), self.table.trait_env.clone(),
self.get_traits_in_scope().as_ref().left_or_else(|&it| it), self.get_traits_in_scope().as_ref().left_or_else(|&it| it),
VisibleFromModule::Filter(self.resolver.module()), VisibleFromModule::Filter(self.resolver.module()),
@ -1608,7 +1608,7 @@ impl InferenceContext<'_> {
let resolved = method_resolution::lookup_method( let resolved = method_resolution::lookup_method(
self.db, self.db,
&canonicalized_receiver.value, &canonicalized_receiver,
self.table.trait_env.clone(), self.table.trait_env.clone(),
self.get_traits_in_scope().as_ref().left_or_else(|&it| it), self.get_traits_in_scope().as_ref().left_or_else(|&it| it),
VisibleFromModule::Filter(self.resolver.module()), VisibleFromModule::Filter(self.resolver.module()),
@ -1641,7 +1641,7 @@ impl InferenceContext<'_> {
}; };
let assoc_func_with_same_name = method_resolution::iterate_method_candidates( let assoc_func_with_same_name = method_resolution::iterate_method_candidates(
&canonicalized_receiver.value, &canonicalized_receiver,
self.db, self.db,
self.table.trait_env.clone(), self.table.trait_env.clone(),
self.get_traits_in_scope().as_ref().left_or_else(|&it| it), self.get_traits_in_scope().as_ref().left_or_else(|&it| it),

View file

@ -321,7 +321,7 @@ impl InferenceContext<'_> {
let mut not_visible = None; let mut not_visible = None;
let res = method_resolution::iterate_method_candidates( let res = method_resolution::iterate_method_candidates(
&canonical_ty.value, &canonical_ty,
self.db, self.db,
self.table.trait_env.clone(), self.table.trait_env.clone(),
self.get_traits_in_scope().as_ref().left_or_else(|&it| it), self.get_traits_in_scope().as_ref().left_or_else(|&it| it),

View file

@ -23,12 +23,9 @@ use crate::{
}; };
impl InferenceContext<'_> { impl InferenceContext<'_> {
pub(super) fn canonicalize<T: TypeFoldable<Interner> + HasInterner<Interner = Interner>>( pub(super) fn canonicalize<T>(&mut self, t: T) -> Canonical<T>
&mut self,
t: T,
) -> Canonicalized<T>
where where
T: HasInterner<Interner = Interner>, T: TypeFoldable<Interner> + HasInterner<Interner = Interner>,
{ {
self.table.canonicalize(t) self.table.canonicalize(t)
} }
@ -128,14 +125,14 @@ impl<T: HasInterner<Interner = Interner>> Canonicalized<T> {
}), }),
); );
for (i, v) in solution.value.iter(Interner).enumerate() { for (i, v) in solution.value.iter(Interner).enumerate() {
let var = self.free_vars[i].clone(); let var = &self.free_vars[i];
if let Some(ty) = v.ty(Interner) { if let Some(ty) = v.ty(Interner) {
// eagerly replace projections in the type; we may be getting types // eagerly replace projections in the type; we may be getting types
// e.g. from where clauses where this hasn't happened yet // e.g. from where clauses where this hasn't happened yet
let ty = ctx.normalize_associated_types_in(new_vars.apply(ty.clone(), Interner)); let ty = ctx.normalize_associated_types_in(new_vars.apply(ty.clone(), Interner));
ctx.unify(var.assert_ty_ref(Interner), &ty); ctx.unify(var.assert_ty_ref(Interner), &ty);
} else { } else {
let _ = ctx.try_unify(&var, &new_vars.apply(v.clone(), Interner)); let _ = ctx.try_unify(var, &new_vars.apply(v.clone(), Interner));
} }
} }
} }
@ -307,12 +304,9 @@ impl<'a> InferenceTable<'a> {
.intern(Interner) .intern(Interner)
} }
pub(crate) fn canonicalize<T: TypeFoldable<Interner> + HasInterner<Interner = Interner>>( pub(crate) fn canonicalize_with_free_vars<T>(&mut self, t: T) -> Canonicalized<T>
&mut self,
t: T,
) -> Canonicalized<T>
where where
T: HasInterner<Interner = Interner>, T: TypeFoldable<Interner> + HasInterner<Interner = Interner>,
{ {
// try to resolve obligations before canonicalizing, since this might // try to resolve obligations before canonicalizing, since this might
// result in new knowledge about variables // result in new knowledge about variables
@ -326,6 +320,16 @@ impl<'a> InferenceTable<'a> {
Canonicalized { value: result.quantified, free_vars } Canonicalized { value: result.quantified, free_vars }
} }
pub(crate) fn canonicalize<T>(&mut self, t: T) -> Canonical<T>
where
T: TypeFoldable<Interner> + HasInterner<Interner = Interner>,
{
// try to resolve obligations before canonicalizing, since this might
// result in new knowledge about variables
self.resolve_obligations_as_possible();
self.var_unification_table.canonicalize(Interner, t).quantified
}
/// Recurses through the given type, normalizing associated types mentioned /// Recurses through the given type, normalizing associated types mentioned
/// in it by replacing them by type variables and registering obligations to /// in it by replacing them by type variables and registering obligations to
/// resolve later. This should be done once for every type we get from some /// resolve later. This should be done once for every type we get from some
@ -541,7 +545,7 @@ impl<'a> InferenceTable<'a> {
Err(_) => return false, Err(_) => return false,
}; };
result.goals.iter().all(|goal| { result.goals.iter().all(|goal| {
let canonicalized = self.canonicalize(goal.clone()); let canonicalized = self.canonicalize_with_free_vars(goal.clone());
self.try_resolve_obligation(&canonicalized).is_some() self.try_resolve_obligation(&canonicalized).is_some()
}) })
} }
@ -602,7 +606,7 @@ impl<'a> InferenceTable<'a> {
let in_env = InEnvironment::new(&self.trait_env.env, goal); let in_env = InEnvironment::new(&self.trait_env.env, goal);
let canonicalized = self.canonicalize(in_env); let canonicalized = self.canonicalize(in_env);
self.db.trait_solve(self.trait_env.krate, self.trait_env.block, canonicalized.value) self.db.trait_solve(self.trait_env.krate, self.trait_env.block, canonicalized)
} }
pub(crate) fn register_obligation(&mut self, goal: Goal) { pub(crate) fn register_obligation(&mut self, goal: Goal) {
@ -611,7 +615,7 @@ impl<'a> InferenceTable<'a> {
} }
fn register_obligation_in_env(&mut self, goal: InEnvironment<Goal>) { fn register_obligation_in_env(&mut self, goal: InEnvironment<Goal>) {
let canonicalized = self.canonicalize(goal); let canonicalized = self.canonicalize_with_free_vars(goal);
let solution = self.try_resolve_obligation(&canonicalized); let solution = self.try_resolve_obligation(&canonicalized);
if matches!(solution, Some(Solution::Ambig(_))) { if matches!(solution, Some(Solution::Ambig(_))) {
self.pending_obligations.push(canonicalized); self.pending_obligations.push(canonicalized);
@ -824,11 +828,7 @@ impl<'a> InferenceTable<'a> {
environment: trait_env.clone(), environment: trait_env.clone(),
}; };
let canonical = self.canonicalize(obligation.clone()); let canonical = self.canonicalize(obligation.clone());
if self if self.db.trait_solve(krate, self.trait_env.block, canonical.cast(Interner)).is_some() {
.db
.trait_solve(krate, self.trait_env.block, canonical.value.cast(Interner))
.is_some()
{
self.register_obligation(obligation.goal); self.register_obligation(obligation.goal);
let return_ty = self.normalize_projection_ty(projection); let return_ty = self.normalize_projection_ty(projection);
for fn_x in [FnTrait::Fn, FnTrait::FnMut, FnTrait::FnOnce] { for fn_x in [FnTrait::Fn, FnTrait::FnMut, FnTrait::FnOnce] {
@ -841,7 +841,7 @@ impl<'a> InferenceTable<'a> {
let canonical = self.canonicalize(obligation.clone()); let canonical = self.canonicalize(obligation.clone());
if self if self
.db .db
.trait_solve(krate, self.trait_env.block, canonical.value.cast(Interner)) .trait_solve(krate, self.trait_env.block, canonical.cast(Interner))
.is_some() .is_some()
{ {
return Some((fn_x, arg_tys, return_ty)); return Some((fn_x, arg_tys, return_ty));

View file

@ -973,7 +973,7 @@ pub fn iterate_method_candidates_dyn(
deref_chain.into_iter().try_for_each(|(receiver_ty, adj)| { deref_chain.into_iter().try_for_each(|(receiver_ty, adj)| {
iterate_method_candidates_with_autoref( iterate_method_candidates_with_autoref(
&mut table, &mut table,
&receiver_ty, receiver_ty,
adj, adj,
traits_in_scope, traits_in_scope,
visible_from_module, visible_from_module,
@ -1000,7 +1000,7 @@ pub fn iterate_method_candidates_dyn(
#[tracing::instrument(skip_all, fields(name = ?name))] #[tracing::instrument(skip_all, fields(name = ?name))]
fn iterate_method_candidates_with_autoref( fn iterate_method_candidates_with_autoref(
table: &mut InferenceTable<'_>, table: &mut InferenceTable<'_>,
receiver_ty: &Canonical<Ty>, receiver_ty: Canonical<Ty>,
first_adjustment: ReceiverAdjustments, first_adjustment: ReceiverAdjustments,
traits_in_scope: &FxHashSet<TraitId>, traits_in_scope: &FxHashSet<TraitId>,
visible_from_module: VisibleFromModule, visible_from_module: VisibleFromModule,
@ -1031,7 +1031,7 @@ fn iterate_method_candidates_with_autoref(
maybe_reborrowed.autoderefs += 1; maybe_reborrowed.autoderefs += 1;
} }
iterate_method_candidates_by_receiver(receiver_ty, maybe_reborrowed)?; iterate_method_candidates_by_receiver(receiver_ty.clone(), maybe_reborrowed)?;
let refed = Canonical { let refed = Canonical {
value: TyKind::Ref(Mutability::Not, static_lifetime(), receiver_ty.value.clone()) value: TyKind::Ref(Mutability::Not, static_lifetime(), receiver_ty.value.clone())
@ -1039,7 +1039,7 @@ fn iterate_method_candidates_with_autoref(
binders: receiver_ty.binders.clone(), binders: receiver_ty.binders.clone(),
}; };
iterate_method_candidates_by_receiver(&refed, first_adjustment.with_autoref(Mutability::Not))?; iterate_method_candidates_by_receiver(refed, first_adjustment.with_autoref(Mutability::Not))?;
let ref_muted = Canonical { let ref_muted = Canonical {
value: TyKind::Ref(Mutability::Mut, static_lifetime(), receiver_ty.value.clone()) value: TyKind::Ref(Mutability::Mut, static_lifetime(), receiver_ty.value.clone())
@ -1047,16 +1047,13 @@ fn iterate_method_candidates_with_autoref(
binders: receiver_ty.binders.clone(), binders: receiver_ty.binders.clone(),
}; };
iterate_method_candidates_by_receiver( iterate_method_candidates_by_receiver(ref_muted, first_adjustment.with_autoref(Mutability::Mut))
&ref_muted,
first_adjustment.with_autoref(Mutability::Mut),
)
} }
#[tracing::instrument(skip_all, fields(name = ?name))] #[tracing::instrument(skip_all, fields(name = ?name))]
fn iterate_method_candidates_by_receiver( fn iterate_method_candidates_by_receiver(
table: &mut InferenceTable<'_>, table: &mut InferenceTable<'_>,
receiver_ty: &Canonical<Ty>, receiver_ty: Canonical<Ty>,
receiver_adjustments: ReceiverAdjustments, receiver_adjustments: ReceiverAdjustments,
traits_in_scope: &FxHashSet<TraitId>, traits_in_scope: &FxHashSet<TraitId>,
visible_from_module: VisibleFromModule, visible_from_module: VisibleFromModule,
@ -1143,9 +1140,9 @@ fn iterate_trait_method_candidates(
callback: &mut dyn FnMut(ReceiverAdjustments, AssocItemId, bool) -> ControlFlow<()>, callback: &mut dyn FnMut(ReceiverAdjustments, AssocItemId, bool) -> ControlFlow<()>,
) -> ControlFlow<()> { ) -> ControlFlow<()> {
let db = table.db; let db = table.db;
let env = table.trait_env.clone();
let canonical_self_ty = table.canonicalize(self_ty.clone()).value; let canonical_self_ty = table.canonicalize(self_ty.clone());
let TraitEnvironment { krate, block, .. } = *table.trait_env;
'traits: for &t in traits_in_scope { 'traits: for &t in traits_in_scope {
let data = db.trait_data(t); let data = db.trait_data(t);
@ -1160,7 +1157,7 @@ fn iterate_trait_method_candidates(
{ {
// FIXME: this should really be using the edition of the method name's span, in case it // FIXME: this should really be using the edition of the method name's span, in case it
// comes from a macro // comes from a macro
if db.crate_graph()[env.krate].edition < Edition::Edition2021 { if db.crate_graph()[krate].edition < Edition::Edition2021 {
continue; continue;
} }
} }
@ -1179,8 +1176,8 @@ fn iterate_trait_method_candidates(
IsValidCandidate::No => continue, IsValidCandidate::No => continue,
}; };
if !known_implemented { if !known_implemented {
let goal = generic_implements_goal(db, env.clone(), t, &canonical_self_ty); let goal = generic_implements_goal(db, &table.trait_env, t, &canonical_self_ty);
if db.trait_solve(env.krate, env.block, goal.cast(Interner)).is_none() { if db.trait_solve(krate, block, goal.cast(Interner)).is_none() {
continue 'traits; continue 'traits;
} }
} }
@ -1361,7 +1358,7 @@ pub(crate) fn resolve_indexing_op(
let ty = table.instantiate_canonical(ty); let ty = table.instantiate_canonical(ty);
let deref_chain = autoderef_method_receiver(&mut table, ty); let deref_chain = autoderef_method_receiver(&mut table, ty);
for (ty, adj) in deref_chain { for (ty, adj) in deref_chain {
let goal = generic_implements_goal(db, table.trait_env.clone(), index_trait, &ty); let goal = generic_implements_goal(db, &table.trait_env, index_trait, &ty);
if db if db
.trait_solve(table.trait_env.krate, table.trait_env.block, goal.cast(Interner)) .trait_solve(table.trait_env.krate, table.trait_env.block, goal.cast(Interner))
.is_some() .is_some()
@ -1544,7 +1541,7 @@ fn is_valid_impl_fn_candidate(
for goal in goals.clone() { for goal in goals.clone() {
let in_env = InEnvironment::new(&table.trait_env.env, goal); let in_env = InEnvironment::new(&table.trait_env.env, goal);
let canonicalized = table.canonicalize(in_env); let canonicalized = table.canonicalize_with_free_vars(in_env);
let solution = table.db.trait_solve( let solution = table.db.trait_solve(
table.trait_env.krate, table.trait_env.krate,
table.trait_env.block, table.trait_env.block,
@ -1582,10 +1579,10 @@ fn is_valid_impl_fn_candidate(
pub fn implements_trait( pub fn implements_trait(
ty: &Canonical<Ty>, ty: &Canonical<Ty>,
db: &dyn HirDatabase, db: &dyn HirDatabase,
env: Arc<TraitEnvironment>, env: &TraitEnvironment,
trait_: TraitId, trait_: TraitId,
) -> bool { ) -> bool {
let goal = generic_implements_goal(db, env.clone(), trait_, ty); let goal = generic_implements_goal(db, env, trait_, ty);
let solution = db.trait_solve(env.krate, env.block, goal.cast(Interner)); let solution = db.trait_solve(env.krate, env.block, goal.cast(Interner));
solution.is_some() solution.is_some()
@ -1594,10 +1591,10 @@ pub fn implements_trait(
pub fn implements_trait_unique( pub fn implements_trait_unique(
ty: &Canonical<Ty>, ty: &Canonical<Ty>,
db: &dyn HirDatabase, db: &dyn HirDatabase,
env: Arc<TraitEnvironment>, env: &TraitEnvironment,
trait_: TraitId, trait_: TraitId,
) -> bool { ) -> bool {
let goal = generic_implements_goal(db, env.clone(), trait_, ty); let goal = generic_implements_goal(db, env, trait_, ty);
let solution = db.trait_solve(env.krate, env.block, goal.cast(Interner)); let solution = db.trait_solve(env.krate, env.block, goal.cast(Interner));
matches!(solution, Some(crate::Solution::Unique(_))) matches!(solution, Some(crate::Solution::Unique(_)))
@ -1608,32 +1605,34 @@ pub fn implements_trait_unique(
#[tracing::instrument(skip_all)] #[tracing::instrument(skip_all)]
fn generic_implements_goal( fn generic_implements_goal(
db: &dyn HirDatabase, db: &dyn HirDatabase,
env: Arc<TraitEnvironment>, env: &TraitEnvironment,
trait_: TraitId, trait_: TraitId,
self_ty: &Canonical<Ty>, self_ty: &Canonical<Ty>,
) -> Canonical<InEnvironment<super::DomainGoal>> { ) -> Canonical<InEnvironment<super::DomainGoal>> {
let mut kinds = self_ty.binders.interned().to_vec(); let binders = self_ty.binders.interned();
let trait_ref = TyBuilder::trait_ref(db, trait_) let trait_ref = TyBuilder::trait_ref(db, trait_)
.push(self_ty.value.clone()) .push(self_ty.value.clone())
.fill_with_bound_vars(DebruijnIndex::INNERMOST, kinds.len()) .fill_with_bound_vars(DebruijnIndex::INNERMOST, binders.len())
.build(); .build();
kinds.extend(trait_ref.substitution.iter(Interner).skip(1).map(|it| {
let vk = match it.data(Interner) { let kinds =
chalk_ir::GenericArgData::Ty(_) => { binders.iter().cloned().chain(trait_ref.substitution.iter(Interner).skip(1).map(|it| {
chalk_ir::VariableKind::Ty(chalk_ir::TyVariableKind::General) let vk = match it.data(Interner) {
} chalk_ir::GenericArgData::Ty(_) => {
chalk_ir::GenericArgData::Lifetime(_) => chalk_ir::VariableKind::Lifetime, chalk_ir::VariableKind::Ty(chalk_ir::TyVariableKind::General)
chalk_ir::GenericArgData::Const(c) => { }
chalk_ir::VariableKind::Const(c.data(Interner).ty.clone()) chalk_ir::GenericArgData::Lifetime(_) => chalk_ir::VariableKind::Lifetime,
} chalk_ir::GenericArgData::Const(c) => {
}; chalk_ir::VariableKind::Const(c.data(Interner).ty.clone())
chalk_ir::WithKind::new(vk, UniverseIndex::ROOT) }
})); };
chalk_ir::WithKind::new(vk, UniverseIndex::ROOT)
}));
let binders = CanonicalVarKinds::from_iter(Interner, kinds);
let obligation = trait_ref.cast(Interner); let obligation = trait_ref.cast(Interner);
Canonical { let value = InEnvironment::new(&env.env, obligation);
binders: CanonicalVarKinds::from_iter(Interner, kinds), Canonical { binders, value }
value: InEnvironment::new(&env.env, obligation),
}
} }
fn autoderef_method_receiver( fn autoderef_method_receiver(
@ -1644,7 +1643,7 @@ fn autoderef_method_receiver(
let mut autoderef = autoderef::Autoderef::new(table, ty, false); let mut autoderef = autoderef::Autoderef::new(table, ty, false);
while let Some((ty, derefs)) = autoderef.next() { while let Some((ty, derefs)) = autoderef.next() {
deref_chain.push(( deref_chain.push((
autoderef.table.canonicalize(ty).value, autoderef.table.canonicalize(ty),
ReceiverAdjustments { autoref: None, autoderefs: derefs, unsize_array: false }, ReceiverAdjustments { autoref: None, autoderefs: derefs, unsize_array: false },
)); ));
} }

View file

@ -4025,7 +4025,7 @@ impl Type {
let canonical_ty = let canonical_ty =
Canonical { value: self.ty.clone(), binders: CanonicalVarKinds::empty(Interner) }; Canonical { value: self.ty.clone(), binders: CanonicalVarKinds::empty(Interner) };
method_resolution::implements_trait(&canonical_ty, db, self.env.clone(), trait_) method_resolution::implements_trait(&canonical_ty, db, &self.env, trait_)
} }
/// Checks that particular type `ty` implements `std::ops::FnOnce`. /// Checks that particular type `ty` implements `std::ops::FnOnce`.
@ -4040,12 +4040,7 @@ impl Type {
let canonical_ty = let canonical_ty =
Canonical { value: self.ty.clone(), binders: CanonicalVarKinds::empty(Interner) }; Canonical { value: self.ty.clone(), binders: CanonicalVarKinds::empty(Interner) };
method_resolution::implements_trait_unique( method_resolution::implements_trait_unique(&canonical_ty, db, &self.env, fnonce_trait)
&canonical_ty,
db,
self.env.clone(),
fnonce_trait,
)
} }
// FIXME: Find better API that also handles const generics // FIXME: Find better API that also handles const generics