Skip to content

Implement direct delegates - #19993

Open
kerams wants to merge 38 commits into
dotnet:mainfrom
kerams:del
Open

Implement direct delegates#19993
kerams wants to merge 38 commits into
dotnet:mainfrom
kerams:del

Conversation

@kerams

@kerams kerams commented Jun 24, 2026

Copy link
Copy Markdown
Contributor

Description

Implements fsharp/fslang-suggestions#1083, fixes #11898. RFC.

Test cases should cover everything mentioned in the language suggestion.

Checklist

  • Test cases added
  • Performance benchmarks added in case of performance changes
  • Release notes entry updated:

@github-actions

github-actions Bot commented Jun 24, 2026

Copy link
Copy Markdown
Contributor

❗ Release notes required

You can open this PR in browser to add release notes: open in github.dev


✅ Found changes and release notes in following paths:

Change path Release notes path Description
src/Compiler docs/release-notes/.FSharp.Compiler.Service/11.0.100.md
LanguageFeatures.fsi docs/release-notes/.Language/preview.md

Comment thread src/Compiler/CodeGen/IlxGen.fs
@github-actions github-actions Bot added the ⚠️ Affects-Compiler-Output Tooling check: PR touches IL emission or codegen label Jun 24, 2026
@github-actions

This comment has been minimized.

Comment thread tests/FSharp.Compiler.ComponentTests/EmittedIL/DirectDelegates/DirectDelegates.fs Outdated
Comment thread src/Compiler/CodeGen/IlxGen.fs
Comment thread src/Compiler/CodeGen/IlxGen.fs Outdated
Comment thread tests/FSharp.Compiler.ComponentTests/EmittedIL/DirectDelegates/DirectDelegates.fs Outdated
Comment thread tests/FSharp.Compiler.ComponentTests/EmittedIL/DirectDelegates/DirectDelegates.fs Outdated
@kerams

kerams commented Jun 26, 2026

Copy link
Copy Markdown
Contributor Author

Ready for another pass, think I addressed everything. (But alternatives and unresolved questions in the RFC need answers still:))

@smoothdeveloper

Copy link
Copy Markdown
Contributor

Add an opt-out compiler flag (default on) alongside the language feature.

I think this is not needed anymore, Tomas has added a msbuild way as well as compiler flag to disable specific language features:

--disableLanguageFeature:DirectDelegateConstruction

or

 <ItemGroup>
  <DisabledLanguageFeatures Include="DirectDelegateConstruction" />
</ItemGroup>

You may want to check it picks up as is to allow selectively disabling the feature.

<Compile Include="EmittedIL\CompiledNameAttribute\CompiledNameAttribute.fs" />
<Compile Include="EmittedIL\ComputationExpressions\ComputationExpressions.fs" />
<Compile Include="EmittedIL\ComputedCollections\ComputedCollections.fs" />
<Compile Include="EmittedIL\DirectDelegates\DirectDelegates.fs" />

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Since the use cases are known in the RFC and often framework-integrated, it would be great to have some smoke tests for this integration.

(ASP.NET routing/minimal APIs, dependency-injection containers, mocking libraries, serializers, and logging/diagnostics that print the bound method name. With F# they see Invoke on a closure rather than the intended method, which breaks or degrades these scenarios..)

Either going via "Regression tests" suite and referencing a separate repo and building it with the fresh compiler.
Or picking a few cases and doing an .fsx test with #load of a few chosen libraries?

@abonie abonie Jul 29, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

@kerams Are you planning to address this one? Or otherwise is it ready to merge from your standpoint?

Comment thread src/Compiler/Optimize/DelegateForwarding.fs Outdated
Comment thread src/Compiler/CodeGen/IlxGen.fs
@T-Gro

T-Gro commented Jul 23, 2026

Copy link
Copy Markdown
Member

Direct delegate to a static method on a value type boxes the ref-type first arg as the declaring struct → garbage / AccessViolationException

open System
[<Struct>]
type V =
    static member Pick (s: string, n: int) = s.Length + n

let make () = Func<int,int>(fun n -> V.Pick("abc", n))
// preview:  make().Invoke 10  ->  93584954   (expected 13)

let bad () = Func<int>(fun () -> Int32.Parse "41")
// preview:  bad().Invoke()    ->  System.AccessViolationException

Feature off / main: both correct. The emitted IL boxes the string as the struct:

ldstr   "abc"
box     P/V          // string reinterpreted as a boxed V
ldftn   int32 P/V::Pick(string, int32)
newobj  Func`2<int32,int32>::.ctor(object, native int)

Root cause: the closed-delegate emission boxes whenever targetMspec.DeclaringType.Boxity.IsAsValue (IlxGen.fs ~7703–7707). That is correct for a value-type instance receiver, but here the leading arg is the static method's first parameter — already a reference (guaranteed by staticLeadingArgIsRefType), so it must not be boxed.

Fix: only box when the receiver is a genuine value-type instance receiver (takesInstanceArg), not for the static closed-first-arg form. This path is currently untested — a struct-static positive test would have caught it.

Comment thread src/Compiler/CodeGen/IlxGen.fs
Comment thread src/Compiler/CodeGen/IlxGen.fs
@T-Gro

T-Gro commented Jul 24, 2026

Copy link
Copy Markdown
Member

🤖🕵️

Fixed in 8e5f373 — verified: make().Invoke 10 = 13 and bad().Invoke() = 41 (no AccessViolationException), and the erroneous box V is gone from the emitted IL. The added struct-static positive test covers it. Thanks!

@github-actions github-actions Bot added the AI-Tooling-Check-Scanned-Clean Tooling check: diff analyzed, no interesting infrastructure files label Jul 26, 2026
@github-actions

Copy link
Copy Markdown
Contributor

🔍 Tooling Safety Check — Affects-Compiler-Output
Affects-Compiler-Output: implements direct delegates codegen

Generated by PR Tooling Safety Check · opus46 12.1M ·

@github-project-automation github-project-automation Bot moved this from New to In Progress in F# Compiler and Tooling Jul 29, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

⚠️ Affects-Compiler-Output Tooling check: PR touches IL emission or codegen AI-Tooling-Check-Scanned-Clean Tooling check: diff analyzed, no interesting infrastructure files

Projects

Status: In Progress

Development

Successfully merging this pull request may close these issues.

Don't emit unnecessary closures

4 participants