Skip to content

F# codegen: emit a named this self identifier (#393)#394

Merged
jeremydmiller merged 1 commit into
mainfrom
feat-393-fsharp-self-identifier
May 29, 2026
Merged

F# codegen: emit a named this self identifier (#393)#394
jeremydmiller merged 1 commit into
mainfrom
feat-393-fsharp-self-identifier

Conversation

@jeremydmiller
Copy link
Copy Markdown
Member

Closes #393.

Problem

Generated F# members were emitted as member _.X(...), discarding the self identifier. C# generated handlers routinely call inherited instance members unqualified (relying on implicit this) — e.g. a Wolverine.Http.HttpHandler subclass calls the base instance ReadJsonAsync/WriteJsonAsync, and a MessageHandler subclass calls RecordCauseAndEffect. F# has no implicit this, so member _. left those calls unresolvable, blocking the Wolverine F# audit's HTTP JSON path (JasperFx/wolverine#2969, Phase C).

Fix

  • GeneratedMethod.WriteFSharpMethod now emits member this. / override this.. F# does not warn on an unused member self identifier (unlike an unused let binding), so the original unused-this concern doesn't apply, and the F# fixtures don't run warnings-as-errors.
  • MethodCall F# emit renders IsLocal calls as this.method(...) (was the empty prefix), matching the implicit-this semantics of the C# path.

Test

A new GeneratedCalculator fixture type overrides a base abstract method and calls the inherited instance Bump via a local MethodCall, so the compile gate proves the emitted F# compiles:

type GeneratedCalculator() =
    inherit FSharpCodegenTarget.CalculatorBase()
    override this.Compute(seed: int) : int =
        let result_of_Bump = this.Bump(seed)
        result_of_Bump

The four FSharpGenerationTests self-identifier assertions were updated member _.member this..

Verification

  • CodegenTests F# generation/unit tests: 30/30 pass (net9.0 + net10.0).
  • CodegenTests.FSharp compile gate: the regenerated Generated.fs (now this. throughout, incl. the new inherited-call case) compiles via dotnet build on both TFMs.

🤖 Generated with Claude Code

Generated F# members were emitted as `member _.X(...)`, discarding the self
identifier. C# generated handlers routinely call inherited instance members
unqualified (implicit `this`) — e.g. a Wolverine.Http HttpHandler subclass calls
the base `ReadJsonAsync`/`WriteJsonAsync`, and a MessageHandler subclass calls
`RecordCauseAndEffect`. F# has no implicit `this`, so `member _.` left those
calls unresolvable and blocked the Wolverine F# audit's HTTP JSON path
(JasperFx/wolverine#2969 Phase C).

- GeneratedMethod.WriteFSharpMethod now emits `member this.` / `override this.`.
  F# does not warn on an unused member self identifier (unlike an unused `let`),
  so the original unused-`this` concern doesn't apply.
- MethodCall F# emit renders `IsLocal` calls as `this.method(...)` (was the empty
  prefix), matching the implicit-`this` semantics of the C# path.
- Fixture: a new GeneratedCalculator overrides a base abstract method and calls
  the inherited instance `Bump` via a local MethodCall, so the compile gate
  proves `override this.Compute` + `this.Bump(seed)` emits valid, compiling F#.
- Updated the four FSharpGenerationTests assertions from `member _.` to
  `member this.`.

Closes #393.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@jeremydmiller jeremydmiller changed the title F# codegen: emit a named self identifier (#393) F# codegen: emit a named this self identifier (#393) May 29, 2026
@jeremydmiller jeremydmiller merged commit 2ab33ce into main May 29, 2026
1 check passed
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.

F# codegen: generated members need a named self identifier (blocks inherited instance-method calls)

1 participant