Repository navigation
Conversation
Stores nullable private backing fields (`_fooTheme`) for the 47 default-constructed component theme properties on `ThemeData`, returning `const FooThemeData()` lazily from each public getter when null and short-circuiting `ThemeData.lerp`, `operator ==`, and `hashCode` when unconfigured so Dart whole-program TFA can tree-shake unused component themes and their `.lerp` methods.
kevmoo
marked this pull request as ready for review
November 1, 2026 04:50
Contributor
There was a problem hiding this comment.
Code Review
This pull request refactors ThemeData to lazily initialize default component theme data, converting component theme fields into getters backed by nullable private fields to enable tree-shaking of unused themes. It updates copyWith, lerp, equality checks, and hashing to support this new structure, and adds a test suite to verify behavior preservation. The review feedback identifies redundant type casts to InputDecorationThemeData? in both the constructor and the copyWith method.
QuncCccccc
marked this pull request as draft
November 3, 2026 22:22
7 tasks done
This was referenced Nov 11, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Avoid eagerly instantiating all 47 default component theme objects (
AppBarThemeData,BottomSheetThemeData,CardThemeData,DatePickerThemeData,DialogThemeData,SliderThemeData,TimePickerThemeData, etc.) insidefactory ThemeData(...)when those sub-themes are not customized by the application.Background
Currently,
factory ThemeDatainitializes all 47 component theme parameters withfooTheme ??= const FooThemeData()and stores them in non-nullable fields onThemeData. Even when an application only uses a handful of Material widgets, instantiating all 47FooThemeDataclasses inThemeData(and unconditionally callingFooThemeData.lerp(a.fooTheme, b.fooTheme, t)inThemeData.lerp, which is always reachable viaMaterialApp->AnimatedTheme->ThemeDataTween.lerp) prevents Dart's whole-program Type Flow Analysis (TFA) ingen_snapshotanddart2wasmfrom tree-shaking unused*ThemeDataclasses, their.lerp()methods, and theiroperator ==/hashCodeimplementations.Changes
final FooThemeData? _fooTheme;) onThemeData(initialized viarequired FooThemeData? fooThemeinconst ThemeData.raw) and lazily returns_fooTheme ?? const FooThemeData()from each public non-nullable getter.nullbacking fields acrossfactory ThemeData(...)andThemeData.copyWith(...)when a component theme is not explicitly provided.ThemeData.lerp(a._fooTheme == null && b._fooTheme == null ? null : FooThemeData.lerp(a.fooTheme, b.fooTheme, t)),ThemeData.==((other._fooTheme == null && _fooTheme == null) || other.fooTheme == fooTheme), andThemeData.hashCode(if (_fooTheme != null && _fooTheme != const FooThemeData()) _fooTheme) so:_fooThemehas typeNulland folds the null check totrue, tree-shakingconst FooThemeData(),FooThemeData.==, andFooThemeData.lerp.const FooThemeData()(or copied viatheme.copyWith(fooTheme: theme.fooTheme)),==,hashCode, andlerpbehave identically to an omitted (null) backing field.Measured Binary Size Impact (
kevmoo/slide_puzzle, stacked on #13515)libapp.so,gen_snapshot):-81,920 B(-2.72%,3,015,640 B->2,933,720 B;-180,224 B/-5.79%combined with#13515).wasmbinary (flutter build web --wasm --source-maps):-37,053 B(-1.51%,2,453,498 B->2,416,445 B;-81,255 B/-3.25%combined with#13515)--no-source-maps):-27,339 B(-2.78%,-118compiled functions;-45,866 B/-4.57%combined with#13515)ThemeDataTween.lerp:9,559 B->2,070 B(-7,489 B/-78.34%)ThemeData.==:1,820 B->888 B(-932 B/-51.21%)Part of flutter/flutter#196349
Related to flutter/flutter#91772
Design RFC: flutter/rfc#43
Pre-Review Checklist
[shared_preferences]///).If you need help, consider asking for advice on the #hackers-new channel on Discord.
Note: The Flutter team is currently trialing the use of Gemini Code Assist for GitHub. Comments from the
gemini-code-assistbot should not be taken as authoritative feedback from the Flutter team. If you find its comments useful you can update your code accordingly, but if you are unsure or disagree with the feedback, please feel free to wait for a Flutter team member's review for guidance on which automated comments should be addressed.Footnotes
Regular contributors who have demonstrated familiarity with the repository guidelines only need to comment if the PR is not auto-exempted by repo tooling. ↩ ↩2