Skip to content

Fix degraded codegen for inner recursive functions under realsig#19882

Open
T-Gro wants to merge 4 commits into
mainfrom
fix/realsign-codegen
Open

Fix degraded codegen for inner recursive functions under realsig#19882
T-Gro wants to merge 4 commits into
mainfrom
fix/realsign-codegen

Conversation

@T-Gro
Copy link
Copy Markdown
Member

@T-Gro T-Gro commented Jun 2, 2026

Fixes #17607 and #14492.

Under --realsig+ (default since .NET 9), inner recursive functions were not lifted to static methods by TLR, producing closure allocations and losing tail. calls — causing up to 23× perf regression for struct-heavy mutual recursion.

Additionally, constrained inline generics inlined into closures could leak type parameter constraints onto the Specialize<T> override, causing TypeLoadException at runtime.

Note: .net472.bsl baselines for Match01 and TestFunction23 need TEST_UPDATE_BSL=1 regeneration on Windows CI.

T-Gro and others added 4 commits June 2, 2026 12:42
Two codegen bugs fixed:

1. TLR (Top-Level Routing) was disabled under --realsig+ via a blanket
   short-circuit in InnerLambdasToTopLevelFuncs, causing inner recursive
   functions to be emitted as closure classes instead of static methods.
   This produced ~23× perf regression for struct mutual recursion (#17607).

   Fix: Remove the realsig band-aid. Instead, add a moduleCloc field to
   IlxGenEnv that always points to the enclosing non-generic module class.
   TLR-lifted vals (IsCompiledAsTopLevel && !IsMemberOrModuleBinding) are
   routed to moduleCloc, preventing them from inheriting class typars of
   a generic enclosing type.

2. Constrained inline generics, when inlined into closures, attached their
   constraints to the closure class's type params. The Specialize<T> override
   (from FSharpTypeFunc) must be unconstrained to match its base signature.
   When constraints leaked, the JIT threw TypeLoadException (#14492).

   Fix: In EraseClosures CASE 1, strip constraints from both the Specialize
   override method-typars (CASE 1b) and the later closure class-typars
   (CASE 1a) at the CASE 1 head. Rewrite stripILGenericParamConstraints
   via mkILSimpleTypar to be future-proof (clears all constraint fields
   including CustomAttrsStored which carries IsUnmanagedAttribute).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…sent HOF

- verifyILContains now throws on mismatch instead of silently returning
  CompilationResult.Failure (which callers were ignoring with |> ignore).
- Unify checkILPresent/checkILNotPresent via shared checkILFragments HOF.
- Expose verifyILPresent in Compiler.fs (symmetric with verifyILNotPresent).
- Fix TypeTests.fs assertions exposed by the silent-failure fix.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
New test files:
- Regression_TLR_MutualInnerRec_StructuralAssertions.fs: 20 tests covering
  TLR scenarios (generic class, nested module, three-way rec, quotation,
  value rec) and constraint stripping (IL shape, ILVerify, >5 params CASE 2a,
  combined TLR+constraint). All run under both realsig on/off.
- Regression_Specialize_ConstraintVerification.fs: 14 tests exercising each
  ILGenericParameterDef field stripped by mkILSimpleTypar (struct, not struct,
  unmanaged, new(), interface, comparison, combined) via ILVerify + run.
- 4 new IL-baseline source files (mutual rec, captured env, generic, Point2D)
  with Off/On .il.bsl pairs confirming realsig parity.

Regenerated baselines:
- TestFunction06, TestFunction23: closures replaced by static methods
- Match01: clo@4 closure removed (TLR fires under realsig+)
- Unmanaged: virtual DirectInvoke → static func@3

Note: Match01 and TestFunction23 .net472.bsl baselines need TEST_UPDATE_BSL=1
regeneration on Windows CI (macOS cannot target net472).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…ix (#14492)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Jun 2, 2026

❗ Release notes required


✅ Found changes and release notes in following paths:

Warning

No PR link found in some release notes, please consider adding it.

Change path Release notes path Description
src/Compiler docs/release-notes/.FSharp.Compiler.Service/11.0.100.md No current pull request URL (#19882) found, please consider adding it

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

Labels

None yet

Projects

Status: New

Development

Successfully merging this pull request may close these issues.

Degraded IL codegen with .NET 9 preview 7

1 participant