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 ff1c9aae2dd..5ae42d4d3af 100644 --- a/docs/release-notes/.FSharp.Compiler.Service/11.0.100.md +++ b/docs/release-notes/.FSharp.Compiler.Service/11.0.100.md @@ -1,5 +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)) * 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)) * Fix FS0421 "The address of the variable cannot be used at this point" incorrectly raised for the discard pattern `let _ = &expr` when `let x = &expr` compiles. ([Issue #18841](https://github.com/dotnet/fsharp/issues/18841), [PR #19811](https://github.com/dotnet/fsharp/pull/19811)) * 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)) 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 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..ace6735b154 --- /dev/null +++ b/tests/FSharp.Compiler.ComponentTests/EmittedIL/Inlining/Regression_Specialize_ConstraintVerification.fs @@ -0,0 +1,66 @@ +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 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 @@ - 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" ]