From c12ae1b274a386cc8fd401aa5072178622c60e2f Mon Sep 17 00:00:00 2001 From: Tomas Grosup Date: Tue, 24 Mar 2026 11:48:28 +0100 Subject: [PATCH 1/2] Add regression test for #3660: array of functions invocation without closure allocation - Runtime correctness test: compiles and runs the indexed array function invocation pattern, verifying correct results - IL verification test: compiles runAll as a library with optimizations and asserts no closure class (extending FSharpFunc) is emitted, ensuring the compiler does not generate needless allocations for fArr.[i] x Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../CodeGenRegressions_Closures.fs | 59 +++++++++++++++++++ 1 file changed, 59 insertions(+) diff --git a/tests/FSharp.Compiler.ComponentTests/EmittedIL/CodeGenRegressions/CodeGenRegressions_Closures.fs b/tests/FSharp.Compiler.ComponentTests/EmittedIL/CodeGenRegressions/CodeGenRegressions_Closures.fs index 1f8fb7840fe..367954f6d8e 100644 --- a/tests/FSharp.Compiler.ComponentTests/EmittedIL/CodeGenRegressions/CodeGenRegressions_Closures.fs +++ b/tests/FSharp.Compiler.ComponentTests/EmittedIL/CodeGenRegressions/CodeGenRegressions_Closures.fs @@ -365,3 +365,62 @@ let main _ = |> shouldSucceed |> ignore + // https://github.com/dotnet/fsharp/issues/3660 + [] + let ``Issue_3660_ArrayOfFunctionsInvocationCorrectness`` () = + let source = + """ +module Test + +let runAll (fArr: (int -> int) array) x = + let mutable n = 0 + + for i = 0 to fArr.Length - 1 do + n <- n + fArr.[i] x + + n + +[] +let main _ = + let fns = [| (fun x -> x + 1); (fun x -> x * 2); (fun x -> x - 3) |] + let result = runAll fns 10 + if result <> (11 + 20 + 7) then failwithf "Expected 38, got %d" result + printfn "SUCCESS" + 0 +""" + + FSharp source + |> asExe + |> compile + |> shouldSucceed + |> run + |> shouldSucceed + |> ignore + + // https://github.com/dotnet/fsharp/issues/3660 + // Verify that indexed array function invocation does not emit closure classes + [] + let ``Issue_3660_NoClosureClassForIndexedArrayInvocation`` () = + let source = + """ +module Test + +let runAll (fArr: (int -> int) array) x = + let mutable n = 0 + + for i = 0 to fArr.Length - 1 do + n <- n + fArr.[i] x + + n +""" + + FSharp source + |> asLibrary + |> withOptimize + |> compile + |> shouldSucceed + |> verifyILNotPresent [ + "extends class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc" + ] + |> ignore + From 0c47bf5b15b3b118e0b79af152118b7b3275f5a0 Mon Sep 17 00:00:00 2001 From: Adam Boniecki <20281641+abonie@users.noreply.github.com> Date: Wed, 25 Mar 2026 21:27:00 +0100 Subject: [PATCH 2/2] Apply suggestions from code review Co-authored-by: Adam Boniecki <20281641+abonie@users.noreply.github.com> --- .../CodeGenRegressions/CodeGenRegressions_Closures.fs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/FSharp.Compiler.ComponentTests/EmittedIL/CodeGenRegressions/CodeGenRegressions_Closures.fs b/tests/FSharp.Compiler.ComponentTests/EmittedIL/CodeGenRegressions/CodeGenRegressions_Closures.fs index 367954f6d8e..898656a55d0 100644 --- a/tests/FSharp.Compiler.ComponentTests/EmittedIL/CodeGenRegressions/CodeGenRegressions_Closures.fs +++ b/tests/FSharp.Compiler.ComponentTests/EmittedIL/CodeGenRegressions/CodeGenRegressions_Closures.fs @@ -376,7 +376,7 @@ let runAll (fArr: (int -> int) array) x = let mutable n = 0 for i = 0 to fArr.Length - 1 do - n <- n + fArr.[i] x + n <- n + fArr[i] x n @@ -409,7 +409,7 @@ let runAll (fArr: (int -> int) array) x = let mutable n = 0 for i = 0 to fArr.Length - 1 do - n <- n + fArr.[i] x + n <- n + fArr[i] x n """