diff --git a/docs/release-notes/.FSharp.Compiler.Service/11.0.100.md b/docs/release-notes/.FSharp.Compiler.Service/11.0.100.md index 562632e460d..93ed2d7111d 100644 --- a/docs/release-notes/.FSharp.Compiler.Service/11.0.100.md +++ b/docs/release-notes/.FSharp.Compiler.Service/11.0.100.md @@ -191,6 +191,7 @@ ### Changed * The `--warnaserror` option now ignores unrecognized diagnostic identifiers in warning lists while still applying recognized F# warning codes. ([PR #20246](https://github.com/dotnet/fsharp/pull/20246)) +* Reduce allocations when inlining a generic function by fusing the optimizer's copy and type-instantiation passes into a single tree traversal instead of cloning the body twice. ([PR #20363](https://github.com/dotnet/fsharp/pull/20363)) * Improvements in error and warning messages: new error FS3885 when `let!`/`use!` is the final expression in a computation expression; new warning FS3886 when a list literal contains a single tuple element (likely missing `;` separator); improved wording for FS0003, FS0025, FS0039, FS0072, FS0247, FS0597, FS0670, FS3082, and SRTP operator-not-in-scope hints. ([PR #19398](https://github.com/dotnet/fsharp/pull/19398)) * Exception field serialization (`GetObjectData` and field-restoring constructor) is now gated behind `langversion:11` (`LanguageFeature.ExceptionFieldSerializationSupport`). With langversion ≤10, exception codegen is unchanged from pre-#19342 behavior. ([PR #19746](https://github.com/dotnet/fsharp/pull/19746)) * field serialization (`GetObjectData` and field-restoring constructor) is now gated behind `langversion:11` (`LanguageFeature.ExceptionFieldSerializationSupport`). With langversion ≤10, exception codegen is unchanged from pre-#19342 behavior. ([PR #19746](https://github.com/dotnet/fsharp/pull/19746)) diff --git a/src/Compiler/Optimize/Optimizer.fs b/src/Compiler/Optimize/Optimizer.fs index 3ecedc13c63..d390696aa96 100644 --- a/src/Compiler/Optimize/Optimizer.fs +++ b/src/Compiler/Optimize/Optimizer.fs @@ -3889,9 +3889,6 @@ and TryInlineApplication cenv env finfo (valExpr: Expr) (tyargs: TType list, arg if isApplicationPartialExpr then None else - // Inlining lambda - let f2R = CopyExprForInlining cenv false f2 m - // Optimizing arguments after inlining // REVIEW: this is a cheapshot way of optimizing the arg expressions as well without the restriction of recursive @@ -3900,7 +3897,17 @@ and TryInlineApplication cenv env finfo (valExpr: Expr) (tyargs: TType list, arg // Beta reduce. MakeApplicationAndBetaReduce g does all the hard work. // Inlining: beta reducing - let exprR = MakeApplicationAndBetaReduce g (f2R, f2ty, [tyargs], argsR, m) + // Generic lambda saturated by its type args: fuse the inlining copy with the type + // instantiation into one traversal (one val-clone) instead of copyExpr then instExpr. + let exprR = + match f2 with + | Expr.TyLambda(_, tyvs, body, _, bodyTy) when tyvs.Length = tyargs.Length -> + let tpinst = bindTypars tyvs tyargs emptyTyparInst + let bodyR = remapExpr g CloneAllAndMarkExprValsAsCompilerGenerated (mkInstRemap tpinst) body |> remarkExpr m + MakeApplicationAndBetaReduce g (bodyR, instType tpinst bodyTy, [], argsR, m) + | _ -> + let f2R = CopyExprForInlining cenv false f2 m + MakeApplicationAndBetaReduce g (f2R, f2ty, [tyargs], argsR, m) // Inlining: reoptimizing Some(OptimizeExpr cenv {env with dontInline = Map.add lambdaId [] env.dontInline} exprR)