Fix Component derive macro

Marshall Bowers created

Change summary

crates/gpui2_macros/src/derive_component.rs  | 84 +++++++++++-----------
crates/ui2/src/components/assistant_panel.rs |  4 
2 files changed, 44 insertions(+), 44 deletions(-)

Detailed changes

crates/gpui2_macros/src/derive_component.rs 🔗

@@ -3,55 +3,29 @@ use quote::quote;
 use syn::{parse_macro_input, parse_quote, DeriveInput};
 
 pub fn derive_component(input: TokenStream) -> TokenStream {
-    let mut ast = parse_macro_input!(input as DeriveInput);
-
-    if !ast
-        .generics
-        .params
-        .iter()
-        .any(|param| matches!(param, syn::GenericParam::Type(_)))
-    {
-        ast.generics.params.push(parse_quote! {
-            V: 'static
-        });
-    }
-
+    let ast = parse_macro_input!(input as DeriveInput);
     let name = &ast.ident;
-    let generics = &ast.generics;
-    let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
 
-    let specified_view_type = ast
-        .attrs
-        .iter()
-        .find(|attr| attr.path.is_ident("component"))
-        .and_then(|attr| {
-            if let Ok(syn::Meta::List(meta_list)) = attr.parse_meta() {
-                meta_list.nested.iter().find_map(|nested| {
-                    if let syn::NestedMeta::Meta(syn::Meta::NameValue(nv)) = nested {
-                        if nv.path.is_ident("view_type") {
-                            if let syn::Lit::Str(lit_str) = &nv.lit {
-                                return Some(
-                                    lit_str
-                                        .parse::<syn::Ident>()
-                                        .expect("Failed to parse view_type"),
-                                );
-                            }
-                        }
-                    }
-                    None
-                })
+    let mut trait_generics = ast.generics.clone();
+    let view_type = if let Some(view_type) = specified_view_type(&ast) {
+        quote! { #view_type }
+    } else {
+        if let Some(first_type_param) = ast.generics.params.iter().find_map(|param| {
+            if let syn::GenericParam::Type(type_param) = param {
+                Some(type_param.ident.clone())
             } else {
                 None
             }
-        });
-
-    let view_type = specified_view_type.unwrap_or_else(|| {
-        if let Some(syn::GenericParam::Type(type_param)) = generics.params.first() {
-            type_param.ident.clone()
+        }) {
+            quote! { #first_type_param }
         } else {
-            panic!("Expected first type parameter to be a view type");
+            trait_generics.params.push(parse_quote! { V: 'static + Send + Sync });
+            quote! { V }
         }
-    });
+    };
+
+    let (impl_generics, _, where_clause) = trait_generics.split_for_impl();
+    let (_, ty_generics, _) = ast.generics.split_for_impl();
 
     let expanded = quote! {
         impl #impl_generics gpui2::Component<#view_type> for #name #ty_generics #where_clause {
@@ -68,3 +42,29 @@ pub fn derive_component(input: TokenStream) -> TokenStream {
 
     TokenStream::from(expanded)
 }
+
+fn specified_view_type(ast: &DeriveInput) -> Option<proc_macro2::Ident> {
+    let component_attr = ast
+        .attrs
+        .iter()
+        .find(|attr| attr.path.is_ident("component"))?;
+
+    if let Ok(syn::Meta::List(meta_list)) = component_attr.parse_meta() {
+        meta_list.nested.iter().find_map(|nested| {
+            if let syn::NestedMeta::Meta(syn::Meta::NameValue(nv)) = nested {
+                if nv.path.is_ident("view_type") {
+                    if let syn::Lit::Str(lit_str) = &nv.lit {
+                        return Some(
+                            lit_str
+                                .parse::<syn::Ident>()
+                                .expect("Failed to parse view_type"),
+                        );
+                    }
+                }
+            }
+            None
+        })
+    } else {
+        None
+    }
+}

crates/ui2/src/components/assistant_panel.rs 🔗

@@ -69,7 +69,7 @@ impl<S: 'static + Send + Sync> AssistantPanel<S> {
                         .overflow_y_scroll()
                         .child(Label::new("Is this thing on?")),
                 )
-                .renderinto_any()])
+                .render()])
             .side(self.current_side)
             .width(AbsoluteLength::Rems(rems(32.)))
     }
@@ -92,7 +92,7 @@ mod stories {
             Self {}
         }
 
-        fn render<V: 'static>(self, _view: &mut V, cx: &mut ViewContext<V>) -> impl Component<V> {
+        fn render<V: 'static + Send + Sync>(self, _view: &mut V, cx: &mut ViewContext<V>) -> impl Component<V> {
             Story::container(cx)
                 .child(Story::title_for::<_, AssistantPanel<V>>(cx))
                 .child(Story::label(cx, "Default"))