Skip to content

Add net10 Solution.g codegen console + toggle (groundwork to free the SourceGenerators ns2.0 cone)#442

Open
ChrisonSimtian wants to merge 9 commits into
Fallout-build:mainfrom
ChrisonSimtian:build/free-sourcegenerators-cone
Open

Add net10 Solution.g codegen console + toggle (groundwork to free the SourceGenerators ns2.0 cone)#442
ChrisonSimtian wants to merge 9 commits into
Fallout-build:mainfrom
ChrisonSimtian:build/free-sourcegenerators-cone

Conversation

@ChrisonSimtian

@ChrisonSimtian ChrisonSimtian commented Jun 29, 2026

Copy link
Copy Markdown
Collaborator

Groundwork for #441 (move the Roslyn generator off the netstandard2.0 floor). Adds a net10 pre-build codegen path for the strongly-typed [Solution] accessor so the in-compiler generator can eventually shed its Solution/Persistence/Utilities/Globbing dependency cone. Non-breaking and dogfooded.

What changed

  • Fallout.Solution.Codegen (net10 console) — discovers [Solution(GenerateProjects = true)] syntactically (no compilation pre-build), reads the solution with the real Fallout.Persistence.Solution parser, emits <Member>.g.cs.
  • Fallout.Solution.Codegen.Emit (new netstandard2.0;net10.0 project) — the shared emitter, referenced by both the console and the generator. Replaces the old src/shared/ linked-source hack; output stays byte-identical. Bundled into the analyzer via the existing GetDependencyTargetPaths.
  • StronglyTypedSolutionGenerator — self-suppresses when FalloutSolutionCodegenMode == Build; otherwise unchanged, so it remains the in-IDE fallback.
  • Fallout.Solution.Codegen.targets — reusable pre-build target + toggle plumbing (FalloutSolutionCodegenProject in-repo, or FalloutSolutionCodegenAssembly for packaged consumers).
  • build/_build.csproj — dogfoods the console path (Mode=Build).
  • TestsFallout.Solution.Codegen.Specs covers discovery (qualified/aliased names, relativePath:, properties/fields, multiple members, negatives), the emit pipeline, stale-output removal, the parameters-file fallback, and identifier escaping; plus generator self-suppression specs. Discovery also prunes bin/obj/hidden in the bare---root fallback scan.

Why

The generator parses solutions at compile time, which forces the parser cone to netstandard2.0. Moving codegen to a net10 console lets the generator later drop those refs. Shipped as non-breaking groundwork: both paths coexist (toggle-gated), so consumers are untouched until the console ships in the NuGet.

Verification

  • Full fallout.slnx build: 0 errors.
  • Fallout.Solution.Codegen.Specs 25/25, Fallout.SourceGenerators.Specs 10/10 (incl. the generator Verify snapshot).
  • Dogfood _build: console emits Solution.g.cs → generator suppresses → compiles.

Part of #441.

Follow-ups (not here)

  • Ship the console + targets (and the .Emit DLL) in the consumer NuGet (build/), flip the consumer default to Build, then drop the generator's cone refs (frees Solution/Utilities to net10) and the .Emit ns2.0 target.
  • The .targets happy path is covered by the dogfood _build (+ Fallout.Canary), not an automated spawn-build test.
  • The pre-build target passes every compile item as --source on one Exec line; a very large Mode=Build consumer could hit the Windows ~32K command-line limit (the --root fallback mitigates). Batch/response-file if that ever bites.
  • FancyNames is currently dead code — tracked in [Solution] FancyNames option is dead code #445.

ChrisonSimtian and others added 3 commits June 29, 2026 23:12
First half of freeing the Fallout.SourceGenerators dependency cone (issue
Fallout-build#441, Lever 1): introduce a net10 pre-build codegen path for the
strongly-typed [Solution] accessor as the future default, with the in-compiler
generator retained as the toggle fallback.

- src/shared/SolutionEmitter.cs: the Scriban emit logic extracted out of
  StronglyTypedSolutionGenerator into a single shared source file, linked into
  BOTH the generator and the new console so they emit byte-identical Solution.g.cs.
- StronglyTypedSolutionGenerator: refactored to call SolutionEmitter (behaviour
  unchanged — still the in-IDE/live fallback).
- src/Fallout.Solution.Codegen: net10 console that discovers
  [Solution(GenerateProjects = true)] members by parsing the build project's .cs
  syntactically (no compilation available pre-build), reads the solution with the
  real Fallout.Persistence.Solution parser (no parsing-parity risk), and emits via
  the shared emitter. Verified end-to-end against this repo's own build/Build.cs +
  fallout.slnx — output matches the generator.
- AssemblyInfo: IVT for the console (it uses Build.Shared's internal Constants).

Remaining (next commits on this branch): the packaged pre-build MSBuild target +
FalloutSolutionCodegenMode toggle (default = console; suppress the generator in
console mode), dogfood-build wiring, and — as the deliberate follow-up — dropping
the now-removable cone refs from Fallout.SourceGenerators once the fallback is
retired/cone-freed.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…1, steps 1-2)

- StronglyTypedSolutionGenerator self-suppresses when FalloutSolutionCodegenMode == Build
  (reads it via CompilerVisibleProperty), so exactly one path emits.
- src/Fallout.Solution.Codegen/build/Fallout.Solution.Codegen.targets: reusable pre-build
  target that runs the console (via FalloutSolutionCodegenProject or a published
  FalloutSolutionCodegenAssembly), writes <Member>.g.cs into obj/, and includes it. Exposes
  the toggle to the fallback generator.
- build/_build.csproj: dogfoods the console path (FalloutSolutionCodegenMode=Build). Verified:
  the target runs the console, emits Solution.g.cs from fallout.slnx, the generator suppresses,
  and _build compiles (0 errors). Full fallout.slnx build green.

Default is unchanged for everyone else (generator runs unless a project opts into Build), so
this is non-breaking. Remaining follow-ups: ship the console + targets in the consumer package
and flip the default to Build, then drop the now-removable cone refs from Fallout.SourceGenerators.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…allout.Solution.Codegen project

The generator's output for fallout.slnx now includes the new Fallout.Solution.Codegen
project; the only snapshot change is that one accessor line (confirming the shared-emitter
refactor preserved output). BOM stripped to match the repo's no-BOM verified convention.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@ChrisonSimtian ChrisonSimtian requested a review from a team as a code owner June 29, 2026 11:17
@ChrisonSimtian ChrisonSimtian added enhancement New feature or request target/2026 Targets the 2026 calendar-version line (current). See ADR-0004. labels Jun 29, 2026
@ChrisonSimtian ChrisonSimtian requested review from Copilot and dennisdoomen and removed request for dennisdoomen June 29, 2026 11:18
@ChrisonSimtian ChrisonSimtian marked this pull request as draft June 29, 2026 11:19

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Groundwork for issue #441 by introducing a net10 pre-build codegen path for the strongly-typed [Solution] accessor (Solution.g.cs), sharing a single emitter between the console path and the Roslyn generator fallback, and dogfooding the build-path in build/_build.csproj.

Changes:

  • Add Fallout.Solution.Codegen (net10 console) + MSBuild .targets to generate *.g.cs before compile when FalloutSolutionCodegenMode=Build.
  • Extract shared Scriban emit logic to src/shared/SolutionEmitter.cs and link it into both the console and StronglyTypedSolutionGenerator.
  • Update solution + Verify snapshot and wire the dogfood build to use the new build-time codegen path.

Reviewed changes

Copilot reviewed 10 out of 10 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
tests/Fallout.SourceGenerators.Specs/StronglyTypedSolutionGeneratorSpecs.Test#Solution.g.verified.cs Snapshot update reflecting the new Fallout.Solution.Codegen project presence.
src/shared/SolutionEmitter.cs New shared emitter used by both generator and console to keep output byte-identical.
src/Fallout.SourceGenerators/StronglyTypedSolutionGenerator.cs Refactor onto shared emitter + self-suppress when FalloutSolutionCodegenMode=Build.
src/Fallout.SourceGenerators/Fallout.SourceGenerators.csproj Link in shared emitter source file.
src/Fallout.Solution.Codegen/Program.cs New net10 console that syntactically discovers [Solution(GenerateProjects=true)] and emits *.g.cs.
src/Fallout.Solution.Codegen/Fallout.Solution.Codegen.csproj New net10 console project + linked emitter + references/packages.
src/Fallout.Solution.Codegen/build/Fallout.Solution.Codegen.targets New MSBuild target to run the console pre-build and include generated sources.
fallout.slnx Adds the new Fallout.Solution.Codegen project to the repo solution.
build/_build.csproj Dogfoods the console path (Mode=Build) and imports the new targets.
AssemblyInfo.cs Adds InternalsVisibleTo("Fallout.Solution.Codegen").

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/Fallout.Solution.Codegen/build/Fallout.Solution.Codegen.targets
Comment thread src/Fallout.Solution.Codegen/Program.cs Outdated
Comment thread src/Fallout.Solution.Codegen/Program.cs Outdated
Comment thread src/Fallout.Solution.Codegen/Program.cs Outdated
ChrisonSimtian and others added 5 commits June 30, 2026 12:53
Extract the syntactic [Solution] discovery out of Program into a testable
SolutionMemberDiscovery, and tighten it to match the symbol-based generator:

- Match the attribute by its rightmost name segment so qualified/aliased usages
  ([Fallout.Solutions.Solution], [Solutions.Solution], [global::...Attribute])
  are recognised, not just the bare [Solution]/[SolutionAttribute].
- Accept the relativePath constructor argument written positionally or as
  'relativePath:' (NameColon).
- Prune bin/obj/hidden directories in the bare --root fallback scan instead of
  walking AllDirectories.
- Delete any existing *.g.cs in the output directory before emitting, so a
  removed or renamed [Solution] member can't leave an orphan that still compiles.

GenerateProjects/FancyNames stay NameEquals-only on purpose: they are settable
properties, so '=' is the only valid syntax.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Unit tests for SolutionMemberDiscovery: rightmost-segment attribute matching,
positional vs. relativePath: arguments, FancyNames, property vs. field members,
and the negatives (GenerateProjects=false, unrelated attributes). Wires the new
project into fallout.slnx and InternalsVisibleTo.

The generator Verify snapshot gains one accessor line for the newly-added test
project (the generator enumerates the real solution).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Move the discover -> resolve -> emit loop out of Program's top-level statements
into a testable SolutionCodegenRunner; Program is now a thin arg-parsing shell.
This puts the previously untested output side-effects under test:

- emits the accessor for a discovered member against a real (minimal) .slnx
- clears stale *.g.cs before emitting (orphan removal)
- removes all outputs when no member remains

Also adds a test for EnumerateProjectSources confirming bin/obj/hidden dirs are
pruned from the bare --root fallback scan.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The emitter was linked-source into both the Roslyn generator and the net10
console via a src/shared/ directory. Promote it to a proper multi-targeted
project, Fallout.Solution.Codegen.Emit (netstandard2.0;net10.0), that both
reference:

- netstandard2.0 so the in-compiler StronglyTypedSolutionGenerator (also ns2.0)
  can reference it; its DLL is bundled into the analyzer via the existing
  GetDependencyTargetPaths mechanism.
- net10.0 so the console gets a modern build. When the generator fallback is
  retired (Fallout-build#441), the ns2.0 target can simply be dropped.

SolutionEmitter becomes public (it now crosses an assembly boundary). Scriban
moves to the emit project and reaches the console transitively. No /shared.

It stays a dedicated codegen library rather than folding into Fallout.Solution:
the emitter pulls in Scriban, which shouldn't leak into everything that consumes
the Solution model. Output is still byte-identical (the generator Verify
snapshot passes; the one delta is the new project's own accessor line).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Fills the gaps in the previously thin spots:

- Generator self-suppression: asserts the in-compiler generator no-ops when
  FalloutSolutionCodegenMode=Build (case-insensitive) and still emits otherwise.
  This is the toggle that guarantees exactly one path emits Solution.g.cs.
- Parameters-file fallback: the runner resolves a [Solution] member with no path
  argument via .fallout/parameters.json.
- Multiple members: discovery and the runner both handle more than one
  [Solution(GenerateProjects = true)] member, emitting one file each.
- Emitter escaping: dotted project names become valid identifiers, and names
  starting with a digit get an underscore prefix.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Adds a spec exercising the recursive folder declaration (Unsafe.As / nested
SolutionFolder class) — previously only covered transitively by the generator
snapshot.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@ChrisonSimtian ChrisonSimtian requested a review from a team June 30, 2026 08:55
@ChrisonSimtian ChrisonSimtian marked this pull request as ready for review June 30, 2026 08:55
@ChrisonSimtian

Copy link
Copy Markdown
Collaborator Author

@dennisdoomen this one would be good, groundwork PR for other stuff

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

Labels

enhancement New feature or request target/2026 Targets the 2026 calendar-version line (current). See ADR-0004.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants