From 1c2d63de90ef987d49a1d9ade72826fd97e07a32 Mon Sep 17 00:00:00 2001 From: Tomas Grosup Date: Mon, 1 Jun 2026 16:31:29 +0200 Subject: [PATCH 1/5] Fix TLR under --realsig+ and closure constraint stripping MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 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> --- src/Compiler/AbstractIL/il.fs | 9 ++---- src/Compiler/CodeGen/EraseClosures.fs | 12 ++++---- src/Compiler/CodeGen/IlxGen.fs | 30 ++++++++++++++----- .../Optimize/InnerLambdasToTopLevelFuncs.fs | 4 +-- 4 files changed, 33 insertions(+), 22 deletions(-) diff --git a/src/Compiler/AbstractIL/il.fs b/src/Compiler/AbstractIL/il.fs index 5a80b12fbdc..ba8be1d05a7 100644 --- a/src/Compiler/AbstractIL/il.fs +++ b/src/Compiler/AbstractIL/il.fs @@ -3375,14 +3375,9 @@ let mkILSimpleTypar nm = MetadataIndex = NoMetadataIdx } +/// Returns gp with all constraints cleared, including IsUnmanagedAttribute (carried via CustomAttrsStored). let stripILGenericParamConstraints (gp: ILGenericParameterDef) = - { gp with - Constraints = [] - HasReferenceTypeConstraint = false - HasNotNullableValueTypeConstraint = false - HasDefaultConstructorConstraint = false - HasAllowsRefStruct = false - } + { mkILSimpleTypar gp.Name with Variance = gp.Variance; MetadataIndex = gp.MetadataIndex } let genericParamOfGenericActual (_ga: ILType) = mkILSimpleTypar "T" diff --git a/src/Compiler/CodeGen/EraseClosures.fs b/src/Compiler/CodeGen/EraseClosures.fs index 6aef85d40b5..4b857209f62 100644 --- a/src/Compiler/CodeGen/EraseClosures.fs +++ b/src/Compiler/CodeGen/EraseClosures.fs @@ -484,9 +484,13 @@ let rec convIlxClosureDef cenv encl (td: ILTypeDef) clo = match tyargsl, tmargsl, laterStruct with // CASE 1 - Type abstraction | _ :: _, [], _ -> - let addedGenParams = tyargsl let nowReturnTy = (mkTyOfLambdas cenv laterStruct) + // Strip constraints: both the Specialize override method-typars (CASE 1b) and the + // later closure class-typars (CASE 1a) must be unconstrained — the override must match + // its base signature, and the class must accept any T that Specialize passes. See #14492. + let unconstrainedGenParams = tyargsl |> List.map stripILGenericParamConstraints + // CASE 1a. Split a type abstraction. // Adjust all the argument and environment accesses // Actually that special to do here in the type abstraction case @@ -504,7 +508,7 @@ let rec convIlxClosureDef cenv encl (td: ILTypeDef) clo = let laterTypeName = td.Name + "T" let laterTypeRef = mkILNestedTyRef (ILScopeRef.Local, encl, laterTypeName) - let laterGenericParams = td.GenericParams @ addedGenParams + let laterGenericParams = td.GenericParams @ unconstrainedGenParams let selfFreeVar = let baseName = CompilerGeneratedName("self" + string nowFields.Length) @@ -564,14 +568,12 @@ let rec convIlxClosureDef cenv encl (td: ILTypeDef) clo = let convil = convILMethodBody (Some nowCloSpec, boxReturnTy) clo.cloCode.Value - let specializeGenParams = addedGenParams |> List.map stripILGenericParamConstraints - let nowApplyMethDef = mkILGenericVirtualMethod ( "Specialize", ILCallingConv.Instance, ILMemberAccess.Public, - specializeGenParams, + unconstrainedGenParams, [], mkILReturn cenv.ilg.typ_Object, MethodBody.IL(notlazy convil) diff --git a/src/Compiler/CodeGen/IlxGen.fs b/src/Compiler/CodeGen/IlxGen.fs index 49207b9f480..e29fe76b8d2 100644 --- a/src/Compiler/CodeGen/IlxGen.fs +++ b/src/Compiler/CodeGen/IlxGen.fs @@ -1207,6 +1207,9 @@ and IlxGenEnv = /// Indicates the default "place" for stuff we're currently generating cloc: CompileLocation + /// Always points to the enclosing module (non-generic). Used for TLR-lifted vals. + moduleCloc: CompileLocation + /// Indicates the default "place" for initialization stuff we're currently generating initClassCompLoc: CompileLocation option @@ -1299,6 +1302,8 @@ let EnvForTycon tps eenv = tyenv = eenv.tyenv.ForTycon tps } +/// Narrows cloc into a nested type scope. moduleCloc is intentionally NOT updated: +/// TLR-lifted vals must stay in the module class, not in a generic enclosing type. let AddEnclosingToEnv eenv enclosing name ns = { eenv with cloc = @@ -10269,7 +10274,13 @@ and AllocValReprWithinExpr cenv cgbuf endMark cloc v eenv = else NoShadowLocal, eenv - ComputeAndAddStorageForLocalValWithValReprInfo (cenv, eenv.intraAssemblyInfo, cenv.options.isInteractive, optShadowLocal) cloc v eenv + // TLR-lifted inner functions must go in the module class — if emitted inside a generic + // enclosing type they inherit its class typar, conflicting with their own method typars. See #17607. + // Note: also matches `do let x = …` and `copyOfStruct` vals — safe because at module scope cloc == moduleCloc. + let effectiveCloc = + if v.IsCompiledAsTopLevel && not v.IsMemberOrModuleBinding then eenv.moduleCloc else cloc + + ComputeAndAddStorageForLocalValWithValReprInfo (cenv, eenv.intraAssemblyInfo, cenv.options.isInteractive, optShadowLocal) effectiveCloc v eenv //-------------------------------------------------------------------------- // Generate stack save/restore and assertions - pulled into letrec by alloc* @@ -10692,9 +10703,12 @@ and GenModuleBinding cenv (cgbuf: CodeGenBuffer) (qname: QualifiedNameOfFile) la // Evaluate bindings for module let hidden = IsHiddenTycon eenv.sigToImplRemapInfo mspec + let moduleLoc = CompLocForFixedModule cenv.options.fragName qname.Text mspec + let eenvinner = { eenv with - cloc = CompLocForFixedModule cenv.options.fragName qname.Text mspec + cloc = moduleLoc + moduleCloc = moduleLoc initLocals = eenv.initLocals && not (EntityHasWellKnownAttribute cenv.g WellKnownEntityAttributes.SkipLocalsInitAttribute mspec) @@ -10760,13 +10774,13 @@ and GenImplFile cenv (mgbuf: AssemblyBuilder) mainInfoOpt eenv (implFile: Checke for anonInfo in anonRecdTypes.Values do mgbuf.GenerateAnonType((fun ilThisTy -> GenToStringMethod cenv eenv ilThisTy m), anonInfo) + let withQName (loc: CompileLocation) = + { loc with TopImplQualifiedName = qname.Text; Range = m } + let eenv = { eenv with - cloc = - { eenv.cloc with - TopImplQualifiedName = qname.Text - Range = m - } + cloc = withQName eenv.cloc + moduleCloc = withQName eenv.moduleCloc } cenv.optimizeDuringCodeGen <- optimizeDuringCodeGen @@ -12505,6 +12519,7 @@ let GetEmptyIlxGenEnv (g: TcGlobals) ccu = { tyenv = TypeReprEnv.Empty cloc = CompLocForCcu ccu + moduleCloc = CompLocForCcu ccu initClassCompLoc = None initFieldName = CompilerGeneratedName "init" staticInitializationName = CompilerGeneratedName "staticInitialization" @@ -12589,6 +12604,7 @@ let GenerateCode (cenv, anonTypeTable, eenv, CheckedAssemblyAfterOptimization im let eenv = { eenv with cloc = CompLocForFragment cenv.options.fragName cenv.viewCcu + moduleCloc = CompLocForFragment cenv.options.fragName cenv.viewCcu delayCodeGen = cenv.options.parallelIlxGenEnabled } diff --git a/src/Compiler/Optimize/InnerLambdasToTopLevelFuncs.fs b/src/Compiler/Optimize/InnerLambdasToTopLevelFuncs.fs index 885917fee37..099c3e2149f 100644 --- a/src/Compiler/Optimize/InnerLambdasToTopLevelFuncs.fs +++ b/src/Compiler/Optimize/InnerLambdasToTopLevelFuncs.fs @@ -194,9 +194,7 @@ module Pass1_DetermineTLRAndArities = let arity = min nFormals nMaxApplied if atTopLevel then Some (f, arity) - elif g.realsig then - None - else if arity<>0 || not (isNil tps) then + elif arity <> 0 || not (isNil tps) then Some (f, arity) else None From f38d45b557121eeb2d9d9b7e177126997eec7487 Mon Sep 17 00:00:00 2001 From: Tomas Grosup Date: Mon, 1 Jun 2026 16:31:39 +0200 Subject: [PATCH 2/5] Fix verifyILContains silent failure, add checkILPresent/checkILNotPresent 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> --- .../FSharp.Compiler.ComponentTests.fsproj | 2 ++ .../Signatures/TypeTests.fs | 7 +++---- tests/FSharp.Test.Utilities/Compiler.fs | 5 +++-- tests/FSharp.Test.Utilities/ILChecker.fs | 18 ++++++++++++------ 4 files changed, 20 insertions(+), 12 deletions(-) diff --git a/tests/FSharp.Compiler.ComponentTests/FSharp.Compiler.ComponentTests.fsproj b/tests/FSharp.Compiler.ComponentTests/FSharp.Compiler.ComponentTests.fsproj index acfeca79f35..c334d58b0a7 100644 --- a/tests/FSharp.Compiler.ComponentTests/FSharp.Compiler.ComponentTests.fsproj +++ b/tests/FSharp.Compiler.ComponentTests/FSharp.Compiler.ComponentTests.fsproj @@ -262,6 +262,8 @@ + + diff --git a/tests/FSharp.Compiler.ComponentTests/Signatures/TypeTests.fs b/tests/FSharp.Compiler.ComponentTests/Signatures/TypeTests.fs index d8317ff8e92..80f5955ce9f 100644 --- a/tests/FSharp.Compiler.ComponentTests/Signatures/TypeTests.fs +++ b/tests/FSharp.Compiler.ComponentTests/Signatures/TypeTests.fs @@ -344,7 +344,7 @@ type GenericType<'X> with one |> withAdditionalSourceFiles [ two; three ] |> compile - |> verifyILContains [ ".Print" ] + |> verifyILPresent [ ".Print" ] // https://github.com/dotnet/fsharp/issues/14310 [] @@ -1001,8 +1001,7 @@ type D() = """ |> compile |> shouldSucceed - |> verifyILContains [ - ".method public hidebysig instance int32 M() cil managed" + |> verifyILPresent [ + ".method public hidebysig instance int32 M(class [FSharp.Core]Microsoft.FSharp.Core.Unit _arg1) cil managed" ".method public hidebysig instance int32 M(int32 y) cil managed" ] - |> ignore diff --git a/tests/FSharp.Test.Utilities/Compiler.fs b/tests/FSharp.Test.Utilities/Compiler.fs index 914741559a2..45602a1f4bb 100644 --- a/tests/FSharp.Test.Utilities/Compiler.fs +++ b/tests/FSharp.Test.Utilities/Compiler.fs @@ -1342,8 +1342,7 @@ Actual: | Some p -> match ILChecker.verifyILAndReturnActual [] p expected with | true, _, _ -> result - | false, errorMsg, _actualIL -> - CompilationResult.Failure( {s with Output = Some (ExecutionOutput {Outcome = NoExitCode; StdOut = errorMsg; StdErr = ""})} ) + | false, errorMsg, _actualIL -> failwith $"IL verification failed:\n{errorMsg}" | CompilationResult.Failure f -> printfn "Failure:" printfn $"{f}" @@ -1351,6 +1350,8 @@ Actual: let verifyIL = doILCheck ILChecker.checkIL + let verifyILPresent = doILCheck ILChecker.checkILPresent + let verifyILNotPresent = doILCheck ILChecker.checkILNotPresent /// Verifies that the compiled assembly contains an assembly reference whose name starts with the given prefix. diff --git a/tests/FSharp.Test.Utilities/ILChecker.fs b/tests/FSharp.Test.Utilities/ILChecker.fs index a9ec56ccc67..42ff05ad8d6 100644 --- a/tests/FSharp.Test.Utilities/ILChecker.fs +++ b/tests/FSharp.Test.Utilities/ILChecker.fs @@ -195,19 +195,25 @@ module ILChecker = let verifyILAndReturnActual args dllFilePath expectedIL = checkILPrim args dllFilePath expectedIL - let checkILNotPresent dllFilePath unexpectedIL = + let private checkILFragments shouldBePresent dllFilePath fragments = let actualIL = generateIL dllFilePath [] - if unexpectedIL = [] then - Assert.Fail $"No unexpected IL given. This is actual IL: \n{actualIL}" + if fragments = [] then + Assert.Fail $"No IL fragments given. This is actual IL: \n{actualIL}" + let label = if shouldBePresent then "Not found in" else "Found in" + let isError (fragment: string) = actualIL.Contains(fragment) <> shouldBePresent let errors = - unexpectedIL + fragments |> Seq.map (normalizeILText None) - |> Seq.filter actualIL.Contains - |> Seq.map (sprintf "Found in actual IL: '%s'") + |> Seq.filter isError + |> Seq.map (sprintf "%s actual IL: '%s'" label) |> String.concat "\n" if errors <> "" then Assert.Fail $"{errors}\n\n\nEntire actual:\n{actualIL}" + let checkILNotPresent dllFilePath unexpectedIL = checkILFragments false dllFilePath unexpectedIL + + let checkILPresent dllFilePath expectedIL = checkILFragments true dllFilePath expectedIL + let reassembleIL ilFilePath dllFilePath = let ilasmPath = config.ILASM let _, _, errors = exec ilasmPath [ $"%s{ilFilePath} /output=%s{dllFilePath} /dll" ] From 739cf42f7dff9b94ba5ec9d961db5dfb20694c39 Mon Sep 17 00:00:00 2001 From: Tomas Grosup Date: Mon, 1 Jun 2026 16:31:58 +0200 Subject: [PATCH 3/5] Add tests and regenerate IL baselines for TLR/constraint fixes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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> --- .../Conformance/Constraints/Unmanaged.fs | 20 +- .../EmittedIL/Inlining/Inlining.fs | 24 + ....fs.RealInternalSignatureOn.il.netcore.bsl | 703 ++++++++---------- ...ssion_Specialize_ConstraintVerification.fs | 82 ++ .../Inlining/Regression_TLR_MutualInnerRec.fs | 15 + ...nnerRec.fs.RealInternalSignatureOff.il.bsl | 141 ++++ ...InnerRec.fs.RealInternalSignatureOn.il.bsl | 141 ++++ ...gression_TLR_MutualInnerRec_CapturedEnv.fs | 15 + ...uredEnv.fs.RealInternalSignatureOff.il.bsl | 166 +++++ ...turedEnv.fs.RealInternalSignatureOn.il.bsl | 166 +++++ .../Regression_TLR_MutualInnerRec_Generic.fs | 16 + ...Generic.fs.RealInternalSignatureOff.il.bsl | 168 +++++ ..._Generic.fs.RealInternalSignatureOn.il.bsl | 168 +++++ .../Regression_TLR_MutualInnerRec_Point2D.fs | 23 + ...Point2D.fs.RealInternalSignatureOff.il.bsl | 687 +++++++++++++++++ ..._Point2D.fs.RealInternalSignatureOn.il.bsl | 687 +++++++++++++++++ ...TLR_MutualInnerRec_StructuralAssertions.fs | 258 +++++++ ....RealInternalSignatureOn.OptimizeOn.il.bsl | 88 +-- ...ernalSignatureOn.OptimizeOn.il.netcore.bsl | 98 +-- 19 files changed, 3135 insertions(+), 531 deletions(-) create mode 100644 tests/FSharp.Compiler.ComponentTests/EmittedIL/Inlining/Regression_Specialize_ConstraintVerification.fs create mode 100644 tests/FSharp.Compiler.ComponentTests/EmittedIL/Inlining/Regression_TLR_MutualInnerRec.fs create mode 100644 tests/FSharp.Compiler.ComponentTests/EmittedIL/Inlining/Regression_TLR_MutualInnerRec.fs.RealInternalSignatureOff.il.bsl create mode 100644 tests/FSharp.Compiler.ComponentTests/EmittedIL/Inlining/Regression_TLR_MutualInnerRec.fs.RealInternalSignatureOn.il.bsl create mode 100644 tests/FSharp.Compiler.ComponentTests/EmittedIL/Inlining/Regression_TLR_MutualInnerRec_CapturedEnv.fs create mode 100644 tests/FSharp.Compiler.ComponentTests/EmittedIL/Inlining/Regression_TLR_MutualInnerRec_CapturedEnv.fs.RealInternalSignatureOff.il.bsl create mode 100644 tests/FSharp.Compiler.ComponentTests/EmittedIL/Inlining/Regression_TLR_MutualInnerRec_CapturedEnv.fs.RealInternalSignatureOn.il.bsl create mode 100644 tests/FSharp.Compiler.ComponentTests/EmittedIL/Inlining/Regression_TLR_MutualInnerRec_Generic.fs create mode 100644 tests/FSharp.Compiler.ComponentTests/EmittedIL/Inlining/Regression_TLR_MutualInnerRec_Generic.fs.RealInternalSignatureOff.il.bsl create mode 100644 tests/FSharp.Compiler.ComponentTests/EmittedIL/Inlining/Regression_TLR_MutualInnerRec_Generic.fs.RealInternalSignatureOn.il.bsl create mode 100644 tests/FSharp.Compiler.ComponentTests/EmittedIL/Inlining/Regression_TLR_MutualInnerRec_Point2D.fs create mode 100644 tests/FSharp.Compiler.ComponentTests/EmittedIL/Inlining/Regression_TLR_MutualInnerRec_Point2D.fs.RealInternalSignatureOff.il.bsl create mode 100644 tests/FSharp.Compiler.ComponentTests/EmittedIL/Inlining/Regression_TLR_MutualInnerRec_Point2D.fs.RealInternalSignatureOn.il.bsl create mode 100644 tests/FSharp.Compiler.ComponentTests/EmittedIL/Inlining/Regression_TLR_MutualInnerRec_StructuralAssertions.fs diff --git a/tests/FSharp.Compiler.ComponentTests/Conformance/Constraints/Unmanaged.fs b/tests/FSharp.Compiler.ComponentTests/Conformance/Constraints/Unmanaged.fs index 173f18537a5..712333340fa 100644 --- a/tests/FSharp.Compiler.ComponentTests/Conformance/Constraints/Unmanaged.fs +++ b/tests/FSharp.Compiler.ComponentTests/Conformance/Constraints/Unmanaged.fs @@ -526,15 +526,17 @@ Main() |> compile |> shouldSucceed |> verifyIL [""" - .method assembly strict virtual instance class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2 DirectInvoke() cil managed - { - .param type T - .custom instance void [runtime]System.Runtime.CompilerServices.IsUnmanagedAttribute::.ctor() = ( 01 00 00 00 ) - - .maxstack 8 - IL_0000: ldsfld class Test/'func@3-1' class Test/'func@3-1'::@_instance - IL_0005: ret - } """] + .method assembly static class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2 + func@3() cil managed + { + .custom instance void [FSharp.Core]Microsoft.FSharp.Core.CompilationMappingAttribute::.ctor(valuetype [FSharp.Core]Microsoft.FSharp.Core.SourceConstructFlags) = ( 01 00 09 00 00 00 00 00 ) + .param type T + .custom instance void [runtime]System.Runtime.CompilerServices.IsUnmanagedAttribute::.ctor() = ( 01 00 00 00 ) + + .maxstack 8 + IL_0000: ldsfld class Test/'func@3-1' class Test/'func@3-1'::@_instance + IL_0005: ret + } """] [] diff --git a/tests/FSharp.Compiler.ComponentTests/EmittedIL/Inlining/Inlining.fs b/tests/FSharp.Compiler.ComponentTests/EmittedIL/Inlining/Inlining.fs index 5bd346e2075..3358122f743 100644 --- a/tests/FSharp.Compiler.ComponentTests/EmittedIL/Inlining/Inlining.fs +++ b/tests/FSharp.Compiler.ComponentTests/EmittedIL/Inlining/Inlining.fs @@ -28,6 +28,30 @@ module Inlining = |> getCompilation |> verifyCompilation + [] + let ``Regression_TLR_MutualInnerRec_fs`` compilation = + compilation + |> getCompilation + |> verifyCompilation + + [] + let ``Regression_TLR_MutualInnerRec_Point2D_fs`` compilation = + compilation + |> getCompilation + |> verifyCompilation + + [] + let ``Regression_TLR_MutualInnerRec_Generic_fs`` compilation = + compilation + |> getCompilation + |> verifyCompilation + + [] + let ``Regression_TLR_MutualInnerRec_CapturedEnv_fs`` compilation = + compilation + |> getCompilation + |> verifyCompilation + // SOURCE=Match02.fs SCFLAGS="-a --optimize+" COMPILE_ONLY=1 POSTCMD="..\\CompareIL.cmd Match02.dll" # Match02.fs [] let ``Match02_fs`` compilation = diff --git a/tests/FSharp.Compiler.ComponentTests/EmittedIL/Inlining/Match01.fs.RealInternalSignatureOn.il.netcore.bsl b/tests/FSharp.Compiler.ComponentTests/EmittedIL/Inlining/Match01.fs.RealInternalSignatureOn.il.netcore.bsl index b0035f72dbc..0dddc8c3978 100644 --- a/tests/FSharp.Compiler.ComponentTests/EmittedIL/Inlining/Match01.fs.RealInternalSignatureOn.il.netcore.bsl +++ b/tests/FSharp.Compiler.ComponentTests/EmittedIL/Inlining/Match01.fs.RealInternalSignatureOn.il.netcore.bsl @@ -449,361 +449,6 @@ } } - .class auto ansi serializable sealed nested assembly beforefieldinit clo@4 - extends class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2 - { - .field public class assembly/Test1 this - .custom instance void [runtime]System.Diagnostics.DebuggerBrowsableAttribute::.ctor(valuetype [runtime]System.Diagnostics.DebuggerBrowsableState) = ( 01 00 00 00 00 00 00 00 ) - .custom instance void [runtime]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) - .custom instance void [runtime]System.Diagnostics.DebuggerNonUserCodeAttribute::.ctor() = ( 01 00 00 00 ) - .field public class assembly/Test1 obj - .custom instance void [runtime]System.Diagnostics.DebuggerBrowsableAttribute::.ctor(valuetype [runtime]System.Diagnostics.DebuggerBrowsableState) = ( 01 00 00 00 00 00 00 00 ) - .custom instance void [runtime]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) - .custom instance void [runtime]System.Diagnostics.DebuggerNonUserCodeAttribute::.ctor() = ( 01 00 00 00 ) - .method assembly specialname rtspecialname instance void .ctor(class assembly/Test1 this, class assembly/Test1 obj) cil managed - { - .custom instance void [runtime]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) - .custom instance void [runtime]System.Diagnostics.DebuggerNonUserCodeAttribute::.ctor() = ( 01 00 00 00 ) - - .maxstack 8 - IL_0000: ldarg.0 - IL_0001: call instance void class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2::.ctor() - IL_0006: ldarg.0 - IL_0007: ldarg.1 - IL_0008: stfld class assembly/Test1 assembly/Test1/clo@4::this - IL_000d: ldarg.0 - IL_000e: ldarg.2 - IL_000f: stfld class assembly/Test1 assembly/Test1/clo@4::obj - IL_0014: ret - } - - .method public strict virtual instance int32 Invoke(class [FSharp.Core]Microsoft.FSharp.Core.Unit unitVar) cil managed - { - - .maxstack 7 - .locals init (int32 V_0, - int32 V_1, - class assembly/Test1/X11 V_2, - class assembly/Test1/X11 V_3, - class [runtime]System.Collections.IComparer V_4, - int32 V_5, - int32 V_6, - class assembly/Test1/X12 V_7, - class assembly/Test1/X12 V_8, - class assembly/Test1/X13 V_9, - class assembly/Test1/X13 V_10, - class assembly/Test1/X14 V_11, - class assembly/Test1/X14 V_12) - IL_0000: ldarg.0 - IL_0001: ldfld class assembly/Test1 assembly/Test1/clo@4::this - IL_0006: ldfld int32 assembly/Test1::_tag - IL_000b: stloc.0 - IL_000c: ldarg.0 - IL_000d: ldfld class assembly/Test1 assembly/Test1/clo@4::obj - IL_0012: ldfld int32 assembly/Test1::_tag - IL_0017: stloc.1 - IL_0018: ldloc.0 - IL_0019: ldloc.1 - IL_001a: bne.un IL_013f - - IL_001f: ldarg.0 - IL_0020: ldfld class assembly/Test1 assembly/Test1/clo@4::this - IL_0025: call instance int32 assembly/Test1::get_Tag() - IL_002a: switch ( - IL_003f, - IL_007c, - IL_00bd, - IL_00fe) - IL_003f: ldarg.0 - IL_0040: ldfld class assembly/Test1 assembly/Test1/clo@4::this - IL_0045: castclass assembly/Test1/X11 - IL_004a: stloc.2 - IL_004b: ldarg.0 - IL_004c: ldfld class assembly/Test1 assembly/Test1/clo@4::obj - IL_0051: castclass assembly/Test1/X11 - IL_0056: stloc.3 - IL_0057: call class [runtime]System.Collections.IComparer [FSharp.Core]Microsoft.FSharp.Core.LanguagePrimitives::get_GenericComparer() - IL_005c: stloc.s V_4 - IL_005e: ldloc.2 - IL_005f: ldfld int32 assembly/Test1/X11::item - IL_0064: stloc.s V_5 - IL_0066: ldloc.3 - IL_0067: ldfld int32 assembly/Test1/X11::item - IL_006c: stloc.s V_6 - IL_006e: ldloc.s V_5 - IL_0070: ldloc.s V_6 - IL_0072: cgt - IL_0074: ldloc.s V_5 - IL_0076: ldloc.s V_6 - IL_0078: clt - IL_007a: sub - IL_007b: ret - - IL_007c: ldarg.0 - IL_007d: ldfld class assembly/Test1 assembly/Test1/clo@4::this - IL_0082: castclass assembly/Test1/X12 - IL_0087: stloc.s V_7 - IL_0089: ldarg.0 - IL_008a: ldfld class assembly/Test1 assembly/Test1/clo@4::obj - IL_008f: castclass assembly/Test1/X12 - IL_0094: stloc.s V_8 - IL_0096: call class [runtime]System.Collections.IComparer [FSharp.Core]Microsoft.FSharp.Core.LanguagePrimitives::get_GenericComparer() - IL_009b: stloc.s V_4 - IL_009d: ldloc.s V_7 - IL_009f: ldfld int32 assembly/Test1/X12::item - IL_00a4: stloc.s V_5 - IL_00a6: ldloc.s V_8 - IL_00a8: ldfld int32 assembly/Test1/X12::item - IL_00ad: stloc.s V_6 - IL_00af: ldloc.s V_5 - IL_00b1: ldloc.s V_6 - IL_00b3: cgt - IL_00b5: ldloc.s V_5 - IL_00b7: ldloc.s V_6 - IL_00b9: clt - IL_00bb: sub - IL_00bc: ret - - IL_00bd: ldarg.0 - IL_00be: ldfld class assembly/Test1 assembly/Test1/clo@4::this - IL_00c3: castclass assembly/Test1/X13 - IL_00c8: stloc.s V_9 - IL_00ca: ldarg.0 - IL_00cb: ldfld class assembly/Test1 assembly/Test1/clo@4::obj - IL_00d0: castclass assembly/Test1/X13 - IL_00d5: stloc.s V_10 - IL_00d7: call class [runtime]System.Collections.IComparer [FSharp.Core]Microsoft.FSharp.Core.LanguagePrimitives::get_GenericComparer() - IL_00dc: stloc.s V_4 - IL_00de: ldloc.s V_9 - IL_00e0: ldfld int32 assembly/Test1/X13::item - IL_00e5: stloc.s V_5 - IL_00e7: ldloc.s V_10 - IL_00e9: ldfld int32 assembly/Test1/X13::item - IL_00ee: stloc.s V_6 - IL_00f0: ldloc.s V_5 - IL_00f2: ldloc.s V_6 - IL_00f4: cgt - IL_00f6: ldloc.s V_5 - IL_00f8: ldloc.s V_6 - IL_00fa: clt - IL_00fc: sub - IL_00fd: ret - - IL_00fe: ldarg.0 - IL_00ff: ldfld class assembly/Test1 assembly/Test1/clo@4::this - IL_0104: castclass assembly/Test1/X14 - IL_0109: stloc.s V_11 - IL_010b: ldarg.0 - IL_010c: ldfld class assembly/Test1 assembly/Test1/clo@4::obj - IL_0111: castclass assembly/Test1/X14 - IL_0116: stloc.s V_12 - IL_0118: call class [runtime]System.Collections.IComparer [FSharp.Core]Microsoft.FSharp.Core.LanguagePrimitives::get_GenericComparer() - IL_011d: stloc.s V_4 - IL_011f: ldloc.s V_11 - IL_0121: ldfld int32 assembly/Test1/X14::item - IL_0126: stloc.s V_5 - IL_0128: ldloc.s V_12 - IL_012a: ldfld int32 assembly/Test1/X14::item - IL_012f: stloc.s V_6 - IL_0131: ldloc.s V_5 - IL_0133: ldloc.s V_6 - IL_0135: cgt - IL_0137: ldloc.s V_5 - IL_0139: ldloc.s V_6 - IL_013b: clt - IL_013d: sub - IL_013e: ret - - IL_013f: ldloc.0 - IL_0140: ldloc.1 - IL_0141: sub - IL_0142: ret - } - - } - - .class auto ansi serializable sealed nested assembly beforefieldinit 'clo@4-1' - extends class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2 - { - .field public class assembly/Test1 this - .custom instance void [runtime]System.Diagnostics.DebuggerBrowsableAttribute::.ctor(valuetype [runtime]System.Diagnostics.DebuggerBrowsableState) = ( 01 00 00 00 00 00 00 00 ) - .custom instance void [runtime]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) - .custom instance void [runtime]System.Diagnostics.DebuggerNonUserCodeAttribute::.ctor() = ( 01 00 00 00 ) - .field public object obj - .custom instance void [runtime]System.Diagnostics.DebuggerBrowsableAttribute::.ctor(valuetype [runtime]System.Diagnostics.DebuggerBrowsableState) = ( 01 00 00 00 00 00 00 00 ) - .custom instance void [runtime]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) - .custom instance void [runtime]System.Diagnostics.DebuggerNonUserCodeAttribute::.ctor() = ( 01 00 00 00 ) - .field public class assembly/Test1 objTemp - .custom instance void [runtime]System.Diagnostics.DebuggerBrowsableAttribute::.ctor(valuetype [runtime]System.Diagnostics.DebuggerBrowsableState) = ( 01 00 00 00 00 00 00 00 ) - .custom instance void [runtime]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) - .custom instance void [runtime]System.Diagnostics.DebuggerNonUserCodeAttribute::.ctor() = ( 01 00 00 00 ) - .method assembly specialname rtspecialname - instance void .ctor(class assembly/Test1 this, - object obj, - class assembly/Test1 objTemp) cil managed - { - .custom instance void [runtime]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) - .custom instance void [runtime]System.Diagnostics.DebuggerNonUserCodeAttribute::.ctor() = ( 01 00 00 00 ) - - .maxstack 8 - IL_0000: ldarg.0 - IL_0001: call instance void class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2::.ctor() - IL_0006: ldarg.0 - IL_0007: ldarg.1 - IL_0008: stfld class assembly/Test1 assembly/Test1/'clo@4-1'::this - IL_000d: ldarg.0 - IL_000e: ldarg.2 - IL_000f: stfld object assembly/Test1/'clo@4-1'::obj - IL_0014: ldarg.0 - IL_0015: ldarg.3 - IL_0016: stfld class assembly/Test1 assembly/Test1/'clo@4-1'::objTemp - IL_001b: ret - } - - .method public strict virtual instance int32 Invoke(class [FSharp.Core]Microsoft.FSharp.Core.Unit unitVar) cil managed - { - - .maxstack 7 - .locals init (int32 V_0, - int32 V_1, - class assembly/Test1/X11 V_2, - class assembly/Test1/X11 V_3, - int32 V_4, - int32 V_5, - class assembly/Test1/X12 V_6, - class assembly/Test1/X12 V_7, - class assembly/Test1/X13 V_8, - class assembly/Test1/X13 V_9, - class assembly/Test1/X14 V_10, - class assembly/Test1/X14 V_11) - IL_0000: ldarg.0 - IL_0001: ldfld object assembly/Test1/'clo@4-1'::obj - IL_0006: unbox.any assembly/Test1 - IL_000b: brfalse IL_0137 - - IL_0010: ldarg.0 - IL_0011: ldfld class assembly/Test1 assembly/Test1/'clo@4-1'::this - IL_0016: ldfld int32 assembly/Test1::_tag - IL_001b: stloc.0 - IL_001c: ldarg.0 - IL_001d: ldfld class assembly/Test1 assembly/Test1/'clo@4-1'::objTemp - IL_0022: ldfld int32 assembly/Test1::_tag - IL_0027: stloc.1 - IL_0028: ldloc.0 - IL_0029: ldloc.1 - IL_002a: bne.un IL_0133 - - IL_002f: ldarg.0 - IL_0030: ldfld class assembly/Test1 assembly/Test1/'clo@4-1'::this - IL_0035: call instance int32 assembly/Test1::get_Tag() - IL_003a: switch ( - IL_004f, - IL_0085, - IL_00bf, - IL_00f9) - IL_004f: ldarg.0 - IL_0050: ldfld class assembly/Test1 assembly/Test1/'clo@4-1'::this - IL_0055: castclass assembly/Test1/X11 - IL_005a: stloc.2 - IL_005b: ldarg.0 - IL_005c: ldfld class assembly/Test1 assembly/Test1/'clo@4-1'::objTemp - IL_0061: castclass assembly/Test1/X11 - IL_0066: stloc.3 - IL_0067: ldloc.2 - IL_0068: ldfld int32 assembly/Test1/X11::item - IL_006d: stloc.s V_4 - IL_006f: ldloc.3 - IL_0070: ldfld int32 assembly/Test1/X11::item - IL_0075: stloc.s V_5 - IL_0077: ldloc.s V_4 - IL_0079: ldloc.s V_5 - IL_007b: cgt - IL_007d: ldloc.s V_4 - IL_007f: ldloc.s V_5 - IL_0081: clt - IL_0083: sub - IL_0084: ret - - IL_0085: ldarg.0 - IL_0086: ldfld class assembly/Test1 assembly/Test1/'clo@4-1'::this - IL_008b: castclass assembly/Test1/X12 - IL_0090: stloc.s V_6 - IL_0092: ldarg.0 - IL_0093: ldfld class assembly/Test1 assembly/Test1/'clo@4-1'::objTemp - IL_0098: castclass assembly/Test1/X12 - IL_009d: stloc.s V_7 - IL_009f: ldloc.s V_6 - IL_00a1: ldfld int32 assembly/Test1/X12::item - IL_00a6: stloc.s V_4 - IL_00a8: ldloc.s V_7 - IL_00aa: ldfld int32 assembly/Test1/X12::item - IL_00af: stloc.s V_5 - IL_00b1: ldloc.s V_4 - IL_00b3: ldloc.s V_5 - IL_00b5: cgt - IL_00b7: ldloc.s V_4 - IL_00b9: ldloc.s V_5 - IL_00bb: clt - IL_00bd: sub - IL_00be: ret - - IL_00bf: ldarg.0 - IL_00c0: ldfld class assembly/Test1 assembly/Test1/'clo@4-1'::this - IL_00c5: castclass assembly/Test1/X13 - IL_00ca: stloc.s V_8 - IL_00cc: ldarg.0 - IL_00cd: ldfld class assembly/Test1 assembly/Test1/'clo@4-1'::objTemp - IL_00d2: castclass assembly/Test1/X13 - IL_00d7: stloc.s V_9 - IL_00d9: ldloc.s V_8 - IL_00db: ldfld int32 assembly/Test1/X13::item - IL_00e0: stloc.s V_4 - IL_00e2: ldloc.s V_9 - IL_00e4: ldfld int32 assembly/Test1/X13::item - IL_00e9: stloc.s V_5 - IL_00eb: ldloc.s V_4 - IL_00ed: ldloc.s V_5 - IL_00ef: cgt - IL_00f1: ldloc.s V_4 - IL_00f3: ldloc.s V_5 - IL_00f5: clt - IL_00f7: sub - IL_00f8: ret - - IL_00f9: ldarg.0 - IL_00fa: ldfld class assembly/Test1 assembly/Test1/'clo@4-1'::this - IL_00ff: castclass assembly/Test1/X14 - IL_0104: stloc.s V_10 - IL_0106: ldarg.0 - IL_0107: ldfld class assembly/Test1 assembly/Test1/'clo@4-1'::objTemp - IL_010c: castclass assembly/Test1/X14 - IL_0111: stloc.s V_11 - IL_0113: ldloc.s V_10 - IL_0115: ldfld int32 assembly/Test1/X14::item - IL_011a: stloc.s V_4 - IL_011c: ldloc.s V_11 - IL_011e: ldfld int32 assembly/Test1/X14::item - IL_0123: stloc.s V_5 - IL_0125: ldloc.s V_4 - IL_0127: ldloc.s V_5 - IL_0129: cgt - IL_012b: ldloc.s V_4 - IL_012d: ldloc.s V_5 - IL_012f: clt - IL_0131: sub - IL_0132: ret - - IL_0133: ldloc.0 - IL_0134: ldloc.1 - IL_0135: sub - IL_0136: ret - - IL_0137: ldc.i4.1 - IL_0138: ret - } - - } - .field assembly initonly int32 _tag .custom instance void [runtime]System.Diagnostics.DebuggerBrowsableAttribute::.ctor(valuetype [runtime]System.Diagnostics.DebuggerBrowsableState) = ( 01 00 00 00 00 00 00 00 ) .custom instance void [runtime]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) @@ -971,36 +616,32 @@ { .custom instance void [runtime]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) - .maxstack 4 - .locals init (class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2 V_0) + .maxstack 8 IL_0000: ldarg.0 - IL_0001: brfalse.s IL_001a + IL_0001: brfalse.s IL_0011 IL_0003: ldarg.1 - IL_0004: brfalse.s IL_0018 + IL_0004: brfalse.s IL_000f IL_0006: ldarg.0 IL_0007: ldarg.1 - IL_0008: newobj instance void assembly/Test1/clo@4::.ctor(class assembly/Test1, - class assembly/Test1) - IL_000d: stloc.0 - IL_000e: ldloc.0 - IL_000f: ldnull - IL_0010: tail. - IL_0012: callvirt instance !1 class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2::Invoke(!0) - IL_0017: ret + IL_0008: ldnull + IL_0009: call int32 assembly::CompareTo$cont@4(class assembly/Test1, + class assembly/Test1, + class [FSharp.Core]Microsoft.FSharp.Core.Unit) + IL_000e: ret - IL_0018: ldc.i4.1 - IL_0019: ret + IL_000f: ldc.i4.1 + IL_0010: ret - IL_001a: ldarg.1 - IL_001b: brfalse.s IL_001f + IL_0011: ldarg.1 + IL_0012: brfalse.s IL_0016 - IL_001d: ldc.i4.m1 - IL_001e: ret + IL_0014: ldc.i4.m1 + IL_0015: ret - IL_001f: ldc.i4.0 - IL_0020: ret + IL_0016: ldc.i4.0 + IL_0017: ret } .method public hidebysig virtual final instance int32 CompareTo(object obj) cil managed @@ -1019,37 +660,33 @@ { .custom instance void [runtime]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) - .maxstack 5 - .locals init (class assembly/Test1 V_0, - class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2 V_1) + .maxstack 6 + .locals init (class assembly/Test1 V_0) IL_0000: ldarg.1 IL_0001: unbox.any assembly/Test1 IL_0006: stloc.0 IL_0007: ldarg.0 - IL_0008: brfalse.s IL_001d + IL_0008: brfalse.s IL_0014 IL_000a: ldarg.0 IL_000b: ldarg.1 IL_000c: ldloc.0 - IL_000d: newobj instance void assembly/Test1/'clo@4-1'::.ctor(class assembly/Test1, - object, - class assembly/Test1) - IL_0012: stloc.1 - IL_0013: ldloc.1 - IL_0014: ldnull - IL_0015: tail. - IL_0017: callvirt instance !1 class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2::Invoke(!0) - IL_001c: ret - - IL_001d: ldarg.1 - IL_001e: unbox.any assembly/Test1 - IL_0023: brfalse.s IL_0027 - - IL_0025: ldc.i4.m1 - IL_0026: ret - - IL_0027: ldc.i4.0 - IL_0028: ret + IL_000d: ldnull + IL_000e: call int32 assembly::'CompareTo$cont@4-1'(class assembly/Test1, + object, + class assembly/Test1, + class [FSharp.Core]Microsoft.FSharp.Core.Unit) + IL_0013: ret + + IL_0014: ldarg.1 + IL_0015: unbox.any assembly/Test1 + IL_001a: brfalse.s IL_001e + + IL_001c: ldc.i4.m1 + IL_001d: ret + + IL_001e: ldc.i4.0 + IL_001f: ret } .method public hidebysig virtual final instance int32 GetHashCode(class [runtime]System.Collections.IEqualityComparer comp) cil managed @@ -1498,6 +1135,275 @@ IL_0006: ret } + .method assembly static int32 CompareTo$cont@4(class assembly/Test1 this, + class assembly/Test1 obj, + class [FSharp.Core]Microsoft.FSharp.Core.Unit unitVar) cil managed + { + .custom instance void [runtime]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) + + .maxstack 5 + .locals init (int32 V_0, + int32 V_1, + class assembly/Test1/X11 V_2, + class assembly/Test1/X11 V_3, + class [runtime]System.Collections.IComparer V_4, + int32 V_5, + int32 V_6, + class assembly/Test1/X12 V_7, + class assembly/Test1/X12 V_8, + class assembly/Test1/X13 V_9, + class assembly/Test1/X13 V_10, + class assembly/Test1/X14 V_11, + class assembly/Test1/X14 V_12) + IL_0000: ldarg.0 + IL_0001: ldfld int32 assembly/Test1::_tag + IL_0006: stloc.0 + IL_0007: ldarg.1 + IL_0008: ldfld int32 assembly/Test1::_tag + IL_000d: stloc.1 + IL_000e: ldloc.0 + IL_000f: ldloc.1 + IL_0010: bne.un IL_0108 + + IL_0015: ldarg.0 + IL_0016: call instance int32 assembly/Test1::get_Tag() + IL_001b: switch ( + IL_0030, + IL_0063, + IL_009a, + IL_00d1) + IL_0030: ldarg.0 + IL_0031: castclass assembly/Test1/X11 + IL_0036: stloc.2 + IL_0037: ldarg.1 + IL_0038: castclass assembly/Test1/X11 + IL_003d: stloc.3 + IL_003e: call class [runtime]System.Collections.IComparer [FSharp.Core]Microsoft.FSharp.Core.LanguagePrimitives::get_GenericComparer() + IL_0043: stloc.s V_4 + IL_0045: ldloc.2 + IL_0046: ldfld int32 assembly/Test1/X11::item + IL_004b: stloc.s V_5 + IL_004d: ldloc.3 + IL_004e: ldfld int32 assembly/Test1/X11::item + IL_0053: stloc.s V_6 + IL_0055: ldloc.s V_5 + IL_0057: ldloc.s V_6 + IL_0059: cgt + IL_005b: ldloc.s V_5 + IL_005d: ldloc.s V_6 + IL_005f: clt + IL_0061: sub + IL_0062: ret + + IL_0063: ldarg.0 + IL_0064: castclass assembly/Test1/X12 + IL_0069: stloc.s V_7 + IL_006b: ldarg.1 + IL_006c: castclass assembly/Test1/X12 + IL_0071: stloc.s V_8 + IL_0073: call class [runtime]System.Collections.IComparer [FSharp.Core]Microsoft.FSharp.Core.LanguagePrimitives::get_GenericComparer() + IL_0078: stloc.s V_4 + IL_007a: ldloc.s V_7 + IL_007c: ldfld int32 assembly/Test1/X12::item + IL_0081: stloc.s V_5 + IL_0083: ldloc.s V_8 + IL_0085: ldfld int32 assembly/Test1/X12::item + IL_008a: stloc.s V_6 + IL_008c: ldloc.s V_5 + IL_008e: ldloc.s V_6 + IL_0090: cgt + IL_0092: ldloc.s V_5 + IL_0094: ldloc.s V_6 + IL_0096: clt + IL_0098: sub + IL_0099: ret + + IL_009a: ldarg.0 + IL_009b: castclass assembly/Test1/X13 + IL_00a0: stloc.s V_9 + IL_00a2: ldarg.1 + IL_00a3: castclass assembly/Test1/X13 + IL_00a8: stloc.s V_10 + IL_00aa: call class [runtime]System.Collections.IComparer [FSharp.Core]Microsoft.FSharp.Core.LanguagePrimitives::get_GenericComparer() + IL_00af: stloc.s V_4 + IL_00b1: ldloc.s V_9 + IL_00b3: ldfld int32 assembly/Test1/X13::item + IL_00b8: stloc.s V_5 + IL_00ba: ldloc.s V_10 + IL_00bc: ldfld int32 assembly/Test1/X13::item + IL_00c1: stloc.s V_6 + IL_00c3: ldloc.s V_5 + IL_00c5: ldloc.s V_6 + IL_00c7: cgt + IL_00c9: ldloc.s V_5 + IL_00cb: ldloc.s V_6 + IL_00cd: clt + IL_00cf: sub + IL_00d0: ret + + IL_00d1: ldarg.0 + IL_00d2: castclass assembly/Test1/X14 + IL_00d7: stloc.s V_11 + IL_00d9: ldarg.1 + IL_00da: castclass assembly/Test1/X14 + IL_00df: stloc.s V_12 + IL_00e1: call class [runtime]System.Collections.IComparer [FSharp.Core]Microsoft.FSharp.Core.LanguagePrimitives::get_GenericComparer() + IL_00e6: stloc.s V_4 + IL_00e8: ldloc.s V_11 + IL_00ea: ldfld int32 assembly/Test1/X14::item + IL_00ef: stloc.s V_5 + IL_00f1: ldloc.s V_12 + IL_00f3: ldfld int32 assembly/Test1/X14::item + IL_00f8: stloc.s V_6 + IL_00fa: ldloc.s V_5 + IL_00fc: ldloc.s V_6 + IL_00fe: cgt + IL_0100: ldloc.s V_5 + IL_0102: ldloc.s V_6 + IL_0104: clt + IL_0106: sub + IL_0107: ret + + IL_0108: ldloc.0 + IL_0109: ldloc.1 + IL_010a: sub + IL_010b: ret + } + + .method assembly static int32 'CompareTo$cont@4-1'(class assembly/Test1 this, + object obj, + class assembly/Test1 objTemp, + class [FSharp.Core]Microsoft.FSharp.Core.Unit unitVar) cil managed + { + .custom instance void [runtime]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) + + .maxstack 5 + .locals init (int32 V_0, + int32 V_1, + class assembly/Test1/X11 V_2, + class assembly/Test1/X11 V_3, + int32 V_4, + int32 V_5, + class assembly/Test1/X12 V_6, + class assembly/Test1/X12 V_7, + class assembly/Test1/X13 V_8, + class assembly/Test1/X13 V_9, + class assembly/Test1/X14 V_10, + class assembly/Test1/X14 V_11) + IL_0000: ldarg.1 + IL_0001: unbox.any assembly/Test1 + IL_0006: brfalse IL_00fb + + IL_000b: ldarg.0 + IL_000c: ldfld int32 assembly/Test1::_tag + IL_0011: stloc.0 + IL_0012: ldarg.2 + IL_0013: ldfld int32 assembly/Test1::_tag + IL_0018: stloc.1 + IL_0019: ldloc.0 + IL_001a: ldloc.1 + IL_001b: bne.un IL_00f7 + + IL_0020: ldarg.0 + IL_0021: call instance int32 assembly/Test1::get_Tag() + IL_0026: switch ( + IL_003b, + IL_0067, + IL_0097, + IL_00c7) + IL_003b: ldarg.0 + IL_003c: castclass assembly/Test1/X11 + IL_0041: stloc.2 + IL_0042: ldarg.2 + IL_0043: castclass assembly/Test1/X11 + IL_0048: stloc.3 + IL_0049: ldloc.2 + IL_004a: ldfld int32 assembly/Test1/X11::item + IL_004f: stloc.s V_4 + IL_0051: ldloc.3 + IL_0052: ldfld int32 assembly/Test1/X11::item + IL_0057: stloc.s V_5 + IL_0059: ldloc.s V_4 + IL_005b: ldloc.s V_5 + IL_005d: cgt + IL_005f: ldloc.s V_4 + IL_0061: ldloc.s V_5 + IL_0063: clt + IL_0065: sub + IL_0066: ret + + IL_0067: ldarg.0 + IL_0068: castclass assembly/Test1/X12 + IL_006d: stloc.s V_6 + IL_006f: ldarg.2 + IL_0070: castclass assembly/Test1/X12 + IL_0075: stloc.s V_7 + IL_0077: ldloc.s V_6 + IL_0079: ldfld int32 assembly/Test1/X12::item + IL_007e: stloc.s V_4 + IL_0080: ldloc.s V_7 + IL_0082: ldfld int32 assembly/Test1/X12::item + IL_0087: stloc.s V_5 + IL_0089: ldloc.s V_4 + IL_008b: ldloc.s V_5 + IL_008d: cgt + IL_008f: ldloc.s V_4 + IL_0091: ldloc.s V_5 + IL_0093: clt + IL_0095: sub + IL_0096: ret + + IL_0097: ldarg.0 + IL_0098: castclass assembly/Test1/X13 + IL_009d: stloc.s V_8 + IL_009f: ldarg.2 + IL_00a0: castclass assembly/Test1/X13 + IL_00a5: stloc.s V_9 + IL_00a7: ldloc.s V_8 + IL_00a9: ldfld int32 assembly/Test1/X13::item + IL_00ae: stloc.s V_4 + IL_00b0: ldloc.s V_9 + IL_00b2: ldfld int32 assembly/Test1/X13::item + IL_00b7: stloc.s V_5 + IL_00b9: ldloc.s V_4 + IL_00bb: ldloc.s V_5 + IL_00bd: cgt + IL_00bf: ldloc.s V_4 + IL_00c1: ldloc.s V_5 + IL_00c3: clt + IL_00c5: sub + IL_00c6: ret + + IL_00c7: ldarg.0 + IL_00c8: castclass assembly/Test1/X14 + IL_00cd: stloc.s V_10 + IL_00cf: ldarg.2 + IL_00d0: castclass assembly/Test1/X14 + IL_00d5: stloc.s V_11 + IL_00d7: ldloc.s V_10 + IL_00d9: ldfld int32 assembly/Test1/X14::item + IL_00de: stloc.s V_4 + IL_00e0: ldloc.s V_11 + IL_00e2: ldfld int32 assembly/Test1/X14::item + IL_00e7: stloc.s V_5 + IL_00e9: ldloc.s V_4 + IL_00eb: ldloc.s V_5 + IL_00ed: cgt + IL_00ef: ldloc.s V_4 + IL_00f1: ldloc.s V_5 + IL_00f3: clt + IL_00f5: sub + IL_00f6: ret + + IL_00f7: ldloc.0 + IL_00f8: ldloc.1 + IL_00f9: sub + IL_00fa: ret + + IL_00fb: ldc.i4.1 + IL_00fc: ret + } + } .class private abstract auto ansi sealed ''.$assembly @@ -1517,4 +1423,3 @@ - diff --git a/tests/FSharp.Compiler.ComponentTests/EmittedIL/Inlining/Regression_Specialize_ConstraintVerification.fs b/tests/FSharp.Compiler.ComponentTests/EmittedIL/Inlining/Regression_Specialize_ConstraintVerification.fs new file mode 100644 index 00000000000..5117f860ddd --- /dev/null +++ b/tests/FSharp.Compiler.ComponentTests/EmittedIL/Inlining/Regression_Specialize_ConstraintVerification.fs @@ -0,0 +1,82 @@ +namespace EmittedIL.RealInternalSignature + +open Xunit +open FSharp.Test +open FSharp.Test.Compiler + +/// Inline functions with constrained type params, when inlined into closures, +/// attach those constraints to the closure class's generic params. The closure's +/// Specialize override (from FSharpFunc) must be unconstrained to match the base. +/// If constraints leak, the JIT throws at type-load time: +/// "TypeLoadException: Method 'Specialize' on type '...' tried to implicitly +/// override a method with weaker type parameter constraints." +/// +/// Each test exercises a different ILGenericParameterDef field stripped by mkILSimpleTypar: +/// struct → HasNotNullableValueTypeConstraint +/// not struct → HasReferenceTypeConstraint +/// unmanaged → CustomAttrsStored (IsUnmanagedAttribute) +/// new() → HasDefaultConstructorConstraint +/// :> interface → Constraints list +/// comparison → SRTP resolved to specific IL calls +/// +/// Pipeline: compile (optimized) → ILVerify (metadata) → run (TypeLoadException guard). +/// See #14492. +module Regression_Specialize_ConstraintVerification = + + open Regression_TLR_MutualInnerRec_StructuralAssertions + + let private compileVerifyAndRun realsig source = + let compiled = source |> compileOptimized realsig |> compile |> shouldSucceed + compiled |> verifyPEFileWithSystemDlls |> shouldSucceed |> ignore + compiled |> run |> shouldSucceed |> ignore + + [] + let ``struct + equality`` (realsig: bool) = + closureWithConstraint "'a : struct and 'a : equality" "a = b" "int" "42" + |> compileVerifyAndRun realsig + + [] + let ``not struct + equality`` (realsig: bool) = + closureWithConstraint "'a : not struct and 'a : equality" "obj.ReferenceEquals(a, b)" "string" "\"ok\"" + |> compileVerifyAndRun realsig + + [] + let ``unmanaged + equality`` (realsig: bool) = + closureWithConstraint "'a : unmanaged and 'a : equality" "a = b" "int" "42" + |> compileVerifyAndRun realsig + + [] + let ``default constructor`` (realsig: bool) = + closureWithConstraint "'a : (new : unit -> 'a) and 'a : equality" "a = b" "int" "42" + |> compileVerifyAndRun realsig + + [] + let ``interface IComparable`` (realsig: bool) = + closureWithConstraint "'a :> System.IComparable" "(a :> System.IComparable).CompareTo(b) = 0" "int" "42" + |> compileVerifyAndRun realsig + + [] + let ``comparison`` (realsig: bool) = + closureWithConstraint "'a : comparison" "compare a b = 0" "int" "42" + |> compileVerifyAndRun realsig + + [] + let ``struct + comparison + equality combined`` (realsig: bool) = + closureWithConstraint "'a : struct and 'a : comparison and 'a : equality" "a >= b" "int" "42" + |> compileVerifyAndRun realsig + + /// Constrained inline member call inside a closure caused CLR segfault. See #19075. + [] + let ``SRTP member constraint with IDisposable`` (realsig: bool) = + """module Test +open System +open System.IO +module Dispose = + let inline action<'a when 'a: (member Dispose: unit -> unit) and 'a :> IDisposable>(a: 'a) = a.Dispose() +[] +let main _ = + let ms = new MemoryStream() + ms |> Dispose.action + 0 +""" + |> compileVerifyAndRun realsig diff --git a/tests/FSharp.Compiler.ComponentTests/EmittedIL/Inlining/Regression_TLR_MutualInnerRec.fs b/tests/FSharp.Compiler.ComponentTests/EmittedIL/Inlining/Regression_TLR_MutualInnerRec.fs new file mode 100644 index 00000000000..1fa8383bf62 --- /dev/null +++ b/tests/FSharp.Compiler.ComponentTests/EmittedIL/Inlining/Regression_TLR_MutualInnerRec.fs @@ -0,0 +1,15 @@ +module Regression_TLR_MutualInnerRec + +let fifth() = + let rec fifthMethodFirstCallee(iterationCount, firstArg: int) = + if iterationCount = 0 then 100 + else if iterationCount % 2 = 0 then fifthMethodSecondCallee(iterationCount - 1, firstArg) + else fifthMethodFirstCallee(iterationCount - 1, firstArg) + and fifthMethodSecondCallee(iterationCount, firstArg) = + if iterationCount = 0 then 101 + else if iterationCount % 2 = 0 then fifthMethodSecondCallee(iterationCount - 1, firstArg) + else fifthMethodFirstCallee(iterationCount - 1, firstArg) + fifthMethodFirstCallee(1000000, 158_423) + +[] +let main _argv = fifth () diff --git a/tests/FSharp.Compiler.ComponentTests/EmittedIL/Inlining/Regression_TLR_MutualInnerRec.fs.RealInternalSignatureOff.il.bsl b/tests/FSharp.Compiler.ComponentTests/EmittedIL/Inlining/Regression_TLR_MutualInnerRec.fs.RealInternalSignatureOff.il.bsl new file mode 100644 index 00000000000..e6b6253be66 --- /dev/null +++ b/tests/FSharp.Compiler.ComponentTests/EmittedIL/Inlining/Regression_TLR_MutualInnerRec.fs.RealInternalSignatureOff.il.bsl @@ -0,0 +1,141 @@ + + + + + +.assembly extern runtime { } +.assembly extern FSharp.Core { } +.assembly assembly +{ + .custom instance void [FSharp.Core]Microsoft.FSharp.Core.FSharpInterfaceDataVersionAttribute::.ctor(int32, + int32, + int32) = ( 01 00 02 00 00 00 00 00 00 00 00 00 00 00 00 00 ) + + + + + .hash algorithm 0x00008004 + .ver 0:0:0:0 +} +.module assembly.exe + +.imagebase {value} +.file alignment 0x00000200 +.stackreserve 0x00100000 +.subsystem 0x0003 +.corflags 0x00000001 + + + + + +.class public abstract auto ansi sealed assembly + extends [runtime]System.Object +{ + .custom instance void [FSharp.Core]Microsoft.FSharp.Core.CompilationMappingAttribute::.ctor(valuetype [FSharp.Core]Microsoft.FSharp.Core.SourceConstructFlags) = ( 01 00 07 00 00 00 00 00 ) + .method public static int32 fifth() cil managed + { + + .maxstack 8 + IL_0000: ldc.i4 0xf4240 + IL_0005: ldc.i4 0x26ad7 + IL_000a: tail. + IL_000c: call int32 assembly::fifthMethodFirstCallee@4(int32, + int32) + IL_0011: ret + } + + .method public static int32 main(string[] _argv) cil managed + { + .entrypoint + .custom instance void [FSharp.Core]Microsoft.FSharp.Core.EntryPointAttribute::.ctor() = ( 01 00 00 00 ) + + .maxstack 8 + IL_0000: tail. + IL_0002: call int32 assembly::fifth() + IL_0007: ret + } + + .method assembly static int32 fifthMethodFirstCallee@4(int32 iterationCount, + int32 firstArg) cil managed + { + + .maxstack 8 + IL_0000: nop + IL_0001: ldarg.0 + IL_0002: brtrue.s IL_0007 + + IL_0004: ldc.i4.s 100 + IL_0006: ret + + IL_0007: nop + IL_0008: ldarg.0 + IL_0009: ldc.i4.2 + IL_000a: rem + IL_000b: brtrue.s IL_0019 + + IL_000d: ldarg.0 + IL_000e: ldc.i4.1 + IL_000f: sub + IL_0010: ldarg.1 + IL_0011: tail. + IL_0013: call int32 assembly::fifthMethodSecondCallee@8(int32, + int32) + IL_0018: ret + + IL_0019: ldarg.0 + IL_001a: ldc.i4.1 + IL_001b: sub + IL_001c: ldarg.1 + IL_001d: starg.s firstArg + IL_001f: starg.s iterationCount + IL_0021: br.s IL_0000 + } + + .method assembly static int32 fifthMethodSecondCallee@8(int32 iterationCount, + int32 firstArg) cil managed + { + + .maxstack 8 + IL_0000: nop + IL_0001: ldarg.0 + IL_0002: brtrue.s IL_0007 + + IL_0004: ldc.i4.s 101 + IL_0006: ret + + IL_0007: nop + IL_0008: ldarg.0 + IL_0009: ldc.i4.2 + IL_000a: rem + IL_000b: brtrue.s IL_0017 + + IL_000d: ldarg.0 + IL_000e: ldc.i4.1 + IL_000f: sub + IL_0010: ldarg.1 + IL_0011: starg.s firstArg + IL_0013: starg.s iterationCount + IL_0015: br.s IL_0000 + + IL_0017: ldarg.0 + IL_0018: ldc.i4.1 + IL_0019: sub + IL_001a: ldarg.1 + IL_001b: tail. + IL_001d: call int32 assembly::fifthMethodFirstCallee@4(int32, + int32) + IL_0022: ret + } + +} + +.class private abstract auto ansi sealed ''.$assembly + extends [runtime]System.Object +{ +} + + + + + diff --git a/tests/FSharp.Compiler.ComponentTests/EmittedIL/Inlining/Regression_TLR_MutualInnerRec.fs.RealInternalSignatureOn.il.bsl b/tests/FSharp.Compiler.ComponentTests/EmittedIL/Inlining/Regression_TLR_MutualInnerRec.fs.RealInternalSignatureOn.il.bsl new file mode 100644 index 00000000000..e6b6253be66 --- /dev/null +++ b/tests/FSharp.Compiler.ComponentTests/EmittedIL/Inlining/Regression_TLR_MutualInnerRec.fs.RealInternalSignatureOn.il.bsl @@ -0,0 +1,141 @@ + + + + + +.assembly extern runtime { } +.assembly extern FSharp.Core { } +.assembly assembly +{ + .custom instance void [FSharp.Core]Microsoft.FSharp.Core.FSharpInterfaceDataVersionAttribute::.ctor(int32, + int32, + int32) = ( 01 00 02 00 00 00 00 00 00 00 00 00 00 00 00 00 ) + + + + + .hash algorithm 0x00008004 + .ver 0:0:0:0 +} +.module assembly.exe + +.imagebase {value} +.file alignment 0x00000200 +.stackreserve 0x00100000 +.subsystem 0x0003 +.corflags 0x00000001 + + + + + +.class public abstract auto ansi sealed assembly + extends [runtime]System.Object +{ + .custom instance void [FSharp.Core]Microsoft.FSharp.Core.CompilationMappingAttribute::.ctor(valuetype [FSharp.Core]Microsoft.FSharp.Core.SourceConstructFlags) = ( 01 00 07 00 00 00 00 00 ) + .method public static int32 fifth() cil managed + { + + .maxstack 8 + IL_0000: ldc.i4 0xf4240 + IL_0005: ldc.i4 0x26ad7 + IL_000a: tail. + IL_000c: call int32 assembly::fifthMethodFirstCallee@4(int32, + int32) + IL_0011: ret + } + + .method public static int32 main(string[] _argv) cil managed + { + .entrypoint + .custom instance void [FSharp.Core]Microsoft.FSharp.Core.EntryPointAttribute::.ctor() = ( 01 00 00 00 ) + + .maxstack 8 + IL_0000: tail. + IL_0002: call int32 assembly::fifth() + IL_0007: ret + } + + .method assembly static int32 fifthMethodFirstCallee@4(int32 iterationCount, + int32 firstArg) cil managed + { + + .maxstack 8 + IL_0000: nop + IL_0001: ldarg.0 + IL_0002: brtrue.s IL_0007 + + IL_0004: ldc.i4.s 100 + IL_0006: ret + + IL_0007: nop + IL_0008: ldarg.0 + IL_0009: ldc.i4.2 + IL_000a: rem + IL_000b: brtrue.s IL_0019 + + IL_000d: ldarg.0 + IL_000e: ldc.i4.1 + IL_000f: sub + IL_0010: ldarg.1 + IL_0011: tail. + IL_0013: call int32 assembly::fifthMethodSecondCallee@8(int32, + int32) + IL_0018: ret + + IL_0019: ldarg.0 + IL_001a: ldc.i4.1 + IL_001b: sub + IL_001c: ldarg.1 + IL_001d: starg.s firstArg + IL_001f: starg.s iterationCount + IL_0021: br.s IL_0000 + } + + .method assembly static int32 fifthMethodSecondCallee@8(int32 iterationCount, + int32 firstArg) cil managed + { + + .maxstack 8 + IL_0000: nop + IL_0001: ldarg.0 + IL_0002: brtrue.s IL_0007 + + IL_0004: ldc.i4.s 101 + IL_0006: ret + + IL_0007: nop + IL_0008: ldarg.0 + IL_0009: ldc.i4.2 + IL_000a: rem + IL_000b: brtrue.s IL_0017 + + IL_000d: ldarg.0 + IL_000e: ldc.i4.1 + IL_000f: sub + IL_0010: ldarg.1 + IL_0011: starg.s firstArg + IL_0013: starg.s iterationCount + IL_0015: br.s IL_0000 + + IL_0017: ldarg.0 + IL_0018: ldc.i4.1 + IL_0019: sub + IL_001a: ldarg.1 + IL_001b: tail. + IL_001d: call int32 assembly::fifthMethodFirstCallee@4(int32, + int32) + IL_0022: ret + } + +} + +.class private abstract auto ansi sealed ''.$assembly + extends [runtime]System.Object +{ +} + + + + + diff --git a/tests/FSharp.Compiler.ComponentTests/EmittedIL/Inlining/Regression_TLR_MutualInnerRec_CapturedEnv.fs b/tests/FSharp.Compiler.ComponentTests/EmittedIL/Inlining/Regression_TLR_MutualInnerRec_CapturedEnv.fs new file mode 100644 index 00000000000..3fc9f0f344f --- /dev/null +++ b/tests/FSharp.Compiler.ComponentTests/EmittedIL/Inlining/Regression_TLR_MutualInnerRec_CapturedEnv.fs @@ -0,0 +1,15 @@ +module Regression_TLR_MutualInnerRec_CapturedEnv + +let outer (threshold: int) (factor: int) = + let rec a(n) = + if n = 0 then threshold + elif n % 2 = 0 then b(n - 1) + else a(n - factor) + and b(n) = + if n = 0 then threshold + 1 + elif n % 2 = 0 then b(n - factor) + else a(n - 1) + a(100) + +[] +let main _argv = outer 7 1 diff --git a/tests/FSharp.Compiler.ComponentTests/EmittedIL/Inlining/Regression_TLR_MutualInnerRec_CapturedEnv.fs.RealInternalSignatureOff.il.bsl b/tests/FSharp.Compiler.ComponentTests/EmittedIL/Inlining/Regression_TLR_MutualInnerRec_CapturedEnv.fs.RealInternalSignatureOff.il.bsl new file mode 100644 index 00000000000..9dc10e0e9cb --- /dev/null +++ b/tests/FSharp.Compiler.ComponentTests/EmittedIL/Inlining/Regression_TLR_MutualInnerRec_CapturedEnv.fs.RealInternalSignatureOff.il.bsl @@ -0,0 +1,166 @@ + + + + + +.assembly extern runtime { } +.assembly extern FSharp.Core { } +.assembly assembly +{ + .custom instance void [FSharp.Core]Microsoft.FSharp.Core.FSharpInterfaceDataVersionAttribute::.ctor(int32, + int32, + int32) = ( 01 00 02 00 00 00 00 00 00 00 00 00 00 00 00 00 ) + + + + + .hash algorithm 0x00008004 + .ver 0:0:0:0 +} +.module assembly.exe + +.imagebase {value} +.file alignment 0x00000200 +.stackreserve 0x00100000 +.subsystem 0x0003 +.corflags 0x00000001 + + + + + +.class public abstract auto ansi sealed assembly + extends [runtime]System.Object +{ + .custom instance void [FSharp.Core]Microsoft.FSharp.Core.CompilationMappingAttribute::.ctor(valuetype [FSharp.Core]Microsoft.FSharp.Core.SourceConstructFlags) = ( 01 00 07 00 00 00 00 00 ) + .method public static int32 outer(int32 threshold, + int32 factor) cil managed + { + .custom instance void [FSharp.Core]Microsoft.FSharp.Core.CompilationArgumentCountsAttribute::.ctor(int32[]) = ( 01 00 02 00 00 00 01 00 00 00 01 00 00 00 00 00 ) + + .maxstack 5 + .locals init (int32 V_0, + int32 V_1) + IL_0000: ldarg.0 + IL_0001: stloc.0 + IL_0002: ldarg.1 + IL_0003: stloc.1 + IL_0004: ldarg.0 + IL_0005: ldarg.1 + IL_0006: ldc.i4.s 100 + IL_0008: tail. + IL_000a: call int32 assembly::a@4(int32, + int32, + int32) + IL_000f: ret + } + + .method public static int32 main(string[] _argv) cil managed + { + .entrypoint + .custom instance void [FSharp.Core]Microsoft.FSharp.Core.EntryPointAttribute::.ctor() = ( 01 00 00 00 ) + + .maxstack 8 + IL_0000: ldc.i4.7 + IL_0001: ldc.i4.1 + IL_0002: tail. + IL_0004: call int32 assembly::outer(int32, + int32) + IL_0009: ret + } + + .method assembly static int32 a@4(int32 threshold, + int32 factor, + int32 n) cil managed + { + + .maxstack 8 + IL_0000: nop + IL_0001: ldarg.2 + IL_0002: brtrue.s IL_0006 + + IL_0004: ldarg.0 + IL_0005: ret + + IL_0006: nop + IL_0007: ldarg.2 + IL_0008: ldc.i4.2 + IL_0009: rem + IL_000a: brtrue.s IL_0019 + + IL_000c: ldarg.0 + IL_000d: ldarg.1 + IL_000e: ldarg.2 + IL_000f: ldc.i4.1 + IL_0010: sub + IL_0011: tail. + IL_0013: call int32 assembly::b@8(int32, + int32, + int32) + IL_0018: ret + + IL_0019: ldarg.0 + IL_001a: ldarg.1 + IL_001b: ldarg.2 + IL_001c: ldarg.1 + IL_001d: sub + IL_001e: starg.s n + IL_0020: starg.s factor + IL_0022: starg.s threshold + IL_0024: br.s IL_0000 + } + + .method assembly static int32 b@8(int32 threshold, + int32 factor, + int32 n) cil managed + { + + .maxstack 8 + IL_0000: nop + IL_0001: ldarg.2 + IL_0002: brtrue.s IL_0008 + + IL_0004: ldarg.0 + IL_0005: ldc.i4.1 + IL_0006: add + IL_0007: ret + + IL_0008: nop + IL_0009: ldarg.2 + IL_000a: ldc.i4.2 + IL_000b: rem + IL_000c: brtrue.s IL_001b + + IL_000e: ldarg.0 + IL_000f: ldarg.1 + IL_0010: ldarg.2 + IL_0011: ldarg.1 + IL_0012: sub + IL_0013: starg.s n + IL_0015: starg.s factor + IL_0017: starg.s threshold + IL_0019: br.s IL_0000 + + IL_001b: ldarg.0 + IL_001c: ldarg.1 + IL_001d: ldarg.2 + IL_001e: ldc.i4.1 + IL_001f: sub + IL_0020: tail. + IL_0022: call int32 assembly::a@4(int32, + int32, + int32) + IL_0027: ret + } + +} + +.class private abstract auto ansi sealed ''.$assembly + extends [runtime]System.Object +{ +} + + + + + diff --git a/tests/FSharp.Compiler.ComponentTests/EmittedIL/Inlining/Regression_TLR_MutualInnerRec_CapturedEnv.fs.RealInternalSignatureOn.il.bsl b/tests/FSharp.Compiler.ComponentTests/EmittedIL/Inlining/Regression_TLR_MutualInnerRec_CapturedEnv.fs.RealInternalSignatureOn.il.bsl new file mode 100644 index 00000000000..9dc10e0e9cb --- /dev/null +++ b/tests/FSharp.Compiler.ComponentTests/EmittedIL/Inlining/Regression_TLR_MutualInnerRec_CapturedEnv.fs.RealInternalSignatureOn.il.bsl @@ -0,0 +1,166 @@ + + + + + +.assembly extern runtime { } +.assembly extern FSharp.Core { } +.assembly assembly +{ + .custom instance void [FSharp.Core]Microsoft.FSharp.Core.FSharpInterfaceDataVersionAttribute::.ctor(int32, + int32, + int32) = ( 01 00 02 00 00 00 00 00 00 00 00 00 00 00 00 00 ) + + + + + .hash algorithm 0x00008004 + .ver 0:0:0:0 +} +.module assembly.exe + +.imagebase {value} +.file alignment 0x00000200 +.stackreserve 0x00100000 +.subsystem 0x0003 +.corflags 0x00000001 + + + + + +.class public abstract auto ansi sealed assembly + extends [runtime]System.Object +{ + .custom instance void [FSharp.Core]Microsoft.FSharp.Core.CompilationMappingAttribute::.ctor(valuetype [FSharp.Core]Microsoft.FSharp.Core.SourceConstructFlags) = ( 01 00 07 00 00 00 00 00 ) + .method public static int32 outer(int32 threshold, + int32 factor) cil managed + { + .custom instance void [FSharp.Core]Microsoft.FSharp.Core.CompilationArgumentCountsAttribute::.ctor(int32[]) = ( 01 00 02 00 00 00 01 00 00 00 01 00 00 00 00 00 ) + + .maxstack 5 + .locals init (int32 V_0, + int32 V_1) + IL_0000: ldarg.0 + IL_0001: stloc.0 + IL_0002: ldarg.1 + IL_0003: stloc.1 + IL_0004: ldarg.0 + IL_0005: ldarg.1 + IL_0006: ldc.i4.s 100 + IL_0008: tail. + IL_000a: call int32 assembly::a@4(int32, + int32, + int32) + IL_000f: ret + } + + .method public static int32 main(string[] _argv) cil managed + { + .entrypoint + .custom instance void [FSharp.Core]Microsoft.FSharp.Core.EntryPointAttribute::.ctor() = ( 01 00 00 00 ) + + .maxstack 8 + IL_0000: ldc.i4.7 + IL_0001: ldc.i4.1 + IL_0002: tail. + IL_0004: call int32 assembly::outer(int32, + int32) + IL_0009: ret + } + + .method assembly static int32 a@4(int32 threshold, + int32 factor, + int32 n) cil managed + { + + .maxstack 8 + IL_0000: nop + IL_0001: ldarg.2 + IL_0002: brtrue.s IL_0006 + + IL_0004: ldarg.0 + IL_0005: ret + + IL_0006: nop + IL_0007: ldarg.2 + IL_0008: ldc.i4.2 + IL_0009: rem + IL_000a: brtrue.s IL_0019 + + IL_000c: ldarg.0 + IL_000d: ldarg.1 + IL_000e: ldarg.2 + IL_000f: ldc.i4.1 + IL_0010: sub + IL_0011: tail. + IL_0013: call int32 assembly::b@8(int32, + int32, + int32) + IL_0018: ret + + IL_0019: ldarg.0 + IL_001a: ldarg.1 + IL_001b: ldarg.2 + IL_001c: ldarg.1 + IL_001d: sub + IL_001e: starg.s n + IL_0020: starg.s factor + IL_0022: starg.s threshold + IL_0024: br.s IL_0000 + } + + .method assembly static int32 b@8(int32 threshold, + int32 factor, + int32 n) cil managed + { + + .maxstack 8 + IL_0000: nop + IL_0001: ldarg.2 + IL_0002: brtrue.s IL_0008 + + IL_0004: ldarg.0 + IL_0005: ldc.i4.1 + IL_0006: add + IL_0007: ret + + IL_0008: nop + IL_0009: ldarg.2 + IL_000a: ldc.i4.2 + IL_000b: rem + IL_000c: brtrue.s IL_001b + + IL_000e: ldarg.0 + IL_000f: ldarg.1 + IL_0010: ldarg.2 + IL_0011: ldarg.1 + IL_0012: sub + IL_0013: starg.s n + IL_0015: starg.s factor + IL_0017: starg.s threshold + IL_0019: br.s IL_0000 + + IL_001b: ldarg.0 + IL_001c: ldarg.1 + IL_001d: ldarg.2 + IL_001e: ldc.i4.1 + IL_001f: sub + IL_0020: tail. + IL_0022: call int32 assembly::a@4(int32, + int32, + int32) + IL_0027: ret + } + +} + +.class private abstract auto ansi sealed ''.$assembly + extends [runtime]System.Object +{ +} + + + + + diff --git a/tests/FSharp.Compiler.ComponentTests/EmittedIL/Inlining/Regression_TLR_MutualInnerRec_Generic.fs b/tests/FSharp.Compiler.ComponentTests/EmittedIL/Inlining/Regression_TLR_MutualInnerRec_Generic.fs new file mode 100644 index 00000000000..f1895ba465c --- /dev/null +++ b/tests/FSharp.Compiler.ComponentTests/EmittedIL/Inlining/Regression_TLR_MutualInnerRec_Generic.fs @@ -0,0 +1,16 @@ +module Regression_TLR_MutualInnerRec_Generic + +let outer<'T> (initial: 'T) (zero: 'T) = + let rec a(n, v: 'T) = + if n = 0 then v + elif n % 2 = 0 then b(n - 1, v) + else a(n - 1, v) + and b(n, v: 'T) = + if n = 0 then zero + elif n % 2 = 0 then b(n - 1, v) + else a(n - 1, v) + a(1000, initial) + +[] +let main _argv = + if outer 1 0 = 1 then 0 else 1 diff --git a/tests/FSharp.Compiler.ComponentTests/EmittedIL/Inlining/Regression_TLR_MutualInnerRec_Generic.fs.RealInternalSignatureOff.il.bsl b/tests/FSharp.Compiler.ComponentTests/EmittedIL/Inlining/Regression_TLR_MutualInnerRec_Generic.fs.RealInternalSignatureOff.il.bsl new file mode 100644 index 00000000000..7f866e6e4b4 --- /dev/null +++ b/tests/FSharp.Compiler.ComponentTests/EmittedIL/Inlining/Regression_TLR_MutualInnerRec_Generic.fs.RealInternalSignatureOff.il.bsl @@ -0,0 +1,168 @@ + + + + + +.assembly extern runtime { } +.assembly extern FSharp.Core { } +.assembly assembly +{ + .custom instance void [FSharp.Core]Microsoft.FSharp.Core.FSharpInterfaceDataVersionAttribute::.ctor(int32, + int32, + int32) = ( 01 00 02 00 00 00 00 00 00 00 00 00 00 00 00 00 ) + + + + + .hash algorithm 0x00008004 + .ver 0:0:0:0 +} +.module assembly.exe + +.imagebase {value} +.file alignment 0x00000200 +.stackreserve 0x00100000 +.subsystem 0x0003 +.corflags 0x00000001 + + + + + +.class public abstract auto ansi sealed assembly + extends [runtime]System.Object +{ + .custom instance void [FSharp.Core]Microsoft.FSharp.Core.CompilationMappingAttribute::.ctor(valuetype [FSharp.Core]Microsoft.FSharp.Core.SourceConstructFlags) = ( 01 00 07 00 00 00 00 00 ) + .method public static !!T outer(!!T initial, + !!T zero) cil managed + { + .custom instance void [FSharp.Core]Microsoft.FSharp.Core.CompilationArgumentCountsAttribute::.ctor(int32[]) = ( 01 00 02 00 00 00 01 00 00 00 01 00 00 00 00 00 ) + + .maxstack 5 + .locals init (!!T V_0) + IL_0000: ldarg.1 + IL_0001: stloc.0 + IL_0002: ldarg.1 + IL_0003: ldc.i4 0x3e8 + IL_0008: ldarg.0 + IL_0009: tail. + IL_000b: call !!0 assembly::a@4(!!0, + int32, + !!0) + IL_0010: ret + } + + .method public static int32 main(string[] _argv) cil managed + { + .entrypoint + .custom instance void [FSharp.Core]Microsoft.FSharp.Core.EntryPointAttribute::.ctor() = ( 01 00 00 00 ) + + .maxstack 8 + IL_0000: nop + IL_0001: ldc.i4.1 + IL_0002: ldc.i4.0 + IL_0003: call !!0 assembly::outer(!!0, + !!0) + IL_0008: ldc.i4.1 + IL_0009: bne.un.s IL_000d + + IL_000b: ldc.i4.0 + IL_000c: ret + + IL_000d: ldc.i4.1 + IL_000e: ret + } + + .method assembly static !!T a@4(!!T zero, + int32 n, + !!T v) cil managed + { + + .maxstack 8 + IL_0000: nop + IL_0001: ldarg.1 + IL_0002: brtrue.s IL_0006 + + IL_0004: ldarg.2 + IL_0005: ret + + IL_0006: nop + IL_0007: ldarg.1 + IL_0008: ldc.i4.2 + IL_0009: rem + IL_000a: brtrue.s IL_0019 + + IL_000c: ldarg.0 + IL_000d: ldarg.1 + IL_000e: ldc.i4.1 + IL_000f: sub + IL_0010: ldarg.2 + IL_0011: tail. + IL_0013: call !!0 assembly::b@8(!!0, + int32, + !!0) + IL_0018: ret + + IL_0019: ldarg.0 + IL_001a: ldarg.1 + IL_001b: ldc.i4.1 + IL_001c: sub + IL_001d: ldarg.2 + IL_001e: starg.s v + IL_0020: starg.s n + IL_0022: starg.s zero + IL_0024: br.s IL_0000 + } + + .method assembly static !!T b@8(!!T zero, + int32 n, + !!T v) cil managed + { + + .maxstack 8 + IL_0000: nop + IL_0001: ldarg.1 + IL_0002: brtrue.s IL_0006 + + IL_0004: ldarg.0 + IL_0005: ret + + IL_0006: nop + IL_0007: ldarg.1 + IL_0008: ldc.i4.2 + IL_0009: rem + IL_000a: brtrue.s IL_0019 + + IL_000c: ldarg.0 + IL_000d: ldarg.1 + IL_000e: ldc.i4.1 + IL_000f: sub + IL_0010: ldarg.2 + IL_0011: starg.s v + IL_0013: starg.s n + IL_0015: starg.s zero + IL_0017: br.s IL_0000 + + IL_0019: ldarg.0 + IL_001a: ldarg.1 + IL_001b: ldc.i4.1 + IL_001c: sub + IL_001d: ldarg.2 + IL_001e: tail. + IL_0020: call !!0 assembly::a@4(!!0, + int32, + !!0) + IL_0025: ret + } + +} + +.class private abstract auto ansi sealed ''.$assembly + extends [runtime]System.Object +{ +} + + + + + diff --git a/tests/FSharp.Compiler.ComponentTests/EmittedIL/Inlining/Regression_TLR_MutualInnerRec_Generic.fs.RealInternalSignatureOn.il.bsl b/tests/FSharp.Compiler.ComponentTests/EmittedIL/Inlining/Regression_TLR_MutualInnerRec_Generic.fs.RealInternalSignatureOn.il.bsl new file mode 100644 index 00000000000..7f866e6e4b4 --- /dev/null +++ b/tests/FSharp.Compiler.ComponentTests/EmittedIL/Inlining/Regression_TLR_MutualInnerRec_Generic.fs.RealInternalSignatureOn.il.bsl @@ -0,0 +1,168 @@ + + + + + +.assembly extern runtime { } +.assembly extern FSharp.Core { } +.assembly assembly +{ + .custom instance void [FSharp.Core]Microsoft.FSharp.Core.FSharpInterfaceDataVersionAttribute::.ctor(int32, + int32, + int32) = ( 01 00 02 00 00 00 00 00 00 00 00 00 00 00 00 00 ) + + + + + .hash algorithm 0x00008004 + .ver 0:0:0:0 +} +.module assembly.exe + +.imagebase {value} +.file alignment 0x00000200 +.stackreserve 0x00100000 +.subsystem 0x0003 +.corflags 0x00000001 + + + + + +.class public abstract auto ansi sealed assembly + extends [runtime]System.Object +{ + .custom instance void [FSharp.Core]Microsoft.FSharp.Core.CompilationMappingAttribute::.ctor(valuetype [FSharp.Core]Microsoft.FSharp.Core.SourceConstructFlags) = ( 01 00 07 00 00 00 00 00 ) + .method public static !!T outer(!!T initial, + !!T zero) cil managed + { + .custom instance void [FSharp.Core]Microsoft.FSharp.Core.CompilationArgumentCountsAttribute::.ctor(int32[]) = ( 01 00 02 00 00 00 01 00 00 00 01 00 00 00 00 00 ) + + .maxstack 5 + .locals init (!!T V_0) + IL_0000: ldarg.1 + IL_0001: stloc.0 + IL_0002: ldarg.1 + IL_0003: ldc.i4 0x3e8 + IL_0008: ldarg.0 + IL_0009: tail. + IL_000b: call !!0 assembly::a@4(!!0, + int32, + !!0) + IL_0010: ret + } + + .method public static int32 main(string[] _argv) cil managed + { + .entrypoint + .custom instance void [FSharp.Core]Microsoft.FSharp.Core.EntryPointAttribute::.ctor() = ( 01 00 00 00 ) + + .maxstack 8 + IL_0000: nop + IL_0001: ldc.i4.1 + IL_0002: ldc.i4.0 + IL_0003: call !!0 assembly::outer(!!0, + !!0) + IL_0008: ldc.i4.1 + IL_0009: bne.un.s IL_000d + + IL_000b: ldc.i4.0 + IL_000c: ret + + IL_000d: ldc.i4.1 + IL_000e: ret + } + + .method assembly static !!T a@4(!!T zero, + int32 n, + !!T v) cil managed + { + + .maxstack 8 + IL_0000: nop + IL_0001: ldarg.1 + IL_0002: brtrue.s IL_0006 + + IL_0004: ldarg.2 + IL_0005: ret + + IL_0006: nop + IL_0007: ldarg.1 + IL_0008: ldc.i4.2 + IL_0009: rem + IL_000a: brtrue.s IL_0019 + + IL_000c: ldarg.0 + IL_000d: ldarg.1 + IL_000e: ldc.i4.1 + IL_000f: sub + IL_0010: ldarg.2 + IL_0011: tail. + IL_0013: call !!0 assembly::b@8(!!0, + int32, + !!0) + IL_0018: ret + + IL_0019: ldarg.0 + IL_001a: ldarg.1 + IL_001b: ldc.i4.1 + IL_001c: sub + IL_001d: ldarg.2 + IL_001e: starg.s v + IL_0020: starg.s n + IL_0022: starg.s zero + IL_0024: br.s IL_0000 + } + + .method assembly static !!T b@8(!!T zero, + int32 n, + !!T v) cil managed + { + + .maxstack 8 + IL_0000: nop + IL_0001: ldarg.1 + IL_0002: brtrue.s IL_0006 + + IL_0004: ldarg.0 + IL_0005: ret + + IL_0006: nop + IL_0007: ldarg.1 + IL_0008: ldc.i4.2 + IL_0009: rem + IL_000a: brtrue.s IL_0019 + + IL_000c: ldarg.0 + IL_000d: ldarg.1 + IL_000e: ldc.i4.1 + IL_000f: sub + IL_0010: ldarg.2 + IL_0011: starg.s v + IL_0013: starg.s n + IL_0015: starg.s zero + IL_0017: br.s IL_0000 + + IL_0019: ldarg.0 + IL_001a: ldarg.1 + IL_001b: ldc.i4.1 + IL_001c: sub + IL_001d: ldarg.2 + IL_001e: tail. + IL_0020: call !!0 assembly::a@4(!!0, + int32, + !!0) + IL_0025: ret + } + +} + +.class private abstract auto ansi sealed ''.$assembly + extends [runtime]System.Object +{ +} + + + + + diff --git a/tests/FSharp.Compiler.ComponentTests/EmittedIL/Inlining/Regression_TLR_MutualInnerRec_Point2D.fs b/tests/FSharp.Compiler.ComponentTests/EmittedIL/Inlining/Regression_TLR_MutualInnerRec_Point2D.fs new file mode 100644 index 00000000000..d9c2e7ae00b --- /dev/null +++ b/tests/FSharp.Compiler.ComponentTests/EmittedIL/Inlining/Regression_TLR_MutualInnerRec_Point2D.fs @@ -0,0 +1,23 @@ +module Regression_TLR_MutualInnerRec_Point2D + +[] +type Point2D(x: double, y: double) = + member _.X = x + member _.Y = y + +let fifth() = + let rec firstCallee(n, a: Point2D, b: Point2D, c: Point2D, d: Point2D, e: Point2D) = + if a.X <> 10.0 then -100 + elif n = 0 then 100 + elif n % 2 = 0 then secondCallee(n - 1, a, b, c, d, e) + else firstCallee(n - 1, a, b, c, d, e) + and secondCallee(n, a: Point2D, b: Point2D, c: Point2D, d: Point2D, e: Point2D) = + if n = 0 then 101 + elif n % 2 = 0 then secondCallee(n - 1, a, b, c, d, e) + else firstCallee(n - 1, a, b, c, d, e) + let p = Point2D(10.0, 20.0) + let q = Point2D(30.0, 40.0) + firstCallee(1000000, p, q, p, q, p) + +[] +let main _argv = fifth () diff --git a/tests/FSharp.Compiler.ComponentTests/EmittedIL/Inlining/Regression_TLR_MutualInnerRec_Point2D.fs.RealInternalSignatureOff.il.bsl b/tests/FSharp.Compiler.ComponentTests/EmittedIL/Inlining/Regression_TLR_MutualInnerRec_Point2D.fs.RealInternalSignatureOff.il.bsl new file mode 100644 index 00000000000..9e9d30977fe --- /dev/null +++ b/tests/FSharp.Compiler.ComponentTests/EmittedIL/Inlining/Regression_TLR_MutualInnerRec_Point2D.fs.RealInternalSignatureOff.il.bsl @@ -0,0 +1,687 @@ + + + + + +.assembly extern runtime { } +.assembly extern FSharp.Core { } +.assembly assembly +{ + .custom instance void [FSharp.Core]Microsoft.FSharp.Core.FSharpInterfaceDataVersionAttribute::.ctor(int32, + int32, + int32) = ( 01 00 02 00 00 00 00 00 00 00 00 00 00 00 00 00 ) + + + + + .hash algorithm 0x00008004 + .ver 0:0:0:0 +} +.module assembly.exe + +.imagebase {value} +.file alignment 0x00000200 +.stackreserve 0x00100000 +.subsystem 0x0003 +.corflags 0x00000001 + + + + + +.class public abstract auto ansi sealed assembly + extends [runtime]System.Object +{ + .custom instance void [FSharp.Core]Microsoft.FSharp.Core.CompilationMappingAttribute::.ctor(valuetype [FSharp.Core]Microsoft.FSharp.Core.SourceConstructFlags) = ( 01 00 07 00 00 00 00 00 ) + .class sequential ansi serializable sealed nested public Point2D + extends [runtime]System.ValueType + implements class [runtime]System.IEquatable`1, + [runtime]System.Collections.IStructuralEquatable, + class [runtime]System.IComparable`1, + [runtime]System.IComparable, + [runtime]System.Collections.IStructuralComparable + { + .custom instance void [FSharp.Core]Microsoft.FSharp.Core.StructAttribute::.ctor() = ( 01 00 00 00 ) + .custom instance void [FSharp.Core]Microsoft.FSharp.Core.CompilationMappingAttribute::.ctor(valuetype [FSharp.Core]Microsoft.FSharp.Core.SourceConstructFlags) = ( 01 00 03 00 00 00 00 00 ) + .field assembly float64 x + .field assembly float64 y + .method public hidebysig virtual final instance int32 CompareTo(valuetype assembly/Point2D obj) cil managed + { + .custom instance void [runtime]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) + + .maxstack 5 + .locals init (int32 V_0, + class [runtime]System.Collections.IComparer V_1, + float64 V_2, + float64 V_3) + IL_0000: call class [runtime]System.Collections.IComparer [FSharp.Core]Microsoft.FSharp.Core.LanguagePrimitives::get_GenericComparer() + IL_0005: stloc.1 + IL_0006: ldarg.0 + IL_0007: ldfld float64 assembly/Point2D::x + IL_000c: stloc.2 + IL_000d: ldarga.s obj + IL_000f: ldfld float64 assembly/Point2D::x + IL_0014: stloc.3 + IL_0015: ldloc.2 + IL_0016: ldloc.3 + IL_0017: clt + IL_0019: brfalse.s IL_001f + + IL_001b: ldc.i4.m1 + IL_001c: nop + IL_001d: br.s IL_003e + + IL_001f: ldloc.2 + IL_0020: ldloc.3 + IL_0021: cgt + IL_0023: brfalse.s IL_0029 + + IL_0025: ldc.i4.1 + IL_0026: nop + IL_0027: br.s IL_003e + + IL_0029: ldloc.2 + IL_002a: ldloc.3 + IL_002b: ceq + IL_002d: brfalse.s IL_0033 + + IL_002f: ldc.i4.0 + IL_0030: nop + IL_0031: br.s IL_003e + + IL_0033: ldloc.1 + IL_0034: ldloc.2 + IL_0035: ldloc.3 + IL_0036: call int32 [FSharp.Core]Microsoft.FSharp.Core.LanguagePrimitives/HashCompare::GenericComparisonWithComparerIntrinsic(class [runtime]System.Collections.IComparer, + !!0, + !!0) + IL_003b: nop + IL_003c: br.s IL_003e + + IL_003e: stloc.0 + IL_003f: ldloc.0 + IL_0040: ldc.i4.0 + IL_0041: bge.s IL_0045 + + IL_0043: ldloc.0 + IL_0044: ret + + IL_0045: ldloc.0 + IL_0046: ldc.i4.0 + IL_0047: ble.s IL_004b + + IL_0049: ldloc.0 + IL_004a: ret + + IL_004b: call class [runtime]System.Collections.IComparer [FSharp.Core]Microsoft.FSharp.Core.LanguagePrimitives::get_GenericComparer() + IL_0050: stloc.1 + IL_0051: ldarg.0 + IL_0052: ldfld float64 assembly/Point2D::y + IL_0057: stloc.2 + IL_0058: ldarga.s obj + IL_005a: ldfld float64 assembly/Point2D::y + IL_005f: stloc.3 + IL_0060: ldloc.2 + IL_0061: ldloc.3 + IL_0062: clt + IL_0064: brfalse.s IL_0068 + + IL_0066: ldc.i4.m1 + IL_0067: ret + + IL_0068: ldloc.2 + IL_0069: ldloc.3 + IL_006a: cgt + IL_006c: brfalse.s IL_0070 + + IL_006e: ldc.i4.1 + IL_006f: ret + + IL_0070: ldloc.2 + IL_0071: ldloc.3 + IL_0072: ceq + IL_0074: brfalse.s IL_0078 + + IL_0076: ldc.i4.0 + IL_0077: ret + + IL_0078: ldloc.1 + IL_0079: ldloc.2 + IL_007a: ldloc.3 + IL_007b: tail. + IL_007d: call int32 [FSharp.Core]Microsoft.FSharp.Core.LanguagePrimitives/HashCompare::GenericComparisonWithComparerIntrinsic(class [runtime]System.Collections.IComparer, + !!0, + !!0) + IL_0082: ret + } + + .method public hidebysig virtual final instance int32 CompareTo(object obj) cil managed + { + .custom instance void [runtime]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) + + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: ldarg.1 + IL_0002: unbox.any assembly/Point2D + IL_0007: call instance int32 assembly/Point2D::CompareTo(valuetype assembly/Point2D) + IL_000c: ret + } + + .method public hidebysig virtual final instance int32 CompareTo(object obj, class [runtime]System.Collections.IComparer comp) cil managed + { + .custom instance void [runtime]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) + + .maxstack 5 + .locals init (valuetype assembly/Point2D V_0, + int32 V_1, + float64 V_2, + float64 V_3) + IL_0000: ldarg.1 + IL_0001: unbox.any assembly/Point2D + IL_0006: stloc.0 + IL_0007: ldarg.0 + IL_0008: ldfld float64 assembly/Point2D::x + IL_000d: stloc.2 + IL_000e: ldloca.s V_0 + IL_0010: ldfld float64 assembly/Point2D::x + IL_0015: stloc.3 + IL_0016: ldloc.2 + IL_0017: ldloc.3 + IL_0018: clt + IL_001a: brfalse.s IL_0020 + + IL_001c: ldc.i4.m1 + IL_001d: nop + IL_001e: br.s IL_003f + + IL_0020: ldloc.2 + IL_0021: ldloc.3 + IL_0022: cgt + IL_0024: brfalse.s IL_002a + + IL_0026: ldc.i4.1 + IL_0027: nop + IL_0028: br.s IL_003f + + IL_002a: ldloc.2 + IL_002b: ldloc.3 + IL_002c: ceq + IL_002e: brfalse.s IL_0034 + + IL_0030: ldc.i4.0 + IL_0031: nop + IL_0032: br.s IL_003f + + IL_0034: ldarg.2 + IL_0035: ldloc.2 + IL_0036: ldloc.3 + IL_0037: call int32 [FSharp.Core]Microsoft.FSharp.Core.LanguagePrimitives/HashCompare::GenericComparisonWithComparerIntrinsic(class [runtime]System.Collections.IComparer, + !!0, + !!0) + IL_003c: nop + IL_003d: br.s IL_003f + + IL_003f: stloc.1 + IL_0040: ldloc.1 + IL_0041: ldc.i4.0 + IL_0042: bge.s IL_0046 + + IL_0044: ldloc.1 + IL_0045: ret + + IL_0046: ldloc.1 + IL_0047: ldc.i4.0 + IL_0048: ble.s IL_004c + + IL_004a: ldloc.1 + IL_004b: ret + + IL_004c: ldarg.0 + IL_004d: ldfld float64 assembly/Point2D::y + IL_0052: stloc.2 + IL_0053: ldloca.s V_0 + IL_0055: ldfld float64 assembly/Point2D::y + IL_005a: stloc.3 + IL_005b: ldloc.2 + IL_005c: ldloc.3 + IL_005d: clt + IL_005f: brfalse.s IL_0063 + + IL_0061: ldc.i4.m1 + IL_0062: ret + + IL_0063: ldloc.2 + IL_0064: ldloc.3 + IL_0065: cgt + IL_0067: brfalse.s IL_006b + + IL_0069: ldc.i4.1 + IL_006a: ret + + IL_006b: ldloc.2 + IL_006c: ldloc.3 + IL_006d: ceq + IL_006f: brfalse.s IL_0073 + + IL_0071: ldc.i4.0 + IL_0072: ret + + IL_0073: ldarg.2 + IL_0074: ldloc.2 + IL_0075: ldloc.3 + IL_0076: tail. + IL_0078: call int32 [FSharp.Core]Microsoft.FSharp.Core.LanguagePrimitives/HashCompare::GenericComparisonWithComparerIntrinsic(class [runtime]System.Collections.IComparer, + !!0, + !!0) + IL_007d: ret + } + + .method public hidebysig virtual final instance int32 GetHashCode(class [runtime]System.Collections.IEqualityComparer comp) cil managed + { + .custom instance void [runtime]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) + + .maxstack 7 + .locals init (int32 V_0) + IL_0000: ldc.i4.0 + IL_0001: stloc.0 + IL_0002: ldc.i4 0x9e3779b9 + IL_0007: ldarg.1 + IL_0008: ldarg.0 + IL_0009: ldfld float64 assembly/Point2D::y + IL_000e: call int32 [FSharp.Core]Microsoft.FSharp.Core.LanguagePrimitives/HashCompare::GenericHashWithComparerIntrinsic(class [runtime]System.Collections.IEqualityComparer, + !!0) + IL_0013: ldloc.0 + IL_0014: ldc.i4.6 + IL_0015: shl + IL_0016: ldloc.0 + IL_0017: ldc.i4.2 + IL_0018: shr + IL_0019: add + IL_001a: add + IL_001b: add + IL_001c: stloc.0 + IL_001d: ldc.i4 0x9e3779b9 + IL_0022: ldarg.1 + IL_0023: ldarg.0 + IL_0024: ldfld float64 assembly/Point2D::x + IL_0029: call int32 [FSharp.Core]Microsoft.FSharp.Core.LanguagePrimitives/HashCompare::GenericHashWithComparerIntrinsic(class [runtime]System.Collections.IEqualityComparer, + !!0) + IL_002e: ldloc.0 + IL_002f: ldc.i4.6 + IL_0030: shl + IL_0031: ldloc.0 + IL_0032: ldc.i4.2 + IL_0033: shr + IL_0034: add + IL_0035: add + IL_0036: add + IL_0037: stloc.0 + IL_0038: ldloc.0 + IL_0039: ret + } + + .method public hidebysig virtual final instance int32 GetHashCode() cil managed + { + .custom instance void [runtime]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) + + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: call class [runtime]System.Collections.IEqualityComparer [FSharp.Core]Microsoft.FSharp.Core.LanguagePrimitives::get_GenericEqualityComparer() + IL_0006: call instance int32 assembly/Point2D::GetHashCode(class [runtime]System.Collections.IEqualityComparer) + IL_000b: ret + } + + .method public hidebysig instance bool Equals(valuetype assembly/Point2D obj, class [runtime]System.Collections.IEqualityComparer comp) cil managed + { + .custom instance void [runtime]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) + + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: ldfld float64 assembly/Point2D::x + IL_0006: ldarga.s obj + IL_0008: ldfld float64 assembly/Point2D::x + IL_000d: ceq + IL_000f: brfalse.s IL_0021 + + IL_0011: ldarg.0 + IL_0012: ldfld float64 assembly/Point2D::y + IL_0017: ldarga.s obj + IL_0019: ldfld float64 assembly/Point2D::y + IL_001e: ceq + IL_0020: ret + + IL_0021: ldc.i4.0 + IL_0022: ret + } + + .method public hidebysig virtual final instance bool Equals(object obj, class [runtime]System.Collections.IEqualityComparer comp) cil managed + { + .custom instance void [runtime]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) + + .maxstack 5 + .locals init (valuetype assembly/Point2D V_0) + IL_0000: ldarg.1 + IL_0001: isinst assembly/Point2D + IL_0006: brfalse.s IL_0018 + + IL_0008: ldarg.1 + IL_0009: unbox.any assembly/Point2D + IL_000e: stloc.0 + IL_000f: ldarg.0 + IL_0010: ldloc.0 + IL_0011: ldarg.2 + IL_0012: call instance bool assembly/Point2D::Equals(valuetype assembly/Point2D, + class [runtime]System.Collections.IEqualityComparer) + IL_0017: ret + + IL_0018: ldc.i4.0 + IL_0019: ret + } + + .method public specialname rtspecialname instance void .ctor(float64 x, float64 y) cil managed + { + + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: ldarg.1 + IL_0002: stfld float64 assembly/Point2D::x + IL_0007: ldarg.0 + IL_0008: ldarg.2 + IL_0009: stfld float64 assembly/Point2D::y + IL_000e: ret + } + + .method public hidebysig specialname instance float64 get_X() cil managed + { + + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: ldfld float64 assembly/Point2D::x + IL_0006: ret + } + + .method public hidebysig specialname instance float64 get_Y() cil managed + { + + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: ldfld float64 assembly/Point2D::y + IL_0006: ret + } + + .method public hidebysig virtual final instance bool Equals(valuetype assembly/Point2D obj) cil managed + { + .custom instance void [runtime]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) + + .maxstack 4 + .locals init (float64 V_0, + float64 V_1) + IL_0000: ldarg.0 + IL_0001: ldfld float64 assembly/Point2D::x + IL_0006: stloc.0 + IL_0007: ldarga.s obj + IL_0009: ldfld float64 assembly/Point2D::x + IL_000e: stloc.1 + IL_000f: ldloc.0 + IL_0010: ldloc.1 + IL_0011: ceq + IL_0013: brfalse.s IL_0019 + + IL_0015: ldc.i4.1 + IL_0016: nop + IL_0017: br.s IL_002b + + IL_0019: ldloc.0 + IL_001a: ldloc.0 + IL_001b: beq.s IL_0027 + + IL_001d: ldloc.1 + IL_001e: ldloc.1 + IL_001f: ceq + IL_0021: ldc.i4.0 + IL_0022: ceq + IL_0024: nop + IL_0025: br.s IL_002b + + IL_0027: ldc.i4.0 + IL_0028: nop + IL_0029: br.s IL_002b + + IL_002b: brfalse.s IL_0052 + + IL_002d: ldarg.0 + IL_002e: ldfld float64 assembly/Point2D::y + IL_0033: stloc.0 + IL_0034: ldarga.s obj + IL_0036: ldfld float64 assembly/Point2D::y + IL_003b: stloc.1 + IL_003c: ldloc.0 + IL_003d: ldloc.1 + IL_003e: ceq + IL_0040: brfalse.s IL_0044 + + IL_0042: ldc.i4.1 + IL_0043: ret + + IL_0044: ldloc.0 + IL_0045: ldloc.0 + IL_0046: beq.s IL_0050 + + IL_0048: ldloc.1 + IL_0049: ldloc.1 + IL_004a: ceq + IL_004c: ldc.i4.0 + IL_004d: ceq + IL_004f: ret + + IL_0050: ldc.i4.0 + IL_0051: ret + + IL_0052: ldc.i4.0 + IL_0053: ret + } + + .method public hidebysig virtual final instance bool Equals(object obj) cil managed + { + .custom instance void [runtime]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) + + .maxstack 8 + IL_0000: ldarg.1 + IL_0001: isinst assembly/Point2D + IL_0006: brfalse.s IL_0015 + + IL_0008: ldarg.0 + IL_0009: ldarg.1 + IL_000a: unbox.any assembly/Point2D + IL_000f: call instance bool assembly/Point2D::Equals(valuetype assembly/Point2D) + IL_0014: ret + + IL_0015: ldc.i4.0 + IL_0016: ret + } + + .property instance float64 X() + { + .get instance float64 assembly/Point2D::get_X() + } + .property instance float64 Y() + { + .get instance float64 assembly/Point2D::get_Y() + } + } + + .method public static int32 fifth() cil managed + { + + .maxstack 8 + .locals init (valuetype assembly/Point2D V_0, + valuetype assembly/Point2D V_1) + IL_0000: ldc.r8 10 + IL_0009: ldc.r8 20 + IL_0012: newobj instance void assembly/Point2D::.ctor(float64, + float64) + IL_0017: stloc.0 + IL_0018: ldc.r8 30 + IL_0021: ldc.r8 40 + IL_002a: newobj instance void assembly/Point2D::.ctor(float64, + float64) + IL_002f: stloc.1 + IL_0030: ldc.i4 0xf4240 + IL_0035: ldloc.0 + IL_0036: ldloc.1 + IL_0037: ldloc.0 + IL_0038: ldloc.1 + IL_0039: ldloc.0 + IL_003a: tail. + IL_003c: call int32 assembly::firstCallee@9(int32, + valuetype assembly/Point2D, + valuetype assembly/Point2D, + valuetype assembly/Point2D, + valuetype assembly/Point2D, + valuetype assembly/Point2D) + IL_0041: ret + } + + .method public static int32 main(string[] _argv) cil managed + { + .entrypoint + .custom instance void [FSharp.Core]Microsoft.FSharp.Core.EntryPointAttribute::.ctor() = ( 01 00 00 00 ) + + .maxstack 8 + IL_0000: tail. + IL_0002: call int32 assembly::fifth() + IL_0007: ret + } + + .method assembly static int32 firstCallee@9(int32 n, + valuetype assembly/Point2D a, + valuetype assembly/Point2D b, + valuetype assembly/Point2D c, + valuetype assembly/Point2D d, + valuetype assembly/Point2D e) cil managed + { + + .maxstack 8 + IL_0000: nop + IL_0001: ldarga.s a + IL_0003: ldfld float64 assembly/Point2D::x + IL_0008: ldc.r8 10 + IL_0011: beq.s IL_0016 + + IL_0013: ldc.i4.s -100 + IL_0015: ret + + IL_0016: nop + IL_0017: ldarg.0 + IL_0018: brtrue.s IL_001d + + IL_001a: ldc.i4.s 100 + IL_001c: ret + + IL_001d: nop + IL_001e: ldarg.0 + IL_001f: ldc.i4.2 + IL_0020: rem + IL_0021: brtrue.s IL_0035 + + IL_0023: ldarg.0 + IL_0024: ldc.i4.1 + IL_0025: sub + IL_0026: ldarg.1 + IL_0027: ldarg.2 + IL_0028: ldarg.3 + IL_0029: ldarg.s d + IL_002b: ldarg.s e + IL_002d: tail. + IL_002f: call int32 assembly::secondCallee@14(int32, + valuetype assembly/Point2D, + valuetype assembly/Point2D, + valuetype assembly/Point2D, + valuetype assembly/Point2D, + valuetype assembly/Point2D) + IL_0034: ret + + IL_0035: ldarg.0 + IL_0036: ldc.i4.1 + IL_0037: sub + IL_0038: ldarg.1 + IL_0039: ldarg.2 + IL_003a: ldarg.3 + IL_003b: ldarg.s d + IL_003d: ldarg.s e + IL_003f: starg.s e + IL_0041: starg.s d + IL_0043: starg.s c + IL_0045: starg.s b + IL_0047: starg.s a + IL_0049: starg.s n + IL_004b: br.s IL_0000 + } + + .method assembly static int32 secondCallee@14(int32 n, + valuetype assembly/Point2D a, + valuetype assembly/Point2D b, + valuetype assembly/Point2D c, + valuetype assembly/Point2D d, + valuetype assembly/Point2D e) cil managed + { + + .maxstack 8 + IL_0000: nop + IL_0001: ldarg.0 + IL_0002: brtrue.s IL_0007 + + IL_0004: ldc.i4.s 101 + IL_0006: ret + + IL_0007: nop + IL_0008: ldarg.0 + IL_0009: ldc.i4.2 + IL_000a: rem + IL_000b: brtrue.s IL_0025 + + IL_000d: ldarg.0 + IL_000e: ldc.i4.1 + IL_000f: sub + IL_0010: ldarg.1 + IL_0011: ldarg.2 + IL_0012: ldarg.3 + IL_0013: ldarg.s d + IL_0015: ldarg.s e + IL_0017: starg.s e + IL_0019: starg.s d + IL_001b: starg.s c + IL_001d: starg.s b + IL_001f: starg.s a + IL_0021: starg.s n + IL_0023: br.s IL_0000 + + IL_0025: ldarg.0 + IL_0026: ldc.i4.1 + IL_0027: sub + IL_0028: ldarg.1 + IL_0029: ldarg.2 + IL_002a: ldarg.3 + IL_002b: ldarg.s d + IL_002d: ldarg.s e + IL_002f: tail. + IL_0031: call int32 assembly::firstCallee@9(int32, + valuetype assembly/Point2D, + valuetype assembly/Point2D, + valuetype assembly/Point2D, + valuetype assembly/Point2D, + valuetype assembly/Point2D) + IL_0036: ret + } + +} + +.class private abstract auto ansi sealed ''.$assembly + extends [runtime]System.Object +{ +} + + + + + diff --git a/tests/FSharp.Compiler.ComponentTests/EmittedIL/Inlining/Regression_TLR_MutualInnerRec_Point2D.fs.RealInternalSignatureOn.il.bsl b/tests/FSharp.Compiler.ComponentTests/EmittedIL/Inlining/Regression_TLR_MutualInnerRec_Point2D.fs.RealInternalSignatureOn.il.bsl new file mode 100644 index 00000000000..9e9d30977fe --- /dev/null +++ b/tests/FSharp.Compiler.ComponentTests/EmittedIL/Inlining/Regression_TLR_MutualInnerRec_Point2D.fs.RealInternalSignatureOn.il.bsl @@ -0,0 +1,687 @@ + + + + + +.assembly extern runtime { } +.assembly extern FSharp.Core { } +.assembly assembly +{ + .custom instance void [FSharp.Core]Microsoft.FSharp.Core.FSharpInterfaceDataVersionAttribute::.ctor(int32, + int32, + int32) = ( 01 00 02 00 00 00 00 00 00 00 00 00 00 00 00 00 ) + + + + + .hash algorithm 0x00008004 + .ver 0:0:0:0 +} +.module assembly.exe + +.imagebase {value} +.file alignment 0x00000200 +.stackreserve 0x00100000 +.subsystem 0x0003 +.corflags 0x00000001 + + + + + +.class public abstract auto ansi sealed assembly + extends [runtime]System.Object +{ + .custom instance void [FSharp.Core]Microsoft.FSharp.Core.CompilationMappingAttribute::.ctor(valuetype [FSharp.Core]Microsoft.FSharp.Core.SourceConstructFlags) = ( 01 00 07 00 00 00 00 00 ) + .class sequential ansi serializable sealed nested public Point2D + extends [runtime]System.ValueType + implements class [runtime]System.IEquatable`1, + [runtime]System.Collections.IStructuralEquatable, + class [runtime]System.IComparable`1, + [runtime]System.IComparable, + [runtime]System.Collections.IStructuralComparable + { + .custom instance void [FSharp.Core]Microsoft.FSharp.Core.StructAttribute::.ctor() = ( 01 00 00 00 ) + .custom instance void [FSharp.Core]Microsoft.FSharp.Core.CompilationMappingAttribute::.ctor(valuetype [FSharp.Core]Microsoft.FSharp.Core.SourceConstructFlags) = ( 01 00 03 00 00 00 00 00 ) + .field assembly float64 x + .field assembly float64 y + .method public hidebysig virtual final instance int32 CompareTo(valuetype assembly/Point2D obj) cil managed + { + .custom instance void [runtime]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) + + .maxstack 5 + .locals init (int32 V_0, + class [runtime]System.Collections.IComparer V_1, + float64 V_2, + float64 V_3) + IL_0000: call class [runtime]System.Collections.IComparer [FSharp.Core]Microsoft.FSharp.Core.LanguagePrimitives::get_GenericComparer() + IL_0005: stloc.1 + IL_0006: ldarg.0 + IL_0007: ldfld float64 assembly/Point2D::x + IL_000c: stloc.2 + IL_000d: ldarga.s obj + IL_000f: ldfld float64 assembly/Point2D::x + IL_0014: stloc.3 + IL_0015: ldloc.2 + IL_0016: ldloc.3 + IL_0017: clt + IL_0019: brfalse.s IL_001f + + IL_001b: ldc.i4.m1 + IL_001c: nop + IL_001d: br.s IL_003e + + IL_001f: ldloc.2 + IL_0020: ldloc.3 + IL_0021: cgt + IL_0023: brfalse.s IL_0029 + + IL_0025: ldc.i4.1 + IL_0026: nop + IL_0027: br.s IL_003e + + IL_0029: ldloc.2 + IL_002a: ldloc.3 + IL_002b: ceq + IL_002d: brfalse.s IL_0033 + + IL_002f: ldc.i4.0 + IL_0030: nop + IL_0031: br.s IL_003e + + IL_0033: ldloc.1 + IL_0034: ldloc.2 + IL_0035: ldloc.3 + IL_0036: call int32 [FSharp.Core]Microsoft.FSharp.Core.LanguagePrimitives/HashCompare::GenericComparisonWithComparerIntrinsic(class [runtime]System.Collections.IComparer, + !!0, + !!0) + IL_003b: nop + IL_003c: br.s IL_003e + + IL_003e: stloc.0 + IL_003f: ldloc.0 + IL_0040: ldc.i4.0 + IL_0041: bge.s IL_0045 + + IL_0043: ldloc.0 + IL_0044: ret + + IL_0045: ldloc.0 + IL_0046: ldc.i4.0 + IL_0047: ble.s IL_004b + + IL_0049: ldloc.0 + IL_004a: ret + + IL_004b: call class [runtime]System.Collections.IComparer [FSharp.Core]Microsoft.FSharp.Core.LanguagePrimitives::get_GenericComparer() + IL_0050: stloc.1 + IL_0051: ldarg.0 + IL_0052: ldfld float64 assembly/Point2D::y + IL_0057: stloc.2 + IL_0058: ldarga.s obj + IL_005a: ldfld float64 assembly/Point2D::y + IL_005f: stloc.3 + IL_0060: ldloc.2 + IL_0061: ldloc.3 + IL_0062: clt + IL_0064: brfalse.s IL_0068 + + IL_0066: ldc.i4.m1 + IL_0067: ret + + IL_0068: ldloc.2 + IL_0069: ldloc.3 + IL_006a: cgt + IL_006c: brfalse.s IL_0070 + + IL_006e: ldc.i4.1 + IL_006f: ret + + IL_0070: ldloc.2 + IL_0071: ldloc.3 + IL_0072: ceq + IL_0074: brfalse.s IL_0078 + + IL_0076: ldc.i4.0 + IL_0077: ret + + IL_0078: ldloc.1 + IL_0079: ldloc.2 + IL_007a: ldloc.3 + IL_007b: tail. + IL_007d: call int32 [FSharp.Core]Microsoft.FSharp.Core.LanguagePrimitives/HashCompare::GenericComparisonWithComparerIntrinsic(class [runtime]System.Collections.IComparer, + !!0, + !!0) + IL_0082: ret + } + + .method public hidebysig virtual final instance int32 CompareTo(object obj) cil managed + { + .custom instance void [runtime]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) + + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: ldarg.1 + IL_0002: unbox.any assembly/Point2D + IL_0007: call instance int32 assembly/Point2D::CompareTo(valuetype assembly/Point2D) + IL_000c: ret + } + + .method public hidebysig virtual final instance int32 CompareTo(object obj, class [runtime]System.Collections.IComparer comp) cil managed + { + .custom instance void [runtime]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) + + .maxstack 5 + .locals init (valuetype assembly/Point2D V_0, + int32 V_1, + float64 V_2, + float64 V_3) + IL_0000: ldarg.1 + IL_0001: unbox.any assembly/Point2D + IL_0006: stloc.0 + IL_0007: ldarg.0 + IL_0008: ldfld float64 assembly/Point2D::x + IL_000d: stloc.2 + IL_000e: ldloca.s V_0 + IL_0010: ldfld float64 assembly/Point2D::x + IL_0015: stloc.3 + IL_0016: ldloc.2 + IL_0017: ldloc.3 + IL_0018: clt + IL_001a: brfalse.s IL_0020 + + IL_001c: ldc.i4.m1 + IL_001d: nop + IL_001e: br.s IL_003f + + IL_0020: ldloc.2 + IL_0021: ldloc.3 + IL_0022: cgt + IL_0024: brfalse.s IL_002a + + IL_0026: ldc.i4.1 + IL_0027: nop + IL_0028: br.s IL_003f + + IL_002a: ldloc.2 + IL_002b: ldloc.3 + IL_002c: ceq + IL_002e: brfalse.s IL_0034 + + IL_0030: ldc.i4.0 + IL_0031: nop + IL_0032: br.s IL_003f + + IL_0034: ldarg.2 + IL_0035: ldloc.2 + IL_0036: ldloc.3 + IL_0037: call int32 [FSharp.Core]Microsoft.FSharp.Core.LanguagePrimitives/HashCompare::GenericComparisonWithComparerIntrinsic(class [runtime]System.Collections.IComparer, + !!0, + !!0) + IL_003c: nop + IL_003d: br.s IL_003f + + IL_003f: stloc.1 + IL_0040: ldloc.1 + IL_0041: ldc.i4.0 + IL_0042: bge.s IL_0046 + + IL_0044: ldloc.1 + IL_0045: ret + + IL_0046: ldloc.1 + IL_0047: ldc.i4.0 + IL_0048: ble.s IL_004c + + IL_004a: ldloc.1 + IL_004b: ret + + IL_004c: ldarg.0 + IL_004d: ldfld float64 assembly/Point2D::y + IL_0052: stloc.2 + IL_0053: ldloca.s V_0 + IL_0055: ldfld float64 assembly/Point2D::y + IL_005a: stloc.3 + IL_005b: ldloc.2 + IL_005c: ldloc.3 + IL_005d: clt + IL_005f: brfalse.s IL_0063 + + IL_0061: ldc.i4.m1 + IL_0062: ret + + IL_0063: ldloc.2 + IL_0064: ldloc.3 + IL_0065: cgt + IL_0067: brfalse.s IL_006b + + IL_0069: ldc.i4.1 + IL_006a: ret + + IL_006b: ldloc.2 + IL_006c: ldloc.3 + IL_006d: ceq + IL_006f: brfalse.s IL_0073 + + IL_0071: ldc.i4.0 + IL_0072: ret + + IL_0073: ldarg.2 + IL_0074: ldloc.2 + IL_0075: ldloc.3 + IL_0076: tail. + IL_0078: call int32 [FSharp.Core]Microsoft.FSharp.Core.LanguagePrimitives/HashCompare::GenericComparisonWithComparerIntrinsic(class [runtime]System.Collections.IComparer, + !!0, + !!0) + IL_007d: ret + } + + .method public hidebysig virtual final instance int32 GetHashCode(class [runtime]System.Collections.IEqualityComparer comp) cil managed + { + .custom instance void [runtime]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) + + .maxstack 7 + .locals init (int32 V_0) + IL_0000: ldc.i4.0 + IL_0001: stloc.0 + IL_0002: ldc.i4 0x9e3779b9 + IL_0007: ldarg.1 + IL_0008: ldarg.0 + IL_0009: ldfld float64 assembly/Point2D::y + IL_000e: call int32 [FSharp.Core]Microsoft.FSharp.Core.LanguagePrimitives/HashCompare::GenericHashWithComparerIntrinsic(class [runtime]System.Collections.IEqualityComparer, + !!0) + IL_0013: ldloc.0 + IL_0014: ldc.i4.6 + IL_0015: shl + IL_0016: ldloc.0 + IL_0017: ldc.i4.2 + IL_0018: shr + IL_0019: add + IL_001a: add + IL_001b: add + IL_001c: stloc.0 + IL_001d: ldc.i4 0x9e3779b9 + IL_0022: ldarg.1 + IL_0023: ldarg.0 + IL_0024: ldfld float64 assembly/Point2D::x + IL_0029: call int32 [FSharp.Core]Microsoft.FSharp.Core.LanguagePrimitives/HashCompare::GenericHashWithComparerIntrinsic(class [runtime]System.Collections.IEqualityComparer, + !!0) + IL_002e: ldloc.0 + IL_002f: ldc.i4.6 + IL_0030: shl + IL_0031: ldloc.0 + IL_0032: ldc.i4.2 + IL_0033: shr + IL_0034: add + IL_0035: add + IL_0036: add + IL_0037: stloc.0 + IL_0038: ldloc.0 + IL_0039: ret + } + + .method public hidebysig virtual final instance int32 GetHashCode() cil managed + { + .custom instance void [runtime]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) + + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: call class [runtime]System.Collections.IEqualityComparer [FSharp.Core]Microsoft.FSharp.Core.LanguagePrimitives::get_GenericEqualityComparer() + IL_0006: call instance int32 assembly/Point2D::GetHashCode(class [runtime]System.Collections.IEqualityComparer) + IL_000b: ret + } + + .method public hidebysig instance bool Equals(valuetype assembly/Point2D obj, class [runtime]System.Collections.IEqualityComparer comp) cil managed + { + .custom instance void [runtime]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) + + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: ldfld float64 assembly/Point2D::x + IL_0006: ldarga.s obj + IL_0008: ldfld float64 assembly/Point2D::x + IL_000d: ceq + IL_000f: brfalse.s IL_0021 + + IL_0011: ldarg.0 + IL_0012: ldfld float64 assembly/Point2D::y + IL_0017: ldarga.s obj + IL_0019: ldfld float64 assembly/Point2D::y + IL_001e: ceq + IL_0020: ret + + IL_0021: ldc.i4.0 + IL_0022: ret + } + + .method public hidebysig virtual final instance bool Equals(object obj, class [runtime]System.Collections.IEqualityComparer comp) cil managed + { + .custom instance void [runtime]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) + + .maxstack 5 + .locals init (valuetype assembly/Point2D V_0) + IL_0000: ldarg.1 + IL_0001: isinst assembly/Point2D + IL_0006: brfalse.s IL_0018 + + IL_0008: ldarg.1 + IL_0009: unbox.any assembly/Point2D + IL_000e: stloc.0 + IL_000f: ldarg.0 + IL_0010: ldloc.0 + IL_0011: ldarg.2 + IL_0012: call instance bool assembly/Point2D::Equals(valuetype assembly/Point2D, + class [runtime]System.Collections.IEqualityComparer) + IL_0017: ret + + IL_0018: ldc.i4.0 + IL_0019: ret + } + + .method public specialname rtspecialname instance void .ctor(float64 x, float64 y) cil managed + { + + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: ldarg.1 + IL_0002: stfld float64 assembly/Point2D::x + IL_0007: ldarg.0 + IL_0008: ldarg.2 + IL_0009: stfld float64 assembly/Point2D::y + IL_000e: ret + } + + .method public hidebysig specialname instance float64 get_X() cil managed + { + + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: ldfld float64 assembly/Point2D::x + IL_0006: ret + } + + .method public hidebysig specialname instance float64 get_Y() cil managed + { + + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: ldfld float64 assembly/Point2D::y + IL_0006: ret + } + + .method public hidebysig virtual final instance bool Equals(valuetype assembly/Point2D obj) cil managed + { + .custom instance void [runtime]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) + + .maxstack 4 + .locals init (float64 V_0, + float64 V_1) + IL_0000: ldarg.0 + IL_0001: ldfld float64 assembly/Point2D::x + IL_0006: stloc.0 + IL_0007: ldarga.s obj + IL_0009: ldfld float64 assembly/Point2D::x + IL_000e: stloc.1 + IL_000f: ldloc.0 + IL_0010: ldloc.1 + IL_0011: ceq + IL_0013: brfalse.s IL_0019 + + IL_0015: ldc.i4.1 + IL_0016: nop + IL_0017: br.s IL_002b + + IL_0019: ldloc.0 + IL_001a: ldloc.0 + IL_001b: beq.s IL_0027 + + IL_001d: ldloc.1 + IL_001e: ldloc.1 + IL_001f: ceq + IL_0021: ldc.i4.0 + IL_0022: ceq + IL_0024: nop + IL_0025: br.s IL_002b + + IL_0027: ldc.i4.0 + IL_0028: nop + IL_0029: br.s IL_002b + + IL_002b: brfalse.s IL_0052 + + IL_002d: ldarg.0 + IL_002e: ldfld float64 assembly/Point2D::y + IL_0033: stloc.0 + IL_0034: ldarga.s obj + IL_0036: ldfld float64 assembly/Point2D::y + IL_003b: stloc.1 + IL_003c: ldloc.0 + IL_003d: ldloc.1 + IL_003e: ceq + IL_0040: brfalse.s IL_0044 + + IL_0042: ldc.i4.1 + IL_0043: ret + + IL_0044: ldloc.0 + IL_0045: ldloc.0 + IL_0046: beq.s IL_0050 + + IL_0048: ldloc.1 + IL_0049: ldloc.1 + IL_004a: ceq + IL_004c: ldc.i4.0 + IL_004d: ceq + IL_004f: ret + + IL_0050: ldc.i4.0 + IL_0051: ret + + IL_0052: ldc.i4.0 + IL_0053: ret + } + + .method public hidebysig virtual final instance bool Equals(object obj) cil managed + { + .custom instance void [runtime]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) + + .maxstack 8 + IL_0000: ldarg.1 + IL_0001: isinst assembly/Point2D + IL_0006: brfalse.s IL_0015 + + IL_0008: ldarg.0 + IL_0009: ldarg.1 + IL_000a: unbox.any assembly/Point2D + IL_000f: call instance bool assembly/Point2D::Equals(valuetype assembly/Point2D) + IL_0014: ret + + IL_0015: ldc.i4.0 + IL_0016: ret + } + + .property instance float64 X() + { + .get instance float64 assembly/Point2D::get_X() + } + .property instance float64 Y() + { + .get instance float64 assembly/Point2D::get_Y() + } + } + + .method public static int32 fifth() cil managed + { + + .maxstack 8 + .locals init (valuetype assembly/Point2D V_0, + valuetype assembly/Point2D V_1) + IL_0000: ldc.r8 10 + IL_0009: ldc.r8 20 + IL_0012: newobj instance void assembly/Point2D::.ctor(float64, + float64) + IL_0017: stloc.0 + IL_0018: ldc.r8 30 + IL_0021: ldc.r8 40 + IL_002a: newobj instance void assembly/Point2D::.ctor(float64, + float64) + IL_002f: stloc.1 + IL_0030: ldc.i4 0xf4240 + IL_0035: ldloc.0 + IL_0036: ldloc.1 + IL_0037: ldloc.0 + IL_0038: ldloc.1 + IL_0039: ldloc.0 + IL_003a: tail. + IL_003c: call int32 assembly::firstCallee@9(int32, + valuetype assembly/Point2D, + valuetype assembly/Point2D, + valuetype assembly/Point2D, + valuetype assembly/Point2D, + valuetype assembly/Point2D) + IL_0041: ret + } + + .method public static int32 main(string[] _argv) cil managed + { + .entrypoint + .custom instance void [FSharp.Core]Microsoft.FSharp.Core.EntryPointAttribute::.ctor() = ( 01 00 00 00 ) + + .maxstack 8 + IL_0000: tail. + IL_0002: call int32 assembly::fifth() + IL_0007: ret + } + + .method assembly static int32 firstCallee@9(int32 n, + valuetype assembly/Point2D a, + valuetype assembly/Point2D b, + valuetype assembly/Point2D c, + valuetype assembly/Point2D d, + valuetype assembly/Point2D e) cil managed + { + + .maxstack 8 + IL_0000: nop + IL_0001: ldarga.s a + IL_0003: ldfld float64 assembly/Point2D::x + IL_0008: ldc.r8 10 + IL_0011: beq.s IL_0016 + + IL_0013: ldc.i4.s -100 + IL_0015: ret + + IL_0016: nop + IL_0017: ldarg.0 + IL_0018: brtrue.s IL_001d + + IL_001a: ldc.i4.s 100 + IL_001c: ret + + IL_001d: nop + IL_001e: ldarg.0 + IL_001f: ldc.i4.2 + IL_0020: rem + IL_0021: brtrue.s IL_0035 + + IL_0023: ldarg.0 + IL_0024: ldc.i4.1 + IL_0025: sub + IL_0026: ldarg.1 + IL_0027: ldarg.2 + IL_0028: ldarg.3 + IL_0029: ldarg.s d + IL_002b: ldarg.s e + IL_002d: tail. + IL_002f: call int32 assembly::secondCallee@14(int32, + valuetype assembly/Point2D, + valuetype assembly/Point2D, + valuetype assembly/Point2D, + valuetype assembly/Point2D, + valuetype assembly/Point2D) + IL_0034: ret + + IL_0035: ldarg.0 + IL_0036: ldc.i4.1 + IL_0037: sub + IL_0038: ldarg.1 + IL_0039: ldarg.2 + IL_003a: ldarg.3 + IL_003b: ldarg.s d + IL_003d: ldarg.s e + IL_003f: starg.s e + IL_0041: starg.s d + IL_0043: starg.s c + IL_0045: starg.s b + IL_0047: starg.s a + IL_0049: starg.s n + IL_004b: br.s IL_0000 + } + + .method assembly static int32 secondCallee@14(int32 n, + valuetype assembly/Point2D a, + valuetype assembly/Point2D b, + valuetype assembly/Point2D c, + valuetype assembly/Point2D d, + valuetype assembly/Point2D e) cil managed + { + + .maxstack 8 + IL_0000: nop + IL_0001: ldarg.0 + IL_0002: brtrue.s IL_0007 + + IL_0004: ldc.i4.s 101 + IL_0006: ret + + IL_0007: nop + IL_0008: ldarg.0 + IL_0009: ldc.i4.2 + IL_000a: rem + IL_000b: brtrue.s IL_0025 + + IL_000d: ldarg.0 + IL_000e: ldc.i4.1 + IL_000f: sub + IL_0010: ldarg.1 + IL_0011: ldarg.2 + IL_0012: ldarg.3 + IL_0013: ldarg.s d + IL_0015: ldarg.s e + IL_0017: starg.s e + IL_0019: starg.s d + IL_001b: starg.s c + IL_001d: starg.s b + IL_001f: starg.s a + IL_0021: starg.s n + IL_0023: br.s IL_0000 + + IL_0025: ldarg.0 + IL_0026: ldc.i4.1 + IL_0027: sub + IL_0028: ldarg.1 + IL_0029: ldarg.2 + IL_002a: ldarg.3 + IL_002b: ldarg.s d + IL_002d: ldarg.s e + IL_002f: tail. + IL_0031: call int32 assembly::firstCallee@9(int32, + valuetype assembly/Point2D, + valuetype assembly/Point2D, + valuetype assembly/Point2D, + valuetype assembly/Point2D, + valuetype assembly/Point2D) + IL_0036: ret + } + +} + +.class private abstract auto ansi sealed ''.$assembly + extends [runtime]System.Object +{ +} + + + + + diff --git a/tests/FSharp.Compiler.ComponentTests/EmittedIL/Inlining/Regression_TLR_MutualInnerRec_StructuralAssertions.fs b/tests/FSharp.Compiler.ComponentTests/EmittedIL/Inlining/Regression_TLR_MutualInnerRec_StructuralAssertions.fs new file mode 100644 index 00000000000..6945afcfba3 --- /dev/null +++ b/tests/FSharp.Compiler.ComponentTests/EmittedIL/Inlining/Regression_TLR_MutualInnerRec_StructuralAssertions.fs @@ -0,0 +1,258 @@ +namespace EmittedIL.RealInternalSignature + +open Xunit +open FSharp.Test +open FSharp.Test.Compiler + +module Regression_TLR_MutualInnerRec_StructuralAssertions = + + let internal compileOptimized realsig source = + FSharp source + |> withRealInternalSignature realsig + |> asExe + |> withOptimize + |> ignoreWarnings + + let private compileOptimizedAndRun realsig source = + source |> compileOptimized realsig |> compileExeAndRun |> shouldSucceed |> ignore + + let private compileAndAssertNoClosures realsig expectedIL source = + let result = source |> compileOptimized realsig |> compile |> shouldSucceed + result |> verifyILPresent expectedIL + result |> verifyILNotPresent [ "extends class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc" ] + result + + let private compileAssertNoClosuresAndRun realsig expectedIL source = + source |> compileAndAssertNoClosures realsig expectedIL |> run |> shouldSucceed |> ignore + + /// Source template: an inline constrained function is called inside a memoize closure. + /// The inline expands into the closure body, attaching constrained type params + /// to the closure class. EraseClosures must strip them from Specialize. + let internal closureWithConstraint constraintClause inlineBody typeAnnotation callValue = + $"""module Test +open System +let inline worker<'a when {constraintClause}> (a: 'a) (b: 'a) : bool = {inlineBody} +let inline tee f x = f x; x +let memoize (f: 'a -> 'b) = + let cell = ref None + let f' (x: 'a) = + match cell.Value with + | Some (x', value) when worker x' x -> value + | _ -> f x |> tee (fun y -> cell.Value <- Some (x, y)) + f' +[] +let main _argv = + let f: {typeAnnotation} -> {typeAnnotation} = memoize id + if f {callValue} = {callValue} then 0 else 1 +""" + + // --- TLR tests (#17607) --- + + [] + let ``Single inner let rec fires TLR`` (realsig: bool) = + """module Sample +let wrapper() = + let rec countdown(n) = + if n = 0 then 100 + else countdown(n - 1) + countdown(1000000) +[] +let main _argv = wrapper() +""" + |> compileAndAssertNoClosures realsig [ "static int32 countdown@" ] + |> ignore + + [] + let ``TLR inside generic class member`` (realsig: bool) = + """module Sample +type Container<'T>(initial: 'T) = + member _.Run() = + let rec a(n, v: 'T) = + if n = 0 then v + elif n % 2 = 0 then b(n - 1, v) + else a(n - 1, v) + and b(n, v: 'T) = + if n = 0 then v + elif n % 2 = 0 then b(n - 1, v) + else a(n - 1, v) + a(100, initial) +[] +let main _argv = + if Container(42).Run() = 42 then 0 else 1 +""" + |> compileAssertNoClosuresAndRun realsig [ "static !!T a@"; "static !!T b@" ] + + [] + let ``TLR with generic method on generic type`` (realsig: bool) = + """module Sample +type Processor<'T when 'T : struct>(value: 'T) = + member _.Transform<'U when 'U : equality>(input: 'U, expected: 'U) = + let rec apply(n, acc: 'U) = + if n <= 0 then acc = expected + else step(n, acc) + and step(n, acc: 'U) = + apply(n - 1, acc) + apply(100, input) +[] +let main _argv = + if Processor(1).Transform("hello", "hello") then 0 else 1 +""" + |> compileAssertNoClosuresAndRun realsig [ "static bool apply@"; "static bool step@"; "!!U" ] + + [] + let ``Three-way mutual recursion`` (realsig: bool) = + """module Sample +let run() = + let rec a(n) = + if n = 0 then 100 + elif n % 3 = 0 then b(n - 1) + elif n % 3 = 1 then c(n - 1) + else a(n - 1) + and b(n) = + if n = 0 then 101 else a(n - 1) + and c(n) = + if n = 0 then 102 else b(n - 1) + a(1000) +[] +let main _argv = run() +""" + |> compileAssertNoClosuresAndRun realsig [ "static int32 a@"; "static int32 b@"; "static int32 c@" ] + + [] + let ``TLR in nested module`` (realsig: bool) = + """module Outer +module Inner = + let run() = + let rec a(n) = + if n = 0 then 100 + elif n % 2 = 0 then b(n - 1) + else a(n - 1) + and b(n) = + if n = 0 then 101 else a(n - 1) + a(1000) +[] +let main _argv = Inner.run() +""" + |> compileAssertNoClosuresAndRun realsig [ "static int32 a@"; "static int32 b@" ] + + [] + let ``Value recursion is not broken by TLR`` (realsig: bool) = + """module Sample +let run() = + let rec values = [| 1; 2; 3 |] + and sum() = Array.sum values + sum() +[] +let main _argv = if run() = 6 then 0 else 1 +""" + |> compileOptimizedAndRun realsig + + [] + let ``Quotation body is not affected by TLR`` (realsig: bool) = + """module Sample +open Microsoft.FSharp.Quotations +open Microsoft.FSharp.Quotations.Patterns +let q : Expr = + <@ + let rec a(n) = + if n = 0 then 1 + elif n % 2 = 0 then b(n - 1) + else a(n - 1) + and b(n) = + if n = 0 then 2 + elif n % 2 = 0 then b(n - 1) + else a(n - 1) + a(100) + @> +[] +let main _argv = + match q.Raw with LetRecursive _ -> 0 | _ -> 1 +""" + |> compileOptimizedAndRun realsig + + // --- Constraint stripping tests (#14492) --- + + [] + let ``Issue 14492: Specialize override and T-suffix class have no constraints in IL`` (realsig: bool) = + let result = + closureWithConstraint "'a : not struct and 'a : equality" "obj.ReferenceEquals(a, b)" "string" "\"ok\"" + |> compileOptimized realsig + |> compile + |> shouldSucceed + + // Specialize method typars are unconstrained (CASE 1b fix) + result |> verifyILPresent [ "object Specialize<" ] + result |> verifyILNotPresent [ "Specialize verifyILNotPresent [ "T5 curried params on the inner closure forces CASE 2a term-splitting in + /// EraseClosures, producing a D-suffixed nested type. Module-level memoize creates + /// FSharpTypeFunc with Specialize<>. Constraint stripping is verified. + [] + let ``Issue 14492: >5 params closure chain produces D-suffix and unconstrained Specialize`` (realsig: bool) = + let source = + """module Sample +open System +let inline worker<'a when 'a : not struct> (a: 'a) (b: 'a) : bool = obj.ReferenceEquals(a, b) +let inline tee f x = f x; x +let memoize (f: 'a -> 'b) = + let cell = ref None + let f' (x: 'a) (a2: 'a) (a3: 'a) (a4: 'a) (a5: 'a) (a6: 'a) = + match cell.Value with + | Some (k, v) when worker k x && worker a2 a3 -> v + | _ -> f (if worker a4 a5 then x else a6) |> tee (fun y -> cell.Value <- Some (x, y)) + f' +[] +let main _argv = + let g: string -> string -> string -> string -> string -> string -> string = memoize id + if g "ok" "ok" "ok" "ok" "ok" "ok" = "ok" then 0 else 1 +""" + + let result = source |> compileOptimized realsig |> compile |> shouldSucceed + + // Specialize exists with NO IL constraints (stripped by fix) + result |> verifyILPresent [ "object Specialize<" ] + result |> verifyILNotPresent [ "Specialize5 params) + result |> verifyILPresent [ "memoize@8D<" ] + + result |> verifyPEFileWithSystemDlls |> shouldSucceed |> ignore + result |> run |> shouldSucceed |> ignore + + // --- Combined test (exercises both #17607 and #14492 together) --- + + /// Combines both fixes: TLR inside generic class (#17607) + constrained inline + /// inside closure (#14492). The inner rec is TLR-lifted to moduleCloc, and the + /// inline worker's constraint must be stripped from the closure's Specialize<>. + [] + let ``Combined: TLR in generic class with constrained inline closure`` (realsig: bool) = + let result = + """module Sample +open System +let inline worker<'a when 'a : not struct> (a: 'a) (b: 'a) : bool = obj.ReferenceEquals(a, b) +type Cache<'T when 'T : not struct and 'T : equality>(initial: 'T) = + member _.Lookup(key: 'T) = + let memoize (f: 'a -> 'b) = + let cell = ref None + let f' (x: 'a) = + match cell.Value with + | Some (k, v) when worker k x -> v + | _ -> let v = f x in cell.Value <- Some (x, v); v + f' + let rec search n = + if n <= 0 then false + elif (memoize id) key = key then true + else check (n - 1) + and check n = search (n - 1) + search 10 +[] +let main _argv = + if Cache("test").Lookup("test") then 0 else 1 +""" + |> compileOptimized realsig |> compile |> shouldSucceed + + result |> verifyILPresent [ "static bool search@" ] + result |> verifyPEFileWithSystemDlls |> shouldSucceed |> ignore + result |> run |> shouldSucceed |> ignore diff --git a/tests/FSharp.Compiler.ComponentTests/EmittedIL/TestFunctions/TestFunction06.fs.RealInternalSignatureOn.OptimizeOn.il.bsl b/tests/FSharp.Compiler.ComponentTests/EmittedIL/TestFunctions/TestFunction06.fs.RealInternalSignatureOn.OptimizeOn.il.bsl index fa8c139a871..43d92d119f3 100644 --- a/tests/FSharp.Compiler.ComponentTests/EmittedIL/TestFunctions/TestFunction06.fs.RealInternalSignatureOn.OptimizeOn.il.bsl +++ b/tests/FSharp.Compiler.ComponentTests/EmittedIL/TestFunctions/TestFunction06.fs.RealInternalSignatureOn.OptimizeOn.il.bsl @@ -38,54 +38,6 @@ extends [runtime]System.Object { .custom instance void [FSharp.Core]Microsoft.FSharp.Core.CompilationMappingAttribute::.ctor(valuetype [FSharp.Core]Microsoft.FSharp.Core.SourceConstructFlags) = ( 01 00 07 00 00 00 00 00 ) - .class auto ansi serializable sealed nested assembly beforefieldinit f@11 - extends class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2 - { - .field static assembly initonly class assembly/f@11 @_instance - .method assembly specialname rtspecialname instance void .ctor() cil managed - { - .custom instance void [runtime]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) - .custom instance void [runtime]System.Diagnostics.DebuggerNonUserCodeAttribute::.ctor() = ( 01 00 00 00 ) - - .maxstack 8 - IL_0000: ldarg.0 - IL_0001: call instance void class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2::.ctor() - IL_0006: ret - } - - .method public strict virtual instance int32 Invoke(class [FSharp.Core]Microsoft.FSharp.Core.Unit unitVar0) cil managed - { - - .maxstack 6 - .locals init (int32 V_0, - class [FSharp.Core]Microsoft.FSharp.Core.PrintfFormat`4 V_1) - IL_0000: call int32 assembly::TestFunction1() - IL_0005: stloc.0 - IL_0006: ldstr "Hello" - IL_000b: newobj instance void class [FSharp.Core]Microsoft.FSharp.Core.PrintfFormat`5::.ctor(string) - IL_0010: stloc.1 - IL_0011: call class [netstandard]System.IO.TextWriter [netstandard]System.Console::get_Out() - IL_0016: ldloc.1 - IL_0017: call !!0 [FSharp.Core]Microsoft.FSharp.Core.PrintfModule::PrintFormatLineToTextWriter(class [runtime]System.IO.TextWriter, - class [FSharp.Core]Microsoft.FSharp.Core.PrintfFormat`4) - IL_001c: pop - IL_001d: ldloc.0 - IL_001e: ldloc.0 - IL_001f: add - IL_0020: ret - } - - .method private specialname rtspecialname static void .cctor() cil managed - { - - .maxstack 10 - IL_0000: newobj instance void assembly/f@11::.ctor() - IL_0005: stsfld class assembly/f@11 assembly/f@11::@_instance - IL_000a: ret - } - - } - .method public static int32 TestFunction1() cil managed { @@ -114,18 +66,35 @@ .method public static int32 TestFunction6() cil managed { - .maxstack 5 - .locals init (class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2 V_0) - IL_0000: ldsfld class assembly/f@11 assembly/f@11::@_instance + .maxstack 8 + IL_0000: ldnull + IL_0001: call int32 assembly::f@10(class [FSharp.Core]Microsoft.FSharp.Core.Unit) + IL_0006: ldnull + IL_0007: call int32 assembly::f@10(class [FSharp.Core]Microsoft.FSharp.Core.Unit) + IL_000c: add + IL_000d: ret + } + + .method assembly static int32 f@10(class [FSharp.Core]Microsoft.FSharp.Core.Unit unitVar0) cil managed + { + + .maxstack 4 + .locals init (int32 V_0, + class [FSharp.Core]Microsoft.FSharp.Core.PrintfFormat`4 V_1) + IL_0000: call int32 assembly::TestFunction1() IL_0005: stloc.0 - IL_0006: ldloc.0 - IL_0007: ldnull - IL_0008: callvirt instance !1 class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2::Invoke(!0) - IL_000d: ldloc.0 - IL_000e: ldnull - IL_000f: callvirt instance !1 class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2::Invoke(!0) - IL_0014: add - IL_0015: ret + IL_0006: ldstr "Hello" + IL_000b: newobj instance void class [FSharp.Core]Microsoft.FSharp.Core.PrintfFormat`5::.ctor(string) + IL_0010: stloc.1 + IL_0011: call class [netstandard]System.IO.TextWriter [netstandard]System.Console::get_Out() + IL_0016: ldloc.1 + IL_0017: call !!0 [FSharp.Core]Microsoft.FSharp.Core.PrintfModule::PrintFormatLineToTextWriter(class [runtime]System.IO.TextWriter, + class [FSharp.Core]Microsoft.FSharp.Core.PrintfFormat`4) + IL_001c: pop + IL_001d: ldloc.0 + IL_001e: ldloc.0 + IL_001f: add + IL_0020: ret } } @@ -147,4 +116,3 @@ - diff --git a/tests/FSharp.Compiler.ComponentTests/EmittedIL/TestFunctions/TestFunction23.fs.RealInternalSignatureOn.OptimizeOn.il.netcore.bsl b/tests/FSharp.Compiler.ComponentTests/EmittedIL/TestFunctions/TestFunction23.fs.RealInternalSignatureOn.OptimizeOn.il.netcore.bsl index 422674eeb50..82a314e85a7 100644 --- a/tests/FSharp.Compiler.ComponentTests/EmittedIL/TestFunctions/TestFunction23.fs.RealInternalSignatureOn.OptimizeOn.il.netcore.bsl +++ b/tests/FSharp.Compiler.ComponentTests/EmittedIL/TestFunctions/TestFunction23.fs.RealInternalSignatureOn.OptimizeOn.il.netcore.bsl @@ -5,12 +5,12 @@ .assembly extern runtime { } .assembly extern FSharp.Core { } -.assembly extern runtime { } .assembly extern netstandard { .publickeytoken = (CC 7B 13 FF CD 2D DD 51 ) .ver 2:1:0:0 } +.assembly extern runtime { } .assembly assembly { .custom instance void [FSharp.Core]Microsoft.FSharp.Core.FSharpInterfaceDataVersionAttribute::.ctor(int32, @@ -87,72 +87,45 @@ } - .class auto ansi serializable sealed nested assembly beforefieldinit g@13 - extends class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2 - { - .field static assembly initonly class assembly/g@13 @_instance - .method assembly specialname rtspecialname instance void .ctor() cil managed - { - .custom instance void [runtime]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) - .custom instance void [runtime]System.Diagnostics.DebuggerNonUserCodeAttribute::.ctor() = ( 01 00 00 00 ) - - .maxstack 8 - IL_0000: ldarg.0 - IL_0001: call instance void class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2::.ctor() - IL_0006: ret - } - - .method public strict virtual instance class [FSharp.Core]Microsoft.FSharp.Core.Unit Invoke(class [FSharp.Core]Microsoft.FSharp.Core.Unit unitVar0) cil managed - { - - .maxstack 6 - .locals init (class [FSharp.Core]Microsoft.FSharp.Core.PrintfFormat`4 V_0) - IL_0000: ldstr "Hello" - IL_0005: newobj instance void class [FSharp.Core]Microsoft.FSharp.Core.PrintfFormat`5::.ctor(string) - IL_000a: stloc.0 - IL_000b: call class [netstandard]System.IO.TextWriter [netstandard]System.Console::get_Out() - IL_0010: ldloc.0 - IL_0011: call !!0 [FSharp.Core]Microsoft.FSharp.Core.PrintfModule::PrintFormatLineToTextWriter(class [runtime]System.IO.TextWriter, - class [FSharp.Core]Microsoft.FSharp.Core.PrintfFormat`4) - IL_0016: pop - IL_0017: ldstr "Hello" - IL_001c: newobj instance void class [FSharp.Core]Microsoft.FSharp.Core.PrintfFormat`5::.ctor(string) - IL_0021: stloc.0 - IL_0022: call class [netstandard]System.IO.TextWriter [netstandard]System.Console::get_Out() - IL_0027: ldloc.0 - IL_0028: tail. - IL_002a: call !!0 [FSharp.Core]Microsoft.FSharp.Core.PrintfModule::PrintFormatLineToTextWriter(class [runtime]System.IO.TextWriter, - class [FSharp.Core]Microsoft.FSharp.Core.PrintfFormat`4) - IL_002f: ret - } - - .method private specialname rtspecialname static void .cctor() cil managed - { - - .maxstack 10 - IL_0000: newobj instance void assembly/g@13::.ctor() - IL_0005: stsfld class assembly/g@13 assembly/g@13::@_instance - IL_000a: ret - } - - } - .method public static class [runtime]System.Tuple`2 f(!!a x) cil managed { - .maxstack 5 - .locals init (class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2 V_0) - IL_0000: ldsfld class assembly/g@13 assembly/g@13::@_instance - IL_0005: stloc.0 - IL_0006: ldloc.0 + .maxstack 8 + IL_0000: ldnull + IL_0001: call void assembly::g@12(class [FSharp.Core]Microsoft.FSharp.Core.Unit) + IL_0006: nop IL_0007: ldnull - IL_0008: callvirt instance !1 class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2::Invoke(!0) - IL_000d: ldloc.0 - IL_000e: ldnull - IL_000f: callvirt instance !1 class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2::Invoke(!0) - IL_0014: newobj instance void class [runtime]System.Tuple`2::.ctor(!0, + IL_0008: ldnull + IL_0009: call void assembly::g@12(class [FSharp.Core]Microsoft.FSharp.Core.Unit) + IL_000e: nop + IL_000f: ldnull + IL_0010: newobj instance void class [runtime]System.Tuple`2::.ctor(!0, !1) - IL_0019: ret + IL_0015: ret + } + + .method assembly static void g@12(class [FSharp.Core]Microsoft.FSharp.Core.Unit unitVar0) cil managed + { + + .maxstack 4 + .locals init (class [FSharp.Core]Microsoft.FSharp.Core.PrintfFormat`4 V_0) + IL_0000: ldstr "Hello" + IL_0005: newobj instance void class [FSharp.Core]Microsoft.FSharp.Core.PrintfFormat`5::.ctor(string) + IL_000a: stloc.0 + IL_000b: call class [netstandard]System.IO.TextWriter [netstandard]System.Console::get_Out() + IL_0010: ldloc.0 + IL_0011: call !!0 [FSharp.Core]Microsoft.FSharp.Core.PrintfModule::PrintFormatLineToTextWriter(class [runtime]System.IO.TextWriter, + class [FSharp.Core]Microsoft.FSharp.Core.PrintfFormat`4) + IL_0016: pop + IL_0017: ldstr "Hello" + IL_001c: newobj instance void class [FSharp.Core]Microsoft.FSharp.Core.PrintfFormat`5::.ctor(string) + IL_0021: stloc.0 + IL_0022: call class [netstandard]System.IO.TextWriter [netstandard]System.Console::get_Out() + IL_0027: ldloc.0 + IL_0028: call !!0 [FSharp.Core]Microsoft.FSharp.Core.PrintfModule::PrintFormatLineToTextWriter(class [runtime]System.IO.TextWriter, + class [FSharp.Core]Microsoft.FSharp.Core.PrintfFormat`4) + IL_002d: pop + IL_002e: ret } } @@ -174,4 +147,3 @@ - From 5c08b8851284420c1ef47fce2ed63a84c3b654aa Mon Sep 17 00:00:00 2001 From: Tomas Grosup Date: Mon, 1 Jun 2026 16:32:04 +0200 Subject: [PATCH 4/5] Release notes for TLR realsig fix (#17607) and constraint stripping fix (#14492) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- docs/release-notes/.FSharp.Compiler.Service/11.0.100.md | 4 ++++ 1 file changed, 4 insertions(+) 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 c18e1d8f213..787fa5a818c 100644 --- a/docs/release-notes/.FSharp.Compiler.Service/11.0.100.md +++ b/docs/release-notes/.FSharp.Compiler.Service/11.0.100.md @@ -1,7 +1,11 @@ ### Fixed +* Fix inner mutually-recursive `let rec ... and ...` functions under `--realsig+` not being lifted to top-level static methods (TLR), causing `FSharpFunc` closure allocations and loss of `tail.` opcodes — a ≈23× perf regression for struct-typed mutual recursion. ([Issue #17607](https://github.com/dotnet/fsharp/issues/17607)) +* Fix `TypeLoadException` for multi-level closures from constrained inline generics by stripping constraints from added generic params in `EraseClosures.convIlxClosureDef`. ([Issue #14492](https://github.com/dotnet/fsharp/issues/14492)) + * Honor `--nowarn` and `--warnaserror` for warnings emitted during command-line option parsing ([Issue #19576](https://github.com/dotnet/fsharp/issues/19576), [PR #19776](https://github.com/dotnet/fsharp/pull/19776)) * Fix `[]` prefix attributes being silently dropped on class members, and fix false-positive `AllowMultiple=false` errors when `[]` and `[]` are applied to the same binding. ([Issue #17904](https://github.com/dotnet/fsharp/issues/17904), [Issue #19020](https://github.com/dotnet/fsharp/issues/19020), [PR #19738](https://github.com/dotnet/fsharp/pull/19738)) + * Fix attributes on return type of unparenthesized tuple methods being silently dropped from IL. ([Issue #462](https://github.com/dotnet/fsharp/issues/462), [PR #19714](https://github.com/dotnet/fsharp/pull/19714)) * Fix false-positive nullness warning (FS3261) when pattern matching narrows nullness inside seq/list/array comprehensions. ([Issue #19644](https://github.com/dotnet/fsharp/issues/19644), [PR #19743](https://github.com/dotnet/fsharp/pull/19743)) * Fix internal error FS0073 "Undefined or unsolved type variable" in IlxGen when nested inline SRTP functions with multiple overloads leave unsolved typars in the non-witness codegen path. ([Issue #19709](https://github.com/dotnet/fsharp/issues/19709), [PR #19710](https://github.com/dotnet/fsharp/pull/19710)) From 2ccbbb18b3b60f9d7ce79c14e1d1c8b59b528ed1 Mon Sep 17 00:00:00 2001 From: Copilot Date: Wed, 3 Jun 2026 15:01:40 +0200 Subject: [PATCH 5/5] Add PR link to release notes and fix code formatting - Add PR #19882 link to both release note entries - Apply fantomas formatting to il.fs and IlxGen.fs Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../.FSharp.Compiler.Service/11.0.100.md | 4 ++-- src/Compiler/AbstractIL/il.fs | 5 ++++- src/Compiler/CodeGen/IlxGen.fs | 16 +++++++++++++--- 3 files changed, 19 insertions(+), 6 deletions(-) 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 89eaf411050..a03f1453ced 100644 --- a/docs/release-notes/.FSharp.Compiler.Service/11.0.100.md +++ b/docs/release-notes/.FSharp.Compiler.Service/11.0.100.md @@ -1,7 +1,7 @@ ### Fixed -* Fix inner mutually-recursive `let rec ... and ...` functions under `--realsig+` not being lifted to top-level static methods (TLR), causing `FSharpFunc` closure allocations and loss of `tail.` opcodes — a ≈23× perf regression for struct-typed mutual recursion. ([Issue #17607](https://github.com/dotnet/fsharp/issues/17607)) -* Fix `TypeLoadException` for multi-level closures from constrained inline generics by stripping constraints from added generic params in `EraseClosures.convIlxClosureDef`. ([Issue #14492](https://github.com/dotnet/fsharp/issues/14492)) +* Fix inner mutually-recursive `let rec ... and ...` functions under `--realsig+` not being lifted to top-level static methods (TLR), causing `FSharpFunc` closure allocations and loss of `tail.` opcodes — a ≈23× perf regression for struct-typed mutual recursion. ([Issue #17607](https://github.com/dotnet/fsharp/issues/17607), [PR #19882](https://github.com/dotnet/fsharp/pull/19882)) +* Fix `TypeLoadException` for multi-level closures from constrained inline generics by stripping constraints from added generic params in `EraseClosures.convIlxClosureDef`. ([Issue #14492](https://github.com/dotnet/fsharp/issues/14492), [PR #19882](https://github.com/dotnet/fsharp/pull/19882)) * Deduplicate format specifier locations in computation expressions so editor tooling no longer reports duplicate entries for the same `%` specifier. ([Issue #16419](https://github.com/dotnet/fsharp/issues/16419), [PR #19791](https://github.com/dotnet/fsharp/pull/19791)) * Reject non-function bindings for single-case and partial active pattern names with FS1209, matching the existing multi-case behavior. ([PR #19763](https://github.com/dotnet/fsharp/pull/19763)) diff --git a/src/Compiler/AbstractIL/il.fs b/src/Compiler/AbstractIL/il.fs index ba8be1d05a7..cf0dbb1aee2 100644 --- a/src/Compiler/AbstractIL/il.fs +++ b/src/Compiler/AbstractIL/il.fs @@ -3377,7 +3377,10 @@ let mkILSimpleTypar nm = /// Returns gp with all constraints cleared, including IsUnmanagedAttribute (carried via CustomAttrsStored). let stripILGenericParamConstraints (gp: ILGenericParameterDef) = - { mkILSimpleTypar gp.Name with Variance = gp.Variance; MetadataIndex = gp.MetadataIndex } + { mkILSimpleTypar gp.Name with + Variance = gp.Variance + MetadataIndex = gp.MetadataIndex + } let genericParamOfGenericActual (_ga: ILType) = mkILSimpleTypar "T" diff --git a/src/Compiler/CodeGen/IlxGen.fs b/src/Compiler/CodeGen/IlxGen.fs index e29fe76b8d2..7dd0d1c4fab 100644 --- a/src/Compiler/CodeGen/IlxGen.fs +++ b/src/Compiler/CodeGen/IlxGen.fs @@ -10278,9 +10278,16 @@ and AllocValReprWithinExpr cenv cgbuf endMark cloc v eenv = // enclosing type they inherit its class typar, conflicting with their own method typars. See #17607. // Note: also matches `do let x = …` and `copyOfStruct` vals — safe because at module scope cloc == moduleCloc. let effectiveCloc = - if v.IsCompiledAsTopLevel && not v.IsMemberOrModuleBinding then eenv.moduleCloc else cloc + if v.IsCompiledAsTopLevel && not v.IsMemberOrModuleBinding then + eenv.moduleCloc + else + cloc - ComputeAndAddStorageForLocalValWithValReprInfo (cenv, eenv.intraAssemblyInfo, cenv.options.isInteractive, optShadowLocal) effectiveCloc v eenv + ComputeAndAddStorageForLocalValWithValReprInfo + (cenv, eenv.intraAssemblyInfo, cenv.options.isInteractive, optShadowLocal) + effectiveCloc + v + eenv //-------------------------------------------------------------------------- // Generate stack save/restore and assertions - pulled into letrec by alloc* @@ -10775,7 +10782,10 @@ and GenImplFile cenv (mgbuf: AssemblyBuilder) mainInfoOpt eenv (implFile: Checke mgbuf.GenerateAnonType((fun ilThisTy -> GenToStringMethod cenv eenv ilThisTy m), anonInfo) let withQName (loc: CompileLocation) = - { loc with TopImplQualifiedName = qname.Text; Range = m } + { loc with + TopImplQualifiedName = qname.Text + Range = m + } let eenv = { eenv with