about summary refs log tree commit diff
path: root/src/tools/rust-analyzer
diff options
context:
space:
mode:
authorLukas Wirth <lukastw97@gmail.com>2024-08-25 13:11:13 +0200
committerLukas Wirth <lukastw97@gmail.com>2024-08-25 13:12:07 +0200
commit98e23d37065d34a5d30f5465164e70a01998e9d7 (patch)
treee8e78683c7fc4217165f94e06aff555239a796b2 /src/tools/rust-analyzer
parent606401f03c0e980a01183a705d84fd4ea66e9fdc (diff)
downloadrust-98e23d37065d34a5d30f5465164e70a01998e9d7.tar.gz
rust-98e23d37065d34a5d30f5465164e70a01998e9d7.zip
internal: Don't allocate autoderef steps when not needed
Diffstat (limited to 'src/tools/rust-analyzer')
-rw-r--r--src/tools/rust-analyzer/.git-blame-ignore-revs7
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/autoderef.rs73
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs6
3 files changed, 60 insertions, 26 deletions
diff --git a/src/tools/rust-analyzer/.git-blame-ignore-revs b/src/tools/rust-analyzer/.git-blame-ignore-revs
index d5951a94209..2ccdc8c0425 100644
--- a/src/tools/rust-analyzer/.git-blame-ignore-revs
+++ b/src/tools/rust-analyzer/.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/src/tools/rust-analyzer/crates/hir-ty/src/autoderef.rs b/src/tools/rust-analyzer/crates/hir-ty/src/autoderef.rs
index ecfc1ff99e9..7a3846df40e 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/autoderef.rs
+++ b/src/tools/rust-analyzer/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,
     }
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs b/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs
index d08f9b7ff06..5a72b97653d 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs
+++ b/src/tools/rust-analyzer/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<Ty>, 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),