Skip to content

land kanban 586 - #406

Merged
StevenTCramer merged 7 commits into
feature/generator-fixes-2026-11-14from
task/583-generator-emits-null-checks-on-user-value-type
Nov 14, 2026
Merged

StevenTCramer merged 7 commits into
feature/generator-fixes-2026-11-14from
task/583-generator-emits-null-checks-on-user-value-type

Conversation

@StevenTCramer

Copy link
Copy Markdown
Contributor

Summary

What changed

  • New ResultValueKind (MaybeNull, ValueType, Enum) in
    source/timewarp-nuru-analyzers/generators/models/result-value-kind.cs, read from the ITypeSymbol by
    ResultValueKinds.Of (Nullable<T> stays MaybeNull).
  • HandlerReturnType.ValueKind (the result, or T of Task<T>) and HandlerDefinition.SuccessValueKind (problem
    pair success type), set by every extractor that builds a return type: lambda expression and block bodies, method
    groups, [NuruRoute] command classes (IQuery<T>/ICommand<T>), and [Operation] mediator endpoints.
    HandlerDefinition.RenderedValueKind picks the one the invoker writes.
  • HandlerInvokerEmitter.EmitResultOutput skips is not null for any non-nullable value type, and the JSON
    fallback writes result.ToString() with no ?. for one. GetOutputStrategy sends a non-nullable enum to
    Raw, so an enum result prints its member name (Dark) instead of JSON; capabilities now reports such a route's
    returnType kind as Primitive. User structs keep the JSON strategy.
  • Decision: enums print raw. JSON of an enum is its number (no converter in the built-in contexts), which is worse
    for a CLI than the member name, and matches how the binder takes enum input by name.
  • Tests: generator-75 now returns the enum and the struct directly (the 529 workaround shade.ToString() is gone)
    and adds an async enum delegate and an enum method group; new tests/timewarp-nuru-tests/routing/routing-39-value-type-results.cs
    pins runtime output (delegate, async delegate, method group, IQuery<TEnum> endpoint, user struct,
    Nullable<TEnum> null writes nothing) in the CI multi-mode assembly.
  • Audit boy-scout: ganda repo audit --fix set the VS Code window title/icon in the git-ignored
    .vscode/settings.json (advisory vscode-window-icon warning); nothing to commit.

Follow-up (not fixed here)

  • A delegate or method-group result whose type is declared in a namespace the generated file does not import
    fails with CS0246: GetReturnTypeName/GetUnwrappedReturnTypeName and EmitRender declare the result local by
    ShortTypeName (minimally qualified). It hits reference types too, so it is its own defect; routing-39 keeps its
    result types in the global namespace for that reason. Worth a separate task (fully qualified names need the
    nullable reference ? kept, or var).

Gates

Gate Command Result
Build ./bin/dev build pass (exit 0); fix pass 1 rerun: pass (exit 0)
Test ganda runfile cache --clear then ./bin/dev test pass (exit 0; CI multi-mode incl. routing-39, standalone incl. generator-75 6/6); fix pass 1 rerun: pass (exit 0, 0 failed)
Audit ganda repo audit pass; first run had one advisory vscode-window-icon warning, fixed with --fix, rerun "Repository passes all audit checks."; fix pass 1 rerun: pass (exit 0, "Repository passes all audit checks.")

Test plan

Smoke:

ganda runfile cache --clear
dotnet run tests/timewarp-nuru-tests/routing/routing-39-value-type-results.cs
dotnet run tests/timewarp-nuru-tests/generator/generator-75-consumer-surface-no-ivt.cs

Expect: routing-39 6/6 pass (vtr-mode Dark prints Dark, the IQuery<VtrShade> endpoint prints Light,
the struct writes both members, the null VtrShade? writes nothing); generator-75 6/6 pass, with
.WithHandler((Gen75Shade shade) => shade) compiling as a consumer. In
artifacts/generated/routing-39-value-type-results.cs/.../NuruGenerated.g.cs the enum route emits
app.Terminal.WriteLine(result.ToString()); with no if (result is not null), and the struct's JSON fallback is
result.ToString() with no ?..

Kanban task 583
Session: 1411579

StevenTCramer and others added 7 commits November 14, 2026 10:03
Land-Holder: cramer
A handler returning a user enum or struct got an 'is not null' guard (CS0037)
and a '?.ToString()' JSON fallback (CS0023), because the invoker emitter knew
only BCL value types by name. Extractors now carry ResultValueKind on
HandlerReturnType and the problem-pair success type; the emitter skips the
null guard and '?.' for non-nullable value types and prints enums raw.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
M1 is wontfix. The review diffed against master, but task 583 stacks on
feature/generator-fixes-2026-11-14 (work-set 586,583,584,585), which
already carries task 586 via PR #405.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@StevenTCramer
StevenTCramer merged commit a52e46d into feature/generator-fixes-2026-11-14 Nov 14, 2026
7 checks passed
@StevenTCramer
StevenTCramer deleted the task/583-generator-emits-null-checks-on-user-value-type branch November 14, 2026 05:54
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