Return impl IntoElement from RenderOnce::render

Nathan Sobo created

This makes it a bit more approachable to implement.

This required converting the state of Component to AnyElement, which
costs an allocation. I'm hoping this will be ok performance-wise now
that AnyElements use bump allocation, but I need to benchmark still.

Change summary

crates/collab_ui2/src/face_pile.rs                            |  6 
crates/gpui2/src/element.rs                                   | 71 +---
crates/gpui2/src/elements/div.rs                              |  2 
crates/gpui2/src/elements/overlay.rs                          |  2 
crates/gpui2/src/view.rs                                      |  4 
crates/quick_action_bar2/src/quick_action_bar.rs              |  4 
crates/recent_projects2/src/highlighted_workspace_location.rs |  4 
crates/story/src/story.rs                                     | 15 
crates/storybook2/src/stories/z_index.rs                      |  4 
crates/ui2/src/components/avatar.rs                           |  6 
crates/ui2/src/components/button/button.rs                    |  5 
crates/ui2/src/components/button/button_icon.rs               |  4 
crates/ui2/src/components/button/button_like.rs               |  6 
crates/ui2/src/components/button/icon_button.rs               |  4 
crates/ui2/src/components/button/toggle_button.rs             |  4 
crates/ui2/src/components/checkbox.rs                         |  6 
crates/ui2/src/components/disclosure.rs                       |  4 
crates/ui2/src/components/divider.rs                          |  6 
crates/ui2/src/components/icon.rs                             |  6 
crates/ui2/src/components/indicator.rs                        |  6 
crates/ui2/src/components/keybinding.rs                       | 14 
crates/ui2/src/components/label/highlighted_label.rs          |  4 
crates/ui2/src/components/label/label.rs                      |  4 
crates/ui2/src/components/label/label_like.rs                 |  6 
crates/ui2/src/components/list/list.rs                        |  6 
crates/ui2/src/components/list/list_header.rs                 |  7 
crates/ui2/src/components/list/list_item.rs                   |  8 
crates/ui2/src/components/list/list_separator.rs              |  6 
crates/ui2/src/components/list/list_sub_header.rs             |  6 
crates/ui2/src/components/popover.rs                          |  6 
crates/ui2/src/components/popover_menu.rs                     |  4 
crates/ui2/src/components/right_click_menu.rs                 |  4 
crates/ui2/src/components/tab.rs                              |  5 
crates/ui2/src/components/tab_bar.rs                          |  6 
crates/workspace2/src/workspace2.rs                           |  2 
35 files changed, 74 insertions(+), 183 deletions(-)

Detailed changes

crates/collab_ui2/src/face_pile.rs 🔗

@@ -1,5 +1,5 @@
 use gpui::{
-    div, AnyElement, Div, ElementId, IntoElement, ParentElement, RenderOnce, Styled, WindowContext,
+    div, AnyElement, ElementId, IntoElement, ParentElement, RenderOnce, Styled, WindowContext,
 };
 use smallvec::SmallVec;
 
@@ -9,9 +9,7 @@ pub struct FacePile {
 }
 
 impl RenderOnce for FacePile {
-    type Output = Div;
-
-    fn render(self, _: &mut WindowContext) -> Self::Output {
+    fn render(self, _: &mut WindowContext) -> impl IntoElement {
         let player_count = self.faces.len();
         let player_list = self.faces.into_iter().enumerate().map(|(ix, player)| {
             let isnt_last = ix < player_count - 1;

crates/gpui2/src/element.rs 🔗

@@ -113,9 +113,7 @@ pub trait Render: 'static + Sized {
 /// You can derive [IntoElement] on any type that implements this trait.
 /// It is used to allow views to be expressed in terms of abstract data.
 pub trait RenderOnce: 'static {
-    type Output: IntoElement;
-
-    fn render(self, cx: &mut WindowContext) -> Self::Output;
+    fn render(self, cx: &mut WindowContext) -> impl IntoElement;
 }
 
 pub trait ParentElement {
@@ -139,66 +137,29 @@ pub trait ParentElement {
     }
 }
 
-pub struct Component<C> {
-    component: Option<C>,
-}
-
-pub struct ComponentState<C: RenderOnce> {
-    rendered_element: Option<<C::Output as IntoElement>::Element>,
-    rendered_element_state: Option<<<C::Output as IntoElement>::Element as Element>::State>,
-}
+pub struct Component<C: RenderOnce>(Option<C>);
 
-impl<C> Component<C> {
+impl<C: RenderOnce> Component<C> {
     pub fn new(component: C) -> Self {
-        Component {
-            component: Some(component),
-        }
+        Component(Some(component))
     }
 }
 
 impl<C: RenderOnce> Element for Component<C> {
-    type State = ComponentState<C>;
+    type State = AnyElement;
 
     fn request_layout(
         &mut self,
-        state: Option<Self::State>,
+        _: Option<Self::State>,
         cx: &mut WindowContext,
     ) -> (LayoutId, Self::State) {
-        let mut element = self.component.take().unwrap().render(cx).into_element();
-        if let Some(element_id) = element.element_id() {
-            let layout_id =
-                cx.with_element_state(element_id, |state, cx| element.request_layout(state, cx));
-            let state = ComponentState {
-                rendered_element: Some(element),
-                rendered_element_state: None,
-            };
-            (layout_id, state)
-        } else {
-            let (layout_id, state) =
-                element.request_layout(state.and_then(|s| s.rendered_element_state), cx);
-            let state = ComponentState {
-                rendered_element: Some(element),
-                rendered_element_state: Some(state),
-            };
-            (layout_id, state)
-        }
+        let mut element = self.0.take().unwrap().render(cx).into_any_element();
+        let layout_id = element.request_layout(cx);
+        (layout_id, element)
     }
 
-    fn paint(&mut self, bounds: Bounds<Pixels>, state: &mut Self::State, cx: &mut WindowContext) {
-        let mut element = state.rendered_element.take().unwrap();
-        if let Some(element_id) = element.element_id() {
-            cx.with_element_state(element_id, |element_state, cx| {
-                let mut element_state = element_state.unwrap();
-                element.paint(bounds, &mut element_state, cx);
-                ((), element_state)
-            });
-        } else {
-            element.paint(
-                bounds,
-                &mut state.rendered_element_state.as_mut().unwrap(),
-                cx,
-            );
-        }
+    fn paint(&mut self, _: Bounds<Pixels>, element: &mut Self::State, cx: &mut WindowContext) {
+        element.paint(cx)
     }
 }
 
@@ -220,7 +181,7 @@ pub struct GlobalElementId(SmallVec<[ElementId; 32]>);
 trait ElementObject {
     fn element_id(&self) -> Option<ElementId>;
 
-    fn layout(&mut self, cx: &mut WindowContext) -> LayoutId;
+    fn request_layout(&mut self, cx: &mut WindowContext) -> LayoutId;
 
     fn paint(&mut self, cx: &mut WindowContext);
 
@@ -395,7 +356,7 @@ where
         self.as_ref().unwrap().element_id()
     }
 
-    fn layout(&mut self, cx: &mut WindowContext) -> LayoutId {
+    fn request_layout(&mut self, cx: &mut WindowContext) -> LayoutId {
         DrawableElement::request_layout(self.as_mut().unwrap(), cx)
     }
 
@@ -435,8 +396,8 @@ impl AnyElement {
         AnyElement(element)
     }
 
-    pub fn layout(&mut self, cx: &mut WindowContext) -> LayoutId {
-        self.0.layout(cx)
+    pub fn request_layout(&mut self, cx: &mut WindowContext) -> LayoutId {
+        self.0.request_layout(cx)
     }
 
     pub fn paint(&mut self, cx: &mut WindowContext) {
@@ -475,7 +436,7 @@ impl Element for AnyElement {
         _: Option<Self::State>,
         cx: &mut WindowContext,
     ) -> (LayoutId, Self::State) {
-        let layout_id = self.layout(cx);
+        let layout_id = self.request_layout(cx);
         (layout_id, ())
     }
 

crates/gpui2/src/elements/div.rs 🔗

@@ -782,7 +782,7 @@ impl Element for Div {
                     child_layout_ids = self
                         .children
                         .iter_mut()
-                        .map(|child| child.layout(cx))
+                        .map(|child| child.request_layout(cx))
                         .collect::<SmallVec<_>>();
                     cx.request_layout(&style, child_layout_ids.iter().copied())
                 })

crates/gpui2/src/elements/overlay.rs 🔗

@@ -68,7 +68,7 @@ impl Element for Overlay {
         let child_layout_ids = self
             .children
             .iter_mut()
-            .map(|child| child.layout(cx))
+            .map(|child| child.request_layout(cx))
             .collect::<SmallVec<_>>();
 
         let mut overlay_style = Style::default();

crates/gpui2/src/view.rs 🔗

@@ -87,7 +87,7 @@ impl<V: Render> Element for View<V> {
         cx: &mut WindowContext,
     ) -> (LayoutId, Self::State) {
         let mut element = self.update(cx, |view, cx| view.render(cx).into_any_element());
-        let layout_id = element.layout(cx);
+        let layout_id = element.request_layout(cx);
         (layout_id, Some(element))
     }
 
@@ -321,7 +321,7 @@ mod any_view {
     ) -> (LayoutId, AnyElement) {
         let view = view.clone().downcast::<V>().unwrap();
         let mut element = view.update(cx, |view, cx| view.render(cx).into_any_element());
-        let layout_id = element.layout(cx);
+        let layout_id = element.request_layout(cx);
         (layout_id, element)
     }
 

crates/quick_action_bar2/src/quick_action_bar.rs 🔗

@@ -136,9 +136,7 @@ impl QuickActionBarButton {
 }
 
 impl RenderOnce for QuickActionBarButton {
-    type Output = IconButton;
-
-    fn render(self, _: &mut WindowContext) -> Self::Output {
+    fn render(self, _: &mut WindowContext) -> impl IntoElement {
         let tooltip = self.tooltip.clone();
         let action = self.action.boxed_clone();
 

crates/recent_projects2/src/highlighted_workspace_location.rs 🔗

@@ -43,9 +43,7 @@ impl HighlightedText {
 }
 
 impl RenderOnce for HighlightedText {
-    type Output = HighlightedLabel;
-
-    fn render(self, _cx: &mut WindowContext) -> Self::Output {
+    fn render(self, _cx: &mut WindowContext) -> impl IntoElement {
         HighlightedLabel::new(self.text, self.highlight_positions)
     }
 }

crates/story/src/story.rs 🔗

@@ -1,6 +1,5 @@
 use gpui::{
-    div, hsla, prelude::*, px, rems, AnyElement, Div, ElementId, Hsla, SharedString, Stateful,
-    WindowContext,
+    div, hsla, prelude::*, px, rems, AnyElement, Div, ElementId, Hsla, SharedString, WindowContext,
 };
 use itertools::Itertools;
 use smallvec::SmallVec;
@@ -74,9 +73,7 @@ impl ParentElement for StoryContainer {
 }
 
 impl RenderOnce for StoryContainer {
-    type Output = Stateful<Div>;
-
-    fn render(self, _cx: &mut WindowContext) -> Self::Output {
+    fn render(self, _cx: &mut WindowContext) -> impl IntoElement {
         div()
             .size_full()
             .flex()
@@ -294,9 +291,7 @@ impl StoryItem {
 }
 
 impl RenderOnce for StoryItem {
-    type Output = Div;
-
-    fn render(self, _cx: &mut WindowContext) -> Self::Output {
+    fn render(self, _cx: &mut WindowContext) -> impl IntoElement {
         div()
             .my_2()
             .flex()
@@ -358,9 +353,7 @@ impl StorySection {
 }
 
 impl RenderOnce for StorySection {
-    type Output = Div;
-
-    fn render(self, _cx: &mut WindowContext) -> Self::Output {
+    fn render(self, _cx: &mut WindowContext) -> impl IntoElement {
         let children: SmallVec<[AnyElement; 2]> = SmallVec::from_iter(Itertools::intersperse_with(
             self.children.into_iter(),
             || Story::divider().into_any_element(),

crates/storybook2/src/stories/z_index.rs 🔗

@@ -80,9 +80,7 @@ struct ZIndexExample {
 }
 
 impl RenderOnce for ZIndexExample {
-    type Output = Div;
-
-    fn render(self, _cx: &mut WindowContext) -> Self::Output {
+    fn render(self, _cx: &mut WindowContext) -> impl IntoElement {
         div()
             .relative()
             .size_full()

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

@@ -1,5 +1,5 @@
 use crate::prelude::*;
-use gpui::{img, Div, Hsla, ImageSource, Img, IntoElement, Styled};
+use gpui::{img, Hsla, ImageSource, Img, IntoElement, Styled};
 
 #[derive(Debug, Default, PartialEq, Clone)]
 pub enum Shape {
@@ -16,9 +16,7 @@ pub struct Avatar {
 }
 
 impl RenderOnce for Avatar {
-    type Output = Div;
-
-    fn render(mut self, cx: &mut WindowContext) -> Self::Output {
+    fn render(mut self, cx: &mut WindowContext) -> impl IntoElement {
         if self.image.style().corner_radii.top_left.is_none() {
             self = self.shape(Shape::Circle);
         }

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

@@ -136,9 +136,8 @@ impl ButtonCommon for Button {
 }
 
 impl RenderOnce for Button {
-    type Output = ButtonLike;
-
-    fn render(self, _cx: &mut WindowContext) -> Self::Output {
+    #[allow(refining_impl_trait)]
+    fn render(self, _cx: &mut WindowContext) -> ButtonLike {
         let is_disabled = self.base.disabled;
         let is_selected = self.base.selected;
 

crates/ui2/src/components/button/button_icon.rs 🔗

@@ -63,9 +63,7 @@ impl Selectable for ButtonIcon {
 }
 
 impl RenderOnce for ButtonIcon {
-    type Output = IconElement;
-
-    fn render(self, _cx: &mut WindowContext) -> Self::Output {
+    fn render(self, _cx: &mut WindowContext) -> impl IntoElement {
         let icon = self
             .selected_icon
             .filter(|_| self.selected)

crates/ui2/src/components/button/button_like.rs 🔗

@@ -1,5 +1,5 @@
 use gpui::{relative, DefiniteLength, MouseButton};
-use gpui::{rems, transparent_black, AnyElement, AnyView, ClickEvent, Div, Hsla, Rems, Stateful};
+use gpui::{rems, transparent_black, AnyElement, AnyView, ClickEvent, Hsla, Rems};
 use smallvec::SmallVec;
 
 use crate::prelude::*;
@@ -363,9 +363,7 @@ impl ParentElement for ButtonLike {
 }
 
 impl RenderOnce for ButtonLike {
-    type Output = Stateful<Div>;
-
-    fn render(self, cx: &mut WindowContext) -> Self::Output {
+    fn render(self, cx: &mut WindowContext) -> impl IntoElement {
         self.base
             .h_flex()
             .id(self.id.clone())

crates/ui2/src/components/button/icon_button.rs 🔗

@@ -106,9 +106,7 @@ impl VisibleOnHover for IconButton {
 }
 
 impl RenderOnce for IconButton {
-    type Output = ButtonLike;
-
-    fn render(self, _cx: &mut WindowContext) -> Self::Output {
+    fn render(self, _cx: &mut WindowContext) -> impl IntoElement {
         let is_disabled = self.base.disabled;
         let is_selected = self.base.selected;
 

crates/ui2/src/components/button/toggle_button.rs 🔗

@@ -99,9 +99,7 @@ impl ButtonCommon for ToggleButton {
 }
 
 impl RenderOnce for ToggleButton {
-    type Output = ButtonLike;
-
-    fn render(self, _cx: &mut WindowContext) -> Self::Output {
+    fn render(self, _cx: &mut WindowContext) -> impl IntoElement {
         let is_disabled = self.base.disabled;
         let is_selected = self.base.selected;
 

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

@@ -1,4 +1,4 @@
-use gpui::{div, prelude::*, Div, Element, ElementId, IntoElement, Styled, WindowContext};
+use gpui::{div, prelude::*, Element, ElementId, IntoElement, Styled, WindowContext};
 
 use crate::prelude::*;
 use crate::{Color, Icon, IconElement, Selection};
@@ -19,9 +19,7 @@ pub struct Checkbox {
 }
 
 impl RenderOnce for Checkbox {
-    type Output = gpui::Stateful<Div>;
-
-    fn render(self, cx: &mut WindowContext) -> Self::Output {
+    fn render(self, cx: &mut WindowContext) -> impl IntoElement {
         let group_id = format!("checkbox_group_{:?}", self.id);
 
         let icon = match self.checked {

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

@@ -28,9 +28,7 @@ impl Disclosure {
 }
 
 impl RenderOnce for Disclosure {
-    type Output = IconButton;
-
-    fn render(self, _cx: &mut WindowContext) -> Self::Output {
+    fn render(self, _cx: &mut WindowContext) -> impl IntoElement {
         IconButton::new(
             self.id,
             match self.is_open {

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

@@ -1,4 +1,4 @@
-use gpui::{Div, Hsla, IntoElement};
+use gpui::{Hsla, IntoElement};
 
 use crate::prelude::*;
 
@@ -31,9 +31,7 @@ pub struct Divider {
 }
 
 impl RenderOnce for Divider {
-    type Output = Div;
-
-    fn render(self, cx: &mut WindowContext) -> Self::Output {
+    fn render(self, cx: &mut WindowContext) -> impl IntoElement {
         div()
             .map(|this| match self.direction {
                 DividerDirection::Horizontal => {

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

@@ -1,4 +1,4 @@
-use gpui::{rems, svg, IntoElement, Rems, Svg};
+use gpui::{rems, svg, IntoElement, Rems};
 use strum::EnumIter;
 
 use crate::prelude::*;
@@ -200,9 +200,7 @@ pub struct IconElement {
 }
 
 impl RenderOnce for IconElement {
-    type Output = Svg;
-
-    fn render(self, cx: &mut WindowContext) -> Self::Output {
+    fn render(self, cx: &mut WindowContext) -> impl IntoElement {
         svg()
             .size(self.size.rems())
             .flex_none()

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

@@ -1,4 +1,4 @@
-use gpui::{Div, Position};
+use gpui::Position;
 
 use crate::prelude::*;
 
@@ -45,9 +45,7 @@ impl Indicator {
 }
 
 impl RenderOnce for Indicator {
-    type Output = Div;
-
-    fn render(self, cx: &mut WindowContext) -> Self::Output {
+    fn render(self, cx: &mut WindowContext) -> impl IntoElement {
         div()
             .flex_none()
             .map(|this| match self.style {

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

@@ -1,5 +1,5 @@
 use crate::{h_stack, prelude::*, Icon, IconElement, IconSize};
-use gpui::{relative, rems, Action, Div, FocusHandle, IntoElement, Keystroke};
+use gpui::{relative, rems, Action, FocusHandle, IntoElement, Keystroke};
 
 #[derive(IntoElement, Clone)]
 pub struct KeyBinding {
@@ -11,9 +11,7 @@ pub struct KeyBinding {
 }
 
 impl RenderOnce for KeyBinding {
-    type Output = Div;
-
-    fn render(self, cx: &mut WindowContext) -> Self::Output {
+    fn render(self, cx: &mut WindowContext) -> impl IntoElement {
         h_stack()
             .flex_none()
             .gap_2()
@@ -87,9 +85,7 @@ pub struct Key {
 }
 
 impl RenderOnce for Key {
-    type Output = Div;
-
-    fn render(self, cx: &mut WindowContext) -> Self::Output {
+    fn render(self, cx: &mut WindowContext) -> impl IntoElement {
         let single_char = self.key.len() == 1;
 
         div()
@@ -121,9 +117,7 @@ pub struct KeyIcon {
 }
 
 impl RenderOnce for KeyIcon {
-    type Output = Div;
-
-    fn render(self, _cx: &mut WindowContext) -> Self::Output {
+    fn render(self, _cx: &mut WindowContext) -> impl IntoElement {
         div()
             .w(rems(14. / 16.))
             .child(IconElement::new(self.icon).size(IconSize::Small))

crates/ui2/src/components/label/highlighted_label.rs 🔗

@@ -46,9 +46,7 @@ impl LabelCommon for HighlightedLabel {
 }
 
 impl RenderOnce for HighlightedLabel {
-    type Output = LabelLike;
-
-    fn render(self, cx: &mut WindowContext) -> Self::Output {
+    fn render(self, cx: &mut WindowContext) -> impl IntoElement {
         let highlight_color = cx.theme().colors().text_accent;
 
         let mut highlight_indices = self.highlight_indices.iter().copied().peekable();

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

@@ -40,9 +40,7 @@ impl LabelCommon for Label {
 }
 
 impl RenderOnce for Label {
-    type Output = LabelLike;
-
-    fn render(self, _cx: &mut WindowContext) -> Self::Output {
+    fn render(self, _cx: &mut WindowContext) -> impl IntoElement {
         self.base.child(self.label)
     }
 }

crates/ui2/src/components/label/label_like.rs 🔗

@@ -1,4 +1,4 @@
-use gpui::{relative, AnyElement, Div, Styled};
+use gpui::{relative, AnyElement, Styled};
 use smallvec::SmallVec;
 
 use crate::prelude::*;
@@ -76,9 +76,7 @@ impl ParentElement for LabelLike {
 }
 
 impl RenderOnce for LabelLike {
-    type Output = Div;
-
-    fn render(self, cx: &mut WindowContext) -> Self::Output {
+    fn render(self, cx: &mut WindowContext) -> impl IntoElement {
         div()
             .when(self.strikethrough, |this| {
                 this.relative().child(

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

@@ -1,4 +1,4 @@
-use gpui::{AnyElement, Div};
+use gpui::AnyElement;
 use smallvec::SmallVec;
 
 use crate::{prelude::*, v_stack, Label, ListHeader};
@@ -46,9 +46,7 @@ impl ParentElement for List {
 }
 
 impl RenderOnce for List {
-    type Output = Div;
-
-    fn render(self, _cx: &mut WindowContext) -> Self::Output {
+    fn render(self, _cx: &mut WindowContext) -> impl IntoElement {
         v_stack().w_full().py_1().children(self.header).map(|this| {
             match (self.children.is_empty(), self.toggle) {
                 (false, _) => this.children(self.children),

crates/ui2/src/components/list/list_header.rs 🔗

@@ -1,6 +1,5 @@
-use gpui::{AnyElement, ClickEvent, Div, Stateful};
-
 use crate::{h_stack, prelude::*, Disclosure, Label};
+use gpui::{AnyElement, ClickEvent};
 
 #[derive(IntoElement)]
 pub struct ListHeader {
@@ -76,9 +75,7 @@ impl Selectable for ListHeader {
 }
 
 impl RenderOnce for ListHeader {
-    type Output = Stateful<Div>;
-
-    fn render(self, cx: &mut WindowContext) -> Self::Output {
+    fn render(self, cx: &mut WindowContext) -> impl IntoElement {
         h_stack()
             .id(self.label.clone())
             .w_full()

crates/ui2/src/components/list/list_item.rs 🔗

@@ -1,6 +1,4 @@
-use gpui::{
-    px, AnyElement, AnyView, ClickEvent, Div, MouseButton, MouseDownEvent, Pixels, Stateful,
-};
+use gpui::{px, AnyElement, AnyView, ClickEvent, MouseButton, MouseDownEvent, Pixels};
 use smallvec::SmallVec;
 
 use crate::{prelude::*, Disclosure};
@@ -147,9 +145,7 @@ impl ParentElement for ListItem {
 }
 
 impl RenderOnce for ListItem {
-    type Output = Stateful<Div>;
-
-    fn render(self, cx: &mut WindowContext) -> Self::Output {
+    fn render(self, cx: &mut WindowContext) -> impl IntoElement {
         h_stack()
             .id(self.id)
             .w_full()

crates/ui2/src/components/list/list_separator.rs 🔗

@@ -1,14 +1,10 @@
-use gpui::Div;
-
 use crate::prelude::*;
 
 #[derive(IntoElement)]
 pub struct ListSeparator;
 
 impl RenderOnce for ListSeparator {
-    type Output = Div;
-
-    fn render(self, cx: &mut WindowContext) -> Self::Output {
+    fn render(self, cx: &mut WindowContext) -> impl IntoElement {
         div()
             .h_px()
             .w_full()

crates/ui2/src/components/list/list_sub_header.rs 🔗

@@ -1,5 +1,3 @@
-use gpui::Div;
-
 use crate::prelude::*;
 use crate::{h_stack, Icon, IconElement, IconSize, Label};
 
@@ -26,9 +24,7 @@ impl ListSubHeader {
 }
 
 impl RenderOnce for ListSubHeader {
-    type Output = Div;
-
-    fn render(self, _cx: &mut WindowContext) -> Self::Output {
+    fn render(self, _cx: &mut WindowContext) -> impl IntoElement {
         h_stack().flex_1().w_full().relative().py_1().child(
             div()
                 .h_6()

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

@@ -1,5 +1,5 @@
 use gpui::{
-    div, AnyElement, Div, Element, ElementId, IntoElement, ParentElement, RenderOnce, Styled,
+    div, AnyElement, Element, ElementId, IntoElement, ParentElement, RenderOnce, Styled,
     WindowContext,
 };
 use smallvec::SmallVec;
@@ -41,9 +41,7 @@ pub struct Popover {
 }
 
 impl RenderOnce for Popover {
-    type Output = Div;
-
-    fn render(self, cx: &mut WindowContext) -> Self::Output {
+    fn render(self, cx: &mut WindowContext) -> impl IntoElement {
         div()
             .flex()
             .gap_1()

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

@@ -153,7 +153,7 @@ impl<M: ManagedView> Element for PopoverMenu<M> {
             }
 
             let mut element = overlay.child(menu.clone()).into_any();
-            menu_layout_id = Some(element.layout(cx));
+            menu_layout_id = Some(element.request_layout(cx));
             element
         });
 
@@ -164,7 +164,7 @@ impl<M: ManagedView> Element for PopoverMenu<M> {
 
         let child_layout_id = child_element
             .as_mut()
-            .map(|child_element| child_element.layout(cx));
+            .map(|child_element| child_element.request_layout(cx));
 
         let layout_id = cx.request_layout(
             &gpui::Style::default(),

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

@@ -81,7 +81,7 @@ impl<M: ManagedView> Element for RightClickMenu<M> {
             overlay = overlay.position(*position.borrow());
 
             let mut element = overlay.child(menu.clone()).into_any();
-            menu_layout_id = Some(element.layout(cx));
+            menu_layout_id = Some(element.request_layout(cx));
             element
         });
 
@@ -92,7 +92,7 @@ impl<M: ManagedView> Element for RightClickMenu<M> {
 
         let child_layout_id = child_element
             .as_mut()
-            .map(|child_element| child_element.layout(cx));
+            .map(|child_element| child_element.request_layout(cx));
 
         let layout_id = cx.request_layout(
             &gpui::Style::default(),

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

@@ -93,9 +93,8 @@ impl ParentElement for Tab {
 }
 
 impl RenderOnce for Tab {
-    type Output = Stateful<Div>;
-
-    fn render(self, cx: &mut WindowContext) -> Self::Output {
+    #[allow(refining_impl_trait)]
+    fn render(self, cx: &mut WindowContext) -> Stateful<Div> {
         let (text_color, tab_bg, _tab_hover_bg, _tab_active_bg) = match self.selected {
             false => (
                 cx.theme().colors().text_muted,

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

@@ -1,4 +1,4 @@
-use gpui::{AnyElement, ScrollHandle, Stateful};
+use gpui::{AnyElement, ScrollHandle};
 use smallvec::SmallVec;
 
 use crate::prelude::*;
@@ -89,9 +89,7 @@ impl ParentElement for TabBar {
 }
 
 impl RenderOnce for TabBar {
-    type Output = Stateful<Div>;
-
-    fn render(self, cx: &mut WindowContext) -> Self::Output {
+    fn render(self, cx: &mut WindowContext) -> impl IntoElement {
         const HEIGHT_IN_REMS: f32 = 30. / 16.;
 
         div()

crates/workspace2/src/workspace2.rs 🔗

@@ -4305,7 +4305,7 @@ impl Element for DisconnectedOverlay {
                 "Your connection to the remote project has been lost.",
             ))
             .into_any();
-        (overlay.layout(cx), overlay)
+        (overlay.request_layout(cx), overlay)
     }
 
     fn paint(&mut self, bounds: Bounds<Pixels>, overlay: &mut Self::State, cx: &mut WindowContext) {