Fix null check crash in MultiscriptsLayoutDelegate intrinsic layout#132
Fix null check crash in MultiscriptsLayoutDelegate intrinsic layout#132passte-llc wants to merge 1 commit into
Conversation
performHorizontalIntrinsicLayout and performVerticalIntrinsicLayout used non-null assertions on childrenWidths/childrenHeights/childrenBaselines lookups for _ScriptPos.base that are not guaranteed to succeed during intrinsic-size probing. When the base entry is missing, the assertion throws 'Null check operator used on a null value' inside performLayout(), which freezes the whole widget subtree. Replace the three assertions with a '?? 0.0' fallback: identical behavior when the entry is present, graceful degradation instead of a crash when it is absent. Fixes simpleclub#1 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
|
📝 WalkthroughWalkthroughThis change modifies ChangesIntrinsic Layout Null-Safety Fix
Estimated code review effort: 1 (Trivial) | ~5 minutes Related issues: Fixes a Suggested labels: bug, fix Suggested reviewers: znjameswu 🐰 A tiny hop through code so tight, 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
🧹 Nitpick comments (1)
lib/src/render/layout/multiscripts.dart (1)
136-142: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winConsider adding a regression test.
This fixes a reported crash (
Null check operator used on a null valueat Line 136). Sincebaseis a required, always-present child inMultiscripts's widget tree, the missing map entry is specific toCustomLayout's intrinsic-probing pass — worth a targeted golden/unit test (e.g. an intrinsic-width query on a nested subscript/superscript expression) to guard against regressing back to the unsafe!lookup.Also applies to: 184-192
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@lib/src/render/layout/multiscripts.dart` around lines 136 - 142, Add a regression test for Multiscripts to cover the intrinsic-probing path that can omit _ScriptPos.base from childrenWidths. Use the Multiscripts/CustomLayout flow exercised by nested subscript/superscript expressions and assert an intrinsic-width query no longer throws the null check exception. Place the test alongside the Multiscripts layout logic so it protects the baseSize lookup from regressing back to an unsafe ! access.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Nitpick comments:
In `@lib/src/render/layout/multiscripts.dart`:
- Around line 136-142: Add a regression test for Multiscripts to cover the
intrinsic-probing path that can omit _ScriptPos.base from childrenWidths. Use
the Multiscripts/CustomLayout flow exercised by nested subscript/superscript
expressions and assert an intrinsic-width query no longer throws the null check
exception. Place the test alongside the Multiscripts layout logic so it protects
the baseSize lookup from regressing back to an unsafe ! access.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 6539cd66-1895-411e-b696-b9f8e933a0bc
📒 Files selected for processing (1)
lib/src/render/layout/multiscripts.dart
Summary
Fixes #1.
MultiscriptsLayoutDelegate.performHorizontalIntrinsicLayoutandperformVerticalIntrinsicLayout(lib/src/render/layout/multiscripts.dart)use a non-null assertion (
childrenWidths[_ScriptPos.base]!,childrenHeights[_ScriptPos.base]!,childrenBaselines[_ScriptPos.base]!)on map lookups that are not guaranteed to succeed during intrinsic-size
layout probing. When the base script's size/baseline hasn't been recorded
in the map yet at the time intrinsic layout runs, the assertion throws
Null check operator used on a null value(_CastError) insideperformLayout(). Because Flutter's rendering pipeline does not catchlayout exceptions, this crashes the entire widget subtree and freezes the
UI — there is no graceful degradation.
Reproduction
We hit this consistently in production with expressions that mix subscript
characters inside
\mathrm{}, e.g.:rendered via
Math.tex(...)inside a layout that triggers intrinsic widthcomputation (e.g. content that may need to wrap). Issue #1 reports the same
stack trace (
multiscripts.dart:136) triggered via\displaystyle{...}inside a
RichText-hostedMath.texwidget, with a workaround of removingdisplaystyle— but the underlying null-check panic inMultiscriptsLayoutDelegatewas never fixed upstream.Fix
Replace the three non-null assertions on
_ScriptPos.baselookups with a?? 0.0fallback:performHorizontalIntrinsicLayout:childrenWidths[_ScriptPos.base] ?? 0.0performVerticalIntrinsicLayout:childrenHeights[_ScriptPos.base] ?? 0.0and
childrenBaselines[_ScriptPos.base] ?? 0.0When the base entry is present (the expected/common case), behavior is
byte-for-byte identical to before —
?? 0.0is a no-op unless the maplookup is null. When the base entry is absent (the previously-crashing
case), layout now degrades gracefully instead of throwing: the widget
continues to render (with a fallback intrinsic size of
0.0for themissing entry) instead of freezing the whole app.
Backward compatibility
Testing
dart analyze lib/src/render/layout/multiscripts.dart: no issues.(
\mathrm{CL_r = CL_{tot} \times f_e}) rendered inside a layout thatexercises intrinsic width computation — previously threw
Null check operator used on a null valuesynchronously onperformLayout(), now renders without throwing. We have been shippingthis exact 3-line patch in a production Flutter app (iOS, App Store)
since 2026-05 with no regressions in math rendering.