Skip to content

Files with no @Solid annotations bypass the pipeline, so cross-file @SolidState reads in pure consumers are never lowered #106

Description

@nank1ro

Problem

builder.dart's fast bailout (lines ~136-143 in 3.0.0-dev.3):

final hasSolidAnnotation = source.contains(_solidAnnotationHint);
final hasProviderHint = source.contains(_providerCallHint) || source.contains(_environmentCallHint);
if (!hasSolidAnnotation && !hasProviderHint) {
  await buildStep.writeAsString(outputId, source); // verbatim passthrough
  return;
}

means a pure consumer — a file that holds a @SolidState-bearing class via plain constructor injection but declares no @Solid* annotation and no provider call site of its own — never enters the transform pipeline. The #104/#105 registry seeding fix only helps files that are being processed, so it never runs for these files: their cross-file session reads stay silently un-lowered.

Every golden fixture in the #105 suite accidentally masks this: each consumer class carries its own @SolidState control field (loadCount), which is exactly what defeats the bailout.

Severity — reproduced, worse than a wrong comparison

In a real app (advisor frontend), making the auth repository's session a public @SolidState field and regenerating produced, for an annotation-free router.dart guard:

  • dart fix's dead_code/unnecessary_null_comparison passes saw the un-lowered Signal<Session?> as always-non-null and collapsed AuthGuard.onNavigation to an unconditional resolver.next(); return; — a generated authentication bypass, surfaced only as dead_code warnings;
  • the inverse login-route guard collapsed to unconditionally redirect every /login visit;
  • session!.token in annotation-free repositories became session.token → compile error (getter 'token' isn't defined for 'Signal<Session?>') — the lucky failure mode.

Candidate fix

Before the passthrough, do the cheap syntactic pass that #105 already implements: parse the unit, seed candidate type names from instance fields / constructor params (existing skip-set + local-shadowing + combinator rules), and walk the relative imports' registries. Enter the full pipeline iff the resulting registry is non-empty; keep the verbatim passthrough otherwise, preserving the fast path for genuinely solid-free files. Plus a golden fixture whose consumer has zero own annotations — the shape the current suite lacks.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions