Index: sky/sdk/lib/framework/fn2.dart |
diff --git a/sky/sdk/lib/framework/fn2.dart b/sky/sdk/lib/framework/fn2.dart |
index 931d4f379ef132c2c3b0674c41fdf6c509439528..69aaf7ad5e588e7f8b22582e48d756b402600933 100644 |
--- a/sky/sdk/lib/framework/fn2.dart |
+++ b/sky/sdk/lib/framework/fn2.dart |
@@ -116,6 +116,8 @@ abstract class UINode { |
// Returns the child which should be retained as the child of this node. |
UINode syncChild(UINode node, UINode oldNode, dynamic slot) { |
+ assert(oldNode is! Component || !oldNode._disqualifiedFromEverAppearingAgain); |
+ |
if (node == oldNode) { |
assert(node == null || node.mounted); |
return node; // Nothing to do. Subtrees must be identical. |
@@ -331,14 +333,15 @@ abstract class RenderObjectWrapper extends UINode { |
} |
abstract class OneChildRenderObjectWrapper extends RenderObjectWrapper { |
- final UINode child; |
+ UINode _child; |
+ UINode get child => _child; |
- OneChildRenderObjectWrapper({ this.child, Object key }) : super(key: key); |
+ OneChildRenderObjectWrapper({ UINode child, Object key }) : _child = child, super(key: key); |
void syncRenderObject(RenderObjectWrapper old) { |
super.syncRenderObject(old); |
UINode oldChild = old == null ? null : (old as OneChildRenderObjectWrapper).child; |
- syncChild(child, oldChild, null); |
+ _child = syncChild(child, oldChild, null); |
} |
void insert(RenderObjectWrapper child, dynamic slot) { |
@@ -531,6 +534,7 @@ abstract class MultiChildRenderObjectWrapper extends RenderObjectWrapper { |
void removeChild(UINode node) { |
final root = this.root; // TODO(ianh): Remove this once the analyzer is cleverer |
assert(root is ContainerRenderObjectMixin); |
+ assert(node.root.parent == root); |
root.remove(node.root); |
super.removeChild(node); |
assert(root == this.root); // TODO(ianh): Remove this once the analyzer is cleverer |
@@ -783,7 +787,7 @@ class Image extends RenderObjectWrapper { |
} |
} |
-List<Component> _dirtyComponents = new List<Component>(); |
+Set<Component> _dirtyComponents = new Set<Component>(); |
bool _buildScheduled = false; |
bool _inRenderDirtyComponents = false; |
@@ -797,8 +801,9 @@ void _buildDirtyComponents() { |
try { |
_inRenderDirtyComponents = true; |
- _dirtyComponents.sort((a, b) => a._order - b._order); |
- for (var comp in _dirtyComponents) { |
+ List<Component> sortedDirtyComponents = _dirtyComponents.toList(); |
+ sortedDirtyComponents.sort((Component a, Component b) => a._order - b._order); |
+ for (var comp in sortedDirtyComponents) { |
comp._buildIfDirty(); |
} |
@@ -832,6 +837,8 @@ abstract class Component extends UINode { |
bool get _isBuilding => _currentlyBuilding == this; |
bool _dirty = true; |
+ bool _disqualifiedFromEverAppearingAgain = false; |
+ |
UINode _built; |
final int _order; |
static int _currentOrder = 0; |
@@ -864,6 +871,7 @@ abstract class Component extends UINode { |
: this(key: key, stateful: stateful); |
void _didMount() { |
+ assert(!_disqualifiedFromEverAppearingAgain); |
super._didMount(); |
if (_mountCallbacks != null) |
for (Function fn in _mountCallbacks) |
@@ -890,6 +898,8 @@ abstract class Component extends UINode { |
} |
bool _willSync(UINode old) { |
+ assert(!_disqualifiedFromEverAppearingAgain); |
+ |
Component oldComponent = old as Component; |
if (oldComponent == null || !oldComponent._stateful) |
return false; |
@@ -898,6 +908,7 @@ abstract class Component extends UINode { |
_stateful = false; |
_built = oldComponent._built; |
assert(_built != null); |
+ _disqualifiedFromEverAppearingAgain = true; |
// Make |oldComponent| the "new" component |
reflect.copyPublicFields(this, oldComponent); |
@@ -916,6 +927,7 @@ abstract class Component extends UINode { |
*/ |
void _sync(UINode old, dynamic slot) { |
assert(_built == null || old == null); |
+ assert(!_disqualifiedFromEverAppearingAgain); |
Component oldComponent = old as Component; |
@@ -945,6 +957,7 @@ abstract class Component extends UINode { |
} |
void _buildIfDirty() { |
+ assert(!_disqualifiedFromEverAppearingAgain); |
if (!_dirty || !_mounted) |
return; |
@@ -957,6 +970,7 @@ abstract class Component extends UINode { |
} |
void setState(Function fn()) { |
+ assert(!_disqualifiedFromEverAppearingAgain); |
_stateful = true; |
fn(); |
if (_isBuilding || _dirty || !_mounted) |