Skip to content

fix(solid_generator): seed bare super.x constructor params syntactically - #109

Merged
nank1ro merged 2 commits into
mainfrom
fix/bare-super-param-probe-seeding
Aug 26, 2026
Merged

nank1ro merged 2 commits into
mainfrom
fix/bare-super-param-probe-seeding

Conversation

@nank1ro

@nank1ro nank1ro commented Aug 26, 2026

Copy link
Copy Markdown
Owner

Closes #108. Cut as solid_generator 3.0.0-dev.5.

Problem

An annotation-free pure consumer whose ONLY link to a @SolidState class is a bare super.x constructor parameter carries no type text anywhere in its file — the syntactic probe gate (#107) had nothing to seed, the file passed through verbatim, and its cross-file reads stayed silently un-lowered (same dart fix dead-code hazard as #106, on a rarer shape).

Fix (stays syntactic)

  • Bare super.x resolves via the extends-clause name → located in the current unit or the import walk (alias/prefix-aware; same-package imports only — {super.key} never touches Flutter files; local declarations shadow) → targeted super constructor matched (named/unnamed; positional matching among super formals is provably unambiguous — Dart rejects the confusable mixes) → this.x matches fall back to the superclass field's type → super-formal chains recurse (depth-bounded) → generic type parameters map by index to the extends-clause type arguments. Ambiguity over-seeds candidate names, never guesses.
  • One-hop registry extension: the consumer typically imports only its base file, so the registry walk also searches the located superclass file's own imports — gated by the consuming file's local declarations (review caught the ungated version emitting .value on a local plain class).
  • Syntactic seeding skips when resolved-path resolution already succeeded.

Review guide — fixtures (test/golden/)

Fixture Proves
cross_file_super_param_bare_pure_consumer the literal issue shape, de-rigged (consumer imports only its base file); unnamed + super.named() targets + named param
cross_file_super_param_bare_chain two-hop super-formal relay
cross_file_super_param_generic_base extends Base<AuthRepository> type-argument mapping
cross_file_super_param_one_hop_local_shadow a local plain class is never rewritten by a one-hop foreign same-name (was a demonstrated non-compiling regression mid-review)
cross_file_super_param_bare_no_state plain superclass-field type → verbatim passthrough via the genuine found-but-no-@SolidState path

Also in this PR (separate commit)

Repo hygiene repeatedly surfaced by rebuilds: regenerated example/lib/main.dart (pre-existing const drift; prefer_const_constructors suppressed with rationale — the const-call-site rewriter is per-file), integration_tests/cross_file_env made regenerable (relative imports + non-const list init; two latent blockers), Flutter-tooling exclude: migrations accepted to end pub get churn.

Verification

349/349 solid_generator tests (5 new fixture families + idempotency), 11/11 integration, repo-root dart analyze --fatal-infos zero (CI's exact gate), format clean, examples zero-delta, RED authenticity re-proven against main. Pre-release validation against the real downstream app (fairtile accountant_app via path overrides): byte-identical lib/ on the app itself, plus a planted probe of the exact issue shape lowering to session.value — tree left clean.

Known residuals (documented): a class reachable only through a 2+ hop import chain; part-file consumers (pre-existing pipeline-wide limit); name-keyed registry collision surface (SPEC §4.9).

…ions

- example/lib/main.dart: commit the regenerated output; the const drift
  predated this branch (source lost the const in dev.1, the committed
  lib was stale) and every rebuild has been surfacing it. The generated
  call sites legitimately lack const (the const-call-site rewriter is
  per-file and cannot see sibling-file lowered classes), so example's
  analysis_options now suppresses prefer_const_constructors.
- integration_tests cross_file_env: relative same-package imports (the
  generator rejects package: self-imports) and a non-const List
  initializer (const literals are rejected for collection signals) —
  the fixture was unregenerable: build_runner deleted its two tracked
  lib/ outputs on every run, masking the second blocker. lib/ keeps
  always_use_package_imports off (it mirrors source's relative style;
  test/ deliberately keeps package: imports).
- example/examples analysis_options: accept the Flutter-tooling
  exclude-block auto-migration so pub get stops churning the files.
Closes #108. An annotation-free pure consumer whose only link to a
@SolidState class is a bare super.x parameter carried no type text for
the probe gate to seed, so the file passed through verbatim and its
cross-file reads stayed silently un-lowered.

The seeding walk now resolves bare super formals syntactically: the
extends-clause name is located in the current unit or via the import
walk (alias/prefix-aware, same-package imports only, local declarations
shadow), the targeted super constructor is matched (named or unnamed;
positional matching among super formals is unambiguous — Dart rejects
the mixes that could confuse it), untyped this.x matches fall back to
the superclass field's type, super-formal chains recurse with a depth
bound, and generic type parameters map by index to the extends-clause
type arguments. Ambiguity over-seeds candidate names instead of
guessing. The registry walk gains a one-hop extension into the located
superclass file's own imports — gated by the consuming file's local
declarations (review caught the ungated version rewriting a local plain
class) — since the consumer typically imports only its base file.
Syntactic seeding is skipped when resolved-path resolution already
succeeded, so ubiquitous {super.key} params never trigger file reads.

Five golden fixture families cover the issue shape (de-rigged: the
consumer imports only its base file), named targets and named params,
two-hop chains, generic bases, the local-shadow decoy, and a
no-@SolidState negative proving the fast path survives. Validated
against a real downstream app via path overrides before release:
byte-identical output on the app itself plus a probe of the exact issue
shape lowering correctly.
@nank1ro
nank1ro merged commit 926344c into main Aug 26, 2026
1 check passed
@nank1ro
nank1ro deleted the fix/bare-super-param-probe-seeding branch August 26, 2026 11:20
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.

Pure consumer whose only link is a bare super.x parameter misses the syntactic probe gate

1 participant