Commit e5e5f61c authored by Ian Hickson's avatar Ian Hickson Committed by GitHub

Improve error messages from slivers. (#9971)

Also, fix some logic in SliverPadding.
parent 6ab29580
...@@ -384,7 +384,7 @@ class BoxConstraints extends Constraints { ...@@ -384,7 +384,7 @@ class BoxConstraints extends Constraints {
@override @override
bool debugAssertIsValid({ bool debugAssertIsValid({
bool isAppliedConstraint: false, bool isAppliedConstraint: false,
InformationCollector informationCollector InformationCollector informationCollector,
}) { }) {
assert(() { assert(() {
void throwError(String message) { void throwError(String message) {
......
...@@ -397,21 +397,31 @@ class SliverConstraints extends Constraints { ...@@ -397,21 +397,31 @@ class SliverConstraints extends Constraints {
@override @override
bool debugAssertIsValid({ bool debugAssertIsValid({
bool isAppliedConstraint: false, bool isAppliedConstraint: false,
InformationCollector informationCollector InformationCollector informationCollector,
}) { }) {
// TODO(ianh): make these show pretty errors assert(() {
assert(axis != null); void verify(bool check, String message) {
assert(growthDirection != null); if (check)
assert(scrollOffset != null); return;
assert(overlap != null); final StringBuffer information = new StringBuffer();
assert(remainingPaintExtent != null); if (informationCollector != null)
assert(crossAxisExtent != null); informationCollector(information);
assert(viewportMainAxisExtent != null); throw new FlutterError('$runtimeType is not valid: $message\n${information}The offending constraints were:\n $this');
assert(scrollOffset >= 0.0); }
assert(crossAxisExtent >= 0.0); verify(axis != null, 'The "axis" is null.');
assert(viewportMainAxisExtent >= 0.0); verify(growthDirection != null, 'The "growthDirection" is null.');
assert(remainingPaintExtent >= 0.0); verify(scrollOffset != null, 'The "scrollOffset" is null.');
assert(isNormalized); // should be redundant with earlier checks verify(overlap != null, 'The "overlap" is null.');
verify(remainingPaintExtent != null, 'The "remainingPaintExtent" is null.');
verify(crossAxisExtent != null, 'The "crossAxisExtent" is null.');
verify(viewportMainAxisExtent != null, 'The "viewportMainAxisExtent" is null.');
verify(scrollOffset >= 0.0, 'The "scrollOffset" is negative.');
verify(crossAxisExtent >= 0.0, 'The "crossAxisExtent" is negative.');
verify(viewportMainAxisExtent >= 0.0, 'The "viewportMainAxisExtent" is negative.');
verify(remainingPaintExtent >= 0.0, 'The "remainingPaintExtent" is negative.');
verify(isNormalized, 'The constraints are not normalized.'); // should be redundant with earlier checks
return true;
});
return true; return true;
} }
...@@ -566,39 +576,46 @@ class SliverGeometry { ...@@ -566,39 +576,46 @@ class SliverGeometry {
/// Asserts that this geometry is internally consistent. /// Asserts that this geometry is internally consistent.
/// ///
/// Does nothing if asserts are disabled. Always returns true. /// Does nothing if asserts are disabled. Always returns true.
bool get debugAssertIsValid { bool debugAssertIsValid({
assert(scrollExtent != null); InformationCollector informationCollector,
assert(scrollExtent >= 0.0); }) {
assert(paintExtent != null);
assert(paintExtent >= 0.0);
assert(paintOrigin != null);
assert(layoutExtent != null);
assert(layoutExtent >= 0.0);
assert(() { assert(() {
void verify(bool check, String message) {
if (check)
return;
final StringBuffer information = new StringBuffer();
if (informationCollector != null)
informationCollector(information);
throw new FlutterError('$runtimeType is not valid: $message\n$information');
}
verify(scrollExtent != null, 'The "scrollExtent" is null.');
verify(scrollExtent >= 0.0, 'The "scrollExtent" is negative.');
verify(paintExtent != null, 'The "paintExtent" is null.');
verify(paintExtent >= 0.0, 'The "paintExtent" is negative.');
verify(paintOrigin != null, 'The "paintOrigin" is null.');
verify(layoutExtent != null, 'The "layoutExtent" is null.');
verify(layoutExtent >= 0.0, 'The "layoutExtent" is negative.');
if (layoutExtent > paintExtent) { if (layoutExtent > paintExtent) {
throw new FlutterError( verify(false,
'SliverGeometry has a layoutExtent that exceeds its paintExtent.\n' + 'The "layoutExtent" exceeds the "paintExtent".\n' +
_debugCompareFloats('paintExtent', paintExtent, 'layoutExtent', layoutExtent) _debugCompareFloats('paintExtent', paintExtent, 'layoutExtent', layoutExtent),
); );
} }
return true; verify(maxPaintExtent != null, 'The "maxPaintExtent" is null.');
});
assert(maxPaintExtent != null);
assert(() {
if (maxPaintExtent < paintExtent) { if (maxPaintExtent < paintExtent) {
throw new FlutterError( verify(false,
'SliverGeometry has a maxPaintExtent that is less than its paintExtent.\n' + 'The "maxPaintExtent" is less than the "paintExtent".\n' +
_debugCompareFloats('maxPaintExtent', maxPaintExtent, 'paintExtent', paintExtent) + _debugCompareFloats('maxPaintExtent', maxPaintExtent, 'paintExtent', paintExtent) +
'By definition, a sliver can\'t paint more than the maximum that it can paint!' 'By definition, a sliver can\'t paint more than the maximum that it can paint!'
); );
} }
verify(hitTestExtent != null, 'The "hitTestExtent" is null.');
verify(hitTestExtent >= 0.0, 'The "hitTestExtent" is negative.');
verify(visible != null, 'The "visible" property is null.');
verify(hasVisualOverflow != null, 'The "hasVisualOverflow" is null.');
verify(scrollOffsetCorrection != null, 'The "scrollOffsetCorrection" is null.');
return true; return true;
}); });
assert(hitTestExtent != null);
assert(hitTestExtent >= 0.0);
assert(visible != null);
assert(hasVisualOverflow != null);
assert(scrollOffsetCorrection != null);
return true; return true;
} }
...@@ -837,7 +854,12 @@ abstract class RenderSliver extends RenderObject { ...@@ -837,7 +854,12 @@ abstract class RenderSliver extends RenderObject {
@override @override
void debugAssertDoesMeetConstraints() { void debugAssertDoesMeetConstraints() {
assert(geometry.debugAssertIsValid); assert(geometry.debugAssertIsValid(
informationCollector: (StringBuffer information) {
information.writeln('The RenderSliver that returned the offending geometry was:');
information.writeln(' ${toStringShallow('\n ')}');
},
));
assert(() { assert(() {
if (geometry.paintExtent > constraints.remainingPaintExtent) { if (geometry.paintExtent > constraints.remainingPaintExtent) {
throw new FlutterError( throw new FlutterError(
......
...@@ -162,16 +162,14 @@ class RenderSliverPadding extends RenderSliver with RenderObjectWithChildMixin<R ...@@ -162,16 +162,14 @@ class RenderSliverPadding extends RenderSliver with RenderObjectWithChildMixin<R
to: mainAxisPadding + childLayoutGeometry.scrollExtent, to: mainAxisPadding + childLayoutGeometry.scrollExtent,
); );
final double mainAxisPaddingPaintExtent = beforePaddingPaintExtent + afterPaddingPaintExtent; final double mainAxisPaddingPaintExtent = beforePaddingPaintExtent + afterPaddingPaintExtent;
final double paintExtent = math.min(
beforePaddingPaintExtent + math.max(childLayoutGeometry.paintExtent, childLayoutGeometry.layoutExtent + afterPaddingPaintExtent),
constraints.remainingPaintExtent,
);
geometry = new SliverGeometry( geometry = new SliverGeometry(
scrollExtent: mainAxisPadding + childLayoutGeometry.scrollExtent, scrollExtent: mainAxisPadding + childLayoutGeometry.scrollExtent,
paintExtent: math.min( paintExtent: paintExtent,
beforePaddingPaintExtent + math.max(childLayoutGeometry.paintExtent, childLayoutGeometry.layoutExtent + afterPaddingPaintExtent), layoutExtent: math.min(mainAxisPaddingPaintExtent + childLayoutGeometry.layoutExtent, paintExtent),
constraints.remainingPaintExtent,
),
layoutExtent: math.min(
mainAxisPaddingPaintExtent + childLayoutGeometry.layoutExtent,
constraints.remainingPaintExtent,
),
maxPaintExtent: mainAxisPadding + childLayoutGeometry.maxPaintExtent, maxPaintExtent: mainAxisPadding + childLayoutGeometry.maxPaintExtent,
hitTestExtent: math.max( hitTestExtent: math.max(
mainAxisPaddingPaintExtent + childLayoutGeometry.paintExtent, mainAxisPaddingPaintExtent + childLayoutGeometry.paintExtent,
......
...@@ -69,12 +69,12 @@ void main() { ...@@ -69,12 +69,12 @@ void main() {
}); });
test('SliverGeometry', () { test('SliverGeometry', () {
expect(const SliverGeometry().debugAssertIsValid, isTrue); expect(const SliverGeometry().debugAssertIsValid(), isTrue);
expect(() { expect(() {
const SliverGeometry(layoutExtent: 10.0, paintExtent: 9.0).debugAssertIsValid; const SliverGeometry(layoutExtent: 10.0, paintExtent: 9.0).debugAssertIsValid();
}, throwsFlutterError); }, throwsFlutterError);
expect(() { expect(() {
const SliverGeometry(paintExtent: 9.0, maxPaintExtent: 8.0).debugAssertIsValid; const SliverGeometry(paintExtent: 9.0, maxPaintExtent: 8.0).debugAssertIsValid();
}, throwsFlutterError); }, throwsFlutterError);
}); });
} }
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