From 7019919bd24a57abbea7a7c540f88c68134d292e Mon Sep 17 00:00:00 2001 From: KevinRansom Date: Tue, 20 Feb 2024 00:42:56 -0800 Subject: [PATCH] Fix 16105 --- src/Compiler/Optimize/Optimizer.fs | 20 +- .../EmittedIL/NoCompilerInlining.fs | 201 +++++++++++++++++- tests/FSharp.Test.Utilities/Compiler.fs | 4 + tests/FSharp.Test.Utilities/CompilerAssert.fs | 7 +- 4 files changed, 224 insertions(+), 8 deletions(-) diff --git a/src/Compiler/Optimize/Optimizer.fs b/src/Compiler/Optimize/Optimizer.fs index fd3c85dd60b2..7efa30de54f9 100644 --- a/src/Compiler/Optimize/Optimizer.fs +++ b/src/Compiler/Optimize/Optimizer.fs @@ -3062,11 +3062,14 @@ and TryOptimizeVal cenv env (vOpt: ValRef option, mustInline, inlineIfLambda, va failwith "tuple, union and record values cannot be marked 'inline'" | UnknownValue when mustInline -> - warning(Error(FSComp.SR.optValueMarkedInlineHasUnexpectedValue(), m)); None + warning(Error(FSComp.SR.optValueMarkedInlineHasUnexpectedValue(), m)) + None | _ when mustInline -> - warning(Error(FSComp.SR.optValueMarkedInlineCouldNotBeInlined(), m)); None - | _ -> None + warning(Error(FSComp.SR.optValueMarkedInlineCouldNotBeInlined(), m)) + None + + | _ -> None and TryOptimizeValInfo cenv env m vinfo = if vinfo.HasEffect then None else TryOptimizeVal cenv env (None, false, false, vinfo.Info, m) @@ -3402,7 +3405,7 @@ and TryInlineApplication cenv env finfo (tyargs: TType list, args: Expr list, m) | _ -> false | _ -> false | _ -> false - | _ -> false + | _ -> false if isValFromLazyExtensions then None else @@ -3421,6 +3424,15 @@ and TryInlineApplication cenv env finfo (tyargs: TType list, args: Expr list, m) if isGetHashCode then None else + let isApplicationComplete = + match finfo.Info with + | ValValue (_, CurriedLambdaValue (_, _, _, Expr.Lambda (_, _, _, _, Expr.App (Expr.Val(vr,_,_), _, _, _, _), _, _), _) ) -> + IsPartialExprVal (GetInfoForVal cenv env m vr).ValExprInfo + | _ -> + false + + if isApplicationComplete then None else + // Inlining lambda let f2R = CopyExprForInlining cenv false f2 m diff --git a/tests/FSharp.Compiler.ComponentTests/EmittedIL/NoCompilerInlining.fs b/tests/FSharp.Compiler.ComponentTests/EmittedIL/NoCompilerInlining.fs index b798d1552094..4dc1ed904e39 100644 --- a/tests/FSharp.Compiler.ComponentTests/EmittedIL/NoCompilerInlining.fs +++ b/tests/FSharp.Compiler.ComponentTests/EmittedIL/NoCompilerInlining.fs @@ -5,7 +5,206 @@ namespace EmittedIL open Xunit open FSharp.Test.Compiler -module ``NoCompilerInlining`` = +module NoCompilerInlining = + + [] + let ``Methods marked internal not available for cross module inlining``() = + + let outerModule = + FSharpWithFileName + "outerModule.fs" + """ +module internal OuterModule + open System.Runtime.CompilerServices + + [] + do () + + let sayOuterModuleHello () = System.Console.WriteLine("Hello World") """ + |> withOptimize + |> asLibrary + |> withName "outerLibrary" + + let middleModule = + FSharpWithFileName + "middleModule.fs" + """ +module MiddleModule + let sayMiddleModuleHello () = OuterModule.sayOuterModuleHello()""" + |> withOptimize + |> withReferences [outerModule] + |> asLibrary + |> withName "middleModule" + + FSharpWithFileName + "program.fs" + """MiddleModule.sayMiddleModuleHello()""" + |> withOptimize + |> withReferences [middleModule; outerModule] + |> withName "Program" + |> compileExeAndRun + |> shouldSucceed + |> verifyIL [ """ + .method public static void main@() cil managed + { + .entrypoint + + .maxstack 8 + IL_0000: call void [middleModule]MiddleModule::sayMiddleModuleHello() + IL_0005: ret + } +""" ] + + [] + let ``Methods marked public available for cross module inlining``() = + + let outerModule = + FSharpWithFileName + "outerModule.fs" + """ +module OuterModule + open System.Runtime.CompilerServices + + let sayOuterModuleHello () = System.Console.WriteLine("Hello World") """ + |> withOptimize + |> asLibrary + |> withName "outerLibrary" + + let middleModule = + FSharpWithFileName + "middleModule.fs" + """ +module MiddleModule + let sayMiddleModuleHello () = OuterModule.sayOuterModuleHello()""" + |> withOptimize + |> withReferences [outerModule] + |> asLibrary + |> withName "middleModule" + + FSharpWithFileName + "program.fs" + """MiddleModule.sayMiddleModuleHello()""" + |> withOptimize + |> withReferences [middleModule; outerModule] + |> withName "Program" + |> compileExeAndRun + |> shouldSucceed + |> verifyIL [ """ + .method public static void main@() cil managed + { + .entrypoint + + .maxstack 8 + IL_0000: ldstr "Hello World" + IL_0005: call void [runtime]System.Console::WriteLine(string) + IL_000a: ret + } +""" ] + + + [] + let ``Nested Module marked internal not available for cross module inlining``() = + + let outerModule = + FSharpWithFileName + "outerModule.fs" + """ +module OuterModule + open System.Runtime.CompilerServices + + [] + do () + + module internal nestedModule = + let sayNestedModuleHello () = System.Console.WriteLine("Hello World") + + let sayOuterModuleHello () = nestedModule.sayNestedModuleHello () """ + |> withOptimize + |> asLibrary + |> withName "outerLibrary" + + let middleModule = + FSharpWithFileName + "middleModule.fs" + """ +module MiddleModule + let sayMiddleModuleHello () = OuterModule.sayOuterModuleHello()""" + |> withOptimize + |> withReferences [outerModule] + |> asLibrary + |> withName "middleModule" + + FSharpWithFileName + "program.fs" + """MiddleModule.sayMiddleModuleHello()""" + |> withOptimize + |> withReferences [middleModule; outerModule] + |> withName "Program" + |> compileExeAndRun + |> shouldSucceed + |> verifyIL [ """ + .method public static void main@() cil managed + { + .entrypoint + + .maxstack 8 + IL_0000: ldstr "Hello World" + IL_0005: call void [runtime]System.Console::WriteLine(string) + IL_000a: ret + } +""" ] + + [] + let ``Nested Module marked public available for cross module inlining``() = + + let outerModule = + FSharpWithFileName + "outerModule.fs" + """ +module OuterModule + open System.Runtime.CompilerServices + + module nestedModule = + let sayNestedModuleHello () = System.Console.WriteLine("Hello World") + + let sayOuterModuleHello () = nestedModule.sayNestedModuleHello () """ + |> withOptimize + |> asLibrary + |> withName "outerLibrary" + + let middleModule = + FSharpWithFileName + "middleModule.fs" + """ +module MiddleModule + let sayMiddleModuleHello () = OuterModule.sayOuterModuleHello()""" + |> withOptimize + |> withReferences [outerModule] + |> asLibrary + |> withName "middleModule" + + FSharpWithFileName + "program.fs" + """MiddleModule.sayMiddleModuleHello()""" + |> withOptimize + |> withReferences [middleModule; outerModule] + |> withName "Program" + |> compileExeAndRun + |> shouldSucceed + |> verifyIL [ """ + .method public static void main@() cil managed + { + .entrypoint + + .maxstack 8 + IL_0000: ldstr "Hello World" + IL_0005: call void [runtime]System.Console::WriteLine(string) + IL_000a: ret + } +""" ] + + + [] let ``Function marked with NoCompilerInlining is not inlined by the compiler``() = FSharp """ diff --git a/tests/FSharp.Test.Utilities/Compiler.fs b/tests/FSharp.Test.Utilities/Compiler.fs index c29d09588012..7865e82cdfb5 100644 --- a/tests/FSharp.Test.Utilities/Compiler.fs +++ b/tests/FSharp.Test.Utilities/Compiler.fs @@ -366,6 +366,10 @@ module rec Compiler = let FSharp (source: string) : CompilationUnit = Fs source + let FSharpWithFileName name (source: string) : CompilationUnit = + fsFromString (SourceCodeFileKind.Fs({FileName=name; SourceText=Some source })) + |> FS + let FsFromPath (path: string) : CompilationUnit = fsFromString (SourceFromPath path) |> FS diff --git a/tests/FSharp.Test.Utilities/CompilerAssert.fs b/tests/FSharp.Test.Utilities/CompilerAssert.fs index e7d56f247dd0..a97b214acde7 100644 --- a/tests/FSharp.Test.Utilities/CompilerAssert.fs +++ b/tests/FSharp.Test.Utilities/CompilerAssert.fs @@ -439,9 +439,10 @@ module rec CompilerAssertHelpers = | Some text -> // In memory source file copy it to the build directory let source = item.ChangeExtension - File.WriteAllText (source.GetSourceFileName, text) - disposals.Add(disposeFile source.GetSourceFileName) - yield source + let destFileName = Path.Combine(outputDirectory.FullName, Path.GetFileName(source.GetSourceFileName)) + File.WriteAllText (destFileName, text) + disposals.Add(disposeFile destFileName) + yield source.WithFileName(destFileName) | None -> // On Disk file let sourceFileName = item.GetSourceFileName