Fix _debugElementWasRebuilt global key asserts#105430
Fix _debugElementWasRebuilt global key asserts#105430LongCatIsLooong wants to merge 2 commits intoflutter:masterfrom
_debugElementWasRebuilt global key asserts#105430Conversation
There was a problem hiding this comment.
Element.updateChild is also evidence that this is being rebuilt.
Instead of doing _debugElementWasRebuilt(context) in buildScope just for LayoutBuilder this feels slightly better?
There was a problem hiding this comment.
To me this feels out of place here. We should detect before this place that the element was rebuild because it may potentially not have any children.
There was a problem hiding this comment.
because it may potentially not have any children.
that case is already taken care of here:
flutter/packages/flutter/lib/src/widgets/framework.dart
Lines 3562 to 3565 in 2aa348b
But the above line doesn't call _debugElementWasRebuilt on the root element Element that initiated the subtree update, like in LayoutBuilder:
With _debugElementWasRebuilt's current implementation it's OK for it to be called on the same Element multiple times in a frame.
There was a problem hiding this comment.
Another reason why this feels out of place here: technically you don't have to go through updateChild. You can just call the methods called from here directly and bypass updateChild completely.
There was a problem hiding this comment.
Hm, but I guess if you do that you miss also some of the other debug key-locig at the end of this method?
8cbca03 to
fd52cff
Compare
…bal key reparenting
fd52cff to
f894cc4
Compare
| try { | ||
| element.rebuild(); | ||
| assert(() { | ||
| _debugElementWasRebuilt(element); |
There was a problem hiding this comment.
This is duplication with the updateChild's check?
There was a problem hiding this comment.
Let _debugElementWasRebuilt returns true will simpler the assertion?
There was a problem hiding this comment.
rebuild doesn't necessarily call updateChild. The widget may not have a child.
There was a problem hiding this comment.
rebuilddoesn't necessarily callupdateChild. The widget may not have a child.
I mean if we check here, the new check you added to updateChild by this change is unnecessary.
But the check above when callback is non-null should retain.
There was a problem hiding this comment.
Could you elaborate? You mean the 2 _debugElementWasRebuilt calls at the end of updateChild are not necessary?
There was a problem hiding this comment.
Could you elaborate? You mean the 2
_debugElementWasRebuiltcalls at the end ofupdateChildare not necessary?
Right.
There was a problem hiding this comment.
LayoutBuilder doesn't call rebuild when it rebuilds in performLayout, nor does it parent call update on the layout builder so those are still needed. I don't think we want to call _debugElementWasRebuilt(context) in invokeLayoutCallback since it's not guaranteed that context will be rebuilt.
There was a problem hiding this comment.
LayoutBuilder doesn't call rebuild when it rebuilds in
performLayout, nor does it parent callupdateon the layout builder so those are still needed. I don't think we want to call_debugElementWasRebuilt(context)ininvokeLayoutCallbacksince it's not guaranteed thatcontextwill be rebuilt.
Add a test for this?
There was a problem hiding this comment.
It's covered by existing tests I think. I can add one that specifically verifies that _debugElementWasRebuilt(context) is no longer being called and there's no false negatives because we removed _debugElementWasRebuilt(context) but that one feels a little bit too specific to be useful?
There was a problem hiding this comment.
We can add a test that failed #105492 to prevent regression by accident. : )
|
It looks like this is fixing two distinct issues? And there is no dependency between the two fixes? Maybe break this up into two separate PRs to make potential breakages easier to debug and roll-backs more targeted? |
There was a problem hiding this comment.
To me this feels out of place here. We should detect before this place that the element was rebuild because it may potentially not have any children.
| List<S>? _debugPreviousSlots; | ||
|
|
||
| void _updateChildren() { | ||
| void _updateChildren(SlottedMultiChildRenderObjectWidgetMixin<S> newWidget) { |
There was a problem hiding this comment.
This newly added parameter appears unused?
| }(), '${widget.runtimeType}.slots must not change.'); | ||
| assert(slottedMultiChildRenderObjectWidgetMixin.slots.toSet().length == slottedMultiChildRenderObjectWidgetMixin.slots.length, 'slots must be unique'); | ||
|
|
||
| final Map<GlobalKey, S> globalKeyedSlots = _globalKeyToSlot; |
There was a problem hiding this comment.
Maybe rename this to oldGlobalKedSlots to avoid confusion?
| _updateChild(slottedMultiChildRenderObjectWidgetMixin.childForSlot(slot), slot); | ||
| final Widget? widget = slottedMultiChildRenderObjectWidgetMixin.childForSlot(slot); | ||
| final Key? newWidgetKey = widget?.key; | ||
| if (widget != null && newWidgetKey is GlobalKey) { |
There was a problem hiding this comment.
This now has me wondering: Don't we need to do this for all keys, not just globalkeys? If a keyed widget changes slots, it should be matched with the element from the previous slot it was in?
_debugElementWasRebuilt global key asserts & handle global key reparenting for SlottedMultiChildRenderObjectWidgetMixin _debugElementWasRebuilt global key asserts
|
Looking at this some more: The most obvious place to call |
|
|
You're right. That's probably the reason why we currently call I just experimented with this. If I only call |
|
I think we currently account for that by doing this: But that doesn't seem to be the right place to do that. |
Byproduct of #105335
Pre-launch Checklist
///).If you need help, consider asking for advice on the #hackers-new channel on Discord.