chore: Replace as_any functions with trait upcasting (#28221)

Piotr Osiewicz created

Closes #ISSUE

Release Notes:

- N/A

Change summary

crates/copilot/src/copilot.rs                  |  4 ----
crates/git_ui/src/commit_view.rs               |  8 --------
crates/gpui/src/action.rs                      | 14 ++++----------
crates/gpui/src/key_dispatch.rs                |  4 ----
crates/gpui/tests/action_macros.rs             |  4 ----
crates/language/src/buffer.rs                  |  9 +--------
crates/project/src/debugger/session.rs         | 13 ++++---------
crates/proto/src/typed_envelope.rs             |  7 +------
crates/recent_projects/src/remote_servers.rs   |  8 +++-----
crates/rpc/src/proto_client.rs                 |  8 +++-----
crates/terminal_view/src/terminal_scrollbar.rs |  5 -----
crates/ui/src/components/scrollbar.rs          | 15 +--------------
crates/worktree/src/worktree.rs                | 11 ++++++-----
13 files changed, 23 insertions(+), 87 deletions(-)

Detailed changes

crates/copilot/src/copilot.rs 🔗

@@ -1280,10 +1280,6 @@ mod tests {
             unimplemented!()
         }
 
-        fn as_any(&self) -> &dyn std::any::Any {
-            unimplemented!()
-        }
-
         fn to_proto(&self, _: &App) -> rpc::proto::File {
             unimplemented!()
         }

crates/git_ui/src/commit_view.rs 🔗

@@ -244,10 +244,6 @@ impl language::File for GitBlob {
         self.worktree_id
     }
 
-    fn as_any(&self) -> &dyn Any {
-        self
-    }
-
     fn to_proto(&self, _cx: &App) -> language::proto::File {
         unimplemented!()
     }
@@ -282,10 +278,6 @@ impl language::File for CommitMetadataFile {
         self.worktree_id
     }
 
-    fn as_any(&self) -> &dyn Any {
-        self
-    }
-
     fn to_proto(&self, _: &App) -> language::proto::File {
         unimplemented!()
     }

crates/gpui/src/action.rs 🔗

@@ -42,13 +42,10 @@ use std::{
 /// }
 /// register_action!(Paste);
 /// ```
-pub trait Action: 'static + Send {
+pub trait Action: Any + Send {
     /// Clone the action into a new box
     fn boxed_clone(&self) -> Box<dyn Action>;
 
-    /// Cast the action to the any type
-    fn as_any(&self) -> &dyn Any;
-
     /// Do a partial equality check on this action and the other
     fn partial_eq(&self, action: &dyn Action) -> bool;
 
@@ -94,9 +91,9 @@ impl std::fmt::Debug for dyn Action {
 }
 
 impl dyn Action {
-    /// Get the type id of this action
-    pub fn type_id(&self) -> TypeId {
-        self.as_any().type_id()
+    /// Type-erase Action type.
+    pub fn as_any(&self) -> &dyn Any {
+        self as &dyn Any
     }
 }
 
@@ -557,9 +554,6 @@ macro_rules! __impl_action {
                 ::std::boxed::Box::new(self.clone())
             }
 
-            fn as_any(&self) -> &dyn ::std::any::Any {
-                self
-            }
 
             $($items)*
         }

crates/gpui/src/key_dispatch.rs 🔗

@@ -597,10 +597,6 @@ mod tests {
             Box::new(TestAction)
         }
 
-        fn as_any(&self) -> &dyn ::std::any::Any {
-            self
-        }
-
         fn build(_value: serde_json::Value) -> anyhow::Result<Box<dyn Action>>
         where
             Self: Sized,

crates/gpui/tests/action_macros.rs 🔗

@@ -22,10 +22,6 @@ fn test_action_macros() {
             unimplemented!()
         }
 
-        fn as_any(&self) -> &dyn std::any::Any {
-            unimplemented!()
-        }
-
         fn partial_eq(&self, _action: &dyn gpui::Action) -> bool {
             unimplemented!()
         }

crates/language/src/buffer.rs 🔗

@@ -306,7 +306,7 @@ pub enum BufferEvent {
 }
 
 /// The file associated with a buffer.
-pub trait File: Send + Sync {
+pub trait File: Send + Sync + Any {
     /// Returns the [`LocalFile`] associated with this file, if the
     /// file is local.
     fn as_local(&self) -> Option<&dyn LocalFile>;
@@ -336,9 +336,6 @@ pub trait File: Send + Sync {
     /// This is needed for looking up project-specific settings.
     fn worktree_id(&self, cx: &App) -> WorktreeId;
 
-    /// Converts this file into an [`Any`] trait object.
-    fn as_any(&self) -> &dyn Any;
-
     /// Converts this file into a protobuf message.
     fn to_proto(&self, cx: &App) -> rpc::proto::File;
 
@@ -4610,10 +4607,6 @@ impl File for TestFile {
         WorktreeId::from_usize(0)
     }
 
-    fn as_any(&self) -> &dyn std::any::Any {
-        unimplemented!()
-    }
-
     fn to_proto(&self, _: &App) -> rpc::proto::File {
         unimplemented!()
     }

crates/project/src/debugger/session.rs 🔗

@@ -746,8 +746,7 @@ pub struct Session {
     _background_tasks: Vec<Task<()>>,
 }
 
-trait CacheableCommand: 'static + Send + Sync {
-    fn as_any(&self) -> &dyn Any;
+trait CacheableCommand: Any + Send + Sync {
     fn dyn_eq(&self, rhs: &dyn CacheableCommand) -> bool;
     fn dyn_hash(&self, hasher: &mut dyn Hasher);
     fn as_any_arc(self: Arc<Self>) -> Arc<dyn Any + Send + Sync>;
@@ -757,12 +756,8 @@ impl<T> CacheableCommand for T
 where
     T: DapCommand + PartialEq + Eq + Hash,
 {
-    fn as_any(&self) -> &dyn Any {
-        self
-    }
-
     fn dyn_eq(&self, rhs: &dyn CacheableCommand) -> bool {
-        rhs.as_any()
+        (rhs as &dyn Any)
             .downcast_ref::<Self>()
             .map_or(false, |rhs| self == rhs)
     }
@@ -795,7 +790,7 @@ impl Eq for RequestSlot {}
 impl Hash for RequestSlot {
     fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
         self.0.dyn_hash(state);
-        self.0.as_any().type_id().hash(state)
+        (&*self.0 as &dyn Any).type_id().hash(state)
     }
 }
 
@@ -1345,7 +1340,7 @@ impl Session {
 
     fn invalidate_state(&mut self, key: &RequestSlot) {
         self.requests
-            .entry(key.0.as_any().type_id())
+            .entry((&*key.0 as &dyn Any).type_id())
             .and_modify(|request_map| {
                 request_map.remove(&key);
             });

crates/proto/src/typed_envelope.rs 🔗

@@ -31,10 +31,9 @@ pub trait RequestMessage: EnvelopedMessage {
     type Response: EnvelopedMessage;
 }
 
-pub trait AnyTypedEnvelope: 'static + Send + Sync {
+pub trait AnyTypedEnvelope: Any + Send + Sync {
     fn payload_type_id(&self) -> TypeId;
     fn payload_type_name(&self) -> &'static str;
-    fn as_any(&self) -> &dyn Any;
     fn into_any(self: Box<Self>) -> Box<dyn Any + Send + Sync>;
     fn is_background(&self) -> bool;
     fn original_sender_id(&self) -> Option<PeerId>;
@@ -56,10 +55,6 @@ impl<T: EnvelopedMessage> AnyTypedEnvelope for TypedEnvelope<T> {
         T::NAME
     }
 
-    fn as_any(&self) -> &dyn Any {
-        self
-    }
-
     fn into_any(self: Box<Self>) -> Box<dyn Any + Send + Sync> {
         self
     }

crates/recent_projects/src/remote_servers.rs 🔗

@@ -1,3 +1,4 @@
+use std::any::Any;
 use std::collections::BTreeSet;
 use std::path::PathBuf;
 use std::sync::Arc;
@@ -1288,11 +1289,8 @@ impl RemoteServerProjects {
                 cx.notify();
             }));
 
-        let Some(scroll_handle) = scroll_state
-            .scroll_handle()
-            .as_any()
-            .downcast_ref::<ScrollHandle>()
-        else {
+        let handle = &**scroll_state.scroll_handle() as &dyn Any;
+        let Some(scroll_handle) = handle.downcast_ref::<ScrollHandle>() else {
             unreachable!()
         };
 

crates/rpc/src/proto_client.rs 🔗

@@ -10,7 +10,7 @@ use proto::{
     error::ErrorExt as _,
 };
 use std::{
-    any::TypeId,
+    any::{Any, TypeId},
     sync::{Arc, Weak},
 };
 
@@ -250,8 +250,7 @@ impl AnyProtoClient {
         let message_type_id = TypeId::of::<M>();
         let entity_type_id = TypeId::of::<E>();
         let entity_id_extractor = |envelope: &dyn AnyTypedEnvelope| {
-            envelope
-                .as_any()
+            (envelope as &dyn Any)
                 .downcast_ref::<TypedEnvelope<M>>()
                 .unwrap()
                 .payload
@@ -296,8 +295,7 @@ impl AnyProtoClient {
         let message_type_id = TypeId::of::<M>();
         let entity_type_id = TypeId::of::<E>();
         let entity_id_extractor = |envelope: &dyn AnyTypedEnvelope| {
-            envelope
-                .as_any()
+            (envelope as &dyn Any)
                 .downcast_ref::<TypedEnvelope<M>>()
                 .unwrap()
                 .payload

crates/ui/src/components/scrollbar.rs 🔗

@@ -33,10 +33,6 @@ impl ScrollableHandle for UniformListScrollHandle {
     fn viewport(&self) -> Bounds<Pixels> {
         self.0.borrow().base_handle.bounds()
     }
-
-    fn as_any(&self) -> &dyn Any {
-        self
-    }
 }
 
 impl ScrollableHandle for ListState {
@@ -66,10 +62,6 @@ impl ScrollableHandle for ListState {
     fn viewport(&self) -> Bounds<Pixels> {
         self.viewport_bounds()
     }
-
-    fn as_any(&self) -> &dyn Any {
-        self
-    }
 }
 
 impl ScrollableHandle for ScrollHandle {
@@ -107,10 +99,6 @@ impl ScrollableHandle for ScrollHandle {
     fn viewport(&self) -> Bounds<Pixels> {
         self.bounds()
     }
-
-    fn as_any(&self) -> &dyn Any {
-        self
-    }
 }
 
 #[derive(Debug)]
@@ -119,12 +107,11 @@ pub struct ContentSize {
     pub scroll_adjustment: Option<Point<Pixels>>,
 }
 
-pub trait ScrollableHandle: Debug + 'static {
+pub trait ScrollableHandle: Any + Debug {
     fn content_size(&self) -> Option<ContentSize>;
     fn set_offset(&self, point: Point<Pixels>);
     fn offset(&self) -> Point<Pixels>;
     fn viewport(&self) -> Bounds<Pixels>;
-    fn as_any(&self) -> &dyn Any;
     fn drag_started(&self) {}
     fn drag_ended(&self) {}
 }

crates/worktree/src/worktree.rs 🔗

@@ -45,6 +45,7 @@ use smallvec::{SmallVec, smallvec};
 use smol::channel::{self, Sender};
 use std::{
     any::Any,
+    borrow::Borrow as _,
     cmp::Ordering,
     collections::hash_map,
     convert::TryFrom,
@@ -3263,10 +3264,6 @@ impl language::File for File {
         self.worktree.read(cx).id()
     }
 
-    fn as_any(&self) -> &dyn Any {
-        self
-    }
-
     fn to_proto(&self, cx: &App) -> rpc::proto::File {
         rpc::proto::File {
             worktree_id: self.worktree.read(cx).id().to_proto(),
@@ -3359,7 +3356,11 @@ impl File {
     }
 
     pub fn from_dyn(file: Option<&Arc<dyn language::File>>) -> Option<&Self> {
-        file.and_then(|f| f.as_any().downcast_ref())
+        file.and_then(|f| {
+            let f: &dyn language::File = f.borrow();
+            let f: &dyn Any = f;
+            f.downcast_ref()
+        })
     }
 
     pub fn worktree_id(&self, cx: &App) -> WorktreeId {