Skip to content

fix(solid_generator): cross-instance @SolidState in mixed-file pure consumers (dev.10) - #116

Merged
nank1ro merged 1 commit into
mainfrom
fix/widget-plain-field-cross-instance-state
Aug 29, 2026
Merged

nank1ro merged 1 commit into
mainfrom
fix/widget-plain-field-cross-instance-state

Conversation

@nank1ro

@nank1ro nank1ro commented Aug 29, 2026

Copy link
Copy Markdown
Owner

Problem

Whole-file pure-consumer lowering (lowerPureConsumers) only runs when every class in a file is annotation-free. In a mixed file — a no-annotation presentation widget/class co-located with the annotated class it consumes — _resultForClass passed the consumer through verbatim. So a cross-instance @SolidState write through a plain constructor/instance field:

class Counter { @SolidState() int count = 0; }

class CounterView extends StatelessWidget {
  const CounterView({required this.counter});
  final Counter counter;                                   // plain field
  Widget build(_) => GestureDetector(
    onTap: () => counter.count = counter.count + 1,        // NOT lowered
    child: Text('${counter.count}'),                       // NOT lowered / not reactive
  );
}

stayed un-lowered → counter.count = … hit assignment_to_final on the generated final Signal, and the read stayed non-reactive (no SignalBuilder).

Fix

New per-class lowerPureConsumerClass (mirrors the two whole-file collectors: buildrewriteBuildMethod for .value + wrap; other ctors/methods → collectValueEdits; applied via applyEditsToRange(slice, edits, decl.offset)). _resultForClass calls it for hasNoAnnotations classes instead of a verbatim passthrough, returning {'SignalBuilder'} on wrap so flutter_solidart is imported. The pure consumer is not lifted and gains no Disposable — it owns no reactive member.

Tests

  • New goldens mixed_file_pure_consumer_widget (StatelessWidget: write+read lowered, wrapped, imported) and mixed_file_pure_consumer_plain_class (plain class: read+write lowered, no wrap, no Disposable).
  • Full suite 372/372 (incl. idempotency), dart analyze lib clean.

Reviewed by 2 adversarial reviewers (0 findings). Bumps solid_generator to 3.0.0-dev.10.

…pure consumers

Whole-file pure-consumer lowering only ran when NO class in the file was
annotated. In a mixed file, a no-annotation consumer that reaches another
class's @SolidState through a plain constructor/instance field was passed
through verbatim, so a cross-instance write (vm.x = v) hit assignment_to_final
on the generated final Signal, and reads stayed non-reactive.

Adds a per-class lowerPureConsumerClass (mirroring the whole-file collectors)
that _resultForClass invokes for no-annotation classes, so the same .value
lowering + SignalBuilder wrap fires in mixed files too. Adds
mixed_file_pure_consumer_{widget,plain_class} goldens.

Reviewed by 2 adversarial reviewers (0 findings; plain-class golden added on rec).
@nank1ro
nank1ro merged commit c9ea58e into main Aug 29, 2026
1 check failed
@nank1ro
nank1ro deleted the fix/widget-plain-field-cross-instance-state branch August 29, 2026 07:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant