Commit 12054e33 authored by Ian Hickson's avatar Ian Hickson Committed by GitHub

Clean up some of the fn3 debugging logic. (#6024)

The debugging logic was lagging behind the recent actual logic changes,
especially around buildScope.
parent fea4a91a
...@@ -1607,7 +1607,7 @@ class BuildOwner { ...@@ -1607,7 +1607,7 @@ class BuildOwner {
/// Only one [buildScope] can be active at a time. /// Only one [buildScope] can be active at a time.
/// ///
/// A [buildScope] implies a [lockState] scope as well. /// A [buildScope] implies a [lockState] scope as well.
void buildScope(Element context, [VoidCallback callback]) { void buildScope(BuildableElement context, [VoidCallback callback]) {
if (callback == null && _dirtyElements.isEmpty) if (callback == null && _dirtyElements.isEmpty)
return; return;
assert(context != null); assert(context != null);
...@@ -1623,8 +1623,27 @@ class BuildOwner { ...@@ -1623,8 +1623,27 @@ class BuildOwner {
Timeline.startSync('Build'); Timeline.startSync('Build');
try { try {
_scheduledFlushDirtyElements = true; _scheduledFlushDirtyElements = true;
if (callback != null) if (callback != null) {
callback(); assert(context is BuildableElement);
assert(_debugStateLocked);
BuildableElement debugPreviousBuildTarget;
assert(() {
context._debugSetAllowIgnoredCallsToMarkNeedsBuild(true);
debugPreviousBuildTarget = _debugCurrentBuildTarget;
_debugCurrentBuildTarget = context;
return true;
});
try {
callback();
} finally {
assert(() {
context._debugSetAllowIgnoredCallsToMarkNeedsBuild(false);
assert(_debugCurrentBuildTarget == context);
_debugCurrentBuildTarget = debugPreviousBuildTarget;
return true;
});
}
}
_dirtyElements.sort(_elementSort); _dirtyElements.sort(_elementSort);
_dirtyElementsNeedsResorting = false; _dirtyElementsNeedsResorting = false;
int dirtyCount = _dirtyElements.length; int dirtyCount = _dirtyElements.length;
...@@ -2423,6 +2442,10 @@ class ErrorWidget extends LeafRenderObjectWidget { ...@@ -2423,6 +2442,10 @@ class ErrorWidget extends LeafRenderObjectWidget {
} }
/// An [Element] that can be marked dirty and rebuilt. /// An [Element] that can be marked dirty and rebuilt.
///
/// In practice, all subclasses of [Element] in the Flutter framework are
/// subclasses of [BuildableElement]. The distinction exists primarily to
/// segregate unrelated code.
abstract class BuildableElement extends Element { abstract class BuildableElement extends Element {
/// Creates an element that uses the given widget as its configuration. /// Creates an element that uses the given widget as its configuration.
BuildableElement(Widget widget) : super(widget); BuildableElement(Widget widget) : super(widget);
...@@ -2464,26 +2487,34 @@ abstract class BuildableElement extends Element { ...@@ -2464,26 +2487,34 @@ abstract class BuildableElement extends Element {
assert(_debugLifecycleState == _ElementLifecycle.active); assert(_debugLifecycleState == _ElementLifecycle.active);
assert(() { assert(() {
if (owner._debugBuilding) { if (owner._debugBuilding) {
if (owner._debugCurrentBuildTarget == null) { assert(owner._debugCurrentBuildTarget != null);
// If _debugCurrentBuildTarget is null, we're not actually building a assert(owner._debugStateLocked);
// widget but instead building the root of the tree via runApp.
// TODO(abarth): Remove these cases and ensure that we always have
// a current build target when we're building.
return true;
}
if (_debugIsInScope(owner._debugCurrentBuildTarget)) if (_debugIsInScope(owner._debugCurrentBuildTarget))
return true; return true;
} if (!_debugAllowIgnoredCallsToMarkNeedsBuild) {
if (owner._debugStateLocked && (!_debugAllowIgnoredCallsToMarkNeedsBuild || !dirty)) { throw new FlutterError(
'setState() or markNeedsBuild() called during build.\n'
'This ${widget.runtimeType} widget cannot be marked as needing to build because the framework '
'is already in the process of building widgets. A widget can be marked as '
'needing to be built during the build phase only if one of its ancestors '
'is currently building. This exception is allowed because the framework '
'builds parent widgets before children, which means a dirty descendant '
'will always be built. Otherwise, the framework might not visit this '
'widget during this build phase.\n'
'The widget on which setState() or markNeedsBuild() was called was:\n'
' $this\n'
'${owner._debugCurrentBuildTarget == null ? "" : "The widget which was currently being built when the offending call was made was:\n ${owner._debugCurrentBuildTarget}"}'
);
}
assert(dirty); // can only get here if we're not in scope, but ignored calls are allowed, and our call would somehow be ignored (since we're already dirty)
} else if (owner._debugStateLocked) {
assert(!_debugAllowIgnoredCallsToMarkNeedsBuild);
throw new FlutterError( throw new FlutterError(
'setState() or markNeedsBuild() called during build.\n' 'setState() or markNeedsBuild() called when widget tree was locked.\n'
'This widget cannot be marked as needing to build because the framework ' 'This ${widget.runtimeType} widget cannot be marked as needing to build '
'is already in the process of building widgets. A widget can be marked as ' 'because the framework is locked.\n'
'needing to be built during the build phase only if one if its ancestors ' 'The widget on which setState() or markNeedsBuild() was called was:\n'
'is currently building. This exception is allowed because the framework ' ' $this\n'
'builds parent widgets before children, which means a dirty descendant '
'will always be built. Otherwise, the framework might not visit this '
'widget during this build phase.'
); );
} }
return true; return true;
...@@ -2596,6 +2627,8 @@ Widget _buildNothing(BuildContext context) => null; ...@@ -2596,6 +2627,8 @@ Widget _buildNothing(BuildContext context) => null;
/// ///
/// Rather than creating a [RenderObject] directly, a [ComponentElement] creates /// Rather than creating a [RenderObject] directly, a [ComponentElement] creates
/// [RenderObject]s indirectly by creating other [Element]s. /// [RenderObject]s indirectly by creating other [Element]s.
///
/// Contrast with [RenderObjectElement].
abstract class ComponentElement extends BuildableElement { abstract class ComponentElement extends BuildableElement {
/// Creates an element that uses the given widget as its configuration. /// Creates an element that uses the given widget as its configuration.
ComponentElement(Widget widget) : super(widget); ComponentElement(Widget widget) : super(widget);
...@@ -2994,6 +3027,12 @@ class InheritedElement extends ProxyElement { ...@@ -2994,6 +3027,12 @@ class InheritedElement extends ProxyElement {
} }
/// An element that uses a [RenderObjectWidget] as its configuration. /// An element that uses a [RenderObjectWidget] as its configuration.
///
/// [RenderObjectElement] objects have an associated [RenderObject] widget in
/// the render tree, which handles concrete operations like laying out,
/// painting, and hit testing.
///
/// Contrast with [ComponentElement].
abstract class RenderObjectElement extends BuildableElement { abstract class RenderObjectElement extends BuildableElement {
/// Creates an element that uses the given widget as its configuration. /// Creates an element that uses the given widget as its configuration.
RenderObjectElement(RenderObjectWidget widget) : super(widget); RenderObjectElement(RenderObjectWidget widget) : super(widget);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment