diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs index d5951a9420..2ccdc8c042 100644 --- a/.git-blame-ignore-revs +++ b/.git-blame-ignore-revs @@ -7,9 +7,10 @@ # prettier format f247090558c9ba3c551566eae5882b7ca865225f -# subtree syncs -932d85b52946d917deab2c23ead552f7f713b828 +# pre-josh subtree syncs 3e358a6827d83e8d6473913a5e304734aadfed04 +932d85b52946d917deab2c23ead552f7f713b828 9d2cb42a413e51deb50b36794a2e1605381878fc -f532576ac53ddcc666bc8d59e0b6437065e2f599 +b2f6fd4f961fc7e4fbfdb80cae2e6065f8436f15 c48062fe2ab9a2d913d1985a6b0aec4bf936bfc1 +f532576ac53ddcc666bc8d59e0b6437065e2f599 diff --git a/crates/hir-ty/src/autoderef.rs b/crates/hir-ty/src/autoderef.rs index ecfc1ff99e..7a3846df40 100644 --- a/crates/hir-ty/src/autoderef.rs +++ b/crates/hir-ty/src/autoderef.rs @@ -3,6 +3,8 @@ //! reference to a type with the field `bar`. This is an approximation of the //! logic in rustc (which lives in rustc_hir_analysis/check/autoderef.rs). +use std::mem; + use chalk_ir::cast::Cast; use hir_def::lang_item::LangItem; use hir_expand::name::Name; @@ -37,7 +39,7 @@ pub fn autoderef( ) -> impl Iterator { let mut table = InferenceTable::new(db, env); let ty = table.instantiate_canonical(ty); - let mut autoderef = Autoderef::new(&mut table, ty, false); + let mut autoderef = Autoderef::new_no_tracking(&mut table, ty, false); let mut v = Vec::new(); while let Some((ty, _steps)) = autoderef.next() { // `ty` may contain unresolved inference variables. Since there's no chance they would be @@ -58,41 +60,76 @@ pub fn autoderef( v.into_iter() } +trait TrackAutoderefSteps { + fn len(&self) -> usize; + fn push(&mut self, kind: AutoderefKind, ty: &Ty); +} + +impl TrackAutoderefSteps for usize { + fn len(&self) -> usize { + *self + } + fn push(&mut self, _: AutoderefKind, _: &Ty) { + *self += 1; + } +} +impl TrackAutoderefSteps for Vec<(AutoderefKind, Ty)> { + fn len(&self) -> usize { + self.len() + } + fn push(&mut self, kind: AutoderefKind, ty: &Ty) { + self.push((kind, ty.clone())); + } +} + #[derive(Debug)] -pub(crate) struct Autoderef<'a, 'db> { - pub(crate) table: &'a mut InferenceTable<'db>, +pub(crate) struct Autoderef<'table, 'db, T = Vec<(AutoderefKind, Ty)>> { + pub(crate) table: &'table mut InferenceTable<'db>, ty: Ty, at_start: bool, - steps: Vec<(AutoderefKind, Ty)>, + steps: T, explicit: bool, } -impl<'a, 'db> Autoderef<'a, 'db> { - pub(crate) fn new(table: &'a mut InferenceTable<'db>, ty: Ty, explicit: bool) -> Self { +impl<'table, 'db> Autoderef<'table, 'db> { + pub(crate) fn new(table: &'table mut InferenceTable<'db>, ty: Ty, explicit: bool) -> Self { let ty = table.resolve_ty_shallow(&ty); Autoderef { table, ty, at_start: true, steps: Vec::new(), explicit } } - pub(crate) fn step_count(&self) -> usize { - self.steps.len() - } - pub(crate) fn steps(&self) -> &[(AutoderefKind, Ty)] { &self.steps } +} + +impl<'table, 'db> Autoderef<'table, 'db, usize> { + pub(crate) fn new_no_tracking( + table: &'table mut InferenceTable<'db>, + ty: Ty, + explicit: bool, + ) -> Self { + let ty = table.resolve_ty_shallow(&ty); + Autoderef { table, ty, at_start: true, steps: 0, explicit } + } +} + +#[allow(private_bounds)] +impl<'table, 'db, T: TrackAutoderefSteps> Autoderef<'table, 'db, T> { + pub(crate) fn step_count(&self) -> usize { + self.steps.len() + } pub(crate) fn final_ty(&self) -> Ty { self.ty.clone() } } -impl Iterator for Autoderef<'_, '_> { +impl Iterator for Autoderef<'_, '_, T> { type Item = (Ty, usize); #[tracing::instrument(skip_all)] fn next(&mut self) -> Option { - if self.at_start { - self.at_start = false; + if mem::take(&mut self.at_start) { return Some((self.ty.clone(), 0)); } @@ -102,7 +139,7 @@ impl Iterator for Autoderef<'_, '_> { let (kind, new_ty) = autoderef_step(self.table, self.ty.clone(), self.explicit)?; - self.steps.push((kind, self.ty.clone())); + self.steps.push(kind, &self.ty); self.ty = new_ty; Some((self.ty.clone(), self.step_count())) @@ -129,12 +166,8 @@ pub(crate) fn builtin_deref<'ty>( match ty.kind(Interner) { TyKind::Ref(.., ty) => Some(ty), TyKind::Raw(.., ty) if explicit => Some(ty), - &TyKind::Adt(chalk_ir::AdtId(adt), ref substs) => { - if crate::lang_items::is_box(db, adt) { - substs.at(Interner, 0).ty(Interner) - } else { - None - } + &TyKind::Adt(chalk_ir::AdtId(adt), ref substs) if crate::lang_items::is_box(db, adt) => { + substs.at(Interner, 0).ty(Interner) } _ => None, } diff --git a/crates/hir-ty/src/method_resolution.rs b/crates/hir-ty/src/method_resolution.rs index d08f9b7ff0..5a72b97653 100644 --- a/crates/hir-ty/src/method_resolution.rs +++ b/crates/hir-ty/src/method_resolution.rs @@ -1067,7 +1067,7 @@ 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(table, receiver_ty.clone(), true); + let mut autoderef = autoderef::Autoderef::new_no_tracking(table, receiver_ty.clone(), true); while let Some((self_ty, _)) = autoderef.next() { iterate_inherent_methods( &self_ty, @@ -1082,7 +1082,7 @@ fn iterate_method_candidates_by_receiver( ControlFlow::Continue(()) })?; table.run_in_snapshot(|table| { - let mut autoderef = autoderef::Autoderef::new(table, receiver_ty.clone(), true); + let mut autoderef = autoderef::Autoderef::new_no_tracking(table, receiver_ty.clone(), true); while let Some((self_ty, _)) = autoderef.next() { if matches!(self_ty.kind(Interner), TyKind::InferenceVar(_, TyVariableKind::General)) { // don't try to resolve methods on unknown types @@ -1657,7 +1657,7 @@ fn autoderef_method_receiver( ty: Ty, ) -> Vec<(Canonical, ReceiverAdjustments)> { let mut deref_chain: Vec<_> = Vec::new(); - let mut autoderef = autoderef::Autoderef::new(table, ty, false); + let mut autoderef = autoderef::Autoderef::new_no_tracking(table, ty, false); while let Some((ty, derefs)) = autoderef.next() { deref_chain.push(( autoderef.table.canonicalize(ty),