Revert "Mixin for slotted RenderObjectWidgets and RenderBox (#94077)" (#94620)

This reverts commit 988959dad9b6f07086d5a0903b1fb17ce3d00188.
diff --git a/examples/api/lib/widgets/slotted_render_object_widget/slotted_multi_child_render_object_widget_mixin.0.dart b/examples/api/lib/widgets/slotted_render_object_widget/slotted_multi_child_render_object_widget_mixin.0.dart
deleted file mode 100644
index 217544b..0000000
--- a/examples/api/lib/widgets/slotted_render_object_widget/slotted_multi_child_render_object_widget_mixin.0.dart
+++ /dev/null
@@ -1,289 +0,0 @@
-// Copyright 2014 The Flutter Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-import 'package:flutter/material.dart';
-import 'package:flutter/rendering.dart';
-
-/// Slots used for the children of [Diagonal] and [RenderDiagonal].
-enum DiagonalSlot {
-  topLeft,
-  bottomRight,
-}
-
-/// A widget that demonstrates the usage of [SlottedMultiChildRenderObjectWidgetMixin]
-/// by providing slots for two children that will be arranged diagonally.
-class Diagonal extends RenderObjectWidget with SlottedMultiChildRenderObjectWidgetMixin<DiagonalSlot> {
-  const Diagonal({
-    Key? key,
-    this.topLeft,
-    this.bottomRight,
-    this.backgroundColor,
-  }) : super(key: key);
-
-  final Widget? topLeft;
-  final Widget? bottomRight;
-  final Color? backgroundColor;
-
-  @override
-  Iterable<DiagonalSlot> get slots => DiagonalSlot.values;
-
-  @override
-  Widget? childForSlot(DiagonalSlot slot) {
-    switch (slot) {
-      case DiagonalSlot.topLeft:
-        return topLeft;
-      case DiagonalSlot.bottomRight:
-        return bottomRight;
-    }
-  }
-
-  // The [createRenderObject] and [updateRenderObject] methods configure the
-  // [RenderObject] backing this widget with the configuration of the widget.
-  // They do not need to do anything with the children of the widget, though.
-  // The children of the widget are automatically configured on the
-  // [RenderObject] by [SlottedRenderObjectElement.mount] and
-  // [SlottedRenderObjectElement.update].
-
-  @override
-  SlottedContainerRenderObjectMixin<DiagonalSlot> createRenderObject(
-    BuildContext context,
-  ) {
-    return RenderDiagonal(
-      backgroundColor: backgroundColor,
-    );
-  }
-
-  @override
-  void updateRenderObject(
-    BuildContext context,
-    SlottedContainerRenderObjectMixin<DiagonalSlot> renderObject,
-  ) {
-    (renderObject as RenderDiagonal).backgroundColor = backgroundColor;
-  }
-}
-
-/// A render object that demonstrates the usage of [SlottedContainerRenderObjectMixin]
-/// by providing slots for two children that will be arranged diagonally.
-class RenderDiagonal extends RenderBox with SlottedContainerRenderObjectMixin<DiagonalSlot>, DebugOverflowIndicatorMixin {
-  RenderDiagonal({Color? backgroundColor}) : _backgroundColor = backgroundColor;
-
-  // Getters and setters to configure the [RenderObject] with the configuration
-  // of the [Widget]. These mostly contain boilerplate code, but depending on
-  // where the configuration value is used, the setter has to call
-  // [markNeedsLayout], [markNeedsPaint], or [markNeedsSemanticsUpdate].
-  Color? get backgroundColor => _backgroundColor;
-  Color? _backgroundColor;
-  set backgroundColor(Color? value) {
-    assert(value != null);
-    if (_backgroundColor == value) {
-      return;
-    }
-    _backgroundColor = value;
-    markNeedsPaint();
-  }
-
-  // Getters to simplify accessing the slotted children.
-  RenderBox? get _topLeft => childForSlot(DiagonalSlot.topLeft);
-  RenderBox? get _bottomRight => childForSlot(DiagonalSlot.bottomRight);
-
-  // The size this render object would have if the incoming constraints were
-  // unconstrained; calculated during performLayout used during paint for an
-  // assertion that checks for unintended overflow.
-  late Size _childrenSize;
-
-  // Returns children in hit test order.
-  @override
-  Iterable<RenderBox> get children sync* {
-    if (_topLeft != null) {
-      yield _topLeft!;
-    }
-    if (_bottomRight != null) {
-      yield _bottomRight!;
-    }
-  }
-
-  // LAYOUT
-
-  @override
-  void performLayout() {
-    // Children are allowed to be as big as they want (= unconstrained).
-    const BoxConstraints childConstraints = BoxConstraints();
-
-    // Lay out the top left child and position it at offset zero.
-    Size topLeftSize = Size.zero;
-    final RenderBox? topLeft = _topLeft;
-    if (topLeft != null) {
-      topLeft.layout(childConstraints, parentUsesSize: true);
-      _positionChild(topLeft, Offset.zero);
-      topLeftSize = topLeft.size;
-    }
-
-    // Lay out the bottom right child and position it at the bottom right corner
-    // of the top left child.
-    Size bottomRightSize = Size.zero;
-    final RenderBox? bottomRight = _bottomRight;
-    if (bottomRight != null) {
-      bottomRight.layout(childConstraints, parentUsesSize: true);
-      _positionChild(
-        bottomRight,
-        Offset(topLeftSize.width, topLeftSize.height),
-      );
-      bottomRightSize = bottomRight.size;
-    }
-
-    // Calculate the overall size and constrain it to the given constraints.
-    // Any overflow is marked (in debug mode) during paint.
-    _childrenSize = Size(
-      topLeftSize.width + bottomRightSize.width,
-      topLeftSize.height + bottomRightSize.height,
-    );
-    size = constraints.constrain(_childrenSize);
-  }
-
-  void _positionChild(RenderBox child, Offset offset) {
-    (child.parentData! as BoxParentData).offset = offset;
-  }
-
-  // PAINT
-
-  @override
-  void paint(PaintingContext context, Offset offset) {
-    // Paint the background.
-    if (backgroundColor != null) {
-      context.canvas.drawRect(
-        offset & size,
-        Paint()
-          ..color = backgroundColor!,
-      );
-    }
-
-    void paintChild(RenderBox child, PaintingContext context, Offset offset) {
-      final BoxParentData childParentData = child.parentData! as BoxParentData;
-      context.paintChild(child, childParentData.offset + offset);
-    }
-
-    // Paint the children at the offset calculated during layout.
-    final RenderBox? topLeft = _topLeft;
-    if (topLeft != null) {
-      paintChild(topLeft, context, offset);
-    }
-    final RenderBox? bottomRight = _bottomRight;
-    if (bottomRight != null) {
-      paintChild(bottomRight, context, offset);
-    }
-
-    // Paint an overflow indicator in debug mode if the children want to be
-    // larger than the incoming constraints allow.
-    assert(() {
-      paintOverflowIndicator(
-        context,
-        offset,
-        Offset.zero & size,
-        Offset.zero & _childrenSize,
-      );
-      return true;
-    }());
-  }
-
-  // HIT TEST
-
-  @override
-  bool hitTestChildren(BoxHitTestResult result, { required Offset position }) {
-    for (final RenderBox child in children) {
-      final BoxParentData parentData = child.parentData! as BoxParentData;
-      final bool isHit = result.addWithPaintOffset(
-        offset: parentData.offset,
-        position: position,
-        hitTest: (BoxHitTestResult result, Offset transformed) {
-          assert(transformed == position - parentData.offset);
-          return child.hitTest(result, position: transformed);
-        },
-      );
-      if (isHit) {
-        return true;
-      }
-    }
-    return false;
-  }
-
-  // INTRINSICS
-
-  // Incoming height/width are ignored as children are always laid out unconstrained.
-
-  @override
-  double computeMinIntrinsicWidth(double height) {
-    final double topLeftWidth = _topLeft?.getMinIntrinsicWidth(double.infinity) ?? 0;
-    final double bottomRightWith = _bottomRight?.getMinIntrinsicWidth(double.infinity) ?? 0;
-    return topLeftWidth + bottomRightWith;
-  }
-
-  @override
-  double computeMaxIntrinsicWidth(double height) {
-    final double topLeftWidth = _topLeft?.getMaxIntrinsicWidth(double.infinity) ?? 0;
-    final double bottomRightWith = _bottomRight?.getMaxIntrinsicWidth(double.infinity) ?? 0;
-    return topLeftWidth + bottomRightWith;  }
-
-  @override
-  double computeMinIntrinsicHeight(double width) {
-    final double topLeftHeight = _topLeft?.getMinIntrinsicHeight(double.infinity) ?? 0;
-    final double bottomRightHeight = _bottomRight?.getMinIntrinsicHeight(double.infinity) ?? 0;
-    return topLeftHeight + bottomRightHeight;
-  }
-
-  @override
-  double computeMaxIntrinsicHeight(double width) {
-    final double topLeftHeight = _topLeft?.getMaxIntrinsicHeight(double.infinity) ?? 0;
-    final double bottomRightHeight = _bottomRight?.getMaxIntrinsicHeight(double.infinity) ?? 0;
-    return topLeftHeight + bottomRightHeight;
-  }
-
-  @override
-  Size computeDryLayout(BoxConstraints constraints) {
-    const BoxConstraints childConstraints = BoxConstraints();
-    final Size topLeftSize = _topLeft?.computeDryLayout(childConstraints) ?? Size.zero;
-    final Size bottomRightSize = _bottomRight?.computeDryLayout(childConstraints) ?? Size.zero;
-    return constraints.constrain(Size(
-      topLeftSize.width + bottomRightSize.width,
-      topLeftSize.height + bottomRightSize.height,
-    ));
-  }
-}
-
-class ExampleWidget extends StatelessWidget {
-  const ExampleWidget({Key? key}) : super(key: key);
-
-  @override
-  Widget build(BuildContext context) {
-    return MaterialApp(
-      home: Scaffold(
-        appBar: AppBar(title: const Text('Slotted RenderObject Example')),
-        body: Center(
-          child: Diagonal(
-            topLeft: Container(
-              color: Colors.green,
-              height: 100,
-              width: 200,
-              child: const Center(
-                child: Text('topLeft'),
-              ),
-            ),
-            bottomRight: Container(
-              color: Colors.yellow,
-              height: 60,
-              width: 30,
-              child: const Center(
-                child: Text('bottomRight'),
-              ),
-            ),
-            backgroundColor: Colors.blue,
-          ),
-        ),
-      ),
-    );
-  }
-}
-
-void main() {
-  runApp(const ExampleWidget());
-}
diff --git a/examples/api/test/widgets/slotted_render_object_widget/slotted_multi_child_render_object_widget_mixin.0_test.dart b/examples/api/test/widgets/slotted_render_object_widget/slotted_multi_child_render_object_widget_mixin.0_test.dart
deleted file mode 100644
index 150d9e5..0000000
--- a/examples/api/test/widgets/slotted_render_object_widget/slotted_multi_child_render_object_widget_mixin.0_test.dart
+++ /dev/null
@@ -1,41 +0,0 @@
-// Copyright 2014 The Flutter Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-import 'package:flutter/widgets.dart';
-import 'package:flutter_api_samples/widgets/slotted_render_object_widget/slotted_multi_child_render_object_widget_mixin.0.dart' as example;
-import 'package:flutter_test/flutter_test.dart';
-
-void main() {
-  testWidgets('shows two widgets arranged diagonally', (WidgetTester tester) async {
-    await tester.pumpWidget(
-      const example.ExampleWidget(),
-    );
-
-    expect(find.text('topLeft'), findsOneWidget);
-    expect(find.text('bottomRight'), findsOneWidget);
-
-    expect(
-      tester.getBottomRight(findContainerWithText('topLeft')),
-      tester.getTopLeft(findContainerWithText('bottomRight')),
-    );
-
-    expect(
-      tester.getSize(findContainerWithText('topLeft')),
-      const Size(200, 100),
-    );
-    expect(
-      tester.getSize(findContainerWithText('bottomRight')),
-      const Size(30, 60),
-    );
-
-    expect(
-      tester.getSize(find.byType(example.Diagonal)),
-      const Size(200 + 30, 100 + 60),
-    );
-  });
-}
-
-Finder findContainerWithText(String text) {
-  return find.ancestor(of: find.text(text), matching: find.byType(Container));
-}
diff --git a/packages/flutter/lib/src/material/chip.dart b/packages/flutter/lib/src/material/chip.dart
index b720b85..82ff6c2 100644
--- a/packages/flutter/lib/src/material/chip.dart
+++ b/packages/flutter/lib/src/material/chip.dart
@@ -2059,7 +2059,7 @@
   }
 }
 
-class _ChipRenderWidget extends RenderObjectWidget with SlottedMultiChildRenderObjectWidgetMixin<_ChipSlot> {
+class _ChipRenderWidget extends RenderObjectWidget {
   const _ChipRenderWidget({
     Key? key,
     required this.theme,
@@ -2083,19 +2083,7 @@
   final ShapeBorder? avatarBorder;
 
   @override
-  Iterable<_ChipSlot> get slots => _ChipSlot.values;
-
-  @override
-  Widget? childForSlot(_ChipSlot slot) {
-    switch (slot) {
-      case _ChipSlot.label:
-        return theme.label;
-      case _ChipSlot.avatar:
-        return theme.avatar;
-      case _ChipSlot.deleteIcon:
-        return theme.deleteIcon;
-    }
-  }
+  _RenderChipElement createElement() => _RenderChipElement(this);
 
   @override
   void updateRenderObject(BuildContext context, _RenderChip renderObject) {
@@ -2112,7 +2100,7 @@
   }
 
   @override
-  SlottedContainerRenderObjectMixin<_ChipSlot> createRenderObject(BuildContext context) {
+  RenderObject createRenderObject(BuildContext context) {
     return _RenderChip(
       theme: theme,
       textDirection: Directionality.of(context),
@@ -2133,6 +2121,105 @@
   deleteIcon,
 }
 
+class _RenderChipElement extends RenderObjectElement {
+  _RenderChipElement(_ChipRenderWidget chip) : super(chip);
+
+  final Map<_ChipSlot, Element> slotToChild = <_ChipSlot, Element>{};
+
+  @override
+  _ChipRenderWidget get widget => super.widget as _ChipRenderWidget;
+
+  @override
+  _RenderChip get renderObject => super.renderObject as _RenderChip;
+
+  @override
+  void visitChildren(ElementVisitor visitor) {
+    slotToChild.values.forEach(visitor);
+  }
+
+  @override
+  void forgetChild(Element child) {
+    assert(slotToChild.containsValue(child));
+    assert(child.slot is _ChipSlot);
+    assert(slotToChild.containsKey(child.slot));
+    slotToChild.remove(child.slot);
+    super.forgetChild(child);
+  }
+
+  void _mountChild(Widget widget, _ChipSlot slot) {
+    final Element? oldChild = slotToChild[slot];
+    final Element? newChild = updateChild(oldChild, widget, slot);
+    if (oldChild != null) {
+      slotToChild.remove(slot);
+    }
+    if (newChild != null) {
+      slotToChild[slot] = newChild;
+    }
+  }
+
+  @override
+  void mount(Element? parent, Object? newSlot) {
+    super.mount(parent, newSlot);
+    _mountChild(widget.theme.avatar, _ChipSlot.avatar);
+    _mountChild(widget.theme.deleteIcon, _ChipSlot.deleteIcon);
+    _mountChild(widget.theme.label, _ChipSlot.label);
+  }
+
+  void _updateChild(Widget widget, _ChipSlot slot) {
+    final Element? oldChild = slotToChild[slot];
+    final Element? newChild = updateChild(oldChild, widget, slot);
+    if (oldChild != null) {
+      slotToChild.remove(slot);
+    }
+    if (newChild != null) {
+      slotToChild[slot] = newChild;
+    }
+  }
+
+  @override
+  void update(_ChipRenderWidget newWidget) {
+    super.update(newWidget);
+    assert(widget == newWidget);
+    _updateChild(widget.theme.label, _ChipSlot.label);
+    _updateChild(widget.theme.avatar, _ChipSlot.avatar);
+    _updateChild(widget.theme.deleteIcon, _ChipSlot.deleteIcon);
+  }
+
+  void _updateRenderObject(RenderObject? child, _ChipSlot slot) {
+    switch (slot) {
+      case _ChipSlot.avatar:
+        renderObject.avatar = child as RenderBox?;
+        break;
+      case _ChipSlot.label:
+        renderObject.label = child as RenderBox?;
+        break;
+      case _ChipSlot.deleteIcon:
+        renderObject.deleteIcon = child as RenderBox?;
+        break;
+    }
+  }
+
+  @override
+  void insertRenderObjectChild(RenderObject child, _ChipSlot slot) {
+    assert(child is RenderBox);
+    _updateRenderObject(child, slot);
+    assert(renderObject.children.keys.contains(slot));
+  }
+
+  @override
+  void removeRenderObjectChild(RenderObject child, _ChipSlot slot) {
+    assert(child is RenderBox);
+    assert(renderObject.children[slot] == child);
+    _updateRenderObject(null, slot);
+    assert(!renderObject.children.keys.contains(slot));
+  }
+
+  @override
+  void moveRenderObjectChild(RenderObject child, Object? oldSlot, Object? newSlot) {
+    assert(false, 'not reachable');
+  }
+}
+
 @immutable
 class _ChipRenderTheme {
   const _ChipRenderTheme({
@@ -2199,7 +2286,7 @@
   }
 }
 
-class _RenderChip extends RenderBox with SlottedContainerRenderObjectMixin<_ChipSlot> {
+class _RenderChip extends RenderBox {
   _RenderChip({
     required _ChipRenderTheme theme,
     required TextDirection textDirection,
@@ -2220,6 +2307,8 @@
     enableAnimation.addListener(markNeedsPaint);
   }
 
+  final Map<_ChipSlot, RenderBox> children = <_ChipSlot, RenderBox>{};
+
   bool? value;
   bool? isEnabled;
   late Rect _deleteButtonRect;
@@ -2230,9 +2319,35 @@
   Animation<double> enableAnimation;
   ShapeBorder? avatarBorder;
 
-  RenderBox? get avatar => childForSlot(_ChipSlot.avatar);
-  RenderBox? get deleteIcon => childForSlot(_ChipSlot.deleteIcon);
-  RenderBox? get label => childForSlot(_ChipSlot.label);
+  RenderBox? _updateChild(RenderBox? oldChild, RenderBox? newChild, _ChipSlot slot) {
+    if (oldChild != null) {
+      dropChild(oldChild);
+      children.remove(slot);
+    }
+    if (newChild != null) {
+      children[slot] = newChild;
+      adoptChild(newChild);
+    }
+    return newChild;
+  }
+
+  RenderBox? _avatar;
+  RenderBox? get avatar => _avatar;
+  set avatar(RenderBox? value) {
+    _avatar = _updateChild(_avatar, value, _ChipSlot.avatar);
+  }
+
+  RenderBox? _deleteIcon;
+  RenderBox? get deleteIcon => _deleteIcon;
+  set deleteIcon(RenderBox? value) {
+    _deleteIcon = _updateChild(_deleteIcon, value, _ChipSlot.deleteIcon);
+  }
+
+  RenderBox? _label;
+  RenderBox? get label => _label;
+  set label(RenderBox? value) {
+    _label = _updateChild(_label, value, _ChipSlot.label);
+  }
 
   _ChipRenderTheme get theme => _theme;
   _ChipRenderTheme _theme;
@@ -2255,8 +2370,7 @@
   }
 
   // The returned list is ordered for hit testing.
-  @override
-  Iterable<RenderBox> get children sync* {
+  Iterable<RenderBox> get _children sync* {
     if (avatar != null) {
       yield avatar!;
     }
@@ -2272,6 +2386,47 @@
   bool get deleteIconShowing => !deleteDrawerAnimation.isDismissed;
 
   @override
+  void attach(PipelineOwner owner) {
+    super.attach(owner);
+    for (final RenderBox child in _children) {
+      child.attach(owner);
+    }
+  }
+
+  @override
+  void detach() {
+    super.detach();
+    for (final RenderBox child in _children) {
+      child.detach();
+    }
+  }
+
+  @override
+  void redepthChildren() {
+    _children.forEach(redepthChild);
+  }
+
+  @override
+  void visitChildren(RenderObjectVisitor visitor) {
+    _children.forEach(visitor);
+  }
+
+  @override
+  List<DiagnosticsNode> debugDescribeChildren() {
+    final List<DiagnosticsNode> value = <DiagnosticsNode>[];
+    void add(RenderBox? child, String name) {
+      if (child != null) {
+        value.add(child.toDiagnosticsNode(name: name));
+      }
+    }
+
+    add(avatar, 'avatar');
+    add(label, 'label');
+    add(deleteIcon, 'deleteIcon');
+    return value;
+  }
+
+  @override
   bool get sizedByParent => false;
 
   static double _minWidth(RenderBox? box, double height) {
diff --git a/packages/flutter/lib/src/material/input_decorator.dart b/packages/flutter/lib/src/material/input_decorator.dart
index 7e9d5e9..ba9d7ec 100644
--- a/packages/flutter/lib/src/material/input_decorator.dart
+++ b/packages/flutter/lib/src/material/input_decorator.dart
@@ -682,7 +682,7 @@
 }
 
 // The workhorse: layout and paint a _Decorator widget's _Decoration.
-class _RenderDecoration extends RenderBox with SlottedContainerRenderObjectMixin<_DecorationSlot> {
+class _RenderDecoration extends RenderBox {
   _RenderDecoration({
     required _Decoration decoration,
     required TextDirection textDirection,
@@ -702,22 +702,88 @@
        _expands = expands;
 
   static const double subtextGap = 8.0;
+  final Map<_DecorationSlot, RenderBox> children = <_DecorationSlot, RenderBox>{};
 
-  RenderBox? get icon => childForSlot(_DecorationSlot.icon);
-  RenderBox? get input => childForSlot(_DecorationSlot.input);
-  RenderBox? get label => childForSlot(_DecorationSlot.label);
-  RenderBox? get hint => childForSlot(_DecorationSlot.hint);
-  RenderBox? get prefix => childForSlot(_DecorationSlot.prefix);
-  RenderBox? get suffix => childForSlot(_DecorationSlot.suffix);
-  RenderBox? get prefixIcon => childForSlot(_DecorationSlot.prefixIcon);
-  RenderBox? get suffixIcon => childForSlot(_DecorationSlot.suffixIcon);
-  RenderBox? get helperError => childForSlot(_DecorationSlot.helperError);
-  RenderBox? get counter => childForSlot(_DecorationSlot.counter);
-  RenderBox? get container => childForSlot(_DecorationSlot.container);
+  RenderBox? _updateChild(RenderBox? oldChild, RenderBox? newChild, _DecorationSlot slot) {
+    if (oldChild != null) {
+      dropChild(oldChild);
+      children.remove(slot);
+    }
+    if (newChild != null) {
+      children[slot] = newChild;
+      adoptChild(newChild);
+    }
+    return newChild;
+  }
+
+  RenderBox? _icon;
+  RenderBox? get icon => _icon;
+  set icon(RenderBox? value) {
+    _icon = _updateChild(_icon, value, _DecorationSlot.icon);
+  }
+
+  RenderBox? _input;
+  RenderBox? get input => _input;
+  set input(RenderBox? value) {
+    _input = _updateChild(_input, value, _DecorationSlot.input);
+  }
+
+  RenderBox? _label;
+  RenderBox? get label => _label;
+  set label(RenderBox? value) {
+    _label = _updateChild(_label, value, _DecorationSlot.label);
+  }
+
+  RenderBox? _hint;
+  RenderBox? get hint => _hint;
+  set hint(RenderBox? value) {
+    _hint = _updateChild(_hint, value, _DecorationSlot.hint);
+  }
+
+  RenderBox? _prefix;
+  RenderBox? get prefix => _prefix;
+  set prefix(RenderBox? value) {
+    _prefix = _updateChild(_prefix, value, _DecorationSlot.prefix);
+  }
+
+  RenderBox? _suffix;
+  RenderBox? get suffix => _suffix;
+  set suffix(RenderBox? value) {
+    _suffix = _updateChild(_suffix, value, _DecorationSlot.suffix);
+  }
+
+  RenderBox? _prefixIcon;
+  RenderBox? get prefixIcon => _prefixIcon;
+  set prefixIcon(RenderBox? value) {
+    _prefixIcon = _updateChild(_prefixIcon, value, _DecorationSlot.prefixIcon);
+  }
+
+  RenderBox? _suffixIcon;
+  RenderBox? get suffixIcon => _suffixIcon;
+  set suffixIcon(RenderBox? value) {
+    _suffixIcon = _updateChild(_suffixIcon, value, _DecorationSlot.suffixIcon);
+  }
+
+  RenderBox? _helperError;
+  RenderBox? get helperError => _helperError;
+  set helperError(RenderBox? value) {
+    _helperError = _updateChild(_helperError, value, _DecorationSlot.helperError);
+  }
+
+  RenderBox? _counter;
+  RenderBox? get counter => _counter;
+  set counter(RenderBox? value) {
+    _counter = _updateChild(_counter, value, _DecorationSlot.counter);
+  }
+
+  RenderBox? _container;
+  RenderBox? get container => _container;
+  set container(RenderBox? value) {
+    _container = _updateChild(_container, value, _DecorationSlot.container);
+  }
 
   // The returned list is ordered for hit testing.
-  @override
-  Iterable<RenderBox> get children sync* {
+  Iterable<RenderBox> get _children sync* {
     if (icon != null)
       yield icon!;
     if (input != null)
@@ -817,6 +883,30 @@
   }
 
   @override
+  void attach(PipelineOwner owner) {
+    super.attach(owner);
+    for (final RenderBox child in _children)
+      child.attach(owner);
+  }
+
+  @override
+  void detach() {
+    super.detach();
+    for (final RenderBox child in _children)
+      child.detach();
+  }
+
+  @override
+  void redepthChildren() {
+    _children.forEach(redepthChild);
+  }
+
+  @override
+  void visitChildren(RenderObjectVisitor visitor) {
+    _children.forEach(visitor);
+  }
+
+  @override
   void visitChildrenForSemantics(RenderObjectVisitor visitor) {
     if (icon != null)
       visitor(icon!);
@@ -851,6 +941,27 @@
   }
 
   @override
+  List<DiagnosticsNode> debugDescribeChildren() {
+    final List<DiagnosticsNode> value = <DiagnosticsNode>[];
+    void add(RenderBox? child, String name) {
+      if (child != null)
+        value.add(child.toDiagnosticsNode(name: name));
+    }
+    add(icon, 'icon');
+    add(input, 'input');
+    add(label, 'label');
+    add(hint, 'hint');
+    add(prefix, 'prefix');
+    add(suffix, 'suffix');
+    add(prefixIcon, 'prefixIcon');
+    add(suffixIcon, 'suffixIcon');
+    add(helperError, 'helperError');
+    add(counter, 'counter');
+    add(container, 'container');
+    return value;
+  }
+
+  @override
   bool get sizedByParent => false;
 
   static double _minWidth(RenderBox? box, double height) {
@@ -1527,7 +1638,7 @@
   @override
   bool hitTestChildren(BoxHitTestResult result, { required Offset position }) {
     assert(position != null);
-    for (final RenderBox child in children) {
+    for (final RenderBox child in _children) {
       // The label must be handled specially since we've transformed it.
       final Offset offset = _boxParentData(child).offset;
       final bool isHit = result.addWithPaintOffset(
@@ -1556,7 +1667,146 @@
   }
 }
 
-class _Decorator extends RenderObjectWidget with SlottedMultiChildRenderObjectWidgetMixin<_DecorationSlot> {
+class _DecorationElement extends RenderObjectElement {
+  _DecorationElement(_Decorator widget) : super(widget);
+
+  final Map<_DecorationSlot, Element> slotToChild = <_DecorationSlot, Element>{};
+
+  @override
+  _Decorator get widget => super.widget as _Decorator;
+
+  @override
+  _RenderDecoration get renderObject => super.renderObject as _RenderDecoration;
+
+  @override
+  void visitChildren(ElementVisitor visitor) {
+    slotToChild.values.forEach(visitor);
+  }
+
+  @override
+  void forgetChild(Element child) {
+    assert(slotToChild.containsValue(child));
+    assert(child.slot is _DecorationSlot);
+    assert(slotToChild.containsKey(child.slot));
+    slotToChild.remove(child.slot);
+    super.forgetChild(child);
+  }
+
+  void _mountChild(Widget? widget, _DecorationSlot slot) {
+    final Element? oldChild = slotToChild[slot];
+    final Element? newChild = updateChild(oldChild, widget, slot);
+    if (oldChild != null) {
+      slotToChild.remove(slot);
+    }
+    if (newChild != null) {
+      slotToChild[slot] = newChild;
+    }
+  }
+
+  @override
+  void mount(Element? parent, Object? newSlot) {
+    super.mount(parent, newSlot);
+    _mountChild(widget.decoration.icon, _DecorationSlot.icon);
+    _mountChild(widget.decoration.input, _DecorationSlot.input);
+    _mountChild(widget.decoration.label, _DecorationSlot.label);
+    _mountChild(widget.decoration.hint, _DecorationSlot.hint);
+    _mountChild(widget.decoration.prefix, _DecorationSlot.prefix);
+    _mountChild(widget.decoration.suffix, _DecorationSlot.suffix);
+    _mountChild(widget.decoration.prefixIcon, _DecorationSlot.prefixIcon);
+    _mountChild(widget.decoration.suffixIcon, _DecorationSlot.suffixIcon);
+    _mountChild(widget.decoration.helperError, _DecorationSlot.helperError);
+    _mountChild(widget.decoration.counter, _DecorationSlot.counter);
+    _mountChild(widget.decoration.container, _DecorationSlot.container);
+  }
+
+  void _updateChild(Widget? widget, _DecorationSlot slot) {
+    final Element? oldChild = slotToChild[slot];
+    final Element? newChild = updateChild(oldChild, widget, slot);
+    if (oldChild != null) {
+      slotToChild.remove(slot);
+    }
+    if (newChild != null) {
+      slotToChild[slot] = newChild;
+    }
+  }
+
+  @override
+  void update(_Decorator newWidget) {
+    super.update(newWidget);
+    assert(widget == newWidget);
+    _updateChild(widget.decoration.icon, _DecorationSlot.icon);
+    _updateChild(widget.decoration.input, _DecorationSlot.input);
+    _updateChild(widget.decoration.label, _DecorationSlot.label);
+    _updateChild(widget.decoration.hint, _DecorationSlot.hint);
+    _updateChild(widget.decoration.prefix, _DecorationSlot.prefix);
+    _updateChild(widget.decoration.suffix, _DecorationSlot.suffix);
+    _updateChild(widget.decoration.prefixIcon, _DecorationSlot.prefixIcon);
+    _updateChild(widget.decoration.suffixIcon, _DecorationSlot.suffixIcon);
+    _updateChild(widget.decoration.helperError, _DecorationSlot.helperError);
+    _updateChild(widget.decoration.counter, _DecorationSlot.counter);
+    _updateChild(widget.decoration.container, _DecorationSlot.container);
+  }
+
+  void _updateRenderObject(RenderBox? child, _DecorationSlot slot) {
+    switch (slot) {
+      case _DecorationSlot.icon:
+        renderObject.icon = child;
+        break;
+      case _DecorationSlot.input:
+        renderObject.input = child;
+        break;
+      case _DecorationSlot.label:
+        renderObject.label = child;
+        break;
+      case _DecorationSlot.hint:
+        renderObject.hint = child;
+        break;
+      case _DecorationSlot.prefix:
+        renderObject.prefix = child;
+        break;
+      case _DecorationSlot.suffix:
+        renderObject.suffix = child;
+        break;
+      case _DecorationSlot.prefixIcon:
+        renderObject.prefixIcon = child;
+        break;
+      case _DecorationSlot.suffixIcon:
+        renderObject.suffixIcon = child;
+        break;
+      case _DecorationSlot.helperError:
+        renderObject.helperError = child;
+        break;
+      case _DecorationSlot.counter:
+        renderObject.counter = child;
+        break;
+      case _DecorationSlot.container:
+        renderObject.container = child;
+        break;
+    }
+  }
+
+  @override
+  void insertRenderObjectChild(RenderObject child, _DecorationSlot slot) {
+    assert(child is RenderBox);
+    _updateRenderObject(child as RenderBox, slot);
+    assert(renderObject.children.keys.contains(slot));
+  }
+
+  @override
+  void removeRenderObjectChild(RenderObject child, _DecorationSlot slot) {
+    assert(child is RenderBox);
+    assert(renderObject.children[slot] == child);
+    _updateRenderObject(null, slot);
+    assert(!renderObject.children.keys.contains(slot));
+  }
+
+  @override
+  void moveRenderObjectChild(RenderObject child, Object? oldSlot, Object? newSlot) {
+    assert(false, 'not reachable');
+  }
+}
+
+class _Decorator extends RenderObjectWidget {
   const _Decorator({
     Key? key,
     required this.textAlignVertical,
@@ -1579,35 +1829,7 @@
   final bool expands;
 
   @override
-  Iterable<_DecorationSlot> get slots => _DecorationSlot.values;
-
-  @override
-  Widget? childForSlot(_DecorationSlot slot) {
-    switch (slot) {
-      case _DecorationSlot.icon:
-        return decoration.icon;
-      case _DecorationSlot.input:
-        return decoration.input;
-      case _DecorationSlot.label:
-        return decoration.label;
-      case _DecorationSlot.hint:
-        return decoration.hint;
-      case _DecorationSlot.prefix:
-        return decoration.prefix;
-      case _DecorationSlot.suffix:
-        return decoration.suffix;
-      case _DecorationSlot.prefixIcon:
-        return decoration.prefixIcon;
-      case _DecorationSlot.suffixIcon:
-        return decoration.suffixIcon;
-      case _DecorationSlot.helperError:
-        return decoration.helperError;
-      case _DecorationSlot.counter:
-        return decoration.counter;
-      case _DecorationSlot.container:
-        return decoration.container;
-    }
-  }
+  _DecorationElement createElement() => _DecorationElement(this);
 
   @override
   _RenderDecoration createRenderObject(BuildContext context) {
diff --git a/packages/flutter/lib/src/material/list_tile.dart b/packages/flutter/lib/src/material/list_tile.dart
index 87a3c11..1c68b55 100644
--- a/packages/flutter/lib/src/material/list_tile.dart
+++ b/packages/flutter/lib/src/material/list_tile.dart
@@ -1266,7 +1266,7 @@
   trailing,
 }
 
-class _ListTile extends RenderObjectWidget with SlottedMultiChildRenderObjectWidgetMixin<_ListTileSlot> {
+class _ListTile extends RenderObjectWidget {
   const _ListTile({
     Key? key,
     this.leading,
@@ -1307,21 +1307,7 @@
   final double minLeadingWidth;
 
   @override
-  Iterable<_ListTileSlot> get slots => _ListTileSlot.values;
-
-  @override
-  Widget? childForSlot(_ListTileSlot slot) {
-    switch (slot) {
-      case _ListTileSlot.leading:
-        return leading;
-      case _ListTileSlot.title:
-        return title;
-      case _ListTileSlot.subtitle:
-        return subtitle;
-      case _ListTileSlot.trailing:
-        return trailing;
-    }
-  }
+  _ListTileElement createElement() => _ListTileElement(this);
 
   @override
   _RenderListTile createRenderObject(BuildContext context) {
@@ -1353,7 +1339,111 @@
   }
 }
 
-class _RenderListTile extends RenderBox with SlottedContainerRenderObjectMixin<_ListTileSlot> {
+class _ListTileElement extends RenderObjectElement {
+  _ListTileElement(_ListTile widget) : super(widget);
+
+  final Map<_ListTileSlot, Element> slotToChild = <_ListTileSlot, Element>{};
+
+  @override
+  _ListTile get widget => super.widget as _ListTile;
+
+  @override
+  _RenderListTile get renderObject => super.renderObject as _RenderListTile;
+
+  @override
+  void visitChildren(ElementVisitor visitor) {
+    slotToChild.values.forEach(visitor);
+  }
+
+  @override
+  void forgetChild(Element child) {
+    assert(slotToChild.containsValue(child));
+    assert(child.slot is _ListTileSlot);
+    assert(slotToChild.containsKey(child.slot));
+    slotToChild.remove(child.slot);
+    super.forgetChild(child);
+  }
+
+  void _mountChild(Widget? widget, _ListTileSlot slot) {
+    final Element? oldChild = slotToChild[slot];
+    final Element? newChild = updateChild(oldChild, widget, slot);
+    if (oldChild != null) {
+      slotToChild.remove(slot);
+    }
+    if (newChild != null) {
+      slotToChild[slot] = newChild;
+    }
+  }
+
+  @override
+  void mount(Element? parent, Object? newSlot) {
+    super.mount(parent, newSlot);
+    _mountChild(widget.leading, _ListTileSlot.leading);
+    _mountChild(widget.title, _ListTileSlot.title);
+    _mountChild(widget.subtitle, _ListTileSlot.subtitle);
+    _mountChild(widget.trailing, _ListTileSlot.trailing);
+  }
+
+  void _updateChild(Widget? widget, _ListTileSlot slot) {
+    final Element? oldChild = slotToChild[slot];
+    final Element? newChild = updateChild(oldChild, widget, slot);
+    if (oldChild != null) {
+      slotToChild.remove(slot);
+    }
+    if (newChild != null) {
+      slotToChild[slot] = newChild;
+    }
+  }
+
+  @override
+  void update(_ListTile newWidget) {
+    super.update(newWidget);
+    assert(widget == newWidget);
+    _updateChild(widget.leading, _ListTileSlot.leading);
+    _updateChild(widget.title, _ListTileSlot.title);
+    _updateChild(widget.subtitle, _ListTileSlot.subtitle);
+    _updateChild(widget.trailing, _ListTileSlot.trailing);
+  }
+
+  void _updateRenderObject(RenderBox? child, _ListTileSlot slot) {
+    switch (slot) {
+      case _ListTileSlot.leading:
+        renderObject.leading = child;
+        break;
+      case _ListTileSlot.title:
+        renderObject.title = child;
+        break;
+      case _ListTileSlot.subtitle:
+        renderObject.subtitle = child;
+        break;
+      case _ListTileSlot.trailing:
+        renderObject.trailing = child;
+        break;
+    }
+  }
+
+  @override
+  void insertRenderObjectChild(RenderObject child, _ListTileSlot slot) {
+    assert(child is RenderBox);
+    _updateRenderObject(child as RenderBox, slot);
+    assert(renderObject.children.keys.contains(slot));
+  }
+
+  @override
+  void removeRenderObjectChild(RenderObject child, _ListTileSlot slot) {
+    assert(child is RenderBox);
+    assert(renderObject.children[slot] == child);
+    _updateRenderObject(null, slot);
+    assert(!renderObject.children.keys.contains(slot));
+  }
+
+  @override
+  void moveRenderObjectChild(RenderObject child, Object? oldSlot, Object? newSlot) {
+    assert(false, 'not reachable');
+  }
+}
+
+class _RenderListTile extends RenderBox {
   _RenderListTile({
     required bool isDense,
     required VisualDensity visualDensity,
@@ -1382,14 +1472,46 @@
        _minVerticalPadding = minVerticalPadding,
        _minLeadingWidth = minLeadingWidth;
 
-  RenderBox? get leading => childForSlot(_ListTileSlot.leading);
-  RenderBox? get title => childForSlot(_ListTileSlot.title);
-  RenderBox? get subtitle => childForSlot(_ListTileSlot.subtitle);
-  RenderBox? get trailing => childForSlot(_ListTileSlot.trailing);
+  final Map<_ListTileSlot, RenderBox> children = <_ListTileSlot, RenderBox>{};
+
+  RenderBox? _updateChild(RenderBox? oldChild, RenderBox? newChild, _ListTileSlot slot) {
+    if (oldChild != null) {
+      dropChild(oldChild);
+      children.remove(slot);
+    }
+    if (newChild != null) {
+      children[slot] = newChild;
+      adoptChild(newChild);
+    }
+    return newChild;
+  }
+
+  RenderBox? _leading;
+  RenderBox? get leading => _leading;
+  set leading(RenderBox? value) {
+    _leading = _updateChild(_leading, value, _ListTileSlot.leading);
+  }
+
+  RenderBox? _title;
+  RenderBox? get title => _title;
+  set title(RenderBox? value) {
+    _title = _updateChild(_title, value, _ListTileSlot.title);
+  }
+
+  RenderBox? _subtitle;
+  RenderBox? get subtitle => _subtitle;
+  set subtitle(RenderBox? value) {
+    _subtitle = _updateChild(_subtitle, value, _ListTileSlot.subtitle);
+  }
+
+  RenderBox? _trailing;
+  RenderBox? get trailing => _trailing;
+  set trailing(RenderBox? value) {
+    _trailing = _updateChild(_trailing, value, _ListTileSlot.trailing);
+  }
 
   // The returned list is ordered for hit testing.
-  @override
-  Iterable<RenderBox> get children sync* {
+  Iterable<RenderBox> get _children sync* {
     if (leading != null)
       yield leading!;
     if (title != null)
@@ -1494,6 +1616,44 @@
   }
 
   @override
+  void attach(PipelineOwner owner) {
+    super.attach(owner);
+    for (final RenderBox child in _children)
+      child.attach(owner);
+  }
+
+  @override
+  void detach() {
+    super.detach();
+    for (final RenderBox child in _children)
+      child.detach();
+  }
+
+  @override
+  void redepthChildren() {
+    _children.forEach(redepthChild);
+  }
+
+  @override
+  void visitChildren(RenderObjectVisitor visitor) {
+    _children.forEach(visitor);
+  }
+
+  @override
+  List<DiagnosticsNode> debugDescribeChildren() {
+    final List<DiagnosticsNode> value = <DiagnosticsNode>[];
+    void add(RenderBox? child, String name) {
+      if (child != null)
+        value.add(child.toDiagnosticsNode(name: name));
+    }
+    add(leading, 'leading');
+    add(title, 'title');
+    add(subtitle, 'subtitle');
+    add(trailing, 'trailing');
+    return value;
+  }
+
+  @override
   bool get sizedByParent => false;
 
   static double _minWidth(RenderBox? box, double height) {
@@ -1745,7 +1905,7 @@
   @override
   bool hitTestChildren(BoxHitTestResult result, { required Offset position }) {
     assert(position != null);
-    for (final RenderBox child in children) {
+    for (final RenderBox child in _children) {
       final BoxParentData parentData = child.parentData! as BoxParentData;
       final bool isHit = result.addWithPaintOffset(
         offset: parentData.offset,
diff --git a/packages/flutter/lib/src/rendering/object.dart b/packages/flutter/lib/src/rendering/object.dart
index cf95c13..dd4248f 100644
--- a/packages/flutter/lib/src/rendering/object.dart
+++ b/packages/flutter/lib/src/rendering/object.dart
@@ -3167,11 +3167,6 @@
 /// parent data.
 ///
 /// Moreover, this is a required mixin for render objects returned to [MultiChildRenderObjectWidget].
-///
-/// See also:
-///
-///  * [SlottedContainerRenderObjectMixin], which organizes its children
-///    in different named slots.
 mixin ContainerRenderObjectMixin<ChildType extends RenderObject, ParentDataType extends ContainerParentDataMixin<ChildType>> on RenderObject {
   bool _debugUltimatePreviousSiblingOf(ChildType child, { ChildType? equals }) {
     ParentDataType childParentData = child.parentData! as ParentDataType;
diff --git a/packages/flutter/lib/src/widgets/framework.dart b/packages/flutter/lib/src/widgets/framework.dart
index 31cf0d0..ed0424f 100644
--- a/packages/flutter/lib/src/widgets/framework.dart
+++ b/packages/flutter/lib/src/widgets/framework.dart
@@ -1677,13 +1677,6 @@
 /// RenderObjectWidgets provide the configuration for [RenderObjectElement]s,
 /// which wrap [RenderObject]s, which provide the actual rendering of the
 /// application.
-///
-/// See also:
-///
-///  * [MultiChildRenderObjectWidget], which configures a [RenderObject] with
-///    a single list of children.
-///  * [SlottedMultiChildRenderObjectWidgetMixin], which configures a
-///    [RenderObject] that organizes its children in different named slots.
 abstract class RenderObjectWidget extends Widget {
   /// Abstract const constructor. This constructor enables subclasses to provide
   /// const constructors so that they can be used in const expressions.
@@ -1774,11 +1767,7 @@
 /// See also:
 ///
 ///  * [Stack], which uses [MultiChildRenderObjectWidget].
-///  * [RenderStack], for an example implementation of the associated render
-///    object.
-///  * [SlottedMultiChildRenderObjectWidgetMixin], which configures a
-///    [RenderObject] that instead of having a single list of children organizes
-///    its children in named slots.
+///  * [RenderStack], for an example implementation of the associated render object.
 abstract class MultiChildRenderObjectWidget extends RenderObjectWidget {
   /// Initializes fields for subclasses.
   ///
diff --git a/packages/flutter/lib/src/widgets/slotted_render_object_widget.dart b/packages/flutter/lib/src/widgets/slotted_render_object_widget.dart
deleted file mode 100644
index 25ae7b4..0000000
--- a/packages/flutter/lib/src/widgets/slotted_render_object_widget.dart
+++ /dev/null
@@ -1,271 +0,0 @@
-// Copyright 2014 The Flutter Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-import 'package:flutter/foundation.dart';
-import 'package:flutter/rendering.dart';
-
-import 'framework.dart';
-
-/// A mixin for a [RenderObjectWidget] that configures a [RenderObject]
-/// subclass, which organizes its children in different slots.
-///
-/// Implementers of this mixin have to provide the list of available slots by
-/// overriding [slots]. The list of slots must never change for a given class
-/// implementing this mixin. In the common case, [Enum] values are used as slots
-/// and [slots] is typically implemented to return the value of the enum's
-/// `values` getter.
-///
-/// Furthermore, [childForSlot] must be implemented to return the current
-/// widget configuration for a given slot.
-///
-/// The [RenderObject] returned by [createRenderObject] and updated by
-/// [updateRenderObject] must implement the [SlottedContainerRenderObjectMixin].
-///
-/// The type parameter `S` is the type for the slots to be used by this
-/// [RenderObjectWidget] and the [RenderObject] it configures. In the typical
-/// case, `S` is an [Enum] type.
-///
-/// {@tool dartpad}
-/// This example uses the [SlottedMultiChildRenderObjectWidgetMixin] in
-/// combination with the [SlottedContainerRenderObjectMixin] to implement a
-/// widget that provides two slots: topLeft and bottomRight. The widget arranges
-/// the children in those slots diagonally.
-///
-/// ** See code in examples/api/lib/widgets/slotted_render_object_widget/slotted_multi_child_render_object_widget_mixin.0.dart **
-/// {@end-tool}
-///
-/// See also:
-///
-///   * [MultiChildRenderObjectWidget], which configures a [RenderObject]
-///     with a single list of children.
-///   * [ListTile], which uses [SlottedMultiChildRenderObjectWidgetMixin] in its
-///     internal (private) implementation.
-mixin SlottedMultiChildRenderObjectWidgetMixin<S> on RenderObjectWidget {
-  /// Returns a list of all available slots.
-  ///
-  /// The list of slots must be static and must never change for a given class
-  /// implementing this mixin.
-  ///
-  /// Typically, an [Enum] is used to identify the different slots. In that case
-  /// this getter can be implemented by returning what the `values` getter
-  /// of the enum used returns.
-  @protected
-  Iterable<S> get slots;
-
-  /// Returns the widget that is currently occupying the provided `slot`.
-  ///
-  /// The [RenderObject] configured by this class will be configured to have
-  /// the [RenderObject] produced by the returned [Widget] in the provided
-  /// `slot`.
-  @protected
-  Widget? childForSlot(S slot);
-
-  @override
-  SlottedContainerRenderObjectMixin<S> createRenderObject(BuildContext context);
-
-  @override
-  void updateRenderObject(BuildContext context, SlottedContainerRenderObjectMixin<S> renderObject);
-
-  @override
-  SlottedRenderObjectElement<S> createElement() => SlottedRenderObjectElement<S>(this);
-}
-
-/// Mixin for a [RenderBox] configured by a [SlottedMultiChildRenderObjectWidgetMixin].
-///
-/// The [RenderBox] child currently occupying a given slot can be obtained by
-/// calling [childForSlot].
-///
-/// Implementers may consider overriding [children] to return the children
-/// of this render object in a consistent order (e.g. hit test order).
-///
-/// The type parameter `S` is the type for the slots to be used by this
-/// [RenderObject] and the [SlottedMultiChildRenderObjectWidgetMixin] it was
-/// configured by. In the typical case, `S` is an [Enum] type.
-///
-/// See [SlottedMultiChildRenderObjectWidgetMixin] for example code showcasing
-/// how this mixin is used in combination with the
-/// [SlottedMultiChildRenderObjectWidgetMixin].
-///
-/// See also:
-///
-///  * [ContainerRenderObjectMixin], which organizes its children in a single
-///    list.
-mixin SlottedContainerRenderObjectMixin<S> on RenderBox {
-  /// Returns the [RenderBox] child that is currently occupying the provided
-  /// `slot`.
-  ///
-  /// Returns null if no [RenderBox] is configured for the given slot.
-  @protected
-  RenderBox? childForSlot(S slot) => _slotToChild[slot];
-
-  /// Returns an [Iterable] of all non-null children.
-  ///
-  /// This getter is used by the default implementation of [attach], [detach],
-  /// [redepthChildren], [visitChildren], and [debugDescribeChildren] to iterate
-  /// over the children of this [RenderBox]. The base implementation makes no
-  /// guarantee about the order in which the children are returned. Subclasses,
-  /// for which the child order is important should override this getter and
-  /// return the children in the desired order.
-  @protected
-  Iterable<RenderBox> get children => _slotToChild.values;
-
-  /// Returns the debug name for a given `slot`.
-  ///
-  /// This method is called by [debugDescribeChildren] for each slot that is
-  /// currently occupied by a child to obtain a name for that slot for debug
-  /// outputs.
-  ///
-  /// The default implementation calls [EnumName.name] on `slot` it it is an
-  /// [Enum] value and `toString` if it is not.
-  @protected
-  String debugNameForSlot(S slot) {
-    if (slot is Enum) {
-      return slot.name;
-    }
-    return slot.toString();
-  }
-
-  @override
-  void attach(PipelineOwner owner) {
-    super.attach(owner);
-    for (final RenderBox child in children) {
-      child.attach(owner);
-    }
-  }
-
-  @override
-  void detach() {
-    super.detach();
-    for (final RenderBox child in children) {
-      child.detach();
-    }
-  }
-
-  @override
-  void redepthChildren() {
-    children.forEach(redepthChild);
-  }
-
-  @override
-  void visitChildren(RenderObjectVisitor visitor) {
-    children.forEach(visitor);
-  }
-
-  @override
-  List<DiagnosticsNode> debugDescribeChildren() {
-    final List<DiagnosticsNode> value = <DiagnosticsNode>[];
-    final Map<RenderBox, S> childToSlot = Map<RenderBox, S>.fromIterables(
-      _slotToChild.values,
-      _slotToChild.keys,
-    );
-    for (final RenderBox child in children) {
-      _addDiagnostics(child, value, debugNameForSlot(childToSlot[child] as S));
-    }
-    return value;
-  }
-
-  void _addDiagnostics(RenderBox child, List<DiagnosticsNode> value, String name) {
-    value.add(child.toDiagnosticsNode(name: name));
-  }
-
-  final Map<S, RenderBox> _slotToChild = <S, RenderBox>{};
-
-  void _setChild(RenderBox? child, S slot) {
-    final RenderBox? oldChild = _slotToChild[slot];
-    if (oldChild != null) {
-      dropChild(oldChild);
-      _slotToChild.remove(slot);
-    }
-    if (child != null) {
-      _slotToChild[slot] = child;
-      adoptChild(child);
-    }
-  }
-}
-
-/// Element used by the [SlottedMultiChildRenderObjectWidgetMixin].
-class SlottedRenderObjectElement<S> extends RenderObjectElement {
-  /// Creates an element that uses the given widget as its configuration.
-  SlottedRenderObjectElement(SlottedMultiChildRenderObjectWidgetMixin<S> widget) : super(widget);
-
-  final Map<S, Element> _slotToChild = <S, Element>{};
-
-  @override
-  SlottedMultiChildRenderObjectWidgetMixin<S> get widget => super.widget as SlottedMultiChildRenderObjectWidgetMixin<S>;
-
-  @override
-  SlottedContainerRenderObjectMixin<S> get renderObject => super.renderObject as SlottedContainerRenderObjectMixin<S>;
-
-  @override
-  void visitChildren(ElementVisitor visitor) {
-    _slotToChild.values.forEach(visitor);
-  }
-
-  @override
-  void forgetChild(Element child) {
-    assert(_slotToChild.containsValue(child));
-    assert(child.slot is S);
-    assert(_slotToChild.containsKey(child.slot));
-    _slotToChild.remove(child.slot);
-    super.forgetChild(child);
-  }
-
-  @override
-  void mount(Element? parent, Object? newSlot) {
-    super.mount(parent, newSlot);
-    _updateChildren();
-  }
-
-  @override
-  void update(SlottedMultiChildRenderObjectWidgetMixin<S> newWidget) {
-    super.update(newWidget);
-    assert(widget == newWidget);
-    _updateChildren();
-  }
-
-  List<S>? _debugPreviousSlots;
-
-  void _updateChildren() {
-    assert(() {
-      _debugPreviousSlots ??= widget.slots.toList();
-      return listEquals(_debugPreviousSlots, widget.slots.toList());
-    }(), '${widget.runtimeType}.slots must not change.');
-    assert(widget.slots.toSet().length == widget.slots.length, 'slots must be unique');
-
-    for (final S slot in widget.slots) {
-      _updateChild(widget.childForSlot(slot), slot);
-    }
-  }
-
-  void _updateChild(Widget? widget, S slot) {
-    final Element? oldChild = _slotToChild[slot];
-    assert(oldChild == null || oldChild.slot == slot); // Reason why [moveRenderObjectChild] is not reachable.
-    final Element? newChild = updateChild(oldChild, widget, slot);
-    if (oldChild != null) {
-      _slotToChild.remove(slot);
-    }
-    if (newChild != null) {
-      _slotToChild[slot] = newChild;
-    }
-  }
-
-  @override
-  void insertRenderObjectChild(RenderBox child, S slot) {
-    renderObject._setChild(child, slot);
-    assert(renderObject._slotToChild[slot] == child);
-  }
-
-  @override
-  void removeRenderObjectChild(RenderBox child, S slot) {
-    assert(renderObject._slotToChild[slot] == child);
-    renderObject._setChild(null, slot);
-    assert(renderObject._slotToChild[slot] == null);
-  }
-
-  @override
-  void moveRenderObjectChild(RenderBox child, Object? oldSlot, Object? newSlot) {
-    // Existing elements are never moved to a new slot, see assert in [_updateChild].
-    assert(false, 'not reachable');
-  }
-}
diff --git a/packages/flutter/lib/widgets.dart b/packages/flutter/lib/widgets.dart
index 62e702e..c424d6e 100644
--- a/packages/flutter/lib/widgets.dart
+++ b/packages/flutter/lib/widgets.dart
@@ -116,7 +116,6 @@
 export 'src/widgets/sliver_layout_builder.dart';
 export 'src/widgets/sliver_persistent_header.dart';
 export 'src/widgets/sliver_prototype_extent_list.dart';
-export 'src/widgets/slotted_render_object_widget.dart';
 export 'src/widgets/spacer.dart';
 export 'src/widgets/status_transitions.dart';
 export 'src/widgets/table.dart';
diff --git a/packages/flutter/test/material/chip_test.dart b/packages/flutter/test/material/chip_test.dart
index e229d00..f4e0a7c 100644
--- a/packages/flutter/test/material/chip_test.dart
+++ b/packages/flutter/test/material/chip_test.dart
@@ -15,7 +15,7 @@
 import 'feedback_tester.dart';
 
 Finder findRenderChipElement() {
-  return find.byElementPredicate((Element e) => '${e.renderObject.runtimeType}' == '_RenderChip');
+  return find.byElementPredicate((Element e) => '${e.runtimeType}' == '_RenderChipElement');
 }
 
 RenderBox getMaterialBox(WidgetTester tester) {
diff --git a/packages/flutter/test/widgets/slotted_render_object_widget_test.dart b/packages/flutter/test/widgets/slotted_render_object_widget_test.dart
deleted file mode 100644
index 7da4ae4..0000000
--- a/packages/flutter/test/widgets/slotted_render_object_widget_test.dart
+++ /dev/null
@@ -1,292 +0,0 @@
-// Copyright 2014 The Flutter Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-import 'package:flutter/foundation.dart';
-import 'package:flutter/material.dart';
-import 'package:flutter/rendering.dart';
-import 'package:flutter/widgets.dart';
-import 'package:flutter_test/flutter_test.dart';
-
-import '../rendering/mock_canvas.dart';
-
-const Color green = Color(0xFF00FF00);
-const Color yellow = Color(0xFFFFFF00);
-
-void main() {
-  testWidgets('SlottedRenderObjectWidget test', (WidgetTester tester) async {
-    await tester.pumpWidget(buildWidget(
-      topLeft: Container(
-        height: 100,
-        width: 80,
-        color: yellow,
-        child: const Text('topLeft'),
-      ),
-      bottomRight: Container(
-        height: 120,
-        width: 110,
-        color: green,
-        child: const Text('bottomRight'),
-      ),
-    ));
-
-    expect(find.text('topLeft'), findsOneWidget);
-    expect(find.text('bottomRight'), findsOneWidget);
-    expect(tester.getSize(find.byType(_Diagonal)), const Size(80 + 110, 100 + 120));
-    expect(find.byType(_Diagonal), paints
-      ..rect(
-        rect: const Rect.fromLTWH(0, 0, 80, 100),
-        color: yellow,
-      )
-      ..rect(
-        rect: const Rect.fromLTWH(80, 100, 110, 120),
-        color: green,
-      )
-    );
-
-    await tester.pumpWidget(buildWidget(
-      topLeft: Container(
-        height: 200,
-        width: 100,
-        color: yellow,
-        child: const Text('topLeft'),
-      ),
-      bottomRight: Container(
-        height: 220,
-        width: 210,
-        color: green,
-        child: const Text('bottomRight'),
-      ),
-    ));
-
-    expect(find.text('topLeft'), findsOneWidget);
-    expect(find.text('bottomRight'), findsOneWidget);
-    expect(tester.getSize(find.byType(_Diagonal)), const Size(100 + 210, 200 + 220));
-    expect(find.byType(_Diagonal), paints
-      ..rect(
-        rect: const Rect.fromLTWH(0, 0, 100, 200),
-        color: yellow,
-      )
-      ..rect(
-        rect: const Rect.fromLTWH(100, 200, 210, 220),
-        color: green,
-      )
-    );
-
-    await tester.pumpWidget(buildWidget(
-      topLeft: Container(
-        height: 200,
-        width: 100,
-        color: yellow,
-        child: const Text('topLeft'),
-      ),
-      bottomRight: Container(
-        key: UniqueKey(),
-        height: 230,
-        width: 220,
-        color: green,
-        child: const Text('bottomRight'),
-      ),
-    ));
-
-    expect(find.text('topLeft'), findsOneWidget);
-    expect(find.text('bottomRight'), findsOneWidget);
-    expect(tester.getSize(find.byType(_Diagonal)), const Size(100 + 220, 200 + 230));
-    expect(find.byType(_Diagonal), paints
-      ..rect(
-        rect: const Rect.fromLTWH(0, 0, 100, 200),
-        color: yellow,
-      )
-      ..rect(
-        rect: const Rect.fromLTWH(100, 200, 220, 230),
-        color: green,
-      )
-    );
-
-    await tester.pumpWidget(buildWidget(
-      topLeft: Container(
-        height: 200,
-        width: 100,
-        color: yellow,
-        child: const Text('topLeft'),
-      ),
-    ));
-
-    expect(find.text('topLeft'), findsOneWidget);
-    expect(find.text('bottomRight'), findsNothing);
-    expect(tester.getSize(find.byType(_Diagonal)), const Size(100, 200));
-    expect(find.byType(_Diagonal), paints
-      ..rect(
-        rect: const Rect.fromLTWH(0, 0, 100, 200),
-        color: yellow,
-      )
-    );
-
-    await tester.pumpWidget(buildWidget());
-    expect(find.text('topLeft'), findsNothing);
-    expect(find.text('bottomRight'), findsNothing);
-    expect(tester.getSize(find.byType(_Diagonal)), Size.zero);
-    expect(find.byType(_Diagonal), paintsNothing);
-
-    await tester.pumpWidget(Container());
-    expect(find.byType(_Diagonal), findsNothing);
-  });
-
-  test('nameForSlot', () {
-    expect(_RenderDiagonal().publicNameForSlot(_DiagonalSlot.bottomRight), 'bottomRight');
-    expect(_RenderDiagonal().publicNameForSlot(_DiagonalSlot.topLeft), 'topLeft');
-    final _Slot slot = _Slot();
-    expect(_RenderTest().publicNameForSlot(slot), slot.toString());
-  });
-
-  testWidgets('debugDescribeChildren', (WidgetTester tester) async {
-    await tester.pumpWidget(buildWidget(
-      topLeft: const SizedBox(
-        height: 100,
-        width: 80,
-      ),
-      bottomRight: const SizedBox(
-        height: 120,
-        width: 110,
-      ),
-    ));
-
-    expect(
-      tester.renderObject(find.byType(_Diagonal)).toStringDeep(),
-      equalsIgnoringHashCodes(r'''
-_RenderDiagonal#00000 relayoutBoundary=up1
- │ creator: _Diagonal ← Align ← Directionality ← [root]
- │ parentData: offset=Offset(0.0, 0.0) (can use size)
- │ constraints: BoxConstraints(0.0<=w<=800.0, 0.0<=h<=600.0)
- │ size: Size(190.0, 220.0)
- │
- ├─topLeft: RenderConstrainedBox#00000 relayoutBoundary=up2
- │   creator: SizedBox ← _Diagonal ← Align ← Directionality ← [root]
- │   parentData: offset=Offset(0.0, 0.0) (can use size)
- │   constraints: BoxConstraints(unconstrained)
- │   size: Size(80.0, 100.0)
- │   additionalConstraints: BoxConstraints(w=80.0, h=100.0)
- │
- └─bottomRight: RenderConstrainedBox#00000 relayoutBoundary=up2
-     creator: SizedBox ← _Diagonal ← Align ← Directionality ← [root]
-     parentData: offset=Offset(80.0, 100.0) (can use size)
-     constraints: BoxConstraints(unconstrained)
-     size: Size(110.0, 120.0)
-     additionalConstraints: BoxConstraints(w=110.0, h=120.0)
-''')
-    );
-  });
-}
-
-Widget buildWidget({Widget? topLeft, Widget? bottomRight}) {
-  return Directionality(
-    textDirection: TextDirection.ltr,
-    child: Align(
-      alignment: Alignment.topLeft,
-      child: _Diagonal(
-        topLeft: topLeft,
-        bottomRight: bottomRight,
-      ),
-    ),
-  );
-}
-
-enum _DiagonalSlot {
-  topLeft,
-  bottomRight,
-}
-
-class _Diagonal extends RenderObjectWidget with SlottedMultiChildRenderObjectWidgetMixin<_DiagonalSlot> {
-  const _Diagonal({
-    Key? key,
-    this.topLeft,
-    this.bottomRight,
-    this.backgroundColor,
-  }) : super(key: key);
-
-  final Widget? topLeft;
-  final Widget? bottomRight;
-  final Color? backgroundColor;
-
-  @override
-  Iterable<_DiagonalSlot> get slots => _DiagonalSlot.values;
-
-  @override
-  Widget? childForSlot(Object slot) {
-    switch (slot) {
-      case _DiagonalSlot.topLeft:
-        return topLeft;
-      case _DiagonalSlot.bottomRight:
-        return bottomRight;
-    }
-  }
-
-  @override
-  SlottedContainerRenderObjectMixin<_DiagonalSlot> createRenderObject(
-    BuildContext context,
-  ) {
-    return _RenderDiagonal();
-  }
-}
-
-class _RenderDiagonal extends RenderBox with SlottedContainerRenderObjectMixin<_DiagonalSlot> {
-  RenderBox? get _topLeft => childForSlot(_DiagonalSlot.topLeft);
-  RenderBox? get _bottomRight => childForSlot(_DiagonalSlot.bottomRight);
-
-  @override
-  void performLayout() {
-    const BoxConstraints childConstraints = BoxConstraints();
-
-    Size topLeftSize = Size.zero;
-    if (_topLeft != null) {
-      _topLeft!.layout(childConstraints, parentUsesSize: true);
-      _positionChild(_topLeft!, Offset.zero);
-      topLeftSize = _topLeft!.size;
-    }
-
-    Size bottomRightSize = Size.zero;
-    if (_bottomRight != null) {
-      _bottomRight!.layout(childConstraints, parentUsesSize: true);
-      _positionChild(
-        _bottomRight!,
-        Offset(topLeftSize.width, topLeftSize.height),
-      );
-      bottomRightSize = _bottomRight!.size;
-    }
-
-    size = constraints.constrain(Size(
-      topLeftSize.width + bottomRightSize.width,
-      topLeftSize.height + bottomRightSize.height,
-    ));
-  }
-
-  void _positionChild(RenderBox child, Offset offset) {
-    (child.parentData! as BoxParentData).offset = offset;
-  }
-
-  @override
-  void paint(PaintingContext context, Offset offset) {
-    if (_topLeft != null) {
-      _paintChild(_topLeft!, context, offset);
-    }
-    if (_bottomRight != null) {
-      _paintChild(_bottomRight!, context, offset);
-    }
-  }
-
-  void _paintChild(RenderBox child, PaintingContext context, Offset offset) {
-    final BoxParentData childParentData = child.parentData! as BoxParentData;
-    context.paintChild(child, childParentData.offset + offset);
-  }
-
-  String publicNameForSlot(_DiagonalSlot slot) => debugNameForSlot(slot);
-}
-
-class _Slot {
-  @override
-  String toString() => describeIdentity(this);
-}
-
-class _RenderTest extends RenderBox with SlottedContainerRenderObjectMixin<_Slot> {
-  String publicNameForSlot(_Slot slot) => debugNameForSlot(slot);
-}