Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/hir-ty/src/autoderef.rs')
-rw-r--r--crates/hir-ty/src/autoderef.rs73
1 files changed, 53 insertions, 20 deletions
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<Item = Ty> {
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<T: TrackAutoderefSteps> Iterator for Autoderef<'_, '_, T> {
type Item = (Ty, usize);
#[tracing::instrument(skip_all)]
fn next(&mut self) -> Option<Self::Item> {
- 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,
}