Skip to content

fix(mix_generator): allow plain MixableSpec widget targets - #1025

Merged
leoafarias merged 5 commits into
mainfrom
fix/1022
Aug 17, 2026
Merged

fix(mix_generator): allow plain MixableSpec widget targets#1025
leoafarias merged 5 commits into
mainfrom
fix/1022

Conversation

@leoafarias

@leoafarias leoafarias commented Aug 13, 2026

Copy link
Copy Markdown
Member

Related issue

Closes #1022.

Description

@MixableSpec(target:) now accepts plain Widget constructors when their named style parameter can receive the generated Styler, removing the unnecessary StyleWidget inheritance requirement.

Changes

  • Validate the target's Widget subtype and constructor contract while preserving existing parameter and generic-target handling.
  • Cover compatible Style<Spec>, Object, and exact generated-Styler parameters, including when a prior generated part is already resolved.
  • Match Style<Spec> by analyzer element and library identity so unrelated same-named types are rejected.
  • Qualify target-class static defaults when copied into generated call() methods, sharing the established @MixWidget(target:) behavior while leaving top-level defaults unchanged.
  • Keep the exact-type shortcut limited to concrete generated Stylers so legacy @MixableStyler mixins retain their stricter Style<Spec> receiver contract.
  • Update the changelog, generator documentation, and regression coverage for valid and invalid target shapes.

Review Checklist

  • Testing: Generator, repository, clean-build, prior-output, and generated-output resolver tests were run after merging the latest main.
  • Breaking Changes: No breaking changes; existing StyleWidget targets remain supported.
  • Documentation Updates: The generator README, changelog, and Mix skill documentation are updated.
  • Website Updates: No website update is required for this generator validation fix.

Additional Information (optional)

melos run gen:build and melos run ci passed, both protocol inventories passed, all 11 packages passed Dart analysis, and the changed planner passed focused DCM analysis. The aggregate analysis command remains non-zero only for 11 pre-existing DCM findings on unchanged lines.

@leoafarias

leoafarias commented Aug 13, 2026

Copy link
Copy Markdown
Member Author

I found a resolution-state edge case that looks blocking for the exact generated-Styler parameter shape this PR adds.

On a clean build, a parameter such as BoxStyler style is unresolved and reaches _targetStyleAcceptsGeneratedStyler as InvalidType, so it is accepted. When a prior generated part is separately supplied to or resolved by the generator, BoxStyler instead becomes an InterfaceType. The helper then finds its Style<BoxSpec> supertype and checks whether that base type is assignable to BoxStyler; it is not, so generation fails with:

@MixableSpec(target:) PlainWidget `style` parameter cannot accept the generated `BoxStyler`.

I reproduced this by including a prior generated part containing BoxStyler extends Style<BoxSpec> and running the part builder to a separate output. The current clean-build test passes, while the prior-output case fails. I could not reproduce this through a normal incremental build_runner run, so this should not be read as a claim that every later build fails; the underlying problem is that validation changes with analyzer resolution state.

This is relevant to checked-in or otherwise independently resolved generated parts. Remix has that shape—its plain widgets type style as concrete generated classes such as ButtonStyler—so the promised behavior should remain valid whenever those types are already resolved.

A localized fix is to pass stylerName into the compatibility helper and, before the Style<Spec> supertype check, accept an InterfaceType whose element has that name and belongs to the spec's library. I prototyped that together with a prior-output regression test; the same-build case and the existing custom-style-subtype and wrong-spec negative tests still pass.

@leoafarias

Copy link
Copy Markdown
Member Author

Follow-up from validating the current head (367b1f9) against the full Remix workspace: the earlier analyzer-resolution-state issue is fixed, but the integration exposed one additional blocking target-default case.

When a target constructor uses an unqualified static member from its own class as a default, for example transitionBuilder = defaultAccordionTransitionBuilder on RemixAccordion, the generated Styler method copies that expression into the Styler class unchanged. The result references defaultAccordionTransitionBuilder out of scope and does not compile; it needs to be emitted as RemixAccordion.defaultAccordionTransitionBuilder.

The @MixWidget path already qualifies direct target-member defaults. Sharing that qualification with the @MixableSpec(target:) planner, plus a resolver regression fixture for prior generated output, fixes the case locally. With that patch, mix_generator analysis and all 372 tests pass. Remix #152 validates all 27 migrated component surfaces and the full 3,028-test workspace; it temporarily normalizes Accordion's nullable default inside the constructor so it can remain pinned to this exact PR head.

Verdict remains: the overall direction is correct, but this static-default qualification should be fixed before #1025 merges so other same-library targets cannot generate uncompilable code.

@leoafarias
leoafarias merged commit 390421b into main Aug 17, 2026
7 checks passed
@leoafarias
leoafarias deleted the fix/1022 branch August 17, 2026 19:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

@MixableSpec(target:) rejects plain Widget targets with compatible style parameters

1 participant