Re-use InferenceTable by snapshotting in method resolution

This commit is contained in:
Lukas Wirth 2024-03-04 15:56:34 +01:00
parent 2898c4217d
commit 593156a357
4 changed files with 48 additions and 56 deletions

View file

@ -113,7 +113,7 @@ pub(crate) fn autoderef_step(
ty: Ty, ty: Ty,
explicit: bool, explicit: bool,
) -> Option<(AutoderefKind, Ty)> { ) -> Option<(AutoderefKind, Ty)> {
if let Some(derefed) = builtin_deref(table, &ty, explicit) { if let Some(derefed) = builtin_deref(table.db, &ty, explicit) {
Some((AutoderefKind::Builtin, table.resolve_ty_shallow(derefed))) Some((AutoderefKind::Builtin, table.resolve_ty_shallow(derefed)))
} else { } else {
Some((AutoderefKind::Overloaded, deref_by_trait(table, ty)?)) Some((AutoderefKind::Overloaded, deref_by_trait(table, ty)?))
@ -121,7 +121,7 @@ pub(crate) fn autoderef_step(
} }
pub(crate) fn builtin_deref<'ty>( pub(crate) fn builtin_deref<'ty>(
table: &mut InferenceTable<'_>, db: &dyn HirDatabase,
ty: &'ty Ty, ty: &'ty Ty,
explicit: bool, explicit: bool,
) -> Option<&'ty Ty> { ) -> Option<&'ty Ty> {
@ -129,7 +129,7 @@ pub(crate) fn builtin_deref<'ty>(
TyKind::Ref(.., ty) => Some(ty), TyKind::Ref(.., ty) => Some(ty),
TyKind::Raw(.., ty) if explicit => Some(ty), TyKind::Raw(.., ty) if explicit => Some(ty),
&TyKind::Adt(chalk_ir::AdtId(adt), ref substs) => { &TyKind::Adt(chalk_ir::AdtId(adt), ref substs) => {
if crate::lang_items::is_box(table.db, adt) { if crate::lang_items::is_box(db, adt) {
substs.at(Interner, 0).ty(Interner) substs.at(Interner, 0).ty(Interner)
} else { } else {
None None

View file

@ -657,7 +657,7 @@ impl InferenceContext<'_> {
); );
} }
} }
if let Some(derefed) = builtin_deref(&mut self.table, &inner_ty, true) { if let Some(derefed) = builtin_deref(self.table.db, &inner_ty, true) {
self.resolve_ty_shallow(derefed) self.resolve_ty_shallow(derefed)
} else { } else {
deref_by_trait(&mut self.table, inner_ty) deref_by_trait(&mut self.table, inner_ty)

View file

@ -243,7 +243,7 @@ pub(crate) struct InferenceTable<'a> {
pub(crate) db: &'a dyn HirDatabase, pub(crate) db: &'a dyn HirDatabase,
pub(crate) trait_env: Arc<TraitEnvironment>, pub(crate) trait_env: Arc<TraitEnvironment>,
var_unification_table: ChalkInferenceTable, var_unification_table: ChalkInferenceTable,
type_variable_table: Vec<TypeVariableFlags>, type_variable_table: SmallVec<[TypeVariableFlags; 16]>,
pending_obligations: Vec<Canonicalized<InEnvironment<Goal>>>, pending_obligations: Vec<Canonicalized<InEnvironment<Goal>>>,
/// Double buffer used in [`Self::resolve_obligations_as_possible`] to cut down on /// Double buffer used in [`Self::resolve_obligations_as_possible`] to cut down on
/// temporary allocations. /// temporary allocations.
@ -252,8 +252,8 @@ pub(crate) struct InferenceTable<'a> {
pub(crate) struct InferenceTableSnapshot { pub(crate) struct InferenceTableSnapshot {
var_table_snapshot: chalk_solve::infer::InferenceSnapshot<Interner>, var_table_snapshot: chalk_solve::infer::InferenceSnapshot<Interner>,
type_variable_table: SmallVec<[TypeVariableFlags; 16]>,
pending_obligations: Vec<Canonicalized<InEnvironment<Goal>>>, pending_obligations: Vec<Canonicalized<InEnvironment<Goal>>>,
type_variable_table_snapshot: Vec<TypeVariableFlags>,
} }
impl<'a> InferenceTable<'a> { impl<'a> InferenceTable<'a> {
@ -262,7 +262,7 @@ impl<'a> InferenceTable<'a> {
db, db,
trait_env, trait_env,
var_unification_table: ChalkInferenceTable::new(), var_unification_table: ChalkInferenceTable::new(),
type_variable_table: Vec::new(), type_variable_table: SmallVec::new(),
pending_obligations: Vec::new(), pending_obligations: Vec::new(),
resolve_obligations_buffer: Vec::new(), resolve_obligations_buffer: Vec::new(),
} }
@ -575,19 +575,15 @@ impl<'a> InferenceTable<'a> {
pub(crate) fn snapshot(&mut self) -> InferenceTableSnapshot { pub(crate) fn snapshot(&mut self) -> InferenceTableSnapshot {
let var_table_snapshot = self.var_unification_table.snapshot(); let var_table_snapshot = self.var_unification_table.snapshot();
let type_variable_table_snapshot = self.type_variable_table.clone(); let type_variable_table = self.type_variable_table.clone();
let pending_obligations = self.pending_obligations.clone(); let pending_obligations = self.pending_obligations.clone();
InferenceTableSnapshot { InferenceTableSnapshot { var_table_snapshot, pending_obligations, type_variable_table }
var_table_snapshot,
pending_obligations,
type_variable_table_snapshot,
}
} }
#[tracing::instrument(skip_all)] #[tracing::instrument(skip_all)]
pub(crate) fn rollback_to(&mut self, snapshot: InferenceTableSnapshot) { pub(crate) fn rollback_to(&mut self, snapshot: InferenceTableSnapshot) {
self.var_unification_table.rollback_to(snapshot.var_table_snapshot); self.var_unification_table.rollback_to(snapshot.var_table_snapshot);
self.type_variable_table = snapshot.type_variable_table_snapshot; self.type_variable_table = snapshot.type_variable_table;
self.pending_obligations = snapshot.pending_obligations; self.pending_obligations = snapshot.pending_obligations;
} }

View file

@ -972,10 +972,9 @@ 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,
&receiver_ty, &receiver_ty,
adj, adj,
db,
env.clone(),
traits_in_scope, traits_in_scope,
visible_from_module, visible_from_module,
name, name,
@ -1000,10 +999,9 @@ 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<'_>,
receiver_ty: &Canonical<Ty>, receiver_ty: &Canonical<Ty>,
first_adjustment: ReceiverAdjustments, first_adjustment: ReceiverAdjustments,
db: &dyn HirDatabase,
env: Arc<TraitEnvironment>,
traits_in_scope: &FxHashSet<TraitId>, traits_in_scope: &FxHashSet<TraitId>,
visible_from_module: VisibleFromModule, visible_from_module: VisibleFromModule,
name: Option<&Name>, name: Option<&Name>,
@ -1016,10 +1014,9 @@ fn iterate_method_candidates_with_autoref(
let mut iterate_method_candidates_by_receiver = move |receiver_ty, first_adjustment| { let mut iterate_method_candidates_by_receiver = move |receiver_ty, first_adjustment| {
iterate_method_candidates_by_receiver( iterate_method_candidates_by_receiver(
table,
receiver_ty, receiver_ty,
first_adjustment, first_adjustment,
db,
env.clone(),
traits_in_scope, traits_in_scope,
visible_from_module, visible_from_module,
name, name,
@ -1058,50 +1055,49 @@ fn iterate_method_candidates_with_autoref(
#[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<'_>,
receiver_ty: &Canonical<Ty>, receiver_ty: &Canonical<Ty>,
receiver_adjustments: ReceiverAdjustments, receiver_adjustments: ReceiverAdjustments,
db: &dyn HirDatabase,
env: Arc<TraitEnvironment>,
traits_in_scope: &FxHashSet<TraitId>, traits_in_scope: &FxHashSet<TraitId>,
visible_from_module: VisibleFromModule, visible_from_module: VisibleFromModule,
name: Option<&Name>, name: Option<&Name>,
mut callback: &mut dyn FnMut(ReceiverAdjustments, AssocItemId, bool) -> ControlFlow<()>, mut callback: &mut dyn FnMut(ReceiverAdjustments, AssocItemId, bool) -> ControlFlow<()>,
) -> ControlFlow<()> { ) -> ControlFlow<()> {
let mut table = InferenceTable::new(db, env); table.run_in_snapshot(|table| {
let receiver_ty = table.instantiate_canonical(receiver_ty.clone()); let receiver_ty = table.instantiate_canonical(receiver_ty.clone());
let snapshot = table.snapshot(); // We're looking for methods with *receiver* type receiver_ty. These could
// 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
// be found in any of the derefs of receiver_ty, so we have to go through // that, including raw derefs.
// that, including raw derefs. table.run_in_snapshot(|table| {
let mut autoderef = autoderef::Autoderef::new(&mut table, receiver_ty.clone(), true); let mut autoderef = autoderef::Autoderef::new(table, receiver_ty.clone(), true);
while let Some((self_ty, _)) = autoderef.next() { while let Some((self_ty, _)) = autoderef.next() {
iterate_inherent_methods( iterate_inherent_methods(
&self_ty, &self_ty,
autoderef.table, autoderef.table,
name, name,
Some(&receiver_ty), Some(&receiver_ty),
Some(receiver_adjustments.clone()), Some(receiver_adjustments.clone()),
visible_from_module, visible_from_module,
&mut callback, &mut callback,
)? )?
} }
ControlFlow::Continue(())
})?;
table.rollback_to(snapshot); let mut autoderef = autoderef::Autoderef::new(table, receiver_ty.clone(), true);
while let Some((self_ty, _)) = autoderef.next() {
let mut autoderef = autoderef::Autoderef::new(&mut table, receiver_ty.clone(), true); iterate_trait_method_candidates(
while let Some((self_ty, _)) = autoderef.next() { &self_ty,
iterate_trait_method_candidates( autoderef.table,
&self_ty, traits_in_scope,
autoderef.table, name,
traits_in_scope, Some(&receiver_ty),
name, Some(receiver_adjustments.clone()),
Some(&receiver_ty), &mut callback,
Some(receiver_adjustments.clone()), )?
&mut callback, }
)? ControlFlow::Continue(())
} })
ControlFlow::Continue(())
} }
#[tracing::instrument(skip_all, fields(name = ?name))] #[tracing::instrument(skip_all, fields(name = ?name))]