From a9f59cd4e55d7853e1f05e88e7a3d1ac2479c674 Mon Sep 17 00:00:00 2001 From: "Kevin Ransom (msft)" Date: Wed, 29 Jan 2025 02:25:06 -0800 Subject: [PATCH 01/29] Add ILVerification to test framework (#18255) --- .config/dotnet-tools.json | 16 +-- .../Events/Basic/Basic.fs | 19 ++- .../ClassTypeInitialization.fs | 109 +++++++++++++++++- .../ClassTypeVisibilityModuleRoot.fs | 85 +++++++++++++- .../ClassTypeVisibilityNamespaceRoot.fs | 70 +++++++++++ tests/FSharp.Test.Utilities/Compiler.fs | 48 ++++++-- tests/FSharp.Test.Utilities/CompilerAssert.fs | 2 + .../FSharp.Test.Utilities.fsproj | 4 +- .../FSharp.Test.Utilities/ILVerifierModule.fs | 78 +++++++++++++ tests/FSharp.Test.Utilities/Peverifier.fs | 80 ------------- tests/FSharp.Test.Utilities/TestFramework.fs | 16 +-- ...y_FSharp.Compiler.Service_Debug_net9.0.bsl | 17 --- ....Compiler.Service_Debug_netstandard2.0.bsl | 17 --- ...FSharp.Compiler.Service_Release_net9.0.bsl | 12 -- ...ompiler.Service_Release_netstandard2.0.bsl | 12 -- 15 files changed, 399 insertions(+), 186 deletions(-) create mode 100644 tests/FSharp.Test.Utilities/ILVerifierModule.fs delete mode 100644 tests/FSharp.Test.Utilities/Peverifier.fs diff --git a/.config/dotnet-tools.json b/.config/dotnet-tools.json index 88f8c3d1576..46cb8a756ca 100644 --- a/.config/dotnet-tools.json +++ b/.config/dotnet-tools.json @@ -44,19 +44,19 @@ ], "rollForward": true }, - "dotnet-ilverify": { - "version": "9.0.0-rc.2.24473.5", - "commands": [ - "ilverify" - ], - "rollForward": true - }, "fantomas": { "version": "6.2.3", "commands": [ "fantomas" ], "rollForward": true + }, + "dotnet-ilverify": { + "version": "9.0.0", + "commands": [ + "ilverify" + ], + "rollForward": false } } -} +} \ No newline at end of file diff --git a/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/Events/Basic/Basic.fs b/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/Events/Basic/Basic.fs index caede79cd6b..590e707751d 100644 --- a/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/Events/Basic/Basic.fs +++ b/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/Events/Basic/Basic.fs @@ -80,20 +80,15 @@ module Events = |> verifyCompileAndRun |> shouldSucceed - // NoMT SOURCE=SanityCheck02.fs # SanityCheck02.fs - [] - let ``SanityCheck02_fs`` compilation = - compilation - |> verifyCompileAndRun - |> shouldSucceed - -#if false && !NETCOREAPP && !NETSTANDARD // SOURCE=SanityCheck02.fs PEVER=/MD # SanityCheck02.fs - /MD [] - let ``SanityCheck02_fs_peverify`` compilation = + let ``SanityCheck02`` compilation = compilation |> asExe |> withOptions ["--nowarn:988"] - |> PEVerifier.verifyPEFile - |> PEVerifier.shouldSucceed -#endif + |> verifyCompileAndRun + |> shouldSucceed + |> verifyPEFileWithSystemDlls + |> withOutputContainsAllInOrderWithWildcards [ + "All Classes and Methods in*SanityCheck02.exe Verified." + ] diff --git a/tests/FSharp.Compiler.ComponentTests/EmittedIL/RealInternalSignature/ClassTypeInitialization.fs b/tests/FSharp.Compiler.ComponentTests/EmittedIL/RealInternalSignature/ClassTypeInitialization.fs index fd9eb1848d4..981b2e5d95a 100644 --- a/tests/FSharp.Compiler.ComponentTests/EmittedIL/RealInternalSignature/ClassTypeInitialization.fs +++ b/tests/FSharp.Compiler.ComponentTests/EmittedIL/RealInternalSignature/ClassTypeInitialization.fs @@ -34,6 +34,7 @@ module MyModule = printfn "Hello from main method" 0 """ + |> withName "SimpleTypesInNamespace" |> withRealInternalSignature realSig |> compileExeAndRun |> shouldSucceed @@ -42,6 +43,11 @@ module MyModule = "Hello, World from MyLibrary.MySecondType" "Hello from main method" ] + |> verifyPEFileWithSystemDlls + |> withOutputContainsAllInOrderWithWildcards [ + "All Classes and Methods in*SimpleTypesInNamespace.exe Verified." + ] + [] // RealSig @@ -60,6 +66,7 @@ type MySecondType = printfn "Hello from implicit main method" """ + |> withName "SimpleTypesInImplicitMain" |> withRealInternalSignature realSig |> compileExeAndRun |> shouldSucceed @@ -68,6 +75,10 @@ printfn "Hello from implicit main method" "Hello, World from MyProgram.MySecondType" "Hello from implicit main method" ] + |> verifyPEFileWithSystemDlls + |> withOutputContainsAllInOrderWithWildcards [ + "All Classes and Methods in*SimpleTypesInImplicitMain.exe Verified." + ] [] // RealSig @@ -91,6 +102,7 @@ module MyModule = printfn "Hello from main method" 0 """ + |> withName "SimpleTypeOneAndTypeTwoInNamespace" |> withRealInternalSignature realSig |> compileExeAndRun |> withStdOutContainsAllInOrder [ @@ -99,6 +111,10 @@ module MyModule = "Hello from main method" ] |> shouldSucceed + |> verifyPEFileWithSystemDlls + |> withOutputContainsAllInOrderWithWildcards [ + "All Classes and Methods in*SimpleTypeOneAndTypeTwoInNamespace.exe Verified." + ] [] // RealSig [] // Regular @@ -130,12 +146,17 @@ module doit = FSharpSource.CreateFromFile("Hello") |> ignore printfn "Main program" """ + |> withName "PublicTypePublicCtor" |> withRealInternalSignature realSig |> compileExeAndRun |> shouldSucceed |> withStdOutContainsAllInOrder [ "Main program" ] + |> verifyPEFileWithSystemDlls + |> withOutputContainsAllInOrderWithWildcards [ + "All Classes and Methods in*PublicTypePublicCtor.exe Verified." + ] [] // RealSig @@ -168,12 +189,17 @@ module doit = FSharpSource.CreateFromFile("Hello") |> ignore printfn "Main program" """ + |> withName "PublicTypeInternalCtor" |> withRealInternalSignature realSig |> compileExeAndRun |> shouldSucceed |> withStdOutContainsAllInOrder [ "Main program" ] + |> verifyPEFileWithSystemDlls + |> withOutputContainsAllInOrderWithWildcards [ + "All Classes and Methods in*PublicTypeInternalCtor.exe Verified." + ] [] // RealSig @@ -206,12 +232,17 @@ module doit = FSharpSource.CreateFromFile("Hello") |> ignore printfn "Main program" """ + |> withName "PublicTypePrivateCtor" |> withRealInternalSignature realSig |> compileExeAndRun |> shouldSucceed |> withStdOutContainsAllInOrder [ "Main program" ] + |> verifyPEFileWithSystemDlls + |> withOutputContainsAllInOrderWithWildcards [ + "All Classes and Methods in*PublicTypePrivateCtor.exe Verified." + ] [] // RealSig [] // Regular @@ -243,12 +274,17 @@ module doit = FSharpSource.CreateFromFile("Hello") |> ignore printfn "Main program" """ + |> withName "PublicTypeUnspecifiedCtor" |> withRealInternalSignature realSig |> compileExeAndRun |> shouldSucceed |> withStdOutContainsAllInOrder [ "Main program" ] + |> verifyPEFileWithSystemDlls + |> withOutputContainsAllInOrderWithWildcards [ + "All Classes and Methods in*PublicTypeUnspecifiedCtor.exe Verified." + ] [] // RealSig [] // Regular @@ -280,13 +316,17 @@ module doit = FSharpSource.CreateFromFile("Hello") |> ignore printfn "Main program" """ + |> withName "PrivateTypePublicCtor" |> withRealInternalSignature realSig |> compileExeAndRun |> shouldSucceed |> withStdOutContainsAllInOrder [ "Main program" ] - + |> verifyPEFileWithSystemDlls + |> withOutputContainsAllInOrderWithWildcards [ + "All Classes and Methods in*PrivateTypePublicCtor.exe Verified." + ] [] // RealSig [] // Regular @@ -318,12 +358,17 @@ module doit = FSharpSource.CreateFromFile("Hello") |> ignore printfn "Main program" """ + |> withName "PrivateTypeInternalCtor" |> withRealInternalSignature realSig |> compileExeAndRun |> withStdOutContainsAllInOrder [ "Main program" ] |> shouldSucceed + |> verifyPEFileWithSystemDlls + |> withOutputContainsAllInOrderWithWildcards [ + "All Classes and Methods in*PrivateTypeInternalCtor.exe Verified." + ] [] // RealSig [] // Regular @@ -362,12 +407,17 @@ type FSharpSource with module doit = printfn "Main program" """ + |> withName "PrivateTypePrivateCtor" |> withRealInternalSignature realSig |> compileExeAndRun |> shouldSucceed |> withStdOutContainsAllInOrder [ "Main program" ] + |> verifyPEFileWithSystemDlls + |> withOutputContainsAllInOrderWithWildcards [ + "All Classes and Methods in*PrivateTypePrivateCtor.exe Verified." + ] [] // RealSig [] // Regular @@ -399,12 +449,17 @@ module doit = FSharpSource.CreateFromFile("Hello") |> ignore printfn "Main program" """ + |> withName "PrivateTypeUnspecifiedCtor" |> withRealInternalSignature realSig |> compileExeAndRun |> shouldSucceed |> withStdOutContainsAllInOrder [ "Main program" ] + |> verifyPEFileWithSystemDlls + |> withOutputContainsAllInOrderWithWildcards [ + "All Classes and Methods in*PrivateTypeUnspecifiedCtor.exe Verified." + ] [] // RealSig [] // Regular @@ -439,12 +494,17 @@ let message = FSharpSourceFromFile.SetIt ("Here is something") printfn $"{message}" """ + |> withName "StaticInitializationNoInlinePrivateField" |> withRealInternalSignature realSig |> compileExeAndRun |> shouldSucceed |> withStdOutContainsAllInOrder [ "Here is something" ] + |> verifyPEFileWithSystemDlls + |> withOutputContainsAllInOrderWithWildcards [ + "All Classes and Methods in*StaticInitializationNoInlinePrivateField.exe Verified." + ] [] // RealSig [] // Regular @@ -476,6 +536,7 @@ type MyClass = printfn "%A" (MyClass.result()) """ + |> withName "ComputationExpressionAccessPrivateBinding" |> withRealInternalSignature realSig |> withNoOptimize |> compileExeAndRun @@ -483,7 +544,10 @@ printfn "%A" (MyClass.result()) |> withStdOutContainsAllInOrder [ "Some 3" ] - + |> verifyPEFileWithSystemDlls + |> withOutputContainsAllInOrderWithWildcards [ + "All Classes and Methods in*ComputationExpressionAccessPrivateBinding.exe Verified." + ] [] // RealSig Optimize [] // RealSig NoOptimize @@ -495,11 +559,16 @@ printfn "%A" (MyClass.result()) let source = File.ReadAllText (path) FSharp source + |> withName "NestedGenericClosure" |> asExe |> withRealInternalSignature realSig |> withOptimization optimize |> compileAndRun |> shouldSucceed + |> verifyPEFileWithSystemDlls + |> withOutputContainsAllInOrderWithWildcards [ + "All Classes and Methods in*NestedGenericClosure.exe Verified." + ] [] // RealSig Optimize [] // RealSig NoOptimize @@ -538,11 +607,16 @@ module doIt = for i in enumerator.MoveNext() do printfn "%A" i """ + |> withName "GenericClassWithClosureWithConstraints" |> asExe |> withRealInternalSignature realSig |> withOptimization optimize |> compileAndRun |> shouldSucceed + |> verifyPEFileWithSystemDlls + |> withOutputContainsAllInOrderWithWildcards [ + "All Classes and Methods in*GenericClassWithClosureWithConstraints.exe Verified." + ] [] // RealSig Optimize [] // RealSig NoOptimize @@ -700,11 +774,16 @@ type internal AgedLookup<'Token, 'Key, 'Value when 'Value: not struct>(keepStron let keep = FilterAndHold(tok) AssignWithStrength(tok, keep) """ + |> withName "AgedLookup" |> asLibrary |> withRealInternalSignature realSig |> withOptimization optimize |> compile |> shouldSucceed + |> verifyPEFileWithSystemDlls + |> withOutputContainsAllInOrderWithWildcards [ + "All Classes and Methods in*AgedLookup.dll Verified." + ] [] // RealSig Optimize [] // RealSig NoOptimize @@ -718,11 +797,16 @@ namespace Equality type BigGenericTuple<'a> = BigGenericTuple of int * 'a * byte * int * 'a * byte """ + |> withName "BigTuples" |> asLibrary |> withRealInternalSignature realSig |> withOptimization optimize |> compile |> shouldSucceed + |> verifyPEFileWithSystemDlls + |> withOutputContainsAllInOrderWithWildcards [ + "All Classes and Methods in*BigTuples.dll Verified." + ] [] // RealSig Optimize [] // RealSig NoOptimize @@ -735,14 +819,18 @@ type BigGenericTuple<'a> = BigGenericTuple of int * 'a * byte * int * 'a * byte module GroupByTest let ``for _ in Array groupBy id [||] do ...`` () = [|for _ in Array.groupBy id [||] do 0|] """ + |> withName "ArrayGroupById" |> asLibrary |> withRealInternalSignature realSig |> withOptimization optimize |> compile |> shouldSucceed + |> verifyPEFileWithSystemDlls + |> withOutputContainsAllInOrderWithWildcards [ + "All Classes and Methods in*ArrayGroupById.dll Verified." + ] - - let roundTripWithInterfaceGeneration(realsig, optimize, implementationFile) = + let roundTripWithInterfaceGeneration(realsig, optimize, implementationFile, name) = let generatedSignature = Fs implementationFile @@ -751,6 +839,7 @@ let ``for _ in Array groupBy id [||] do ...`` () = [|for _ in Array.groupBy id [ |> printSignatures Fsi generatedSignature + |> withName name |> asLibrary |> withAdditionalSourceFile (FsSource implementationFile) |> withRealInternalSignature realsig @@ -774,7 +863,11 @@ type IMonad<'a> = abstract bind : #IMonad<'a> -> ('a -> #IMonad<'b>) -> IMonad<'b> end""" - roundTripWithInterfaceGeneration(realsig, optimize, implementationFile) + roundTripWithInterfaceGeneration(realsig, optimize, implementationFile, "GenericParameterOrderRoundtrip") + |> verifyPEFileWithSystemDlls + |> withOutputContainsAllInOrderWithWildcards [ + "All Classes and Methods in*GenericParameterOrderRoundtrip.dll Verified." + ] [] // RealSig Optimize [] // RealSig NoOptimize @@ -803,4 +896,8 @@ namespace GenericInterfaceTest new(x) = { store = x } end""" - roundTripWithInterfaceGeneration(realsig, optimize, implementationFile) + roundTripWithInterfaceGeneration(realsig, optimize, implementationFile, "MembersBasicRoundtrip") + |> verifyPEFileWithSystemDlls + |> withOutputContainsAllInOrderWithWildcards [ + "All Classes and Methods in*MembersBasicRoundtrip.dll Verified." + ] diff --git a/tests/FSharp.Compiler.ComponentTests/EmittedIL/RealInternalSignature/ClassTypeVisibilityModuleRoot.fs b/tests/FSharp.Compiler.ComponentTests/EmittedIL/RealInternalSignature/ClassTypeVisibilityModuleRoot.fs index 763bbc9c33e..a7ba195e02f 100644 --- a/tests/FSharp.Compiler.ComponentTests/EmittedIL/RealInternalSignature/ClassTypeVisibilityModuleRoot.fs +++ b/tests/FSharp.Compiler.ComponentTests/EmittedIL/RealInternalSignature/ClassTypeVisibilityModuleRoot.fs @@ -24,9 +24,14 @@ type public TypeTwo internal () = class end type public TypeThree private () = class end type public TypeFour () = class end """ + |> withName "PublicTypeConstructors" |> asLibrary |> withRealInternalSignature realSig |> compile + |> verifyPEFileWithSystemDlls + |> withOutputContainsAllInOrderWithWildcards [ + "All Classes and Methods in*PublicTypeConstructors.dll Verified." + ] |> withILContains [ if realSig then """ .class auto ansi serializable nested public TypeOne @@ -91,9 +96,14 @@ type private TypeOne public () = class end type private TypeTwo internal () = class end type private TypeThree private () = class end type private TypeFour () = class end""" + |> withName "PrivateTypeConstructors" |> asLibrary |> withRealInternalSignature realSig |> compile + |> verifyPEFileWithSystemDlls + |> withOutputContainsAllInOrderWithWildcards [ + "All Classes and Methods in*PrivateTypeConstructors.dll Verified." + ] |> withILContains [ if realSig then """ @@ -254,9 +264,14 @@ type public TestType () = member private _.PrivateMethod() = () member _.DefaultMethod() = () """ + |> withName "PublicTypeInstanceMethods" |> asLibrary |> withRealInternalSignature realSig |> compile + |> verifyPEFileWithSystemDlls + |> withOutputContainsAllInOrderWithWildcards [ + "All Classes and Methods in*PublicTypeInstanceMethods.dll Verified." + ] |> withILContains [ if realSig then ".method public hidebysig instance void PublicMethod() cil managed" @@ -285,9 +300,14 @@ type public TestType () = member private _.PrivateMethod() = () member _.DefaultMethod() = () """ + |> withName "PrivateTypeInstanceMethods" |> asLibrary |> withRealInternalSignature realSig |> compile + |> verifyPEFileWithSystemDlls + |> withOutputContainsAllInOrderWithWildcards [ + "All Classes and Methods in*PrivateTypeInstanceMethods.dll Verified." + ] |> withILContains [ if realSig then ".method public hidebysig instance void PublicMethod() cil managed" @@ -317,9 +337,14 @@ type public TestType () = member val private PrivateProperty = 0 with get, set member val DefaultProperty = 0 with get, set """ + |> withName "PublicTypeInstanceProperties" |> asLibrary |> withRealInternalSignature realSig |> compile + |> verifyPEFileWithSystemDlls + |> withOutputContainsAllInOrderWithWildcards [ + "All Classes and Methods in*PublicTypeInstanceProperties.dll Verified." + ] |> withILContains [ if realSig then ".method public hidebysig specialname instance int32 get_PublicProperty() cil managed" @@ -357,9 +382,14 @@ type public TestType () = member val private PrivateProperty = 0 with get, set member val DefaultProperty = 0 with get, set """ + |> withName "PrivateTypeInstanceMixedProperties" |> asLibrary |> withRealInternalSignature realSig |> compile + |> verifyPEFileWithSystemDlls + |> withOutputContainsAllInOrderWithWildcards [ + "All Classes and Methods in*PrivateTypeInstanceMixedProperties.dll Verified." + ] |> withILContains [ if realSig then ".method public hidebysig specialname instance int32 get_PublicProperty() cil managed" @@ -405,9 +435,14 @@ type public TestType () = member _.MixedPropertyEleven with internal get() = 0 and set (_:int) = () member _.MixedPropertyTwelve with private get() = 0 and set (_:int) = () """ + |> withName "PublicTypeInstanceMixedProperties" |> asLibrary |> withRealInternalSignature realSig |> compile + |> verifyPEFileWithSystemDlls + |> withOutputContainsAllInOrderWithWildcards [ + "All Classes and Methods in*PublicTypeInstanceMixedProperties.dll Verified." + ] |> withILContains [ if realSig then ".method public hidebysig specialname instance int32 get_MixedPropertyOne() cil managed" @@ -460,7 +495,6 @@ type public TestType () = ".method public hidebysig specialname instance void set_MixedPropertyEleven(int32 _arg11) cil managed" ".method assembly hidebysig specialname instance int32 get_MixedPropertyTwelve() cil managed" ".method public hidebysig specialname instance void set_MixedPropertyTwelve(int32 _arg12) cil managed" - ] |> shouldSucceed @@ -485,9 +519,14 @@ type private TestType () = member _.MixedPropertyEleven with internal get() = 0 and set (_:int) = () member _.MixedPropertyTwelve with private get() = 0 and set (_:int) = () """ + |> withName "PrivateTypeInstanceMixedProperties" |> asLibrary |> withRealInternalSignature realSig |> compile + |> verifyPEFileWithSystemDlls + |> withOutputContainsAllInOrderWithWildcards [ + "All Classes and Methods in*PrivateTypeInstanceMixedProperties.dll Verified." + ] |> withILContains [ if realSig then ".method public hidebysig specialname instance int32 get_MixedPropertyOne() cil managed" @@ -557,9 +596,14 @@ type public TestType () = static member private PrivateMethod() = () static member DefaultMethod() = () """ + |> withName "PublicTypeStaticMethods" |> asLibrary |> withRealInternalSignature realSig |> compile + |> verifyPEFileWithSystemDlls + |> withOutputContainsAllInOrderWithWildcards [ + "All Classes and Methods in*PublicTypeStaticMethods.dll Verified." + ] |> withILContains [ if realSig then ".method public static void PublicMethod() cil managed" @@ -589,16 +633,20 @@ type private TestType () = static member private PrivateMethod() = () static member DefaultMethod() = () """ + |> withName "PrivateTypeStaticMethods" |> asLibrary |> withRealInternalSignature realSig |> compile + |> verifyPEFileWithSystemDlls + |> withOutputContainsAllInOrderWithWildcards [ + "All Classes and Methods in*PrivateTypeStaticMethods.dll Verified." + ] |> withILContains [ if realSig then ".method public static void PublicMethod() cil managed" ".method assembly static void InternalMethod() cil managed" ".method private static void PrivateMethod() cil managed" ".method public static void DefaultMethod() cil managed" - else ".method assembly static void PublicMethod() cil managed" ".method assembly static void InternalMethod() cil managed" @@ -620,9 +668,14 @@ type public TestType () = static member val internal InternalProperty = 0 with get, set static member val private PrivateProperty = 0 with get, set static member val DefaultProperty = 0 with get, set""" + |> withName "PublicTypeStaticProperties" |> asLibrary |> withRealInternalSignature realSig |> compile + |> verifyPEFileWithSystemDlls + |> withOutputContainsAllInOrderWithWildcards [ + "All Classes and Methods in*PublicTypeStaticProperties.dll Verified." + ] |> withILContains [ if realSig then ".method public specialname static int32 get_PublicProperty() cil managed" @@ -658,9 +711,14 @@ type private TestType () = static member val internal InternalProperty = 0 with get, set static member val private PrivateProperty = 0 with get, set static member val DefaultProperty = 0 with get, set""" + |> withName "PrivateTypeStaticProperties" |> asLibrary |> withRealInternalSignature realSig |> compile + |> verifyPEFileWithSystemDlls + |> withOutputContainsAllInOrderWithWildcards [ + "All Classes and Methods in*PrivateTypeStaticProperties.dll Verified." + ] |> withILContains [ if realSig then ".method public specialname static int32 get_PublicProperty() cil managed" @@ -705,9 +763,14 @@ type public TestType () = static member MixedPropertyEleven with internal get() = 0 and set (_:int) = () static member MixedPropertyTwelve with private get() = 0 and set (_:int) = () """ + |> withName "PublicTypeStaticMixedProperties" |> asLibrary |> withRealInternalSignature realSig |> compile + |> verifyPEFileWithSystemDlls + |> withOutputContainsAllInOrderWithWildcards [ + "All Classes and Methods in*PublicTypeStaticMixedProperties.dll Verified." + ] |> withILContains [ if realSig then ".method public specialname static int32 get_MixedPropertyOne() cil managed" @@ -785,9 +848,14 @@ type private TestType () = static member MixedPropertyEleven with internal get() = 0 and set (_:int) = () static member MixedPropertyTwelve with private get() = 0 and set (_:int) = () """ + |> withName "PrivateTypeStaticMixedProperties" |> asLibrary |> withRealInternalSignature realSig |> compile + |> verifyPEFileWithSystemDlls + |> withOutputContainsAllInOrderWithWildcards [ + "All Classes and Methods in*PrivateTypeStaticMixedProperties.dll Verified." + ] |> withILContains [ if realSig then ".method public specialname static int32 get_MixedPropertyOne() cil managed" @@ -844,12 +912,12 @@ type private TestType () = ] |> shouldSucceed - [] // RealSig - [] // Regular + [] // RealSig + [] // Regular [] // RealSig [] // Regular - [] // RealSig - [] // Regular + [] // RealSig + [] // Regular [] let ``lazy operation - member with various visibilities`` (realSig, scope) = FSharp $""" @@ -858,8 +926,13 @@ module internal SR = let getLazyThing () = lazyThing.Force() SR.getLazyThing () """ + |> withName "LazyOperationMemberWithVariousVisibilities" |> asExe |> withOptimize |> withRealInternalSignature realSig |> compileExeAndRun |> shouldSucceed + |> verifyPEFileWithSystemDlls + |> withOutputContainsAllInOrderWithWildcards [ + "All Classes and Methods in*LazyOperationMemberWithVariousVisibilities.exe Verified." + ] diff --git a/tests/FSharp.Compiler.ComponentTests/EmittedIL/RealInternalSignature/ClassTypeVisibilityNamespaceRoot.fs b/tests/FSharp.Compiler.ComponentTests/EmittedIL/RealInternalSignature/ClassTypeVisibilityNamespaceRoot.fs index 695d6cd8ba2..bfddf645779 100644 --- a/tests/FSharp.Compiler.ComponentTests/EmittedIL/RealInternalSignature/ClassTypeVisibilityNamespaceRoot.fs +++ b/tests/FSharp.Compiler.ComponentTests/EmittedIL/RealInternalSignature/ClassTypeVisibilityNamespaceRoot.fs @@ -24,9 +24,14 @@ type public TypeTwo internal () = class end type public TypeThree private () = class end type public TypeFour () = class end """ + |> withName "PublicTypeConstructors" |> asLibrary |> withRealInternalSignature realSig |> compile + |> verifyPEFileWithSystemDlls + |> withOutputContainsAllInOrderWithWildcards [ + "All Classes and Methods in*PublicTypeConstructors.dll Verified." + ] |> withILContains [ if realSig then """ @@ -189,9 +194,14 @@ type private TypeTwo internal () = class end type private TypeThree private () = class end type private TypeFour () = class end """ + |> withName "PrivateTypeConstructors" |> asLibrary |> withRealInternalSignature realSig |> compile + |> verifyPEFileWithSystemDlls + |> withOutputContainsAllInOrderWithWildcards [ + "All Classes and Methods in*PrivateTypeConstructors.dll Verified." + ] |> withILContains [ """ .class private auto ansi serializable RealInternalSignature.TypeOne @@ -282,9 +292,14 @@ type public TestType () = member private _.PrivateMethod() = () member _.DefaultMethod() = () """ + |> withName "PublicTypeInstanceMethods" |> asLibrary |> withRealInternalSignature realSig |> compile + |> verifyPEFileWithSystemDlls + |> withOutputContainsAllInOrderWithWildcards [ + "All Classes and Methods in*PublicTypeInstanceMethods.dll Verified." + ] |> withILContains [ if realSig then ".method public hidebysig instance void PublicMethod() cil managed" @@ -313,9 +328,14 @@ type private TestType () = member private _.PrivateMethod() = () member _.DefaultMethod() = () """ + |> withName "PrivateTypeInstanceMethods" |> asLibrary |> withRealInternalSignature realSig |> compile + |> verifyPEFileWithSystemDlls + |> withOutputContainsAllInOrderWithWildcards [ + "All Classes and Methods in*PrivateTypeInstanceMethods.dll Verified." + ] |> withILContains [ if realSig then ".method public hidebysig instance void PublicMethod() cil managed" @@ -345,9 +365,14 @@ type public TestType () = member val private PrivateProperty = 0 with get, set member val DefaultProperty = 0 with get, set """ + |> withName "PrivateTypeInstanceMethods" |> asLibrary |> withRealInternalSignature realSig |> compile + |> verifyPEFileWithSystemDlls + |> withOutputContainsAllInOrderWithWildcards [ + "All Classes and Methods in*PrivateTypeInstanceMethods.dll Verified." + ] |> withILContains [ if realSig then ".method public hidebysig specialname instance int32 get_PublicProperty() cil managed" @@ -385,9 +410,14 @@ type public TestType () = member val private PrivateProperty = 0 with get, set member val DefaultProperty = 0 with get, set """ + |> withName "PrivateTypeInstanceProperties" |> asLibrary |> withRealInternalSignature realSig |> compile + |> verifyPEFileWithSystemDlls + |> withOutputContainsAllInOrderWithWildcards [ + "All Classes and Methods in*PrivateTypeInstanceProperties.dll Verified." + ] |> withILContains [ if realSig then ".method public hidebysig specialname instance int32 get_PublicProperty() cil managed" @@ -433,9 +463,14 @@ type public TestType () = member _.MixedPropertyEleven with internal get() = 0 and set (_:int) = () member _.MixedPropertyTwelve with private get() = 0 and set (_:int) = () """ + |> withName "PublicTypeInstanceMixedProperties" |> asLibrary |> withRealInternalSignature realSig |> compile + |> verifyPEFileWithSystemDlls + |> withOutputContainsAllInOrderWithWildcards [ + "All Classes and Methods in*PublicTypeInstanceMixedProperties.dll Verified." + ] |> withILContains [ if realSig then ".method public specialname rtspecialname instance void .ctor() cil managed" @@ -515,9 +550,14 @@ type private TestType () = member _.MixedPropertyEleven with internal get() = 0 and set (_:int) = () member _.MixedPropertyTwelve with private get() = 0 and set (_:int) = () """ + |> withName "PrivateTypeInstanceMixedProperties" |> asLibrary |> withRealInternalSignature realSig |> compile + |> verifyPEFileWithSystemDlls + |> withOutputContainsAllInOrderWithWildcards [ + "All Classes and Methods in*PrivateTypeInstanceMixedProperties.dll Verified." + ] |> withILContains [ if realSig then ".method public hidebysig specialname instance int32 get_MixedPropertyOne() cil managed" @@ -586,9 +626,14 @@ type public TestType () = static member private PrivateMethod() = () static member DefaultMethod() = () """ + |> withName "PublicTypeStaticMethods" |> asLibrary |> withRealInternalSignature realSig |> compile + |> verifyPEFileWithSystemDlls + |> withOutputContainsAllInOrderWithWildcards [ + "All Classes and Methods in*PublicTypeStaticMethods.dll Verified." + ] |> withILContains [ if realSig then ".method public static void PublicMethod() cil managed" @@ -617,9 +662,14 @@ type public TestType () = static member private PrivateMethod() = () static member DefaultMethod() = () """ + |> withName "PrivateTypeStaticMethods" |> asLibrary |> withRealInternalSignature realSig |> compile + |> verifyPEFileWithSystemDlls + |> withOutputContainsAllInOrderWithWildcards [ + "All Classes and Methods in*PrivateTypeStaticMethods.dll Verified." + ] |> withILContains [ if realSig then ".method public static void PublicMethod() cil managed" @@ -648,9 +698,14 @@ type public TestType () = static member val internal InternalProperty = 0 with get, set static member val private PrivateProperty = 0 with get, set static member val DefaultProperty = 0 with get, set""" + |> withName "PublicTypeStaticProperties" |> asLibrary |> withRealInternalSignature realSig |> compile + |> verifyPEFileWithSystemDlls + |> withOutputContainsAllInOrderWithWildcards [ + "All Classes and Methods in*PublicTypeStaticProperties.dll Verified." + ] |> withILContains [ if realSig then ".method public specialname static int32 get_PublicProperty() cil managed" @@ -687,9 +742,14 @@ type private TestType () = static member val internal InternalProperty = 0 with get, set static member val private PrivateProperty = 0 with get, set static member val DefaultProperty = 0 with get, set""" + |> withName "PrivateTypeStaticProperties" |> asLibrary |> withRealInternalSignature realSig |> compile + |> verifyPEFileWithSystemDlls + |> withOutputContainsAllInOrderWithWildcards [ + "All Classes and Methods in*PrivateTypeStaticProperties.dll Verified." + ] |> withILContains [ if realSig then ".method public specialname static int32 get_PublicProperty() cil managed" @@ -735,9 +795,14 @@ type public TestType () = static member MixedPropertyEleven with internal get() = 0 and set (_:int) = () static member MixedPropertyTwelve with private get() = 0 and set (_:int) = () """ + |> withName "PublicTypeStatiMixedProperties" |> asLibrary |> withRealInternalSignature realSig |> compile + |> verifyPEFileWithSystemDlls + |> withOutputContainsAllInOrderWithWildcards [ + "All Classes and Methods in*PublicTypeStatiMixedProperties.dll Verified." + ] |> withILContains [ if realSig then ".method public specialname static int32 get_MixedPropertyOne() cil managed" @@ -815,9 +880,14 @@ type private TestType () = static member MixedPropertyEleven with internal get() = 0 and set (_:int) = () static member MixedPropertyTwelve with private get() = 0 and set (_:int) = () """ + |> withName "PrivateTypeStatiMixedProperties" |> asLibrary |> withRealInternalSignature realSig |> compile + |> verifyPEFileWithSystemDlls + |> withOutputContainsAllInOrderWithWildcards [ + "All Classes and Methods in*PrivateTypeStatiMixedProperties.dll Verified." + ] |> withILContains [ if realSig then ".method public specialname static int32 get_MixedPropertyOne() cil managed" diff --git a/tests/FSharp.Test.Utilities/Compiler.fs b/tests/FSharp.Test.Utilities/Compiler.fs index 7de76521d83..1c9fca26592 100644 --- a/tests/FSharp.Test.Utilities/Compiler.fs +++ b/tests/FSharp.Test.Utilities/Compiler.fs @@ -204,6 +204,8 @@ module rec Compiler = with member this.Output = match this with Success o | Failure o -> o member this.RunOutput = this.Output.Output + member this.Compilation = this.Output.Compilation + member this.OutputPath = this.Output.OutputPath type ExecutionPlatform = | Anycpu = 0 @@ -1468,7 +1470,6 @@ Actual: failwith $"Expected imports are different from PDB.\nExpected:\n%A{expectedScope}\nActual:%A{imports}" let private verifySequencePoints (reader: MetadataReader) expectedSequencePoints = - let sequencePoints = [ for sp in reader.MethodDebugInformation do let mdi = reader.GetMethodDebugInformation sp @@ -1480,7 +1481,6 @@ Actual: failwith $"Expected sequence points are different from PDB.\nExpected: %A{expectedSequencePoints}\nActual: %A{sequencePoints}" let private verifyDocuments (reader: MetadataReader) expectedDocuments = - let documents = [ for doc in reader.Documents do if not doc.IsNil then @@ -1819,7 +1819,20 @@ Actual: | _ -> failwith "Cannot check exit code on this run result." result - let private checkOutputInOrder (category: string) (substrings: string list) (selector: ExecutionOutput -> string) (result: CompilationResult) : CompilationResult = + let private getMatch (input: string) (pattern: string) useWildcards= + // Escape special characters and replace wildcards with regex equivalents + if useWildcards then + let input = input.Replace("\r\n", "\n") + let pattern = $"""^{Regex.Escape(pattern).Replace("\\*", ".*").Replace("\\?", ".")}$""" + let m = Regex(pattern, RegexOptions.Multiline).Match(input) + if m.Success then + m.Index + else + -1 + else + input.IndexOf(pattern) + + let private checkOutputInOrderCore useWildcards (category: string) (substrings: string list) (selector: ExecutionOutput -> string) (result: CompilationResult) : CompilationResult = match result.RunOutput with | None -> printfn "Execution output is missing cannot check \"%A\"" category @@ -1827,20 +1840,23 @@ Actual: | Some o -> match o with | ExecutionOutput e -> - let where = selector e + let input = selector e let mutable searchPos = 0 for substring in substrings do - match where.IndexOf(substring, searchPos) with - | -1 -> failwith (sprintf "\nThe following substring:\n %A\nwas not found in the %A\nOutput:\n %A" substring category where) + match getMatch (input.Substring(searchPos)) substring useWildcards with + | -1 -> failwith (sprintf "\nThe following substring:\n %A\nwas not found in the %A\nOutput:\n %A" substring category input) | pos -> searchPos <- pos + substring.Length | _ -> failwith "Cannot check output on this run result." result + let private checkOutputInOrder category substrings selector result = + checkOutputInOrderCore false category substrings selector result + let withOutputContainsAllInOrder (substrings: string list) (result: CompilationResult) : CompilationResult = checkOutputInOrder "STDERR/STDOUT" substrings (fun o -> o.StdOut + "\n" + o.StdErr) result let withStdOutContains (substring: string) (result: CompilationResult) : CompilationResult = - checkOutputInOrder "STDOUT" [substring] (fun o -> o.StdOut) result + checkOutputInOrder "STDOUT" [substring] (fun o -> o.StdOut) result let withStdOutContainsAllInOrder (substrings: string list) (result: CompilationResult) : CompilationResult = checkOutputInOrder "STDOUT" substrings (fun o -> o.StdOut) result @@ -1851,6 +1867,24 @@ Actual: let withStdErrContains (substring: string) (result: CompilationResult) : CompilationResult = checkOutputInOrder "STDERR" [substring] (fun o -> o.StdErr) result + let private checkOutputInOrderWithWildcards category substrings selector result = + checkOutputInOrderCore true category substrings selector result + + let withOutputContainsAllInOrderWithWildcards (substrings: string list) (result: CompilationResult) : CompilationResult = + checkOutputInOrderWithWildcards "STDERR/STDOUT" substrings (fun o -> o.StdOut + "\n" + o.StdErr) result + + let withStdOutContainsWithWildcards (substring: string) (result: CompilationResult) : CompilationResult = + checkOutputInOrderWithWildcards "STDOUT" [substring] (fun o -> o.StdOut) result + + let withStdOutContainsAllInOrderWithWildcards (substrings: string list) (result: CompilationResult) : CompilationResult = + checkOutputInOrderWithWildcards "STDOUT" substrings (fun o -> o.StdOut) result + + let withStdErrContainsAllInOrderWithWildcards (substrings: string list) (result: CompilationResult) : CompilationResult = + checkOutputInOrderWithWildcards "STDERR" substrings (fun o -> o.StdErr) result + + let withStdErrContainsWithWildcards (substring: string) (result: CompilationResult) : CompilationResult = + checkOutputInOrderWithWildcards "STDERR" [substring] (fun o -> o.StdErr) result + let private assertEvalOutput (selector: FsiValue -> 'T) (value: 'T) (result: CompilationResult) : CompilationResult = match result.RunOutput with | None -> failwith "Execution output is missing cannot check value." diff --git a/tests/FSharp.Test.Utilities/CompilerAssert.fs b/tests/FSharp.Test.Utilities/CompilerAssert.fs index cc5fb4c3e9b..0f7baf597fb 100644 --- a/tests/FSharp.Test.Utilities/CompilerAssert.fs +++ b/tests/FSharp.Test.Utilities/CompilerAssert.fs @@ -59,6 +59,8 @@ module AssemblyResolver = match found() with | None -> Unchecked.defaultof | Some name -> Assembly.Load(name) ) + + do addResolver() #endif type ExecutionOutcome = diff --git a/tests/FSharp.Test.Utilities/FSharp.Test.Utilities.fsproj b/tests/FSharp.Test.Utilities/FSharp.Test.Utilities.fsproj index 192783edd57..37c1940b7a9 100644 --- a/tests/FSharp.Test.Utilities/FSharp.Test.Utilities.fsproj +++ b/tests/FSharp.Test.Utilities/FSharp.Test.Utilities.fsproj @@ -40,7 +40,7 @@ - + @@ -106,7 +106,7 @@ - + diff --git a/tests/FSharp.Test.Utilities/ILVerifierModule.fs b/tests/FSharp.Test.Utilities/ILVerifierModule.fs new file mode 100644 index 00000000000..8610476f217 --- /dev/null +++ b/tests/FSharp.Test.Utilities/ILVerifierModule.fs @@ -0,0 +1,78 @@ +// Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information. +namespace FSharp.Test + +open FSharp.Test.Compiler +open System +open System.IO +open TestFramework + +[] +module ILVerifierModule = + let config = initializeSuite () + + let fsharpCoreReference = $"--reference \"{typeof.Assembly.Location}\"" + + let private systemDllReferences = + // Get the path containing mecorlib.dll or System.Core.Private.dll + let refs = + let systemPath = Path.GetDirectoryName(typeof.Assembly.Location) + DirectoryInfo(systemPath).GetFiles("*.dll") + |> Array.map (fun dll -> $"--reference \"{Path.Combine(systemPath, dll.FullName)}\"") + |> Array.toList + (fsharpCoreReference :: refs) + + let private exec (dotnetExe: string) args workingDirectory = + let arguments = args |> String.concat " " + let exitCode, _output, errors = Commands.executeProcess dotnetExe arguments workingDirectory + let errors = errors |> String.concat Environment.NewLine + errors, exitCode + + let private verifyPEFileCore peverifierArgs (dllFilePath: string) = + let nuget_packages = + match Environment.GetEnvironmentVariable("NUGET_PACKAGES") with + | null -> + let profile = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile) + $"""{profile}/.nuget/packages""" + | path -> path + let peverifyFullArgs = [ yield "exec"; yield $"""{nuget_packages}/dotnet-ilverify/9.0.0/tools/net9.0/any/ILVerify.dll"""; yield "--verbose"; yield dllFilePath; yield! peverifierArgs ] + let workingDirectory = Path.GetDirectoryName dllFilePath + let _, exitCode = + let peverifierCommandPath = Path.ChangeExtension(dllFilePath, ".peverifierCommandPath.cmd") + let args = peverifyFullArgs |> Seq.fold(fun a acc -> $"{a} " + acc) "" + File.WriteAllLines(peverifierCommandPath, [| $"{args}" |] ) + File.Copy(typeof.Assembly.Location, Path.GetDirectoryName(dllFilePath) ++ "FSharp.Core.dll", true) + exec config.DotNetExe peverifyFullArgs workingDirectory + + // Grab output + let outputText = File.ReadAllText(Path.Combine(workingDirectory, "StandardOutput.txt")) + let errorText = File.ReadAllText(Path.Combine(workingDirectory, "StandardError.txt")) + + match exitCode with + | 0 -> {Outcome = NoExitCode; StdOut = outputText; StdErr = errorText } + | _ -> {Outcome = ExitCode exitCode; StdOut = outputText; StdErr = errorText } + + let private verifyPEFileAux (compilationResult: CompilationResult) args = + let result = + match compilationResult.Compilation with + | FS _ -> + match compilationResult, compilationResult.OutputPath with + | CompilationResult.Success result, Some name -> + let verifyResult = verifyPEFileCore args name + match verifyResult.Outcome with + | NoExitCode -> CompilationResult.Success {result with Output = Some (ExecutionOutput verifyResult)} + | ExitCode _ -> CompilationResult.Failure {result with Output = Some (ExecutionOutput verifyResult)} + | failed -> failwith $"Compilation must succeed in order to verify IL.{failed}" + | failed -> + failwith $"""Compilation must succeed in order to verify IL.{failed}""" + | _ -> + failwith "PEVerify is only supported for F#." + result + + let verifyPEFile compilationResult = + verifyPEFileAux compilationResult [| fsharpCoreReference |] + + let verifyPEFileWithArgs compilationResult args = + verifyPEFileAux compilationResult (fsharpCoreReference :: args) + + let verifyPEFileWithSystemDlls compilationResult = + verifyPEFileAux compilationResult systemDllReferences diff --git a/tests/FSharp.Test.Utilities/Peverifier.fs b/tests/FSharp.Test.Utilities/Peverifier.fs deleted file mode 100644 index 0591a435484..00000000000 --- a/tests/FSharp.Test.Utilities/Peverifier.fs +++ /dev/null @@ -1,80 +0,0 @@ -// Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information. -namespace FSharp.Test - -open FSharp.Test.Compiler -open System -open System.IO -open TestFramework - -type PEVerifyOutput = - { - ExitCode: int - Lines: string array - } - -[] -type PEVerifyResult = - | Success of PEVerifyOutput - | Failure of PEVerifyOutput - -[] -module PEVerifier = - - let config = initializeSuite () - - let private exec exe args = - let arguments = args |> String.concat " " - let exitCode, _output, errors = Commands.executeProcess exe arguments "" - let errors = errors |> String.concat Environment.NewLine - errors, exitCode - - let private verifyPEFileCore peverifierArgs dllFilePath = - let mutable errors = ResizeArray () - let peverifierPath = config.PEVERIFY - let peverifyFullArgs = [ yield dllFilePath; yield "/NOLOGO"; yield! peverifierArgs ] - let stdErr, exitCode = - let peverifierCommandPath = Path.ChangeExtension(dllFilePath, ".peverifierCommandPath") - File.WriteAllLines(peverifierCommandPath, [| $"{peverifierPath} {peverifyFullArgs}" |] ) - File.Copy(typeof.Assembly.Location, Path.GetDirectoryName(dllFilePath) ++ "FSharp.Core.dll", true) - exec peverifierPath peverifyFullArgs - - if exitCode <> 0 then - errors.Add (sprintf "PEVERIFIER failed with error code: %d" exitCode) - - if not (String.IsNullOrWhiteSpace stdErr) then - errors.Add (sprintf "PEVERIFIER stderr is not empty:\n %s" stdErr) - - let error = { ExitCode=exitCode; Lines = errors.ToArray() } - - match errors.Count with - | 0 -> PEVerifyResult.Success error - | _ -> PEVerifyResult.Failure error - - let private verifyPEFileAux cUnit args = - let result = - match cUnit with - | FS fs -> - match compile cUnit, fs.OutputFileName with - | CompilationResult.Success _, Some name -> - verifyPEFileCore args name - | failed -> - failwith $"""Compilation must succeed in order to verify IL.{failed}""" - | _ -> - failwith "PEVerify is only supported for F#." - result - - let verifyPEFile cUnit = - verifyPEFileAux cUnit [||] - - let verifyPEFileWithArgs cUnit args = - verifyPEFileCore cUnit args - - let shouldFail result = - match result with - | PEVerifyResult.Success _ -> failwith $"Expected to Fail - {result}" - | PEVerifyResult.Failure _ -> () - - let shouldSucceed result = - match result with - | PEVerifyResult.Success _ -> () - | PEVerifyResult.Failure _ -> failwith $"Expected to Succeed - {result}" diff --git a/tests/FSharp.Test.Utilities/TestFramework.fs b/tests/FSharp.Test.Utilities/TestFramework.fs index 38976846a4a..06b454005c2 100644 --- a/tests/FSharp.Test.Utilities/TestFramework.fs +++ b/tests/FSharp.Test.Utilities/TestFramework.fs @@ -14,12 +14,12 @@ let getShortId() = Guid.NewGuid().ToString().[..7] // Temporary directory is TempPath + "/FSharp.Test.Utilities/xxxxxxx/" let tempDirectoryOfThisTestRun = - let temp = Path.GetTempPath() - lazy DirectoryInfo(temp).CreateSubdirectory($"FSharp.Test.Utilities/{getShortId()}") + let temp = DirectoryInfo(Path.Combine(__SOURCE_DIRECTORY__, @"../../artifacts/Temp/FSharp.Test.Utilities", $"{getShortId()}")) + lazy (temp.Create(); temp) let cleanUpTemporaryDirectoryOfThisTestRun () = if tempDirectoryOfThisTestRun.IsValueCreated then - try tempDirectoryOfThisTestRun.Value.Delete(true) with _ -> () + ()//try tempDirectoryOfThisTestRun.Value.Delete(true) with _ -> () let createTemporaryDirectory () = tempDirectoryOfThisTestRun.Value @@ -87,10 +87,13 @@ module Commands = psi.RedirectStandardError <- true psi.Arguments <- arguments psi.CreateNoWindow <- true + // When running tests, we want to roll forward to minor versions (including previews). psi.EnvironmentVariables["DOTNET_ROLL_FORWARD"] <- "LatestMajor" psi.EnvironmentVariables["DOTNET_ROLL_FORWARD_TO_PRERELEASE"] <- "1" - psi.EnvironmentVariables.Remove("MSBuildSDKsPath") // Host can sometimes add this, and it can break things + + // Host can sometimes add this, and it can break things + psi.EnvironmentVariables.Remove("MSBuildSDKsPath") psi.UseShellExecute <- false use p = new Process() @@ -103,7 +106,7 @@ module Commands = p.BeginOutputReadLine() p.BeginErrorReadLine() p.WaitForExit() -#if DEBUG + let workingDir' = if workingDir = "" then @@ -118,7 +121,6 @@ module Commands = File.WriteAllLines(Path.Combine(workingDir', "StandardOutput.txt"), outputList) File.WriteAllLines(Path.Combine(workingDir', "StandardError.txt"), errorsList) ) -#endif p.ExitCode, outputList.ToArray(), errorsList.ToArray() let getfullpath workDir (path:string) = @@ -329,7 +331,7 @@ let config configurationName envVars = let ILASM_EXE = if operatingSystem = "win" then "ilasm.exe" else "ilasm" let ILASM = requirePackage (("runtime." + operatingSystem + "-" + architectureMoniker + ".Microsoft.NETCore.ILAsm") ++ coreClrRuntimePackageVersion ++ "runtimes" ++ (operatingSystem + "-" + architectureMoniker) ++ "native" ++ ILASM_EXE) //let PEVERIFY_EXE = if operatingSystem = "win" then "PEVerify.exe" elif operatingSystem = "osx" then "PEVerify.dll" else "PEVerify" - let PEVERIFY = "dummy" //requireArtifact ("PEVerify" ++ configurationName ++ peverifyArchitecture ++ PEVERIFY_EXE) + let PEVERIFY = "ilverify" //requireArtifact ("PEVerify" ++ configurationName ++ peverifyArchitecture ++ PEVERIFY_EXE) // let FSI_FOR_SCRIPTS = artifactsBinPath ++ "fsi" ++ configurationName ++ fsiArchitecture ++ "fsi.exe" let FSharpBuild = requireArtifact ("FSharp.Build" ++ configurationName ++ fsharpBuildArchitecture ++ "FSharp.Build.dll") let FSharpCompilerInteractiveSettings = requireArtifact ("FSharp.Compiler.Interactive.Settings" ++ configurationName ++ fsharpCompilerInteractiveSettingsArchitecture ++ "FSharp.Compiler.Interactive.Settings.dll") diff --git a/tests/ILVerify/ilverify_FSharp.Compiler.Service_Debug_net9.0.bsl b/tests/ILVerify/ilverify_FSharp.Compiler.Service_Debug_net9.0.bsl index d301673c927..41e393f5f30 100644 --- a/tests/ILVerify/ilverify_FSharp.Compiler.Service_Debug_net9.0.bsl +++ b/tests/ILVerify/ilverify_FSharp.Compiler.Service_Debug_net9.0.bsl @@ -71,20 +71,3 @@ [IL]: Error [StackUnexpected]: : FSharp.Compiler.IO.FileSystemUtils::trimQuotes(string)][offset 0x00000014][found Char] Unexpected type on the stack. [IL]: Error [StackUnexpected]: : Internal.Utilities.Library.String::lowerCaseFirstChar(string)][offset 0x0000003F][found Char] Unexpected type on the stack. [IL]: Error [StackUnexpected]: : Internal.Utilities.Library.Array+loop@276-4::Invoke(int32)][offset 0x00000012][found Byte] Unexpected type on the stack. -[IL]: Error [StackUnexpected]: : Microsoft.FSharp.Collections.ArrayModule+Parallel::Choose([FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2>, !!0[])][offset 0x000000A0][found Byte] Unexpected type on the stack. -[IL]: Error [StackUnexpected]: : Microsoft.FSharp.Collections.ArrayModule+Parallel::Filter([FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2, !!0[])][offset 0x00000029][found Byte] Unexpected type on the stack. -[IL]: Error [StackUnexpected]: : Microsoft.FSharp.Collections.ArrayModule+Parallel::Partition([FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2, !!0[])][offset 0x00000038][found Byte] Unexpected type on the stack. -[IL]: Error [StackUnexpected]: : Microsoft.FSharp.Collections.ArrayModule+Parallel+Pipe #2 input at line 2241@2245-1::Invoke(int32, [System.Threading.Tasks.Parallel]System.Threading.Tasks.ParallelLoopState, int32)][offset 0x00000030][found Boolean] Unexpected type on the stack. -[IL]: Error [StackUnexpected]: : Microsoft.FSharp.Collections.ArrayModule+Parallel+Pipe #2 input at line 2571@2575-1::Invoke(int32, [System.Threading.Tasks.Parallel]System.Threading.Tasks.ParallelLoopState, int32)][offset 0x00000022][found Boolean] Unexpected type on the stack. -[IL]: Error [StackUnexpected]: : Microsoft.FSharp.Core.StringModule::Map([FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2, string)][offset 0x00000020][found Short] Unexpected type on the stack. -[IL]: Error [StackUnexpected]: : Microsoft.FSharp.Core.StringModule::Map([FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2, string)][offset 0x00000031][found Char] Unexpected type on the stack. -[IL]: Error [StackUnexpected]: : Microsoft.FSharp.Core.StringModule::MapIndexed([FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2>, string)][offset 0x00000029][found Short] Unexpected type on the stack. -[IL]: Error [StackUnexpected]: : Microsoft.FSharp.Core.StringModule::MapIndexed([FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2>, string)][offset 0x00000033][found Char] Unexpected type on the stack. -[IL]: Error [StackUnexpected]: : Microsoft.FSharp.Core.StringModule::Filter([FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2, string)][offset 0x00000075][found Char] Unexpected type on the stack. -[IL]: Error [StackUnexpected]: : Microsoft.FSharp.Core.Operators::castToString(!!0)][offset 0x00000001][found value 'T'][expected ref 'string'] Unexpected type on the stack. -[IL]: Error [StackUnexpected]: : Microsoft.FSharp.Core.LanguagePrimitives::retype(!!0)][offset 0x00000001][found value 'T'][expected value 'TResult'] Unexpected type on the stack. -[IL]: Error [StackUnexpected]: : Microsoft.FSharp.Core.LanguagePrimitives+HashCompare::GenericEqualityCharArray(char[], char[])][offset 0x0000001C][found Short] Unexpected type on the stack. -[IL]: Error [StackUnexpected]: : Microsoft.FSharp.Core.LanguagePrimitives+HashCompare::GenericEqualityCharArray(char[], char[])][offset 0x00000023][found Short] Unexpected type on the stack. -[IL]: Error [StackUnexpected]: : Microsoft.FSharp.Core.BasicInlinedOperations::castclassPrim(object)][offset 0x00000006][found ref 'T'][expected value 'T'] Unexpected type on the stack. -[IL]: Error [StackUnexpected]: : Microsoft.FSharp.Core.BasicInlinedOperations::notnullPrim(!!0)][offset 0x00000002][found Nullobjref 'NullReference'][expected value 'T'] Unexpected type on the stack. -[IL]: Error [StackUnexpected]: : Microsoft.FSharp.Core.BasicInlinedOperations::iscastPrim(object)][offset 0x00000006][found ref 'T'][expected value 'T'] Unexpected type on the stack. diff --git a/tests/ILVerify/ilverify_FSharp.Compiler.Service_Debug_netstandard2.0.bsl b/tests/ILVerify/ilverify_FSharp.Compiler.Service_Debug_netstandard2.0.bsl index 81cc143b139..23bfed609bb 100644 --- a/tests/ILVerify/ilverify_FSharp.Compiler.Service_Debug_netstandard2.0.bsl +++ b/tests/ILVerify/ilverify_FSharp.Compiler.Service_Debug_netstandard2.0.bsl @@ -96,20 +96,3 @@ [IL]: Error [StackUnexpected]: : FSharp.Compiler.IO.FileSystemUtils::trimQuotes(string)][offset 0x00000014][found Char] Unexpected type on the stack. [IL]: Error [StackUnexpected]: : Internal.Utilities.Library.String::lowerCaseFirstChar(string)][offset 0x0000003F][found Char] Unexpected type on the stack. [IL]: Error [StackUnexpected]: : Internal.Utilities.Library.Array+loop@276-4::Invoke(int32)][offset 0x00000012][found Byte] Unexpected type on the stack. -[IL]: Error [StackUnexpected]: : Microsoft.FSharp.Collections.ArrayModule+Parallel::Choose([FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2>, !!0[])][offset 0x000000A0][found Byte] Unexpected type on the stack. -[IL]: Error [StackUnexpected]: : Microsoft.FSharp.Collections.ArrayModule+Parallel::Filter([FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2, !!0[])][offset 0x00000029][found Byte] Unexpected type on the stack. -[IL]: Error [StackUnexpected]: : Microsoft.FSharp.Collections.ArrayModule+Parallel::Partition([FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2, !!0[])][offset 0x00000038][found Byte] Unexpected type on the stack. -[IL]: Error [StackUnexpected]: : Microsoft.FSharp.Collections.ArrayModule+Parallel+Pipe #2 input at line 2241@2245-1::Invoke(int32, [System.Threading.Tasks.Parallel]System.Threading.Tasks.ParallelLoopState, int32)][offset 0x00000030][found Boolean] Unexpected type on the stack. -[IL]: Error [StackUnexpected]: : Microsoft.FSharp.Collections.ArrayModule+Parallel+Pipe #2 input at line 2571@2575-1::Invoke(int32, [System.Threading.Tasks.Parallel]System.Threading.Tasks.ParallelLoopState, int32)][offset 0x00000022][found Boolean] Unexpected type on the stack. -[IL]: Error [StackUnexpected]: : Microsoft.FSharp.Core.StringModule::Map([FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2, string)][offset 0x00000020][found Short] Unexpected type on the stack. -[IL]: Error [StackUnexpected]: : Microsoft.FSharp.Core.StringModule::Map([FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2, string)][offset 0x00000031][found Char] Unexpected type on the stack. -[IL]: Error [StackUnexpected]: : Microsoft.FSharp.Core.StringModule::MapIndexed([FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2>, string)][offset 0x00000029][found Short] Unexpected type on the stack. -[IL]: Error [StackUnexpected]: : Microsoft.FSharp.Core.StringModule::MapIndexed([FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2>, string)][offset 0x00000033][found Char] Unexpected type on the stack. -[IL]: Error [StackUnexpected]: : Microsoft.FSharp.Core.StringModule::Filter([FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2, string)][offset 0x00000075][found Char] Unexpected type on the stack. -[IL]: Error [StackUnexpected]: : Microsoft.FSharp.Core.Operators::castToString(!!0)][offset 0x00000001][found value 'T'][expected ref 'string'] Unexpected type on the stack. -[IL]: Error [StackUnexpected]: : Microsoft.FSharp.Core.LanguagePrimitives::retype(!!0)][offset 0x00000001][found value 'T'][expected value 'TResult'] Unexpected type on the stack. -[IL]: Error [StackUnexpected]: : Microsoft.FSharp.Core.LanguagePrimitives+HashCompare::GenericEqualityCharArray(char[], char[])][offset 0x0000001C][found Short] Unexpected type on the stack. -[IL]: Error [StackUnexpected]: : Microsoft.FSharp.Core.LanguagePrimitives+HashCompare::GenericEqualityCharArray(char[], char[])][offset 0x00000023][found Short] Unexpected type on the stack. -[IL]: Error [StackUnexpected]: : Microsoft.FSharp.Core.BasicInlinedOperations::castclassPrim(object)][offset 0x00000006][found ref 'T'][expected value 'T'] Unexpected type on the stack. -[IL]: Error [StackUnexpected]: : Microsoft.FSharp.Core.BasicInlinedOperations::notnullPrim(!!0)][offset 0x00000002][found Nullobjref 'NullReference'][expected value 'T'] Unexpected type on the stack. -[IL]: Error [StackUnexpected]: : Microsoft.FSharp.Core.BasicInlinedOperations::iscastPrim(object)][offset 0x00000006][found ref 'T'][expected value 'T'] Unexpected type on the stack. diff --git a/tests/ILVerify/ilverify_FSharp.Compiler.Service_Release_net9.0.bsl b/tests/ILVerify/ilverify_FSharp.Compiler.Service_Release_net9.0.bsl index 8c2b6a97465..d1ac4690f8b 100644 --- a/tests/ILVerify/ilverify_FSharp.Compiler.Service_Release_net9.0.bsl +++ b/tests/ILVerify/ilverify_FSharp.Compiler.Service_Release_net9.0.bsl @@ -97,15 +97,3 @@ [IL]: Error [StackUnexpected]: : FSharp.Compiler.IO.FileSystemUtils::trimQuotes(string)][offset 0x00000014][found Char] Unexpected type on the stack. [IL]: Error [StackUnexpected]: : Internal.Utilities.Library.String::lowerCaseFirstChar(string)][offset 0x0000003A][found Char] Unexpected type on the stack. [IL]: Error [StackUnexpected]: : Internal.Utilities.Library.Array::loop@275-3(bool[], int32)][offset 0x00000008][found Byte] Unexpected type on the stack. -[IL]: Error [StackUnexpected]: : Microsoft.FSharp.Collections.ArrayModule+Parallel::Choose([FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2>, !!0[])][offset 0x00000081][found Byte] Unexpected type on the stack. -[IL]: Error [StackUnexpected]: : Microsoft.FSharp.Collections.ArrayModule+Parallel::Filter([FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2, !!0[])][offset 0x00000029][found Byte] Unexpected type on the stack. -[IL]: Error [StackUnexpected]: : Microsoft.FSharp.Collections.ArrayModule+Parallel::Partition([FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2, !!0[])][offset 0x00000038][found Byte] Unexpected type on the stack. -[IL]: Error [StackUnexpected]: : Microsoft.FSharp.Collections.ArrayModule+Parallel+Choose@2245-2::Invoke(int32, [System.Threading.Tasks.Parallel]System.Threading.Tasks.ParallelLoopState, int32)][offset 0x00000030][found Boolean] Unexpected type on the stack. -[IL]: Error [StackUnexpected]: : Microsoft.FSharp.Collections.ArrayModule+Parallel+countAndCollectTrueItems@2575-1::Invoke(int32, [System.Threading.Tasks.Parallel]System.Threading.Tasks.ParallelLoopState, int32)][offset 0x00000022][found Boolean] Unexpected type on the stack. -[IL]: Error [StackUnexpected]: : Microsoft.FSharp.Core.StringModule::Map([FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2, string)][offset 0x0000001E][found Short] Unexpected type on the stack. -[IL]: Error [StackUnexpected]: : Microsoft.FSharp.Core.StringModule::Map([FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2, string)][offset 0x0000002D][found Char] Unexpected type on the stack. -[IL]: Error [StackUnexpected]: : Microsoft.FSharp.Core.StringModule::MapIndexed([FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2>, string)][offset 0x00000029][found Short] Unexpected type on the stack. -[IL]: Error [StackUnexpected]: : Microsoft.FSharp.Core.StringModule::MapIndexed([FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2>, string)][offset 0x00000033][found Char] Unexpected type on the stack. -[IL]: Error [StackUnexpected]: : Microsoft.FSharp.Core.StringModule::Filter([FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2, string)][offset 0x0000006C][found Char] Unexpected type on the stack. -[IL]: Error [StackUnexpected]: : Microsoft.FSharp.Core.LanguagePrimitives+HashCompare::GenericEqualityCharArray(char[], char[])][offset 0x0000001C][found Short] Unexpected type on the stack. -[IL]: Error [StackUnexpected]: : Microsoft.FSharp.Core.LanguagePrimitives+HashCompare::GenericEqualityCharArray(char[], char[])][offset 0x00000023][found Short] Unexpected type on the stack. diff --git a/tests/ILVerify/ilverify_FSharp.Compiler.Service_Release_netstandard2.0.bsl b/tests/ILVerify/ilverify_FSharp.Compiler.Service_Release_netstandard2.0.bsl index 588f29f5a96..15bc7aba394 100644 --- a/tests/ILVerify/ilverify_FSharp.Compiler.Service_Release_netstandard2.0.bsl +++ b/tests/ILVerify/ilverify_FSharp.Compiler.Service_Release_netstandard2.0.bsl @@ -123,15 +123,3 @@ [IL]: Error [StackUnexpected]: : FSharp.Compiler.IO.FileSystemUtils::trimQuotes(string)][offset 0x00000014][found Char] Unexpected type on the stack. [IL]: Error [StackUnexpected]: : Internal.Utilities.Library.String::lowerCaseFirstChar(string)][offset 0x0000003A][found Char] Unexpected type on the stack. [IL]: Error [StackUnexpected]: : Internal.Utilities.Library.Array::loop@275-3(bool[], int32)][offset 0x00000008][found Byte] Unexpected type on the stack. -[IL]: Error [StackUnexpected]: : Microsoft.FSharp.Collections.ArrayModule+Parallel::Choose([FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2>, !!0[])][offset 0x00000081][found Byte] Unexpected type on the stack. -[IL]: Error [StackUnexpected]: : Microsoft.FSharp.Collections.ArrayModule+Parallel::Filter([FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2, !!0[])][offset 0x00000029][found Byte] Unexpected type on the stack. -[IL]: Error [StackUnexpected]: : Microsoft.FSharp.Collections.ArrayModule+Parallel::Partition([FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2, !!0[])][offset 0x00000038][found Byte] Unexpected type on the stack. -[IL]: Error [StackUnexpected]: : Microsoft.FSharp.Collections.ArrayModule+Parallel+Choose@2245-2::Invoke(int32, [System.Threading.Tasks.Parallel]System.Threading.Tasks.ParallelLoopState, int32)][offset 0x00000030][found Boolean] Unexpected type on the stack. -[IL]: Error [StackUnexpected]: : Microsoft.FSharp.Collections.ArrayModule+Parallel+countAndCollectTrueItems@2575-1::Invoke(int32, [System.Threading.Tasks.Parallel]System.Threading.Tasks.ParallelLoopState, int32)][offset 0x00000022][found Boolean] Unexpected type on the stack. -[IL]: Error [StackUnexpected]: : Microsoft.FSharp.Core.StringModule::Map([FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2, string)][offset 0x0000001E][found Short] Unexpected type on the stack. -[IL]: Error [StackUnexpected]: : Microsoft.FSharp.Core.StringModule::Map([FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2, string)][offset 0x0000002D][found Char] Unexpected type on the stack. -[IL]: Error [StackUnexpected]: : Microsoft.FSharp.Core.StringModule::MapIndexed([FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2>, string)][offset 0x00000029][found Short] Unexpected type on the stack. -[IL]: Error [StackUnexpected]: : Microsoft.FSharp.Core.StringModule::MapIndexed([FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2>, string)][offset 0x00000033][found Char] Unexpected type on the stack. -[IL]: Error [StackUnexpected]: : Microsoft.FSharp.Core.StringModule::Filter([FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2, string)][offset 0x0000006C][found Char] Unexpected type on the stack. -[IL]: Error [StackUnexpected]: : Microsoft.FSharp.Core.LanguagePrimitives+HashCompare::GenericEqualityCharArray(char[], char[])][offset 0x0000001C][found Short] Unexpected type on the stack. -[IL]: Error [StackUnexpected]: : Microsoft.FSharp.Core.LanguagePrimitives+HashCompare::GenericEqualityCharArray(char[], char[])][offset 0x00000023][found Short] Unexpected type on the stack. From afb15f068045802ae0155e003562d44c185b76bc Mon Sep 17 00:00:00 2001 From: Jakub Majocha <1760221+majocha@users.noreply.github.com> Date: Wed, 29 Jan 2025 14:00:24 +0100 Subject: [PATCH 02/29] remove redundant ifdef (#18284) --- src/Compiler/TypedTree/TypeProviders.fs | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/src/Compiler/TypedTree/TypeProviders.fs b/src/Compiler/TypedTree/TypeProviders.fs index be22209a27a..acef34047ca 100644 --- a/src/Compiler/TypedTree/TypeProviders.fs +++ b/src/Compiler/TypedTree/TypeProviders.fs @@ -122,7 +122,6 @@ let CreateTypeProvider ( // Create the TypeProviderConfig to pass to the type provider constructor let e = -#if FSHARPCORE_USE_PACKAGE TypeProviderConfig(systemRuntimeContainsType, ReferencedAssemblies=getReferencedAssemblies(), ResolutionFolder=resolutionEnvironment.ResolutionFolder, @@ -131,16 +130,7 @@ let CreateTypeProvider ( IsInvalidationSupported=isInvalidationSupported, IsHostedExecution= isInteractive, SystemRuntimeAssemblyVersion = systemRuntimeAssemblyVersion) -#else - TypeProviderConfig(systemRuntimeContainsType, - ReferencedAssemblies=getReferencedAssemblies(), - ResolutionFolder=resolutionEnvironment.ResolutionFolder, - RuntimeAssembly=runtimeAssemblyPath, - TemporaryFolder=resolutionEnvironment.TemporaryFolder, - IsInvalidationSupported=isInvalidationSupported, - IsHostedExecution= isInteractive, - SystemRuntimeAssemblyVersion = systemRuntimeAssemblyVersion) -#endif + protect (fun () -> !!(Activator.CreateInstance(typeProviderImplementationType, [| box e|])) :?> ITypeProvider ) elif not(isNull(typeProviderImplementationType.GetConstructor [| |])) then From 58560f8ce35a691415e10dd2b0189322d21afdfc Mon Sep 17 00:00:00 2001 From: Eugene Auduchinok Date: Wed, 29 Jan 2025 22:24:03 +0900 Subject: [PATCH 03/29] Cancellable: only cancel on OCE with own token (#18277) --- docs/release-notes/.FSharp.Compiler.Service/9.0.300.md | 1 + src/Compiler/Checking/CheckDeclarations.fs | 2 +- src/Compiler/Utilities/Cancellable.fs | 5 +++-- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/docs/release-notes/.FSharp.Compiler.Service/9.0.300.md b/docs/release-notes/.FSharp.Compiler.Service/9.0.300.md index 52b92207001..5c444bd4fd3 100644 --- a/docs/release-notes/.FSharp.Compiler.Service/9.0.300.md +++ b/docs/release-notes/.FSharp.Compiler.Service/9.0.300.md @@ -2,6 +2,7 @@ * Fix Realsig+ generates nested closures with incorrect Generic ([Issue #17797](https://github.com/dotnet/fsharp/issues/17797), [PR #17877](https://github.com/dotnet/fsharp/pull/17877)) * Fix internal error when missing measure attribute in an unsolved measure typar. ([Issue #7491](https://github.com/dotnet/fsharp/issues/7491), [PR #18234](https://github.com/dotnet/fsharp/pull/18234)== * Set `Cancellable.token` from async computation ([Issue #18235](https://github.com/dotnet/fsharp/issues/18235), [PR #18238](https://github.com/dotnet/fsharp/pull/18238)) +* Cancellable: only cancel on OCE with own token ([PR #18277](https://github.com/dotnet/fsharp/pull/18277)) ### Added * Added missing type constraints in FCS. ([PR #18241](https://github.com/dotnet/fsharp/pull/18241)) diff --git a/src/Compiler/Checking/CheckDeclarations.fs b/src/Compiler/Checking/CheckDeclarations.fs index 23c547b36b8..af3e712a8db 100644 --- a/src/Compiler/Checking/CheckDeclarations.fs +++ b/src/Compiler/Checking/CheckDeclarations.fs @@ -5479,7 +5479,7 @@ let rec TcModuleOrNamespaceElementNonMutRec (cenv: cenv) parent typeNames scopem and [] TcModuleOrNamespaceElementsNonMutRec cenv parent typeNames endm (defsSoFar, env, envAtEnd) (moreDefs: SynModuleDecl list) (ct: CancellationToken) = if ct.IsCancellationRequested then - ValueOrCancelled.Cancelled (OperationCanceledException()) + ValueOrCancelled.Cancelled(OperationCanceledException ct) else match moreDefs with | [] -> diff --git a/src/Compiler/Utilities/Cancellable.fs b/src/Compiler/Utilities/Cancellable.fs index 9ec81438ca4..ad739b5039e 100644 --- a/src/Compiler/Utilities/Cancellable.fs +++ b/src/Compiler/Utilities/Cancellable.fs @@ -68,8 +68,9 @@ module Cancellable = try use _ = Cancellable.UsingToken(ct) oper ct - with :? OperationCanceledException as e -> - ValueOrCancelled.Cancelled(OperationCanceledException e.CancellationToken) + with + | :? OperationCanceledException as e when ct.IsCancellationRequested -> ValueOrCancelled.Cancelled e + | :? OperationCanceledException as e -> InvalidOperationException("Wrong cancellation token", e) |> raise let fold f acc seq = Cancellable(fun ct -> From 5b910afd674f62377d3c054dd1709201378dc7ed Mon Sep 17 00:00:00 2001 From: Tomas Grosup Date: Mon, 3 Feb 2025 13:27:52 +0100 Subject: [PATCH 04/29] Bugfix :: Fix optimizer bug where field.Index included compiler generated static fields (#18280) * Fix optimizer bug where field.Index included compiler generated static fields * notes added --- .../.FSharp.Compiler.Service/9.0.300.md | 1 + src/Compiler/TypedTree/TypedTree.fs | 20 ++++++++++++++----- .../StaticLet/RecordOptimizerRegression.fs | 14 +++++++++++++ .../StaticLet/StaticLetInUnionsAndRecords.fs | 10 ++++++++++ 4 files changed, 40 insertions(+), 5 deletions(-) create mode 100644 tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/StaticLet/RecordOptimizerRegression.fs diff --git a/docs/release-notes/.FSharp.Compiler.Service/9.0.300.md b/docs/release-notes/.FSharp.Compiler.Service/9.0.300.md index 5c444bd4fd3..e3beae168a3 100644 --- a/docs/release-notes/.FSharp.Compiler.Service/9.0.300.md +++ b/docs/release-notes/.FSharp.Compiler.Service/9.0.300.md @@ -1,5 +1,6 @@ ### Fixed * Fix Realsig+ generates nested closures with incorrect Generic ([Issue #17797](https://github.com/dotnet/fsharp/issues/17797), [PR #17877](https://github.com/dotnet/fsharp/pull/17877)) +* Fix optimizer internal error for records with static fields ([Issue #18165](https://github.com/dotnet/fsharp/issues/18165), [PR #18280](https://github.com/dotnet/fsharp/pull/18280)) * Fix internal error when missing measure attribute in an unsolved measure typar. ([Issue #7491](https://github.com/dotnet/fsharp/issues/7491), [PR #18234](https://github.com/dotnet/fsharp/pull/18234)== * Set `Cancellable.token` from async computation ([Issue #18235](https://github.com/dotnet/fsharp/issues/18235), [PR #18238](https://github.com/dotnet/fsharp/pull/18238)) * Cancellable: only cancel on OCE with own token ([PR #18277](https://github.com/dotnet/fsharp/pull/18277)) diff --git a/src/Compiler/TypedTree/TypedTree.fs b/src/Compiler/TypedTree/TypedTree.fs index d2af320b8de..27e80d396be 100644 --- a/src/Compiler/TypedTree/TypedTree.fs +++ b/src/Compiler/TypedTree/TypedTree.fs @@ -4273,6 +4273,19 @@ type UnionCaseRef = override x.ToString() = x.CaseName +let findLogicalFieldIndexOfRecordField (tcref:TyconRef) (id:string) = + let arr = tcref.AllFieldsArray + + // We are skipping compiler generated fields such as "init@5" from index calculation + let rec go originalIdx skippedItems = + if originalIdx >= arr.Length then error(InternalError(sprintf "field %s not found in type %s" id tcref.LogicalName, tcref.Range)) + else + let currentItem = arr[originalIdx] + if currentItem.LogicalName = id then (originalIdx-skippedItems) + else go (originalIdx + 1) (skippedItems + (if currentItem.IsCompilerGenerated && currentItem.IsStatic then 1 else 0)) + + go 0 0 + /// Represents a reference to a field in a record, class or struct [] type RecdFieldRef = @@ -4316,11 +4329,8 @@ type RecdFieldRef = member x.Index = let (RecdFieldRef(tcref, id)) = x - try - // REVIEW: this could be faster, e.g. by storing the index in the NameMap - tcref.AllFieldsArray |> Array.findIndex (fun rfspec -> rfspec.LogicalName = id) - with :? KeyNotFoundException -> - error(InternalError(sprintf "field %s not found in type %s" id tcref.LogicalName, tcref.Range)) + findLogicalFieldIndexOfRecordField tcref id + [] member x.DebugText = x.ToString() diff --git a/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/StaticLet/RecordOptimizerRegression.fs b/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/StaticLet/RecordOptimizerRegression.fs new file mode 100644 index 00000000000..1ecbe38c6f8 --- /dev/null +++ b/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/StaticLet/RecordOptimizerRegression.fs @@ -0,0 +1,14 @@ +module Test + +// https://github.com/dotnet/fsharp/issues/18165 + +type FooBar = + { xyz : string } + static let staticLet = 1 + +let doThing (foo : FooBar) = + let bar = { foo with xyz = foo.xyz } + let baz = { bar with xyz = bar.xyz } + printf "%O" baz + +doThing { xyz = "" } \ No newline at end of file diff --git a/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/StaticLet/StaticLetInUnionsAndRecords.fs b/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/StaticLet/StaticLetInUnionsAndRecords.fs index 17c7c03c808..5ce43b8db72 100644 --- a/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/StaticLet/StaticLetInUnionsAndRecords.fs +++ b/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/StaticLet/StaticLetInUnionsAndRecords.fs @@ -95,6 +95,16 @@ init R 2 1 2""" +[] +let ``Static let - record optimizer regression`` compilation = + compilation + |> withOptimize + |> verifyCompileAndRun + |> shouldSucceed + |> withStdOutContains """{ xyz = "" }""" + + + [] let ``Static let - lowercase DU`` compilation = compilation From 319504116eba950686f94b74cdcf6bdc8720ecad Mon Sep 17 00:00:00 2001 From: Tomas Grosup Date: Mon, 3 Feb 2025 13:29:14 +0100 Subject: [PATCH 05/29] Bugfix :: Support for 'use' on a nullable IDisposable (#18262) * Support for 'use' on a nullable IDisposable * release notes --- .../.FSharp.Compiler.Service/9.0.300.md | 1 + .../Checking/Expressions/CheckExpressions.fs | 6 +++--- .../Checking/Expressions/CheckExpressionsOps.fs | 2 +- src/Compiler/Optimize/LowerComputedCollections.fs | 2 +- src/Compiler/TypedTree/TcGlobals.fs | 1 + src/Compiler/TypedTree/TcGlobals.fsi | 2 ++ .../Nullness/NullableReferenceTypesTests.fs | 13 +++++++++++++ 7 files changed, 22 insertions(+), 5 deletions(-) diff --git a/docs/release-notes/.FSharp.Compiler.Service/9.0.300.md b/docs/release-notes/.FSharp.Compiler.Service/9.0.300.md index e3beae168a3..859bd0e3c31 100644 --- a/docs/release-notes/.FSharp.Compiler.Service/9.0.300.md +++ b/docs/release-notes/.FSharp.Compiler.Service/9.0.300.md @@ -7,6 +7,7 @@ ### Added * Added missing type constraints in FCS. ([PR #18241](https://github.com/dotnet/fsharp/pull/18241)) +* The 'use' keyword can be used on IDisposable|null without nullness warnings ([PR #18262](https://github.com/dotnet/fsharp/pull/18262)) ### Changed diff --git a/src/Compiler/Checking/Expressions/CheckExpressions.fs b/src/Compiler/Checking/Expressions/CheckExpressions.fs index 9987f02759c..f33c7239063 100644 --- a/src/Compiler/Checking/Expressions/CheckExpressions.fs +++ b/src/Compiler/Checking/Expressions/CheckExpressions.fs @@ -3097,7 +3097,7 @@ let BuildDisposableCleanup (cenv: cenv) env m (v: Val) = else mkUnit g m else - let disposeObjVar, disposeObjExpr = mkCompGenLocal m "objectToDispose" g.system_IDisposable_ty + let disposeObjVar, disposeObjExpr = mkCompGenLocal m "objectToDispose" g.system_IDisposableNull_ty let disposeExpr, _ = BuildPossiblyConditionalMethodCall cenv env PossiblyMutates m false disposeMethod NormalValUse [] [disposeObjExpr] [] None let inputExpr = mkCoerceExpr(exprForVal v.Range v, g.obj_ty_ambivalent, m, v.Type) mkIsInstConditional g m g.system_IDisposable_ty inputExpr disposeObjVar disposeExpr (mkUnit g m) @@ -6811,7 +6811,7 @@ and TcCtorCall isNaked cenv env tpenv (overallTy: OverallTy) objTy mObjTyOpt ite match item, args with | Item.CtorGroup(methodName, minfos), _ -> let meths = List.map (fun minfo -> minfo, None) minfos - if isNaked && TypeFeasiblySubsumesType 0 g cenv.amap mWholeCall g.system_IDisposable_ty NoCoerce objTy then + if isNaked && TypeFeasiblySubsumesType 0 g cenv.amap mWholeCall g.system_IDisposableNull_ty NoCoerce objTy then warning(Error(FSComp.SR.tcIDisposableTypeShouldUseNew(), mWholeCall)) // Check the type is not abstract @@ -11603,7 +11603,7 @@ and TcLetBinding (cenv: cenv) isUse env containerInfo declKind tpenv (synBinds, let isDiscarded = match checkedPat2 with TPat_wild _ -> true | _ -> false let allValsDefinedByPattern = if isDiscarded then [patternInputTmp] else allValsDefinedByPattern (allValsDefinedByPattern, (bodyExpr, bodyExprTy)) ||> List.foldBack (fun v (bodyExpr, bodyExprTy) -> - AddCxTypeMustSubsumeType ContextInfo.NoContext denv cenv.css v.Range NoTrace g.system_IDisposable_ty v.Type + AddCxTypeMustSubsumeType ContextInfo.NoContext denv cenv.css v.Range NoTrace g.system_IDisposableNull_ty v.Type let cleanupE = BuildDisposableCleanup cenv env m v mkTryFinally g (bodyExpr, cleanupE, m, bodyExprTy, DebugPointAtTry.No, DebugPointAtFinally.No), bodyExprTy) else diff --git a/src/Compiler/Checking/Expressions/CheckExpressionsOps.fs b/src/Compiler/Checking/Expressions/CheckExpressionsOps.fs index 17572c86e4f..3552b1345f7 100644 --- a/src/Compiler/Checking/Expressions/CheckExpressionsOps.fs +++ b/src/Compiler/Checking/Expressions/CheckExpressionsOps.fs @@ -297,7 +297,7 @@ let mkSeqEmpty (cenv: TcFileState) env m genTy = let mkSeqUsing (cenv: TcFileState) (env: TcEnv) m resourceTy genTy resourceExpr lam = let g = cenv.g - AddCxTypeMustSubsumeType ContextInfo.NoContext env.DisplayEnv cenv.css m NoTrace g.system_IDisposable_ty resourceTy + AddCxTypeMustSubsumeType ContextInfo.NoContext env.DisplayEnv cenv.css m NoTrace g.system_IDisposableNull_ty resourceTy let genResultTy = NewInferenceType g UnifyTypes cenv env m genTy (mkSeqTy cenv.g genResultTy) mkCallSeqUsing cenv.g m resourceTy genResultTy resourceExpr lam diff --git a/src/Compiler/Optimize/LowerComputedCollections.fs b/src/Compiler/Optimize/LowerComputedCollections.fs index 1f224ea499c..4e74722e1bf 100644 --- a/src/Compiler/Optimize/LowerComputedCollections.fs +++ b/src/Compiler/Optimize/LowerComputedCollections.fs @@ -35,7 +35,7 @@ let BuildDisposableCleanup tcVal (g: TcGlobals) infoReader m (v: Val) = disposeExpr else - let disposeObjVar, disposeObjExpr = mkCompGenLocal m "objectToDispose" g.system_IDisposable_ty + let disposeObjVar, disposeObjExpr = mkCompGenLocal m "objectToDispose" g.system_IDisposableNull_ty let disposeExpr, _ = BuildMethodCall tcVal g infoReader.amap PossiblyMutates m false disposeMethod NormalValUse [] [disposeObjExpr] [] None let inputExpr = mkCoerceExpr(exprForVal v.Range v, g.obj_ty_ambivalent, m, v.Type) mkIsInstConditional g m g.system_IDisposable_ty inputExpr disposeObjVar disposeExpr (mkUnit g m) diff --git a/src/Compiler/TypedTree/TcGlobals.fs b/src/Compiler/TypedTree/TcGlobals.fs index 4f4a45c735e..d8b95566717 100644 --- a/src/Compiler/TypedTree/TcGlobals.fs +++ b/src/Compiler/TypedTree/TcGlobals.fs @@ -1369,6 +1369,7 @@ type TcGlobals( member val system_Array_ty = mkSysNonGenericTy sys "Array" member val system_Object_ty = mkSysNonGenericTy sys "Object" member val system_IDisposable_ty = mkSysNonGenericTy sys "IDisposable" + member val system_IDisposableNull_ty = mkNonGenericTyWithNullness (findSysTyconRef sys "IDisposable") v_knownWithNull member val system_RuntimeHelpers_ty = mkSysNonGenericTy sysCompilerServices "RuntimeHelpers" member val system_Value_ty = mkSysNonGenericTy sys "ValueType" member val system_Delegate_ty = mkSysNonGenericTy sys "Delegate" diff --git a/src/Compiler/TypedTree/TcGlobals.fsi b/src/Compiler/TypedTree/TcGlobals.fsi index 73d26a64b62..772bc6b96d7 100644 --- a/src/Compiler/TypedTree/TcGlobals.fsi +++ b/src/Compiler/TypedTree/TcGlobals.fsi @@ -1199,6 +1199,8 @@ type internal TcGlobals = member system_IDisposable_ty: FSharp.Compiler.TypedTree.TType + member system_IDisposableNull_ty: FSharp.Compiler.TypedTree.TType + member system_IFormattable_tcref: FSharp.Compiler.TypedTree.EntityRef member system_IFormattable_ty: FSharp.Compiler.TypedTree.TType diff --git a/tests/FSharp.Compiler.ComponentTests/Language/Nullness/NullableReferenceTypesTests.fs b/tests/FSharp.Compiler.ComponentTests/Language/Nullness/NullableReferenceTypesTests.fs index 819bd475152..7eec0ba8054 100644 --- a/tests/FSharp.Compiler.ComponentTests/Language/Nullness/NullableReferenceTypesTests.fs +++ b/tests/FSharp.Compiler.ComponentTests/Language/Nullness/NullableReferenceTypesTests.fs @@ -173,6 +173,19 @@ let safeHolder : IDisposable = |> typeCheckWithStrictNullness |> shouldSucceed +[] +let ``Can _use_ a nullable IDisposable`` () = + FSharp """module TestLib +open System +let workWithResource (getD:int -> (IDisposable|null)) = + use _ = getD 15 + 15 + + """ + |> asLibrary + |> typeCheckWithStrictNullness + |> shouldSucceed + [] let ``Does not duplicate warnings`` () = FSharp """ From 4583331935edb7fe06d3bfd9b7ca76f890ed9802 Mon Sep 17 00:00:00 2001 From: Eugene Auduchinok Date: Tue, 4 Feb 2025 01:41:53 +0900 Subject: [PATCH 06/29] Cancellable: set token in more places (#18283) --- docs/release-notes/.FSharp.Compiler.Service/9.0.300.md | 1 + src/Compiler/Service/BackgroundCompiler.fs | 2 ++ src/Compiler/Service/ServiceAnalysis.fs | 3 +++ .../ILVerify/ilverify_FSharp.Compiler.Service_Debug_net9.0.bsl | 2 +- .../ilverify_FSharp.Compiler.Service_Debug_netstandard2.0.bsl | 2 +- .../ilverify_FSharp.Compiler.Service_Release_net9.0.bsl | 2 +- ...ilverify_FSharp.Compiler.Service_Release_netstandard2.0.bsl | 2 +- 7 files changed, 10 insertions(+), 4 deletions(-) diff --git a/docs/release-notes/.FSharp.Compiler.Service/9.0.300.md b/docs/release-notes/.FSharp.Compiler.Service/9.0.300.md index 859bd0e3c31..a981aa6e79e 100644 --- a/docs/release-notes/.FSharp.Compiler.Service/9.0.300.md +++ b/docs/release-notes/.FSharp.Compiler.Service/9.0.300.md @@ -4,6 +4,7 @@ * Fix internal error when missing measure attribute in an unsolved measure typar. ([Issue #7491](https://github.com/dotnet/fsharp/issues/7491), [PR #18234](https://github.com/dotnet/fsharp/pull/18234)== * Set `Cancellable.token` from async computation ([Issue #18235](https://github.com/dotnet/fsharp/issues/18235), [PR #18238](https://github.com/dotnet/fsharp/pull/18238)) * Cancellable: only cancel on OCE with own token ([PR #18277](https://github.com/dotnet/fsharp/pull/18277)) +* Cancellable: set token in more places ([PR #18283](https://github.com/dotnet/fsharp/pull/18283)) ### Added * Added missing type constraints in FCS. ([PR #18241](https://github.com/dotnet/fsharp/pull/18241)) diff --git a/src/Compiler/Service/BackgroundCompiler.fs b/src/Compiler/Service/BackgroundCompiler.fs index 8f119f2fd60..da04b6ebb83 100644 --- a/src/Compiler/Service/BackgroundCompiler.fs +++ b/src/Compiler/Service/BackgroundCompiler.fs @@ -503,6 +503,8 @@ type internal BackgroundCompiler match tryGetBuilder options with | Some getBuilder -> async { + do! Cancellable.UseToken() + match! getBuilder with | builderOpt, creationDiags when builderOpt.IsNone || not builderOpt.Value.IsReferencesInvalidated -> return builderOpt, creationDiags diff --git a/src/Compiler/Service/ServiceAnalysis.fs b/src/Compiler/Service/ServiceAnalysis.fs index 26b2ea1f7a2..1347751d167 100644 --- a/src/Compiler/Service/ServiceAnalysis.fs +++ b/src/Compiler/Service/ServiceAnalysis.fs @@ -6,6 +6,7 @@ open System open System.Collections.Generic open System.Runtime.CompilerServices open Internal.Utilities.Library +open FSharp.Compiler open FSharp.Compiler.CodeAnalysis open FSharp.Compiler.Symbols open FSharp.Compiler.Syntax.PrettyNaming @@ -301,6 +302,8 @@ module UnusedOpens = /// Async to allow cancellation. let getUnusedOpens (checkFileResults: FSharpCheckFileResults, getSourceLineStr: int -> string) : Async = async { + do! Cancellable.UseToken() + if checkFileResults.OpenDeclarations.Length = 0 then return [] else diff --git a/tests/ILVerify/ilverify_FSharp.Compiler.Service_Debug_net9.0.bsl b/tests/ILVerify/ilverify_FSharp.Compiler.Service_Debug_net9.0.bsl index 41e393f5f30..60c5f6e4b5f 100644 --- a/tests/ILVerify/ilverify_FSharp.Compiler.Service_Debug_net9.0.bsl +++ b/tests/ILVerify/ilverify_FSharp.Compiler.Service_Debug_net9.0.bsl @@ -21,7 +21,7 @@ [IL]: Error [StackUnexpected]: : FSharp.Compiler.CodeAnalysis.Hosted.CompilerHelpers::fscCompile([FSharp.Compiler.Service]FSharp.Compiler.CodeAnalysis.LegacyReferenceResolver, string, string[])][offset 0x00000082][found Char] Unexpected type on the stack. [IL]: Error [StackUnexpected]: : FSharp.Compiler.CodeAnalysis.Hosted.CompilerHelpers::fscCompile([FSharp.Compiler.Service]FSharp.Compiler.CodeAnalysis.LegacyReferenceResolver, string, string[])][offset 0x0000008B][found Char] Unexpected type on the stack. [IL]: Error [StackUnexpected]: : FSharp.Compiler.Interactive.Shell+MagicAssemblyResolution::ResolveAssemblyCore([FSharp.Compiler.Service]Internal.Utilities.Library.CompilationThreadToken, [FSharp.Compiler.Service]FSharp.Compiler.Text.Range, [FSharp.Compiler.Service]FSharp.Compiler.CompilerConfig+TcConfigBuilder, [FSharp.Compiler.Service]FSharp.Compiler.CompilerImports+TcImports, [FSharp.Compiler.Service]FSharp.Compiler.Interactive.Shell+FsiDynamicCompiler, [FSharp.Compiler.Service]FSharp.Compiler.Interactive.Shell+FsiConsoleOutput, string)][offset 0x00000015][found Char] Unexpected type on the stack. -[IL]: Error [StackUnexpected]: : FSharp.Compiler.Interactive.Shell+clo@3510-786::Invoke([S.P.CoreLib]System.Tuple`3)][offset 0x000001E5][found Char] Unexpected type on the stack. +[IL]: Error [StackUnexpected]: : FSharp.Compiler.Interactive.Shell+clo@3510-788::Invoke([S.P.CoreLib]System.Tuple`3)][offset 0x000001E5][found Char] Unexpected type on the stack. [IL]: Error [UnmanagedPointer]: : FSharp.Compiler.Interactive.Shell+Utilities+pointerToNativeInt@110::Invoke(object)][offset 0x00000007] Unmanaged pointers are not a verifiable type. [IL]: Error [StackUnexpected]: : .$FSharpCheckerResults+dataTipOfReferences@2205::Invoke([FSharp.Core]Microsoft.FSharp.Core.Unit)][offset 0x00000084][found Char] Unexpected type on the stack. [IL]: Error [StackUnexpected]: : .$ServiceLexing+clo@921-508::Invoke([FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2,Microsoft.FSharp.Core.Unit>)][offset 0x00000032][found Char] Unexpected type on the stack. diff --git a/tests/ILVerify/ilverify_FSharp.Compiler.Service_Debug_netstandard2.0.bsl b/tests/ILVerify/ilverify_FSharp.Compiler.Service_Debug_netstandard2.0.bsl index 23bfed609bb..1e0df962a05 100644 --- a/tests/ILVerify/ilverify_FSharp.Compiler.Service_Debug_netstandard2.0.bsl +++ b/tests/ILVerify/ilverify_FSharp.Compiler.Service_Debug_netstandard2.0.bsl @@ -28,7 +28,7 @@ [IL]: Error [StackUnexpected]: : FSharp.Compiler.CodeAnalysis.Hosted.CompilerHelpers::fscCompile([FSharp.Compiler.Service]FSharp.Compiler.CodeAnalysis.LegacyReferenceResolver, string, string[])][offset 0x0000008B][found Char] Unexpected type on the stack. [IL]: Error [StackUnexpected]: : FSharp.Compiler.Interactive.Shell+FsiStdinSyphon::GetLine(string, int32)][offset 0x00000039][found Char] Unexpected type on the stack. [IL]: Error [StackUnexpected]: : FSharp.Compiler.Interactive.Shell+MagicAssemblyResolution::ResolveAssemblyCore([FSharp.Compiler.Service]Internal.Utilities.Library.CompilationThreadToken, [FSharp.Compiler.Service]FSharp.Compiler.Text.Range, [FSharp.Compiler.Service]FSharp.Compiler.CompilerConfig+TcConfigBuilder, [FSharp.Compiler.Service]FSharp.Compiler.CompilerImports+TcImports, [FSharp.Compiler.Service]FSharp.Compiler.Interactive.Shell+FsiDynamicCompiler, [FSharp.Compiler.Service]FSharp.Compiler.Interactive.Shell+FsiConsoleOutput, string)][offset 0x00000015][found Char] Unexpected type on the stack. -[IL]: Error [StackUnexpected]: : FSharp.Compiler.Interactive.Shell+clo@3510-786::Invoke([S.P.CoreLib]System.Tuple`3)][offset 0x000001E5][found Char] Unexpected type on the stack. +[IL]: Error [StackUnexpected]: : FSharp.Compiler.Interactive.Shell+clo@3510-788::Invoke([S.P.CoreLib]System.Tuple`3)][offset 0x000001E5][found Char] Unexpected type on the stack. [IL]: Error [StackUnexpected]: : FSharp.Compiler.Interactive.Shell+FsiInteractionProcessor::CompletionsForPartialLID([FSharp.Compiler.Service]FSharp.Compiler.Interactive.Shell+FsiDynamicCompilerState, string)][offset 0x0000001B][found Char] Unexpected type on the stack. [IL]: Error [UnmanagedPointer]: : FSharp.Compiler.Interactive.Shell+Utilities+pointerToNativeInt@110::Invoke(object)][offset 0x00000007] Unmanaged pointers are not a verifiable type. [IL]: Error [StackUnexpected]: : .$FSharpCheckerResults+dataTipOfReferences@2205::Invoke([FSharp.Core]Microsoft.FSharp.Core.Unit)][offset 0x00000084][found Char] Unexpected type on the stack. diff --git a/tests/ILVerify/ilverify_FSharp.Compiler.Service_Release_net9.0.bsl b/tests/ILVerify/ilverify_FSharp.Compiler.Service_Release_net9.0.bsl index d1ac4690f8b..1a088c5a702 100644 --- a/tests/ILVerify/ilverify_FSharp.Compiler.Service_Release_net9.0.bsl +++ b/tests/ILVerify/ilverify_FSharp.Compiler.Service_Release_net9.0.bsl @@ -21,7 +21,7 @@ [IL]: Error [StackUnexpected]: : FSharp.Compiler.CodeAnalysis.Hosted.CompilerHelpers::fscCompile([FSharp.Compiler.Service]FSharp.Compiler.CodeAnalysis.LegacyReferenceResolver, string, string[])][offset 0x00000082][found Char] Unexpected type on the stack. [IL]: Error [StackUnexpected]: : FSharp.Compiler.CodeAnalysis.Hosted.CompilerHelpers::fscCompile([FSharp.Compiler.Service]FSharp.Compiler.CodeAnalysis.LegacyReferenceResolver, string, string[])][offset 0x0000008B][found Char] Unexpected type on the stack. [IL]: Error [StackUnexpected]: : FSharp.Compiler.Interactive.Shell+MagicAssemblyResolution::ResolveAssemblyCore([FSharp.Compiler.Service]Internal.Utilities.Library.CompilationThreadToken, [FSharp.Compiler.Service]FSharp.Compiler.Text.Range, [FSharp.Compiler.Service]FSharp.Compiler.CompilerConfig+TcConfigBuilder, [FSharp.Compiler.Service]FSharp.Compiler.CompilerImports+TcImports, [FSharp.Compiler.Service]FSharp.Compiler.Interactive.Shell+FsiDynamicCompiler, [FSharp.Compiler.Service]FSharp.Compiler.Interactive.Shell+FsiConsoleOutput, string)][offset 0x00000015][found Char] Unexpected type on the stack. -[IL]: Error [StackUnexpected]: : FSharp.Compiler.Interactive.Shell+clo@3510-830::Invoke([S.P.CoreLib]System.Tuple`3)][offset 0x000001C7][found Char] Unexpected type on the stack. +[IL]: Error [StackUnexpected]: : FSharp.Compiler.Interactive.Shell+clo@3510-832::Invoke([S.P.CoreLib]System.Tuple`3)][offset 0x000001C7][found Char] Unexpected type on the stack. [IL]: Error [StackUnexpected]: : .$FSharpCheckerResults+GetReferenceResolutionStructuredToolTipText@2205::Invoke([FSharp.Core]Microsoft.FSharp.Core.Unit)][offset 0x00000076][found Char] Unexpected type on the stack. [IL]: Error [StackUnexpected]: : .$ServiceLexing+clo@921-529::Invoke([FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2,Microsoft.FSharp.Core.Unit>)][offset 0x00000032][found Char] Unexpected type on the stack. [IL]: Error [StackUnexpected]: : .$ServiceLexing+clo@921-529::Invoke([FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2,Microsoft.FSharp.Core.Unit>)][offset 0x0000003B][found Char] Unexpected type on the stack. diff --git a/tests/ILVerify/ilverify_FSharp.Compiler.Service_Release_netstandard2.0.bsl b/tests/ILVerify/ilverify_FSharp.Compiler.Service_Release_netstandard2.0.bsl index 15bc7aba394..48af8ec2f2f 100644 --- a/tests/ILVerify/ilverify_FSharp.Compiler.Service_Release_netstandard2.0.bsl +++ b/tests/ILVerify/ilverify_FSharp.Compiler.Service_Release_netstandard2.0.bsl @@ -28,7 +28,7 @@ [IL]: Error [StackUnexpected]: : FSharp.Compiler.CodeAnalysis.Hosted.CompilerHelpers::fscCompile([FSharp.Compiler.Service]FSharp.Compiler.CodeAnalysis.LegacyReferenceResolver, string, string[])][offset 0x0000008B][found Char] Unexpected type on the stack. [IL]: Error [StackUnexpected]: : FSharp.Compiler.Interactive.Shell+FsiStdinSyphon::GetLine(string, int32)][offset 0x00000032][found Char] Unexpected type on the stack. [IL]: Error [StackUnexpected]: : FSharp.Compiler.Interactive.Shell+MagicAssemblyResolution::ResolveAssemblyCore([FSharp.Compiler.Service]Internal.Utilities.Library.CompilationThreadToken, [FSharp.Compiler.Service]FSharp.Compiler.Text.Range, [FSharp.Compiler.Service]FSharp.Compiler.CompilerConfig+TcConfigBuilder, [FSharp.Compiler.Service]FSharp.Compiler.CompilerImports+TcImports, [FSharp.Compiler.Service]FSharp.Compiler.Interactive.Shell+FsiDynamicCompiler, [FSharp.Compiler.Service]FSharp.Compiler.Interactive.Shell+FsiConsoleOutput, string)][offset 0x00000015][found Char] Unexpected type on the stack. -[IL]: Error [StackUnexpected]: : FSharp.Compiler.Interactive.Shell+clo@3510-830::Invoke([S.P.CoreLib]System.Tuple`3)][offset 0x000001C7][found Char] Unexpected type on the stack. +[IL]: Error [StackUnexpected]: : FSharp.Compiler.Interactive.Shell+clo@3510-832::Invoke([S.P.CoreLib]System.Tuple`3)][offset 0x000001C7][found Char] Unexpected type on the stack. [IL]: Error [StackUnexpected]: : FSharp.Compiler.Interactive.Shell+FsiInteractionProcessor::CompletionsForPartialLID([FSharp.Compiler.Service]FSharp.Compiler.Interactive.Shell+FsiDynamicCompilerState, string)][offset 0x00000024][found Char] Unexpected type on the stack. [IL]: Error [StackUnexpected]: : .$FSharpCheckerResults+GetReferenceResolutionStructuredToolTipText@2205::Invoke([FSharp.Core]Microsoft.FSharp.Core.Unit)][offset 0x00000076][found Char] Unexpected type on the stack. [IL]: Error [StackUnexpected]: : FSharp.Compiler.EditorServices.AssemblyContent+traverseMemberFunctionAndValues@176::Invoke([FSharp.Compiler.Service]FSharp.Compiler.Symbols.FSharpMemberOrFunctionOrValue)][offset 0x0000002B][found Char] Unexpected type on the stack. From d3bd7584d6aad7ab50cb7a52ded044ad086068be Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Mon, 3 Feb 2025 09:32:05 -0800 Subject: [PATCH 07/29] [main] Update dependencies from dotnet/source-build-reference-packages (#18281) * Update dependencies from https://github.com/dotnet/source-build-reference-packages build 20250128.6 Microsoft.SourceBuild.Intermediate.source-build-reference-packages From Version 9.0.0-alpha.1.25066.1 -> To Version 9.0.0-alpha.1.25078.6 * Update dependencies from https://github.com/dotnet/source-build-reference-packages build 20250131.6 Microsoft.SourceBuild.Intermediate.source-build-reference-packages From Version 9.0.0-alpha.1.25066.1 -> To Version 9.0.0-alpha.1.25081.6 --------- Co-authored-by: dotnet-maestro[bot] Co-authored-by: Petr --- eng/Version.Details.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index e0c968cbe09..7071e352237 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -1,9 +1,9 @@ - + https://github.com/dotnet/source-build-reference-packages - 93a3395781d30f69201367371c28cfc5005c0264 + 1cec3b4a8fb07138136a1ca1e04763bfcf7841db From 0263870af420926318dd7c69849c584162207154 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Mon, 3 Feb 2025 09:32:48 -0800 Subject: [PATCH 08/29] Update dependencies from https://github.com/dotnet/arcade build 20250127.4 (#18282) Microsoft.SourceBuild.Intermediate.arcade , Microsoft.DotNet.Arcade.Sdk From Version 9.0.0-beta.25065.2 -> To Version 9.0.0-beta.25077.4 Co-authored-by: dotnet-maestro[bot] --- eng/Version.Details.xml | 8 ++++---- eng/common/internal/Tools.csproj | 10 ---------- global.json | 2 +- 3 files changed, 5 insertions(+), 15 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 7071e352237..c7056f9a86d 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -42,14 +42,14 @@ - + https://github.com/dotnet/arcade - c4bbc67763bf0c5a868862df874079380e647d61 + bac7e1caea791275b7c3ccb4cb75fd6a04a26618 - + https://github.com/dotnet/arcade - c4bbc67763bf0c5a868862df874079380e647d61 + bac7e1caea791275b7c3ccb4cb75fd6a04a26618 diff --git a/eng/common/internal/Tools.csproj b/eng/common/internal/Tools.csproj index 32f79dfb340..feaa6d20812 100644 --- a/eng/common/internal/Tools.csproj +++ b/eng/common/internal/Tools.csproj @@ -15,16 +15,6 @@ - - - - https://devdiv.pkgs.visualstudio.com/_packaging/dotnet-core-internal-tooling/nuget/v3/index.json; - - - $(RestoreSources); - https://devdiv.pkgs.visualstudio.com/_packaging/VS/nuget/v3/index.json; - - diff --git a/global.json b/global.json index 8fe04b02ff8..5ba1a798140 100644 --- a/global.json +++ b/global.json @@ -17,7 +17,7 @@ "perl": "5.38.2.2" }, "msbuild-sdks": { - "Microsoft.DotNet.Arcade.Sdk": "9.0.0-beta.25065.2", + "Microsoft.DotNet.Arcade.Sdk": "9.0.0-beta.25077.4", "Microsoft.DotNet.Helix.Sdk": "8.0.0-beta.23255.2" } } From bacc1605ee79b97de69ad5e275ab90c7017c9305 Mon Sep 17 00:00:00 2001 From: Tomas Grosup Date: Tue, 4 Feb 2025 11:10:43 +0100 Subject: [PATCH 09/29] Bugfix: Warn when upcast drops nullness via FindUniqueFeasibleSupertype (#18261) * Warn when upcast drops nullness via FindUniqueFeasibleSupertype * temporary null shutuops before `use` is softened * notes added --- .../.FSharp.Compiler.Service/9.0.300.md | 1 + src/Compiler/Checking/TypeRelations.fs | 12 ++++++++++-- src/Compiler/Utilities/Activity.fs | 6 +++--- .../Nullness/NullableReferenceTypesTests.fs | 14 ++++++++++++++ 4 files changed, 28 insertions(+), 5 deletions(-) diff --git a/docs/release-notes/.FSharp.Compiler.Service/9.0.300.md b/docs/release-notes/.FSharp.Compiler.Service/9.0.300.md index a981aa6e79e..7b1942196b9 100644 --- a/docs/release-notes/.FSharp.Compiler.Service/9.0.300.md +++ b/docs/release-notes/.FSharp.Compiler.Service/9.0.300.md @@ -3,6 +3,7 @@ * Fix optimizer internal error for records with static fields ([Issue #18165](https://github.com/dotnet/fsharp/issues/18165), [PR #18280](https://github.com/dotnet/fsharp/pull/18280)) * Fix internal error when missing measure attribute in an unsolved measure typar. ([Issue #7491](https://github.com/dotnet/fsharp/issues/7491), [PR #18234](https://github.com/dotnet/fsharp/pull/18234)== * Set `Cancellable.token` from async computation ([Issue #18235](https://github.com/dotnet/fsharp/issues/18235), [PR #18238](https://github.com/dotnet/fsharp/pull/18238)) +* Fix missing nullness warning when static upcast dropped nullness ([Issue #18232](https://github.com/dotnet/fsharp/issues/18232), [PR #18261](https://github.com/dotnet/fsharp/pull/18261)) * Cancellable: only cancel on OCE with own token ([PR #18277](https://github.com/dotnet/fsharp/pull/18277)) * Cancellable: set token in more places ([PR #18283](https://github.com/dotnet/fsharp/pull/18283)) diff --git a/src/Compiler/Checking/TypeRelations.fs b/src/Compiler/Checking/TypeRelations.fs index d180bb778dd..2cb5dd4057a 100644 --- a/src/Compiler/Checking/TypeRelations.fs +++ b/src/Compiler/Checking/TypeRelations.fs @@ -341,5 +341,13 @@ let IteratedAdjustLambdaToMatchValReprInfo g amap valReprInfo lambdaExpr = /// "Single Feasible Type" inference /// Look for the unique supertype of ty2 for which ty2 :> ty1 might feasibly hold let FindUniqueFeasibleSupertype g amap m ty1 ty2 = - let supertypes = Option.toList (GetSuperTypeOfType g amap m ty2) @ (GetImmediateInterfacesOfType SkipUnrefInterfaces.Yes g amap m ty2) - supertypes |> List.tryFind (TypeFeasiblySubsumesType 0 g amap m ty1 NoCoerce) + let n2 = nullnessOfTy g ty2 + let nullify t = addNullnessToTy n2 t + + let supertypes = + Option.toList (GetSuperTypeOfType g amap m ty2) @ + (GetImmediateInterfacesOfType SkipUnrefInterfaces.Yes g amap m ty2) + + supertypes + |> List.tryFind (TypeFeasiblySubsumesType 0 g amap m ty1 NoCoerce) + |> Option.map nullify diff --git a/src/Compiler/Utilities/Activity.fs b/src/Compiler/Utilities/Activity.fs index b6fafe1c1b9..2403f00d3de 100644 --- a/src/Compiler/Utilities/Activity.fs +++ b/src/Compiler/Utilities/Activity.fs @@ -93,14 +93,14 @@ module internal Activity = let activity = activitySource.CreateActivity(name, ActivityKind.Internal) match activity with - | null -> activity + | null -> !!activity //TODO change retTy to |null after PR #18262 is merged!! | activity -> for key, value in tags do activity.AddTag(key, value) |> ignore activity.Start() - let startNoTags (name: string) : IDisposable = activitySource.StartActivity name + let startNoTags (name: string) : IDisposable = !! (activitySource.StartActivity name) //TODO change retTy to |null after PR #18262 is merged!! let addEvent name = match Activity.Current with @@ -122,7 +122,7 @@ module internal Activity = let private profiledSource = new ActivitySource(ActivityNames.ProfiledSourceName) - let startAndMeasureEnvironmentStats (name: string) : IDisposable = profiledSource.StartActivity(name) + let startAndMeasureEnvironmentStats (name: string) : IDisposable = !!(profiledSource.StartActivity(name)) //TODO change retTy to |null after PR #18262 is merged!! type private GCStats = int[] diff --git a/tests/FSharp.Compiler.ComponentTests/Language/Nullness/NullableReferenceTypesTests.fs b/tests/FSharp.Compiler.ComponentTests/Language/Nullness/NullableReferenceTypesTests.fs index 7eec0ba8054..7dbe3527fbf 100644 --- a/tests/FSharp.Compiler.ComponentTests/Language/Nullness/NullableReferenceTypesTests.fs +++ b/tests/FSharp.Compiler.ComponentTests/Language/Nullness/NullableReferenceTypesTests.fs @@ -17,6 +17,20 @@ let typeCheckWithStrictNullness cu = |> withNullnessOptions |> typecheck +[] +let ``Warning on nullness hidden behind interface upcast`` () = + FSharp """module Test + +open System.IO +open System + +// This is bad - input is nullable, output is not = must warn +let whatisThis (s:Stream|null) : IDisposable = + s""" + |> asLibrary + |> typeCheckWithStrictNullness + |> shouldFail + |> withDiagnostics [Error 3261, Line 8, Col 5, Line 8, Col 6, "Nullness warning: The types 'IDisposable' and 'IDisposable | null' do not have compatible nullability."] [] let ``Report warning when applying anon record to a nullable generic return value`` () = From 1f9b0ce1da85aa2e7bbfc6112a595623e0cad7c7 Mon Sep 17 00:00:00 2001 From: Eugene Auduchinok Date: Tue, 4 Feb 2025 19:59:15 +0900 Subject: [PATCH 10/29] Cancellable: remove UsingToken usages in tests (#18276) * Remove Cancellable.UsingToken from tests The token is now always set inside the cancellable computation * Release notes --------- Co-authored-by: Kevin Ransom (msft) --- .../.FSharp.Compiler.Service/9.0.300.md | 1 + .../ModuleReaderCancellationTests.fs | 14 +++++++++----- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/docs/release-notes/.FSharp.Compiler.Service/9.0.300.md b/docs/release-notes/.FSharp.Compiler.Service/9.0.300.md index 7b1942196b9..683c8dc0f5c 100644 --- a/docs/release-notes/.FSharp.Compiler.Service/9.0.300.md +++ b/docs/release-notes/.FSharp.Compiler.Service/9.0.300.md @@ -15,5 +15,6 @@ * FSharpCheckFileResults.ProjectContext.ProjectOptions will not be available when using the experimental Transparent Compiler feature. ([PR #18205](https://github.com/dotnet/fsharp/pull/18205)) * Update `Obsolete` attribute checking to account for `DiagnosticId` and `UrlFormat` properties. ([PR #18224](https://github.com/dotnet/fsharp/pull/18224)) +* Remove `Cancellable.UsingToken` from tests ([PR #18276](https://github.com/dotnet/fsharp/pull/18276)) ### Breaking Changes diff --git a/tests/FSharp.Compiler.Service.Tests/ModuleReaderCancellationTests.fs b/tests/FSharp.Compiler.Service.Tests/ModuleReaderCancellationTests.fs index 62e36de58b9..981c4dda14b 100644 --- a/tests/FSharp.Compiler.Service.Tests/ModuleReaderCancellationTests.fs +++ b/tests/FSharp.Compiler.Service.Tests/ModuleReaderCancellationTests.fs @@ -22,7 +22,6 @@ let mutable private wasCancelled = false let runCancelFirstTime f = let mutable requestCount = 0 fun () -> - use _ = Cancellable.UsingToken cts.Token if requestCount = 0 then cts.Cancel() @@ -150,12 +149,17 @@ let referenceReaderProject getPreTypeDefs (cancelOnModuleAccess: bool) (options: let parseAndCheck path source options = cts <- new CancellationTokenSource() wasCancelled <- false - use _ = Cancellable.UsingToken cts.Token try - match Async.RunSynchronously(checker.ParseAndCheckFileInProject(path, 0, SourceText.ofString source, options), cancellationToken = cts.Token) with - | fileResults, FSharpCheckFileAnswer.Aborted -> None - | fileResults, FSharpCheckFileAnswer.Succeeded results -> Some results + let checkFileAsync = checker.ParseAndCheckFileInProject(path, 0, SourceText.ofString source, options) + let result = + match Async.RunSynchronously(checkFileAsync, cancellationToken = cts.Token) with + | _, FSharpCheckFileAnswer.Aborted -> None + | _, FSharpCheckFileAnswer.Succeeded results -> Some results + + Cancellable.HasCancellationToken |> shouldEqual false + result + with :? OperationCanceledException -> wasCancelled <- true None From 10b812b91e05da57c264660b1fe45a18cba3a38a Mon Sep 17 00:00:00 2001 From: Tomas Grosup Date: Tue, 4 Feb 2025 14:03:01 +0100 Subject: [PATCH 11/29] Bugfix :: Flexible types should subsume nullable version of equivalent CoarcesTo constraints (#18266) --- .../.FSharp.Compiler.Service/9.0.300.md | 1 + src/Compiler/Checking/ConstraintSolver.fs | 18 ++++++++- .../Nullness/NullableReferenceTypesTests.fs | 40 ++++++++++++++++++- .../Signatures/SeqTests.fs | 16 ++++++++ 4 files changed, 73 insertions(+), 2 deletions(-) diff --git a/docs/release-notes/.FSharp.Compiler.Service/9.0.300.md b/docs/release-notes/.FSharp.Compiler.Service/9.0.300.md index 683c8dc0f5c..de19496f010 100644 --- a/docs/release-notes/.FSharp.Compiler.Service/9.0.300.md +++ b/docs/release-notes/.FSharp.Compiler.Service/9.0.300.md @@ -1,6 +1,7 @@ ### Fixed * Fix Realsig+ generates nested closures with incorrect Generic ([Issue #17797](https://github.com/dotnet/fsharp/issues/17797), [PR #17877](https://github.com/dotnet/fsharp/pull/17877)) * Fix optimizer internal error for records with static fields ([Issue #18165](https://github.com/dotnet/fsharp/issues/18165), [PR #18280](https://github.com/dotnet/fsharp/pull/18280)) +* Fix nullness warning with flexible types ([Issue #18056](https://github.com/dotnet/fsharp/issues/18056), [PR #18266](https://github.com/dotnet/fsharp/pull/18266)) * Fix internal error when missing measure attribute in an unsolved measure typar. ([Issue #7491](https://github.com/dotnet/fsharp/issues/7491), [PR #18234](https://github.com/dotnet/fsharp/pull/18234)== * Set `Cancellable.token` from async computation ([Issue #18235](https://github.com/dotnet/fsharp/issues/18235), [PR #18238](https://github.com/dotnet/fsharp/pull/18238)) * Fix missing nullness warning when static upcast dropped nullness ([Issue #18232](https://github.com/dotnet/fsharp/issues/18232), [PR #18261](https://github.com/dotnet/fsharp/pull/18261)) diff --git a/src/Compiler/Checking/ConstraintSolver.fs b/src/Compiler/Checking/ConstraintSolver.fs index 82141080743..902bf331d85 100644 --- a/src/Compiler/Checking/ConstraintSolver.fs +++ b/src/Compiler/Checking/ConstraintSolver.fs @@ -1609,7 +1609,10 @@ and SolveTyparSubtypeOfType (csenv: ConstraintSolverEnv) ndeep m2 trace tp ty1 = elif isSealedTy g ty1 then SolveTypeEqualsTypeKeepAbbrevs csenv ndeep m2 trace (mkTyparTy tp) ty1 else - AddConstraint csenv ndeep m2 trace tp (TyparConstraint.CoercesTo(ty1, csenv.m)) + if SubtypeConstraintImplied g tp.Constraints ty1 then + CompleteD + else + AddConstraint csenv ndeep m2 trace tp (TyparConstraint.CoercesTo(ty1, csenv.m)) and DepthCheck ndeep m = if ndeep > 300 then @@ -2490,6 +2493,19 @@ and CheckConstraintImplication (csenv: ConstraintSolverEnv) tpc1 tpc2 = and CheckConstraintsImplication csenv existingConstraints newConstraint = existingConstraints |> List.exists (fun tpc2 -> CheckConstraintImplication csenv tpc2 newConstraint) +and SubtypeConstraintImplied g existingConstraints newCoarceToTy = + if g.checkNullness then + let canBeNull t = (nullnessOfTy g t).Evaluate() = NullnessInfo.WithNull + let newTyIsWithoutNull = canBeNull newCoarceToTy |> not + let typeCoversNewConstraint existingTy = + typeEquiv g existingTy newCoarceToTy + && not (newTyIsWithoutNull && canBeNull existingTy) // :> T? cannot imply :>T, since non-nullable is a stricter constraint. + + existingConstraints + |> List.exists (function | TyparConstraint.CoercesTo(ty2,_) when typeCoversNewConstraint ty2 -> true | _ -> false) + else + false + // Ensure constraint conforms with existing constraints // NOTE: QUADRATIC and EnforceConstraintSetConsistency csenv ndeep m2 trace retry allCxs i cxs = diff --git a/tests/FSharp.Compiler.ComponentTests/Language/Nullness/NullableReferenceTypesTests.fs b/tests/FSharp.Compiler.ComponentTests/Language/Nullness/NullableReferenceTypesTests.fs index 7dbe3527fbf..85b872d01a2 100644 --- a/tests/FSharp.Compiler.ComponentTests/Language/Nullness/NullableReferenceTypesTests.fs +++ b/tests/FSharp.Compiler.ComponentTests/Language/Nullness/NullableReferenceTypesTests.fs @@ -1003,7 +1003,45 @@ looseFunc(maybeTuple2) |> ignore Error 3261, Line 29, Col 12, Line 29, Col 19, "Nullness warning: The type 'MyDu | null' supports 'null' but a non-null type is expected." Error 3261, Line 30, Col 12, Line 30, Col 21, "Nullness warning: The type 'MyRecord | null' supports 'null' but a non-null type is expected." Error 43, Line 40, Col 36, Line 40, Col 40, "The type 'Maybe' does not have 'null' as a proper value"] - + + +[] +let ``Nullness support for flexible types`` () = + FSharp """module MyLibrary +open System +let dispose (x: IDisposable | null) : unit = + match x with + | null -> () + | d -> d.Dispose() + +let useThing (thing: #IDisposable) = + try + printfn "%O" thing + finally + dispose thing // Warning used to be here, should not warn! """ + |> asLibrary + |> typeCheckWithStrictNullness + |> shouldSucceed + +[] +let ``Nullness support for flexible types - opposite`` () = + FSharp """module MyLibrary +open System +let dispose (x: IDisposable) : unit = + x.Dispose() + +let useThing (thing: #IDisposable | null) = + try + printfn "%O" thing + finally + dispose thing // Warning should be here, because 'thing' can be null! + """ + |> asLibrary + |> typeCheckWithStrictNullness + |> shouldFail + |> withDiagnostics [Error 3261, Line 10, Col 17, Line 10, Col 22, "Nullness warning: The types 'IDisposable' and ''a | null' do not have compatible nullability."] + + [] let ``Static member on Record with null arg`` () = FSharp """module MyLibrary diff --git a/tests/FSharp.Compiler.ComponentTests/Signatures/SeqTests.fs b/tests/FSharp.Compiler.ComponentTests/Signatures/SeqTests.fs index 10a0d0b3a25..fdca6035783 100644 --- a/tests/FSharp.Compiler.ComponentTests/Signatures/SeqTests.fs +++ b/tests/FSharp.Compiler.ComponentTests/Signatures/SeqTests.fs @@ -2,6 +2,8 @@ open Xunit open Signatures.TestHelpers +open FSharp.Test +open FSharp.Test.Compiler [] let ``int seq`` () = @@ -14,3 +16,17 @@ let ``tuple seq`` () = assertSingleSignatureBinding "let s = seq { yield (1, 'b', 2.) }" "val s: (int * char * float) seq" + +[] +let ``seq transpose`` () = + let encodeFs = + FsSource """module Program +let transpose (source: seq<#seq<'T>>) = + source |> Seq.collect Seq.indexed |> Seq.groupBy fst |> Seq.map (snd >> (Seq.map snd))""" + + Fsi """module Program +val transpose: source: seq<'Collection> -> seq> when 'Collection :> seq<'T>""" + |> withAdditionalSourceFile encodeFs + |> withLangVersionPreview + |> compile + |> shouldSucceed From adb02dc702cf86ec1bfe4e14ef34e5dcfa6ee125 Mon Sep 17 00:00:00 2001 From: Tomas Grosup Date: Tue, 4 Feb 2025 14:03:31 +0100 Subject: [PATCH 12/29] Bugfix:: Add missing codegen for mapping of overlapped struct DU fields and read it in fslib reflection (#18274) --- .../.FSharp.Compiler.Service/9.0.300.md | 1 + docs/release-notes/.FSharp.Core/9.0.300.md | 8 + src/Compiler/AbstractIL/ilx.fsi | 2 + src/Compiler/CodeGen/IlxGen.fs | 47 +++++- src/Compiler/TypedTree/TypedTreeOps.fs | 3 - src/Compiler/TypedTree/TypedTreeOps.fsi | 2 - src/Compiler/Utilities/illib.fs | 8 + src/Compiler/Utilities/illib.fsi | 2 + src/FSharp.Core/prim-types.fs | 2 +- src/FSharp.Core/prim-types.fsi | 2 +- src/FSharp.Core/reflect.fs | 148 +++++++++--------- tests/AheadOfTime/Trimming/check.ps1 | 4 +- .../Types/UnionTypes/UnionStructTypes.fs | 71 +++++++++ .../FSharpReflection.fs | 18 ++- ...FSharp.Compiler.Service_Release_net9.0.bsl | 4 +- ...ompiler.Service_Release_netstandard2.0.bsl | 4 +- 16 files changed, 230 insertions(+), 96 deletions(-) create mode 100644 docs/release-notes/.FSharp.Core/9.0.300.md diff --git a/docs/release-notes/.FSharp.Compiler.Service/9.0.300.md b/docs/release-notes/.FSharp.Compiler.Service/9.0.300.md index de19496f010..32ae2560ab0 100644 --- a/docs/release-notes/.FSharp.Compiler.Service/9.0.300.md +++ b/docs/release-notes/.FSharp.Compiler.Service/9.0.300.md @@ -19,3 +19,4 @@ * Remove `Cancellable.UsingToken` from tests ([PR #18276](https://github.com/dotnet/fsharp/pull/18276)) ### Breaking Changes +* Struct unions with overlapping fields now generate mappings needed for reading via reflection ([Issue #18121](https://github.com/dotnet/fsharp/issues/17797), [PR #18274](https://github.com/dotnet/fsharp/pull/17877)) \ No newline at end of file diff --git a/docs/release-notes/.FSharp.Core/9.0.300.md b/docs/release-notes/.FSharp.Core/9.0.300.md new file mode 100644 index 00000000000..87d3502539c --- /dev/null +++ b/docs/release-notes/.FSharp.Core/9.0.300.md @@ -0,0 +1,8 @@ +### Fixed + +### Added + +### Changed + +### Breaking Changes +* Struct unions with overlapping fields now generate mappings needed for reading via reflection ([Issue #18121](https://github.com/dotnet/fsharp/issues/17797), [PR #18274](https://github.com/dotnet/fsharp/pull/17877)). Previous versions of FSharp.Core returned incomplete mapping between fields and cases, these older fslib versions will now report an exception. diff --git a/src/Compiler/AbstractIL/ilx.fsi b/src/Compiler/AbstractIL/ilx.fsi index bb4a7344d84..28122885f8e 100644 --- a/src/Compiler/AbstractIL/ilx.fsi +++ b/src/Compiler/AbstractIL/ilx.fsi @@ -162,6 +162,8 @@ val mkILFormalCloRef: ILGenericParameterDefs -> IlxClosureRef -> useStaticField: // MS-ILX: Unions // -------------------------------------------------------------------- +val mkLowerName: nm: string -> string + val actualTypOfIlxUnionField: IlxUnionSpec -> int -> int -> ILType val mkILFreeVar: string * bool * ILType -> IlxClosureFreeVar diff --git a/src/Compiler/CodeGen/IlxGen.fs b/src/Compiler/CodeGen/IlxGen.fs index 861caeea4ab..ff0859486d7 100644 --- a/src/Compiler/CodeGen/IlxGen.fs +++ b/src/Compiler/CodeGen/IlxGen.fs @@ -601,6 +601,29 @@ let voidCheck m g permits ty = error (InternalError("System.Void unexpectedly detected in IL code generation. This should not occur.", m)) #endif +[] +type DuFieldCoordinates = { CaseIdx: int; FieldIdx: int } + +/// Structure for maintaining field reuse across struct unions +type UnionFieldReuseMap = MultiMap + +let unionFieldReuseMapping thisUnionTy (cases: UnionCase[]) : UnionFieldReuseMap = + + if not (isStructTyconRef thisUnionTy) then + Map.empty + else + let fieldKey (f: RecdField) = mkLowerName f.LogicalName + + [ + for i = 0 to cases.Length - 1 do + let fields = cases[i].RecdFieldsArray + + for j = 0 to fields.Length - 1 do + let f = fields[j] + yield fieldKey f, { CaseIdx = i; FieldIdx = j } + ] + |> MultiMap.ofList + /// When generating parameter and return types generate precise .NET IL pointer types. /// These can't be generated for generic instantiations, since .NET generics doesn't /// permit this. But for 'naked' values (locals, parameters, return values etc.) machine @@ -702,18 +725,24 @@ and GenTypeAux cenv m (tyenv: TypeReprEnv) voidOK ptrsOK ty = //-------------------------------------------------------------------------- // Generate ILX references to closures, classunions etc. given a tyenv //-------------------------------------------------------------------------- - -and GenUnionCaseRef (cenv: cenv) m tyenv i (fspecs: RecdField[]) = +and GenUnionCaseRef (cenv: cenv) m tyenv (reuseMap: UnionFieldReuseMap) i (fspecs: RecdField[]) = let g = cenv.g + let fieldMarker = int SourceConstructFlags.Field + fspecs |> Array.mapi (fun j fspec -> let ilFieldDef = mkILInstanceField (fspec.LogicalName, GenType cenv m tyenv fspec.FormalType, None, ILMemberAccess.Public) // These properties on the "field" of an alternative end up going on a property generated by cu_erase.fs - let attrs = - (mkCompilationMappingAttrWithVariantNumAndSeqNum g (int SourceConstructFlags.Field) i j) - :: GenAdditionalAttributesForTy g fspec.FormalType + let mappingAttrs = + match reuseMap |> MultiMap.find (mkLowerName fspec.LogicalName) with + | [] -> [ mkCompilationMappingAttrWithVariantNumAndSeqNum g fieldMarker i j ] + | mappings -> + mappings + |> List.map (fun m -> mkCompilationMappingAttrWithVariantNumAndSeqNum g fieldMarker m.CaseIdx m.FieldIdx) + + let attrs = mappingAttrs @ GenAdditionalAttributesForTy g fspec.FormalType IlxUnionCaseField(ilFieldDef.With(customAttrs = mkILCustomAttrs attrs))) @@ -731,13 +760,15 @@ and GenUnionRef (cenv: cenv) m (tcref: TyconRef) = match tcref.CompiledRepresentation with | CompiledTypeRepr.ILAsmOpen _ -> failwith "GenUnionRef m: unexpected ASM tyrep" | CompiledTypeRepr.ILAsmNamed(tref, _, _) -> + let fieldReuseMap = unionFieldReuseMapping tcref tycon.UnionCasesArray + let alternatives = tycon.UnionCasesArray |> Array.mapi (fun i cspec -> { altName = cspec.CompiledName altCustomAttrs = emptyILCustomAttrs - altFields = GenUnionCaseRef cenv m tyenvinner i cspec.RecdFieldsArray + altFields = GenUnionCaseRef cenv m tyenvinner fieldReuseMap i cspec.RecdFieldsArray }) let nullPermitted = IsUnionTypeWithNullAsTrueValue g tycon @@ -11658,11 +11689,13 @@ and GenTypeDef cenv mgbuf lazyInitInfo eenv m (tycon: Tycon) : ILTypeRef option | _ -> false) -> let alternatives = + let fieldReuseMap = unionFieldReuseMapping tcref tycon.UnionCasesArray + tycon.UnionCasesArray |> Array.mapi (fun i ucspec -> { altName = ucspec.CompiledName - altFields = GenUnionCaseRef cenv m eenvinner.tyenv i ucspec.RecdFieldsArray + altFields = GenUnionCaseRef cenv m eenvinner.tyenv fieldReuseMap i ucspec.RecdFieldsArray altCustomAttrs = mkILCustomAttrs ( GenAttrs cenv eenv ucspec.Attribs diff --git a/src/Compiler/TypedTree/TypedTreeOps.fs b/src/Compiler/TypedTree/TypedTreeOps.fs index 909d6f437a8..ebe42db34fe 100644 --- a/src/Compiler/TypedTree/TypedTreeOps.fs +++ b/src/Compiler/TypedTree/TypedTreeOps.fs @@ -8337,9 +8337,6 @@ let IsMatchingSignatureDataVersionAttr (version: ILVersionInfo) cattr = warning(Failure(FSComp.SR.tastUnexpectedDecodeOfInterfaceDataVersionAttribute())) false -let mkCompilerGeneratedAttr (g: TcGlobals) n = - mkILCustomAttribute (tref_CompilationMappingAttr g, [mkILNonGenericValueTy (tref_SourceConstructFlags g)], [ILAttribElem.Int32 n], []) - //-------------------------------------------------------------------------- // tupled lambda --> method/function with a given valReprInfo specification. // diff --git a/src/Compiler/TypedTree/TypedTreeOps.fsi b/src/Compiler/TypedTree/TypedTreeOps.fsi index 3bca5cdb21e..3a4a1ca4c0a 100755 --- a/src/Compiler/TypedTree/TypedTreeOps.fsi +++ b/src/Compiler/TypedTree/TypedTreeOps.fsi @@ -2380,8 +2380,6 @@ val mkCompilationSourceNameAttr: TcGlobals -> string -> ILAttribute val mkSignatureDataVersionAttr: TcGlobals -> ILVersionInfo -> ILAttribute -val mkCompilerGeneratedAttr: TcGlobals -> int -> ILAttribute - //------------------------------------------------------------------------- // More common type construction //------------------------------------------------------------------------- diff --git a/src/Compiler/Utilities/illib.fs b/src/Compiler/Utilities/illib.fs index 5e32e3b8699..9ed400f3ab8 100644 --- a/src/Compiler/Utilities/illib.fs +++ b/src/Compiler/Utilities/illib.fs @@ -1307,6 +1307,14 @@ module MultiMap = let initBy f xs : MultiMap<_, _> = xs |> Seq.groupBy f |> Seq.map (fun (k, v) -> (k, List.ofSeq v)) |> Map.ofSeq + let ofList (xs: ('a * 'b) list) : MultiMap<'a,'b> = + (Map.empty, xs) + ||> List.fold (fun m (k, v) -> + m |> Map.change k (function + | None -> Some [v] + | Some vs -> Some (v :: vs))) + |> Map.map (fun _ values -> List.rev values) + type LayeredMap<'Key, 'Value when 'Key: comparison> = Map<'Key, 'Value> [] diff --git a/src/Compiler/Utilities/illib.fsi b/src/Compiler/Utilities/illib.fsi index 03525593188..2b23de7de2e 100644 --- a/src/Compiler/Utilities/illib.fsi +++ b/src/Compiler/Utilities/illib.fsi @@ -570,6 +570,8 @@ module internal MultiMap = val initBy: f: ('a -> 'b) -> xs: seq<'a> -> MultiMap<'b, 'a> when 'b: comparison + val ofList: xs: ('a * 'b) list -> MultiMap<'a,'b> when 'a: comparison + type internal LayeredMap<'Key, 'Value when 'Key: comparison> = Map<'Key, 'Value> [] diff --git a/src/FSharp.Core/prim-types.fs b/src/FSharp.Core/prim-types.fs index 7f1b0a122ad..1fc9e799ab4 100644 --- a/src/FSharp.Core/prim-types.fs +++ b/src/FSharp.Core/prim-types.fs @@ -221,7 +221,7 @@ namespace Microsoft.FSharp.Core member _.Minor = minor member _.Release = release - [] + [] [] type CompilationMappingAttribute(sourceConstructFlags:SourceConstructFlags, variantNumber:int, diff --git a/src/FSharp.Core/prim-types.fsi b/src/FSharp.Core/prim-types.fsi index a992a0204e0..15326559354 100644 --- a/src/FSharp.Core/prim-types.fsi +++ b/src/FSharp.Core/prim-types.fsi @@ -657,7 +657,7 @@ namespace Microsoft.FSharp.Core /// their original forms. It is not intended for use from user code. /// /// Attributes - [] + [] [] type CompilationMappingAttribute = inherit Attribute diff --git a/src/FSharp.Core/reflect.fs b/src/FSharp.Core/reflect.fs index f8c8e57d695..32811ae604c 100644 --- a/src/FSharp.Core/reflect.fs +++ b/src/FSharp.Core/reflect.fs @@ -266,108 +266,103 @@ module internal Impl = //----------------------------------------------------------------- // ATTRIBUTE DECOMPILATION - let tryFindCompilationMappingAttribute (attrs: obj array) = + let findCompilationMappingAttributeAllowMultiple (attrs: obj array) = match attrs with - | null - | [||] -> None - | [| res |] -> - let a = (res :?> CompilationMappingAttribute) - Some(a.SourceConstructFlags, a.SequenceNumber, a.VariantNumber) - | _ -> invalidOp (SR.GetString(SR.multipleCompilationMappings)) - - let findCompilationMappingAttribute (attrs: obj array) = - match tryFindCompilationMappingAttribute attrs with - | None -> failwith "no compilation mapping attribute" - | Some a -> a + | null -> [||] + | attrs -> + attrs + |> Array.map (fun res -> + let a = (res :?> CompilationMappingAttribute) + (a.SourceConstructFlags, a.SequenceNumber, a.VariantNumber)) let cmaName = typeof.FullName let assemblyName = typeof.Assembly.GetName().Name let _ = assert (assemblyName = "FSharp.Core") - let tryFindCompilationMappingAttributeFromData (attrs: IList) = + let findCompilationMappingAttributeFromDataAllowMultiple (attrs: IList) = match attrs with - | null -> None + | null -> [||] | _ -> - let mutable res = None - - for a in attrs do - if a.Constructor.DeclaringType.FullName = cmaName then - let args = a.ConstructorArguments - - let flags = - match args.Count with - | 1 -> - let arg0 = args.[0] - let v0 = arg0.Value :?> SourceConstructFlags - (v0, 0, 0) - | 2 -> - let arg0 = args.[0] - let v0 = arg0.Value :?> SourceConstructFlags - let arg1 = args.[1] - let v1 = arg1.Value :?> int - (v0, v1, 0) - | 3 -> - let arg0 = args.[0] - let v0 = arg0.Value :?> SourceConstructFlags - let arg1 = args.[1] - let v1 = arg1.Value :?> int - let arg2 = args.[2] - let v2 = arg2.Value :?> int - (v0, v1, v2) - | _ -> (enum 0, 0, 0) - - res <- Some flags - - res - - let findCompilationMappingAttributeFromData attrs = - match tryFindCompilationMappingAttributeFromData attrs with - | None -> failwith "no compilation mapping attribute" - | Some a -> a + let filtered = + attrs + |> Array.ofSeq + |> Array.filter (fun a -> a.Constructor.DeclaringType.FullName = cmaName) + + filtered + |> Array.map (fun a -> + let args = a.ConstructorArguments + + match args.Count with + | 1 -> + let arg0 = args.[0] + let v0 = arg0.Value :?> SourceConstructFlags + (v0, 0, 0) + | 2 -> + let arg0 = args.[0] + let v0 = arg0.Value :?> SourceConstructFlags + let arg1 = args.[1] + let v1 = arg1.Value :?> int + (v0, v1, 0) + | 3 -> + let arg0 = args.[0] + let v0 = arg0.Value :?> SourceConstructFlags + let arg1 = args.[1] + let v1 = arg1.Value :?> int + let arg2 = args.[2] + let v2 = arg2.Value :?> int + (v0, v1, v2) + | _ -> (enum 0, 0, 0)) let tryFindCompilationMappingAttributeFromType (typ: Type) = let assem = typ.Assembly if (not (isNull assem)) && assem.ReflectionOnly then - tryFindCompilationMappingAttributeFromData (typ.GetCustomAttributesData()) - else - tryFindCompilationMappingAttribute (typ.GetCustomAttributes(typeof, false)) - - let tryFindCompilationMappingAttributeFromMemberInfo (info: MemberInfo) = - let assem = info.DeclaringType.Assembly - - if (not (isNull assem)) && assem.ReflectionOnly then - tryFindCompilationMappingAttributeFromData (info.GetCustomAttributesData()) + findCompilationMappingAttributeFromDataAllowMultiple (typ.GetCustomAttributesData()) else - tryFindCompilationMappingAttribute (info.GetCustomAttributes(typeof, false)) + findCompilationMappingAttributeAllowMultiple ( + typ.GetCustomAttributes(typeof, false) + ) let findCompilationMappingAttributeFromMemberInfo (info: MemberInfo) = let assem = info.DeclaringType.Assembly if (not (isNull assem)) && assem.ReflectionOnly then - findCompilationMappingAttributeFromData (info.GetCustomAttributesData()) + findCompilationMappingAttributeFromDataAllowMultiple (info.GetCustomAttributesData()) else - findCompilationMappingAttribute (info.GetCustomAttributes(typeof, false)) + findCompilationMappingAttributeAllowMultiple ( + info.GetCustomAttributes(typeof, false) + ) let sequenceNumberOfMember (x: MemberInfo) = - let (_, n, _) = findCompilationMappingAttributeFromMemberInfo x in n + let (_, n, _) = findCompilationMappingAttributeFromMemberInfo x |> Array.head + n + + let sequenceNumberOfUnionCaseField (x: MemberInfo) caseTag = + findCompilationMappingAttributeFromMemberInfo x + |> Array.tryFind (fun (_, _, vn) -> vn = caseTag) + |> Option.map (fun (_, sn, _) -> sn) + |> Option.defaultValue Int32.MaxValue - let variantNumberOfMember (x: MemberInfo) = - let (_, _, vn) = findCompilationMappingAttributeFromMemberInfo x in vn + let belongsToCase (x: MemberInfo) caseTag = + findCompilationMappingAttributeFromMemberInfo x + |> Array.exists (fun (_, _, vn) -> vn = caseTag) let sortFreshArray f arr = Array.sortInPlaceWith f arr arr let isFieldProperty (prop: PropertyInfo) = - match tryFindCompilationMappingAttributeFromMemberInfo prop with - | None -> false - | Some(flags, _n, _vn) -> (flags &&& SourceConstructFlags.KindMask) = SourceConstructFlags.Field + match findCompilationMappingAttributeFromMemberInfo prop with + | [||] -> false + | arr -> + let (flags, _, _) = arr |> Array.head + (flags &&& SourceConstructFlags.KindMask) = SourceConstructFlags.Field let tryFindSourceConstructFlagsOfType (typ: Type) = match tryFindCompilationMappingAttributeFromType typ with - | None -> None - | Some(flags, _n, _vn) -> Some flags + | [||] -> None + | [| flags, _n, _vn |] -> Some flags + | _ -> invalidOp (SR.GetString(SR.multipleCompilationMappings)) //----------------------------------------------------------------- // UNION DECOMPILATION @@ -379,9 +374,11 @@ module internal Impl = | null -> typ.GetMethods(staticMethodFlags ||| bindingFlags) |> Array.choose (fun minfo -> - match tryFindCompilationMappingAttributeFromMemberInfo minfo with - | None -> None - | Some(flags, n, _vn) -> + match findCompilationMappingAttributeFromMemberInfo minfo with + | [||] -> None + | arr -> + let (flags, n, _) = arr |> Array.head + if (flags &&& SourceConstructFlags.KindMask) = SourceConstructFlags.UnionCase then let nm = minfo.Name // chop "get_" or "New" off the front @@ -510,8 +507,9 @@ module internal Impl = caseTyp.GetProperties(instancePropertyFlags ||| bindingFlags) |> Array.filter isFieldProperty - |> Array.filter (fun prop -> variantNumberOfMember prop = tag) - |> sortFreshArray (fun p1 p2 -> compare (sequenceNumberOfMember p1) (sequenceNumberOfMember p2)) + |> Array.filter (fun prop -> belongsToCase prop tag) + |> sortFreshArray (fun p1 p2 -> + compare (sequenceNumberOfUnionCaseField p1 tag) (sequenceNumberOfUnionCaseField p2 tag)) let getUnionCaseRecordReader (typ: Type, tag: int, bindingFlags) = let props = fieldsPropsOfUnionCase (typ, tag, bindingFlags) diff --git a/tests/AheadOfTime/Trimming/check.ps1 b/tests/AheadOfTime/Trimming/check.ps1 index b1380ede186..50a8a9e6422 100644 --- a/tests/AheadOfTime/Trimming/check.ps1 +++ b/tests/AheadOfTime/Trimming/check.ps1 @@ -43,7 +43,7 @@ function CheckTrim($root, $tfm, $outputfile, $expected_len) { # error NETSDK1124: Trimming assemblies requires .NET Core 3.0 or higher. # Check net7.0 trimmed assemblies -CheckTrim -root "SelfContained_Trimming_Test" -tfm "net9.0" -outputfile "FSharp.Core.dll" -expected_len 299008 +CheckTrim -root "SelfContained_Trimming_Test" -tfm "net9.0" -outputfile "FSharp.Core.dll" -expected_len 300032 # Check net8.0 trimmed assemblies -CheckTrim -root "StaticLinkedFSharpCore_Trimming_Test" -tfm "net9.0" -outputfile "StaticLinkedFSharpCore_Trimming_Test.dll" -expected_len 9149952 +CheckTrim -root "StaticLinkedFSharpCore_Trimming_Test" -tfm "net9.0" -outputfile "StaticLinkedFSharpCore_Trimming_Test.dll" -expected_len 9150976 diff --git a/tests/FSharp.Compiler.ComponentTests/Conformance/Types/UnionTypes/UnionStructTypes.fs b/tests/FSharp.Compiler.ComponentTests/Conformance/Types/UnionTypes/UnionStructTypes.fs index b3801e113f5..0ec6dc99632 100644 --- a/tests/FSharp.Compiler.ComponentTests/Conformance/Types/UnionTypes/UnionStructTypes.fs +++ b/tests/FSharp.Compiler.ComponentTests/Conformance/Types/UnionTypes/UnionStructTypes.fs @@ -805,6 +805,77 @@ printf $"{result1};{result2}" |> run |> verifyOutput "333;666" + [] + let ``Struct DU with field overlap can be reflected`` () = + Fsx """module Test +open Microsoft.FSharp.Reflection + +[] +type MySharedStructDu = + | A of a:int64 + | B of a:int64 + | C of a:int64 * s:char + | D of s:char * a:int64 + +printf "Size=%i;" (sizeof) +for value in [A 1L; B 2L;D('x',3L)] do + let caseInfo, inner = FSharpValue.GetUnionFields(value, typeof) + printf $"%s{caseInfo.Name}=%A{inner};" + + """ + |> asExe + |> compile + |> shouldSucceed + |> run + |> verifyOutput """Size=16;A=[|1L|];B=[|2L|];D=[|'x'; 3L|];""" + + [] + let ``Field overlap does carry attributes for all cases`` () = + Fsx """module Test + +[] +type MySharedStructDu = + | A of a:int64 + | B of a:int64 + | C of a:int64 * s:char + | D of s:char * a:int64 + + """ + |> asLibrary + |> compile + |> verifyIL [ // Prop "a" is mapped 4x, for cases 0,1,2,3. For case 3/D, it comes at position one. Prop "s" is mapped to two cases. + """ + .property instance int64 a() + { + .custom instance void [FSharp.Core]Microsoft.FSharp.Core.CompilationMappingAttribute::.ctor(valuetype [FSharp.Core]Microsoft.FSharp.Core.SourceConstructFlags, + int32, + int32) = ( 01 00 04 00 00 00 00 00 00 00 00 00 00 00 00 00 ) + .custom instance void [FSharp.Core]Microsoft.FSharp.Core.CompilationMappingAttribute::.ctor(valuetype [FSharp.Core]Microsoft.FSharp.Core.SourceConstructFlags, + int32, + int32) = ( 01 00 04 00 00 00 01 00 00 00 00 00 00 00 00 00 ) + .custom instance void [FSharp.Core]Microsoft.FSharp.Core.CompilationMappingAttribute::.ctor(valuetype [FSharp.Core]Microsoft.FSharp.Core.SourceConstructFlags, + int32, + int32) = ( 01 00 04 00 00 00 02 00 00 00 00 00 00 00 00 00 ) + .custom instance void [FSharp.Core]Microsoft.FSharp.Core.CompilationMappingAttribute::.ctor(valuetype [FSharp.Core]Microsoft.FSharp.Core.SourceConstructFlags, + int32, + int32) = ( 01 00 04 00 00 00 03 00 00 00 01 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 ) + .get instance int64 Test/MySharedStructDu::get_a() + } + .property instance char s() + { + .custom instance void [FSharp.Core]Microsoft.FSharp.Core.CompilationMappingAttribute::.ctor(valuetype [FSharp.Core]Microsoft.FSharp.Core.SourceConstructFlags, + int32, + int32) = ( 01 00 04 00 00 00 02 00 00 00 01 00 00 00 00 00 ) + .custom instance void [FSharp.Core]Microsoft.FSharp.Core.CompilationMappingAttribute::.ctor(valuetype [FSharp.Core]Microsoft.FSharp.Core.SourceConstructFlags, + int32, + int32) = ( 01 00 04 00 00 00 03 00 00 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 ) + .get instance char Test/MySharedStructDu::get_s() + } """ ] + [] let ``Custom ValueOption keeps working`` () = Fsx """ diff --git a/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Reflection/FSharpReflection.fs b/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Reflection/FSharpReflection.fs index 95de124e9f5..56fd8a0a1b1 100644 --- a/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Reflection/FSharpReflection.fs +++ b/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Reflection/FSharpReflection.fs @@ -51,10 +51,12 @@ type DiscUnionType<'T> = | B of 'T * DiscUnionType<'T> option | C of float * string +[] type DiscStructUnionType<'T> = | A // No data associated with tag | B of 'T - | C of float * string + | Evil_C of f:float // This is sharing the field "f" in the struct + | C of f:float * s:string exception ExceptionInt of int @@ -1204,6 +1206,11 @@ type UnionCaseInfoTests() = let ((discUnionInfoC:UnionCaseInfo), discvaluearray) = FSharpValue.GetUnionFields(discUniontypeC, typeof>) let ((recDiscCaseinfo:UnionCaseInfo), recDiscCasevaluearray) = FSharpValue.GetUnionFields(recDiscUniontypeB, typeof>) + + let ((sharedstructUnionInfoA:UnionCaseInfo), _) = FSharpValue.GetUnionFields(DiscStructUnionType.A, typeof>) + let ((sharedstructUnionInfoB:UnionCaseInfo), _) = FSharpValue.GetUnionFields(DiscStructUnionType.B(15), typeof>) + let ((sharedstructUnionInfoC:UnionCaseInfo), _) = FSharpValue.GetUnionFields(DiscStructUnionType.C(15.,"x"), typeof>) + let ((sharedstructUnionInfoEvilC:UnionCaseInfo), _) = FSharpValue.GetUnionFields(DiscStructUnionType.Evil_C(15.), typeof>) [] member _.Equals() = @@ -1266,6 +1273,15 @@ type UnionCaseInfoTests() = // rec disc union let recdiscFieldInfo = (recDiscCaseinfo.GetFields()).[0] Assert.AreEqual(recdiscFieldInfo.PropertyType , typeof) + + + Assert.AreEqual(sharedstructUnionInfoA.GetFields().Length ,0) + Assert.AreEqual(sharedstructUnionInfoB.GetFields().[0].PropertyType ,typeof) + + Assert.AreEqual(sharedstructUnionInfoC.GetFields().[0].PropertyType ,typeof) + Assert.AreEqual(sharedstructUnionInfoC.GetFields().[1].PropertyType ,typeof) + + Assert.AreEqual(sharedstructUnionInfoEvilC.GetFields().[0].PropertyType ,typeof) [] member _.GetHashCode() = diff --git a/tests/ILVerify/ilverify_FSharp.Compiler.Service_Release_net9.0.bsl b/tests/ILVerify/ilverify_FSharp.Compiler.Service_Release_net9.0.bsl index 1a088c5a702..bc7e03d8154 100644 --- a/tests/ILVerify/ilverify_FSharp.Compiler.Service_Release_net9.0.bsl +++ b/tests/ILVerify/ilverify_FSharp.Compiler.Service_Release_net9.0.bsl @@ -43,8 +43,8 @@ [IL]: Error [StackUnexpected]: : FSharp.Compiler.ParseAndCheckInputs+CheckMultipleInputsUsingGraphMode@1865::Invoke(int32)][offset 0x0000003A][found Char] Unexpected type on the stack. [IL]: Error [StackUnexpected]: : FSharp.Compiler.CompilerConfig+TcConfig::.ctor([FSharp.Compiler.Service]FSharp.Compiler.CompilerConfig+TcConfigBuilder, bool)][offset 0x0000059C][found Char] Unexpected type on the stack. [IL]: Error [StackUnexpected]: : FSharp.Compiler.CompilerConfig+TcConfig::.ctor([FSharp.Compiler.Service]FSharp.Compiler.CompilerConfig+TcConfigBuilder, bool)][offset 0x000005A5][found Char] Unexpected type on the stack. -[IL]: Error [StackUnexpected]: : FSharp.Compiler.IlxGen::HashRangeSorted([S.P.CoreLib]System.Collections.Generic.IDictionary`2>)][offset 0x00000011][found ref '[FSharp.Compiler.Service]FSharp.Compiler.IlxGen+HashRangeSorted@1859-1'][expected ref '[FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2,int32>'] Unexpected type on the stack. -[IL]: Error [StackUnexpected]: : FSharp.Compiler.IlxGen::HashRangeSorted([S.P.CoreLib]System.Collections.Generic.IDictionary`2>)][offset 0x00000012][found ref '[FSharp.Compiler.Service]FSharp.Compiler.IlxGen+HashRangeSorted@1859'][expected ref '[FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2,T0>'] Unexpected type on the stack. +[IL]: Error [StackUnexpected]: : FSharp.Compiler.IlxGen::HashRangeSorted([S.P.CoreLib]System.Collections.Generic.IDictionary`2>)][offset 0x00000011][found ref '[FSharp.Compiler.Service]FSharp.Compiler.IlxGen+HashRangeSorted@1890-1'][expected ref '[FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2,int32>'] Unexpected type on the stack. +[IL]: Error [StackUnexpected]: : FSharp.Compiler.IlxGen::HashRangeSorted([S.P.CoreLib]System.Collections.Generic.IDictionary`2>)][offset 0x00000012][found ref '[FSharp.Compiler.Service]FSharp.Compiler.IlxGen+HashRangeSorted@1890'][expected ref '[FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2,T0>'] Unexpected type on the stack. [IL]: Error [StackUnexpected]: : FSharp.Compiler.PatternMatchCompilation::isProblematicClause([FSharp.Compiler.Service]FSharp.Compiler.PatternMatchCompilation+MatchClause)][offset 0x00000040][found Byte] Unexpected type on the stack. [IL]: Error [StackUnexpected]: : .$FSharp.Compiler.PatternMatchCompilation::.cctor()][offset 0x0000000B][found Boolean] Unexpected type on the stack. [IL]: Error [StackUnexpected]: : FSharp.Compiler.TypeProviders::ValidateExpectedName([FSharp.Compiler.Service]FSharp.Compiler.Text.Range, string[], string, [FSharp.Compiler.Service]FSharp.Compiler.Tainted`1)][offset 0x000000A8][found Char] Unexpected type on the stack. diff --git a/tests/ILVerify/ilverify_FSharp.Compiler.Service_Release_netstandard2.0.bsl b/tests/ILVerify/ilverify_FSharp.Compiler.Service_Release_netstandard2.0.bsl index 48af8ec2f2f..88e5b423f24 100644 --- a/tests/ILVerify/ilverify_FSharp.Compiler.Service_Release_netstandard2.0.bsl +++ b/tests/ILVerify/ilverify_FSharp.Compiler.Service_Release_netstandard2.0.bsl @@ -61,8 +61,8 @@ [IL]: Error [StackUnexpected]: : FSharp.Compiler.CompilerImports+TcConfig-TryResolveLibWithDirectories@558-1::Invoke([FSharp.Core]Microsoft.FSharp.Core.Unit)][offset 0x0000003B][found Char] Unexpected type on the stack. [IL]: Error [StackUnexpected]: : FSharp.Compiler.CompilerConfig+TcConfig::.ctor([FSharp.Compiler.Service]FSharp.Compiler.CompilerConfig+TcConfigBuilder, bool)][offset 0x0000059C][found Char] Unexpected type on the stack. [IL]: Error [StackUnexpected]: : FSharp.Compiler.CompilerConfig+TcConfig::.ctor([FSharp.Compiler.Service]FSharp.Compiler.CompilerConfig+TcConfigBuilder, bool)][offset 0x000005A5][found Char] Unexpected type on the stack. -[IL]: Error [StackUnexpected]: : FSharp.Compiler.IlxGen::HashRangeSorted([S.P.CoreLib]System.Collections.Generic.IDictionary`2>)][offset 0x00000011][found ref '[FSharp.Compiler.Service]FSharp.Compiler.IlxGen+HashRangeSorted@1859-1'][expected ref '[FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2,int32>'] Unexpected type on the stack. -[IL]: Error [StackUnexpected]: : FSharp.Compiler.IlxGen::HashRangeSorted([S.P.CoreLib]System.Collections.Generic.IDictionary`2>)][offset 0x00000012][found ref '[FSharp.Compiler.Service]FSharp.Compiler.IlxGen+HashRangeSorted@1859'][expected ref '[FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2,T0>'] Unexpected type on the stack. +[IL]: Error [StackUnexpected]: : FSharp.Compiler.IlxGen::HashRangeSorted([S.P.CoreLib]System.Collections.Generic.IDictionary`2>)][offset 0x00000011][found ref '[FSharp.Compiler.Service]FSharp.Compiler.IlxGen+HashRangeSorted@1890-1'][expected ref '[FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2,int32>'] Unexpected type on the stack. +[IL]: Error [StackUnexpected]: : FSharp.Compiler.IlxGen::HashRangeSorted([S.P.CoreLib]System.Collections.Generic.IDictionary`2>)][offset 0x00000012][found ref '[FSharp.Compiler.Service]FSharp.Compiler.IlxGen+HashRangeSorted@1890'][expected ref '[FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2,T0>'] Unexpected type on the stack. [IL]: Error [StackUnexpected]: : FSharp.Compiler.PatternMatchCompilation::isProblematicClause([FSharp.Compiler.Service]FSharp.Compiler.PatternMatchCompilation+MatchClause)][offset 0x00000040][found Byte] Unexpected type on the stack. [IL]: Error [StackUnexpected]: : .$FSharp.Compiler.PatternMatchCompilation::.cctor()][offset 0x0000000B][found Boolean] Unexpected type on the stack. [IL]: Error [StackUnexpected]: : FSharp.Compiler.NicePrint+TastDefinitionPrinting+meths@2092-3::Invoke([FSharp.Compiler.Service]FSharp.Compiler.Infos+MethInfo)][offset 0x000000B3][found Char] Unexpected type on the stack. From 5ef029b5b6e5a8ad8ac62054ffdad94a1cf93ffc Mon Sep 17 00:00:00 2001 From: Tomas Grosup Date: Wed, 5 Feb 2025 10:47:22 +0100 Subject: [PATCH 13/29] Add missing project reference from FSharpSuite to fsc project (#18291) * Add missing project reference from FSharpSuite to fsc project * fix --- tests/fsharp/FSharpSuite.Tests.fsproj | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/fsharp/FSharpSuite.Tests.fsproj b/tests/fsharp/FSharpSuite.Tests.fsproj index 753af0ce4aa..fdbec7e88a6 100644 --- a/tests/fsharp/FSharpSuite.Tests.fsproj +++ b/tests/fsharp/FSharpSuite.Tests.fsproj @@ -113,6 +113,9 @@ + + false + From 674e099690a8b20c40901ee8151ef2066cf04f92 Mon Sep 17 00:00:00 2001 From: Eugene Auduchinok Date: Wed, 5 Feb 2025 18:49:16 +0900 Subject: [PATCH 14/29] Symbols: Add FSharpAssembly.IsFSharp (#18290) * Symbols: add FSharpAssembly.IsFSharp * Surface area * Release notes --- .../.FSharp.Compiler.Service/9.0.300.md | 1 + src/Compiler/Symbols/Symbols.fs | 2 ++ src/Compiler/Symbols/Symbols.fsi | 3 +++ ...ervice.SurfaceArea.netstandard20.debug.bsl | 20 ++++++++++--------- ...vice.SurfaceArea.netstandard20.release.bsl | 20 ++++++++++--------- 5 files changed, 28 insertions(+), 18 deletions(-) diff --git a/docs/release-notes/.FSharp.Compiler.Service/9.0.300.md b/docs/release-notes/.FSharp.Compiler.Service/9.0.300.md index 32ae2560ab0..368513722c9 100644 --- a/docs/release-notes/.FSharp.Compiler.Service/9.0.300.md +++ b/docs/release-notes/.FSharp.Compiler.Service/9.0.300.md @@ -11,6 +11,7 @@ ### Added * Added missing type constraints in FCS. ([PR #18241](https://github.com/dotnet/fsharp/pull/18241)) * The 'use' keyword can be used on IDisposable|null without nullness warnings ([PR #18262](https://github.com/dotnet/fsharp/pull/18262)) +* Symbols: Add FSharpAssembly.IsFSharp ([PR #18290](https://github.com/dotnet/fsharp/pull/18290)) ### Changed diff --git a/src/Compiler/Symbols/Symbols.fs b/src/Compiler/Symbols/Symbols.fs index 470327f59cd..f12e9de6321 100644 --- a/src/Compiler/Symbols/Symbols.fs +++ b/src/Compiler/Symbols/Symbols.fs @@ -2991,6 +2991,8 @@ type FSharpAssembly internal (cenv, ccu: CcuThunk) = member _.SimpleName = ccu.AssemblyName + member _.IsFSharp = ccu.IsFSharp + #if !NO_TYPEPROVIDERS member _.IsProviderGenerated = ccu.IsProviderGenerated #endif diff --git a/src/Compiler/Symbols/Symbols.fsi b/src/Compiler/Symbols/Symbols.fsi index 49742673d58..a3eda6ecd3a 100644 --- a/src/Compiler/Symbols/Symbols.fsi +++ b/src/Compiler/Symbols/Symbols.fsi @@ -159,6 +159,9 @@ type FSharpAssembly = /// The simple name for the assembly member SimpleName: string + + member IsFSharp: bool + #if !NO_TYPEPROVIDERS /// Indicates if the assembly was generated by a type provider and is due for static linking member IsProviderGenerated: bool diff --git a/tests/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.SurfaceArea.netstandard20.debug.bsl b/tests/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.SurfaceArea.netstandard20.debug.bsl index e85b3022c96..198dcde56b2 100644 --- a/tests/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.SurfaceArea.netstandard20.debug.bsl +++ b/tests/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.SurfaceArea.netstandard20.debug.bsl @@ -2836,6 +2836,10 @@ FSharp.Compiler.Diagnostics.ExtendedData+FieldNotContainedDiagnosticExtendedData FSharp.Compiler.Diagnostics.ExtendedData+FieldNotContainedDiagnosticExtendedData: FSharp.Compiler.Symbols.FSharpField SignatureField FSharp.Compiler.Diagnostics.ExtendedData+FieldNotContainedDiagnosticExtendedData: FSharp.Compiler.Symbols.FSharpField get_ImplementationField() FSharp.Compiler.Diagnostics.ExtendedData+FieldNotContainedDiagnosticExtendedData: FSharp.Compiler.Symbols.FSharpField get_SignatureField() +FSharp.Compiler.Diagnostics.ExtendedData+ObsoleteDiagnosticExtendedData: System.String DiagnosticId +FSharp.Compiler.Diagnostics.ExtendedData+ObsoleteDiagnosticExtendedData: System.String UrlFormat +FSharp.Compiler.Diagnostics.ExtendedData+ObsoleteDiagnosticExtendedData: System.String get_DiagnosticId() +FSharp.Compiler.Diagnostics.ExtendedData+ObsoleteDiagnosticExtendedData: System.String get_UrlFormat() FSharp.Compiler.Diagnostics.ExtendedData+TypeMismatchDiagnosticExtendedData: DiagnosticContextInfo ContextInfo FSharp.Compiler.Diagnostics.ExtendedData+TypeMismatchDiagnosticExtendedData: DiagnosticContextInfo get_ContextInfo() FSharp.Compiler.Diagnostics.ExtendedData+TypeMismatchDiagnosticExtendedData: FSharp.Compiler.Symbols.FSharpDisplayContext DisplayContext @@ -2854,13 +2858,9 @@ FSharp.Compiler.Diagnostics.ExtendedData: FSharp.Compiler.Diagnostics.ExtendedDa FSharp.Compiler.Diagnostics.ExtendedData: FSharp.Compiler.Diagnostics.ExtendedData+ExpressionIsAFunctionExtendedData FSharp.Compiler.Diagnostics.ExtendedData: FSharp.Compiler.Diagnostics.ExtendedData+FieldNotContainedDiagnosticExtendedData FSharp.Compiler.Diagnostics.ExtendedData: FSharp.Compiler.Diagnostics.ExtendedData+IFSharpDiagnosticExtendedData +FSharp.Compiler.Diagnostics.ExtendedData: FSharp.Compiler.Diagnostics.ExtendedData+ObsoleteDiagnosticExtendedData FSharp.Compiler.Diagnostics.ExtendedData: FSharp.Compiler.Diagnostics.ExtendedData+TypeMismatchDiagnosticExtendedData FSharp.Compiler.Diagnostics.ExtendedData: FSharp.Compiler.Diagnostics.ExtendedData+ValueNotContainedDiagnosticExtendedData -FSharp.Compiler.Diagnostics.ExtendedData+ObsoleteDiagnosticExtendedData: System.String DiagnosticId -FSharp.Compiler.Diagnostics.ExtendedData+ObsoleteDiagnosticExtendedData: System.String UrlFormat -FSharp.Compiler.Diagnostics.ExtendedData+ObsoleteDiagnosticExtendedData: System.String get_DiagnosticId() -FSharp.Compiler.Diagnostics.ExtendedData+ObsoleteDiagnosticExtendedData: System.String get_UrlFormat() -FSharp.Compiler.Diagnostics.ExtendedData: FSharp.Compiler.Diagnostics.ExtendedData+ObsoleteDiagnosticExtendedData FSharp.Compiler.Diagnostics.FSharpDiagnostic: FSharp.Compiler.Diagnostics.FSharpDiagnostic Create(FSharp.Compiler.Diagnostics.FSharpDiagnosticSeverity, System.String, Int32, FSharp.Compiler.Text.Range, Microsoft.FSharp.Core.FSharpOption`1[System.String], Microsoft.FSharp.Core.FSharpOption`1[System.String]) FSharp.Compiler.Diagnostics.FSharpDiagnostic: FSharp.Compiler.Diagnostics.FSharpDiagnosticSeverity Severity FSharp.Compiler.Diagnostics.FSharpDiagnostic: FSharp.Compiler.Diagnostics.FSharpDiagnosticSeverity get_Severity() @@ -5102,7 +5102,9 @@ FSharp.Compiler.Symbols.FSharpAnonRecordTypeDetails: System.String CompiledName FSharp.Compiler.Symbols.FSharpAnonRecordTypeDetails: System.String get_CompiledName() FSharp.Compiler.Symbols.FSharpAnonRecordTypeDetails: System.String[] SortedFieldNames FSharp.Compiler.Symbols.FSharpAnonRecordTypeDetails: System.String[] get_SortedFieldNames() +FSharp.Compiler.Symbols.FSharpAssembly: Boolean IsFSharp FSharp.Compiler.Symbols.FSharpAssembly: Boolean IsProviderGenerated +FSharp.Compiler.Symbols.FSharpAssembly: Boolean get_IsFSharp() FSharp.Compiler.Symbols.FSharpAssembly: Boolean get_IsProviderGenerated() FSharp.Compiler.Symbols.FSharpAssembly: FSharp.Compiler.Symbols.FSharpAssemblySignature Contents FSharp.Compiler.Symbols.FSharpAssembly: FSharp.Compiler.Symbols.FSharpAssemblySignature get_Contents() @@ -5390,6 +5392,7 @@ FSharp.Compiler.Symbols.FSharpGenericParameter: System.Collections.Generic.IList FSharp.Compiler.Symbols.FSharpGenericParameter: System.String Name FSharp.Compiler.Symbols.FSharpGenericParameter: System.String ToString() FSharp.Compiler.Symbols.FSharpGenericParameter: System.String get_Name() +FSharp.Compiler.Symbols.FSharpGenericParameterConstraint: Boolean IsAllowsRefStructConstraint FSharp.Compiler.Symbols.FSharpGenericParameterConstraint: Boolean IsCoercesToConstraint FSharp.Compiler.Symbols.FSharpGenericParameterConstraint: Boolean IsComparisonConstraint FSharp.Compiler.Symbols.FSharpGenericParameterConstraint: Boolean IsDefaultsToConstraint @@ -5398,13 +5401,13 @@ FSharp.Compiler.Symbols.FSharpGenericParameterConstraint: Boolean IsEnumConstrai FSharp.Compiler.Symbols.FSharpGenericParameterConstraint: Boolean IsEqualityConstraint FSharp.Compiler.Symbols.FSharpGenericParameterConstraint: Boolean IsMemberConstraint FSharp.Compiler.Symbols.FSharpGenericParameterConstraint: Boolean IsNonNullableValueTypeConstraint +FSharp.Compiler.Symbols.FSharpGenericParameterConstraint: Boolean IsNotSupportsNullConstraint FSharp.Compiler.Symbols.FSharpGenericParameterConstraint: Boolean IsReferenceTypeConstraint FSharp.Compiler.Symbols.FSharpGenericParameterConstraint: Boolean IsRequiresDefaultConstructorConstraint FSharp.Compiler.Symbols.FSharpGenericParameterConstraint: Boolean IsSimpleChoiceConstraint FSharp.Compiler.Symbols.FSharpGenericParameterConstraint: Boolean IsSupportsNullConstraint FSharp.Compiler.Symbols.FSharpGenericParameterConstraint: Boolean IsUnmanagedConstraint -FSharp.Compiler.Symbols.FSharpGenericParameterConstraint: Boolean IsNotSupportsNullConstraint -FSharp.Compiler.Symbols.FSharpGenericParameterConstraint: Boolean IsAllowsRefStructConstraint +FSharp.Compiler.Symbols.FSharpGenericParameterConstraint: Boolean get_IsAllowsRefStructConstraint() FSharp.Compiler.Symbols.FSharpGenericParameterConstraint: Boolean get_IsCoercesToConstraint() FSharp.Compiler.Symbols.FSharpGenericParameterConstraint: Boolean get_IsComparisonConstraint() FSharp.Compiler.Symbols.FSharpGenericParameterConstraint: Boolean get_IsDefaultsToConstraint() @@ -5413,13 +5416,12 @@ FSharp.Compiler.Symbols.FSharpGenericParameterConstraint: Boolean get_IsEnumCons FSharp.Compiler.Symbols.FSharpGenericParameterConstraint: Boolean get_IsEqualityConstraint() FSharp.Compiler.Symbols.FSharpGenericParameterConstraint: Boolean get_IsMemberConstraint() FSharp.Compiler.Symbols.FSharpGenericParameterConstraint: Boolean get_IsNonNullableValueTypeConstraint() +FSharp.Compiler.Symbols.FSharpGenericParameterConstraint: Boolean get_IsNotSupportsNullConstraint() FSharp.Compiler.Symbols.FSharpGenericParameterConstraint: Boolean get_IsReferenceTypeConstraint() FSharp.Compiler.Symbols.FSharpGenericParameterConstraint: Boolean get_IsRequiresDefaultConstructorConstraint() FSharp.Compiler.Symbols.FSharpGenericParameterConstraint: Boolean get_IsSimpleChoiceConstraint() FSharp.Compiler.Symbols.FSharpGenericParameterConstraint: Boolean get_IsSupportsNullConstraint() FSharp.Compiler.Symbols.FSharpGenericParameterConstraint: Boolean get_IsUnmanagedConstraint() -FSharp.Compiler.Symbols.FSharpGenericParameterConstraint: Boolean get_IsNotSupportsNullConstraint() -FSharp.Compiler.Symbols.FSharpGenericParameterConstraint: Boolean get_IsAllowsRefStructConstraint() FSharp.Compiler.Symbols.FSharpGenericParameterConstraint: FSharp.Compiler.Symbols.FSharpGenericParameterDefaultsToConstraint DefaultsToConstraintData FSharp.Compiler.Symbols.FSharpGenericParameterConstraint: FSharp.Compiler.Symbols.FSharpGenericParameterDefaultsToConstraint get_DefaultsToConstraintData() FSharp.Compiler.Symbols.FSharpGenericParameterConstraint: FSharp.Compiler.Symbols.FSharpGenericParameterDelegateConstraint DelegateConstraintData diff --git a/tests/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.SurfaceArea.netstandard20.release.bsl b/tests/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.SurfaceArea.netstandard20.release.bsl index e85b3022c96..198dcde56b2 100644 --- a/tests/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.SurfaceArea.netstandard20.release.bsl +++ b/tests/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.SurfaceArea.netstandard20.release.bsl @@ -2836,6 +2836,10 @@ FSharp.Compiler.Diagnostics.ExtendedData+FieldNotContainedDiagnosticExtendedData FSharp.Compiler.Diagnostics.ExtendedData+FieldNotContainedDiagnosticExtendedData: FSharp.Compiler.Symbols.FSharpField SignatureField FSharp.Compiler.Diagnostics.ExtendedData+FieldNotContainedDiagnosticExtendedData: FSharp.Compiler.Symbols.FSharpField get_ImplementationField() FSharp.Compiler.Diagnostics.ExtendedData+FieldNotContainedDiagnosticExtendedData: FSharp.Compiler.Symbols.FSharpField get_SignatureField() +FSharp.Compiler.Diagnostics.ExtendedData+ObsoleteDiagnosticExtendedData: System.String DiagnosticId +FSharp.Compiler.Diagnostics.ExtendedData+ObsoleteDiagnosticExtendedData: System.String UrlFormat +FSharp.Compiler.Diagnostics.ExtendedData+ObsoleteDiagnosticExtendedData: System.String get_DiagnosticId() +FSharp.Compiler.Diagnostics.ExtendedData+ObsoleteDiagnosticExtendedData: System.String get_UrlFormat() FSharp.Compiler.Diagnostics.ExtendedData+TypeMismatchDiagnosticExtendedData: DiagnosticContextInfo ContextInfo FSharp.Compiler.Diagnostics.ExtendedData+TypeMismatchDiagnosticExtendedData: DiagnosticContextInfo get_ContextInfo() FSharp.Compiler.Diagnostics.ExtendedData+TypeMismatchDiagnosticExtendedData: FSharp.Compiler.Symbols.FSharpDisplayContext DisplayContext @@ -2854,13 +2858,9 @@ FSharp.Compiler.Diagnostics.ExtendedData: FSharp.Compiler.Diagnostics.ExtendedDa FSharp.Compiler.Diagnostics.ExtendedData: FSharp.Compiler.Diagnostics.ExtendedData+ExpressionIsAFunctionExtendedData FSharp.Compiler.Diagnostics.ExtendedData: FSharp.Compiler.Diagnostics.ExtendedData+FieldNotContainedDiagnosticExtendedData FSharp.Compiler.Diagnostics.ExtendedData: FSharp.Compiler.Diagnostics.ExtendedData+IFSharpDiagnosticExtendedData +FSharp.Compiler.Diagnostics.ExtendedData: FSharp.Compiler.Diagnostics.ExtendedData+ObsoleteDiagnosticExtendedData FSharp.Compiler.Diagnostics.ExtendedData: FSharp.Compiler.Diagnostics.ExtendedData+TypeMismatchDiagnosticExtendedData FSharp.Compiler.Diagnostics.ExtendedData: FSharp.Compiler.Diagnostics.ExtendedData+ValueNotContainedDiagnosticExtendedData -FSharp.Compiler.Diagnostics.ExtendedData+ObsoleteDiagnosticExtendedData: System.String DiagnosticId -FSharp.Compiler.Diagnostics.ExtendedData+ObsoleteDiagnosticExtendedData: System.String UrlFormat -FSharp.Compiler.Diagnostics.ExtendedData+ObsoleteDiagnosticExtendedData: System.String get_DiagnosticId() -FSharp.Compiler.Diagnostics.ExtendedData+ObsoleteDiagnosticExtendedData: System.String get_UrlFormat() -FSharp.Compiler.Diagnostics.ExtendedData: FSharp.Compiler.Diagnostics.ExtendedData+ObsoleteDiagnosticExtendedData FSharp.Compiler.Diagnostics.FSharpDiagnostic: FSharp.Compiler.Diagnostics.FSharpDiagnostic Create(FSharp.Compiler.Diagnostics.FSharpDiagnosticSeverity, System.String, Int32, FSharp.Compiler.Text.Range, Microsoft.FSharp.Core.FSharpOption`1[System.String], Microsoft.FSharp.Core.FSharpOption`1[System.String]) FSharp.Compiler.Diagnostics.FSharpDiagnostic: FSharp.Compiler.Diagnostics.FSharpDiagnosticSeverity Severity FSharp.Compiler.Diagnostics.FSharpDiagnostic: FSharp.Compiler.Diagnostics.FSharpDiagnosticSeverity get_Severity() @@ -5102,7 +5102,9 @@ FSharp.Compiler.Symbols.FSharpAnonRecordTypeDetails: System.String CompiledName FSharp.Compiler.Symbols.FSharpAnonRecordTypeDetails: System.String get_CompiledName() FSharp.Compiler.Symbols.FSharpAnonRecordTypeDetails: System.String[] SortedFieldNames FSharp.Compiler.Symbols.FSharpAnonRecordTypeDetails: System.String[] get_SortedFieldNames() +FSharp.Compiler.Symbols.FSharpAssembly: Boolean IsFSharp FSharp.Compiler.Symbols.FSharpAssembly: Boolean IsProviderGenerated +FSharp.Compiler.Symbols.FSharpAssembly: Boolean get_IsFSharp() FSharp.Compiler.Symbols.FSharpAssembly: Boolean get_IsProviderGenerated() FSharp.Compiler.Symbols.FSharpAssembly: FSharp.Compiler.Symbols.FSharpAssemblySignature Contents FSharp.Compiler.Symbols.FSharpAssembly: FSharp.Compiler.Symbols.FSharpAssemblySignature get_Contents() @@ -5390,6 +5392,7 @@ FSharp.Compiler.Symbols.FSharpGenericParameter: System.Collections.Generic.IList FSharp.Compiler.Symbols.FSharpGenericParameter: System.String Name FSharp.Compiler.Symbols.FSharpGenericParameter: System.String ToString() FSharp.Compiler.Symbols.FSharpGenericParameter: System.String get_Name() +FSharp.Compiler.Symbols.FSharpGenericParameterConstraint: Boolean IsAllowsRefStructConstraint FSharp.Compiler.Symbols.FSharpGenericParameterConstraint: Boolean IsCoercesToConstraint FSharp.Compiler.Symbols.FSharpGenericParameterConstraint: Boolean IsComparisonConstraint FSharp.Compiler.Symbols.FSharpGenericParameterConstraint: Boolean IsDefaultsToConstraint @@ -5398,13 +5401,13 @@ FSharp.Compiler.Symbols.FSharpGenericParameterConstraint: Boolean IsEnumConstrai FSharp.Compiler.Symbols.FSharpGenericParameterConstraint: Boolean IsEqualityConstraint FSharp.Compiler.Symbols.FSharpGenericParameterConstraint: Boolean IsMemberConstraint FSharp.Compiler.Symbols.FSharpGenericParameterConstraint: Boolean IsNonNullableValueTypeConstraint +FSharp.Compiler.Symbols.FSharpGenericParameterConstraint: Boolean IsNotSupportsNullConstraint FSharp.Compiler.Symbols.FSharpGenericParameterConstraint: Boolean IsReferenceTypeConstraint FSharp.Compiler.Symbols.FSharpGenericParameterConstraint: Boolean IsRequiresDefaultConstructorConstraint FSharp.Compiler.Symbols.FSharpGenericParameterConstraint: Boolean IsSimpleChoiceConstraint FSharp.Compiler.Symbols.FSharpGenericParameterConstraint: Boolean IsSupportsNullConstraint FSharp.Compiler.Symbols.FSharpGenericParameterConstraint: Boolean IsUnmanagedConstraint -FSharp.Compiler.Symbols.FSharpGenericParameterConstraint: Boolean IsNotSupportsNullConstraint -FSharp.Compiler.Symbols.FSharpGenericParameterConstraint: Boolean IsAllowsRefStructConstraint +FSharp.Compiler.Symbols.FSharpGenericParameterConstraint: Boolean get_IsAllowsRefStructConstraint() FSharp.Compiler.Symbols.FSharpGenericParameterConstraint: Boolean get_IsCoercesToConstraint() FSharp.Compiler.Symbols.FSharpGenericParameterConstraint: Boolean get_IsComparisonConstraint() FSharp.Compiler.Symbols.FSharpGenericParameterConstraint: Boolean get_IsDefaultsToConstraint() @@ -5413,13 +5416,12 @@ FSharp.Compiler.Symbols.FSharpGenericParameterConstraint: Boolean get_IsEnumCons FSharp.Compiler.Symbols.FSharpGenericParameterConstraint: Boolean get_IsEqualityConstraint() FSharp.Compiler.Symbols.FSharpGenericParameterConstraint: Boolean get_IsMemberConstraint() FSharp.Compiler.Symbols.FSharpGenericParameterConstraint: Boolean get_IsNonNullableValueTypeConstraint() +FSharp.Compiler.Symbols.FSharpGenericParameterConstraint: Boolean get_IsNotSupportsNullConstraint() FSharp.Compiler.Symbols.FSharpGenericParameterConstraint: Boolean get_IsReferenceTypeConstraint() FSharp.Compiler.Symbols.FSharpGenericParameterConstraint: Boolean get_IsRequiresDefaultConstructorConstraint() FSharp.Compiler.Symbols.FSharpGenericParameterConstraint: Boolean get_IsSimpleChoiceConstraint() FSharp.Compiler.Symbols.FSharpGenericParameterConstraint: Boolean get_IsSupportsNullConstraint() FSharp.Compiler.Symbols.FSharpGenericParameterConstraint: Boolean get_IsUnmanagedConstraint() -FSharp.Compiler.Symbols.FSharpGenericParameterConstraint: Boolean get_IsNotSupportsNullConstraint() -FSharp.Compiler.Symbols.FSharpGenericParameterConstraint: Boolean get_IsAllowsRefStructConstraint() FSharp.Compiler.Symbols.FSharpGenericParameterConstraint: FSharp.Compiler.Symbols.FSharpGenericParameterDefaultsToConstraint DefaultsToConstraintData FSharp.Compiler.Symbols.FSharpGenericParameterConstraint: FSharp.Compiler.Symbols.FSharpGenericParameterDefaultsToConstraint get_DefaultsToConstraintData() FSharp.Compiler.Symbols.FSharpGenericParameterConstraint: FSharp.Compiler.Symbols.FSharpGenericParameterDelegateConstraint DelegateConstraintData From 841ba8e7b9b4dc54591b2cdebfce065a7170b97b Mon Sep 17 00:00:00 2001 From: Tomas Grosup Date: Thu, 6 Feb 2025 13:02:29 +0100 Subject: [PATCH 15/29] Bugfix :: Nullness in signature file is not considered by implementation and vice versa (#18186) --- .fantomasignore | 5 + .../.FSharp.Compiler.Service/9.0.300.md | 1 + src/Compiler/AbstractIL/ilreflect.fs | 2 +- src/Compiler/Checking/AttributeChecking.fsi | 4 +- src/Compiler/Checking/CheckDeclarations.fs | 12 +-- src/Compiler/Checking/ConstraintSolver.fs | 2 +- .../Checking/Expressions/CheckExpressions.fs | 2 +- src/Compiler/Checking/InfoReader.fs | 3 +- src/Compiler/Checking/MethodCalls.fs | 14 +-- src/Compiler/Checking/MethodOverrides.fs | 4 +- src/Compiler/Checking/NameResolution.fs | 2 +- src/Compiler/Checking/NicePrint.fs | 6 +- src/Compiler/Checking/SignatureConformance.fs | 52 +++++++--- .../Checking/SignatureConformance.fsi | 6 ++ src/Compiler/Checking/import.fs | 20 ++-- src/Compiler/Checking/import.fsi | 1 - src/Compiler/Checking/infos.fs | 8 +- src/Compiler/CodeGen/IlxGen.fs | 6 +- src/Compiler/CodeGen/IlxGen.fsi | 4 +- .../AssemblyResolveHandler.fs | 2 +- .../AssemblyResolveHandler.fsi | 2 +- .../DependencyManager/DependencyProvider.fs | 4 +- .../DependencyManager/DependencyProvider.fsi | 6 +- .../NativeDllResolveHandler.fs | 2 +- .../NativeDllResolveHandler.fsi | 2 +- src/Compiler/Driver/CompilerConfig.fs | 8 +- src/Compiler/Driver/CompilerDiagnostics.fs | 10 +- src/Compiler/Driver/ParseAndCheckInputs.fs | 11 ++- src/Compiler/Driver/fsc.fs | 2 +- src/Compiler/FSComp.txt | 2 + src/Compiler/Facilities/CompilerLocation.fs | 1 + src/Compiler/Facilities/DiagnosticsLogger.fs | 3 +- src/Compiler/Facilities/DiagnosticsLogger.fsi | 1 + src/Compiler/Facilities/prim-parsing.fs | 5 +- src/Compiler/Interactive/fsi.fs | 40 ++++---- src/Compiler/Interactive/fsi.fsi | 6 +- src/Compiler/Service/FSharpCheckerResults.fs | 2 +- src/Compiler/Service/QuickParse.fs | 2 +- src/Compiler/Symbols/Exprs.fsi | 2 +- src/Compiler/Symbols/FSharpDiagnostic.fs | 4 +- src/Compiler/Symbols/Symbols.fs | 2 +- src/Compiler/Symbols/Symbols.fsi | 10 +- src/Compiler/SyntaxTree/PrettyNaming.fs | 4 +- src/Compiler/TypedTree/TypeProviders.fs | 94 ++++++++----------- src/Compiler/TypedTree/TypeProviders.fsi | 73 +++++++------- src/Compiler/TypedTree/TypedTree.fs | 2 +- src/Compiler/TypedTree/TypedTree.fsi | 4 +- src/Compiler/TypedTree/TypedTreeOps.fs | 74 ++++++++------- src/Compiler/TypedTree/TypedTreeOps.fsi | 12 +-- src/Compiler/TypedTree/tainted.fs | 6 ++ src/Compiler/TypedTree/tainted.fsi | 3 + src/Compiler/Utilities/FileSystem.fs | 6 +- src/Compiler/Utilities/NullnessShims.fs | 8 ++ src/Compiler/Utilities/TaggedCollections.fs | 13 ++- src/Compiler/Utilities/TaggedCollections.fsi | 5 +- src/Compiler/Utilities/illib.fs | 12 +-- src/Compiler/Utilities/illib.fsi | 6 +- src/Compiler/Utilities/lib.fsi | 2 +- src/Compiler/Utilities/range.fs | 16 +++- src/Compiler/xlf/FSComp.txt.cs.xlf | 10 ++ src/Compiler/xlf/FSComp.txt.de.xlf | 10 ++ src/Compiler/xlf/FSComp.txt.es.xlf | 10 ++ src/Compiler/xlf/FSComp.txt.fr.xlf | 10 ++ src/Compiler/xlf/FSComp.txt.it.xlf | 10 ++ src/Compiler/xlf/FSComp.txt.ja.xlf | 10 ++ src/Compiler/xlf/FSComp.txt.ko.xlf | 10 ++ src/Compiler/xlf/FSComp.txt.pl.xlf | 10 ++ src/Compiler/xlf/FSComp.txt.pt-BR.xlf | 10 ++ src/Compiler/xlf/FSComp.txt.ru.xlf | 10 ++ src/Compiler/xlf/FSComp.txt.tr.xlf | 10 ++ src/Compiler/xlf/FSComp.txt.zh-Hans.xlf | 10 ++ src/Compiler/xlf/FSComp.txt.zh-Hant.xlf | 10 ++ src/FSharp.Build/FSharpEmbedResourceText.fs | 8 +- src/FSharp.Core/fslib-extra-pervasives.fs | 2 +- src/FSharp.Core/fslib-extra-pervasives.fsi | 2 +- src/FSharp.Core/map.fsi | 1 - src/FSharp.Core/prim-types.fsi | 12 +-- src/FSharp.Core/quotations.fsi | 2 - src/FSharp.Core/set.fsi | 1 - .../HasSignatureWithMissingOverride.fs | 10 ++ .../HasSignatureWithMissingOverride.fsi | 5 + .../EmittedIL/Nullness/NullnessMetadata.fs | 22 ++++- .../Nullness/NullableRegressionTests.fs | 40 ++++++++ .../Language/Nullness/micro.fs | 2 +- .../Language/Nullness/micro.fsi | 2 +- .../Language/Nullness/signatures.fs | 18 ++++ .../Language/Nullness/signatures.fsi | 15 +++ tests/FSharp.Test.Utilities/Compiler.fs | 7 +- ...y_FSharp.Compiler.Service_Debug_net9.0.bsl | 14 +-- ....Compiler.Service_Debug_netstandard2.0.bsl | 16 ++-- ...FSharp.Compiler.Service_Release_net9.0.bsl | 14 +-- ...ompiler.Service_Release_netstandard2.0.bsl | 16 ++-- 92 files changed, 639 insertions(+), 323 deletions(-) create mode 100644 tests/FSharp.Compiler.ComponentTests/EmittedIL/Nullness/HasSignatureWithMissingOverride.fs create mode 100644 tests/FSharp.Compiler.ComponentTests/EmittedIL/Nullness/HasSignatureWithMissingOverride.fsi create mode 100644 tests/FSharp.Compiler.ComponentTests/Language/Nullness/signatures.fs create mode 100644 tests/FSharp.Compiler.ComponentTests/Language/Nullness/signatures.fsi diff --git a/.fantomasignore b/.fantomasignore index d1bea49f566..9c12ffa8e2c 100644 --- a/.fantomasignore +++ b/.fantomasignore @@ -42,6 +42,8 @@ src/Compiler/Checking/TypeRelations.fs # nullness-related problems src/Compiler/DependencyManager/DependencyProvider.fs +src/FSharp.Core/fslib-extra-pervasives.fs +src/FSharp.Core/fslib-extra-pervasives.fsi # Incorrectly formatted: https://github.com/dotnet/fsharp/pull/14645/commits/49443a67ea8a17670c8a7c80c8bdf91f82231e91 or https://github.com/fsprojects/fantomas/issues/2733 # This CompilerImports.fs behavior is not fixed yet, following up in https://github.com/fsprojects/fantomas/issues/2733 @@ -124,6 +126,9 @@ src/Compiler/SyntaxTree/LexerStore.fs src/Compiler/Driver/GraphChecking/Graph.fsi src/Compiler/Driver/GraphChecking/Graph.fs +src/Compiler/DependencyManager/NativeDllResolveHandler.fsi +src/Compiler/DependencyManager/AssemblyResolveHandler.fsi + # Fantomas limitations on implementation files (to investigate) src/Compiler/AbstractIL/ilwrite.fs diff --git a/docs/release-notes/.FSharp.Compiler.Service/9.0.300.md b/docs/release-notes/.FSharp.Compiler.Service/9.0.300.md index 368513722c9..f41b4ca9289 100644 --- a/docs/release-notes/.FSharp.Compiler.Service/9.0.300.md +++ b/docs/release-notes/.FSharp.Compiler.Service/9.0.300.md @@ -11,6 +11,7 @@ ### Added * Added missing type constraints in FCS. ([PR #18241](https://github.com/dotnet/fsharp/pull/18241)) * The 'use' keyword can be used on IDisposable|null without nullness warnings ([PR #18262](https://github.com/dotnet/fsharp/pull/18262)) +* Nullness warnings are issued for signature<>implementation conformance ([PR #18186](https://github.com/dotnet/fsharp/pull/18186)) * Symbols: Add FSharpAssembly.IsFSharp ([PR #18290](https://github.com/dotnet/fsharp/pull/18290)) ### Changed diff --git a/src/Compiler/AbstractIL/ilreflect.fs b/src/Compiler/AbstractIL/ilreflect.fs index d88cc24d689..45c0652c59d 100644 --- a/src/Compiler/AbstractIL/ilreflect.fs +++ b/src/Compiler/AbstractIL/ilreflect.fs @@ -2548,7 +2548,7 @@ let EmitDynamicAssemblyFragment ignore (typB.InvokeMemberAndLog(methodName, BindingFlags.InvokeMethod ||| BindingFlags.Public ||| BindingFlags.Static, [||])) None with :? TargetInvocationException as exn -> - Some exn.InnerException + Option.ofObj exn.InnerException let emEnv, entryPts = envPopEntryPts emEnv let execs = List.map execEntryPtFun entryPts diff --git a/src/Compiler/Checking/AttributeChecking.fsi b/src/Compiler/Checking/AttributeChecking.fsi index 5885c1b39e9..143763f889c 100644 --- a/src/Compiler/Checking/AttributeChecking.fsi +++ b/src/Compiler/Checking/AttributeChecking.fsi @@ -24,8 +24,8 @@ type AttribInfo = | FSAttribInfo of TcGlobals * Attrib | ILAttribInfo of TcGlobals * Import.ImportMap * ILScopeRef * ILAttribute * range - member ConstructorArguments: (TType * obj) list - member NamedArguments: (TType * string * bool * obj) list + member ConstructorArguments: (TType * objnull) list + member NamedArguments: (TType * string * bool * objnull) list member Range: range member TyconRef: TyconRef diff --git a/src/Compiler/Checking/CheckDeclarations.fs b/src/Compiler/Checking/CheckDeclarations.fs index af3e712a8db..f6b405bf1d6 100644 --- a/src/Compiler/Checking/CheckDeclarations.fs +++ b/src/Compiler/Checking/CheckDeclarations.fs @@ -3060,7 +3060,7 @@ module EstablishTypeDefinitionCores = if not isRootGenerated then let desig = theRootTypeWithRemapping.TypeProviderDesignation - let nm = theRootTypeWithRemapping.PUntaint((fun st -> st.FullName), m) + let nm = theRootTypeWithRemapping.PUntaint((fun st -> string st.FullName), m) error(Error(FSComp.SR.etErasedTypeUsedInGeneration(desig, nm), m)) cenv.createsGeneratedProvidedTypes <- true @@ -3101,7 +3101,7 @@ module EstablishTypeDefinitionCores = if not isGenerated then let desig = st.TypeProviderDesignation - let nm = st.PUntaint((fun st -> st.FullName), m) + let nm = st.PUntaint((fun st -> string st.FullName), m) error(Error(FSComp.SR.etErasedTypeUsedInGeneration(desig, nm), m)) // Embed the type into the module we're compiling @@ -4251,7 +4251,7 @@ module TcDeclarations = // For historical reasons we only give a warning for incorrect type parameters on intrinsic extensions if nReqTypars <> synTypars.Length then errorR(Error(FSComp.SR.tcDeclaredTypeParametersForExtensionDoNotMatchOriginal(tcref.DisplayNameWithStaticParametersAndUnderscoreTypars), m)) - if not (typarsAEquiv g TypeEquivEnv.Empty reqTypars declaredTypars) then + if not (typarsAEquiv g (TypeEquivEnv.EmptyWithNullChecks g) reqTypars declaredTypars) then warning(Error(FSComp.SR.tcDeclaredTypeParametersForExtensionDoNotMatchOriginal(tcref.DisplayNameWithStaticParametersAndUnderscoreTypars), m)) // Note we return 'reqTypars' for intrinsic extensions since we may only have given warnings IntrinsicExtensionBinding, reqTypars @@ -4260,7 +4260,7 @@ module TcDeclarations = errorR(Error(FSComp.SR.tcMembersThatExtendInterfaceMustBePlacedInSeparateModule(), tcref.Range)) if nReqTypars <> synTypars.Length then error(Error(FSComp.SR.tcDeclaredTypeParametersForExtensionDoNotMatchOriginal(tcref.DisplayNameWithStaticParametersAndUnderscoreTypars), m)) - if not (typarsAEquiv g TypeEquivEnv.Empty reqTypars declaredTypars) then + if not (typarsAEquiv g (TypeEquivEnv.EmptyWithNullChecks g) reqTypars declaredTypars) then errorR(Error(FSComp.SR.tcDeclaredTypeParametersForExtensionDoNotMatchOriginal(tcref.DisplayNameWithStaticParametersAndUnderscoreTypars), m)) ExtrinsicExtensionBinding, declaredTypars @@ -5702,7 +5702,7 @@ let CheckModuleSignature g (cenv: cenv) m denvAtEnd rootSigOpt implFileTypePrior |] // We want to show imperative type variables in any types in error messages at this late point - let denv = { denvAtEnd with showInferenceTyparAnnotations=true } + let denv = { denvAtEnd with showInferenceTyparAnnotations=true;showNullnessAnnotations=Some g.checkNullness } try // As typechecked the signature and implementation use different tycons etc. @@ -5714,7 +5714,7 @@ let CheckModuleSignature g (cenv: cenv) m denvAtEnd rootSigOpt implFileTypePrior // Compute the remapping from implementation to signature let remapInfo, _ = ComputeRemappingFromInferredSignatureToExplicitSignature g implFileTypePriorToSig sigFileType - let aenv = { TypeEquivEnv.Empty with EquivTycons = TyconRefMap.OfList remapInfo.RepackagedEntities } + let aenv = { TypeEquivEnv.EmptyWithNullChecks g with EquivTycons = TyconRefMap.OfList remapInfo.RepackagedEntities } if not (SignatureConformance.Checker(g, cenv.amap, denv, remapInfo, true).CheckSignature aenv cenv.infoReader (mkLocalModuleRef implFileSpecPriorToSig) sigFileType) then // We can just raise 'ReportedError' since CheckModuleOrNamespace raises its own error diff --git a/src/Compiler/Checking/ConstraintSolver.fs b/src/Compiler/Checking/ConstraintSolver.fs index 902bf331d85..50026fe382a 100644 --- a/src/Compiler/Checking/ConstraintSolver.fs +++ b/src/Compiler/Checking/ConstraintSolver.fs @@ -345,7 +345,7 @@ let MakeConstraintSolverEnv contextInfo css m denv = eContextInfo = contextInfo MatchingOnly = false ErrorOnFailedMemberConstraintResolution = false - EquivEnv = TypeEquivEnv.Empty + EquivEnv = TypeEquivEnv.EmptyIgnoreNulls DisplayEnv = denv IsSpeculativeForMethodOverloading = false IsSupportsNullFlex = false diff --git a/src/Compiler/Checking/Expressions/CheckExpressions.fs b/src/Compiler/Checking/Expressions/CheckExpressions.fs index f33c7239063..d34d9cf2978 100644 --- a/src/Compiler/Checking/Expressions/CheckExpressions.fs +++ b/src/Compiler/Checking/Expressions/CheckExpressions.fs @@ -12687,7 +12687,7 @@ and FixupLetrecBind (cenv: cenv) denv generalizedTyparsForRecursiveBlock (bind: | Some _ -> match PartitionValTyparsForApparentEnclosingType g vspec with | Some(parentTypars, memberParentTypars, _, _, _) -> - ignore(SignatureConformance.Checker(g, cenv.amap, denv, SignatureRepackageInfo.Empty, false).CheckTypars vspec.Range TypeEquivEnv.Empty memberParentTypars parentTypars) + ignore(SignatureConformance.Checker(g, cenv.amap, denv, SignatureRepackageInfo.Empty, false).CheckTypars vspec.Range TypeEquivEnv.EmptyIgnoreNulls memberParentTypars parentTypars) | None -> errorR(Error(FSComp.SR.tcMemberIsNotSufficientlyGeneric(), vspec.Range)) | _ -> () diff --git a/src/Compiler/Checking/InfoReader.fs b/src/Compiler/Checking/InfoReader.fs index 77fb623efb0..b8a0efd14af 100644 --- a/src/Compiler/Checking/InfoReader.fs +++ b/src/Compiler/Checking/InfoReader.fs @@ -63,7 +63,8 @@ let rec GetImmediateIntrinsicMethInfosOfTypeAux (optFilter, ad) g amap m withExp let st = info.ProvidedType let meths = match optFilter with - | Some name -> st.PApplyArray ((fun st -> st.GetMethods() |> Array.filter (fun mi -> mi.Name = name) ), "GetMethods", m) + | Some name -> + st.PApplyFilteredArray ((fun st -> st.GetMethods()),(fun mi -> mi.Name = name), "GetMethods", m) | None -> st.PApplyArray ((fun st -> st.GetMethods()), "GetMethods", m) [ for mi in meths -> ProvidedMeth(amap, mi.Coerce(m), None, m) ] #endif diff --git a/src/Compiler/Checking/MethodCalls.fs b/src/Compiler/Checking/MethodCalls.fs index 4c561dd7fee..41d731f007e 100644 --- a/src/Compiler/Checking/MethodCalls.fs +++ b/src/Compiler/Checking/MethodCalls.fs @@ -1120,7 +1120,7 @@ let TryImportProvidedMethodBaseAsLibraryIntrinsic (amap: Import.ImportMap, m: ra match tryTcrefOfAppTy amap.g declaringType with | ValueSome declaringEntity -> if not declaringEntity.IsLocalRef && ccuEq declaringEntity.nlr.Ccu amap.g.fslibCcu then - let n = mbase.PUntaint((fun x -> x.GetParameters().Length), m) + let n = mbase.PApplyArray((fun x -> x.GetParameters()),"GetParameters", m).Length match amap.g.knownIntrinsics.TryGetValue ((declaringEntity.LogicalName, None, methodName, n)) with | true, vref -> Some vref | _ -> @@ -1815,14 +1815,14 @@ module ProvidedMethodCalls = let rec loop (st: Tainted) = if st.PUntaint((fun st -> st.IsGenericParameter), m) then st elif st.PUntaint((fun st -> st.IsArray), m) then - let et = st.PApply((fun st -> st.GetElementType()), m) + let et = st.PApply((fun st -> !! st.GetElementType()), m) let rank = st.PUntaint((fun st -> st.GetArrayRank()), m) (loop et).PApply((fun st -> if rank = 1 then st.MakeArrayType() else st.MakeArrayType(rank)), m) elif st.PUntaint((fun st -> st.IsByRef), m) then - let et = st.PApply((fun st -> st.GetElementType()), m) + let et = st.PApply((fun st -> !! st.GetElementType()), m) (loop et).PApply((fun st -> st.MakeByRefType()), m) elif st.PUntaint((fun st -> st.IsPointer), m) then - let et = st.PApply((fun st -> st.GetElementType()), m) + let et = st.PApply((fun st -> !! st.GetElementType()), m) (loop et).PApply((fun st -> st.MakePointerType()), m) else let isGeneric = st.PUntaint((fun st -> st.IsGenericType), m) @@ -1863,7 +1863,7 @@ module ProvidedMethodCalls = allArgs: Exprs, paramVars: Tainted[], g, amap, mut, isProp, isSuperInit, m, - expr: Tainted) = + expr: Tainted) = let varConv = // note: Assuming the size based on paramVars @@ -1873,7 +1873,7 @@ module ProvidedMethodCalls = dict.Add(v, (None, e)) dict - let rec exprToExprAndWitness top (ea: Tainted) = + let rec exprToExprAndWitness top (ea: Tainted) = let fail() = error(Error(FSComp.SR.etUnsupportedProvidedExpression(ea.PUntaint((fun etree -> etree.UnderlyingExpressionString), m)), m)) match ea with | Tainted.Null -> error(Error(FSComp.SR.etNullProvidedExpression(ea.TypeProviderDesignation), m)) @@ -2115,7 +2115,7 @@ module ProvidedMethodCalls = methInfoOpt, expr, exprTy with | :? TypeProviderError as tpe -> - let typeName = mi.PUntaint((fun mb -> (nonNull mb.DeclaringType).FullName), m) + let typeName = mi.PUntaint((fun mb -> (nonNull mb.DeclaringType).FullName |> string), m) let methName = mi.PUntaint((fun mb -> mb.Name), m) raise( tpe.WithContext(typeName, methName) ) // loses original stack trace #endif diff --git a/src/Compiler/Checking/MethodOverrides.fs b/src/Compiler/Checking/MethodOverrides.fs index 18b3f23190f..4621aed620e 100644 --- a/src/Compiler/Checking/MethodOverrides.fs +++ b/src/Compiler/Checking/MethodOverrides.fs @@ -269,7 +269,7 @@ module DispatchSlotChecking = // Compare the types. CompiledSigOfMeth, GetObjectExprOverrideInfo and GetTypeMemberOverrideInfo have already // applied all relevant substitutions except the renamings from fvtmps <-> methTypars - let aenv = TypeEquivEnv.FromEquivTypars fvmethTypars methTypars + let aenv = (TypeEquivEnv.EmptyIgnoreNulls).FromEquivTypars fvmethTypars methTypars List.forall2 (List.lengthsEqAndForall2 (typeAEquiv g aenv)) vargTys argTys && returnTypesAEquiv g aenv vrty retTy && @@ -305,7 +305,7 @@ module DispatchSlotChecking = ComposeTyparInsts ttpinst (ReverseTyparRenaming g memberToParentInst) // Compare under the composed substitutions - let aenv = TypeEquivEnv.FromTyparInst ttpinst + let aenv = (TypeEquivEnv.EmptyIgnoreNulls).FromTyparInst ttpinst typarsAEquiv g aenv fvmethTypars methTypars diff --git a/src/Compiler/Checking/NameResolution.fs b/src/Compiler/Checking/NameResolution.fs index 5b0c9842f77..e3ad26d3ed7 100644 --- a/src/Compiler/Checking/NameResolution.fs +++ b/src/Compiler/Checking/NameResolution.fs @@ -991,7 +991,7 @@ let ResolveProvidedTypeNameInEntity (amap, m, typeName, modref: ModuleOrNamespac //if staticResInfo.NumStaticArgs > 0 then // error(Error(FSComp.SR.etNestedProvidedTypesDoNotTakeStaticArgumentsOrGenericParameters(), m)) [] - | nestedSty -> + | Tainted.NonNull nestedSty -> [AddEntityForProvidedType (amap, modref, resolutionEnvironment, nestedSty, m) ] | _ -> [] #endif diff --git a/src/Compiler/Checking/NicePrint.fs b/src/Compiler/Checking/NicePrint.fs index a01802b1d7c..282773b6b8b 100644 --- a/src/Compiler/Checking/NicePrint.fs +++ b/src/Compiler/Checking/NicePrint.fs @@ -764,7 +764,7 @@ module PrintTypes = |> ListSet.setify (fun (_, cx1) (_, cx2) -> match cx1, cx2 with | TyparConstraint.MayResolveMember(traitInfo1, _), - TyparConstraint.MayResolveMember(traitInfo2, _) -> traitsAEquiv denv.g TypeEquivEnv.Empty traitInfo1 traitInfo2 + TyparConstraint.MayResolveMember(traitInfo2, _) -> traitsAEquiv denv.g (TypeEquivEnv.EmptyWithNullChecks denv.g) traitInfo1 traitInfo2 | _ -> false) let cxsL = List.collect (layoutConstraintWithInfo denv env) cxs @@ -2177,7 +2177,7 @@ module TastDefinitionPrinting = match tcref.TypeReprInfo with | TProvidedTypeRepr info -> [ - for nestedType in info.ProvidedType.PApplyArray((fun sty -> sty.GetNestedTypes() |> Array.filter (fun t -> t.IsPublic || t.IsNestedPublic)), "GetNestedTypes", m) do + for nestedType in info.ProvidedType.PApplyFilteredArray((fun sty -> sty.GetNestedTypes()),(fun t -> t.IsPublic || t.IsNestedPublic), "GetNestedTypes", m) do yield nestedType.PUntaint((fun t -> t.IsClass, t.Name), m) ] |> List.sortBy snd @@ -2930,7 +2930,7 @@ let minimalStringsOfTwoTypes denv ty1 ty2 = let denv = denv.SetOpenPaths [] let denv = { denv with includeStaticParametersInTypeNames=true } let makeName t = - let assemblyName = PrintTypes.layoutAssemblyName denv t |> function Null | NonNull "" -> "" | NonNull name -> sprintf " (%s)" name + let assemblyName = PrintTypes.layoutAssemblyName denv t |> function | "" -> "" | name -> $" (%s{name})" sprintf "%s%s" (stringOfTy denv t) assemblyName (makeName ty1, makeName ty2, stringOfTyparConstraints denv tpcs) diff --git a/src/Compiler/Checking/SignatureConformance.fs b/src/Compiler/Checking/SignatureConformance.fs index 8e8dc84eb2b..d922423017f 100644 --- a/src/Compiler/Checking/SignatureConformance.fs +++ b/src/Compiler/Checking/SignatureConformance.fs @@ -25,15 +25,17 @@ open FSharp.Compiler.TypeHierarchy open FSharp.Compiler.TypeProviders #endif +type TypeMismatchSource = NullnessOnlyMismatch | RegularMismatch + exception RequiredButNotSpecified of DisplayEnv * ModuleOrNamespaceRef * string * (StringBuilder -> unit) * range -exception ValueNotContained of DisplayEnv * InfoReader * ModuleOrNamespaceRef * Val * Val * (string * string * string -> string) +exception ValueNotContained of kind:TypeMismatchSource * DisplayEnv * InfoReader * ModuleOrNamespaceRef * Val * Val * (string * string * string -> string) exception UnionCaseNotContained of DisplayEnv * InfoReader * Tycon * UnionCase * UnionCase * (string * string -> string) exception FSharpExceptionNotContained of DisplayEnv * InfoReader * Tycon * Tycon * (string * string -> string) -exception FieldNotContained of DisplayEnv * InfoReader * Tycon * Tycon * RecdField * RecdField * (string * string -> string) +exception FieldNotContained of kind:TypeMismatchSource * DisplayEnv * InfoReader * Tycon * Tycon * RecdField * RecdField * (string * string -> string) exception InterfaceNotRevealed of DisplayEnv * TType * range @@ -338,8 +340,8 @@ type Checker(g, amap, denv, remapInfo: SignatureRepackageInfo, checkingSig) = implVal.SetOtherRange (sigVal.Range, false) implVal.SetOtherXmlDoc(sigVal.XmlDoc) - let mk_err denv f = ValueNotContained(denv, infoReader, implModRef, implVal, sigVal, f) - let err denv f = errorR(mk_err denv f); false + let mk_err kind denv f = ValueNotContained(kind,denv, infoReader, implModRef, implVal, sigVal, f) + let err denv f = errorR(mk_err RegularMismatch denv f); false let m = implVal.Range if implVal.IsMutable <> sigVal.IsMutable then (err denv FSComp.SR.ValueNotContainedMutabilityAttributesDiffer) elif implVal.LogicalName <> sigVal.LogicalName then (err denv FSComp.SR.ValueNotContainedMutabilityNamesDiffer) @@ -352,14 +354,22 @@ type Checker(g, amap, denv, remapInfo: SignatureRepackageInfo, checkingSig) = else let implTypars, implValTy = implVal.GeneralizedType let sigTypars, sigValTy = sigVal.GeneralizedType - if implTypars.Length <> sigTypars.Length then (err {denv with showTyparBinding=true} FSComp.SR.ValueNotContainedMutabilityParameterCountsDiffer) else - let aenv = aenv.BindEquivTypars implTypars sigTypars - checkTypars m aenv implTypars sigTypars && - if not (typeAEquiv g aenv implValTy sigValTy) then err denv FSComp.SR.ValueNotContainedMutabilityTypesDiffer - elif not (checkValInfo aenv (err denv) implVal sigVal) then false - elif implVal.IsExtensionMember <> sigVal.IsExtensionMember then err denv FSComp.SR.ValueNotContainedMutabilityExtensionsDiffer - elif not (checkMemberDatasConform (err denv) (implVal.Attribs, implVal, implVal.MemberInfo) (sigVal.Attribs, sigVal, sigVal.MemberInfo)) then false - else checkAttribs aenv implVal.Attribs sigVal.Attribs (fun attribs -> implVal.SetAttribs attribs) + if implTypars.Length <> sigTypars.Length then (err {denv with showTyparBinding=true} FSComp.SR.ValueNotContainedMutabilityParameterCountsDiffer) + else + let aenv = aenv.BindEquivTypars implTypars sigTypars + checkTypars m aenv implTypars sigTypars && + let strictTyEquals = typeAEquiv g aenv implValTy sigValTy + let onlyDiffersInNullness = not(strictTyEquals) && g.checkNullness && typeAEquiv g {aenv with NullnessMustEqual = false} implValTy sigValTy + + // The types would be equal if we did not have nullness checks => lets just generate a warning, not an error + if onlyDiffersInNullness then + warning(mk_err NullnessOnlyMismatch denv FSComp.SR.ValueNotContainedMutabilityTypesDifferNullness) + + if not strictTyEquals && not onlyDiffersInNullness then err denv FSComp.SR.ValueNotContainedMutabilityTypesDiffer + elif not (checkValInfo aenv (err denv) implVal sigVal) then false + elif implVal.IsExtensionMember <> sigVal.IsExtensionMember then err denv FSComp.SR.ValueNotContainedMutabilityExtensionsDiffer + elif not (checkMemberDatasConform (err denv) (implVal.Attribs, implVal, implVal.MemberInfo) (sigVal.Attribs, sigVal, sigVal.MemberInfo)) then false + else checkAttribs aenv implVal.Attribs sigVal.Attribs (fun attribs -> implVal.SetAttribs attribs) and checkExnInfo err aenv (infoReader: InfoReader) (enclosingImplTycon: Tycon) (enclosingSigTycon: Tycon) implTypeRepr sigTypeRepr = @@ -394,7 +404,21 @@ type Checker(g, amap, denv, remapInfo: SignatureRepackageInfo, checkingSig) = and checkField aenv infoReader (enclosingImplTycon: Tycon) (enclosingSigTycon: Tycon) implField sigField = implField.SetOtherXmlDoc(sigField.XmlDoc) - let err f = errorR(FieldNotContained(denv, infoReader, enclosingImplTycon, enclosingSigTycon, implField, sigField, f)); false + let diag kind f = FieldNotContained(kind,denv, infoReader, enclosingImplTycon, enclosingSigTycon, implField, sigField, f) + let err f = errorR(diag RegularMismatch f); false + + let areTypesDifferent() = + let strictTyEquals = typeAEquiv g aenv implField.FormalType sigField.FormalType + let onlyDiffersInNullness = not(strictTyEquals) && g.checkNullness && typeAEquiv g {aenv with NullnessMustEqual = false} implField.FormalType sigField.FormalType + + // The types would be equal if we did not have nullness checks => lets just generate a warning, not an error + if onlyDiffersInNullness then + warning(diag NullnessOnlyMismatch FSComp.SR.FieldNotContainedTypesDifferNullness) + false + else + not strictTyEquals + + sigField.rfield_other_range <- Some (implField.Range, true) implField.rfield_other_range <- Some (sigField.Range, false) if implField.rfield_id.idText <> sigField.rfield_id.idText then err FSComp.SR.FieldNotContainedNamesDiffer @@ -402,7 +426,7 @@ type Checker(g, amap, denv, remapInfo: SignatureRepackageInfo, checkingSig) = elif implField.IsStatic <> sigField.IsStatic then err FSComp.SR.FieldNotContainedStaticsDiffer elif implField.IsMutable <> sigField.IsMutable then err FSComp.SR.FieldNotContainedMutablesDiffer elif implField.LiteralValue <> sigField.LiteralValue then err FSComp.SR.FieldNotContainedLiteralsDiffer - elif not (typeAEquiv g aenv implField.FormalType sigField.FormalType) then err FSComp.SR.FieldNotContainedTypesDiffer + elif areTypesDifferent() then err FSComp.SR.FieldNotContainedTypesDiffer else checkAttribs aenv implField.FieldAttribs sigField.FieldAttribs (fun attribs -> implField.rfield_fattribs <- attribs) && checkAttribs aenv implField.PropertyAttribs sigField.PropertyAttribs (fun attribs -> implField.rfield_pattribs <- attribs) diff --git a/src/Compiler/Checking/SignatureConformance.fsi b/src/Compiler/Checking/SignatureConformance.fsi index 1b137968945..136cedce94f 100644 --- a/src/Compiler/Checking/SignatureConformance.fsi +++ b/src/Compiler/Checking/SignatureConformance.fsi @@ -13,9 +13,14 @@ open FSharp.Compiler.TypedTree open FSharp.Compiler.TypedTreeOps open FSharp.Compiler.InfoReader +type TypeMismatchSource = + | NullnessOnlyMismatch + | RegularMismatch + exception RequiredButNotSpecified of DisplayEnv * ModuleOrNamespaceRef * string * (StringBuilder -> unit) * range exception ValueNotContained of + kind: TypeMismatchSource * DisplayEnv * InfoReader * ModuleOrNamespaceRef * @@ -28,6 +33,7 @@ exception UnionCaseNotContained of DisplayEnv * InfoReader * Tycon * UnionCase * exception FSharpExceptionNotContained of DisplayEnv * InfoReader * Tycon * Tycon * (string * string -> string) exception FieldNotContained of + kind: TypeMismatchSource * DisplayEnv * InfoReader * Tycon * diff --git a/src/Compiler/Checking/import.fs b/src/Compiler/Checking/import.fs index c40fd73b234..c87d6cdad03 100644 --- a/src/Compiler/Checking/import.fs +++ b/src/Compiler/Checking/import.fs @@ -75,7 +75,7 @@ type [] TTypeCacheKey = stampEquals this.tcGlobals this.ty1 other.ty1 && stampEquals this.tcGlobals this.ty2 other.ty2 - override this.Equals other = + override this.Equals(other:objnull) = match other with | :? TTypeCacheKey as p -> (this :> System.IEquatable).Equals p | _ -> false @@ -450,13 +450,13 @@ let rec ImportProvidedTypeAsILType (env: ImportMap) (m: range) (st: Tainted st.IsGenericParameter), m) then mkILTyvarTy (uint16 (st.PUntaint((fun st -> st.GenericParameterPosition), m))) elif st.PUntaint((fun st -> st.IsArray), m) then - let et = ImportProvidedTypeAsILType env m (st.PApply((fun st -> st.GetElementType()), m)) + let et = ImportProvidedTypeAsILType env m (st.PApply((fun st -> !! st.GetElementType()), m)) ILType.Array(ILArrayShape.FromRank (st.PUntaint((fun st -> st.GetArrayRank()), m)), et) elif st.PUntaint((fun st -> st.IsByRef), m) then - let et = ImportProvidedTypeAsILType env m (st.PApply((fun st -> st.GetElementType()), m)) + let et = ImportProvidedTypeAsILType env m (st.PApply((fun st -> !! st.GetElementType()), m)) ILType.Byref et elif st.PUntaint((fun st -> st.IsPointer), m) then - let et = ImportProvidedTypeAsILType env m (st.PApply((fun st -> st.GetElementType()), m)) + let et = ImportProvidedTypeAsILType env m (st.PApply((fun st -> !! st.GetElementType()), m)) ILType.Ptr et else let gst, genericArgs = @@ -494,15 +494,15 @@ let rec ImportProvidedType (env: ImportMap) (m: range) (* (tinst: TypeInst) *) ( let g = env.g if st.PUntaint((fun st -> st.IsArray), m) then - let elemTy = ImportProvidedType env m (* tinst *) (st.PApply((fun st -> st.GetElementType()), m)) + let elemTy = ImportProvidedType env m (* tinst *) (st.PApply((fun st -> !! st.GetElementType()), m)) // TODO Nullness - integration into type providers as a separate feature for later. let nullness = Nullness.knownAmbivalent mkArrayTy g (st.PUntaint((fun st -> st.GetArrayRank()), m)) nullness elemTy m elif st.PUntaint((fun st -> st.IsByRef), m) then - let elemTy = ImportProvidedType env m (* tinst *) (st.PApply((fun st -> st.GetElementType()), m)) + let elemTy = ImportProvidedType env m (* tinst *) (st.PApply((fun st -> !! st.GetElementType()), m)) mkByrefTy g elemTy elif st.PUntaint((fun st -> st.IsPointer), m) then - let elemTy = ImportProvidedType env m (* tinst *) (st.PApply((fun st -> st.GetElementType()), m)) + let elemTy = ImportProvidedType env m (* tinst *) (st.PApply((fun st -> !! st.GetElementType()), m)) if isUnitTy g elemTy || isVoidTy g elemTy && g.voidptr_tcr.CanDeref then mkVoidPtrTy g else @@ -602,7 +602,7 @@ let ImportProvidedMethodBaseAsILMethodRef (env: ImportMap) (m: range) (mbase: Ta | Some found -> found.Coerce(m) | None -> let methodName = minfo.PUntaint((fun minfo -> minfo.Name), m) - let typeName = declaringGenericTypeDefn.PUntaint((fun declaringGenericTypeDefn -> declaringGenericTypeDefn.FullName), m) + let typeName = declaringGenericTypeDefn.PUntaint((fun declaringGenericTypeDefn -> string declaringGenericTypeDefn.FullName), m) error(Error(FSComp.SR.etIncorrectProvidedMethod(DisplayNameOfTypeProvider(minfo.TypeProvider, m), methodName, metadataToken, typeName), m)) | _ -> match mbase.OfType() with @@ -634,7 +634,7 @@ let ImportProvidedMethodBaseAsILMethodRef (env: ImportMap) (m: range) (mbase: Ta match found with | Some found -> found.Coerce(m) | None -> - let typeName = declaringGenericTypeDefn.PUntaint((fun x -> x.FullName), m) + let typeName = declaringGenericTypeDefn.PUntaint((fun x -> string x.FullName), m) error(Error(FSComp.SR.etIncorrectProvidedConstructor(DisplayNameOfTypeProvider(cinfo.TypeProvider, m), typeName), m)) | _ -> mbase @@ -648,7 +648,7 @@ let ImportProvidedMethodBaseAsILMethodRef (env: ImportMap) (m: range) (mbase: Ta let genericArity = if mbase.PUntaint((fun x -> x.IsGenericMethod), m) then - mbase.PUntaint((fun x -> x.GetGenericArguments().Length), m) + mbase.PApplyArray((fun x -> x.GetGenericArguments()),"GetGenericArguments", m).Length else 0 let callingConv = (if mbase.PUntaint((fun x -> x.IsStatic), m) then ILCallingConv.Static else ILCallingConv.Instance) diff --git a/src/Compiler/Checking/import.fsi b/src/Compiler/Checking/import.fsi index 001f9367989..c387558fcba 100644 --- a/src/Compiler/Checking/import.fsi +++ b/src/Compiler/Checking/import.fsi @@ -54,7 +54,6 @@ type TTypeCacheKey = val ty2: TType val canCoerce: CanCoerce val tcGlobals: TcGlobals - override Equals: other: obj -> bool override GetHashCode: unit -> int /// Represents a context used for converting AbstractIL .NET and provided types to F# internal compiler data structures. diff --git a/src/Compiler/Checking/infos.fs b/src/Compiler/Checking/infos.fs index 18add6588d0..3fe1ba2f7b1 100644 --- a/src/Compiler/Checking/infos.fs +++ b/src/Compiler/Checking/infos.fs @@ -859,7 +859,7 @@ type MethInfo = | MethInfoWithModifiedReturnType(mi, _) -> mi.NumArgs | DefaultStructCtor _ -> [0] #if !NO_TYPEPROVIDERS - | ProvidedMeth(_, mi, _, m) -> [mi.PUntaint((fun mi -> mi.GetParameters().Length), m)] // Why is this a list? Answer: because the method might be curried + | ProvidedMeth(_, mi, _, m) -> [mi.PApplyArray((fun mi -> mi.GetParameters()),"GetParameters", m).Length] // Why is this a list? Answer: because the method might be curried #endif /// Indicates if the property is a IsABC union case tester implied by a union case definition @@ -2030,7 +2030,7 @@ type PropInfo = failwith "unreachable" #if !NO_TYPEPROVIDERS | ProvidedProp(_, pi, m) -> - pi.PUntaint((fun pi -> pi.GetIndexParameters().Length), m)>0 + pi.PApplyArray((fun pi -> pi.GetIndexParameters()),"GetIndexParameters", m).Length>0 #endif /// Indicates if this is an F# property compiled as a CLI event, e.g. a [] property. @@ -2503,7 +2503,7 @@ let MethInfosEquivByPartialSig erasureFlag ignoreFinal g amap m (minfo: MethInfo let argTys = minfo.GetParamTypes(amap, m, fminst) let argTys2 = minfo2.GetParamTypes(amap, m, fminst2) (argTys, argTys2) ||> List.lengthsEqAndForall2 (List.lengthsEqAndForall2 (fun ty1 ty2 -> - typeAEquivAux erasureFlag g (TypeEquivEnv.FromEquivTypars formalMethTypars formalMethTypars2) (stripByrefTy g ty1) (stripByrefTy g ty2))) + typeAEquivAux erasureFlag g (TypeEquivEnv.EmptyIgnoreNulls.FromEquivTypars formalMethTypars formalMethTypars2) (stripByrefTy g ty1) (stripByrefTy g ty2))) /// Used to hide/filter members from super classes based on signature /// Inref and outref parameter types will be treated as a byref type for equivalency. @@ -2525,7 +2525,7 @@ let MethInfosEquivByNameAndSig erasureFlag ignoreFinal g amap m minfo minfo2 = let (CompiledSig(_, retTy2, formalMethTypars2, _)) = CompiledSigOfMeth g amap m minfo2 match retTy, retTy2 with | None, None -> true - | Some retTy, Some retTy2 -> typeAEquivAux erasureFlag g (TypeEquivEnv.FromEquivTypars formalMethTypars formalMethTypars2) retTy retTy2 + | Some retTy, Some retTy2 -> typeAEquivAux erasureFlag g (TypeEquivEnv.EmptyIgnoreNulls.FromEquivTypars formalMethTypars formalMethTypars2) retTy retTy2 | _ -> false /// Used to hide/filter members from super classes based on signature diff --git a/src/Compiler/CodeGen/IlxGen.fs b/src/Compiler/CodeGen/IlxGen.fs index ff0859486d7..53cfb3e77cd 100644 --- a/src/Compiler/CodeGen/IlxGen.fs +++ b/src/Compiler/CodeGen/IlxGen.fs @@ -12227,7 +12227,7 @@ let LookupGeneratedValue (cenv: cenv) (ctxt: ExecutionContext) eenv (v: Val) = // Lookup the compiled v value (as an object). match StorageForVal v.Range v eenv with | StaticPropertyWithField(fspec, _, hasLiteralAttr, ilContainerTy, _, _, ilGetterMethRef, _, _) -> - let obj = + let obj: objnull = if hasLiteralAttr then let staticTy = ctxt.LookupTypeRef fspec.DeclaringTypeRef // Checked: This FieldInfo (FieldBuilder) supports GetValue(). @@ -12245,7 +12245,7 @@ let LookupGeneratedValue (cenv: cenv) (ctxt: ExecutionContext) eenv (v: Val) = Some(obj, objTyp ()) | StaticProperty(ilGetterMethSpec, _) -> - let obj = + let obj: objnull = let staticTy = ctxt.LookupTypeRef ilGetterMethSpec.MethodRef.DeclaringTypeRef // We can't call .Invoke on the ILMethodRef's MethodInfo, // because it is the MethodBuilder and that does not support Invoke. @@ -12373,7 +12373,7 @@ type IlxAssemblyGenerator(amap: ImportMap, g: TcGlobals, tcVal: ConstraintSolver member _.ClearGeneratedValue(ctxt, v) = ClearGeneratedValue ctxt ilxGenEnv v /// Invert the compilation of the given value and set the storage of the value, even if it is immutable - member _.ForceSetGeneratedValue(ctxt, v, value: obj) = + member _.ForceSetGeneratedValue(ctxt, v, value: objnull) = SetGeneratedValue ctxt ilxGenEnv true v value /// Invert the compilation of the given value and return its current dynamic value and its compiled System.Type diff --git a/src/Compiler/CodeGen/IlxGen.fsi b/src/Compiler/CodeGen/IlxGen.fsi index 4658dd0693b..bb78a30fe41 100644 --- a/src/Compiler/CodeGen/IlxGen.fsi +++ b/src/Compiler/CodeGen/IlxGen.fsi @@ -111,10 +111,10 @@ type public IlxAssemblyGenerator = member ClearGeneratedValue: ExecutionContext * Val -> unit /// Invert the compilation of the given value and set the storage of the value, even if it is immutable - member ForceSetGeneratedValue: ExecutionContext * Val * obj -> unit + member ForceSetGeneratedValue: ExecutionContext * Val * objnull -> unit /// Invert the compilation of the given value and return its current dynamic value and its compiled System.Type - member LookupGeneratedValue: ExecutionContext * Val -> (obj * Type) option + member LookupGeneratedValue: ExecutionContext * Val -> (objnull * Type) option val ReportStatistics: TextWriter -> unit diff --git a/src/Compiler/DependencyManager/AssemblyResolveHandler.fs b/src/Compiler/DependencyManager/AssemblyResolveHandler.fs index 0c87130608e..1f20caa392e 100644 --- a/src/Compiler/DependencyManager/AssemblyResolveHandler.fs +++ b/src/Compiler/DependencyManager/AssemblyResolveHandler.fs @@ -113,7 +113,7 @@ type AssemblyResolveHandler internal (assemblyProbingPaths: AssemblyResolutionPr else new AssemblyResolveHandlerDeskTop(assemblyProbingPaths) :> IDisposable) - new(assemblyProbingPaths: AssemblyResolutionProbe MaybeNull) = new AssemblyResolveHandler(Option.ofObj assemblyProbingPaths) + new(assemblyProbingPaths: AssemblyResolutionProbe | null) = new AssemblyResolveHandler(Option.ofObj assemblyProbingPaths) interface IDisposable with member _.Dispose() = diff --git a/src/Compiler/DependencyManager/AssemblyResolveHandler.fsi b/src/Compiler/DependencyManager/AssemblyResolveHandler.fsi index 0fbb6c33535..e1c0b2574e3 100644 --- a/src/Compiler/DependencyManager/AssemblyResolveHandler.fsi +++ b/src/Compiler/DependencyManager/AssemblyResolveHandler.fsi @@ -12,7 +12,7 @@ type AssemblyResolutionProbe = delegate of Unit -> seq type AssemblyResolveHandler = /// Construct a new DependencyProvider - new: assemblyProbingPaths: AssemblyResolutionProbe -> AssemblyResolveHandler + new: assemblyProbingPaths: AssemblyResolutionProbe|null -> AssemblyResolveHandler /// Construct a new DependencyProvider internal new: assemblyProbingPaths: AssemblyResolutionProbe option -> AssemblyResolveHandler diff --git a/src/Compiler/DependencyManager/DependencyProvider.fs b/src/Compiler/DependencyManager/DependencyProvider.fs index 1bf72a76e5b..6e641af607b 100644 --- a/src/Compiler/DependencyManager/DependencyProvider.fs +++ b/src/Compiler/DependencyManager/DependencyProvider.fs @@ -564,7 +564,7 @@ type DependencyProvider new() = new DependencyProvider(None, None, true) /// Returns a formatted help messages for registered dependencymanagers for the host to present - member _.GetRegisteredDependencyManagerHelpText(compilerTools, outputDir, errorReport) = + member _.GetRegisteredDependencyManagerHelpText(compilerTools, outputDir : string | null, errorReport) = [| let managers = RegisteredDependencyManagers compilerTools (Option.ofString outputDir) errorReport @@ -575,7 +575,7 @@ type DependencyProvider |] /// Clear the DependencyManager results caches - member _.ClearResultsCache(compilerTools, outputDir, errorReport) = + member _.ClearResultsCache(compilerTools, outputDir : string | null, errorReport) = let managers = RegisteredDependencyManagers compilerTools (Option.ofString outputDir) errorReport diff --git a/src/Compiler/DependencyManager/DependencyProvider.fsi b/src/Compiler/DependencyManager/DependencyProvider.fsi index fffaa9a2026..aa1bd27d5b7 100644 --- a/src/Compiler/DependencyManager/DependencyProvider.fsi +++ b/src/Compiler/DependencyManager/DependencyProvider.fsi @@ -108,10 +108,10 @@ type DependencyProvider = DependencyProvider /// Returns a formatted help messages for registered dependencymanagers for the host to present - member GetRegisteredDependencyManagerHelpText: string seq * string * ResolvingErrorReport -> string[] + member GetRegisteredDependencyManagerHelpText: string seq * string MaybeNull * ResolvingErrorReport -> string[] /// Clear the DependencyManager results caches - member ClearResultsCache: string seq * string * ResolvingErrorReport -> unit + member ClearResultsCache: string seq * string MaybeNull * ResolvingErrorReport -> unit /// Returns a formatted error message for the host to present member CreatePackageManagerUnknownError: string seq * string * string * ResolvingErrorReport -> int * string @@ -123,7 +123,7 @@ type DependencyProvider = packageManagerTextLines: (string * string) seq * reportError: ResolvingErrorReport * executionTfm: string * - [] executionRid: string * + [] executionRid: string MaybeNull* [] implicitIncludeDir: string * [] mainScriptName: string * [] fileName: string * diff --git a/src/Compiler/DependencyManager/NativeDllResolveHandler.fs b/src/Compiler/DependencyManager/NativeDllResolveHandler.fs index 6319f3df48b..3c6bbe0a900 100644 --- a/src/Compiler/DependencyManager/NativeDllResolveHandler.fs +++ b/src/Compiler/DependencyManager/NativeDllResolveHandler.fs @@ -184,7 +184,7 @@ type NativeDllResolveHandler(nativeProbingRoots: NativeResolutionProbe option) = |> Option.filter (fun _ -> isRunningOnCoreClr) |> Option.map (fun _ -> new NativeDllResolveHandlerCoreClr(nativeProbingRoots)) - new(nativeProbingRoots: NativeResolutionProbe MaybeNull) = new NativeDllResolveHandler(Option.ofObj nativeProbingRoots) + new(nativeProbingRoots: NativeResolutionProbe | null) = new NativeDllResolveHandler(Option.ofObj nativeProbingRoots) member internal _.RefreshPathsInEnvironment(roots: string seq) = handler |> Option.iter (fun handler -> handler.RefreshPathsInEnvironment(roots)) diff --git a/src/Compiler/DependencyManager/NativeDllResolveHandler.fsi b/src/Compiler/DependencyManager/NativeDllResolveHandler.fsi index 8bb2babae2a..9d2961aa94e 100644 --- a/src/Compiler/DependencyManager/NativeDllResolveHandler.fsi +++ b/src/Compiler/DependencyManager/NativeDllResolveHandler.fsi @@ -12,7 +12,7 @@ type NativeResolutionProbe = delegate of Unit -> seq type NativeDllResolveHandler = /// Construct a new NativeDllResolveHandler - new: nativeProbingRoots: NativeResolutionProbe -> NativeDllResolveHandler + new: nativeProbingRoots: NativeResolutionProbe|null -> NativeDllResolveHandler /// Construct a new NativeDllResolveHandler internal new: nativeProbingRoots: NativeResolutionProbe option -> NativeDllResolveHandler diff --git a/src/Compiler/Driver/CompilerConfig.fs b/src/Compiler/Driver/CompilerConfig.fs index 997f7a50aae..cf875be4959 100644 --- a/src/Compiler/Driver/CompilerConfig.fs +++ b/src/Compiler/Driver/CompilerConfig.fs @@ -317,14 +317,15 @@ type AssemblyReference = member x.ProjectReference = (let (AssemblyReference(_, _, contents)) = x in contents) - member x.SimpleAssemblyNameIs name = + member x.SimpleAssemblyNameIs(name: string) = (String.Compare(FileSystemUtils.fileNameWithoutExtensionWithValidate false x.Text, name, StringComparison.OrdinalIgnoreCase) = 0) || not (x.Text.Contains "/") && not (x.Text.Contains "\\") && not (x.Text.EndsWith(".dll", StringComparison.InvariantCultureIgnoreCase)) && not (x.Text.EndsWith(".exe", StringComparison.InvariantCultureIgnoreCase)) && (try - let aname = System.Reflection.AssemblyName x.Text in aname.Name = name + let aname = System.Reflection.AssemblyName x.Text + aname.Name = name with _ -> false) @@ -699,9 +700,6 @@ type TcConfigBuilder = rangeForErrors ) = - let defaultFSharpBinariesDir = - nullArgCheck "defaultFSharpBinariesDir" defaultFSharpBinariesDir - // These are all default values, many can be overridden using the command line switch { primaryAssembly = PrimaryAssembly.Mscorlib diff --git a/src/Compiler/Driver/CompilerDiagnostics.fs b/src/Compiler/Driver/CompilerDiagnostics.fs index 019226f46e4..289d993e96e 100644 --- a/src/Compiler/Driver/CompilerDiagnostics.fs +++ b/src/Compiler/Driver/CompilerDiagnostics.fs @@ -158,8 +158,8 @@ type Exception with | IndeterminateType m | TyconBadArgs(_, _, _, m) -> Some m - | FieldNotContained(_, _, _, _, arf, _, _) -> Some arf.Range - | ValueNotContained(_, _, _, aval, _, _) -> Some aval.Range + | FieldNotContained(_, _, _, _, _, arf, _, _) -> Some arf.Range + | ValueNotContained(_, _, _, _, aval, _, _) -> Some aval.Range | UnionCaseNotContained(_, _, _, aval, _, _) -> Some aval.Id.idRange | FSharpExceptionNotContained(_, _, aexnc, _, _) -> Some aexnc.Range @@ -255,6 +255,8 @@ type Exception with | LetRecUnsound _ -> 31 | FieldsFromDifferentTypes _ -> 32 | TyconBadArgs _ -> 33 + | FieldNotContained(kind = TypeMismatchSource.NullnessOnlyMismatch) -> 3261 + | ValueNotContained(kind = TypeMismatchSource.NullnessOnlyMismatch) -> 3261 | ValueNotContained _ -> 34 | Deprecated _ -> 35 | UnionCaseNotContained _ -> 36 @@ -1616,7 +1618,7 @@ type Exception with | UnionPatternsBindDifferentNames _ -> os.AppendString(UnionPatternsBindDifferentNamesE().Format) - | ValueNotContained(denv, infoReader, mref, implVal, sigVal, f) -> + | ValueNotContained(_, denv, infoReader, mref, implVal, sigVal, f) -> let text1, text2 = NicePrint.minimalStringsOfTwoValues denv infoReader (mkLocalValRef implVal) (mkLocalValRef sigVal) @@ -1640,7 +1642,7 @@ type Exception with ) ) - | FieldNotContained(denv, infoReader, enclosingTycon, _, v1, v2, f) -> + | FieldNotContained(_, denv, infoReader, enclosingTycon, _, v1, v2, f) -> let enclosingTcref = mkLocalEntityRef enclosingTycon os.AppendString( diff --git a/src/Compiler/Driver/ParseAndCheckInputs.fs b/src/Compiler/Driver/ParseAndCheckInputs.fs index 22ea3c7f033..975bfeef66f 100644 --- a/src/Compiler/Driver/ParseAndCheckInputs.fs +++ b/src/Compiler/Driver/ParseAndCheckInputs.fs @@ -828,7 +828,7 @@ let ParseInputFilesInParallel (tcConfig: TcConfig, lexResourceManager, sourceFil UseMultipleDiagnosticLoggers (sourceFiles, delayLogger, None) (fun sourceFilesWithDelayLoggers -> sourceFilesWithDelayLoggers |> ListParallel.map (fun ((fileName, isLastCompiland), delayLogger) -> - let directoryName = Path.GetDirectoryName fileName + let directoryName = !!(Path.GetDirectoryName fileName) let input = parseInputFileAux (tcConfig, lexResourceManager, fileName, (isLastCompiland, isExe), delayLogger, retryLocked) @@ -841,7 +841,7 @@ let ParseInputFilesSequential (tcConfig: TcConfig, lexResourceManager, sourceFil sourceFiles |> Array.map (fun (fileName, isLastCompiland) -> - let directoryName = Path.GetDirectoryName fileName + let directoryName = !!(Path.GetDirectoryName fileName) let input = ParseOneInputFile(tcConfig, lexResourceManager, fileName, (isLastCompiland, isExe), diagnosticsLogger, retryLocked) @@ -1907,7 +1907,10 @@ let CheckMultipleInputsUsingGraphMode let (Finisher(finisher = finisher)) = cancellable { use _ = UseDiagnosticsLogger logger - let checkForErrors2 () = priorErrors || (logger.ErrorCount > 0) + + let checkForErrors2 () = + priorErrors || (logger.CheckForRealErrorsIgnoringWarnings) + let tcSink = TcResultsSink.NoSink return! @@ -1922,7 +1925,7 @@ let CheckMultipleInputsUsingGraphMode (fun (state: State) -> let tcState, priorErrors = state let (partialResult: PartialResult, tcState) = finisher tcState - let hasErrors = logger.ErrorCount > 0 + let hasErrors = logger.CheckForRealErrorsIgnoringWarnings let priorOrCurrentErrors = priorErrors || hasErrors let state: State = tcState, priorOrCurrentErrors partialResult, state) diff --git a/src/Compiler/Driver/fsc.fs b/src/Compiler/Driver/fsc.fs index 696761f43da..0e26f2db4ac 100644 --- a/src/Compiler/Driver/fsc.fs +++ b/src/Compiler/Driver/fsc.fs @@ -164,7 +164,7 @@ let TypeCheck CheckClosedInputSet( ctok, - diagnosticsLogger.CheckForErrors, + (fun () -> diagnosticsLogger.CheckForRealErrorsIgnoringWarnings), tcConfig, tcImports, tcGlobals, diff --git a/src/Compiler/FSComp.txt b/src/Compiler/FSComp.txt index 4bdee0183ea..ad95dc6556b 100644 --- a/src/Compiler/FSComp.txt +++ b/src/Compiler/FSComp.txt @@ -112,6 +112,7 @@ ValueNotContainedMutabilityLiteralConstantValuesDiffer,"Module '%s' contains\n ValueNotContainedMutabilityOneIsTypeFunction,"Module '%s' contains\n %s \nbut its signature specifies\n %s \nOne is a type function and the other is not. The signature requires explicit type parameters if they are present in the implementation." ValueNotContainedMutabilityParameterCountsDiffer,"Module '%s' contains\n %s \nbut its signature specifies\n %s \nThe respective type parameter counts differ" ValueNotContainedMutabilityTypesDiffer,"Module '%s' contains\n %s \nbut its signature specifies\n %s \nThe types differ" +ValueNotContainedMutabilityTypesDifferNullness,"Nullness warning: Module '%s' contains\n %s \nbut its signature specifies\n %s \nThe types differ in their nullness annotations" ValueNotContainedMutabilityExtensionsDiffer,"Module '%s' contains\n %s \nbut its signature specifies\n %s \nOne is an extension member and the other is not" ValueNotContainedMutabilityArityNotInferred,"Module '%s' contains\n %s \nbut its signature specifies\n %s \nAn arity was not inferred for this value" ValueNotContainedMutabilityGenericParametersDiffer,"Module '%s' contains\n %s \nbut its signature specifies\n %s \nThe number of generic parameters in the signature and implementation differ (the signature declares %s but the implementation declares %s" @@ -167,6 +168,7 @@ FieldNotContainedStaticsDiffer,"The module contains the field\n %s \nbut i FieldNotContainedMutablesDiffer,"The module contains the field\n %s \nbut its signature specifies\n %s \nThe 'mutable' modifiers differ" FieldNotContainedLiteralsDiffer,"The module contains the field\n %s \nbut its signature specifies\n %s \nThe 'literal' modifiers differ" FieldNotContainedTypesDiffer,"The module contains the field\n %s \nbut its signature specifies\n %s \nThe types differ" +FieldNotContainedTypesDifferNullness,"Nullness warning: The module contains the field\n %s \nbut its signature specifies\n %s \nThe types differ in their nullness annotations" 331,typrelCannotResolveImplicitGenericInstantiation,"The implicit instantiation of a generic construct at or near this point could not be resolved because it could resolve to multiple unrelated types, e.g. '%s' and '%s'. Consider using type annotations to resolve the ambiguity" 333,typrelCannotResolveAmbiguityInPrintf,"Could not resolve the ambiguity inherent in the use of a 'printf'-style format string" 334,typrelCannotResolveAmbiguityInEnum,"Could not resolve the ambiguity in the use of a generic construct with an 'enum' constraint at or near this position" diff --git a/src/Compiler/Facilities/CompilerLocation.fs b/src/Compiler/Facilities/CompilerLocation.fs index 9cd20c1863e..2e9137fc75d 100644 --- a/src/Compiler/Facilities/CompilerLocation.fs +++ b/src/Compiler/Facilities/CompilerLocation.fs @@ -32,6 +32,7 @@ module internal FSharpEnvironment = let FSharpCoreLibRunningVersion = try match versionOf with + | null -> None | s when String.IsNullOrEmpty(s) -> None | s -> Some(s) with _ -> diff --git a/src/Compiler/Facilities/DiagnosticsLogger.fs b/src/Compiler/Facilities/DiagnosticsLogger.fs index 69d1f4fc306..cf5c20fe84c 100644 --- a/src/Compiler/Facilities/DiagnosticsLogger.fs +++ b/src/Compiler/Facilities/DiagnosticsLogger.fs @@ -795,8 +795,7 @@ let NewlineifyErrorString (message: string) = /// fixes given string by replacing all control chars with spaces. /// NOTE: newlines are recognized and replaced with stringThatIsAProxyForANewlineInFlatErrors (ASCII 29, the 'group separator'), /// which is decoded by the IDE with 'NewlineifyErrorString' back into newlines, so that multi-line errors can be displayed in QuickInfo -let NormalizeErrorString (text: string MaybeNull) = - let text = nullArgCheck "text" text +let NormalizeErrorString (text: string) = let text = text.Trim() let buf = System.Text.StringBuilder() diff --git a/src/Compiler/Facilities/DiagnosticsLogger.fsi b/src/Compiler/Facilities/DiagnosticsLogger.fsi index e5a4c8e7f8a..da7a6a66ca8 100644 --- a/src/Compiler/Facilities/DiagnosticsLogger.fsi +++ b/src/Compiler/Facilities/DiagnosticsLogger.fsi @@ -207,6 +207,7 @@ type DiagnosticsLogger = abstract ErrorCount: int /// Checks if ErrorCount > 0 + [] member CheckForErrors: unit -> bool abstract CheckForRealErrorsIgnoringWarnings: bool diff --git a/src/Compiler/Facilities/prim-parsing.fs b/src/Compiler/Facilities/prim-parsing.fs index 7fb0d7fca41..632832b8d85 100644 --- a/src/Compiler/Facilities/prim-parsing.fs +++ b/src/Compiler/Facilities/prim-parsing.fs @@ -5,6 +5,7 @@ namespace Internal.Utilities.Text.Parsing open Internal.Utilities.Text.Lexing +open Internal.Utilities.Library open System open System.Buffers @@ -28,7 +29,7 @@ type internal IParseState member _.ResultEndPosition = lhsPos[1] - member _.GetInput index = ruleValues[index - 1] + member _.GetInput index = !!ruleValues[index - 1] member _.ResultRange = (lhsPos[0], lhsPos[1]) @@ -572,7 +573,7 @@ module internal Implementation = else if Flags.debug then Console.WriteLine("ALARM!!! drop through case in parser") // OK, we're done - read off the overall generated value - valueStack.Peep().value + !!valueStack.Peep().value type internal Tables<'Token> with diff --git a/src/Compiler/Interactive/fsi.fs b/src/Compiler/Interactive/fsi.fs index c31f210022f..eaba5aa6582 100644 --- a/src/Compiler/Interactive/fsi.fs +++ b/src/Compiler/Interactive/fsi.fs @@ -77,7 +77,7 @@ open FSharp.Compiler.CheckExpressionsOps // For the FSI as a service methods... //---------------------------------------------------------------------------- -type FsiValue(reflectionValue: obj, reflectionType: Type, fsharpType: FSharpType) = +type FsiValue(reflectionValue: objnull, reflectionType: Type, fsharpType: FSharpType) = member _.ReflectionValue = reflectionValue member _.ReflectionType = reflectionType @@ -93,15 +93,15 @@ type FsiBoundValue(name: string, value: FsiValue) = [] module internal Utilities = type IAnyToLayoutCall = - abstract AnyToLayout: FormatOptions * obj * Type -> Layout - abstract FsiAnyToLayout: FormatOptions * obj * Type -> Layout + abstract AnyToLayout: FormatOptions * objnull * Type -> Layout + abstract FsiAnyToLayout: FormatOptions * objnull * Type -> Layout type private AnyToLayoutSpecialization<'T>() = interface IAnyToLayoutCall with - member _.AnyToLayout(options, o: obj, ty: Type) = + member _.AnyToLayout(options, o: objnull, ty: Type) = Display.any_to_layout options ((Unchecked.unbox o: 'T), ty) - member _.FsiAnyToLayout(options, o: obj, ty: Type) = + member _.FsiAnyToLayout(options, o: objnull, ty: Type) = Display.fsi_any_to_layout options ((Unchecked.unbox o: 'T), ty) let getAnyToLayoutCall (ty: Type) = @@ -112,13 +112,19 @@ module internal Utilities = |> NativeInterop.NativePtr.toNativeInt { new IAnyToLayoutCall with - member _.AnyToLayout(options, o: obj, ty: Type) = - let n = pointerToNativeInt o - Display.any_to_layout options (n, n.GetType()) - - member _.FsiAnyToLayout(options, o: obj, ty: Type) = - let n = pointerToNativeInt o - Display.any_to_layout options (n, n.GetType()) + member _.AnyToLayout(options, o: objnull, ty: Type) = + match o with + | null -> Display.any_to_layout options (o, ty) + | o -> + let n = pointerToNativeInt o + Display.any_to_layout options (n, n.GetType()) + + member _.FsiAnyToLayout(options, o: objnull, ty: Type) = + match o with + | null -> Display.any_to_layout options (o, ty) + | o -> + let n = pointerToNativeInt o + Display.any_to_layout options (n, n.GetType()) } else let specialized = typedefof>.MakeGenericType [| ty |] @@ -677,7 +683,7 @@ type internal FsiValuePrinter(fsi: FsiEvaluationSessionHostConfig, outWriter: Te } /// Generate a layout for an actual F# value, where we know the value has the given static type. - member _.PrintValue(printMode, opts: FormatOptions, x: obj, ty: Type) = + member _.PrintValue(printMode, opts: FormatOptions, x: objnull, ty: Type) = // We do a dynamic invoke of any_to_layout with the right System.Type parameter for the static type of the saved value. // In principle this helps any_to_layout do the right thing as it descends through terms. In practice it means // it at least does the right thing for top level 'null' list and option values (but not for nested ones). @@ -2198,7 +2204,7 @@ type internal FsiDynamicCompiler lock tcLockObject (fun _ -> CheckClosedInputSet( ctok, - diagnosticsLogger.CheckForErrors, + (fun () -> diagnosticsLogger.CheckForRealErrorsIgnoringWarnings), tcConfig, tcImports, tcGlobals, @@ -5191,7 +5197,7 @@ module Settings = and set v = args <- v member _.AddPrinter(printer: 'T -> string) = - addedPrinters <- Choice1Of2(typeof<'T>, (fun (x: obj) -> printer (unbox x))) :: addedPrinters + addedPrinters <- Choice1Of2(typeof<'T>, (fun (x: objnull) -> printer (unbox x))) :: addedPrinters member _.EventLoop with get () = evLoop @@ -5199,8 +5205,8 @@ module Settings = evLoop.ScheduleRestart() evLoop <- x - member _.AddPrintTransformer(printer: 'T -> obj) = - addedPrinters <- Choice2Of2(typeof<'T>, (fun (x: obj) -> printer (unbox x))) :: addedPrinters + member _.AddPrintTransformer(printer: 'T -> objnull) = + addedPrinters <- Choice2Of2(typeof<'T>, (fun (x: objnull) -> printer (unbox x))) :: addedPrinters let fsi = InteractiveSettings() diff --git a/src/Compiler/Interactive/fsi.fsi b/src/Compiler/Interactive/fsi.fsi index c34a583cdb7..0e7415ca728 100644 --- a/src/Compiler/Interactive/fsi.fsi +++ b/src/Compiler/Interactive/fsi.fsi @@ -15,7 +15,7 @@ open Internal.Utilities.Library type FsiValue = /// The value, as an object - member ReflectionValue: obj + member ReflectionValue: objnull /// The type of the value, from the point of view of the .NET type system member ReflectionType: Type @@ -308,7 +308,7 @@ type FsiEvaluationSession = member ReportUnhandledException: exn: exn -> unit /// Event fires when a root-level value is bound to an identifier, e.g., via `let x = ...`. - member ValueBound: IEvent + member ValueBound: IEvent /// Gets the root-level values that are bound to an identifier member GetBoundValues: unit -> FsiBoundValue list @@ -395,7 +395,7 @@ module Settings = member AddPrinter: ('T -> string) -> unit /// Register a print transformer that controls the output of the interactive session. - member AddPrintTransformer: ('T -> obj) -> unit + member AddPrintTransformer: ('T -> objnull) -> unit member internal AddedPrinters: Choice string), Type * (objnull -> objnull)> list diff --git a/src/Compiler/Service/FSharpCheckerResults.fs b/src/Compiler/Service/FSharpCheckerResults.fs index 0d6e83a61c2..771ab536ff8 100644 --- a/src/Compiler/Service/FSharpCheckerResults.fs +++ b/src/Compiler/Service/FSharpCheckerResults.fs @@ -188,7 +188,7 @@ and FSharpProjectOptions = && options1.ReferencedProjects = options2.ReferencedProjects && options1.LoadTime = options2.LoadTime - member po.ProjectDirectory = Path.GetDirectoryName(po.ProjectFileName) + member po.ProjectDirectory = !! Path.GetDirectoryName(po.ProjectFileName) override this.ToString() = "FSharpProjectOptions(" + this.ProjectFileName + ")" diff --git a/src/Compiler/Service/QuickParse.fs b/src/Compiler/Service/QuickParse.fs index ddb7d13f126..e7361ce1634 100644 --- a/src/Compiler/Service/QuickParse.fs +++ b/src/Compiler/Service/QuickParse.fs @@ -200,7 +200,7 @@ module QuickParse = /// a call to `DeclItemsForNamesAtPosition` for intellisense. This will /// allow us to use find the correct qualified items rather than resorting /// to the more expensive and less accurate environment lookup. - let GetCompleteIdentifierIsland (tolerateJustAfter: bool) (lineStr: string) (index: int) : (string * int * bool) option = + let GetCompleteIdentifierIsland (tolerateJustAfter: bool) (lineStr: string MaybeNull) (index: int) : (string * int * bool) option = if String.IsNullOrEmpty lineStr then None else diff --git a/src/Compiler/Symbols/Exprs.fsi b/src/Compiler/Symbols/Exprs.fsi index fddc3d0ea4e..7962855a0e9 100644 --- a/src/Compiler/Symbols/Exprs.fsi +++ b/src/Compiler/Symbols/Exprs.fsi @@ -206,7 +206,7 @@ module public FSharpExprPatterns = /// Matches constant expressions, including signed and unsigned integers, strings, characters, booleans, arrays /// of bytes and arrays of unit16. - val (|Const|_|): FSharpExpr -> (obj * FSharpType) option + val (|Const|_|): FSharpExpr -> (objnull * FSharpType) option /// Matches expressions which take the address of a location val (|AddressOf|_|): FSharpExpr -> FSharpExpr option diff --git a/src/Compiler/Symbols/FSharpDiagnostic.fs b/src/Compiler/Symbols/FSharpDiagnostic.fs index 581b51ab8c7..66e077fba9c 100644 --- a/src/Compiler/Symbols/FSharpDiagnostic.fs +++ b/src/Compiler/Symbols/FSharpDiagnostic.fs @@ -200,10 +200,10 @@ type FSharpDiagnostic(m: range, severity: FSharpDiagnosticSeverity, message: str | FunctionValueUnexpected(_, actualType, _) -> Some(ExpressionIsAFunctionExtendedData(symbolEnv, actualType)) - | FieldNotContained(_, _, implEntity, sigEntity, impl, sign, _) -> + | FieldNotContained(_,_, _, implEntity, sigEntity, impl, sign, _) -> Some(FieldNotContainedDiagnosticExtendedData(symbolEnv, implEntity, sigEntity, sign, impl)) - | ValueNotContained(_, _, _, implValue, sigValue, _) -> + | ValueNotContained(_,_, _, _, implValue, sigValue, _) -> Some(ValueNotContainedDiagnosticExtendedData(symbolEnv, sigValue, implValue)) | ArgumentsInSigAndImplMismatch(sigArg, implArg) -> diff --git a/src/Compiler/Symbols/Symbols.fs b/src/Compiler/Symbols/Symbols.fs index f12e9de6321..48acdf03dae 100644 --- a/src/Compiler/Symbols/Symbols.fs +++ b/src/Compiler/Symbols/Symbols.fs @@ -2779,7 +2779,7 @@ type FSharpType(cenv, ty:TType) = type FSharpAttribute(cenv: SymbolEnv, attrib: AttribInfo) = - let rec resolveArgObj (arg: obj) = + let rec resolveArgObj (arg: objnull) = match arg with | :? TType as t -> box (FSharpType(cenv, t)) | :? (obj[]) as a -> a |> Array.map resolveArgObj |> box diff --git a/src/Compiler/Symbols/Symbols.fsi b/src/Compiler/Symbols/Symbols.fsi index a3eda6ecd3a..701e9a8fe3c 100644 --- a/src/Compiler/Symbols/Symbols.fsi +++ b/src/Compiler/Symbols/Symbols.fsi @@ -575,7 +575,7 @@ type FSharpField = member Name: string /// Get the default initialization info, for static literals - member LiteralValue: obj option + member LiteralValue: objnull option /// Indicates if the declared visibility of the field, not taking signatures into account override Accessibility: FSharpAccessibility @@ -639,7 +639,7 @@ type FSharpStaticParameter = member Kind: FSharpType /// Get the default value for the static parameter - member DefaultValue: obj + member DefaultValue: objnull /// Indicates if the static parameter is optional member IsOptional: bool @@ -954,7 +954,7 @@ type FSharpMemberOrFunctionOrValue = member IsMemberThisValue: bool /// Indicates if this is a [] value, and if so what value? (may be null) - member LiteralValue: obj option + member LiteralValue: objnull option /// Get the accessibility information for the member, function or value override Accessibility: FSharpAccessibility @@ -1198,10 +1198,10 @@ type FSharpAttribute = member AttributeType: FSharpEntity /// The arguments to the constructor for the attribute - member ConstructorArguments: IList + member ConstructorArguments: IList /// The named arguments for the attribute - member NamedArguments: IList + member NamedArguments: IList /// Indicates if the attribute type is in an unresolved assembly member IsUnresolved: bool diff --git a/src/Compiler/SyntaxTree/PrettyNaming.fs b/src/Compiler/SyntaxTree/PrettyNaming.fs index 8ea10266de8..b0ef32edaf0 100755 --- a/src/Compiler/SyntaxTree/PrettyNaming.fs +++ b/src/Compiler/SyntaxTree/PrettyNaming.fs @@ -670,8 +670,8 @@ let IsLogicalPrefixOperator logicalName = if String.IsNullOrEmpty logicalName then false else - let displayName = ConvertValLogicalNameToDisplayNameCore !!logicalName - displayName <> !!logicalName && IsValidPrefixOperatorDefinitionName displayName + let displayName = ConvertValLogicalNameToDisplayNameCore logicalName + displayName <> logicalName && IsValidPrefixOperatorDefinitionName displayName let IsLogicalTernaryOperator logicalName = let displayName = ConvertValLogicalNameToDisplayNameCore logicalName diff --git a/src/Compiler/TypedTree/TypeProviders.fs b/src/Compiler/TypedTree/TypeProviders.fs index acef34047ca..42caa723619 100644 --- a/src/Compiler/TypedTree/TypeProviders.fs +++ b/src/Compiler/TypedTree/TypeProviders.fs @@ -22,6 +22,12 @@ open FSharp.Compiler.Text open FSharp.Compiler.Text.Range type TypeProviderDesignation = TypeProviderDesignation of string +type 'a ProvidedArray= ('a[]) MaybeNull +module ProvidedArray = + let map f (arr:_ ProvidedArray) : _ ProvidedArray = + match arr with + | null -> null + | notNull -> notNull |> Array.map f exception ProvidedTypeResolution of range * exn @@ -366,7 +372,7 @@ type ProvidedType (x: Type, ctxt: ProvidedTypeContext) = member _.Namespace : string MaybeNull = x.Namespace - member _.FullName = x.FullName + member _.FullName : string MaybeNull = x.FullName member _.IsArray = x.IsArray @@ -403,7 +409,7 @@ type ProvidedType (x: Type, ctxt: ProvidedTypeContext) = /// Type.BaseType can be null when Type is interface or object member _.BaseType = x.BaseType |> ProvidedType.Create ctxt - member _.GetStaticParameters(provider: ITypeProvider) : ProvidedParameterInfo[] MaybeNull = provider.GetStaticParameters x |> ProvidedParameterInfo.CreateArray ctxt + member _.GetStaticParameters(provider: ITypeProvider) : ProvidedParameterInfo ProvidedArray = provider.GetStaticParameters x |> ProvidedParameterInfo.CreateArray ctxt /// Type.GetElementType can be null if i.e. Type is not array\pointer\byref type member _.GetElementType() = x.GetElementType() |> ProvidedType.Create ctxt @@ -476,12 +482,10 @@ type ProvidedType (x: Type, ctxt: ProvidedTypeContext) = | null -> nullArg name | t -> ProvidedType (t, ctxt) - static member CreateArray ctxt (xs: Type[] MaybeNull) : ProvidedType[] MaybeNull = - match xs with - | Null -> null - | NonNull xs -> xs |> Array.map (ProvidedType.CreateNonNull ctxt) + static member CreateArray ctxt (xs:_ ProvidedArray) = + xs |> ProvidedArray.map (ProvidedType.CreateNonNull ctxt) - static member CreateNoContext (x:Type) = ProvidedType.Create ProvidedTypeContext.Empty x + static member CreateNoContext (x:Type) = ProvidedType.CreateNonNull ProvidedTypeContext.Empty x static member Void = ProvidedType.CreateNoContext typeof @@ -604,7 +608,7 @@ type ProvidedParameterInfo (x: ParameterInfo, ctxt) = member _.IsOptional = x.IsOptional - member _.RawDefaultValue = x.RawDefaultValue + member _.RawDefaultValue : objnull = x.RawDefaultValue member _.HasDefaultValue = x.Attributes.HasFlag(ParameterAttributes.HasDefault) @@ -618,15 +622,8 @@ type ProvidedParameterInfo (x: ParameterInfo, ctxt) = static member CreateNonNull ctxt x = ProvidedParameterInfo (x, ctxt) - static member CreateArray ctxt (xs: ParameterInfo[] MaybeNull) : ProvidedParameterInfo[] MaybeNull = - match xs with - | Null -> null - | NonNull xs -> xs |> Array.map (ProvidedParameterInfo.CreateNonNull ctxt) - - static member CreateArrayNonNull ctxt xs : ProvidedParameterInfo[] = - match box xs with - | Null -> [| |] - | _ -> xs |> Array.map (ProvidedParameterInfo.CreateNonNull ctxt) + static member CreateArray ctxt (xs: ParameterInfo ProvidedArray) : ProvidedParameterInfo ProvidedArray = + xs |> ProvidedArray.map (ProvidedParameterInfo.CreateNonNull ctxt) interface IProvidedCustomAttributeProvider with member _.GetHasTypeProviderEditorHideMethodsAttribute provider = @@ -712,7 +709,7 @@ type ProvidedMethodBase (x: MethodBase, ctxt) = static member TaintedEquals (pt1: Tainted, pt2: Tainted) = Tainted.EqTainted (pt1.PApplyNoFailure(fun st -> st.Handle)) (pt2.PApplyNoFailure(fun st -> st.Handle)) - member _.GetStaticParametersForMethod(provider: ITypeProvider) : ProvidedParameterInfo[] = + member _.GetStaticParametersForMethod(provider: ITypeProvider) : ProvidedParameterInfo ProvidedArray = let bindingFlags = BindingFlags.Instance ||| BindingFlags.NonPublic ||| BindingFlags.Public let staticParams = @@ -731,7 +728,7 @@ type ProvidedMethodBase (x: MethodBase, ctxt) = with err -> raise (StripException (StripException err)) !!paramsAsObj :?> ParameterInfo[] - staticParams |> ProvidedParameterInfo.CreateArrayNonNull ctxt + staticParams |> ProvidedParameterInfo.CreateArray ctxt member _.ApplyStaticArgumentsForMethod(provider: ITypeProvider, fullNameAfterArguments: string, staticArgs: objnull[]) = let bindingFlags = BindingFlags.Instance ||| BindingFlags.Public ||| BindingFlags.InvokeMethod @@ -778,10 +775,8 @@ type ProvidedFieldInfo (x: FieldInfo, ctxt) = | Null -> null | NonNull x -> ProvidedFieldInfo (x, ctxt) - static member CreateArray ctxt (xs: FieldInfo[] MaybeNull) : ProvidedFieldInfo[] MaybeNull = - match xs with - | Null -> null - | NonNull xs -> xs |> Array.map (ProvidedFieldInfo.CreateNonNull ctxt) + static member CreateArray ctxt (xs: FieldInfo ProvidedArray) : ProvidedFieldInfo ProvidedArray = + xs |> ProvidedArray.map (ProvidedFieldInfo.CreateNonNull ctxt) member _.IsInitOnly = x.IsInitOnly @@ -791,7 +786,7 @@ type ProvidedFieldInfo (x: FieldInfo, ctxt) = member _.IsLiteral = x.IsLiteral - member _.GetRawConstantValue() = x.GetRawConstantValue() + member _.GetRawConstantValue() : objnull = x.GetRawConstantValue() /// FieldInfo.FieldType cannot be null @@ -834,10 +829,8 @@ type ProvidedMethodInfo (x: MethodInfo, ctxt) = | NonNull x -> ProvidedMethodInfo (x, ctxt) - static member CreateArray ctxt (xs: MethodInfo[] MaybeNull) : ProvidedMethodInfo[] MaybeNull = - match xs with - | Null -> null - | NonNull xs -> xs |> Array.map (ProvidedMethodInfo.CreateNonNull ctxt) + static member CreateArray ctxt (xs: MethodInfo ProvidedArray) : ProvidedMethodInfo ProvidedArray = + xs |> ProvidedArray.map (ProvidedMethodInfo.CreateNonNull ctxt) member _.Handle = x @@ -874,10 +867,8 @@ type ProvidedPropertyInfo (x: PropertyInfo, ctxt) = | Null -> null | NonNull x -> ProvidedPropertyInfo (x, ctxt) - static member CreateArray ctxt (xs: PropertyInfo[] MaybeNull) : ProvidedPropertyInfo[] MaybeNull = - match xs with - | Null -> null - | NonNull xs -> xs |> Array.map (ProvidedPropertyInfo.CreateNonNull ctxt) + static member CreateArray ctxt (xs: PropertyInfo ProvidedArray) : ProvidedPropertyInfo ProvidedArray = + xs |> ProvidedArray.map (ProvidedPropertyInfo.CreateNonNull ctxt) member _.Handle = x @@ -914,10 +905,8 @@ type ProvidedEventInfo (x: EventInfo, ctxt) = | Null -> null | NonNull x -> ProvidedEventInfo (x, ctxt) - static member CreateArray ctxt (xs: EventInfo[] MaybeNull) : ProvidedEventInfo[] MaybeNull = - match xs with - | Null -> null - | NonNull xs -> xs |> Array.map (ProvidedEventInfo.CreateNonNull ctxt) + static member CreateArray ctxt (xs: EventInfo ProvidedArray) : ProvidedEventInfo ProvidedArray = + xs |> ProvidedArray.map (ProvidedEventInfo.CreateNonNull ctxt) member _.Handle = x @@ -947,10 +936,8 @@ type ProvidedConstructorInfo (x: ConstructorInfo, ctxt) = | Null -> null | NonNull x -> ProvidedConstructorInfo (x, ctxt) - static member CreateArray ctxt (xs: ConstructorInfo[] MaybeNull) : ProvidedConstructorInfo[] MaybeNull = - match xs with - | Null -> null - | NonNull xs -> xs |> Array.map (ProvidedConstructorInfo.CreateNonNull ctxt) + static member CreateArray ctxt (xs: ConstructorInfo ProvidedArray) : ProvidedConstructorInfo ProvidedArray = + xs |> ProvidedArray.map (ProvidedConstructorInfo.CreateNonNull ctxt) member _.Handle = x @@ -959,19 +946,19 @@ type ProvidedConstructorInfo (x: ConstructorInfo, ctxt) = override _.GetHashCode() = assert false; x.GetHashCode() type ProvidedExprType = - | ProvidedNewArrayExpr of ProvidedType * ProvidedExpr[] - | ProvidedNewObjectExpr of ProvidedConstructorInfo * ProvidedExpr[] + | ProvidedNewArrayExpr of ProvidedType * ProvidedExpr ProvidedArray + | ProvidedNewObjectExpr of ProvidedConstructorInfo * ProvidedExpr ProvidedArray | ProvidedWhileLoopExpr of ProvidedExpr * ProvidedExpr - | ProvidedNewDelegateExpr of ProvidedType * ProvidedVar[] * ProvidedExpr + | ProvidedNewDelegateExpr of ProvidedType * ProvidedVar ProvidedArray * ProvidedExpr | ProvidedForIntegerRangeLoopExpr of ProvidedVar * ProvidedExpr * ProvidedExpr * ProvidedExpr | ProvidedSequentialExpr of ProvidedExpr * ProvidedExpr | ProvidedTryWithExpr of ProvidedExpr * ProvidedVar * ProvidedExpr * ProvidedVar * ProvidedExpr | ProvidedTryFinallyExpr of ProvidedExpr * ProvidedExpr | ProvidedLambdaExpr of ProvidedVar * ProvidedExpr - | ProvidedCallExpr of ProvidedExpr option * ProvidedMethodInfo * ProvidedExpr[] + | ProvidedCallExpr of ProvidedExpr option * ProvidedMethodInfo * ProvidedExpr ProvidedArray | ProvidedConstantExpr of objnull * ProvidedType | ProvidedDefaultExpr of ProvidedType - | ProvidedNewTupleExpr of ProvidedExpr[] + | ProvidedNewTupleExpr of ProvidedExpr ProvidedArray | ProvidedTupleGetExpr of ProvidedExpr * int | ProvidedTypeAsExpr of ProvidedExpr * ProvidedType | ProvidedTypeTestExpr of ProvidedExpr * ProvidedType @@ -987,13 +974,13 @@ type ProvidedExprType = #endif type ProvidedExpr (x: Expr, ctxt) = - member _.Type = x.Type |> ProvidedType.Create ctxt + member _.Type = x.Type |> ProvidedType.CreateNonNull ctxt member _.Handle = x member _.Context = ctxt - member _.UnderlyingExpressionString = x.ToString() + member _.UnderlyingExpressionString = string (x.ToString()) member _.GetExprType() = match x with @@ -1062,7 +1049,7 @@ type ProvidedExpr (x: Expr, ctxt) = [] #endif type ProvidedVar (x: Var, ctxt) = - member _.Type = x.Type |> ProvidedType.Create ctxt + member _.Type = x.Type |> ProvidedType.CreateNonNull ctxt member _.Name = x.Name member _.IsMutable = x.IsMutable member _.Handle = x @@ -1171,7 +1158,7 @@ let ValidateProvidedTypeAfterStaticInstantiation(m, st: Tainted, e if String.IsNullOrEmpty memberName then errorR(Error(FSComp.SR.etNullOrEmptyMemberName fullName, m)) else - let miDeclaringType = TryMemberMember(mi, fullName, memberName, "DeclaringType", m, ProvidedType.CreateNoContext(typeof), fun mi -> mi.DeclaringType) + let miDeclaringType = TryMemberMember(mi, fullName, memberName, "DeclaringType", m, (ProvidedType.CreateNoContext(typeof) |> withNull), fun mi -> mi.DeclaringType) match miDeclaringType with // Generated nested types may have null DeclaringType | Tainted.Null when mi.OfType().IsSome -> () @@ -1261,7 +1248,7 @@ let ValidateProvidedTypeDefinition(m, st: Tainted, expectedPath: s | -1 -> () | n -> errorR(Error(FSComp.SR.etIllegalCharactersInTypeName(string expectedName[n], expectedName), m)) - let staticParameters : Tainted = st.PApplyWithProvider((fun (st, provider) -> st.GetStaticParameters provider), range=m) + let staticParameters = st.PApplyWithProvider((fun (st, provider) -> st.GetStaticParameters provider), range=m) if staticParameters.PUntaint((fun a -> (nonNull a).Length), m) = 0 then ValidateProvidedTypeAfterStaticInstantiation(m, st, expectedPath, expectedName) @@ -1280,7 +1267,7 @@ let ResolveProvidedType (resolver: Tainted, m, moduleOrNamespace: // Check if the provided namespace name is an exact match of the required namespace name if displayName = providedNamespaceName then - let resolvedType = providedNamespace.PApply((fun providedNamespace -> ProvidedType.CreateNoContext(providedNamespace.ResolveTypeName typeName)), range=m) + let resolvedType = providedNamespace.PApply((fun providedNamespace -> ProvidedType.Create ProvidedTypeContext.Empty (providedNamespace.ResolveTypeName typeName)), range=m) match resolvedType with | Tainted.Null -> None | Tainted.NonNull result -> @@ -1341,7 +1328,8 @@ let TryApplyProvidedMethod(methBeforeArgs: Tainted, staticAr else let mangledName = let nm = methBeforeArgs.PUntaint((fun x -> x.Name), m) - let staticParams = methBeforeArgs.PApplyWithProvider((fun (mb, resolver) -> mb.GetStaticParametersForMethod resolver), range=m) + let staticParams = + methBeforeArgs.PApplyWithProvider((fun (mb, resolver) -> mb.GetStaticParametersForMethod resolver |> nonNull), range=m) let mangledName = ComputeMangledNameForApplyStaticParameters(nm, staticArgs, staticParams, m) mangledName match methBeforeArgs.PApplyWithProvider((fun (mb, provider) -> mb.ApplyStaticArgumentsForMethod(provider, mangledName, staticArgs)), range=m) with @@ -1367,7 +1355,7 @@ let TryApplyProvidedType(typeBeforeArguments: Tainted, optGenerate // Otherwise, use the full path of the erased type, including mangled arguments let nm = typeBeforeArguments.PUntaint((fun x -> x.Name), m) let enc, _ = ILPathToProvidedType (typeBeforeArguments, m) - let staticParams : Tainted = typeBeforeArguments.PApplyWithProvider((fun (st, resolver) -> st.GetStaticParameters resolver |> nonNull), range=m) + let staticParams = typeBeforeArguments.PApplyWithProvider((fun (st, resolver) -> st.GetStaticParameters resolver |> nonNull), range=m) let mangledName = ComputeMangledNameForApplyStaticParameters(nm, staticArgs, staticParams, m) enc @ [ mangledName ] diff --git a/src/Compiler/TypedTree/TypeProviders.fsi b/src/Compiler/TypedTree/TypeProviders.fsi index c99f2ab3775..b8ec2158ea4 100755 --- a/src/Compiler/TypedTree/TypeProviders.fsi +++ b/src/Compiler/TypedTree/TypeProviders.fsi @@ -15,6 +15,7 @@ open FSharp.Compiler.AbstractIL.IL open FSharp.Compiler.Text type TypeProviderDesignation = TypeProviderDesignation of string +type 'a ProvidedArray= ('a[]) MaybeNull /// Raised when a type provider has thrown an exception. exception ProvidedTypeResolution of range * exn @@ -104,41 +105,41 @@ type ProvidedType = member IsGenericType: bool - member Namespace: string + member Namespace: string MaybeNull - member FullName: string + member FullName: string MaybeNull member IsArray: bool - member GetInterfaces: unit -> ProvidedType[] + member GetInterfaces: unit -> ProvidedType ProvidedArray - member Assembly: ProvidedAssembly + member Assembly: ProvidedAssembly MaybeNull member BaseType: ProvidedType MaybeNull - member GetNestedType: string -> ProvidedType + member GetNestedType: string -> ProvidedType MaybeNull - member GetNestedTypes: unit -> ProvidedType[] + member GetNestedTypes: unit -> ProvidedType ProvidedArray - member GetAllNestedTypes: unit -> ProvidedType[] + member GetAllNestedTypes: unit -> ProvidedType ProvidedArray - member GetMethods: unit -> ProvidedMethodInfo[] + member GetMethods: unit -> ProvidedMethodInfo ProvidedArray - member GetFields: unit -> ProvidedFieldInfo[] + member GetFields: unit -> ProvidedFieldInfo ProvidedArray - member GetField: string -> ProvidedFieldInfo + member GetField: string -> ProvidedFieldInfo MaybeNull - member GetProperties: unit -> ProvidedPropertyInfo[] + member GetProperties: unit -> ProvidedPropertyInfo ProvidedArray - member GetProperty: string -> ProvidedPropertyInfo + member GetProperty: string -> ProvidedPropertyInfo MaybeNull - member GetEvents: unit -> ProvidedEventInfo[] + member GetEvents: unit -> ProvidedEventInfo ProvidedArray - member GetEvent: string -> ProvidedEventInfo + member GetEvent: string -> ProvidedEventInfo MaybeNull - member GetConstructors: unit -> ProvidedConstructorInfo[] + member GetConstructors: unit -> ProvidedConstructorInfo ProvidedArray - member GetStaticParameters: ITypeProvider -> ProvidedParameterInfo[] + member GetStaticParameters: ITypeProvider -> ProvidedParameterInfo ProvidedArray member GetGenericTypeDefinition: unit -> ProvidedType @@ -170,9 +171,9 @@ type ProvidedType = member GenericParameterPosition: int - member GetElementType: unit -> ProvidedType + member GetElementType: unit -> ProvidedType MaybeNull - member GetGenericArguments: unit -> ProvidedType[] + member GetGenericArguments: unit -> ProvidedType ProvidedArray member GetArrayRank: unit -> int @@ -275,11 +276,11 @@ type ProvidedMethodBase = member IsConstructor: bool - member GetParameters: unit -> ProvidedParameterInfo[] + member GetParameters: unit -> ProvidedParameterInfo ProvidedArray - member GetGenericArguments: unit -> ProvidedType[] + member GetGenericArguments: unit -> ProvidedType ProvidedArray - member GetStaticParametersForMethod: ITypeProvider -> ProvidedParameterInfo[] + member GetStaticParametersForMethod: ITypeProvider -> ProvidedParameterInfo ProvidedArray static member TaintedGetHashCode: Tainted -> int @@ -335,7 +336,7 @@ type ProvidedFieldInfo = member IsLiteral: bool - member GetRawConstantValue: unit -> obj + member GetRawConstantValue: unit -> objnull member FieldType: ProvidedType @@ -359,11 +360,11 @@ type ProvidedPropertyInfo = inherit ProvidedMemberInfo - member GetGetMethod: unit -> ProvidedMethodInfo + member GetGetMethod: unit -> ProvidedMethodInfo MaybeNull - member GetSetMethod: unit -> ProvidedMethodInfo + member GetSetMethod: unit -> ProvidedMethodInfo MaybeNull - member GetIndexParameters: unit -> ProvidedParameterInfo[] + member GetIndexParameters: unit -> ProvidedParameterInfo ProvidedArray member CanRead: bool @@ -383,9 +384,9 @@ type ProvidedEventInfo = inherit ProvidedMemberInfo - member GetAddMethod: unit -> ProvidedMethodInfo + member GetAddMethod: unit -> ProvidedMethodInfo MaybeNull - member GetRemoveMethod: unit -> ProvidedMethodInfo + member GetRemoveMethod: unit -> ProvidedMethodInfo MaybeNull member EventHandlerType: ProvidedType @@ -402,13 +403,13 @@ type ProvidedConstructorInfo = type ProvidedExprType = - | ProvidedNewArrayExpr of ProvidedType * ProvidedExpr[] + | ProvidedNewArrayExpr of ProvidedType * ProvidedExpr ProvidedArray - | ProvidedNewObjectExpr of ProvidedConstructorInfo * ProvidedExpr[] + | ProvidedNewObjectExpr of ProvidedConstructorInfo * ProvidedExpr ProvidedArray | ProvidedWhileLoopExpr of ProvidedExpr * ProvidedExpr - | ProvidedNewDelegateExpr of ProvidedType * ProvidedVar[] * ProvidedExpr + | ProvidedNewDelegateExpr of ProvidedType * ProvidedVar ProvidedArray * ProvidedExpr | ProvidedForIntegerRangeLoopExpr of ProvidedVar * ProvidedExpr * ProvidedExpr * ProvidedExpr @@ -420,13 +421,13 @@ type ProvidedExprType = | ProvidedLambdaExpr of ProvidedVar * ProvidedExpr - | ProvidedCallExpr of ProvidedExpr option * ProvidedMethodInfo * ProvidedExpr[] + | ProvidedCallExpr of ProvidedExpr option * ProvidedMethodInfo * ProvidedExpr ProvidedArray - | ProvidedConstantExpr of obj * ProvidedType + | ProvidedConstantExpr of objnull * ProvidedType | ProvidedDefaultExpr of ProvidedType - | ProvidedNewTupleExpr of ProvidedExpr[] + | ProvidedNewTupleExpr of ProvidedExpr ProvidedArray | ProvidedTupleGetExpr of ProvidedExpr * int @@ -467,12 +468,10 @@ type ProvidedVar = member IsMutable: bool - override Equals: obj -> bool - override GetHashCode: unit -> int /// Get the provided expression for a particular use of a method. -val GetInvokerExpression: ITypeProvider * ProvidedMethodBase * ProvidedVar[] -> ProvidedExpr +val GetInvokerExpression: ITypeProvider * ProvidedMethodBase * ProvidedVar[] -> ProvidedExpr MaybeNull /// Validate that the given provided type meets some of the rules for F# provided types val ValidateProvidedTypeAfterStaticInstantiation: @@ -497,7 +496,7 @@ val TryLinkProvidedType: Tainted * string[] * typeLogicalName: string * range: range -> Tainted option /// Get the parts of a .NET namespace. Special rules: null means global, empty is not allowed. -val GetProvidedNamespaceAsPath: range * Tainted * string -> string list +val GetProvidedNamespaceAsPath: range * Tainted * string MaybeNull -> string list /// Decompose the enclosing name of a type (including any class nestings) into a list of parts. /// e.g. System.Object -> ["System"; "Object"] diff --git a/src/Compiler/TypedTree/TypedTree.fs b/src/Compiler/TypedTree/TypedTree.fs index 27e80d396be..817730ec6ea 100644 --- a/src/Compiler/TypedTree/TypedTree.fs +++ b/src/Compiler/TypedTree/TypedTree.fs @@ -5588,7 +5588,7 @@ type NamedDebugPointKey = override x.GetHashCode() = hash x.Name + hash x.Range - override x.Equals(yobj: obj) = + override x.Equals(yobj: objnull) = match yobj with | :? NamedDebugPointKey as y -> Range.equals x.Range y.Range && x.Name = y.Name | _ -> false diff --git a/src/Compiler/TypedTree/TypedTree.fsi b/src/Compiler/TypedTree/TypedTree.fsi index 82a0a8d84c4..28ef5776e5a 100644 --- a/src/Compiler/TypedTree/TypedTree.fsi +++ b/src/Compiler/TypedTree/TypedTree.fsi @@ -3149,7 +3149,7 @@ type TType = /// For now, used only as a discriminant in error message. /// See https://github.com/dotnet/fsharp/issues/2561 - member GetAssemblyName: unit -> string MaybeNull + member GetAssemblyName: unit -> string override ToString: unit -> string @@ -4050,8 +4050,6 @@ type NamedDebugPointKey = interface IComparable - override Equals: yobj: obj -> bool - override GetHashCode: unit -> int /// Represents a complete typechecked implementation file, including its inferred or explicit signature. diff --git a/src/Compiler/TypedTree/TypedTreeOps.fs b/src/Compiler/TypedTree/TypedTreeOps.fs index ebe42db34fe..f83e48a7c8f 100644 --- a/src/Compiler/TypedTree/TypedTreeOps.fs +++ b/src/Compiler/TypedTree/TypedTreeOps.fs @@ -979,15 +979,26 @@ let stripMeasuresFromTy g ty = [] type TypeEquivEnv = { EquivTypars: TyparMap - EquivTycons: TyconRefRemap} + EquivTycons: TyconRefRemap + NullnessMustEqual : bool} + +let private nullnessEqual anev (n1:Nullness) (n2:Nullness) = + if anev.NullnessMustEqual then + (n1.Evaluate() = NullnessInfo.WithNull) = (n2.Evaluate() = NullnessInfo.WithNull) + else + true // allocate a singleton -let typeEquivEnvEmpty = +let private typeEquivEnvEmpty = { EquivTypars = TyparMap.Empty - EquivTycons = emptyTyconRefRemap } + EquivTycons = emptyTyconRefRemap + NullnessMustEqual = false} + +let private typeEquivCheckNullness = {typeEquivEnvEmpty with NullnessMustEqual = true} type TypeEquivEnv with - static member Empty = typeEquivEnvEmpty + static member EmptyIgnoreNulls = typeEquivEnvEmpty + static member EmptyWithNullChecks (g:TcGlobals) = if g.checkNullness then typeEquivCheckNullness else typeEquivEnvEmpty member aenv.BindTyparsToTypes tps1 tys2 = { aenv with EquivTypars = (tps1, tys2, aenv.EquivTypars) |||> List.foldBack2 (fun tp ty tpmap -> tpmap.Add(tp, ty)) } @@ -995,12 +1006,15 @@ type TypeEquivEnv with member aenv.BindEquivTypars tps1 tps2 = aenv.BindTyparsToTypes tps1 (List.map mkTyparTy tps2) - static member FromTyparInst tpinst = + member aenv.FromTyparInst tpinst = let tps, tys = List.unzip tpinst - TypeEquivEnv.Empty.BindTyparsToTypes tps tys + aenv.BindTyparsToTypes tps tys + + member aenv.FromEquivTypars tps1 tps2 = + aenv.BindEquivTypars tps1 tps2 - static member FromEquivTypars tps1 tps2 = - TypeEquivEnv.Empty.BindEquivTypars tps1 tps2 + member anev.ResetEquiv = + if anev.NullnessMustEqual then typeEquivCheckNullness else typeEquivEnvEmpty let rec traitsAEquivAux erasureFlag g aenv traitInfo1 traitInfo2 = let (TTrait(tys1, nm, mf1, argTys, retTy, _, _)) = traitInfo1 @@ -1081,16 +1095,18 @@ and typeAEquivAux erasureFlag g aenv ty1 ty2 = | TType_forall(tps1, rty1), TType_forall(tps2, retTy2) -> typarsAEquivAux erasureFlag g aenv tps1 tps2 && typeAEquivAux erasureFlag g (aenv.BindEquivTypars tps1 tps2) rty1 retTy2 - | TType_var (tp1, _), TType_var (tp2, _) when typarEq tp1 tp2 -> // NOTE: nullness annotations are ignored for type equivalence - true + | TType_var (tp1, n1), TType_var (tp2, n2) when typarEq tp1 tp2 -> + nullnessEqual aenv n1 n2 - | TType_var (tp1, _), _ -> + | TType_var (tp1, n1), _ -> match aenv.EquivTypars.TryFind tp1 with - | Some tpTy1 -> typeEquivAux erasureFlag g tpTy1 ty2 + | Some tpTy1 -> + let tpTy1 = if (nullnessEqual aenv n1 g.knownWithoutNull) then tpTy1 else addNullnessToTy n1 tpTy1 + typeAEquivAux erasureFlag g aenv.ResetEquiv tpTy1 ty2 | None -> false - // NOTE: nullness annotations are ignored for type equivalence - | TType_app (tcref1, tinst1, _), TType_app (tcref2, tinst2, _) -> + | TType_app (tcref1, tinst1, n1), TType_app (tcref2, tinst2, n2) -> + nullnessEqual aenv n1 n2 && tcrefAEquiv g aenv tcref1 tcref2 && typesAEquivAux erasureFlag g aenv tinst1 tinst2 @@ -1102,8 +1118,8 @@ and typeAEquivAux erasureFlag g aenv ty1 ty2 = | TType_tuple (tupInfo1, l1), TType_tuple (tupInfo2, l2) -> structnessAEquiv tupInfo1 tupInfo2 && typesAEquivAux erasureFlag g aenv l1 l2 - // NOTE: nullness annotations are ignored for type equivalence - | TType_fun (domainTy1, rangeTy1, _), TType_fun (domainTy2, rangeTy2, _) -> + | TType_fun (domainTy1, rangeTy1, n1), TType_fun (domainTy2, rangeTy2, n2) -> + nullnessEqual aenv n1 n2 && typeAEquivAux erasureFlag g aenv domainTy1 domainTy2 && typeAEquivAux erasureFlag g aenv rangeTy1 rangeTy2 | TType_anon (anonInfo1, l1), TType_anon (anonInfo2, l2) -> @@ -1117,18 +1133,6 @@ and typeAEquivAux erasureFlag g aenv ty1 ty2 = | _ -> false -and nullnessSensitivetypeAEquivAux erasureFlag g aenv ty1 ty2 = - let ty1 = stripTyEqnsWrtErasure erasureFlag g ty1 - let ty2 = stripTyEqnsWrtErasure erasureFlag g ty2 - match ty1, ty2 with - | TType_var (_,n1), TType_var (_,n2) - | TType_app (_,_,n1), TType_app (_,_,n2) - | TType_fun (_,_,n1), TType_fun (_,_,n2) -> - n1 === n2 - | _ -> true - - && typeAEquivAux erasureFlag g aenv ty1 ty2 - and anonInfoEquiv (anonInfo1: AnonRecdTypeInfo) (anonInfo2: AnonRecdTypeInfo) = ccuEq anonInfo1.Assembly anonInfo2.Assembly && structnessAEquiv anonInfo1.TupInfo anonInfo2.TupInfo && @@ -1153,7 +1157,7 @@ and measureAEquiv g aenv un1 un2 = and typesAEquivAux erasureFlag g aenv l1 l2 = List.lengthsEqAndForall2 (typeAEquivAux erasureFlag g aenv) l1 l2 -and typeEquivAux erasureFlag g ty1 ty2 = typeAEquivAux erasureFlag g TypeEquivEnv.Empty ty1 ty2 +and typeEquivAux erasureFlag g ty1 ty2 = typeAEquivAux erasureFlag g TypeEquivEnv.EmptyIgnoreNulls ty1 ty2 let typeAEquiv g aenv ty1 ty2 = typeAEquivAux EraseNone g aenv ty1 ty2 @@ -1169,7 +1173,7 @@ let typarsAEquiv g aenv d1 d2 = typarsAEquivAux EraseNone g aenv d1 d2 let returnTypesAEquiv g aenv t1 t2 = returnTypesAEquivAux EraseNone g aenv t1 t2 -let measureEquiv g m1 m2 = measureAEquiv g TypeEquivEnv.Empty m1 m2 +let measureEquiv g m1 m2 = measureAEquiv g TypeEquivEnv.EmptyIgnoreNulls m1 m2 // Get measure of type, float<_> or float32<_> or decimal<_> but not float=float<1> or float32=float32<1> or decimal=decimal<1> let getMeasureOfType g ty = @@ -2735,7 +2739,7 @@ let GetTraitConstraintInfosOfTypars g (tps: Typars) = match cx with | TyparConstraint.MayResolveMember(traitInfo, _) -> traitInfo | _ -> () ] - |> ListSet.setify (traitsAEquiv g TypeEquivEnv.Empty) + |> ListSet.setify (traitsAEquiv g TypeEquivEnv.EmptyIgnoreNulls) |> List.sortBy (fun traitInfo -> traitInfo.MemberLogicalName, traitInfo.GetCompiledArgumentTypes().Length) /// Get information about the runtime witnesses needed for a set of generalized typars @@ -4862,7 +4866,7 @@ type SignatureRepackageInfo = { RepackagedVals: (ValRef * ValRef) list RepackagedEntities: (TyconRef * TyconRef) list } - member remapInfo.ImplToSigMapping = { TypeEquivEnv.Empty with EquivTycons = TyconRefMap.OfList remapInfo.RepackagedEntities } + member remapInfo.ImplToSigMapping g = { TypeEquivEnv.EmptyWithNullChecks g with EquivTycons = TyconRefMap.OfList remapInfo.RepackagedEntities } static member Empty = { RepackagedVals = []; RepackagedEntities= [] } type SignatureHidingInfo = @@ -4988,7 +4992,7 @@ let rec accValRemapFromModuleOrNamespaceType g aenv (mty: ModuleOrNamespaceType) let ComputeRemappingFromInferredSignatureToExplicitSignature g mty msigty = let mrpi, _ as entityRemap = accEntityRemapFromModuleOrNamespaceType mty msigty (SignatureRepackageInfo.Empty, SignatureHidingInfo.Empty) - let aenv = mrpi.ImplToSigMapping + let aenv = mrpi.ImplToSigMapping g let valAndEntityRemap = accValRemapFromModuleOrNamespaceType g aenv mty msigty entityRemap valAndEntityRemap @@ -5051,7 +5055,7 @@ and accValRemapFromModuleOrNamespaceDefs g aenv msigty mdefs acc = List.foldBack let ComputeRemappingFromImplementationToSignature g mdef msigty = let mrpi, _ as entityRemap = accEntityRemapFromModuleOrNamespace msigty mdef (SignatureRepackageInfo.Empty, SignatureHidingInfo.Empty) - let aenv = mrpi.ImplToSigMapping + let aenv = mrpi.ImplToSigMapping g let valAndEntityRemap = accValRemapFromModuleOrNamespace g aenv msigty mdef entityRemap valAndEntityRemap @@ -11436,7 +11440,7 @@ type TraitWitnessInfoHashMap<'T> = ImmutableDictionary let EmptyTraitWitnessInfoHashMap g : TraitWitnessInfoHashMap<'T> = ImmutableDictionary.Create( { new IEqualityComparer<_> with - member _.Equals(a, b) = nullSafeEquality a b (fun a b -> traitKeysAEquiv g TypeEquivEnv.Empty a b) + member _.Equals(a, b) = nullSafeEquality a b (fun a b -> traitKeysAEquiv g TypeEquivEnv.EmptyIgnoreNulls a b) member _.GetHashCode(a) = hash a.MemberName }) diff --git a/src/Compiler/TypedTree/TypedTreeOps.fsi b/src/Compiler/TypedTree/TypedTreeOps.fsi index 3a4a1ca4c0a..932e465b0e9 100755 --- a/src/Compiler/TypedTree/TypedTreeOps.fsi +++ b/src/Compiler/TypedTree/TypedTreeOps.fsi @@ -881,15 +881,17 @@ val stripMeasuresFromTy: TcGlobals -> TType -> TType [] type TypeEquivEnv = { EquivTypars: TyparMap - EquivTycons: TyconRefRemap } + EquivTycons: TyconRefRemap + NullnessMustEqual: bool } - static member Empty: TypeEquivEnv + static member EmptyIgnoreNulls: TypeEquivEnv + static member EmptyWithNullChecks: TcGlobals -> TypeEquivEnv member BindEquivTypars: Typars -> Typars -> TypeEquivEnv - static member FromTyparInst: TyparInstantiation -> TypeEquivEnv + member FromTyparInst: TyparInstantiation -> TypeEquivEnv - static member FromEquivTypars: Typars -> Typars -> TypeEquivEnv + member FromEquivTypars: Typars -> Typars -> TypeEquivEnv val traitsAEquivAux: Erasure -> TcGlobals -> TypeEquivEnv -> TraitConstraintInfo -> TraitConstraintInfo -> bool @@ -907,8 +909,6 @@ val typarsAEquiv: TcGlobals -> TypeEquivEnv -> Typars -> Typars -> bool val typeAEquivAux: Erasure -> TcGlobals -> TypeEquivEnv -> TType -> TType -> bool -val nullnessSensitivetypeAEquivAux: Erasure -> TcGlobals -> TypeEquivEnv -> TType -> TType -> bool - val typeAEquiv: TcGlobals -> TypeEquivEnv -> TType -> TType -> bool val returnTypesAEquivAux: Erasure -> TcGlobals -> TypeEquivEnv -> TType option -> TType option -> bool diff --git a/src/Compiler/TypedTree/tainted.fs b/src/Compiler/TypedTree/tainted.fs index d23b5183a53..76a0ba131e4 100644 --- a/src/Compiler/TypedTree/tainted.fs +++ b/src/Compiler/TypedTree/tainted.fs @@ -138,6 +138,12 @@ type internal Tainted<'T> (context: TaintedContext, value: 'T) = | Null -> raise <| TypeProviderError(FSComp.SR.etProviderReturnedNull(methodName), this.TypeProviderDesignation, range) | NonNull a -> a |> Array.map (fun u -> Tainted(context,u)) + member this.PApplyFilteredArray(factory, filter, methodName, range:range) = + let a : 'U[] MaybeNull = this.Protect factory range + match a with + | Null -> raise <| TypeProviderError(FSComp.SR.etProviderReturnedNull(methodName), this.TypeProviderDesignation, range) + | NonNull a -> a |> Array.filter filter |> Array.map (fun u -> Tainted(context,u)) + member this.PApplyOption(f, range: range) = let a = this.Protect f range match a with diff --git a/src/Compiler/TypedTree/tainted.fsi b/src/Compiler/TypedTree/tainted.fsi index 61392794b5f..d066eefd3b2 100644 --- a/src/Compiler/TypedTree/tainted.fsi +++ b/src/Compiler/TypedTree/tainted.fsi @@ -80,6 +80,9 @@ type internal Tainted<'T> = /// Apply an operation that returns an array. Unwrap array. Any exception will be attributed to the type provider with an error located at the given range. String is method name of thing-returning-array, to diagnostically attribute if it is null member PApplyArray: ('T -> 'U[] MaybeNull) * string * range: range -> Tainted<'U>[] + /// Apply an operation that returns an array. Filter the array. Unwrap array. Any exception will be attributed to the type provider with an error located at the given range. String is method name of thing-returning-array, to diagnostically attribute if it is null + member PApplyFilteredArray: ('T -> 'U[] MaybeNull) * ('U -> bool) *string * range: range -> Tainted<'U>[] + /// Apply an operation that returns an option. Unwrap option. Any exception will be attributed to the type provider with an error located at the given range member PApplyOption: ('T -> 'U option) * range: range -> Tainted<'U> option diff --git a/src/Compiler/Utilities/FileSystem.fs b/src/Compiler/Utilities/FileSystem.fs index a541234199e..81d6113cc18 100644 --- a/src/Compiler/Utilities/FileSystem.fs +++ b/src/Compiler/Utilities/FileSystem.fs @@ -431,16 +431,16 @@ module internal FileSystemUtils = let fileNameOfPath path = checkPathForIllegalChars path - Path.GetFileName(path) + !! Path.GetFileName(path) let fileNameWithoutExtensionWithValidate (validate: bool) path = if validate then checkPathForIllegalChars path - Path.GetFileNameWithoutExtension(path) + !! Path.GetFileNameWithoutExtension(path) let fileNameWithoutExtension path = - fileNameWithoutExtensionWithValidate true path + !! fileNameWithoutExtensionWithValidate true path let trimQuotes (path: string) = path.Trim([| ' '; '\"' |]) diff --git a/src/Compiler/Utilities/NullnessShims.fs b/src/Compiler/Utilities/NullnessShims.fs index 785a6c6a3b8..ee801610255 100644 --- a/src/Compiler/Utilities/NullnessShims.fs +++ b/src/Compiler/Utilities/NullnessShims.fs @@ -63,6 +63,14 @@ module internal NullnessShims = #endif +#if NET5_0_OR_GREATER + // Argument type for overriding System.Object.Equals(arg) + // Desktop frameworks as well as netstandard need plain 'obj' and are not annotated, NET5 and higher can use (obj|null) + type objEqualsArg = objnull +#else + type objEqualsArg = obj +#endif + [] let inline (|NonEmptyString|_|) (x: string MaybeNull) = diff --git a/src/Compiler/Utilities/TaggedCollections.fs b/src/Compiler/Utilities/TaggedCollections.fs index 253b38a196d..cb6add28b10 100644 --- a/src/Compiler/Utilities/TaggedCollections.fs +++ b/src/Compiler/Utilities/TaggedCollections.fs @@ -883,7 +883,7 @@ module MapTree = let k3, v3, l' = spliceOutSuccessor mn.Left in k3, v3, mk l' mn.Key mn.Value mn.Right | _ -> m.Key, m.Value, empty - let rec remove (comparer: IComparer<'Key>) k (m: MapTree<'Key, 'Value>) = + let rec remove (comparer: IComparer<'Key>) (k: 'Key) (m: MapTree<'Key, 'Value>) = if isEmpty m then empty else @@ -905,7 +905,7 @@ module MapTree = rebalance mn.Left mn.Key mn.Value (remove comparer k mn.Right) | _ -> if c = 0 then empty else m - let rec mem (comparer: IComparer<'Key>) k (m: MapTree<'Key, 'Value>) = + let rec mem (comparer: IComparer<'Key>) (k: 'Key) (m: MapTree<'Key, 'Value>) = if isEmpty m then false else @@ -1017,7 +1017,14 @@ module MapTree = let foldBack f m x = foldBackOpt (OptimizedClosures.FSharpFunc<_, _, _, _>.Adapt f) m x - let foldSectionOpt (comparer: IComparer<'Key>) lo hi (f: OptimizedClosures.FSharpFunc<_, _, _, _>) (m: MapTree<'Key, 'Value>) x = + let foldSectionOpt + (comparer: IComparer<'Key>) + (lo: 'Key) + (hi: 'Key) + (f: OptimizedClosures.FSharpFunc<_, _, _, _>) + (m: MapTree<'Key, 'Value>) + x + = let rec foldFromTo (f: OptimizedClosures.FSharpFunc<_, _, _, _>) (m: MapTree<'Key, 'Value>) x = if isEmpty m then x diff --git a/src/Compiler/Utilities/TaggedCollections.fsi b/src/Compiler/Utilities/TaggedCollections.fsi index 25552d0d92c..e826f2719b3 100644 --- a/src/Compiler/Utilities/TaggedCollections.fsi +++ b/src/Compiler/Utilities/TaggedCollections.fsi @@ -5,6 +5,7 @@ namespace Internal.Utilities.Collections.Tagged open System open System.Collections.Generic + open Internal.Utilities.Library /// Immutable sets based on binary trees, default tag @@ -114,7 +115,7 @@ namespace Internal.Utilities.Collections.Tagged interface IComparable - override Equals : obj -> bool + override Equals : objEqualsArg -> bool type internal Set<'T> = Set<'T, IComparer<'T>> @@ -218,7 +219,7 @@ namespace Internal.Utilities.Collections.Tagged interface IComparable - override Equals : obj -> bool + override Equals : objEqualsArg -> bool type internal Map<'Key,'Value> = Map<'Key, 'Value, IComparer<'Key>> diff --git a/src/Compiler/Utilities/illib.fs b/src/Compiler/Utilities/illib.fs index 9ed400f3ab8..0f68d92a429 100644 --- a/src/Compiler/Utilities/illib.fs +++ b/src/Compiler/Utilities/illib.fs @@ -206,12 +206,12 @@ module Order = member _.Compare(x, xx) = compare (p !!x) (p !!xx) } - let orderOn p (pxOrder: IComparer<'U>) = + let orderOn (p:'T->'U) (pxOrder: IComparer<'U>) = { new IComparer<'T> with - member _.Compare(x, xx) = pxOrder.Compare(p x, p xx) + member _.Compare(x, xx) = pxOrder.Compare(p !!x, p !!xx) } - let toFunction (pxOrder: IComparer<'U>) x y = pxOrder.Compare(x, y) + let toFunction (pxOrder: IComparer<'U>) (x:'U) (y:'U) = pxOrder.Compare(x, y) //------------------------------------------------------------------------- // Library: arrays, lists, options, resizearrays @@ -796,10 +796,10 @@ module String = elif (!!value).StartsWithOrdinal pattern then Some() else None - let (|Contains|_|) (pattern:string) value = + let (|Contains|_|) (pattern:string) (value:string|null) = match value with - | value when String.IsNullOrWhiteSpace value -> None | null -> None + | value when String.IsNullOrWhiteSpace value -> None | value -> if value.Contains pattern then Some() else None @@ -811,7 +811,7 @@ module String = let mutable line = reader.ReadLine() while not (isNull line) do - yield line + yield (line |> Unchecked.nonNull) line <- reader.ReadLine() if str.EndsWithOrdinal("\n") then diff --git a/src/Compiler/Utilities/illib.fsi b/src/Compiler/Utilities/illib.fsi index 2b23de7de2e..bd9d330cfe4 100644 --- a/src/Compiler/Utilities/illib.fsi +++ b/src/Compiler/Utilities/illib.fsi @@ -94,6 +94,10 @@ module internal Order = #endif val orderOn: p: ('T -> 'U) -> pxOrder: IComparer<'U> -> IComparer<'T> +#if !NO_CHECKNULLS + when 'T:not null + and 'T:not struct +#endif val toFunction: pxOrder: IComparer<'U> -> x: 'U -> y: 'U -> int @@ -280,7 +284,7 @@ module internal String = val (|StartsWith|_|): pattern: string -> value: string -> unit option - val (|Contains|_|): pattern: string -> value: string -> unit option + val (|Contains|_|): pattern: string -> value: string|null -> unit option val getLines: str: string -> string[] diff --git a/src/Compiler/Utilities/lib.fsi b/src/Compiler/Utilities/lib.fsi index cbdb893c5b8..08b834d17c6 100644 --- a/src/Compiler/Utilities/lib.fsi +++ b/src/Compiler/Utilities/lib.fsi @@ -19,7 +19,7 @@ val isEnvVarSet: s: string -> bool val GetEnvInteger: e: string -> dflt: int -> int -val dispose: x: System.IDisposable -> unit +val dispose: x: (System.IDisposable MaybeNull) -> unit module Bits = /// Get the least significant byte of a 32-bit integer diff --git a/src/Compiler/Utilities/range.fs b/src/Compiler/Utilities/range.fs index f9940461a32..5e13752df0b 100755 --- a/src/Compiler/Utilities/range.fs +++ b/src/Compiler/Utilities/range.fs @@ -448,10 +448,22 @@ module Range = let mkFileIndexRange fileIndex startPos endPos = range (fileIndex, startPos, endPos) let posOrder = - Order.orderOn (fun (p: pos) -> p.Line, p.Column) (Pair.order (Int32.order, Int32.order)) + let pairOrder = Pair.order (Int32.order, Int32.order) + let lineAndColumn = fun (p: pos) -> p.Line, p.Column + + { new IComparer with + member _.Compare(x, xx) = + pairOrder.Compare(lineAndColumn x, lineAndColumn xx) + } let rangeOrder = - Order.orderOn (fun (r: range) -> r.FileName, (r.Start, r.End)) (Pair.order (String.order, Pair.order (posOrder, posOrder))) + let tripleOrder = Pair.order (String.order, Pair.order (posOrder, posOrder)) + let fileLineColumn = fun (r: range) -> r.FileName, (r.Start, r.End) + + { new IComparer with + member _.Compare(x, xx) = + tripleOrder.Compare(fileLineColumn x, fileLineColumn xx) + } let outputRange (os: TextWriter) (m: range) = fprintf os "%s%a-%a" m.FileName outputPos m.Start outputPos m.End diff --git a/src/Compiler/xlf/FSComp.txt.cs.xlf b/src/Compiler/xlf/FSComp.txt.cs.xlf index 94d0739a8ce..30a20d94b26 100644 --- a/src/Compiler/xlf/FSComp.txt.cs.xlf +++ b/src/Compiler/xlf/FSComp.txt.cs.xlf @@ -2,6 +2,16 @@ + + Nullness warning: The module contains the field\n {0} \nbut its signature specifies\n {1} \nThe types differ in their nullness annotations + Nullness warning: The module contains the field\n {0} \nbut its signature specifies\n {1} \nThe types differ in their nullness annotations + + + + Nullness warning: Module '{0}' contains\n {1} \nbut its signature specifies\n {2} \nThe types differ in their nullness annotations + Nullness warning: Module '{0}' contains\n {1} \nbut its signature specifies\n {2} \nThe types differ in their nullness annotations + + Interpolated string contains untyped identifiers. Adding typed format specifiers is recommended. Interpolovaný řetězec obsahuje netypové identifikátory. Doporučuje se přidat specifikátory zadaného formátu. diff --git a/src/Compiler/xlf/FSComp.txt.de.xlf b/src/Compiler/xlf/FSComp.txt.de.xlf index b24a332b3cb..99eb6f814b6 100644 --- a/src/Compiler/xlf/FSComp.txt.de.xlf +++ b/src/Compiler/xlf/FSComp.txt.de.xlf @@ -2,6 +2,16 @@ + + Nullness warning: The module contains the field\n {0} \nbut its signature specifies\n {1} \nThe types differ in their nullness annotations + Nullness warning: The module contains the field\n {0} \nbut its signature specifies\n {1} \nThe types differ in their nullness annotations + + + + Nullness warning: Module '{0}' contains\n {1} \nbut its signature specifies\n {2} \nThe types differ in their nullness annotations + Nullness warning: Module '{0}' contains\n {1} \nbut its signature specifies\n {2} \nThe types differ in their nullness annotations + + Interpolated string contains untyped identifiers. Adding typed format specifiers is recommended. Die interpolierte Zeichenfolge enthält nicht typisierte Bezeichner. Das Hinzufügen typisierter Formatbezeichner wird empfohlen. diff --git a/src/Compiler/xlf/FSComp.txt.es.xlf b/src/Compiler/xlf/FSComp.txt.es.xlf index 40dbae13a65..5a841603175 100644 --- a/src/Compiler/xlf/FSComp.txt.es.xlf +++ b/src/Compiler/xlf/FSComp.txt.es.xlf @@ -2,6 +2,16 @@ + + Nullness warning: The module contains the field\n {0} \nbut its signature specifies\n {1} \nThe types differ in their nullness annotations + Nullness warning: The module contains the field\n {0} \nbut its signature specifies\n {1} \nThe types differ in their nullness annotations + + + + Nullness warning: Module '{0}' contains\n {1} \nbut its signature specifies\n {2} \nThe types differ in their nullness annotations + Nullness warning: Module '{0}' contains\n {1} \nbut its signature specifies\n {2} \nThe types differ in their nullness annotations + + Interpolated string contains untyped identifiers. Adding typed format specifiers is recommended. La cadena interpolada contiene identificadores sin tipo. Se recomienda agregar especificadores de formato con tipo. diff --git a/src/Compiler/xlf/FSComp.txt.fr.xlf b/src/Compiler/xlf/FSComp.txt.fr.xlf index 6ee0c6f3dd1..3e98a558168 100644 --- a/src/Compiler/xlf/FSComp.txt.fr.xlf +++ b/src/Compiler/xlf/FSComp.txt.fr.xlf @@ -2,6 +2,16 @@ + + Nullness warning: The module contains the field\n {0} \nbut its signature specifies\n {1} \nThe types differ in their nullness annotations + Nullness warning: The module contains the field\n {0} \nbut its signature specifies\n {1} \nThe types differ in their nullness annotations + + + + Nullness warning: Module '{0}' contains\n {1} \nbut its signature specifies\n {2} \nThe types differ in their nullness annotations + Nullness warning: Module '{0}' contains\n {1} \nbut its signature specifies\n {2} \nThe types differ in their nullness annotations + + Interpolated string contains untyped identifiers. Adding typed format specifiers is recommended. La chaîne interpolée contient des identifiants non typés. L'ajout de spécificateurs de format typés est recommandé. diff --git a/src/Compiler/xlf/FSComp.txt.it.xlf b/src/Compiler/xlf/FSComp.txt.it.xlf index 95d709d785e..b982714a140 100644 --- a/src/Compiler/xlf/FSComp.txt.it.xlf +++ b/src/Compiler/xlf/FSComp.txt.it.xlf @@ -2,6 +2,16 @@ + + Nullness warning: The module contains the field\n {0} \nbut its signature specifies\n {1} \nThe types differ in their nullness annotations + Nullness warning: The module contains the field\n {0} \nbut its signature specifies\n {1} \nThe types differ in their nullness annotations + + + + Nullness warning: Module '{0}' contains\n {1} \nbut its signature specifies\n {2} \nThe types differ in their nullness annotations + Nullness warning: Module '{0}' contains\n {1} \nbut its signature specifies\n {2} \nThe types differ in their nullness annotations + + Interpolated string contains untyped identifiers. Adding typed format specifiers is recommended. La stringa interpolata contiene identificatori non tipizzati. È consigliabile aggiungere identificatori di formato tipizzato. diff --git a/src/Compiler/xlf/FSComp.txt.ja.xlf b/src/Compiler/xlf/FSComp.txt.ja.xlf index 8d7e59c2726..3a23712a963 100644 --- a/src/Compiler/xlf/FSComp.txt.ja.xlf +++ b/src/Compiler/xlf/FSComp.txt.ja.xlf @@ -2,6 +2,16 @@ + + Nullness warning: The module contains the field\n {0} \nbut its signature specifies\n {1} \nThe types differ in their nullness annotations + Nullness warning: The module contains the field\n {0} \nbut its signature specifies\n {1} \nThe types differ in their nullness annotations + + + + Nullness warning: Module '{0}' contains\n {1} \nbut its signature specifies\n {2} \nThe types differ in their nullness annotations + Nullness warning: Module '{0}' contains\n {1} \nbut its signature specifies\n {2} \nThe types differ in their nullness annotations + + Interpolated string contains untyped identifiers. Adding typed format specifiers is recommended. 挿入文字列には、型指定されていない識別子が含まれています。型指定された書式指定子を追加することをお勧めします。 diff --git a/src/Compiler/xlf/FSComp.txt.ko.xlf b/src/Compiler/xlf/FSComp.txt.ko.xlf index d63fbeba99c..41ad2ce40ab 100644 --- a/src/Compiler/xlf/FSComp.txt.ko.xlf +++ b/src/Compiler/xlf/FSComp.txt.ko.xlf @@ -2,6 +2,16 @@ + + Nullness warning: The module contains the field\n {0} \nbut its signature specifies\n {1} \nThe types differ in their nullness annotations + Nullness warning: The module contains the field\n {0} \nbut its signature specifies\n {1} \nThe types differ in their nullness annotations + + + + Nullness warning: Module '{0}' contains\n {1} \nbut its signature specifies\n {2} \nThe types differ in their nullness annotations + Nullness warning: Module '{0}' contains\n {1} \nbut its signature specifies\n {2} \nThe types differ in their nullness annotations + + Interpolated string contains untyped identifiers. Adding typed format specifiers is recommended. 보간된 문자열은 형식화되지 않은 식별자를 포함합니다. 형식화된 형식 지정자를 추가하는 것이 좋습니다. diff --git a/src/Compiler/xlf/FSComp.txt.pl.xlf b/src/Compiler/xlf/FSComp.txt.pl.xlf index b34ec2ab246..f7cf199c4f5 100644 --- a/src/Compiler/xlf/FSComp.txt.pl.xlf +++ b/src/Compiler/xlf/FSComp.txt.pl.xlf @@ -2,6 +2,16 @@ + + Nullness warning: The module contains the field\n {0} \nbut its signature specifies\n {1} \nThe types differ in their nullness annotations + Nullness warning: The module contains the field\n {0} \nbut its signature specifies\n {1} \nThe types differ in their nullness annotations + + + + Nullness warning: Module '{0}' contains\n {1} \nbut its signature specifies\n {2} \nThe types differ in their nullness annotations + Nullness warning: Module '{0}' contains\n {1} \nbut its signature specifies\n {2} \nThe types differ in their nullness annotations + + Interpolated string contains untyped identifiers. Adding typed format specifiers is recommended. Ciąg interpolowany zawiera identyfikatory bez typu. Rekomendowane jest dodanie specyfikatorów formatu pisanego. diff --git a/src/Compiler/xlf/FSComp.txt.pt-BR.xlf b/src/Compiler/xlf/FSComp.txt.pt-BR.xlf index 04ae53e1fa8..4813c278467 100644 --- a/src/Compiler/xlf/FSComp.txt.pt-BR.xlf +++ b/src/Compiler/xlf/FSComp.txt.pt-BR.xlf @@ -2,6 +2,16 @@ + + Nullness warning: The module contains the field\n {0} \nbut its signature specifies\n {1} \nThe types differ in their nullness annotations + Nullness warning: The module contains the field\n {0} \nbut its signature specifies\n {1} \nThe types differ in their nullness annotations + + + + Nullness warning: Module '{0}' contains\n {1} \nbut its signature specifies\n {2} \nThe types differ in their nullness annotations + Nullness warning: Module '{0}' contains\n {1} \nbut its signature specifies\n {2} \nThe types differ in their nullness annotations + + Interpolated string contains untyped identifiers. Adding typed format specifiers is recommended. A cadeia de caracteres interpolada contém identificadores sem tipo. É recomendável adicionar especificadores de formato com tipo. diff --git a/src/Compiler/xlf/FSComp.txt.ru.xlf b/src/Compiler/xlf/FSComp.txt.ru.xlf index 66c68dbe5e0..b1aad1198d9 100644 --- a/src/Compiler/xlf/FSComp.txt.ru.xlf +++ b/src/Compiler/xlf/FSComp.txt.ru.xlf @@ -2,6 +2,16 @@ + + Nullness warning: The module contains the field\n {0} \nbut its signature specifies\n {1} \nThe types differ in their nullness annotations + Nullness warning: The module contains the field\n {0} \nbut its signature specifies\n {1} \nThe types differ in their nullness annotations + + + + Nullness warning: Module '{0}' contains\n {1} \nbut its signature specifies\n {2} \nThe types differ in their nullness annotations + Nullness warning: Module '{0}' contains\n {1} \nbut its signature specifies\n {2} \nThe types differ in their nullness annotations + + Interpolated string contains untyped identifiers. Adding typed format specifiers is recommended. Интерполированная строка содержит нетипизированные идентификаторы. Рекомендуется добавить типизированные описатели формата. diff --git a/src/Compiler/xlf/FSComp.txt.tr.xlf b/src/Compiler/xlf/FSComp.txt.tr.xlf index b6979546951..050ccf6ea95 100644 --- a/src/Compiler/xlf/FSComp.txt.tr.xlf +++ b/src/Compiler/xlf/FSComp.txt.tr.xlf @@ -2,6 +2,16 @@ + + Nullness warning: The module contains the field\n {0} \nbut its signature specifies\n {1} \nThe types differ in their nullness annotations + Nullness warning: The module contains the field\n {0} \nbut its signature specifies\n {1} \nThe types differ in their nullness annotations + + + + Nullness warning: Module '{0}' contains\n {1} \nbut its signature specifies\n {2} \nThe types differ in their nullness annotations + Nullness warning: Module '{0}' contains\n {1} \nbut its signature specifies\n {2} \nThe types differ in their nullness annotations + + Interpolated string contains untyped identifiers. Adding typed format specifiers is recommended. İlişkilendirilmiş dize, türü belirsiz tanımlayıcılar içeriyor. Türü belirtilen biçim belirticiler eklenmesi önerilir. diff --git a/src/Compiler/xlf/FSComp.txt.zh-Hans.xlf b/src/Compiler/xlf/FSComp.txt.zh-Hans.xlf index 2101acb475e..085668fbc09 100644 --- a/src/Compiler/xlf/FSComp.txt.zh-Hans.xlf +++ b/src/Compiler/xlf/FSComp.txt.zh-Hans.xlf @@ -2,6 +2,16 @@ + + Nullness warning: The module contains the field\n {0} \nbut its signature specifies\n {1} \nThe types differ in their nullness annotations + Nullness warning: The module contains the field\n {0} \nbut its signature specifies\n {1} \nThe types differ in their nullness annotations + + + + Nullness warning: Module '{0}' contains\n {1} \nbut its signature specifies\n {2} \nThe types differ in their nullness annotations + Nullness warning: Module '{0}' contains\n {1} \nbut its signature specifies\n {2} \nThe types differ in their nullness annotations + + Interpolated string contains untyped identifiers. Adding typed format specifiers is recommended. 内插字符串包含非类型化标识符。建议添加类型化格式说明符。 diff --git a/src/Compiler/xlf/FSComp.txt.zh-Hant.xlf b/src/Compiler/xlf/FSComp.txt.zh-Hant.xlf index 0a02ec6669c..48f36e86118 100644 --- a/src/Compiler/xlf/FSComp.txt.zh-Hant.xlf +++ b/src/Compiler/xlf/FSComp.txt.zh-Hant.xlf @@ -2,6 +2,16 @@ + + Nullness warning: The module contains the field\n {0} \nbut its signature specifies\n {1} \nThe types differ in their nullness annotations + Nullness warning: The module contains the field\n {0} \nbut its signature specifies\n {1} \nThe types differ in their nullness annotations + + + + Nullness warning: Module '{0}' contains\n {1} \nbut its signature specifies\n {2} \nThe types differ in their nullness annotations + Nullness warning: Module '{0}' contains\n {1} \nbut its signature specifies\n {2} \nThe types differ in their nullness annotations + + Interpolated string contains untyped identifiers. Adding typed format specifiers is recommended. 差補字串包含不具類型的識別項。建議新增具類型的格式規範。 diff --git a/src/FSharp.Build/FSharpEmbedResourceText.fs b/src/FSharp.Build/FSharpEmbedResourceText.fs index 061715184de..9af5eaf4d72 100644 --- a/src/FSharp.Build/FSharpEmbedResourceText.fs +++ b/src/FSharp.Build/FSharpEmbedResourceText.fs @@ -288,10 +288,10 @@ open Printf if isNull s then System.Diagnostics.Debug.Assert(false, sprintf ""**RESOURCE ERROR**: Resource token %s does not exist!"" name) #endif - #if BUILDING_WITH_LKG || NO_NULLCHECKING_LIB_SUPPORT - s - #else + #if NULLABLE Unchecked.nonNull s + #else + s #endif @@ -374,7 +374,7 @@ open Printf messageString <- postProcessString messageString createMessageString messageString fmt - static member GetTextOpt(key:string) = GetString(key) |> Option.ofObj + static member GetTextOpt(key:string) : string option = GetString(key) |> Option.ofObj /// If set to true, then all error messages will just return the filled 'holes' delimited by ',,,'s - this is for language-neutral testing (e.g. localization-invariant baselines). static member SwallowResourceText with get () = swallowResourceText diff --git a/src/FSharp.Core/fslib-extra-pervasives.fs b/src/FSharp.Core/fslib-extra-pervasives.fs index 8ce025606eb..c0b0bc05a04 100644 --- a/src/FSharp.Core/fslib-extra-pervasives.fs +++ b/src/FSharp.Core/fslib-extra-pervasives.fs @@ -473,7 +473,7 @@ type IProvidedNamespace = abstract GetTypes: unit -> Type array - abstract ResolveTypeName: typeName: string -> Type + abstract ResolveTypeName: typeName: string -> (Type|null) type ITypeProvider = inherit System.IDisposable diff --git a/src/FSharp.Core/fslib-extra-pervasives.fsi b/src/FSharp.Core/fslib-extra-pervasives.fsi index aff5d162b0a..898cb94eb55 100644 --- a/src/FSharp.Core/fslib-extra-pervasives.fsi +++ b/src/FSharp.Core/fslib-extra-pervasives.fsi @@ -509,7 +509,7 @@ namespace Microsoft.FSharp.Core.CompilerServices /// Resolver should return a type called name in namespace NamespaceName or null if the type is unknown. /// /// - abstract ResolveTypeName : typeName: string -> Type + abstract ResolveTypeName : typeName: string -> (Type|null) /// /// Represents an instantiation of a type provider component. diff --git a/src/FSharp.Core/map.fsi b/src/FSharp.Core/map.fsi index 5b982141a34..2fdabdbb29f 100644 --- a/src/FSharp.Core/map.fsi +++ b/src/FSharp.Core/map.fsi @@ -215,7 +215,6 @@ type Map<[] 'Key, [> interface IReadOnlyDictionary<'Key, 'Value> - override Equals: objnull -> bool /// Contains operations for working with values of type . [] diff --git a/src/FSharp.Core/prim-types.fsi b/src/FSharp.Core/prim-types.fsi index 15326559354..17f5a6418b0 100644 --- a/src/FSharp.Core/prim-types.fsi +++ b/src/FSharp.Core/prim-types.fsi @@ -3587,16 +3587,16 @@ namespace Microsoft.FSharp.Core [] val inline nonNullV : value:Nullable<'T> -> 'T - /// Asserts that the value is non-null. - /// The value to check. - /// True when value is null, false otherwise. + /// Re-types a value into a nullable reference type (|null) + /// The non-nullable value. + /// The same value re-typed as a nullable reference type. [] val inline withNull : value:'T -> 'T | null when 'T : not null and 'T : not struct - /// Asserts that the value is non-null. + /// Wraps a value type into System.Nullable /// In a future revision of nullness support this may be unified with 'withNull'. - /// The value to check. - /// True when value is null, false otherwise. + /// The value to wrap. + /// System.Nullable wrapper of the input argument. [] val inline withNullV : value:'T -> Nullable<'T> #endif diff --git a/src/FSharp.Core/quotations.fsi b/src/FSharp.Core/quotations.fsi index ebb3d1021ef..a01ee58b914 100644 --- a/src/FSharp.Core/quotations.fsi +++ b/src/FSharp.Core/quotations.fsi @@ -187,8 +187,6 @@ type Expr = /// member CustomAttributes: Expr list - override Equals: obj: objnull -> bool - /// Builds an expression that represents getting the address of a value. /// /// The target expression. diff --git a/src/FSharp.Core/set.fsi b/src/FSharp.Core/set.fsi index 1be1ad557df..d60432fcd0b 100644 --- a/src/FSharp.Core/set.fsi +++ b/src/FSharp.Core/set.fsi @@ -234,7 +234,6 @@ type Set<[] 'T when 'T: comparison> = interface System.IComparable interface System.Collections.IStructuralEquatable interface IReadOnlyCollection<'T> - override Equals: objnull -> bool #if NETSTANDARD2_1_OR_GREATER /// Contains methods for compiler use related to sets. diff --git a/tests/FSharp.Compiler.ComponentTests/EmittedIL/Nullness/HasSignatureWithMissingOverride.fs b/tests/FSharp.Compiler.ComponentTests/EmittedIL/Nullness/HasSignatureWithMissingOverride.fs new file mode 100644 index 00000000000..fd383440611 --- /dev/null +++ b/tests/FSharp.Compiler.ComponentTests/EmittedIL/Nullness/HasSignatureWithMissingOverride.fs @@ -0,0 +1,10 @@ +module SignatureWithMissingOverride + +type MyCollection(count:int) = + member _.Count =count + // This changes nullable annotation from nullable to non-nullable + override _.ToString() : string = "MyCollection" + // This does not change anything + override _.GetHashCode() = 0 + // This must keep the inferred argument as nullable obj! + override _.Equals(obj) = false \ No newline at end of file diff --git a/tests/FSharp.Compiler.ComponentTests/EmittedIL/Nullness/HasSignatureWithMissingOverride.fsi b/tests/FSharp.Compiler.ComponentTests/EmittedIL/Nullness/HasSignatureWithMissingOverride.fsi new file mode 100644 index 00000000000..f633d1de875 --- /dev/null +++ b/tests/FSharp.Compiler.ComponentTests/EmittedIL/Nullness/HasSignatureWithMissingOverride.fsi @@ -0,0 +1,5 @@ +module SignatureWithMissingOverride +[] +type MyCollection = + member Count : int + override ToString: unit -> string \ No newline at end of file diff --git a/tests/FSharp.Compiler.ComponentTests/EmittedIL/Nullness/NullnessMetadata.fs b/tests/FSharp.Compiler.ComponentTests/EmittedIL/Nullness/NullnessMetadata.fs index bc2bcbf9154..e517c97f507 100644 --- a/tests/FSharp.Compiler.ComponentTests/EmittedIL/Nullness/NullnessMetadata.fs +++ b/tests/FSharp.Compiler.ComponentTests/EmittedIL/Nullness/NullnessMetadata.fs @@ -9,14 +9,18 @@ open FSharp.Test.Compiler module NullnessMetadata = type Optimize = Optimize | DoNotOptimize - let verifyCompilation (o:Optimize) compilation = + let addOptions (o:Optimize) compilation = compilation |> withOptions ["--checknulls"] |> (match o with | Optimize -> withOptimize | DoNotOptimize -> withNoOptimize) |> withNoDebug |> withNoInterfaceData |> withNoOptimizationData - |> asLibrary + |> asLibrary + + let verifyCompilation (o:Optimize) compilation = + compilation + |> addOptions o |> verifyILBaseline [] @@ -123,6 +127,20 @@ module NullnessMetadata = |> withNoWarn 52 |> verifyCompilation DoNotOptimize + [] + let ``Override missing in signature`` () = + FsFromPath (__SOURCE_DIRECTORY__ ++ "HasSignatureWithMissingOverride.fsi") + |> withAdditionalSourceFile (SourceFromPath (__SOURCE_DIRECTORY__ ++ "HasSignatureWithMissingOverride.fs")) + |> withNoWarn 52 + |> addOptions DoNotOptimize + |> compile + |> withILContains + [".method public hidebysig virtual instance string ToString() cil managed" + ".method public hidebysig virtual instance int32 GetHashCode() cil managed" + "hidebysig virtual instance bool Equals(object obj) cil managed" + ] + |> shouldSucceed + [] let ``Downcasting and typetests`` compilation = compilation diff --git a/tests/FSharp.Compiler.ComponentTests/Language/Nullness/NullableRegressionTests.fs b/tests/FSharp.Compiler.ComponentTests/Language/Nullness/NullableRegressionTests.fs index e6398675a01..9bf4730e404 100644 --- a/tests/FSharp.Compiler.ComponentTests/Language/Nullness/NullableRegressionTests.fs +++ b/tests/FSharp.Compiler.ComponentTests/Language/Nullness/NullableRegressionTests.fs @@ -28,6 +28,46 @@ let ``Micro compilation`` langVersion checknulls = |> compile |> shouldSucceed +[] +[] +let ``Signature conformance`` langVersion checknulls = + + FsFromPath (__SOURCE_DIRECTORY__ ++ "signatures.fsi") + |> withAdditionalSourceFile (SourceFromPath (__SOURCE_DIRECTORY__ ++ "signatures.fs")) + |> withLangVersion langVersion + |> fun x -> + if checknulls then + x |> withCheckNulls |> withDefines ["CHECKNULLS"] + else x + |> compile + |> shouldFail + |> withDiagnostics + [(Warning 3261, Line 4, Col 5, Line 4, Col 10, "Nullness warning: Module 'M' contains + val test2: x: string | null -> unit + but its signature specifies + val test2: string -> unit + The types differ in their nullness annotations"); + (Warning 3261, Line 3, Col 5, Line 3, Col 10, "Nullness warning: Module 'M' contains + val test1: x: string -> unit + but its signature specifies + val test1: string | null -> unit + The types differ in their nullness annotations"); + (Warning 3261, Line 6, Col 5, Line 6, Col 17, "Nullness warning: Module 'M' contains + val iRejectNulls: x: string | null -> string + but its signature specifies + val iRejectNulls: string -> string + The types differ in their nullness annotations"); + (Warning 3261, Line 14, Col 14, Line 14, Col 21, "Nullness warning: Module 'M' contains + member GenericContainer.GetNull: unit -> 'T + but its signature specifies + member GenericContainer.GetNull: unit -> 'T | null + The types differ in their nullness annotations"); + (Warning 3261, Line 15, Col 14, Line 15, Col 24, "Nullness warning: Module 'M' contains + member GenericContainer.GetNotNull: unit -> 'T | null + but its signature specifies + member GenericContainer.GetNotNull: unit -> 'T + The types differ in their nullness annotations")] + [] let ``Existing positive v8 disabled`` compilation = compilation diff --git a/tests/FSharp.Compiler.ComponentTests/Language/Nullness/micro.fs b/tests/FSharp.Compiler.ComponentTests/Language/Nullness/micro.fs index a0027c2d0a9..191d1d0f274 100644 --- a/tests/FSharp.Compiler.ComponentTests/Language/Nullness/micro.fs +++ b/tests/FSharp.Compiler.ComponentTests/Language/Nullness/micro.fs @@ -10,4 +10,4 @@ let isNotNull (value: 'T) = let s: System.String | null = null #else let s: System.String = null -#endif \ No newline at end of file +#endif diff --git a/tests/FSharp.Compiler.ComponentTests/Language/Nullness/micro.fsi b/tests/FSharp.Compiler.ComponentTests/Language/Nullness/micro.fsi index 25271ae6d7e..a397a9fb162 100644 --- a/tests/FSharp.Compiler.ComponentTests/Language/Nullness/micro.fsi +++ b/tests/FSharp.Compiler.ComponentTests/Language/Nullness/micro.fsi @@ -1,3 +1,3 @@ module M -val isNotNull: value: 'T -> bool when 'T : null \ No newline at end of file +val isNotNull: value: 'T -> bool when 'T : null diff --git a/tests/FSharp.Compiler.ComponentTests/Language/Nullness/signatures.fs b/tests/FSharp.Compiler.ComponentTests/Language/Nullness/signatures.fs new file mode 100644 index 00000000000..ebff7bf03f8 --- /dev/null +++ b/tests/FSharp.Compiler.ComponentTests/Language/Nullness/signatures.fs @@ -0,0 +1,18 @@ +module M + +let test1 (x: string) = () +let test2 (x: string | null) = () + +let iRejectNulls (x:_|null) = + match x with + | null -> "null" + | s -> String.length s |> string + +type GenericContainer<'T when 'T:not null and 'T:not struct>(x:'T) = + let innerVal = x + + member _.GetNull() : ('T) = x + member _.GetNotNull() : ('T|null) = null + +let private GetString(key:string) : string = key + "" +let GetTextOpt(key:string) = GetString(key) |> Option.ofObj \ No newline at end of file diff --git a/tests/FSharp.Compiler.ComponentTests/Language/Nullness/signatures.fsi b/tests/FSharp.Compiler.ComponentTests/Language/Nullness/signatures.fsi new file mode 100644 index 00000000000..42247ec7115 --- /dev/null +++ b/tests/FSharp.Compiler.ComponentTests/Language/Nullness/signatures.fsi @@ -0,0 +1,15 @@ +module M + +val test1: string | null -> unit +val test2: string -> unit + + +val iRejectNulls: string -> string + +[] +type GenericContainer<'T when 'T:not null and 'T:not struct> = + + member GetNull : unit -> ('T|null) + member GetNotNull: unit -> 'T + +val GetTextOpt: key:string -> string option diff --git a/tests/FSharp.Test.Utilities/Compiler.fs b/tests/FSharp.Test.Utilities/Compiler.fs index 1c9fca26592..c6346cb30f2 100644 --- a/tests/FSharp.Test.Utilities/Compiler.fs +++ b/tests/FSharp.Test.Utilities/Compiler.fs @@ -1300,7 +1300,8 @@ 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 -> + CompilationResult.Failure( {s with Output = Some (ExecutionOutput {Outcome = NoExitCode; StdOut = errorMsg; StdErr = ""})} ) | CompilationResult.Failure f -> printfn "Failure:" printfn $"{f}" @@ -1584,11 +1585,15 @@ Actual: if not (List.exists (fun (el: ErrorInfo) -> (getErrorNumber el.Error) = exp) source) then failwith (sprintf "Mismatch in ErrorNumber, expected '%A' was not found during compilation.\nAll errors:\n%A" exp (List.map getErrorInfo source)) + let consequtiveWhiteSpaceTrimmer = new Regex(@"(\r\n|\n|\ |\t)(\ )+") + let trimExtraSpaces s = consequtiveWhiteSpaceTrimmer.Replace(s,"$1") + let private assertErrors (what: string) libAdjust (source: ErrorInfo list) (expected: ErrorInfo list) : unit = // (Error 67, Line 14, Col 3, Line 14, Col 24, "This type test or downcast will always hold") let errorMessage error = let { Error = err; Range = range; Message = message } = error + let message = trimExtraSpaces message let errorType = match err with | ErrorType.Error n -> $"Error {n}" diff --git a/tests/ILVerify/ilverify_FSharp.Compiler.Service_Debug_net9.0.bsl b/tests/ILVerify/ilverify_FSharp.Compiler.Service_Debug_net9.0.bsl index 60c5f6e4b5f..c2263a4f259 100644 --- a/tests/ILVerify/ilverify_FSharp.Compiler.Service_Debug_net9.0.bsl +++ b/tests/ILVerify/ilverify_FSharp.Compiler.Service_Debug_net9.0.bsl @@ -21,14 +21,14 @@ [IL]: Error [StackUnexpected]: : FSharp.Compiler.CodeAnalysis.Hosted.CompilerHelpers::fscCompile([FSharp.Compiler.Service]FSharp.Compiler.CodeAnalysis.LegacyReferenceResolver, string, string[])][offset 0x00000082][found Char] Unexpected type on the stack. [IL]: Error [StackUnexpected]: : FSharp.Compiler.CodeAnalysis.Hosted.CompilerHelpers::fscCompile([FSharp.Compiler.Service]FSharp.Compiler.CodeAnalysis.LegacyReferenceResolver, string, string[])][offset 0x0000008B][found Char] Unexpected type on the stack. [IL]: Error [StackUnexpected]: : FSharp.Compiler.Interactive.Shell+MagicAssemblyResolution::ResolveAssemblyCore([FSharp.Compiler.Service]Internal.Utilities.Library.CompilationThreadToken, [FSharp.Compiler.Service]FSharp.Compiler.Text.Range, [FSharp.Compiler.Service]FSharp.Compiler.CompilerConfig+TcConfigBuilder, [FSharp.Compiler.Service]FSharp.Compiler.CompilerImports+TcImports, [FSharp.Compiler.Service]FSharp.Compiler.Interactive.Shell+FsiDynamicCompiler, [FSharp.Compiler.Service]FSharp.Compiler.Interactive.Shell+FsiConsoleOutput, string)][offset 0x00000015][found Char] Unexpected type on the stack. -[IL]: Error [StackUnexpected]: : FSharp.Compiler.Interactive.Shell+clo@3510-788::Invoke([S.P.CoreLib]System.Tuple`3)][offset 0x000001E5][found Char] Unexpected type on the stack. +[IL]: Error [StackUnexpected]: : FSharp.Compiler.Interactive.Shell+clo@3516-789::Invoke([S.P.CoreLib]System.Tuple`3)][offset 0x000001E5][found Char] Unexpected type on the stack. [IL]: Error [UnmanagedPointer]: : FSharp.Compiler.Interactive.Shell+Utilities+pointerToNativeInt@110::Invoke(object)][offset 0x00000007] Unmanaged pointers are not a verifiable type. [IL]: Error [StackUnexpected]: : .$FSharpCheckerResults+dataTipOfReferences@2205::Invoke([FSharp.Core]Microsoft.FSharp.Core.Unit)][offset 0x00000084][found Char] Unexpected type on the stack. -[IL]: Error [StackUnexpected]: : .$ServiceLexing+clo@921-508::Invoke([FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2,Microsoft.FSharp.Core.Unit>)][offset 0x00000032][found Char] Unexpected type on the stack. -[IL]: Error [StackUnexpected]: : .$ServiceLexing+clo@921-508::Invoke([FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2,Microsoft.FSharp.Core.Unit>)][offset 0x0000003B][found Char] Unexpected type on the stack. -[IL]: Error [StackUnexpected]: : .$ServiceLexing+clo@921-508::Invoke([FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2,Microsoft.FSharp.Core.Unit>)][offset 0x00000082][found Char] Unexpected type on the stack. -[IL]: Error [StackUnexpected]: : .$ServiceLexing+clo@921-508::Invoke([FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2,Microsoft.FSharp.Core.Unit>)][offset 0x0000008B][found Char] Unexpected type on the stack. -[IL]: Error [StackUnexpected]: : .$ServiceLexing+clo@921-508::Invoke([FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2,Microsoft.FSharp.Core.Unit>)][offset 0x00000094][found Char] Unexpected type on the stack. +[IL]: Error [StackUnexpected]: : .$ServiceLexing+clo@921-509::Invoke([FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2,Microsoft.FSharp.Core.Unit>)][offset 0x00000032][found Char] Unexpected type on the stack. +[IL]: Error [StackUnexpected]: : .$ServiceLexing+clo@921-509::Invoke([FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2,Microsoft.FSharp.Core.Unit>)][offset 0x0000003B][found Char] Unexpected type on the stack. +[IL]: Error [StackUnexpected]: : .$ServiceLexing+clo@921-509::Invoke([FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2,Microsoft.FSharp.Core.Unit>)][offset 0x00000082][found Char] Unexpected type on the stack. +[IL]: Error [StackUnexpected]: : .$ServiceLexing+clo@921-509::Invoke([FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2,Microsoft.FSharp.Core.Unit>)][offset 0x0000008B][found Char] Unexpected type on the stack. +[IL]: Error [StackUnexpected]: : .$ServiceLexing+clo@921-509::Invoke([FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2,Microsoft.FSharp.Core.Unit>)][offset 0x00000094][found Char] Unexpected type on the stack. [IL]: Error [StackUnexpected]: : FSharp.Compiler.StaticLinking+TypeForwarding::followTypeForwardForILTypeRef([FSharp.Compiler.Service]FSharp.Compiler.AbstractIL.IL+ILTypeRef)][offset 0x00000010][found Char] Unexpected type on the stack. [IL]: Error [StackUnexpected]: : FSharp.Compiler.CompilerOptions::getCompilerOption([FSharp.Compiler.Service]FSharp.Compiler.CompilerOptions+CompilerOption, [FSharp.Core]Microsoft.FSharp.Core.FSharpOption`1)][offset 0x000000E6][found Char] Unexpected type on the stack. [IL]: Error [StackUnexpected]: : FSharp.Compiler.CompilerOptions::AddPathMapping([FSharp.Compiler.Service]FSharp.Compiler.CompilerConfig+TcConfigBuilder, string)][offset 0x0000000B][found Char] Unexpected type on the stack. @@ -59,7 +59,7 @@ [IL]: Error [StackUnexpected]: : FSharp.Compiler.AbstractIL.IL::parseILVersion(string)][offset 0x0000000B][found Char] Unexpected type on the stack. [IL]: Error [StackUnexpected]: : FSharp.Compiler.AbstractIL.IL::parseILVersion(string)][offset 0x00000021][found Char] Unexpected type on the stack. [IL]: Error [StackUnexpected]: : .$FSharp.Compiler.DiagnosticsLogger::.cctor()][offset 0x000000CD][found Char] Unexpected type on the stack. -[IL]: Error [CallVirtOnValueType]: : FSharp.Compiler.Text.RangeModule+comparer@546::System.Collections.Generic.IEqualityComparer.GetHashCode([FSharp.Compiler.Service]FSharp.Compiler.Text.Range)][offset 0x00000002] Callvirt on a value type method. +[IL]: Error [CallVirtOnValueType]: : FSharp.Compiler.Text.RangeModule+comparer@558::System.Collections.Generic.IEqualityComparer.GetHashCode([FSharp.Compiler.Service]FSharp.Compiler.Text.Range)][offset 0x00000002] Callvirt on a value type method. [IL]: Error [StackUnexpected]: : Internal.Utilities.PathMapModule::applyDir([FSharp.Compiler.Service]Internal.Utilities.PathMap, string)][offset 0x00000037][found Char] Unexpected type on the stack. [IL]: Error [StackUnexpected]: : Internal.Utilities.PathMapModule::applyDir([FSharp.Compiler.Service]Internal.Utilities.PathMap, string)][offset 0x00000043][found Char] Unexpected type on the stack. [IL]: Error [StackUnexpected]: : .$Internal.Utilities.XmlAdapters::.cctor()][offset 0x0000000A][found Char] Unexpected type on the stack. diff --git a/tests/ILVerify/ilverify_FSharp.Compiler.Service_Debug_netstandard2.0.bsl b/tests/ILVerify/ilverify_FSharp.Compiler.Service_Debug_netstandard2.0.bsl index 1e0df962a05..18045d70b31 100644 --- a/tests/ILVerify/ilverify_FSharp.Compiler.Service_Debug_netstandard2.0.bsl +++ b/tests/ILVerify/ilverify_FSharp.Compiler.Service_Debug_netstandard2.0.bsl @@ -28,18 +28,18 @@ [IL]: Error [StackUnexpected]: : FSharp.Compiler.CodeAnalysis.Hosted.CompilerHelpers::fscCompile([FSharp.Compiler.Service]FSharp.Compiler.CodeAnalysis.LegacyReferenceResolver, string, string[])][offset 0x0000008B][found Char] Unexpected type on the stack. [IL]: Error [StackUnexpected]: : FSharp.Compiler.Interactive.Shell+FsiStdinSyphon::GetLine(string, int32)][offset 0x00000039][found Char] Unexpected type on the stack. [IL]: Error [StackUnexpected]: : FSharp.Compiler.Interactive.Shell+MagicAssemblyResolution::ResolveAssemblyCore([FSharp.Compiler.Service]Internal.Utilities.Library.CompilationThreadToken, [FSharp.Compiler.Service]FSharp.Compiler.Text.Range, [FSharp.Compiler.Service]FSharp.Compiler.CompilerConfig+TcConfigBuilder, [FSharp.Compiler.Service]FSharp.Compiler.CompilerImports+TcImports, [FSharp.Compiler.Service]FSharp.Compiler.Interactive.Shell+FsiDynamicCompiler, [FSharp.Compiler.Service]FSharp.Compiler.Interactive.Shell+FsiConsoleOutput, string)][offset 0x00000015][found Char] Unexpected type on the stack. -[IL]: Error [StackUnexpected]: : FSharp.Compiler.Interactive.Shell+clo@3510-788::Invoke([S.P.CoreLib]System.Tuple`3)][offset 0x000001E5][found Char] Unexpected type on the stack. +[IL]: Error [StackUnexpected]: : FSharp.Compiler.Interactive.Shell+clo@3516-789::Invoke([S.P.CoreLib]System.Tuple`3)][offset 0x000001E5][found Char] Unexpected type on the stack. [IL]: Error [StackUnexpected]: : FSharp.Compiler.Interactive.Shell+FsiInteractionProcessor::CompletionsForPartialLID([FSharp.Compiler.Service]FSharp.Compiler.Interactive.Shell+FsiDynamicCompilerState, string)][offset 0x0000001B][found Char] Unexpected type on the stack. [IL]: Error [UnmanagedPointer]: : FSharp.Compiler.Interactive.Shell+Utilities+pointerToNativeInt@110::Invoke(object)][offset 0x00000007] Unmanaged pointers are not a verifiable type. [IL]: Error [StackUnexpected]: : .$FSharpCheckerResults+dataTipOfReferences@2205::Invoke([FSharp.Core]Microsoft.FSharp.Core.Unit)][offset 0x00000084][found Char] Unexpected type on the stack. [IL]: Error [StackUnexpected]: : FSharp.Compiler.EditorServices.AssemblyContent+traverseMemberFunctionAndValues@176::Invoke([FSharp.Compiler.Service]FSharp.Compiler.Symbols.FSharpMemberOrFunctionOrValue)][offset 0x00000059][found Char] Unexpected type on the stack. [IL]: Error [StackUnexpected]: : FSharp.Compiler.EditorServices.AssemblyContent+traverseEntity@218::GenerateNext([S.P.CoreLib]System.Collections.Generic.IEnumerable`1&)][offset 0x000000DA][found Char] Unexpected type on the stack. [IL]: Error [StackUnexpected]: : FSharp.Compiler.EditorServices.ParsedInput+visitor@1423-6::VisitExpr([FSharp.Core]Microsoft.FSharp.Collections.FSharpList`1, [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2>, [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2>, [FSharp.Compiler.Service]FSharp.Compiler.Syntax.SynExpr)][offset 0x00000605][found Char] Unexpected type on the stack. -[IL]: Error [StackUnexpected]: : .$ServiceLexing+clo@921-508::Invoke([FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2,Microsoft.FSharp.Core.Unit>)][offset 0x00000032][found Char] Unexpected type on the stack. -[IL]: Error [StackUnexpected]: : .$ServiceLexing+clo@921-508::Invoke([FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2,Microsoft.FSharp.Core.Unit>)][offset 0x0000003B][found Char] Unexpected type on the stack. -[IL]: Error [StackUnexpected]: : .$ServiceLexing+clo@921-508::Invoke([FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2,Microsoft.FSharp.Core.Unit>)][offset 0x00000082][found Char] Unexpected type on the stack. -[IL]: Error [StackUnexpected]: : .$ServiceLexing+clo@921-508::Invoke([FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2,Microsoft.FSharp.Core.Unit>)][offset 0x0000008B][found Char] Unexpected type on the stack. -[IL]: Error [StackUnexpected]: : .$ServiceLexing+clo@921-508::Invoke([FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2,Microsoft.FSharp.Core.Unit>)][offset 0x00000094][found Char] Unexpected type on the stack. +[IL]: Error [StackUnexpected]: : .$ServiceLexing+clo@921-509::Invoke([FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2,Microsoft.FSharp.Core.Unit>)][offset 0x00000032][found Char] Unexpected type on the stack. +[IL]: Error [StackUnexpected]: : .$ServiceLexing+clo@921-509::Invoke([FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2,Microsoft.FSharp.Core.Unit>)][offset 0x0000003B][found Char] Unexpected type on the stack. +[IL]: Error [StackUnexpected]: : .$ServiceLexing+clo@921-509::Invoke([FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2,Microsoft.FSharp.Core.Unit>)][offset 0x00000082][found Char] Unexpected type on the stack. +[IL]: Error [StackUnexpected]: : .$ServiceLexing+clo@921-509::Invoke([FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2,Microsoft.FSharp.Core.Unit>)][offset 0x0000008B][found Char] Unexpected type on the stack. +[IL]: Error [StackUnexpected]: : .$ServiceLexing+clo@921-509::Invoke([FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2,Microsoft.FSharp.Core.Unit>)][offset 0x00000094][found Char] Unexpected type on the stack. [IL]: Error [StackUnexpected]: : .$Symbols+fullName@2495-1::Invoke([FSharp.Core]Microsoft.FSharp.Core.Unit)][offset 0x00000015][found Char] Unexpected type on the stack. [IL]: Error [StackUnexpected]: : FSharp.Compiler.CreateILModule+MainModuleBuilder::ConvertProductVersionToILVersionInfo(string)][offset 0x00000011][found Char] Unexpected type on the stack. [IL]: Error [StackUnexpected]: : FSharp.Compiler.StaticLinking+TypeForwarding::followTypeForwardForILTypeRef([FSharp.Compiler.Service]FSharp.Compiler.AbstractIL.IL+ILTypeRef)][offset 0x00000010][found Char] Unexpected type on the stack. @@ -81,10 +81,10 @@ [IL]: Error [StackUnexpected]: : FSharp.Compiler.AbstractIL.IL::parseILVersion(string)][offset 0x00000021][found Char] Unexpected type on the stack. [IL]: Error [StackUnexpected]: : FSharp.Compiler.AbstractIL.IL+parseNamed@5291::Invoke([FSharp.Core]Microsoft.FSharp.Collections.FSharpList`1>, int32, int32)][offset 0x00000087][found Char] Unexpected type on the stack. [IL]: Error [StackUnexpected]: : Internal.Utilities.Collections.Utils::shortPath(string)][offset 0x00000015][found Char] Unexpected type on the stack. -[IL]: Error [StackUnexpected]: : Internal.Utilities.FSharpEnvironment+probePathForDotnetHost@321::Invoke([FSharp.Core]Microsoft.FSharp.Core.Unit)][offset 0x00000028][found Char] Unexpected type on the stack. +[IL]: Error [StackUnexpected]: : Internal.Utilities.FSharpEnvironment+probePathForDotnetHost@322::Invoke([FSharp.Core]Microsoft.FSharp.Core.Unit)][offset 0x00000028][found Char] Unexpected type on the stack. [IL]: Error [StackUnexpected]: : FSharp.Compiler.CodeAnalysis.SimulatedMSBuildReferenceResolver+Pipe #6 input at line 68@68::FSharp.Compiler.CodeAnalysis.ILegacyReferenceResolver.Resolve([FSharp.Compiler.Service]FSharp.Compiler.CodeAnalysis.LegacyResolutionEnvironment, [S.P.CoreLib]System.Tuple`2[], string, [FSharp.Core]Microsoft.FSharp.Collections.FSharpList`1, string, string, [FSharp.Core]Microsoft.FSharp.Collections.FSharpList`1, string, [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2, [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2>>)][offset 0x0000034D][found Char] Unexpected type on the stack. [IL]: Error [StackUnexpected]: : .$FSharp.Compiler.DiagnosticsLogger::.cctor()][offset 0x000000CD][found Char] Unexpected type on the stack. -[IL]: Error [CallVirtOnValueType]: : FSharp.Compiler.Text.RangeModule+comparer@546::System.Collections.Generic.IEqualityComparer.GetHashCode([FSharp.Compiler.Service]FSharp.Compiler.Text.Range)][offset 0x00000002] Callvirt on a value type method. +[IL]: Error [CallVirtOnValueType]: : FSharp.Compiler.Text.RangeModule+comparer@558::System.Collections.Generic.IEqualityComparer.GetHashCode([FSharp.Compiler.Service]FSharp.Compiler.Text.Range)][offset 0x00000002] Callvirt on a value type method. [IL]: Error [StackUnexpected]: : Internal.Utilities.PathMapModule::applyDir([FSharp.Compiler.Service]Internal.Utilities.PathMap, string)][offset 0x00000037][found Char] Unexpected type on the stack. [IL]: Error [StackUnexpected]: : Internal.Utilities.PathMapModule::applyDir([FSharp.Compiler.Service]Internal.Utilities.PathMap, string)][offset 0x00000043][found Char] Unexpected type on the stack. [IL]: Error [StackUnexpected]: : .$Internal.Utilities.XmlAdapters::.cctor()][offset 0x0000000A][found Char] Unexpected type on the stack. diff --git a/tests/ILVerify/ilverify_FSharp.Compiler.Service_Release_net9.0.bsl b/tests/ILVerify/ilverify_FSharp.Compiler.Service_Release_net9.0.bsl index bc7e03d8154..b01f7e04acb 100644 --- a/tests/ILVerify/ilverify_FSharp.Compiler.Service_Release_net9.0.bsl +++ b/tests/ILVerify/ilverify_FSharp.Compiler.Service_Release_net9.0.bsl @@ -21,13 +21,13 @@ [IL]: Error [StackUnexpected]: : FSharp.Compiler.CodeAnalysis.Hosted.CompilerHelpers::fscCompile([FSharp.Compiler.Service]FSharp.Compiler.CodeAnalysis.LegacyReferenceResolver, string, string[])][offset 0x00000082][found Char] Unexpected type on the stack. [IL]: Error [StackUnexpected]: : FSharp.Compiler.CodeAnalysis.Hosted.CompilerHelpers::fscCompile([FSharp.Compiler.Service]FSharp.Compiler.CodeAnalysis.LegacyReferenceResolver, string, string[])][offset 0x0000008B][found Char] Unexpected type on the stack. [IL]: Error [StackUnexpected]: : FSharp.Compiler.Interactive.Shell+MagicAssemblyResolution::ResolveAssemblyCore([FSharp.Compiler.Service]Internal.Utilities.Library.CompilationThreadToken, [FSharp.Compiler.Service]FSharp.Compiler.Text.Range, [FSharp.Compiler.Service]FSharp.Compiler.CompilerConfig+TcConfigBuilder, [FSharp.Compiler.Service]FSharp.Compiler.CompilerImports+TcImports, [FSharp.Compiler.Service]FSharp.Compiler.Interactive.Shell+FsiDynamicCompiler, [FSharp.Compiler.Service]FSharp.Compiler.Interactive.Shell+FsiConsoleOutput, string)][offset 0x00000015][found Char] Unexpected type on the stack. -[IL]: Error [StackUnexpected]: : FSharp.Compiler.Interactive.Shell+clo@3510-832::Invoke([S.P.CoreLib]System.Tuple`3)][offset 0x000001C7][found Char] Unexpected type on the stack. +[IL]: Error [StackUnexpected]: : FSharp.Compiler.Interactive.Shell+clo@3516-833::Invoke([S.P.CoreLib]System.Tuple`3)][offset 0x000001C7][found Char] Unexpected type on the stack. [IL]: Error [StackUnexpected]: : .$FSharpCheckerResults+GetReferenceResolutionStructuredToolTipText@2205::Invoke([FSharp.Core]Microsoft.FSharp.Core.Unit)][offset 0x00000076][found Char] Unexpected type on the stack. -[IL]: Error [StackUnexpected]: : .$ServiceLexing+clo@921-529::Invoke([FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2,Microsoft.FSharp.Core.Unit>)][offset 0x00000032][found Char] Unexpected type on the stack. -[IL]: Error [StackUnexpected]: : .$ServiceLexing+clo@921-529::Invoke([FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2,Microsoft.FSharp.Core.Unit>)][offset 0x0000003B][found Char] Unexpected type on the stack. -[IL]: Error [StackUnexpected]: : .$ServiceLexing+clo@921-529::Invoke([FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2,Microsoft.FSharp.Core.Unit>)][offset 0x00000064][found Char] Unexpected type on the stack. -[IL]: Error [StackUnexpected]: : .$ServiceLexing+clo@921-529::Invoke([FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2,Microsoft.FSharp.Core.Unit>)][offset 0x0000006D][found Char] Unexpected type on the stack. -[IL]: Error [StackUnexpected]: : .$ServiceLexing+clo@921-529::Invoke([FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2,Microsoft.FSharp.Core.Unit>)][offset 0x00000076][found Char] Unexpected type on the stack. +[IL]: Error [StackUnexpected]: : .$ServiceLexing+clo@921-530::Invoke([FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2,Microsoft.FSharp.Core.Unit>)][offset 0x00000032][found Char] Unexpected type on the stack. +[IL]: Error [StackUnexpected]: : .$ServiceLexing+clo@921-530::Invoke([FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2,Microsoft.FSharp.Core.Unit>)][offset 0x0000003B][found Char] Unexpected type on the stack. +[IL]: Error [StackUnexpected]: : .$ServiceLexing+clo@921-530::Invoke([FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2,Microsoft.FSharp.Core.Unit>)][offset 0x00000064][found Char] Unexpected type on the stack. +[IL]: Error [StackUnexpected]: : .$ServiceLexing+clo@921-530::Invoke([FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2,Microsoft.FSharp.Core.Unit>)][offset 0x0000006D][found Char] Unexpected type on the stack. +[IL]: Error [StackUnexpected]: : .$ServiceLexing+clo@921-530::Invoke([FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2,Microsoft.FSharp.Core.Unit>)][offset 0x00000076][found Char] Unexpected type on the stack. [IL]: Error [StackUnexpected]: : FSharp.Compiler.Driver+ProcessCommandLineFlags@301-1::Invoke(string)][offset 0x0000000B][found Char] Unexpected type on the stack. [IL]: Error [StackUnexpected]: : FSharp.Compiler.Driver+ProcessCommandLineFlags@301-1::Invoke(string)][offset 0x00000014][found Char] Unexpected type on the stack. [IL]: Error [StackUnexpected]: : FSharp.Compiler.StaticLinking+TypeForwarding::followTypeForwardForILTypeRef([FSharp.Compiler.Service]FSharp.Compiler.AbstractIL.IL+ILTypeRef)][offset 0x00000010][found Char] Unexpected type on the stack. @@ -85,7 +85,7 @@ [IL]: Error [StackUnexpected]: : FSharp.Compiler.AbstractIL.IL::parseILVersion(string)][offset 0x0000000B][found Char] Unexpected type on the stack. [IL]: Error [StackUnexpected]: : FSharp.Compiler.AbstractIL.IL::parseILVersion(string)][offset 0x00000021][found Char] Unexpected type on the stack. [IL]: Error [StackUnexpected]: : .$FSharp.Compiler.DiagnosticsLogger::.cctor()][offset 0x000000B6][found Char] Unexpected type on the stack. -[IL]: Error [CallVirtOnValueType]: : FSharp.Compiler.Text.RangeModule+comparer@546::System.Collections.Generic.IEqualityComparer.GetHashCode([FSharp.Compiler.Service]FSharp.Compiler.Text.Range)][offset 0x00000002] Callvirt on a value type method. +[IL]: Error [CallVirtOnValueType]: : FSharp.Compiler.Text.RangeModule+comparer@558::System.Collections.Generic.IEqualityComparer.GetHashCode([FSharp.Compiler.Service]FSharp.Compiler.Text.Range)][offset 0x00000002] Callvirt on a value type method. [IL]: Error [StackUnexpected]: : Internal.Utilities.PathMapModule::applyDir([FSharp.Compiler.Service]Internal.Utilities.PathMap, string)][offset 0x00000035][found Char] Unexpected type on the stack. [IL]: Error [StackUnexpected]: : Internal.Utilities.PathMapModule::applyDir([FSharp.Compiler.Service]Internal.Utilities.PathMap, string)][offset 0x00000041][found Char] Unexpected type on the stack. [IL]: Error [StackUnexpected]: : .$Internal.Utilities.XmlAdapters::.cctor()][offset 0x0000000A][found Char] Unexpected type on the stack. diff --git a/tests/ILVerify/ilverify_FSharp.Compiler.Service_Release_netstandard2.0.bsl b/tests/ILVerify/ilverify_FSharp.Compiler.Service_Release_netstandard2.0.bsl index 88e5b423f24..e093fab1d7d 100644 --- a/tests/ILVerify/ilverify_FSharp.Compiler.Service_Release_netstandard2.0.bsl +++ b/tests/ILVerify/ilverify_FSharp.Compiler.Service_Release_netstandard2.0.bsl @@ -28,17 +28,17 @@ [IL]: Error [StackUnexpected]: : FSharp.Compiler.CodeAnalysis.Hosted.CompilerHelpers::fscCompile([FSharp.Compiler.Service]FSharp.Compiler.CodeAnalysis.LegacyReferenceResolver, string, string[])][offset 0x0000008B][found Char] Unexpected type on the stack. [IL]: Error [StackUnexpected]: : FSharp.Compiler.Interactive.Shell+FsiStdinSyphon::GetLine(string, int32)][offset 0x00000032][found Char] Unexpected type on the stack. [IL]: Error [StackUnexpected]: : FSharp.Compiler.Interactive.Shell+MagicAssemblyResolution::ResolveAssemblyCore([FSharp.Compiler.Service]Internal.Utilities.Library.CompilationThreadToken, [FSharp.Compiler.Service]FSharp.Compiler.Text.Range, [FSharp.Compiler.Service]FSharp.Compiler.CompilerConfig+TcConfigBuilder, [FSharp.Compiler.Service]FSharp.Compiler.CompilerImports+TcImports, [FSharp.Compiler.Service]FSharp.Compiler.Interactive.Shell+FsiDynamicCompiler, [FSharp.Compiler.Service]FSharp.Compiler.Interactive.Shell+FsiConsoleOutput, string)][offset 0x00000015][found Char] Unexpected type on the stack. -[IL]: Error [StackUnexpected]: : FSharp.Compiler.Interactive.Shell+clo@3510-832::Invoke([S.P.CoreLib]System.Tuple`3)][offset 0x000001C7][found Char] Unexpected type on the stack. +[IL]: Error [StackUnexpected]: : FSharp.Compiler.Interactive.Shell+clo@3516-833::Invoke([S.P.CoreLib]System.Tuple`3)][offset 0x000001C7][found Char] Unexpected type on the stack. [IL]: Error [StackUnexpected]: : FSharp.Compiler.Interactive.Shell+FsiInteractionProcessor::CompletionsForPartialLID([FSharp.Compiler.Service]FSharp.Compiler.Interactive.Shell+FsiDynamicCompilerState, string)][offset 0x00000024][found Char] Unexpected type on the stack. [IL]: Error [StackUnexpected]: : .$FSharpCheckerResults+GetReferenceResolutionStructuredToolTipText@2205::Invoke([FSharp.Core]Microsoft.FSharp.Core.Unit)][offset 0x00000076][found Char] Unexpected type on the stack. [IL]: Error [StackUnexpected]: : FSharp.Compiler.EditorServices.AssemblyContent+traverseMemberFunctionAndValues@176::Invoke([FSharp.Compiler.Service]FSharp.Compiler.Symbols.FSharpMemberOrFunctionOrValue)][offset 0x0000002B][found Char] Unexpected type on the stack. [IL]: Error [StackUnexpected]: : FSharp.Compiler.EditorServices.AssemblyContent+traverseEntity@218::GenerateNext([S.P.CoreLib]System.Collections.Generic.IEnumerable`1&)][offset 0x000000BB][found Char] Unexpected type on the stack. [IL]: Error [StackUnexpected]: : FSharp.Compiler.EditorServices.ParsedInput+visitor@1423-11::VisitExpr([FSharp.Core]Microsoft.FSharp.Collections.FSharpList`1, [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2>, [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2>, [FSharp.Compiler.Service]FSharp.Compiler.Syntax.SynExpr)][offset 0x00000620][found Char] Unexpected type on the stack. -[IL]: Error [StackUnexpected]: : .$ServiceLexing+clo@921-529::Invoke([FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2,Microsoft.FSharp.Core.Unit>)][offset 0x00000032][found Char] Unexpected type on the stack. -[IL]: Error [StackUnexpected]: : .$ServiceLexing+clo@921-529::Invoke([FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2,Microsoft.FSharp.Core.Unit>)][offset 0x0000003B][found Char] Unexpected type on the stack. -[IL]: Error [StackUnexpected]: : .$ServiceLexing+clo@921-529::Invoke([FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2,Microsoft.FSharp.Core.Unit>)][offset 0x00000064][found Char] Unexpected type on the stack. -[IL]: Error [StackUnexpected]: : .$ServiceLexing+clo@921-529::Invoke([FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2,Microsoft.FSharp.Core.Unit>)][offset 0x0000006D][found Char] Unexpected type on the stack. -[IL]: Error [StackUnexpected]: : .$ServiceLexing+clo@921-529::Invoke([FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2,Microsoft.FSharp.Core.Unit>)][offset 0x00000076][found Char] Unexpected type on the stack. +[IL]: Error [StackUnexpected]: : .$ServiceLexing+clo@921-530::Invoke([FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2,Microsoft.FSharp.Core.Unit>)][offset 0x00000032][found Char] Unexpected type on the stack. +[IL]: Error [StackUnexpected]: : .$ServiceLexing+clo@921-530::Invoke([FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2,Microsoft.FSharp.Core.Unit>)][offset 0x0000003B][found Char] Unexpected type on the stack. +[IL]: Error [StackUnexpected]: : .$ServiceLexing+clo@921-530::Invoke([FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2,Microsoft.FSharp.Core.Unit>)][offset 0x00000064][found Char] Unexpected type on the stack. +[IL]: Error [StackUnexpected]: : .$ServiceLexing+clo@921-530::Invoke([FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2,Microsoft.FSharp.Core.Unit>)][offset 0x0000006D][found Char] Unexpected type on the stack. +[IL]: Error [StackUnexpected]: : .$ServiceLexing+clo@921-530::Invoke([FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2,Microsoft.FSharp.Core.Unit>)][offset 0x00000076][found Char] Unexpected type on the stack. [IL]: Error [StackUnexpected]: : .$Symbols+fullName@2495-3::Invoke([FSharp.Core]Microsoft.FSharp.Core.Unit)][offset 0x00000030][found Char] Unexpected type on the stack. [IL]: Error [StackUnexpected]: : FSharp.Compiler.Driver+ProcessCommandLineFlags@301-1::Invoke(string)][offset 0x0000000B][found Char] Unexpected type on the stack. [IL]: Error [StackUnexpected]: : FSharp.Compiler.Driver+ProcessCommandLineFlags@301-1::Invoke(string)][offset 0x00000014][found Char] Unexpected type on the stack. @@ -108,10 +108,10 @@ [IL]: Error [StackUnexpected]: : FSharp.Compiler.AbstractIL.IL::parseILVersion(string)][offset 0x00000021][found Char] Unexpected type on the stack. [IL]: Error [StackUnexpected]: : FSharp.Compiler.AbstractIL.IL::parseNamed@5290(uint8[], [FSharp.Core]Microsoft.FSharp.Collections.FSharpList`1>, int32, int32)][offset 0x0000007E][found Char] Unexpected type on the stack. [IL]: Error [StackUnexpected]: : Internal.Utilities.Collections.Utils::shortPath(string)][offset 0x00000016][found Char] Unexpected type on the stack. -[IL]: Error [StackUnexpected]: : Internal.Utilities.FSharpEnvironment::probePathForDotnetHost@320([FSharp.Core]Microsoft.FSharp.Core.Unit)][offset 0x0000002A][found Char] Unexpected type on the stack. +[IL]: Error [StackUnexpected]: : Internal.Utilities.FSharpEnvironment::probePathForDotnetHost@321([FSharp.Core]Microsoft.FSharp.Core.Unit)][offset 0x0000002A][found Char] Unexpected type on the stack. [IL]: Error [StackUnexpected]: : FSharp.Compiler.CodeAnalysis.SimulatedMSBuildReferenceResolver+SimulatedMSBuildResolver@68::FSharp.Compiler.CodeAnalysis.ILegacyReferenceResolver.Resolve([FSharp.Compiler.Service]FSharp.Compiler.CodeAnalysis.LegacyResolutionEnvironment, [S.P.CoreLib]System.Tuple`2[], string, [FSharp.Core]Microsoft.FSharp.Collections.FSharpList`1, string, string, [FSharp.Core]Microsoft.FSharp.Collections.FSharpList`1, string, [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2, [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2>>)][offset 0x000002F5][found Char] Unexpected type on the stack. [IL]: Error [StackUnexpected]: : .$FSharp.Compiler.DiagnosticsLogger::.cctor()][offset 0x000000B6][found Char] Unexpected type on the stack. -[IL]: Error [CallVirtOnValueType]: : FSharp.Compiler.Text.RangeModule+comparer@546::System.Collections.Generic.IEqualityComparer.GetHashCode([FSharp.Compiler.Service]FSharp.Compiler.Text.Range)][offset 0x00000002] Callvirt on a value type method. +[IL]: Error [CallVirtOnValueType]: : FSharp.Compiler.Text.RangeModule+comparer@558::System.Collections.Generic.IEqualityComparer.GetHashCode([FSharp.Compiler.Service]FSharp.Compiler.Text.Range)][offset 0x00000002] Callvirt on a value type method. [IL]: Error [StackUnexpected]: : Internal.Utilities.PathMapModule::applyDir([FSharp.Compiler.Service]Internal.Utilities.PathMap, string)][offset 0x00000035][found Char] Unexpected type on the stack. [IL]: Error [StackUnexpected]: : Internal.Utilities.PathMapModule::applyDir([FSharp.Compiler.Service]Internal.Utilities.PathMap, string)][offset 0x00000041][found Char] Unexpected type on the stack. [IL]: Error [StackUnexpected]: : .$Internal.Utilities.XmlAdapters::.cctor()][offset 0x0000000A][found Char] Unexpected type on the stack. From ee559975b208d5eb64cc9c3c832a29de1bf5f131 Mon Sep 17 00:00:00 2001 From: Tomas Grosup Date: Fri, 7 Feb 2025 14:42:02 +0100 Subject: [PATCH 16/29] Handle |null types when optimizing away equals/hash/compare from LanguagePrimitves into instance method calls (#18296) * Handle |null types when optimizing away eqals/hash/compare from function call to instance method * Set propper test assert * fantomas and notes * remove comment --- .../.FSharp.Compiler.Service/9.0.300.md | 1 + .../Checking/AugmentWithHashCompare.fsi | 6 ++ src/Compiler/Optimize/Optimizer.fs | 66 ++++++++++++------- .../Nullness/NullableReferenceTypesTests.fs | 46 ++++++++++++- 4 files changed, 94 insertions(+), 25 deletions(-) diff --git a/docs/release-notes/.FSharp.Compiler.Service/9.0.300.md b/docs/release-notes/.FSharp.Compiler.Service/9.0.300.md index f41b4ca9289..a6d29f078d4 100644 --- a/docs/release-notes/.FSharp.Compiler.Service/9.0.300.md +++ b/docs/release-notes/.FSharp.Compiler.Service/9.0.300.md @@ -7,6 +7,7 @@ * Fix missing nullness warning when static upcast dropped nullness ([Issue #18232](https://github.com/dotnet/fsharp/issues/18232), [PR #18261](https://github.com/dotnet/fsharp/pull/18261)) * Cancellable: only cancel on OCE with own token ([PR #18277](https://github.com/dotnet/fsharp/pull/18277)) * Cancellable: set token in more places ([PR #18283](https://github.com/dotnet/fsharp/pull/18283)) +* Fix NRE when accessing nullable fields of types within their equals/hash/compare methods ([PR #18296](https://github.com/dotnet/fsharp/pull/18296)) ### Added * Added missing type constraints in FCS. ([PR #18241](https://github.com/dotnet/fsharp/pull/18241)) diff --git a/src/Compiler/Checking/AugmentWithHashCompare.fsi b/src/Compiler/Checking/AugmentWithHashCompare.fsi index 4a7d74311b1..b57e25f32cc 100644 --- a/src/Compiler/Checking/AugmentWithHashCompare.fsi +++ b/src/Compiler/Checking/AugmentWithHashCompare.fsi @@ -14,6 +14,12 @@ type EqualityWithComparerAugmentation = EqualsWithComparer: Val EqualsExactWithComparer: Val } +val mkBindNullComparison: TcGlobals -> Text.Range -> thise: Expr -> thate: Expr -> expr: Expr -> Expr + +val mkBindThisNullEquals: TcGlobals -> Text.Range -> thise: Expr -> thate: Expr -> expr: Expr -> Expr + +val mkBindNullHash: TcGlobals -> Text.Range -> thise: Expr -> expr: Expr -> Expr + val CheckAugmentationAttribs: bool -> TcGlobals -> Import.ImportMap -> Tycon -> unit val TyconIsCandidateForAugmentationWithCompare: TcGlobals -> Tycon -> bool diff --git a/src/Compiler/Optimize/Optimizer.fs b/src/Compiler/Optimize/Optimizer.fs index 51d889f5691..69fb9b45974 100644 --- a/src/Compiler/Optimize/Optimizer.fs +++ b/src/Compiler/Optimize/Optimizer.fs @@ -1664,7 +1664,9 @@ and OpHasEffect g m op = | TOp.ExnFieldGet (ecref, n) -> isExnFieldMutable ecref n | TOp.RefAddrGet _ -> false | TOp.AnonRecdGet _ -> true // conservative - | TOp.ValFieldGet rfref -> rfref.RecdField.IsMutable || (TryFindTyconRefBoolAttribute g range0 g.attrib_AllowNullLiteralAttribute rfref.TyconRef = Some true) + | TOp.ValFieldGet rfref -> + rfref.RecdField.IsMutable + || (TryFindTyconRefBoolAttribute g range0 g.attrib_AllowNullLiteralAttribute rfref.TyconRef = Some true) | TOp.ValFieldGetAddr (rfref, _readonly) -> rfref.RecdField.IsMutable | TOp.UnionCaseFieldGetAddr _ -> false // union case fields are immutable | TOp.LValueOp (LAddrOf _, _) -> false // addresses of values are always constants @@ -3167,7 +3169,7 @@ and CanDevirtualizeApplication cenv v vref ty args = && not (isUnitTy g ty) && isAppTy g ty // Exclusion: Some unions have null as representations - && not (IsUnionTypeWithNullAsTrueValue g (fst(StripToNominalTyconRef cenv ty)).Deref) + && not (IsUnionTypeWithNullAsTrueValue g (fst(StripToNominalTyconRef cenv ty)).Deref) // If we de-virtualize an operation on structs then we have to take the address of the object argument // Hence we have to actually have the object argument available to us, && (not (isStructTy g ty) || not (isNil args)) @@ -3189,9 +3191,13 @@ and TakeAddressOfStructArgumentIfNeeded cenv (vref: ValRef) ty args m = else id, args -and DevirtualizeApplication cenv env (vref: ValRef) ty tyargs args m = +and DevirtualizeApplication cenv env (vref: ValRef) ty tyargs args m nullHandlerOpt = let g = cenv.g - let wrap, args = TakeAddressOfStructArgumentIfNeeded cenv vref ty args m + let wrap, args = + match nullHandlerOpt with + | Some nullHandler when g.checkNullness && TypeNullIsExtraValueNew g vref.Range ty -> + nullHandler g m, args + | _ -> TakeAddressOfStructArgumentIfNeeded cenv vref ty args m let transformedExpr = wrap (MakeApplicationAndBetaReduce g (exprForValRef m vref, vref.Type, (if isNil tyargs then [] else [tyargs]), args, m)) OptimizeExpr cenv env transformedExpr @@ -3212,8 +3218,10 @@ and TryDevirtualizeApplication cenv env (f, tyargs, args, m) = | Expr.Val (v, _, _), [ty], _ when CanDevirtualizeApplication cenv v g.generic_comparison_inner_vref ty args -> let tcref, tyargs = StripToNominalTyconRef cenv ty - match tcref.GeneratedCompareToValues with - | Some (_, vref) -> Some (DevirtualizeApplication cenv env vref ty tyargs args m) + match tcref.GeneratedCompareToValues, args with + | Some (_, vref), [x;y] -> + let nullHandler g m = AugmentTypeDefinitions.mkBindNullComparison g m x y + Some (DevirtualizeApplication cenv env vref ty tyargs args m (Some nullHandler)) | _ -> None | Expr.Val (v, _, _), [ty], _ when CanDevirtualizeApplication cenv v g.generic_comparison_withc_inner_vref ty args -> @@ -3225,7 +3233,8 @@ and TryDevirtualizeApplication cenv env (f, tyargs, args, m) = // arg list, and create a tuple of y & comp // push the comparer to the end and box the argument let args2 = [x; mkRefTupledNoTypes g m [mkCoerceExpr(y, g.obj_ty_ambivalent, m, ty) ; comp]] - Some (DevirtualizeApplication cenv env vref ty tyargs args2 m) + let nullHandler g m = AugmentTypeDefinitions.mkBindNullComparison g m x y + Some (DevirtualizeApplication cenv env vref ty tyargs args2 m (Some nullHandler)) | _ -> None // Optimize/analyze calls to LanguagePrimitives.HashCompare.GenericEqualityIntrinsic when type is known @@ -3235,8 +3244,10 @@ and TryDevirtualizeApplication cenv env (f, tyargs, args, m) = | Expr.Val (v, _, _), [ty], _ when CanDevirtualizeApplication cenv v g.generic_equality_er_inner_vref ty args -> let tcref, tyargs = StripToNominalTyconRef cenv ty - match tcref.GeneratedHashAndEqualsValues with - | Some (_, vref) -> Some (DevirtualizeApplication cenv env vref ty tyargs args m) + match tcref.GeneratedHashAndEqualsValues, args with + | Some (_, vref),[x;y] -> + let nullHandler g m = AugmentTypeDefinitions.mkBindThisNullEquals g m x y + Some (DevirtualizeApplication cenv env vref ty tyargs args m (Some nullHandler)) | _ -> None // Optimize/analyze calls to LanguagePrimitives.HashCompare.GenericEqualityWithComparerIntrinsic @@ -3246,11 +3257,13 @@ and TryDevirtualizeApplication cenv env (f, tyargs, args, m) = | Some (_, _, _, Some withcEqualsExactVal), [comp; x; y] -> // push the comparer to the end let args2 = [x; mkRefTupledNoTypes g m [y; comp]] - Some (DevirtualizeApplication cenv env withcEqualsExactVal ty tyargs args2 m) + let nullHandler g m = AugmentTypeDefinitions.mkBindThisNullEquals g m x y + Some (DevirtualizeApplication cenv env withcEqualsExactVal ty tyargs args2 m (Some nullHandler)) | Some (_, _, withcEqualsVal, _ ), [comp; x; y] -> // push the comparer to the end and box the argument let args2 = [x; mkRefTupledNoTypes g m [mkCoerceExpr(y, g.obj_ty_ambivalent, m, ty) ; comp]] - Some (DevirtualizeApplication cenv env withcEqualsVal ty tyargs args2 m) + let nullHandler g m = AugmentTypeDefinitions.mkBindThisNullEquals g m x y + Some (DevirtualizeApplication cenv env withcEqualsVal ty tyargs args2 m (Some nullHandler)) | _ -> None // Optimize/analyze calls to LanguagePrimitives.HashCompare.GenericEqualityIntrinsic @@ -3259,20 +3272,23 @@ and TryDevirtualizeApplication cenv env (f, tyargs, args, m) = match tcref.GeneratedHashAndEqualsWithComparerValues, args with | Some (_, _, _, Some withcEqualsExactVal), [x; y] -> let args2 = [x; mkRefTupledNoTypes g m [y; (mkCallGetGenericPEREqualityComparer g m)]] - Some (DevirtualizeApplication cenv env withcEqualsExactVal ty tyargs args2 m) + let nullHandler g m = AugmentTypeDefinitions.mkBindThisNullEquals g m x y + Some (DevirtualizeApplication cenv env withcEqualsExactVal ty tyargs args2 m (Some nullHandler)) | Some (_, _, withcEqualsVal, _), [x; y] -> let equalsExactOpt = tcref.MembersOfFSharpTyconByName.TryFind("Equals") |> Option.map (List.where (fun x -> x.IsCompilerGenerated)) |> Option.bind List.tryExactlyOne + let nullHandler g m = AugmentTypeDefinitions.mkBindThisNullEquals g m x y + match equalsExactOpt with | Some equalsExact -> let args2 = [x; mkRefTupledNoTypes g m [y; (mkCallGetGenericPEREqualityComparer g m)]] - Some (DevirtualizeApplication cenv env equalsExact ty tyargs args2 m) + Some (DevirtualizeApplication cenv env equalsExact ty tyargs args2 m (Some nullHandler)) | None -> let args2 = [x; mkRefTupledNoTypes g m [mkCoerceExpr(y, g.obj_ty_ambivalent, m, ty); (mkCallGetGenericPEREqualityComparer g m)]] - Some (DevirtualizeApplication cenv env withcEqualsVal ty tyargs args2 m) + Some (DevirtualizeApplication cenv env withcEqualsVal ty tyargs args2 m (Some nullHandler)) | _ -> None // Optimize/analyze calls to LanguagePrimitives.HashCompare.GenericHashIntrinsic @@ -3281,7 +3297,8 @@ and TryDevirtualizeApplication cenv env (f, tyargs, args, m) = match tcref.GeneratedHashAndEqualsWithComparerValues, args with | Some (_, withcGetHashCodeVal, _, _), [x] -> let args2 = [x; mkCallGetGenericEREqualityComparer g m] - Some (DevirtualizeApplication cenv env withcGetHashCodeVal ty tyargs args2 m) + let nullHandler g m = AugmentTypeDefinitions.mkBindNullHash g m x + Some (DevirtualizeApplication cenv env withcGetHashCodeVal ty tyargs args2 m (Some nullHandler)) | _ -> None // Optimize/analyze calls to LanguagePrimitives.HashCompare.GenericHashWithComparerIntrinsic @@ -3290,7 +3307,8 @@ and TryDevirtualizeApplication cenv env (f, tyargs, args, m) = match tcref.GeneratedHashAndEqualsWithComparerValues, args with | Some (_, withcGetHashCodeVal, _, _), [comp; x] -> let args2 = [x; comp] - Some (DevirtualizeApplication cenv env withcGetHashCodeVal ty tyargs args2 m) + let nullHandler g m = AugmentTypeDefinitions.mkBindNullHash g m x + Some (DevirtualizeApplication cenv env withcGetHashCodeVal ty tyargs args2 m (Some nullHandler)) | _ -> None // Optimize/analyze calls to LanguagePrimitives.HashCompare.GenericComparisonWithComparerIntrinsic for tuple types @@ -3304,7 +3322,7 @@ and TryDevirtualizeApplication cenv env (f, tyargs, args, m) = | 5 -> Some g.generic_compare_withc_tuple5_vref | _ -> None match vref with - | Some vref -> Some (DevirtualizeApplication cenv env vref ty tyargs (mkCallGetGenericComparer g m :: args) m) + | Some vref -> Some (DevirtualizeApplication cenv env vref ty tyargs (mkCallGetGenericComparer g m :: args) m None) | None -> None // Optimize/analyze calls to LanguagePrimitives.HashCompare.GenericHashWithComparerIntrinsic for tuple types @@ -3318,7 +3336,7 @@ and TryDevirtualizeApplication cenv env (f, tyargs, args, m) = | 5 -> Some g.generic_hash_withc_tuple5_vref | _ -> None match vref with - | Some vref -> Some (DevirtualizeApplication cenv env vref ty tyargs (mkCallGetGenericEREqualityComparer g m :: args) m) + | Some vref -> Some (DevirtualizeApplication cenv env vref ty tyargs (mkCallGetGenericEREqualityComparer g m :: args) m None) | None -> None // Optimize/analyze calls to LanguagePrimitives.HashCompare.GenericEqualityIntrinsic for tuple types @@ -3334,7 +3352,7 @@ and TryDevirtualizeApplication cenv env (f, tyargs, args, m) = | 5 -> Some g.generic_equals_withc_tuple5_vref | _ -> None match vref with - | Some vref -> Some (DevirtualizeApplication cenv env vref ty tyargs (mkCallGetGenericPEREqualityComparer g m :: args) m) + | Some vref -> Some (DevirtualizeApplication cenv env vref ty tyargs (mkCallGetGenericPEREqualityComparer g m :: args) m None) | None -> None // Optimize/analyze calls to LanguagePrimitives.HashCompare.GenericComparisonWithComparerIntrinsic for tuple types @@ -3348,7 +3366,7 @@ and TryDevirtualizeApplication cenv env (f, tyargs, args, m) = | 5 -> Some g.generic_compare_withc_tuple5_vref | _ -> None match vref with - | Some vref -> Some (DevirtualizeApplication cenv env vref ty tyargs args m) + | Some vref -> Some (DevirtualizeApplication cenv env vref ty tyargs args m None) | None -> None // Optimize/analyze calls to LanguagePrimitives.HashCompare.GenericHashWithComparerIntrinsic for tuple types @@ -3362,7 +3380,7 @@ and TryDevirtualizeApplication cenv env (f, tyargs, args, m) = | 5 -> Some g.generic_hash_withc_tuple5_vref | _ -> None match vref with - | Some vref -> Some (DevirtualizeApplication cenv env vref ty tyargs args m) + | Some vref -> Some (DevirtualizeApplication cenv env vref ty tyargs args m None) | None -> None // Optimize/analyze calls to LanguagePrimitives.HashCompare.GenericEqualityWithComparerIntrinsic for tuple types @@ -3376,7 +3394,7 @@ and TryDevirtualizeApplication cenv env (f, tyargs, args, m) = | 5 -> Some g.generic_equals_withc_tuple5_vref | _ -> None match vref with - | Some vref -> Some (DevirtualizeApplication cenv env vref ty tyargs args m) + | Some vref -> Some (DevirtualizeApplication cenv env vref ty tyargs args m None) | None -> None // Calls to LanguagePrimitives.IntrinsicFunctions.UnboxGeneric can be optimized to calls to UnboxFast when we know that the @@ -3385,7 +3403,7 @@ and TryDevirtualizeApplication cenv env (f, tyargs, args, m) = | Expr.Val (v, _, _), [ty], _ when valRefEq g v g.unbox_vref && canUseUnboxFast g m ty -> - Some(DevirtualizeApplication cenv env g.unbox_fast_vref ty tyargs args m) + Some(DevirtualizeApplication cenv env g.unbox_fast_vref ty tyargs args m None) // Calls to LanguagePrimitives.IntrinsicFunctions.TypeTestGeneric can be optimized to calls to TypeTestFast when we know that the // target type isn't 'NullNotTrueValue', i.e. that the target type is not an F# union, record etc. @@ -3393,7 +3411,7 @@ and TryDevirtualizeApplication cenv env (f, tyargs, args, m) = | Expr.Val (v, _, _), [ty], _ when valRefEq g v g.istype_vref && canUseTypeTestFast g ty -> - Some(DevirtualizeApplication cenv env g.istype_fast_vref ty tyargs args m) + Some(DevirtualizeApplication cenv env g.istype_fast_vref ty tyargs args m None) // Don't fiddle with 'methodhandleof' calls - just remake the application | Expr.Val (vref, _, _), _, _ when valRefEq g vref g.methodhandleof_vref -> diff --git a/tests/FSharp.Compiler.ComponentTests/Language/Nullness/NullableReferenceTypesTests.fs b/tests/FSharp.Compiler.ComponentTests/Language/Nullness/NullableReferenceTypesTests.fs index 85b872d01a2..018b81c9384 100644 --- a/tests/FSharp.Compiler.ComponentTests/Language/Nullness/NullableReferenceTypesTests.fs +++ b/tests/FSharp.Compiler.ComponentTests/Language/Nullness/NullableReferenceTypesTests.fs @@ -1329,4 +1329,48 @@ let myOption () : option = None """ .maxstack 8 IL_0000: ldnull IL_0001: ret - }"] \ No newline at end of file + }"] + +// Regression https://github.com/dotnet/fsharp/issues/18286 +[] +let ``Equality and hashcode augmentation is null safe`` () = + + Fsx """ + +type Bar = { b: string | null } +type Foo = { f: Bar | null } +type DUFoo = WithNull of (Foo|null) +let a = { f = null } +let b = { f = null } + +let c = WithNull(null) +let d = WithNull(null) + +let e = WithNull(a) +let f = WithNull(b) + +[] +let main _ = + printf "Test %A;" ({b = null} = {b = null}) + printf ",1 %A" (a = b) + printf ",2 %A" (a.GetHashCode() = b.GetHashCode()) + printf ",3 %A" (c = d) + printf ",4 %A" (c.GetHashCode() = d.GetHashCode()) + printf ",5 %A" (e = f) + printf ",6 %A" (e = c) + printf ",7 %A" (e.GetHashCode() = f.GetHashCode()) + printf ",8 %A" (e.GetHashCode() = c.GetHashCode()) + + printf ",9 %A" (a > b) + printf ",10 %A" (c > d) + printf ",11 %A" (e > f) + printf ",12 %A" (e > c) + 0 +""" + |> withNullnessOptions + |> withOptimization false + |> asExe + |> compile + //|> verifyIL ["abc"] + |> run + |> verifyOutputContains [|"Test true;,1 true,2 true,3 true,4 true,5 true,6 false,7 true,8 false,9 false,10 false,11 false,12 true"|] \ No newline at end of file From ad29712d1ac6f026711cb585e0d184a190890e4c Mon Sep 17 00:00:00 2001 From: Jeremy Koritzinsky Date: Sat, 8 Feb 2025 11:01:59 -0800 Subject: [PATCH 17/29] Only build the Microsoft.FSharp.Compiler.sln solution in the VMR (#18299) --- eng/DotNetBuild.props | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/eng/DotNetBuild.props b/eng/DotNetBuild.props index b44b8bae3b4..3098934511e 100644 --- a/eng/DotNetBuild.props +++ b/eng/DotNetBuild.props @@ -12,8 +12,7 @@ the cloned source in the inner build. --> + BeforeTargets="GetSourceBuildCommandConfiguration"> $(InnerBuildArgs) /p:Projects="$(InnerSourceBuildRepoRoot)\Microsoft.FSharp.Compiler.sln" From b64ea2b04b729ef02ca79b4ad85bedc45d26679b Mon Sep 17 00:00:00 2001 From: Tomas Grosup Date: Mon, 10 Feb 2025 11:38:00 +0100 Subject: [PATCH 18/29] Consolidate `.Using` and |null in builders (#18292) --- .fantomasignore | 5 +++++ docs/release-notes/.FSharp.Compiler.Service/9.0.300.md | 1 + docs/release-notes/.FSharp.Core/9.0.300.md | 3 ++- src/Compiler/Utilities/Activity.fs | 8 ++++---- src/Compiler/Utilities/Activity.fsi | 7 ++++--- src/Compiler/Utilities/Cancellable.fs | 2 +- src/Compiler/Utilities/Cancellable.fsi | 6 +++++- src/Compiler/Utilities/lib.fs | 5 ++++- src/Compiler/Utilities/lib.fsi | 7 ++++++- src/FSharp.Core/async.fs | 2 +- src/FSharp.Core/async.fsi | 2 +- src/FSharp.Core/prim-types.fs | 5 ++++- src/FSharp.Core/prim-types.fsi | 4 ++++ src/FSharp.Core/resumable.fs | 2 +- src/FSharp.Core/resumable.fsi | 2 +- src/FSharp.Core/tasks.fs | 4 ++-- src/FSharp.Core/tasks.fsi | 2 +- 17 files changed, 47 insertions(+), 20 deletions(-) diff --git a/.fantomasignore b/.fantomasignore index 9c12ffa8e2c..f5798fbdf00 100644 --- a/.fantomasignore +++ b/.fantomasignore @@ -41,6 +41,11 @@ src/Compiler/Checking/TypeHierarchy.fs src/Compiler/Checking/TypeRelations.fs # nullness-related problems +src/Compiler/Utilities/lib.fsi +src/Compiler/Utilities/Cancellable.fsi +src/FSharp.Core/tasks.fsi +src/FSharp.Core/tasks.fs +src/FSharp.Core/resumable.fs src/Compiler/DependencyManager/DependencyProvider.fs src/FSharp.Core/fslib-extra-pervasives.fs src/FSharp.Core/fslib-extra-pervasives.fsi diff --git a/docs/release-notes/.FSharp.Compiler.Service/9.0.300.md b/docs/release-notes/.FSharp.Compiler.Service/9.0.300.md index a6d29f078d4..8343f04bd6a 100644 --- a/docs/release-notes/.FSharp.Compiler.Service/9.0.300.md +++ b/docs/release-notes/.FSharp.Compiler.Service/9.0.300.md @@ -20,6 +20,7 @@ * FSharpCheckFileResults.ProjectContext.ProjectOptions will not be available when using the experimental Transparent Compiler feature. ([PR #18205](https://github.com/dotnet/fsharp/pull/18205)) * Update `Obsolete` attribute checking to account for `DiagnosticId` and `UrlFormat` properties. ([PR #18224](https://github.com/dotnet/fsharp/pull/18224)) * Remove `Cancellable.UsingToken` from tests ([PR #18276](https://github.com/dotnet/fsharp/pull/18276)) +* Added nullability annotations to `.Using` builder method for `async`, `task` and compiler-internal builders ([PR #18292](https://github.com/dotnet/fsharp/pull/18292)) ### Breaking Changes * Struct unions with overlapping fields now generate mappings needed for reading via reflection ([Issue #18121](https://github.com/dotnet/fsharp/issues/17797), [PR #18274](https://github.com/dotnet/fsharp/pull/17877)) \ No newline at end of file diff --git a/docs/release-notes/.FSharp.Core/9.0.300.md b/docs/release-notes/.FSharp.Core/9.0.300.md index 87d3502539c..5e6903f3fa4 100644 --- a/docs/release-notes/.FSharp.Core/9.0.300.md +++ b/docs/release-notes/.FSharp.Core/9.0.300.md @@ -1,8 +1,9 @@ ### Fixed ### Added +* Added nullability annotations to `.Using` builder method for `async` and `task` builders ([PR #18292](https://github.com/dotnet/fsharp/pull/18292)) ### Changed ### Breaking Changes -* Struct unions with overlapping fields now generate mappings needed for reading via reflection ([Issue #18121](https://github.com/dotnet/fsharp/issues/17797), [PR #18274](https://github.com/dotnet/fsharp/pull/17877)). Previous versions of FSharp.Core returned incomplete mapping between fields and cases, these older fslib versions will now report an exception. +* Struct unions with overlapping fields now generate mappings needed for reading via reflection ([Issue #18121](https://github.com/dotnet/fsharp/issues/17797), [PR #18274](https://github.com/dotnet/fsharp/pull/18274)). Previous versions of FSharp.Core returned incomplete mapping between fields and cases, these older fslib versions will now report an exception. diff --git a/src/Compiler/Utilities/Activity.fs b/src/Compiler/Utilities/Activity.fs index 2403f00d3de..e2d7e78fcb6 100644 --- a/src/Compiler/Utilities/Activity.fs +++ b/src/Compiler/Utilities/Activity.fs @@ -89,18 +89,18 @@ module internal Activity = let private activitySource = new ActivitySource(ActivityNames.FscSourceName) - let start (name: string) (tags: (string * string) seq) : IDisposable = + let start (name: string) (tags: (string * string) seq) : IDisposable MaybeNull = let activity = activitySource.CreateActivity(name, ActivityKind.Internal) match activity with - | null -> !!activity //TODO change retTy to |null after PR #18262 is merged!! + | null -> activity | activity -> for key, value in tags do activity.AddTag(key, value) |> ignore activity.Start() - let startNoTags (name: string) : IDisposable = !! (activitySource.StartActivity name) //TODO change retTy to |null after PR #18262 is merged!! + let startNoTags (name: string) : IDisposable MaybeNull = activitySource.StartActivity name let addEvent name = match Activity.Current with @@ -122,7 +122,7 @@ module internal Activity = let private profiledSource = new ActivitySource(ActivityNames.ProfiledSourceName) - let startAndMeasureEnvironmentStats (name: string) : IDisposable = !!(profiledSource.StartActivity(name)) //TODO change retTy to |null after PR #18262 is merged!! + let startAndMeasureEnvironmentStats (name: string) : IDisposable MaybeNull = profiledSource.StartActivity(name) type private GCStats = int[] diff --git a/src/Compiler/Utilities/Activity.fsi b/src/Compiler/Utilities/Activity.fsi index ec6a9fbf6f8..6e7244f5e59 100644 --- a/src/Compiler/Utilities/Activity.fsi +++ b/src/Compiler/Utilities/Activity.fsi @@ -2,6 +2,7 @@ namespace FSharp.Compiler.Diagnostics open System +open Internal.Utilities.Library /// For activities following the dotnet distributed tracing concept /// https://learn.microsoft.com/dotnet/core/diagnostics/distributed-tracing-concepts?source=recommendations @@ -39,14 +40,14 @@ module internal Activity = module Events = val cacheHit: string - val startNoTags: name: string -> IDisposable + val startNoTags: name: string -> IDisposable MaybeNull - val start: name: string -> tags: (string * string) seq -> IDisposable + val start: name: string -> tags: (string * string) seq -> IDisposable MaybeNull val addEvent: name: string -> unit module Profiling = - val startAndMeasureEnvironmentStats: name: string -> IDisposable + val startAndMeasureEnvironmentStats: name: string -> IDisposable MaybeNull val addConsoleListener: unit -> IDisposable module CsvExport = diff --git a/src/Compiler/Utilities/Cancellable.fs b/src/Compiler/Utilities/Cancellable.fs index ad739b5039e..4d6c42cd6f0 100644 --- a/src/Compiler/Utilities/Cancellable.fs +++ b/src/Compiler/Utilities/Cancellable.fs @@ -162,7 +162,7 @@ type CancellableBuilder() = | Choice2Of2 err -> Cancellable.run ct (handler err) | ValueOrCancelled.Cancelled err1 -> ValueOrCancelled.Cancelled err1) - member inline _.Using(resource, [] comp) = + member inline _.Using(resource: _ MaybeNull, [] comp) = Cancellable(fun ct -> #if !FSHARPCORE_USE_PACKAGE __debugPoint "" diff --git a/src/Compiler/Utilities/Cancellable.fsi b/src/Compiler/Utilities/Cancellable.fsi index aba96859491..737a27a4f2a 100644 --- a/src/Compiler/Utilities/Cancellable.fsi +++ b/src/Compiler/Utilities/Cancellable.fsi @@ -71,8 +71,12 @@ type internal CancellableBuilder = comp: Cancellable<'T> * [] handler: (exn -> Cancellable<'T>) -> Cancellable<'T> member inline Using: - resource: 'Resource * [] comp: ('Resource -> Cancellable<'T>) -> Cancellable<'T> + resource: 'Resource MaybeNull * [] comp: ('Resource MaybeNull -> Cancellable<'T>) -> Cancellable<'T> when 'Resource :> IDisposable + and 'Resource:not struct +#if !(NO_CHECKNULLS || BUILDING_WITH_LKG) + and 'Resource:not null +#endif member inline Zero: unit -> Cancellable diff --git a/src/Compiler/Utilities/lib.fs b/src/Compiler/Utilities/lib.fs index 921b0a6dba3..609245f636e 100755 --- a/src/Compiler/Utilities/lib.fs +++ b/src/Compiler/Utilities/lib.fs @@ -403,7 +403,10 @@ type DisposablesTracker() = let items = Stack() /// Register some items to dispose - member _.Register i = items.Push i + member _.Register (i:#IDisposable MaybeNull) = + match box i with + | null -> () + | _ -> items.Push (!!i) interface IDisposable with diff --git a/src/Compiler/Utilities/lib.fsi b/src/Compiler/Utilities/lib.fsi index 08b834d17c6..ea0669bdf4a 100644 --- a/src/Compiler/Utilities/lib.fsi +++ b/src/Compiler/Utilities/lib.fsi @@ -263,7 +263,12 @@ type DisposablesTracker = new: unit -> DisposablesTracker /// Register some items to dispose - member Register: i: System.IDisposable -> unit + member Register: i:'a MaybeNull -> unit + when 'a:>System.IDisposable +#if !(NO_CHECKNULLS || BUILDING_WITH_LKG) + and 'a:not null +#endif + and 'a:not struct interface System.IDisposable diff --git a/src/FSharp.Core/async.fs b/src/FSharp.Core/async.fs index 959d47d0aab..2b117be0b16 100644 --- a/src/FSharp.Core/async.fs +++ b/src/FSharp.Core/async.fs @@ -753,7 +753,7 @@ module AsyncPrimitives = /// - Cancellation check after 'entering' the implied try/finally and before running the body (see CreateTryFinallyAsync) /// - Hijack check after 'entering' the implied try/finally and before running the body (see CreateTryFinallyAsync) /// - Run 'disposeFunction' with exception protection (see CreateTryFinallyAsync) - let CreateUsingAsync (resource: 'T :> IDisposable) (computation: 'T -> Async<'a>) : Async<'a> = + let CreateUsingAsync (resource: 'T :> IDisposable | null) (computation: 'T -> Async<'a>) : Async<'a> = let disposeFunction () = Microsoft.FSharp.Core.LanguagePrimitives.IntrinsicFunctions.Dispose resource diff --git a/src/FSharp.Core/async.fsi b/src/FSharp.Core/async.fsi index e01ba0d8d75..d4227d292f5 100644 --- a/src/FSharp.Core/async.fsi +++ b/src/FSharp.Core/async.fsi @@ -1325,7 +1325,7 @@ namespace Microsoft.FSharp.Control /// An asynchronous computation that binds and eventually disposes resource. /// /// - member Using: resource:'T * binder:('T -> Async<'U>) -> Async<'U> when 'T :> System.IDisposable + member Using: resource:'T * binder:('T -> Async<'U>) -> Async<'U> when 'T :> System.IDisposable|null /// Creates an asynchronous computation that runs computation, and when /// computation generates a result T, runs binder res. diff --git a/src/FSharp.Core/prim-types.fs b/src/FSharp.Core/prim-types.fs index 1fc9e799ab4..4f4849eb849 100644 --- a/src/FSharp.Core/prim-types.fs +++ b/src/FSharp.Core/prim-types.fs @@ -739,8 +739,11 @@ namespace Microsoft.FSharp.Core let inline TypeTestFast<'T>(source: objnull) = //assert not(TypeInfo<'T>.TypeInfo = TypeNullnessSemantics_NullTrueValue) notnullPrim(isinstPrim<'T>(source)) - +#if !BUILDING_WITH_LKG && !NO_NULLCHECKING_LIB_SUPPORT + let Dispose<'T when 'T :> IDisposable >(resource:'T|null) = +#else let Dispose<'T when 'T :> IDisposable >(resource:'T) = +#endif match box resource with | null -> () | _ -> resource.Dispose() diff --git a/src/FSharp.Core/prim-types.fsi b/src/FSharp.Core/prim-types.fsi index 17f5a6418b0..c56fe5375e4 100644 --- a/src/FSharp.Core/prim-types.fsi +++ b/src/FSharp.Core/prim-types.fsi @@ -1796,7 +1796,11 @@ namespace Microsoft.FSharp.Core /// A compiler intrinsic for the efficient compilation of sequence expressions [] +#if !BUILDING_WITH_LKG && !NO_NULLCHECKING_LIB_SUPPORT + val Dispose<'T when 'T :> System.IDisposable> : resource: 'T|null -> unit +#else val Dispose<'T when 'T :> System.IDisposable> : resource: 'T -> unit +#endif /// A compiler intrinsic for checking initialization soundness of recursive bindings [] diff --git a/src/FSharp.Core/resumable.fs b/src/FSharp.Core/resumable.fs index 27e91a93256..1488ab220cf 100644 --- a/src/FSharp.Core/resumable.fs +++ b/src/FSharp.Core/resumable.fs @@ -399,7 +399,7 @@ module ResumableCode = ( resource: 'Resource, body: 'Resource -> ResumableCode<'Data, 'T> - ) : ResumableCode<'Data, 'T> when 'Resource :> IDisposable = + ) : ResumableCode<'Data, 'T> when 'Resource :> IDisposable|null = // A using statement is just a try/finally with the finally block disposing if non-null. TryFinally( ResumableCode<'Data, 'T>(fun sm -> (body resource).Invoke(&sm)), diff --git a/src/FSharp.Core/resumable.fsi b/src/FSharp.Core/resumable.fsi index 466301dc36b..2835b75a4dc 100644 --- a/src/FSharp.Core/resumable.fsi +++ b/src/FSharp.Core/resumable.fsi @@ -90,7 +90,7 @@ module ResumableCode = val inline TryWith: body: ResumableCode<'Data, 'T> * catch: (exn -> ResumableCode<'Data, 'T>) -> ResumableCode<'Data, 'T> /// Specifies resumable code which executes with 'use' semantics - val inline Using: resource: 'Resource * body: ('Resource -> ResumableCode<'Data, 'T>) -> ResumableCode<'Data, 'T> when 'Resource :> IDisposable + val inline Using: resource: 'Resource * body: ('Resource -> ResumableCode<'Data, 'T>) -> ResumableCode<'Data, 'T> when 'Resource :> IDisposable|null /// Specifies resumable code which executes a loop val inline While: [] condition: (unit -> bool) * body: ResumableCode<'Data, unit> -> ResumableCode<'Data, unit> diff --git a/src/FSharp.Core/tasks.fs b/src/FSharp.Core/tasks.fs index faaa920cb15..dfe7f4ba624 100644 --- a/src/FSharp.Core/tasks.fs +++ b/src/FSharp.Core/tasks.fs @@ -138,7 +138,7 @@ type TaskBuilderBase() = false) ) - member inline this.Using<'Resource, 'TOverall, 'T when 'Resource :> IAsyncDisposable> + member inline this.Using<'Resource, 'TOverall, 'T when 'Resource :> IAsyncDisposable|null> ( resource: 'Resource, body: 'Resource -> TaskCode<'TOverall, 'T> @@ -382,7 +382,7 @@ module LowPriority = this.Bind(task, this.Return) - member inline _.Using<'Resource, 'TOverall, 'T when 'Resource :> IDisposable> + member inline _.Using<'Resource, 'TOverall, 'T when 'Resource :> IDisposable|null> ( resource: 'Resource, body: 'Resource -> TaskCode<'TOverall, 'T> diff --git a/src/FSharp.Core/tasks.fsi b/src/FSharp.Core/tasks.fsi index 47713a60a3f..c626cb4bb7b 100644 --- a/src/FSharp.Core/tasks.fsi +++ b/src/FSharp.Core/tasks.fsi @@ -237,7 +237,7 @@ module LowPriority = /// member inline Using: resource: 'Resource * body: ('Resource -> TaskCode<'TOverall, 'T>) -> TaskCode<'TOverall, 'T> - when 'Resource :> IDisposable + when 'Resource :> IDisposable|null /// /// Contains medium-priority overloads for the `task` computation expression builder. From 8e773e70700eea38f472950fd042ac0065dabae0 Mon Sep 17 00:00:00 2001 From: Edgar Gonzalez Date: Mon, 10 Feb 2025 13:35:57 +0000 Subject: [PATCH 19/29] Add support for C# `Experimental` attribute (#18253) --- .../.FSharp.Compiler.Service/9.0.300.md | 1 + src/Compiler/Checking/AttributeChecking.fs | 118 ++++++++------- src/Compiler/Checking/AttributeChecking.fsi | 7 - src/Compiler/Checking/PostInferenceChecks.fs | 2 +- src/Compiler/Driver/CompilerDiagnostics.fs | 23 ++- src/Compiler/FSStrings.resx | 10 +- src/Compiler/Facilities/DiagnosticsLogger.fs | 10 +- src/Compiler/Facilities/DiagnosticsLogger.fsi | 9 +- src/Compiler/Symbols/FSharpDiagnostic.fs | 20 ++- src/Compiler/Symbols/FSharpDiagnostic.fsi | 15 +- src/Compiler/TypedTree/TcGlobals.fs | 1 + src/Compiler/TypedTree/TcGlobals.fsi | 2 + src/Compiler/xlf/FSStrings.cs.xlf | 20 ++- src/Compiler/xlf/FSStrings.de.xlf | 20 ++- src/Compiler/xlf/FSStrings.es.xlf | 20 ++- src/Compiler/xlf/FSStrings.fr.xlf | 20 ++- src/Compiler/xlf/FSStrings.it.xlf | 20 ++- src/Compiler/xlf/FSStrings.ja.xlf | 20 ++- src/Compiler/xlf/FSStrings.ko.xlf | 20 ++- src/Compiler/xlf/FSStrings.pl.xlf | 20 ++- src/Compiler/xlf/FSStrings.pt-BR.xlf | 20 ++- src/Compiler/xlf/FSStrings.ru.xlf | 20 ++- src/Compiler/xlf/FSStrings.tr.xlf | 20 ++- src/Compiler/xlf/FSStrings.zh-Hans.xlf | 20 ++- src/Compiler/xlf/FSStrings.zh-Hant.xlf | 20 ++- .../ExtendedDiagnosticDataTests.fs | 139 ++++++++++++++---- .../FSharp.Compiler.ComponentTests.fsproj | 1 + .../ExperimentalAttributeCheckingTests.fs | 124 ++++++++++++++++ ...ervice.SurfaceArea.netstandard20.debug.bsl | 13 +- ...vice.SurfaceArea.netstandard20.release.bsl | 14 +- .../Warnings/ExperimentalAttributeTests.fs | 33 ----- tests/fsharp/FSharpSuite.Tests.fsproj | 1 - tests/fsharp/typecheck/sigs/neg91.bsl | 2 +- 33 files changed, 594 insertions(+), 211 deletions(-) mode change 100644 => 100755 tests/FSharp.Compiler.ComponentTests/ErrorMessages/ExtendedDiagnosticDataTests.fs create mode 100755 tests/FSharp.Compiler.ComponentTests/Language/ExperimentalAttributeCheckingTests.fs mode change 100644 => 100755 tests/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.SurfaceArea.netstandard20.debug.bsl mode change 100644 => 100755 tests/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.SurfaceArea.netstandard20.release.bsl delete mode 100644 tests/fsharp/Compiler/Warnings/ExperimentalAttributeTests.fs diff --git a/docs/release-notes/.FSharp.Compiler.Service/9.0.300.md b/docs/release-notes/.FSharp.Compiler.Service/9.0.300.md index 8343f04bd6a..bcff9ba132d 100644 --- a/docs/release-notes/.FSharp.Compiler.Service/9.0.300.md +++ b/docs/release-notes/.FSharp.Compiler.Service/9.0.300.md @@ -12,6 +12,7 @@ ### Added * Added missing type constraints in FCS. ([PR #18241](https://github.com/dotnet/fsharp/pull/18241)) * The 'use' keyword can be used on IDisposable|null without nullness warnings ([PR #18262](https://github.com/dotnet/fsharp/pull/18262)) +* Add support for C# `Experimental` attribute. ([PR #18253](https://github.com/dotnet/fsharp/pull/18253)) * Nullness warnings are issued for signature<>implementation conformance ([PR #18186](https://github.com/dotnet/fsharp/pull/18186)) * Symbols: Add FSharpAssembly.IsFSharp ([PR #18290](https://github.com/dotnet/fsharp/pull/18290)) diff --git a/src/Compiler/Checking/AttributeChecking.fs b/src/Compiler/Checking/AttributeChecking.fs index 8c317ad5f31..6e6cef5461b 100755 --- a/src/Compiler/Checking/AttributeChecking.fs +++ b/src/Compiler/Checking/AttributeChecking.fs @@ -24,13 +24,6 @@ open FSharp.Compiler.TypeProviders open FSharp.Core.CompilerServices #endif -exception ObsoleteDiagnostic of - isError: bool * - diagnosticId: string * - message: string * - urlFormat: string * - range: range - let fail() = failwith "This custom attribute has an argument that cannot yet be converted using this API" let rec private evalILAttribElem elem = @@ -247,44 +240,68 @@ let private CheckCompilerFeatureRequiredAttribute (g: TcGlobals) cattrs msg m = | Some([ILAttribElem.String (Some featureName) ], _) when featureName = "RequiredMembers" -> CompleteD | _ -> - ErrorD (ObsoleteDiagnostic(true, "", msg, "", m)) + ErrorD (ObsoleteDiagnostic(true, None, msg, None, m)) + +let private extractILAttribValueFrom name namedArgs = + match namedArgs with + | ExtractILAttributeNamedArg name (AttribElemStringArg v) -> Some v + | _ -> None -let private extractILObsoleteAttributeInfo namedArgs = - let extractILAttribValueFrom name namedArgs = - match namedArgs with - | ExtractILAttributeNamedArg name (AttribElemStringArg v) -> v - | _ -> "" +let private extractILAttributeInfo namedArgs = let diagnosticId = extractILAttribValueFrom "DiagnosticId" namedArgs let urlFormat = extractILAttribValueFrom "UrlFormat" namedArgs (diagnosticId, urlFormat) +let private CheckILExperimentalAttributes (g: TcGlobals) cattrs m = + let (AttribInfo(tref,_)) = g.attrib_IlExperimentalAttribute + match TryDecodeILAttribute tref cattrs with + // [Experimental("DiagnosticId")] + // [Experimental(diagnosticId: "DiagnosticId")] + // [Experimental("DiagnosticId", UrlFormat = "UrlFormat")] + // [Experimental(diagnosticId = "DiagnosticId", UrlFormat = "UrlFormat")] + // Constructors deciding on DiagnosticId and UrlFormat properties. + | Some ([ attribElement ], namedArgs) -> + let diagnosticId = + match attribElement with + | ILAttribElem.String (Some msg) -> Some msg + | ILAttribElem.String None + | _ -> None + + let message = extractILAttribValueFrom "Message" namedArgs + let urlFormat = extractILAttribValueFrom "UrlFormat" namedArgs + + WarnD(Experimental(message, diagnosticId, urlFormat, m)) + // Empty constructor or only UrlFormat property are not allowed. + | Some _ + | None -> CompleteD + let private CheckILObsoleteAttributes (g: TcGlobals) isByrefLikeTyconRef cattrs m = if isByrefLikeTyconRef then CompleteD else let (AttribInfo(tref,_)) = g.attrib_SystemObsolete match TryDecodeILAttribute tref cattrs with - // [] - // [] - // [] - // [] - // [] - // [] - // [] - // [] - // [] + // [Obsolete] + // [Obsolete("Message")] + // [Obsolete("Message", true)] + // [Obsolete("Message", DiagnosticId = "DiagnosticId")] + // [Obsolete("Message", DiagnosticId = "DiagnosticId", UrlFormat = "UrlFormat")] + // [Obsolete(DiagnosticId = "DiagnosticId")] + // [Obsolete(DiagnosticId = "DiagnosticId", UrlFormat = "UrlFormat")] + // [Obsolete("Message", true, DiagnosticId = "DiagnosticId")] + // [Obsolete("Message", true, DiagnosticId = "DiagnosticId", UrlFormat = "UrlFormat")] // Constructors deciding on IsError and Message properties. | Some ([ attribElement ], namedArgs) -> - let diagnosticId, urlFormat = extractILObsoleteAttributeInfo namedArgs + let diagnosticId, urlFormat = extractILAttributeInfo namedArgs let msg = match attribElement with - | ILAttribElem.String (Some msg) -> msg + | ILAttribElem.String (Some msg) -> Some msg | ILAttribElem.String None - | _ -> "" + | _ -> None WarnD (ObsoleteDiagnostic(false, diagnosticId, msg, urlFormat, m)) - | Some ([ILAttribElem.String (Some msg); ILAttribElem.Bool isError ], namedArgs) -> - let diagnosticId, urlFormat = extractILObsoleteAttributeInfo namedArgs + | Some ([ILAttribElem.String msg; ILAttribElem.Bool isError ], namedArgs) -> + let diagnosticId, urlFormat = extractILAttributeInfo namedArgs if isError then if g.langVersion.SupportsFeature(LanguageFeature.RequiredPropertiesSupport) then CheckCompilerFeatureRequiredAttribute g cattrs msg m @@ -294,24 +311,23 @@ let private CheckILObsoleteAttributes (g: TcGlobals) isByrefLikeTyconRef cattrs WarnD (ObsoleteDiagnostic(false, diagnosticId, msg, urlFormat, m)) // Only DiagnosticId, UrlFormat | Some (_, namedArgs) -> - let diagnosticId, urlFormat = extractILObsoleteAttributeInfo namedArgs - WarnD(ObsoleteDiagnostic(false, diagnosticId, "", urlFormat, m)) + let diagnosticId, urlFormat = extractILAttributeInfo namedArgs + WarnD(ObsoleteDiagnostic(false, diagnosticId, None, urlFormat, m)) // No arguments | None -> CompleteD -/// Check IL attributes for 'ObsoleteAttribute', returning errors and warnings as data +/// Check IL attributes for Experimental, warnings as data let private CheckILAttributes (g: TcGlobals) isByrefLikeTyconRef cattrs m = trackErrors { do! CheckILObsoleteAttributes g isByrefLikeTyconRef cattrs m + do! CheckILExperimentalAttributes g cattrs m } -let langVersionPrefix = "--langversion:preview" - let private extractObsoleteAttributeInfo namedArgs = let extractILAttribValueFrom name namedArgs = match namedArgs with - | ExtractAttribNamedArg name (AttribStringArg v) -> v - | _ -> "" + | ExtractAttribNamedArg name (AttribStringArg v) -> Some v + | _ -> None let diagnosticId = extractILAttribValueFrom "DiagnosticId" namedArgs let urlFormat = extractILAttribValueFrom "UrlFormat" namedArgs (diagnosticId, urlFormat) @@ -331,17 +347,17 @@ let private CheckObsoleteAttributes g attribs m = // Constructors deciding on IsError and Message properties. | Some(Attrib(unnamedArgs= [ AttribStringArg s ]; propVal= namedArgs)) -> let diagnosticId, urlFormat = extractObsoleteAttributeInfo namedArgs - do! WarnD(ObsoleteDiagnostic(false, diagnosticId, s, urlFormat, m)) + do! WarnD(ObsoleteDiagnostic(false, diagnosticId, Some s, urlFormat, m)) | Some(Attrib(unnamedArgs= [ AttribStringArg s; AttribBoolArg(isError) ]; propVal= namedArgs)) -> let diagnosticId, urlFormat = extractObsoleteAttributeInfo namedArgs if isError then - do! ErrorD (ObsoleteDiagnostic(true, diagnosticId, s, urlFormat, m)) + do! ErrorD (ObsoleteDiagnostic(true, diagnosticId, Some s, urlFormat, m)) else - do! WarnD (ObsoleteDiagnostic(false, diagnosticId, s, urlFormat, m)) + do! WarnD (ObsoleteDiagnostic(false, diagnosticId, Some s, urlFormat, m)) // Only DiagnosticId, UrlFormat | Some(Attrib(propVal= namedArgs)) -> let diagnosticId, urlFormat = extractObsoleteAttributeInfo namedArgs - do! WarnD(ObsoleteDiagnostic(false, diagnosticId, "", urlFormat, m)) + do! WarnD(ObsoleteDiagnostic(false, diagnosticId, None, urlFormat, m)) | None -> () } @@ -366,21 +382,21 @@ let private CheckCompilerMessageAttribute g attribs m = () } -let private CheckExperimentalAttribute g attribs m = +let private CheckFSharpExperimentalAttribute g attribs m = trackErrors { match TryFindFSharpAttribute g g.attrib_ExperimentalAttribute attribs with + // [] | Some(Attrib(unnamedArgs= [ AttribStringArg(s) ])) -> let isExperimentalAttributeDisabled (s:string) = if g.compilingFSharpCore then true else - g.langVersion.IsPreviewEnabled && (s.IndexOf(langVersionPrefix, StringComparison.OrdinalIgnoreCase) >= 0) + g.langVersion.IsPreviewEnabled && (s.IndexOf("--langversion:preview", StringComparison.OrdinalIgnoreCase) >= 0) if not (isExperimentalAttributeDisabled s) then - do! WarnD(Experimental(s, m)) - | Some _ -> - do! WarnD(Experimental(FSComp.SR.experimentalConstruct (), m)) - | _ -> - () + do! WarnD(Experimental(Some s, None, None, m)) + // Empty constructor is not allowed. + | Some _ + | _ -> () } let private CheckUnverifiableAttribute g attribs m = @@ -399,7 +415,7 @@ let CheckFSharpAttributes (g:TcGlobals) attribs m = trackErrors { do! CheckObsoleteAttributes g attribs m do! CheckCompilerMessageAttribute g attribs m - do! CheckExperimentalAttribute g attribs m + do! CheckFSharpExperimentalAttribute g attribs m do! CheckUnverifiableAttribute g attribs m } @@ -408,16 +424,16 @@ let CheckFSharpAttributes (g:TcGlobals) attribs m = let private CheckProvidedAttributes (g: TcGlobals) m (provAttribs: Tainted) = let (AttribInfo(tref, _)) = g.attrib_SystemObsolete match provAttribs.PUntaint((fun a -> a.GetAttributeConstructorArgs(provAttribs.TypeProvider.PUntaintNoFailure(id), tref.FullName)), m) with - | Some ([ Some (:? string as msg) ], _) -> WarnD(ObsoleteDiagnostic(false, "", msg, "", m)) + | Some ([ Some (:? string as msg) ], _) -> WarnD(ObsoleteDiagnostic(false, None, Some msg, None, m)) | Some ([ Some (:? string as msg); Some (:?bool as isError) ], _) -> if isError then - ErrorD (ObsoleteDiagnostic(true, "", msg, "", m)) + ErrorD (ObsoleteDiagnostic(true, None, Some msg, None, m)) else - WarnD (ObsoleteDiagnostic(false, "", msg, "", m)) + WarnD (ObsoleteDiagnostic(false, None, Some msg, None, m)) | Some ([ None ], _) -> - WarnD(ObsoleteDiagnostic(false, "", "", "", m)) + WarnD(ObsoleteDiagnostic(false, None, None, None, m)) | Some _ -> - WarnD(ObsoleteDiagnostic(false, "", "", "", m)) + WarnD(ObsoleteDiagnostic(false, None, None, None, m)) | None -> CompleteD #endif diff --git a/src/Compiler/Checking/AttributeChecking.fsi b/src/Compiler/Checking/AttributeChecking.fsi index 143763f889c..b23681702da 100644 --- a/src/Compiler/Checking/AttributeChecking.fsi +++ b/src/Compiler/Checking/AttributeChecking.fsi @@ -13,13 +13,6 @@ open FSharp.Compiler.TcGlobals open FSharp.Compiler.Text open FSharp.Compiler.TypedTree -exception ObsoleteDiagnostic of - isError: bool * - diagnosticId: string * - message: string * - urlFormat: string * - range: range - type AttribInfo = | FSAttribInfo of TcGlobals * Attrib | ILAttribInfo of TcGlobals * Import.ImportMap * ILScopeRef * ILAttribute * range diff --git a/src/Compiler/Checking/PostInferenceChecks.fs b/src/Compiler/Checking/PostInferenceChecks.fs index e8d6f5a5af0..3a4fe0e65ed 100644 --- a/src/Compiler/Checking/PostInferenceChecks.fs +++ b/src/Compiler/Checking/PostInferenceChecks.fs @@ -551,7 +551,7 @@ let WarnOnWrongTypeForAccess (cenv: cenv) env objName valAcc m ty = if isLessAccessible tyconAcc valAcc then let errorText = FSComp.SR.chkTypeLessAccessibleThanType(tcref.DisplayName, (objName())) |> snd let warningText = errorText + Environment.NewLine + FSComp.SR.tcTypeAbbreviationsCheckedAtCompileTime() - warning(AttributeChecking.ObsoleteDiagnostic(false, "", warningText, "", m)) + warning(ObsoleteDiagnostic(false, None, Some warningText, None, m)) CheckTypeDeep cenv (visitType, None, None, None, None) cenv.g env NoInfo ty diff --git a/src/Compiler/Driver/CompilerDiagnostics.fs b/src/Compiler/Driver/CompilerDiagnostics.fs index 289d993e96e..7124c5ce1ac 100644 --- a/src/Compiler/Driver/CompilerDiagnostics.fs +++ b/src/Compiler/Driver/CompilerDiagnostics.fs @@ -14,7 +14,6 @@ open Internal.Utilities.Library open Internal.Utilities.Text open FSharp.Compiler -open FSharp.Compiler.AttributeChecking open FSharp.Compiler.CheckExpressions open FSharp.Compiler.CheckDeclarations open FSharp.Compiler.CheckIncrementalClasses @@ -149,7 +148,7 @@ type Exception with | ValueRestriction(_, _, _, _, m) | LetRecUnsound(_, _, m) | ObsoleteDiagnostic(_, _, _, _, m) - | Experimental(_, m) + | Experimental(range = m) | PossibleUnverifiableCode m | UserCompilerMessage(_, _, m) | Deprecated(_, m) @@ -568,7 +567,9 @@ module OldStyleMessages = let ValNotLocalE () = Message("ValNotLocal", "") let Obsolete1E () = Message("Obsolete1", "") let Obsolete2E () = Message("Obsolete2", "%s") - let ExperimentalE () = Message("Experimental", "%s") + let Experimental1E () = Message("Experimental1", "") + let Experimental2E () = Message("Experimental2", "%s") + let Experimental3E () = Message("Experimental3", "") let PossibleUnverifiableCodeE () = Message("PossibleUnverifiableCode", "") let DeprecatedE () = Message("Deprecated", "%s") let LibraryUseOnlyE () = Message("LibraryUseOnly", "") @@ -1791,13 +1792,21 @@ type Exception with | ValNotLocal _ -> os.AppendString(ValNotLocalE().Format) - | ObsoleteDiagnostic(message = s) -> + | ObsoleteDiagnostic(message = message) -> os.AppendString(Obsolete1E().Format) - if s <> "" then - os.AppendString(Obsolete2E().Format s) + match message with + | Some message when message <> "" -> os.AppendString(Obsolete2E().Format message) + | _ -> () + + | Experimental(message = message) -> + os.AppendString(Experimental1E().Format) + + match message with + | Some message when message <> "" -> os.AppendString(Experimental2E().Format message) + | _ -> () - | Experimental(s, _) -> os.AppendString(ExperimentalE().Format s) + os.AppendString(Experimental3E().Format) | PossibleUnverifiableCode _ -> os.AppendString(PossibleUnverifiableCodeE().Format) diff --git a/src/Compiler/FSStrings.resx b/src/Compiler/FSStrings.resx index e9338b6b990..abb2bb57f55 100644 --- a/src/Compiler/FSStrings.resx +++ b/src/Compiler/FSStrings.resx @@ -1029,8 +1029,14 @@ . {0} - - {0}. This warning can be disabled using '--nowarn:57' or '#nowarn "57"'. + + This construct is experimental + + + . {0} + + + . This warning can be disabled using '--nowarn:57' or '#nowarn "57"'. Uses of this construct may result in the generation of unverifiable .NET IL code. This warning can be disabled using '--nowarn:9' or '#nowarn "9"'. diff --git a/src/Compiler/Facilities/DiagnosticsLogger.fs b/src/Compiler/Facilities/DiagnosticsLogger.fs index cf5c20fe84c..04cb35a2e8e 100644 --- a/src/Compiler/Facilities/DiagnosticsLogger.fs +++ b/src/Compiler/Facilities/DiagnosticsLogger.fs @@ -108,7 +108,7 @@ exception LibraryUseOnly of range: range exception Deprecated of message: string * range: range -exception Experimental of message: string * range: range +exception Experimental of message: string option * diagnosticId: string option * urlFormat: string option * range: range exception PossibleUnverifiableCode of range: range @@ -133,6 +133,14 @@ exception DiagnosticWithSuggestions of number: int * message: string * range: ra /// A diagnostic that is raised when enabled manually, or by default with a language feature exception DiagnosticEnabledWithLanguageFeature of number: int * message: string * range: range * enabledByLangFeature: bool +/// A diagnostic that is raised when a diagnostic is obsolete +exception ObsoleteDiagnostic of + isError: bool * + diagnosticId: string option * + message: string option * + urlFormat: string option * + range: range + /// The F# compiler code currently uses 'Error(...)' in many places to create /// an DiagnosticWithText as an exception even if it's a warning. /// diff --git a/src/Compiler/Facilities/DiagnosticsLogger.fsi b/src/Compiler/Facilities/DiagnosticsLogger.fsi index da7a6a66ca8..02471dd383b 100644 --- a/src/Compiler/Facilities/DiagnosticsLogger.fsi +++ b/src/Compiler/Facilities/DiagnosticsLogger.fsi @@ -68,7 +68,7 @@ exception LibraryUseOnly of range: range exception Deprecated of message: string * range: range -exception Experimental of message: string * range: range +exception Experimental of message: string option * diagnosticId: string option * urlFormat: string option * range: range exception PossibleUnverifiableCode of range: range @@ -87,6 +87,13 @@ exception DiagnosticWithSuggestions of identifier: string * suggestions: Suggestions +exception ObsoleteDiagnostic of + isError: bool * + diagnosticId: string option * + message: string option * + urlFormat: string option * + range: range + /// Creates a DiagnosticWithSuggestions whose text comes via SR.* val ErrorWithSuggestions: (int * string) * range * string * Suggestions -> exn diff --git a/src/Compiler/Symbols/FSharpDiagnostic.fs b/src/Compiler/Symbols/FSharpDiagnostic.fs index 66e077fba9c..da542902600 100644 --- a/src/Compiler/Symbols/FSharpDiagnostic.fs +++ b/src/Compiler/Symbols/FSharpDiagnostic.fs @@ -70,14 +70,25 @@ module ExtendedData = /// Additional data for diagnostics about obsolete attributes. [] type ObsoleteDiagnosticExtendedData - internal (diagnosticId: string, urlFormat: string) = + internal (diagnosticId: string option, urlFormat: string option) = interface IFSharpDiagnosticExtendedData /// Represents the DiagnosticId of the diagnostic - member this.DiagnosticId: string = diagnosticId + member this.DiagnosticId: string option = diagnosticId /// Represents the URL format of the diagnostic - member this.UrlFormat: string = urlFormat + member this.UrlFormat: string option = urlFormat + /// Additional data for diagnostics about experimental attributes. + [] + type ExperimentalExtendedData + internal (diagnosticId: string option, urlFormat: string option) = + interface IFSharpDiagnosticExtendedData + /// Represents the DiagnosticId of the diagnostic + member this.DiagnosticId: string option = diagnosticId + + /// Represents the URL format of the diagnostic + member this.UrlFormat: string option = urlFormat + [] type TypeMismatchDiagnosticExtendedData internal (symbolEnv: SymbolEnv, dispEnv: DisplayEnv, expectedType: TType, actualType: TType, context: DiagnosticContextInfo) = @@ -214,6 +225,9 @@ type FSharpDiagnostic(m: range, severity: FSharpDiagnosticSeverity, message: str | ObsoleteDiagnostic(diagnosticId= diagnosticId; urlFormat= urlFormat) -> Some(ObsoleteDiagnosticExtendedData(diagnosticId, urlFormat)) + + | Experimental(diagnosticId= diagnosticId; urlFormat= urlFormat) -> + Some(ExperimentalExtendedData(diagnosticId, urlFormat)) | _ -> None let msg = diff --git a/src/Compiler/Symbols/FSharpDiagnostic.fsi b/src/Compiler/Symbols/FSharpDiagnostic.fsi index ecee4c0540b..8c79ee95232 100644 --- a/src/Compiler/Symbols/FSharpDiagnostic.fsi +++ b/src/Compiler/Symbols/FSharpDiagnostic.fsi @@ -56,10 +56,21 @@ module public ExtendedData = interface IFSharpDiagnosticExtendedData /// Represents the DiagnosticId of the diagnostic - member DiagnosticId: string + member DiagnosticId: string option /// Represents the URL format of the diagnostic - member UrlFormat: string + member UrlFormat: string option + + /// Additional data for diagnostics about experimental attributes. + [] + type public ExperimentalExtendedData = + interface IFSharpDiagnosticExtendedData + + /// Represents the DiagnosticId of the diagnostic + member DiagnosticId: string option + + /// Represents the URL format of the diagnostic + member UrlFormat: string option /// Additional data for type-mismatch-like (usually with ErrorNumber = 1) diagnostics [] diff --git a/src/Compiler/TypedTree/TcGlobals.fs b/src/Compiler/TypedTree/TcGlobals.fs index d8b95566717..93dd8905553 100644 --- a/src/Compiler/TypedTree/TcGlobals.fs +++ b/src/Compiler/TypedTree/TcGlobals.fs @@ -1562,6 +1562,7 @@ type TcGlobals( member val attrib_CompilerFeatureRequiredAttribute = findSysAttrib "System.Runtime.CompilerServices.CompilerFeatureRequiredAttribute" member val attrib_SetsRequiredMembersAttribute = findSysAttrib "System.Diagnostics.CodeAnalysis.SetsRequiredMembersAttribute" member val attrib_RequiredMemberAttribute = findSysAttrib "System.Runtime.CompilerServices.RequiredMemberAttribute" + member val attrib_IlExperimentalAttribute = findSysAttrib "System.Diagnostics.CodeAnalysis.ExperimentalAttribute" member g.improveType tcref tinst = improveTy tcref tinst diff --git a/src/Compiler/TypedTree/TcGlobals.fsi b/src/Compiler/TypedTree/TcGlobals.fsi index 772bc6b96d7..b172536d4f0 100644 --- a/src/Compiler/TypedTree/TcGlobals.fsi +++ b/src/Compiler/TypedTree/TcGlobals.fsi @@ -506,6 +506,8 @@ type internal TcGlobals = member attrib_WarnOnWithoutNullArgumentAttribute: BuiltinAttribInfo + member attrib_IlExperimentalAttribute: BuiltinAttribInfo + member attribs_Unsupported: FSharp.Compiler.TypedTree.TyconRef list member bitwise_and_info: IntrinsicValRef diff --git a/src/Compiler/xlf/FSStrings.cs.xlf b/src/Compiler/xlf/FSStrings.cs.xlf index 20991832c18..698e7180ad6 100644 --- a/src/Compiler/xlf/FSStrings.cs.xlf +++ b/src/Compiler/xlf/FSStrings.cs.xlf @@ -37,6 +37,21 @@ Neshoda typů Očekává se řazená kolekce členů o délce {0} typu\n {1} \nale odevzdala se řazená kolekce členů o délce {2} typu\n {3}{4}\n + + This construct is experimental + This construct is experimental + + + + . {0} + . {0} + + + + . This warning can be disabled using '--nowarn:57' or '#nowarn "57"'. + . This warning can be disabled using '--nowarn:57' or '#nowarn "57"'. + + One or more informational messages in loaded file.\n Nejméně jedna informační zpráva v načteném souboru\n @@ -1547,11 +1562,6 @@ . {0} - - {0}. This warning can be disabled using '--nowarn:57' or '#nowarn "57"'. - {0}. Toto upozornění se dá pomocí --nowarn:57 nebo #nowarn "57" vypnout. - - Uses of this construct may result in the generation of unverifiable .NET IL code. This warning can be disabled using '--nowarn:9' or '#nowarn "9"'. Použití tohoto konstruktoru může způsobit vygenerování neověřitelného kódu .NET IL. Toto upozornění se dá pomocí --nowarn:9 nebo #nowarn "9" vypnout. diff --git a/src/Compiler/xlf/FSStrings.de.xlf b/src/Compiler/xlf/FSStrings.de.xlf index b429cdd522c..ebfb525eb2a 100644 --- a/src/Compiler/xlf/FSStrings.de.xlf +++ b/src/Compiler/xlf/FSStrings.de.xlf @@ -37,6 +37,21 @@ Typenkonflikt. Es wurde ein Tupel der Länge {0} des Typs\n {1} \nerwartet, aber ein Tupel der Länge {2} des Typs\n {3}{4}\n angegeben. + + This construct is experimental + This construct is experimental + + + + . {0} + . {0} + + + + . This warning can be disabled using '--nowarn:57' or '#nowarn "57"'. + . This warning can be disabled using '--nowarn:57' or '#nowarn "57"'. + + One or more informational messages in loaded file.\n Mindestens eine Informationsmeldung in der geladenen Datei.\n @@ -1547,11 +1562,6 @@ . {0} - - {0}. This warning can be disabled using '--nowarn:57' or '#nowarn "57"'. - {0}. Diese Warnung kann mit "--nowarn 57" oder "#nowarn "57"" deaktiviert werden. - - Uses of this construct may result in the generation of unverifiable .NET IL code. This warning can be disabled using '--nowarn:9' or '#nowarn "9"'. Die Verwendung dieses Konstrukts kann die Erzeugung von nicht verifizierbarem .NET-IL-Code zur Folge haben. Diese Warnung kann mit "--nowarn 9" oder "#nowarn "9"" deaktiviert werden. diff --git a/src/Compiler/xlf/FSStrings.es.xlf b/src/Compiler/xlf/FSStrings.es.xlf index 6620ac895f8..46816a23aba 100644 --- a/src/Compiler/xlf/FSStrings.es.xlf +++ b/src/Compiler/xlf/FSStrings.es.xlf @@ -37,6 +37,21 @@ Error de coincidencia de tipos. Se espera una tupla de longitud {0} de tipo\n {1} \nperero se ha proporcionado una tupla de longitud {2} de tipo\n {3}{4}\n + + This construct is experimental + This construct is experimental + + + + . {0} + . {0} + + + + . This warning can be disabled using '--nowarn:57' or '#nowarn "57"'. + . This warning can be disabled using '--nowarn:57' or '#nowarn "57"'. + + One or more informational messages in loaded file.\n Uno o más mensajes informativos en el archivo cargado.\n @@ -1547,11 +1562,6 @@ . {0} - - {0}. This warning can be disabled using '--nowarn:57' or '#nowarn "57"'. - {0}. Esta advertencia se puede deshabilitar con '--nowarn:57' o '#nowarn "57"'. - - Uses of this construct may result in the generation of unverifiable .NET IL code. This warning can be disabled using '--nowarn:9' or '#nowarn "9"'. El uso de esta construcción puede dar lugar a que se genere código .NET de IL que no se puede comprobar. Esta advertencia se puede deshabilitar con '--nowarn:9' o '#nowarn "9"'. diff --git a/src/Compiler/xlf/FSStrings.fr.xlf b/src/Compiler/xlf/FSStrings.fr.xlf index ac459e73f5b..7e8f9df4ee3 100644 --- a/src/Compiler/xlf/FSStrings.fr.xlf +++ b/src/Compiler/xlf/FSStrings.fr.xlf @@ -37,6 +37,21 @@ Incompatibilité de type. Tuple de longueur attendu {0} de type\n {1} \nmais tuple de longueur {2} de type\n {3}{4}\n + + This construct is experimental + This construct is experimental + + + + . {0} + . {0} + + + + . This warning can be disabled using '--nowarn:57' or '#nowarn "57"'. + . This warning can be disabled using '--nowarn:57' or '#nowarn "57"'. + + One or more informational messages in loaded file.\n Un ou plusieurs messages d’information dans le fichier chargé.\n @@ -1547,11 +1562,6 @@ . {0} - - {0}. This warning can be disabled using '--nowarn:57' or '#nowarn "57"'. - {0}. Cet avertissement peut être désactivé à l'aide de '--nowarn:57' ou '#nowarn "57"'. - - Uses of this construct may result in the generation of unverifiable .NET IL code. This warning can be disabled using '--nowarn:9' or '#nowarn "9"'. Les utilisations de cette construction peuvent entraîner la génération de code IL (Intermediate Language) .NET non vérifiable. Cet avertissement peut être désactivé à l'aide de '--nowarn:9' ou '#nowarn "9"'. diff --git a/src/Compiler/xlf/FSStrings.it.xlf b/src/Compiler/xlf/FSStrings.it.xlf index 1f1ad15e05f..004e8d04e13 100644 --- a/src/Compiler/xlf/FSStrings.it.xlf +++ b/src/Compiler/xlf/FSStrings.it.xlf @@ -37,6 +37,21 @@ Tipo non corrispondente. È prevista una tupla di lunghezza {0} di tipo\n {1} \n, ma è stata specificata una tupla di lunghezza {2} di tipo\n {3}{4}\n + + This construct is experimental + This construct is experimental + + + + . {0} + . {0} + + + + . This warning can be disabled using '--nowarn:57' or '#nowarn "57"'. + . This warning can be disabled using '--nowarn:57' or '#nowarn "57"'. + + One or more informational messages in loaded file.\n Uno o più messaggi informativi nel file caricato.\n @@ -1547,11 +1562,6 @@ . {0} - - {0}. This warning can be disabled using '--nowarn:57' or '#nowarn "57"'. - {0}. Questo avviso può essere disabilitato mediante '--nowarn:57' o '#nowarn "57"'. - - Uses of this construct may result in the generation of unverifiable .NET IL code. This warning can be disabled using '--nowarn:9' or '#nowarn "9"'. Gli utilizzi di questo costruttore potrebbero determinare la generazione di codice IL .NET non verificabile. Questo avviso può essere disabilitato mediante '--nowarn:9' o '#nowarn "9"'. diff --git a/src/Compiler/xlf/FSStrings.ja.xlf b/src/Compiler/xlf/FSStrings.ja.xlf index 59d40979899..b7e4a21e670 100644 --- a/src/Compiler/xlf/FSStrings.ja.xlf +++ b/src/Compiler/xlf/FSStrings.ja.xlf @@ -37,6 +37,21 @@ 型が一致しません。型の長さ {0} のタプルが必要です\n {1} \nただし、型の長さ {2} のタプルが指定された場合\n {3}{4}\n + + This construct is experimental + This construct is experimental + + + + . {0} + . {0} + + + + . This warning can be disabled using '--nowarn:57' or '#nowarn "57"'. + . This warning can be disabled using '--nowarn:57' or '#nowarn "57"'. + + One or more informational messages in loaded file.\n 読み込まれたファイル内の 1 つ以上の情報メッセージ。\n @@ -1547,11 +1562,6 @@ 。{0} - - {0}. This warning can be disabled using '--nowarn:57' or '#nowarn "57"'. - {0}。この警告を無効にするには、'--nowarn:57' または '#nowarn "57"' を使用します。 - - Uses of this construct may result in the generation of unverifiable .NET IL code. This warning can be disabled using '--nowarn:9' or '#nowarn "9"'. このコンストラクトを使用すると、検証できない .NET IL コードが生成される可能性があります。この警告を無効にするには、'--nowarn:9' または '#nowarn "9"' を使用してください。 diff --git a/src/Compiler/xlf/FSStrings.ko.xlf b/src/Compiler/xlf/FSStrings.ko.xlf index 8ed60cc681f..edee12a29a2 100644 --- a/src/Compiler/xlf/FSStrings.ko.xlf +++ b/src/Compiler/xlf/FSStrings.ko.xlf @@ -37,6 +37,21 @@ 유형 불일치. 형식이 \n {1}이고 길이가 {0}인 튜플이 필요합니다. \n그러나 형식이 \n {3}이고 길이가 {2}인 튜플이 제공되었습니다.{4}\n + + This construct is experimental + This construct is experimental + + + + . {0} + . {0} + + + + . This warning can be disabled using '--nowarn:57' or '#nowarn "57"'. + . This warning can be disabled using '--nowarn:57' or '#nowarn "57"'. + + One or more informational messages in loaded file.\n 로드된 파일에 하나 이상의 정보 메시지가 있습니다.\n @@ -1547,11 +1562,6 @@ . {0} - - {0}. This warning can be disabled using '--nowarn:57' or '#nowarn "57"'. - {0}. 이 경고는 '--nowarn:57' 또는 '#nowarn "57"'을 통해 사용할 수 없도록 설정할 수 있습니다. - - Uses of this construct may result in the generation of unverifiable .NET IL code. This warning can be disabled using '--nowarn:9' or '#nowarn "9"'. 이 구문을 사용하면 확인할 수 없는 .NET IL 코드가 생성될 수 있습니다. 이 경고는 '--nowarn:9' 또는 '#nowarn "9"'를 통해 사용할 수 없도록 설정할 수 있습니다. diff --git a/src/Compiler/xlf/FSStrings.pl.xlf b/src/Compiler/xlf/FSStrings.pl.xlf index c5f8bbc016b..b50fb8fc188 100644 --- a/src/Compiler/xlf/FSStrings.pl.xlf +++ b/src/Compiler/xlf/FSStrings.pl.xlf @@ -37,6 +37,21 @@ Niezgodność. Oczekiwano krotki o długości {0} typu\n {1} \nale otrzymano krotkę o długości {2} typu\n {3}{4}\n + + This construct is experimental + This construct is experimental + + + + . {0} + . {0} + + + + . This warning can be disabled using '--nowarn:57' or '#nowarn "57"'. + . This warning can be disabled using '--nowarn:57' or '#nowarn "57"'. + + One or more informational messages in loaded file.\n Jeden lub więcej komunikatów informacyjnych w załadowanym pliku.\n @@ -1547,11 +1562,6 @@ . {0} - - {0}. This warning can be disabled using '--nowarn:57' or '#nowarn "57"'. - {0}. To ostrzeżenie można wyłączyć przy użyciu elementu „--nowarn:57” lub „#nowarn "57"”. - - Uses of this construct may result in the generation of unverifiable .NET IL code. This warning can be disabled using '--nowarn:9' or '#nowarn "9"'. Użycie tej konstrukcji może spowodować wygenerowanie kodu .NET IL, którego nie można zweryfikować. To ostrzeżenie można wyłączyć przy użyciu elementu „--nowarn:9” lub „#nowarn "9"”. diff --git a/src/Compiler/xlf/FSStrings.pt-BR.xlf b/src/Compiler/xlf/FSStrings.pt-BR.xlf index 991d77016c9..f94ce79cd97 100644 --- a/src/Compiler/xlf/FSStrings.pt-BR.xlf +++ b/src/Compiler/xlf/FSStrings.pt-BR.xlf @@ -37,6 +37,21 @@ Tipo incompatível. Esperando uma tupla de comprimento {0} do tipo\n {1} \nmas recebeu uma tupla de comprimento {2} do tipo\n {3}{4}\n + + This construct is experimental + This construct is experimental + + + + . {0} + . {0} + + + + . This warning can be disabled using '--nowarn:57' or '#nowarn "57"'. + . This warning can be disabled using '--nowarn:57' or '#nowarn "57"'. + + One or more informational messages in loaded file.\n Uma ou mais mensagens informativas no arquivo carregado.\n @@ -1547,11 +1562,6 @@ . {0} - - {0}. This warning can be disabled using '--nowarn:57' or '#nowarn "57"'. - {0}. Este aviso foi desabilitado com o uso de '--nowarn:57' ou '#nowarn "57"'. - - Uses of this construct may result in the generation of unverifiable .NET IL code. This warning can be disabled using '--nowarn:9' or '#nowarn "9"'. O uso desse construto pode resultar na geração de código .NET IL não verificável. Este aviso pode ser desabilitado usando '--nowarn:9' ou '#nowarn "9"'. diff --git a/src/Compiler/xlf/FSStrings.ru.xlf b/src/Compiler/xlf/FSStrings.ru.xlf index 2c4de5a755c..6df88d26d49 100644 --- a/src/Compiler/xlf/FSStrings.ru.xlf +++ b/src/Compiler/xlf/FSStrings.ru.xlf @@ -37,6 +37,21 @@ Несоответствие типов. Ожидается кортеж длиной {0} типа\n {1}, \nно предоставлен кортеж длиной {2} типа\n {3}{4}\n + + This construct is experimental + This construct is experimental + + + + . {0} + . {0} + + + + . This warning can be disabled using '--nowarn:57' or '#nowarn "57"'. + . This warning can be disabled using '--nowarn:57' or '#nowarn "57"'. + + One or more informational messages in loaded file.\n Одно или несколько информационных сообщений в загруженном файле.\n @@ -1547,11 +1562,6 @@ . {0} - - {0}. This warning can be disabled using '--nowarn:57' or '#nowarn "57"'. - {0}. Данное предупреждение можно отключить, используя --nowarn 57 или #nowarn "57". - - Uses of this construct may result in the generation of unverifiable .NET IL code. This warning can be disabled using '--nowarn:9' or '#nowarn "9"'. Использование данной конструкции может повлечь за собой создание непроверяемого кода .NET IL. Данное предупреждение можно отключить, используя --nowarn 9 или #nowarn "9". diff --git a/src/Compiler/xlf/FSStrings.tr.xlf b/src/Compiler/xlf/FSStrings.tr.xlf index 7b936093a0d..59fc6b69625 100644 --- a/src/Compiler/xlf/FSStrings.tr.xlf +++ b/src/Compiler/xlf/FSStrings.tr.xlf @@ -37,6 +37,21 @@ Tür uyuşmazlığı. {0} uzunluğunda türü\n {1} \nolan bir demet bekleniyordu ancak {2} uzunluğunda türü\n {3}{4}\nolan bir demet verildi + + This construct is experimental + This construct is experimental + + + + . {0} + . {0} + + + + . This warning can be disabled using '--nowarn:57' or '#nowarn "57"'. + . This warning can be disabled using '--nowarn:57' or '#nowarn "57"'. + + One or more informational messages in loaded file.\n Yüklenen dosyada bir veya daha fazla bilgi mesajı.\n @@ -1547,11 +1562,6 @@ . {0} - - {0}. This warning can be disabled using '--nowarn:57' or '#nowarn "57"'. - {0}. Bu uyarı, '--nowarn:57' veya '#nowarn "57"' kullanılarak devre dışı bırakılabilir. - - Uses of this construct may result in the generation of unverifiable .NET IL code. This warning can be disabled using '--nowarn:9' or '#nowarn "9"'. Bu yapının kullanılması doğrulanamayan .NET IL kodunun oluşturulmasıyla sonuçlanabilir. Bu uyarı, '--nowarn:9' veya '#nowarn "9"' kullanılarak devre dışı bırakılabilir. diff --git a/src/Compiler/xlf/FSStrings.zh-Hans.xlf b/src/Compiler/xlf/FSStrings.zh-Hans.xlf index 12afa253444..f97800458f1 100644 --- a/src/Compiler/xlf/FSStrings.zh-Hans.xlf +++ b/src/Compiler/xlf/FSStrings.zh-Hans.xlf @@ -37,6 +37,21 @@ 类型不匹配。应为长度为 {0} 的类型的元组\n {1} \n但提供了长度为 {2} 的类型的元组\n {3}{4}\n + + This construct is experimental + This construct is experimental + + + + . {0} + . {0} + + + + . This warning can be disabled using '--nowarn:57' or '#nowarn "57"'. + . This warning can be disabled using '--nowarn:57' or '#nowarn "57"'. + + One or more informational messages in loaded file.\n 加载文件 .\n 中有一条或多条信息性消息 @@ -1547,11 +1562,6 @@ 。{0} - - {0}. This warning can be disabled using '--nowarn:57' or '#nowarn "57"'. - {0}。可以使用“--nowarn:57”或“#nowarn "57"”禁用此警告。 - - Uses of this construct may result in the generation of unverifiable .NET IL code. This warning can be disabled using '--nowarn:9' or '#nowarn "9"'. 使用此构造可能会导致生成不可验证的 .NET IL 代码。可以使用“--nowarn:9”或“#nowarn "9"”禁用此警告。 diff --git a/src/Compiler/xlf/FSStrings.zh-Hant.xlf b/src/Compiler/xlf/FSStrings.zh-Hant.xlf index 8e52040ed6f..2f0181b62d6 100644 --- a/src/Compiler/xlf/FSStrings.zh-Hant.xlf +++ b/src/Compiler/xlf/FSStrings.zh-Hant.xlf @@ -37,6 +37,21 @@ 類型不符。必須是類型為\n {1} \n 的元組長度 {0},但提供的是類型為\n {3}{4}\n 的元組長度 {2} + + This construct is experimental + This construct is experimental + + + + . {0} + . {0} + + + + . This warning can be disabled using '--nowarn:57' or '#nowarn "57"'. + . This warning can be disabled using '--nowarn:57' or '#nowarn "57"'. + + One or more informational messages in loaded file.\n 已載入檔案中的一或多個資訊訊息。\n @@ -1547,11 +1562,6 @@ . {0} - - {0}. This warning can be disabled using '--nowarn:57' or '#nowarn "57"'. - {0}。使用 '--nowarn:57' 或 '#nowarn "57"' 可以停用這個警告。 - - Uses of this construct may result in the generation of unverifiable .NET IL code. This warning can be disabled using '--nowarn:9' or '#nowarn "9"'. 使用這個建構可能導致產生無法驗證的 .NET IL 程式碼。使用 '--nowarn:9' 或 '#nowarn "9"' 可以停用這個警告。 diff --git a/tests/FSharp.Compiler.ComponentTests/ErrorMessages/ExtendedDiagnosticDataTests.fs b/tests/FSharp.Compiler.ComponentTests/ErrorMessages/ExtendedDiagnosticDataTests.fs old mode 100644 new mode 100755 index 23e4a9b9440..1c6003de003 --- a/tests/FSharp.Compiler.ComponentTests/ErrorMessages/ExtendedDiagnosticDataTests.fs +++ b/tests/FSharp.Compiler.ComponentTests/ErrorMessages/ExtendedDiagnosticDataTests.fs @@ -256,8 +256,8 @@ let x = MyClass() |> checkDiagnostic (44, "This construct is deprecated. Message") (fun (obsoleteDiagnostic: ObsoleteDiagnosticExtendedData) -> - Assert.Equal("FS222", obsoleteDiagnostic.DiagnosticId) - Assert.Equal("https://example.com", obsoleteDiagnostic.UrlFormat)) + Assert.Equal(Some "FS222", obsoleteDiagnostic.DiagnosticId) + Assert.Equal(Some "https://example.com", obsoleteDiagnostic.UrlFormat)) [] let ``Warning - ObsoleteDiagnosticExtendedData 02`` () = @@ -272,8 +272,8 @@ let x = MyClass() |> checkDiagnostic (44, "This construct is deprecated. Message") (fun (obsoleteDiagnostic: ObsoleteDiagnosticExtendedData) -> - Assert.Equal("FS222", obsoleteDiagnostic.DiagnosticId) - Assert.Equal("", obsoleteDiagnostic.UrlFormat)) + Assert.Equal(Some "FS222", obsoleteDiagnostic.DiagnosticId) + Assert.Equal(None, obsoleteDiagnostic.UrlFormat)) [] let ``Warning - ObsoleteDiagnosticExtendedData 03`` () = @@ -288,8 +288,8 @@ let x = MyClass() |> checkDiagnostic (44, "This construct is deprecated. Message") (fun (obsoleteDiagnostic: ObsoleteDiagnosticExtendedData) -> - Assert.Equal("", obsoleteDiagnostic.DiagnosticId) - Assert.Equal("", obsoleteDiagnostic.UrlFormat)) + Assert.Equal(None, obsoleteDiagnostic.DiagnosticId) + Assert.Equal(None, obsoleteDiagnostic.UrlFormat)) [] let ``Warning - ObsoleteDiagnosticExtendedData 04`` () = @@ -304,8 +304,8 @@ let x = MyClass() |> checkDiagnostic (44, "This construct is deprecated") (fun (obsoleteDiagnostic: ObsoleteDiagnosticExtendedData) -> - Assert.Equal("FS222", obsoleteDiagnostic.DiagnosticId) - Assert.Equal("https://example.com", obsoleteDiagnostic.UrlFormat)) + Assert.Equal(Some "FS222", obsoleteDiagnostic.DiagnosticId) + Assert.Equal(Some "https://example.com", obsoleteDiagnostic.UrlFormat)) [] @@ -336,8 +336,8 @@ let text = Class1.Test(); |> checkDiagnostic (44, "This construct is deprecated. Use something else") (fun (obsoleteDiagnostic: ObsoleteDiagnosticExtendedData) -> - Assert.Equal("FS222", obsoleteDiagnostic.DiagnosticId) - Assert.Equal("", obsoleteDiagnostic.UrlFormat)) + Assert.Equal(Some "FS222", obsoleteDiagnostic.DiagnosticId) + Assert.Equal(None, obsoleteDiagnostic.UrlFormat)) [] let ``Warning - ObsoleteDiagnosticExtendedData 06`` () = @@ -367,8 +367,8 @@ let text = Class1.Test(); |> checkDiagnostic (44, "This construct is deprecated. Use something else") (fun (obsoleteDiagnostic: ObsoleteDiagnosticExtendedData) -> - Assert.Equal("FS222", obsoleteDiagnostic.DiagnosticId) - Assert.Equal("https://example.com", obsoleteDiagnostic.UrlFormat)) + Assert.Equal(Some "FS222", obsoleteDiagnostic.DiagnosticId) + Assert.Equal(Some "https://example.com", obsoleteDiagnostic.UrlFormat)) [] let ``Warning - ObsoleteDiagnosticExtendedData 07`` () = @@ -398,8 +398,8 @@ let text = Class1.Test(); |> checkDiagnostic (44, "This construct is deprecated. Use something else") (fun (obsoleteDiagnostic: ObsoleteDiagnosticExtendedData) -> - Assert.Equal("", obsoleteDiagnostic.DiagnosticId) - Assert.Equal("", obsoleteDiagnostic.UrlFormat)) + Assert.Equal(None, obsoleteDiagnostic.DiagnosticId) + Assert.Equal(None, obsoleteDiagnostic.UrlFormat)) [] let ``Warning - ObsoleteDiagnosticExtendedData 08`` () = @@ -429,8 +429,8 @@ let text = Class1.Test(); |> checkDiagnostic (44, "This construct is deprecated") (fun (obsoleteDiagnostic: ObsoleteDiagnosticExtendedData) -> - Assert.Equal("FS222", obsoleteDiagnostic.DiagnosticId) - Assert.Equal("https://example.com", obsoleteDiagnostic.UrlFormat)) + Assert.Equal(Some "FS222", obsoleteDiagnostic.DiagnosticId) + Assert.Equal(Some "https://example.com", obsoleteDiagnostic.UrlFormat)) [] let ``Warning - ObsoleteDiagnosticExtendedData 09`` () = @@ -445,8 +445,8 @@ let x = MyClass() |> checkDiagnostic (44, "This construct is deprecated") (fun (obsoleteDiagnostic: ObsoleteDiagnosticExtendedData) -> - Assert.Equal("", obsoleteDiagnostic.DiagnosticId) - Assert.Equal("", obsoleteDiagnostic.UrlFormat)) + Assert.Equal(None, obsoleteDiagnostic.DiagnosticId) + Assert.Equal(None, obsoleteDiagnostic.UrlFormat)) [] let ``Warning - ObsoleteDiagnosticExtendedData 10`` () = @@ -476,8 +476,8 @@ let text = Class1.Test(); |> checkDiagnostic (44, "This construct is deprecated") (fun (obsoleteDiagnostic: ObsoleteDiagnosticExtendedData) -> - Assert.Equal("", obsoleteDiagnostic.DiagnosticId) - Assert.Equal("", obsoleteDiagnostic.UrlFormat)) + Assert.Equal(None, obsoleteDiagnostic.DiagnosticId) + Assert.Equal(None, obsoleteDiagnostic.UrlFormat)) [] let ``Error - ObsoleteDiagnosticExtendedData 01`` () = @@ -492,8 +492,8 @@ let x = MyClass() |> checkDiagnostic (101, "This construct is deprecated. Message") (fun (obsoleteDiagnostic: ObsoleteDiagnosticExtendedData) -> - Assert.Equal("FS222", obsoleteDiagnostic.DiagnosticId) - Assert.Equal("https://example.com", obsoleteDiagnostic.UrlFormat)) + Assert.Equal(Some "FS222", obsoleteDiagnostic.DiagnosticId) + Assert.Equal(Some "https://example.com", obsoleteDiagnostic.UrlFormat)) [] let ``Error - ObsoleteDiagnosticExtendedData 02`` () = @@ -508,8 +508,8 @@ let x = MyClass() |> checkDiagnostic (101, "This construct is deprecated. Message") (fun (obsoleteDiagnostic: ObsoleteDiagnosticExtendedData) -> - Assert.Equal("FS222", obsoleteDiagnostic.DiagnosticId) - Assert.Equal("", obsoleteDiagnostic.UrlFormat)) + Assert.Equal(Some "FS222", obsoleteDiagnostic.DiagnosticId) + Assert.Equal(None, obsoleteDiagnostic.UrlFormat)) [] let ``Error - ObsoleteDiagnosticExtendedData 03`` () = @@ -524,8 +524,8 @@ let x = MyClass() |> checkDiagnostic (101, "This construct is deprecated. Message") (fun (obsoleteDiagnostic: ObsoleteDiagnosticExtendedData) -> - Assert.Equal("", obsoleteDiagnostic.DiagnosticId) - Assert.Equal("", obsoleteDiagnostic.UrlFormat)) + Assert.Equal(None, obsoleteDiagnostic.DiagnosticId) + Assert.Equal(None, obsoleteDiagnostic.UrlFormat)) [] let ``Error - ObsoleteDiagnosticExtendedData 04`` () = @@ -540,5 +540,88 @@ let x = MyClass() |> checkDiagnostic (101, "This construct is deprecated") (fun (obsoleteDiagnostic: ObsoleteDiagnosticExtendedData) -> - Assert.Equal("FS222", obsoleteDiagnostic.DiagnosticId) - Assert.Equal("https://example.com", obsoleteDiagnostic.UrlFormat)) \ No newline at end of file + Assert.Equal(Some "FS222", obsoleteDiagnostic.DiagnosticId) + Assert.Equal(Some "https://example.com", obsoleteDiagnostic.UrlFormat)) + +[] +let ``Warning - ExperimentalExtendedData 01`` () = + let CSLib = + CSharp """ +using System.Diagnostics.CodeAnalysis; + +[Experimental(diagnosticId: "FS222")] +public static class Class1 +{ + public static string Test() + { + return "Hello"; + } +} + """ + |> withName "CSLib" + + let app = + FSharp """ +open MyLib + +let text = Class1.Test(); + """ |> withReferences [CSLib] + + app + |> typecheckResults + |> checkDiagnostic + (57, """This construct is experimental. This warning can be disabled using '--nowarn:57' or '#nowarn "57"'.""") + (fun (experimental: ExperimentalExtendedData) -> + Assert.Equal(Some "FS222", experimental.DiagnosticId) + Assert.Equal(None, experimental.UrlFormat)) + + +[] +let ``Warning - ExperimentalExtendedData 02`` () = + let CSLib = + CSharp """ +using System.Diagnostics.CodeAnalysis; + +[Experimental(diagnosticId: "FS222", UrlFormat = "https://example.com")] +public static class Class1 +{ + public static string Test() + { + return "Hello"; + } +} + """ + |> withName "CSLib" + + let app = + FSharp """ +open MyLib + +let text = Class1.Test(); + """ |> withReferences [CSLib] + + app + |> typecheckResults + |> checkDiagnostic + (57, """This construct is experimental. This warning can be disabled using '--nowarn:57' or '#nowarn "57"'.""") + (fun (experimental: ExperimentalExtendedData) -> + Assert.Equal(Some "FS222", experimental.DiagnosticId) + Assert.Equal(Some "https://example.com", experimental.UrlFormat)) + +[] +let ``Warning - ExperimentalExtendedData 03`` () = + FSharp """ +module Test + +[] +type Class1() = + static member Test() = "Hello" + +let text = Class1.Test(); + """ + |> typecheckResults + |> checkDiagnostic + (57, """This construct is experimental. Use with caution. This warning can be disabled using '--nowarn:57' or '#nowarn "57"'.""") + (fun (experimental: ExperimentalExtendedData) -> + Assert.Equal(None, experimental.DiagnosticId) + Assert.Equal(None, experimental.UrlFormat)) \ No newline at end of file diff --git a/tests/FSharp.Compiler.ComponentTests/FSharp.Compiler.ComponentTests.fsproj b/tests/FSharp.Compiler.ComponentTests/FSharp.Compiler.ComponentTests.fsproj index 9eb31c35e0d..60b867c7815 100644 --- a/tests/FSharp.Compiler.ComponentTests/FSharp.Compiler.ComponentTests.fsproj +++ b/tests/FSharp.Compiler.ComponentTests/FSharp.Compiler.ComponentTests.fsproj @@ -224,6 +224,7 @@ + diff --git a/tests/FSharp.Compiler.ComponentTests/Language/ExperimentalAttributeCheckingTests.fs b/tests/FSharp.Compiler.ComponentTests/Language/ExperimentalAttributeCheckingTests.fs new file mode 100755 index 00000000000..653aa488281 --- /dev/null +++ b/tests/FSharp.Compiler.ComponentTests/Language/ExperimentalAttributeCheckingTests.fs @@ -0,0 +1,124 @@ +namespace Language + +open Xunit +open FSharp.Test.Compiler +open FSharp.Test + +module ExperimentalAttributeCheckingTests = + + + [] + let ``C# Experimental(diagnosticId) attribute warning is taken into account`` () = + let CSLib = + CSharp """ +using System.Diagnostics.CodeAnalysis; + +namespace MyLib; + +[Experimental("MY001")] +public static class Class1 +{ + public static string Test() + { + return "Hello"; + } +} + """ + |> withCSharpLanguageVersion CSharpLanguageVersion.CSharp12 + |> withName "CSLib" + + let app = + Fsx """ +open MyLib + +let text = Class1.Test() + """ |> withReferences [CSLib] + + app + |> compile + |> shouldFail + |> withDiagnostics [ + (Warning 57, Line 4, Col 12, Line 4, Col 18, """This construct is experimental. This warning can be disabled using '--nowarn:57' or '#nowarn "57"'.""") + (Warning 57, Line 4, Col 12, Line 4, Col 23, """This construct is experimental. This warning can be disabled using '--nowarn:57' or '#nowarn "57"'.""") + ] + + [] + let ``C# Experimental(UrlFormat) attribute warning is taken into account`` () = + let CSLib = + CSharp """ +using System.Diagnostics.CodeAnalysis; + +namespace MyLib; + +[Experimental("MY001", UrlFormat = "https://contoso.com/obsoletion-warnings")] +public static class Class1 +{ + public static string Test() + { + return "Hello"; + } +} + """ + |> withCSharpLanguageVersion CSharpLanguageVersion.CSharp12 + |> withName "CSLib" + + let app = + Fsx """ +open MyLib + +let text = Class1.Test() + """ |> withReferences [CSLib] + + app + |> compile + |> shouldFail + |> withDiagnostics [ + (Warning 57, Line 4, Col 12, Line 4, Col 18, """This construct is experimental. This warning can be disabled using '--nowarn:57' or '#nowarn "57"'.""") + (Warning 57, Line 4, Col 12, Line 4, Col 23, """This construct is experimental. This warning can be disabled using '--nowarn:57' or '#nowarn "57"'.""") + ] + + [] + let ``F# Experimental attribute warning is taken into account`` () = + Fsx """ +[] +module Class1 = + let Test() = "Hello" + +let text = Class1.Test() + """ + |> compile + |> shouldFail + |> withDiagnostics [ + (Warning 57, Line 6, Col 12, Line 6, Col 18, """This construct is experimental. Use with caution. This warning can be disabled using '--nowarn:57' or '#nowarn "57"'.""") + ] + + [] + let ``ExperimentalAttribute nowarn when preview specified``() = + Fsx """ +module TestModule = + + [] + let getString = "A string" + + if getString = "A string" then () + """ + |> withLangVersionPreview + |> compile + |> shouldSucceed + + [] + let ``ExperimentalAttribute warn when preview not specified``() = + Fsx """ +module TestModule = + + [] + let getString = "A string" + + if getString = "A string" then () + """ + |> compile + |> shouldFail + |> withDiagnostics [ + (Warning 57, Line 7, Col 8, Line 7, Col 17, """This construct is experimental. Preview library feature, requires '--langversion:preview'. This warning can be disabled using '--nowarn:57' or '#nowarn "57"'.""") + ] + \ No newline at end of file diff --git a/tests/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.SurfaceArea.netstandard20.debug.bsl b/tests/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.SurfaceArea.netstandard20.debug.bsl old mode 100644 new mode 100755 index 198dcde56b2..1836a6673c1 --- a/tests/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.SurfaceArea.netstandard20.debug.bsl +++ b/tests/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.SurfaceArea.netstandard20.debug.bsl @@ -2836,10 +2836,6 @@ FSharp.Compiler.Diagnostics.ExtendedData+FieldNotContainedDiagnosticExtendedData FSharp.Compiler.Diagnostics.ExtendedData+FieldNotContainedDiagnosticExtendedData: FSharp.Compiler.Symbols.FSharpField SignatureField FSharp.Compiler.Diagnostics.ExtendedData+FieldNotContainedDiagnosticExtendedData: FSharp.Compiler.Symbols.FSharpField get_ImplementationField() FSharp.Compiler.Diagnostics.ExtendedData+FieldNotContainedDiagnosticExtendedData: FSharp.Compiler.Symbols.FSharpField get_SignatureField() -FSharp.Compiler.Diagnostics.ExtendedData+ObsoleteDiagnosticExtendedData: System.String DiagnosticId -FSharp.Compiler.Diagnostics.ExtendedData+ObsoleteDiagnosticExtendedData: System.String UrlFormat -FSharp.Compiler.Diagnostics.ExtendedData+ObsoleteDiagnosticExtendedData: System.String get_DiagnosticId() -FSharp.Compiler.Diagnostics.ExtendedData+ObsoleteDiagnosticExtendedData: System.String get_UrlFormat() FSharp.Compiler.Diagnostics.ExtendedData+TypeMismatchDiagnosticExtendedData: DiagnosticContextInfo ContextInfo FSharp.Compiler.Diagnostics.ExtendedData+TypeMismatchDiagnosticExtendedData: DiagnosticContextInfo get_ContextInfo() FSharp.Compiler.Diagnostics.ExtendedData+TypeMismatchDiagnosticExtendedData: FSharp.Compiler.Symbols.FSharpDisplayContext DisplayContext @@ -2861,6 +2857,15 @@ FSharp.Compiler.Diagnostics.ExtendedData: FSharp.Compiler.Diagnostics.ExtendedDa FSharp.Compiler.Diagnostics.ExtendedData: FSharp.Compiler.Diagnostics.ExtendedData+ObsoleteDiagnosticExtendedData FSharp.Compiler.Diagnostics.ExtendedData: FSharp.Compiler.Diagnostics.ExtendedData+TypeMismatchDiagnosticExtendedData FSharp.Compiler.Diagnostics.ExtendedData: FSharp.Compiler.Diagnostics.ExtendedData+ValueNotContainedDiagnosticExtendedData +FSharp.Compiler.Diagnostics.ExtendedData+ObsoleteDiagnosticExtendedData: Microsoft.FSharp.Core.FSharpOption`1[System.String] DiagnosticId +FSharp.Compiler.Diagnostics.ExtendedData+ObsoleteDiagnosticExtendedData: Microsoft.FSharp.Core.FSharpOption`1[System.String] UrlFormat +FSharp.Compiler.Diagnostics.ExtendedData+ObsoleteDiagnosticExtendedData: Microsoft.FSharp.Core.FSharpOption`1[System.String] get_DiagnosticId() +FSharp.Compiler.Diagnostics.ExtendedData+ObsoleteDiagnosticExtendedData: Microsoft.FSharp.Core.FSharpOption`1[System.String] get_UrlFormat() +FSharp.Compiler.Diagnostics.ExtendedData+ExperimentalExtendedData: Microsoft.FSharp.Core.FSharpOption`1[System.String] DiagnosticId +FSharp.Compiler.Diagnostics.ExtendedData+ExperimentalExtendedData: Microsoft.FSharp.Core.FSharpOption`1[System.String] UrlFormat +FSharp.Compiler.Diagnostics.ExtendedData+ExperimentalExtendedData: Microsoft.FSharp.Core.FSharpOption`1[System.String] get_DiagnosticId() +FSharp.Compiler.Diagnostics.ExtendedData+ExperimentalExtendedData: Microsoft.FSharp.Core.FSharpOption`1[System.String] get_UrlFormat() +FSharp.Compiler.Diagnostics.ExtendedData: FSharp.Compiler.Diagnostics.ExtendedData+ExperimentalExtendedData FSharp.Compiler.Diagnostics.FSharpDiagnostic: FSharp.Compiler.Diagnostics.FSharpDiagnostic Create(FSharp.Compiler.Diagnostics.FSharpDiagnosticSeverity, System.String, Int32, FSharp.Compiler.Text.Range, Microsoft.FSharp.Core.FSharpOption`1[System.String], Microsoft.FSharp.Core.FSharpOption`1[System.String]) FSharp.Compiler.Diagnostics.FSharpDiagnostic: FSharp.Compiler.Diagnostics.FSharpDiagnosticSeverity Severity FSharp.Compiler.Diagnostics.FSharpDiagnostic: FSharp.Compiler.Diagnostics.FSharpDiagnosticSeverity get_Severity() diff --git a/tests/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.SurfaceArea.netstandard20.release.bsl b/tests/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.SurfaceArea.netstandard20.release.bsl old mode 100644 new mode 100755 index 198dcde56b2..fabaa710607 --- a/tests/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.SurfaceArea.netstandard20.release.bsl +++ b/tests/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.SurfaceArea.netstandard20.release.bsl @@ -2836,10 +2836,6 @@ FSharp.Compiler.Diagnostics.ExtendedData+FieldNotContainedDiagnosticExtendedData FSharp.Compiler.Diagnostics.ExtendedData+FieldNotContainedDiagnosticExtendedData: FSharp.Compiler.Symbols.FSharpField SignatureField FSharp.Compiler.Diagnostics.ExtendedData+FieldNotContainedDiagnosticExtendedData: FSharp.Compiler.Symbols.FSharpField get_ImplementationField() FSharp.Compiler.Diagnostics.ExtendedData+FieldNotContainedDiagnosticExtendedData: FSharp.Compiler.Symbols.FSharpField get_SignatureField() -FSharp.Compiler.Diagnostics.ExtendedData+ObsoleteDiagnosticExtendedData: System.String DiagnosticId -FSharp.Compiler.Diagnostics.ExtendedData+ObsoleteDiagnosticExtendedData: System.String UrlFormat -FSharp.Compiler.Diagnostics.ExtendedData+ObsoleteDiagnosticExtendedData: System.String get_DiagnosticId() -FSharp.Compiler.Diagnostics.ExtendedData+ObsoleteDiagnosticExtendedData: System.String get_UrlFormat() FSharp.Compiler.Diagnostics.ExtendedData+TypeMismatchDiagnosticExtendedData: DiagnosticContextInfo ContextInfo FSharp.Compiler.Diagnostics.ExtendedData+TypeMismatchDiagnosticExtendedData: DiagnosticContextInfo get_ContextInfo() FSharp.Compiler.Diagnostics.ExtendedData+TypeMismatchDiagnosticExtendedData: FSharp.Compiler.Symbols.FSharpDisplayContext DisplayContext @@ -2861,6 +2857,16 @@ FSharp.Compiler.Diagnostics.ExtendedData: FSharp.Compiler.Diagnostics.ExtendedDa FSharp.Compiler.Diagnostics.ExtendedData: FSharp.Compiler.Diagnostics.ExtendedData+ObsoleteDiagnosticExtendedData FSharp.Compiler.Diagnostics.ExtendedData: FSharp.Compiler.Diagnostics.ExtendedData+TypeMismatchDiagnosticExtendedData FSharp.Compiler.Diagnostics.ExtendedData: FSharp.Compiler.Diagnostics.ExtendedData+ValueNotContainedDiagnosticExtendedData +FSharp.Compiler.Diagnostics.ExtendedData+ObsoleteDiagnosticExtendedData: Microsoft.FSharp.Core.FSharpOption`1[System.String] DiagnosticId +FSharp.Compiler.Diagnostics.ExtendedData+ObsoleteDiagnosticExtendedData: Microsoft.FSharp.Core.FSharpOption`1[System.String] UrlFormat +FSharp.Compiler.Diagnostics.ExtendedData+ObsoleteDiagnosticExtendedData: Microsoft.FSharp.Core.FSharpOption`1[System.String] get_DiagnosticId() +FSharp.Compiler.Diagnostics.ExtendedData+ObsoleteDiagnosticExtendedData: Microsoft.FSharp.Core.FSharpOption`1[System.String] get_UrlFormat() +FSharp.Compiler.Diagnostics.ExtendedData: FSharp.Compiler.Diagnostics.ExtendedData+ObsoleteDiagnosticExtendedData +FSharp.Compiler.Diagnostics.ExtendedData+ExperimentalExtendedData: Microsoft.FSharp.Core.FSharpOption`1[System.String] DiagnosticId +FSharp.Compiler.Diagnostics.ExtendedData+ExperimentalExtendedData: Microsoft.FSharp.Core.FSharpOption`1[System.String] UrlFormat +FSharp.Compiler.Diagnostics.ExtendedData+ExperimentalExtendedData: Microsoft.FSharp.Core.FSharpOption`1[System.String] get_DiagnosticId() +FSharp.Compiler.Diagnostics.ExtendedData+ExperimentalExtendedData: Microsoft.FSharp.Core.FSharpOption`1[System.String] get_UrlFormat() +FSharp.Compiler.Diagnostics.ExtendedData: FSharp.Compiler.Diagnostics.ExtendedData+ExperimentalExtendedData FSharp.Compiler.Diagnostics.FSharpDiagnostic: FSharp.Compiler.Diagnostics.FSharpDiagnostic Create(FSharp.Compiler.Diagnostics.FSharpDiagnosticSeverity, System.String, Int32, FSharp.Compiler.Text.Range, Microsoft.FSharp.Core.FSharpOption`1[System.String], Microsoft.FSharp.Core.FSharpOption`1[System.String]) FSharp.Compiler.Diagnostics.FSharpDiagnostic: FSharp.Compiler.Diagnostics.FSharpDiagnosticSeverity Severity FSharp.Compiler.Diagnostics.FSharpDiagnostic: FSharp.Compiler.Diagnostics.FSharpDiagnosticSeverity get_Severity() diff --git a/tests/fsharp/Compiler/Warnings/ExperimentalAttributeTests.fs b/tests/fsharp/Compiler/Warnings/ExperimentalAttributeTests.fs deleted file mode 100644 index 582ddf1ac06..00000000000 --- a/tests/fsharp/Compiler/Warnings/ExperimentalAttributeTests.fs +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information. -namespace FSharp.Compiler.UnitTests - -open Xunit -open FSharp.Test -open FSharp.Compiler.Diagnostics - - -module ``Validate ExperimentalAttribute and LanguageVersion`` = - - let experimentalSource = """ -module TestModule = - - [] - let getString = "A string" - - if getString = "A string" then () -""" - - [] - let ``ExperimentalAttribute nowarn when preview specified``() = - CompilerAssert.PassWithOptions - [| "--langversion:preview" |] - experimentalSource - - [] - let ``ExperimentalAttribute warn when preview not specified``() = - CompilerAssert.TypeCheckSingleError - experimentalSource - FSharpDiagnosticSeverity.Warning - 57 - (7, 8, 7, 17) - "Preview library feature, requires '--langversion:preview'. This warning can be disabled using '--nowarn:57' or '#nowarn \"57\"'." diff --git a/tests/fsharp/FSharpSuite.Tests.fsproj b/tests/fsharp/FSharpSuite.Tests.fsproj index fdbec7e88a6..32ff617c0d3 100644 --- a/tests/fsharp/FSharpSuite.Tests.fsproj +++ b/tests/fsharp/FSharpSuite.Tests.fsproj @@ -45,7 +45,6 @@ - diff --git a/tests/fsharp/typecheck/sigs/neg91.bsl b/tests/fsharp/typecheck/sigs/neg91.bsl index 559a4871f92..8cb3e21f836 100644 --- a/tests/fsharp/typecheck/sigs/neg91.bsl +++ b/tests/fsharp/typecheck/sigs/neg91.bsl @@ -9,7 +9,7 @@ neg91.fs(34,13,34,16): typecheck error FS0044: This construct is deprecated. Don neg91.fs(44,13,44,16): typecheck error FS3003: Don't touch me -neg91.fs(54,13,54,16): typecheck error FS0057: It was just an experiment!. This warning can be disabled using '--nowarn:57' or '#nowarn "57"'. +neg91.fs(54,13,54,16): typecheck error FS0057: This construct is experimental. It was just an experiment!. This warning can be disabled using '--nowarn:57' or '#nowarn "57"'. neg91.fs(63,11,63,27): typecheck error FS3191: This literal pattern does not take arguments From 7866d665f47e1dc650248b3d8813d5c99a6c5d1a Mon Sep 17 00:00:00 2001 From: Viktor Hofer Date: Mon, 10 Feb 2025 18:20:51 +0100 Subject: [PATCH 20/29] React to NuGet package pruning warnings (#18304) Contributes to https://github.com/dotnet/sdk/pull/46642 NuGet added a new feature that automatically prunes package and project references that are provided by the shared framework that is targeted. --- eng/Versions.props | 1 - src/fsc/fsc.targets | 9 ++++++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/eng/Versions.props b/eng/Versions.props index 3b36ad6a716..ce0f5f5ac23 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -87,7 +87,6 @@ $(SystemPackageVersionVersion) 6.1.0 $(SystemPackageVersionVersion) - 4.5.0 1.6.0 4.11.0-2.24264.2 diff --git a/src/fsc/fsc.targets b/src/fsc/fsc.targets index 1c67ceb393a..dc80ab5c4b5 100644 --- a/src/fsc/fsc.targets +++ b/src/fsc/fsc.targets @@ -45,13 +45,16 @@ + + + + + + - - - From 5d0812f03f79e8fb551ff60469f6b5b67a2852a5 Mon Sep 17 00:00:00 2001 From: Jakub Majocha <1760221+majocha@users.noreply.github.com> Date: Mon, 10 Feb 2025 18:29:41 +0100 Subject: [PATCH 21/29] More OpenTelemetry changes (#18246) * trace test run activity * declutter StackGuard.Guard traces * add otel to debug vsix * ref otel in debug only * delay tags allocation * fix opens * format * better naming --- src/Compiler/Facilities/DiagnosticsLogger.fs | 22 +++++++++---------- src/Compiler/Utilities/Activity.fs | 10 +++++++-- src/Compiler/Utilities/Activity.fsi | 2 ++ tests/FSharp.Test.Utilities/XunitHelpers.fs | 11 +++++++++- .../VisualFSharp.Core.targets | 14 +++++++++++- .../src/FSharp.Editor/Common/Logging.fs | 20 +++++++++++++++++ .../src/FSharp.Editor/FSharp.Editor.fsproj | 1 + .../LanguageService/LanguageService.fs | 1 + 8 files changed, 66 insertions(+), 15 deletions(-) diff --git a/src/Compiler/Facilities/DiagnosticsLogger.fs b/src/Compiler/Facilities/DiagnosticsLogger.fs index 04cb35a2e8e..e5869fe04b2 100644 --- a/src/Compiler/Facilities/DiagnosticsLogger.fs +++ b/src/Compiler/Facilities/DiagnosticsLogger.fs @@ -882,17 +882,17 @@ type StackGuard(maxDepth: int, name: string) = [] path: string, [] line: int ) = - use _ = - Activity.start - "DiagnosticsLogger.StackGuard.Guard" - [| - Activity.Tags.stackGuardName, name - Activity.Tags.stackGuardCurrentDepth, string depth - Activity.Tags.stackGuardMaxDepth, string maxDepth - Activity.Tags.callerMemberName, memberName - Activity.Tags.callerFilePath, path - Activity.Tags.callerLineNumber, string line - |] + + Activity.addEventWithTags + "DiagnosticsLogger.StackGuard.Guard" + (seq { + Activity.Tags.stackGuardName, box name + Activity.Tags.stackGuardCurrentDepth, depth + Activity.Tags.stackGuardMaxDepth, maxDepth + Activity.Tags.callerMemberName, memberName + Activity.Tags.callerFilePath, path + Activity.Tags.callerLineNumber, line + }) depth <- depth + 1 diff --git a/src/Compiler/Utilities/Activity.fs b/src/Compiler/Utilities/Activity.fs index e2d7e78fcb6..2d204864f69 100644 --- a/src/Compiler/Utilities/Activity.fs +++ b/src/Compiler/Utilities/Activity.fs @@ -7,6 +7,7 @@ open System.Diagnostics open System.IO open System.Text open Internal.Utilities.Library +open System.Collections.Generic module ActivityNames = @@ -102,12 +103,17 @@ module internal Activity = let startNoTags (name: string) : IDisposable MaybeNull = activitySource.StartActivity name - let addEvent name = + let addEventWithTags name (tags: (string * objnull) seq) = match Activity.Current with | null -> () - | activity when activity.Source = activitySource -> activity.AddEvent(ActivityEvent name) |> ignore + | activity when activity.Source = activitySource -> + let collection = tags |> Seq.map KeyValuePair |> ActivityTagsCollection + let event = new ActivityEvent(name, tags = collection) + activity.AddEvent event |> ignore | _ -> () + let addEvent name = addEventWithTags name Seq.empty + module Profiling = module Tags = diff --git a/src/Compiler/Utilities/Activity.fsi b/src/Compiler/Utilities/Activity.fsi index 6e7244f5e59..041b2998765 100644 --- a/src/Compiler/Utilities/Activity.fsi +++ b/src/Compiler/Utilities/Activity.fsi @@ -46,6 +46,8 @@ module internal Activity = val addEvent: name: string -> unit + val addEventWithTags: name: string -> tags: (string * objnull) seq -> unit + module Profiling = val startAndMeasureEnvironmentStats: name: string -> IDisposable MaybeNull val addConsoleListener: unit -> IDisposable diff --git a/tests/FSharp.Test.Utilities/XunitHelpers.fs b/tests/FSharp.Test.Utilities/XunitHelpers.fs index 2747bdc5a63..ce4d47b9635 100644 --- a/tests/FSharp.Test.Utilities/XunitHelpers.fs +++ b/tests/FSharp.Test.Utilities/XunitHelpers.fs @@ -168,7 +168,16 @@ type FSharpXunitFramework(sink: IMessageSink) = cleanUpTemporaryDirectoryOfThisTestRun () traceProvider.ForceFlush() |> ignore traceProvider.Dispose() - base.Dispose() + base.Dispose() + + // Group test run under single activity, to make traces more readable. + // Otherwise this overriden method is not necessary and can be removed. + override this.CreateExecutor (assemblyName) = + { new XunitTestFrameworkExecutor(assemblyName, this.SourceInformationProvider, this.DiagnosticMessageSink) with + override _.RunTestCases(testCases, executionMessageSink, executionOptions) = + use _ = Activity.start $"{assemblyName.Name} {Runtime.InteropServices.RuntimeInformation.FrameworkDescription}" [] + base.RunTestCases(testCases, executionMessageSink, executionOptions) + } override this.CreateDiscoverer (assemblyInfo) = { new XunitTestFrameworkDiscoverer(assemblyInfo, this.SourceInformationProvider, this.DiagnosticMessageSink) with diff --git a/vsintegration/Vsix/VisualFSharpFull/VisualFSharp.Core.targets b/vsintegration/Vsix/VisualFSharpFull/VisualFSharp.Core.targets index f3c3ce40b79..16d69751fd7 100644 --- a/vsintegration/Vsix/VisualFSharpFull/VisualFSharp.Core.targets +++ b/vsintegration/Vsix/VisualFSharpFull/VisualFSharp.Core.targets @@ -110,7 +110,19 @@ False - + + + {65e0e82a-eace-4787-8994-888674c2fe87} + FSharp.Editor + ReferenceCopyLocalPathsOutputGroup%3bBuiltProjectOutputGroup%3bGetCopyToOutputDirectoryItems%3bPkgDefProjectOutputGroup%3bSatelliteDllsProjectOutputGroup%3b + DebugSymbolsProjectOutputGroup%3b + true + All + 2 + True + + + {65e0e82a-eace-4787-8994-888674c2fe87} FSharp.Editor BuiltProjectOutputGroup%3bGetCopyToOutputDirectoryItems%3bPkgDefProjectOutputGroup%3bSatelliteDllsProjectOutputGroup%3b diff --git a/vsintegration/src/FSharp.Editor/Common/Logging.fs b/vsintegration/src/FSharp.Editor/Common/Logging.fs index a69779e9acc..cf531c65384 100644 --- a/vsintegration/src/FSharp.Editor/Common/Logging.fs +++ b/vsintegration/src/FSharp.Editor/Common/Logging.fs @@ -7,6 +7,8 @@ open Microsoft.VisualStudio.Shell open Microsoft.VisualStudio.Shell.Interop open Microsoft.VisualStudio.FSharp.Editor +open FSharp.Compiler.Diagnostics + [] type LogType = | Info @@ -116,7 +118,12 @@ module Logging = let logExceptionWithContext (ex: Exception, context) = logErrorf "Context: %s\nException Message: %s\nStack Trace: %s" context ex.Message ex.StackTrace +#if DEBUG module Activity = + + open OpenTelemetry.Resources + open OpenTelemetry.Trace + let listen filter = let indent (activity: Activity) = let rec loop (activity: Activity) n = @@ -145,4 +152,17 @@ module Activity = ActivitySource.AddActivityListener(listener) + let export () = + OpenTelemetry.Sdk + .CreateTracerProviderBuilder() + .AddSource(ActivityNames.FscSourceName) + .SetResourceBuilder( + ResourceBuilder + .CreateDefault() + .AddService(serviceName = "F#", serviceVersion = "1.0.0") + ) + .AddOtlpExporter() + .Build() + let listenToAll () = listen "" +#endif diff --git a/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj b/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj index 2ec608dda20..5fedad089dd 100644 --- a/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj +++ b/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj @@ -194,6 +194,7 @@ + diff --git a/vsintegration/src/FSharp.Editor/LanguageService/LanguageService.fs b/vsintegration/src/FSharp.Editor/LanguageService/LanguageService.fs index 18cb516b6a9..55cd1b622b3 100644 --- a/vsintegration/src/FSharp.Editor/LanguageService/LanguageService.fs +++ b/vsintegration/src/FSharp.Editor/LanguageService/LanguageService.fs @@ -341,6 +341,7 @@ type internal FSharpPackage() as this = let mutable solutionEventsOpt = None #if DEBUG + let _traceProvider = Logging.Activity.export () let _logger = Logging.Activity.listenToAll () // Logging.Activity.listen "IncrementalBuild" #endif From 5af63aa9170116b543156ef3203e5891cead0a3b Mon Sep 17 00:00:00 2001 From: Eugene Auduchinok Date: Tue, 11 Feb 2025 14:26:29 +0100 Subject: [PATCH 22/29] Cancellable: fix leaking cancellation token (#18295) * Cancellable: fix leaking cancellation token * Release notes Update docs/release-notes/.FSharp.Compiler.Service/9.0.300.md * Set Cancellable.Token in transparent compiler * Review fixes * Move setting the token * Fantomas * Transparent compiler * il bsl --------- Co-authored-by: Petr --- .../.FSharp.Compiler.Service/9.0.300.md | 1 + src/Compiler/Driver/CompilerImports.fs | 2 -- src/Compiler/Service/BackgroundCompiler.fs | 12 ++++++------ src/Compiler/Service/ServiceAnalysis.fs | 2 +- src/Compiler/Service/TransparentCompiler.fs | 6 ++++++ src/Compiler/Utilities/Cancellable.fs | 2 +- src/Compiler/Utilities/Cancellable.fsi | 2 +- ...ilverify_FSharp.Compiler.Service_Debug_net9.0.bsl | 2 +- ..._FSharp.Compiler.Service_Debug_netstandard2.0.bsl | 2 +- ...verify_FSharp.Compiler.Service_Release_net9.0.bsl | 2 +- ...Sharp.Compiler.Service_Release_netstandard2.0.bsl | 2 +- 11 files changed, 20 insertions(+), 15 deletions(-) diff --git a/docs/release-notes/.FSharp.Compiler.Service/9.0.300.md b/docs/release-notes/.FSharp.Compiler.Service/9.0.300.md index bcff9ba132d..f71fa86121d 100644 --- a/docs/release-notes/.FSharp.Compiler.Service/9.0.300.md +++ b/docs/release-notes/.FSharp.Compiler.Service/9.0.300.md @@ -7,6 +7,7 @@ * Fix missing nullness warning when static upcast dropped nullness ([Issue #18232](https://github.com/dotnet/fsharp/issues/18232), [PR #18261](https://github.com/dotnet/fsharp/pull/18261)) * Cancellable: only cancel on OCE with own token ([PR #18277](https://github.com/dotnet/fsharp/pull/18277)) * Cancellable: set token in more places ([PR #18283](https://github.com/dotnet/fsharp/pull/18283)) +* Cancellable: fix leaking cancellation token ([PR #18295](https://github.com/dotnet/fsharp/pull/18295)) * Fix NRE when accessing nullable fields of types within their equals/hash/compare methods ([PR #18296](https://github.com/dotnet/fsharp/pull/18296)) ### Added diff --git a/src/Compiler/Driver/CompilerImports.fs b/src/Compiler/Driver/CompilerImports.fs index 8478429a452..ae14ee51157 100644 --- a/src/Compiler/Driver/CompilerImports.fs +++ b/src/Compiler/Driver/CompilerImports.fs @@ -2255,7 +2255,6 @@ and [] TcImports r: AssemblyResolution ) : Async<(_ * (unit -> AvailableImportedAssembly list)) option> = async { - do! Cancellable.UseToken() CheckDisposed() let m = r.originalReference.Range let fileName = r.resolvedPath @@ -2327,7 +2326,6 @@ and [] TcImports async { CheckDisposed() - let tcConfig = tcConfigP.Get ctok let runMethod = diff --git a/src/Compiler/Service/BackgroundCompiler.fs b/src/Compiler/Service/BackgroundCompiler.fs index da04b6ebb83..a55aaa490be 100644 --- a/src/Compiler/Service/BackgroundCompiler.fs +++ b/src/Compiler/Service/BackgroundCompiler.fs @@ -500,11 +500,11 @@ type internal BackgroundCompiler } let getOrCreateBuilder (options, userOpName) : Async = - match tryGetBuilder options with - | Some getBuilder -> - async { - do! Cancellable.UseToken() + async { + use! _holder = Cancellable.UseToken() + match tryGetBuilder options with + | Some getBuilder -> match! getBuilder with | builderOpt, creationDiags when builderOpt.IsNone || not builderOpt.Value.IsReferencesInvalidated -> return builderOpt, creationDiags @@ -520,8 +520,8 @@ type internal BackgroundCompiler checkFileInProjectCache.RemoveAnySimilar(ltok, key))) return! createAndGetBuilder (options, userOpName) - } - | _ -> createAndGetBuilder (options, userOpName) + | _ -> return! createAndGetBuilder (options, userOpName) + } let getSimilarOrCreateBuilder (options, userOpName) = match tryGetSimilarBuilder options with diff --git a/src/Compiler/Service/ServiceAnalysis.fs b/src/Compiler/Service/ServiceAnalysis.fs index 1347751d167..6455d9f0ff3 100644 --- a/src/Compiler/Service/ServiceAnalysis.fs +++ b/src/Compiler/Service/ServiceAnalysis.fs @@ -302,7 +302,7 @@ module UnusedOpens = /// Async to allow cancellation. let getUnusedOpens (checkFileResults: FSharpCheckFileResults, getSourceLineStr: int -> string) : Async = async { - do! Cancellable.UseToken() + use! _holder = Cancellable.UseToken() if checkFileResults.OpenDeclarations.Length = 0 then return [] diff --git a/src/Compiler/Service/TransparentCompiler.fs b/src/Compiler/Service/TransparentCompiler.fs index 9f35b4f2835..9007a111e7d 100644 --- a/src/Compiler/Service/TransparentCompiler.fs +++ b/src/Compiler/Service/TransparentCompiler.fs @@ -1610,6 +1610,8 @@ type internal TransparentCompiler caches.ParseAndCheckFileInProject.Get( projectSnapshot.FileKeyWithExtraFileSnapshotVersion fileName, async { + use! _holder = Cancellable.UseToken() + use _ = Activity.start "ComputeParseAndCheckFileInProject" [| Activity.Tags.fileName, fileName |> Path.GetFileName |> (!!) |] @@ -1861,6 +1863,7 @@ type internal TransparentCompiler caches.AssemblyData.Get( projectSnapshot.SignatureKey, async { + use! _holder = Cancellable.UseToken() try @@ -1908,6 +1911,7 @@ type internal TransparentCompiler caches.ParseAndCheckProject.Get( projectSnapshot.FullKey, async { + use! _holder = Cancellable.UseToken() match! ComputeBootstrapInfo projectSnapshot with | None, creationDiags -> @@ -1980,6 +1984,8 @@ type internal TransparentCompiler let tryGetSink (fileName: string) (projectSnapshot: ProjectSnapshot) = async { + use! _holder = Cancellable.UseToken() + match! ComputeBootstrapInfo projectSnapshot with | None, _ -> return None | Some bootstrapInfo, _creationDiags -> diff --git a/src/Compiler/Utilities/Cancellable.fs b/src/Compiler/Utilities/Cancellable.fs index 4d6c42cd6f0..9e40de9dd2d 100644 --- a/src/Compiler/Utilities/Cancellable.fs +++ b/src/Compiler/Utilities/Cancellable.fs @@ -21,7 +21,7 @@ type Cancellable = static member UseToken() = async { let! ct = Async.CancellationToken - tokenHolder.Value <- ValueSome ct + return Cancellable.UsingToken ct } static member UsingToken(ct) = diff --git a/src/Compiler/Utilities/Cancellable.fsi b/src/Compiler/Utilities/Cancellable.fsi index 737a27a4f2a..72c098d2234 100644 --- a/src/Compiler/Utilities/Cancellable.fsi +++ b/src/Compiler/Utilities/Cancellable.fsi @@ -5,7 +5,7 @@ open System.Threading [] type Cancellable = - static member internal UseToken: unit -> Async + static member internal UseToken: unit -> Async /// For use in testing only. Cancellable.token should be set only by the cancellable computation. static member internal UsingToken: CancellationToken -> IDisposable diff --git a/tests/ILVerify/ilverify_FSharp.Compiler.Service_Debug_net9.0.bsl b/tests/ILVerify/ilverify_FSharp.Compiler.Service_Debug_net9.0.bsl index c2263a4f259..4f429d04961 100644 --- a/tests/ILVerify/ilverify_FSharp.Compiler.Service_Debug_net9.0.bsl +++ b/tests/ILVerify/ilverify_FSharp.Compiler.Service_Debug_net9.0.bsl @@ -21,7 +21,7 @@ [IL]: Error [StackUnexpected]: : FSharp.Compiler.CodeAnalysis.Hosted.CompilerHelpers::fscCompile([FSharp.Compiler.Service]FSharp.Compiler.CodeAnalysis.LegacyReferenceResolver, string, string[])][offset 0x00000082][found Char] Unexpected type on the stack. [IL]: Error [StackUnexpected]: : FSharp.Compiler.CodeAnalysis.Hosted.CompilerHelpers::fscCompile([FSharp.Compiler.Service]FSharp.Compiler.CodeAnalysis.LegacyReferenceResolver, string, string[])][offset 0x0000008B][found Char] Unexpected type on the stack. [IL]: Error [StackUnexpected]: : FSharp.Compiler.Interactive.Shell+MagicAssemblyResolution::ResolveAssemblyCore([FSharp.Compiler.Service]Internal.Utilities.Library.CompilationThreadToken, [FSharp.Compiler.Service]FSharp.Compiler.Text.Range, [FSharp.Compiler.Service]FSharp.Compiler.CompilerConfig+TcConfigBuilder, [FSharp.Compiler.Service]FSharp.Compiler.CompilerImports+TcImports, [FSharp.Compiler.Service]FSharp.Compiler.Interactive.Shell+FsiDynamicCompiler, [FSharp.Compiler.Service]FSharp.Compiler.Interactive.Shell+FsiConsoleOutput, string)][offset 0x00000015][found Char] Unexpected type on the stack. -[IL]: Error [StackUnexpected]: : FSharp.Compiler.Interactive.Shell+clo@3516-789::Invoke([S.P.CoreLib]System.Tuple`3)][offset 0x000001E5][found Char] Unexpected type on the stack. +[IL]: Error [StackUnexpected]: : FSharp.Compiler.Interactive.Shell+clo@3516-802::Invoke([S.P.CoreLib]System.Tuple`3)][offset 0x000001E5][found Char] Unexpected type on the stack. [IL]: Error [UnmanagedPointer]: : FSharp.Compiler.Interactive.Shell+Utilities+pointerToNativeInt@110::Invoke(object)][offset 0x00000007] Unmanaged pointers are not a verifiable type. [IL]: Error [StackUnexpected]: : .$FSharpCheckerResults+dataTipOfReferences@2205::Invoke([FSharp.Core]Microsoft.FSharp.Core.Unit)][offset 0x00000084][found Char] Unexpected type on the stack. [IL]: Error [StackUnexpected]: : .$ServiceLexing+clo@921-509::Invoke([FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2,Microsoft.FSharp.Core.Unit>)][offset 0x00000032][found Char] Unexpected type on the stack. diff --git a/tests/ILVerify/ilverify_FSharp.Compiler.Service_Debug_netstandard2.0.bsl b/tests/ILVerify/ilverify_FSharp.Compiler.Service_Debug_netstandard2.0.bsl index 18045d70b31..2ec0116a1af 100644 --- a/tests/ILVerify/ilverify_FSharp.Compiler.Service_Debug_netstandard2.0.bsl +++ b/tests/ILVerify/ilverify_FSharp.Compiler.Service_Debug_netstandard2.0.bsl @@ -28,7 +28,7 @@ [IL]: Error [StackUnexpected]: : FSharp.Compiler.CodeAnalysis.Hosted.CompilerHelpers::fscCompile([FSharp.Compiler.Service]FSharp.Compiler.CodeAnalysis.LegacyReferenceResolver, string, string[])][offset 0x0000008B][found Char] Unexpected type on the stack. [IL]: Error [StackUnexpected]: : FSharp.Compiler.Interactive.Shell+FsiStdinSyphon::GetLine(string, int32)][offset 0x00000039][found Char] Unexpected type on the stack. [IL]: Error [StackUnexpected]: : FSharp.Compiler.Interactive.Shell+MagicAssemblyResolution::ResolveAssemblyCore([FSharp.Compiler.Service]Internal.Utilities.Library.CompilationThreadToken, [FSharp.Compiler.Service]FSharp.Compiler.Text.Range, [FSharp.Compiler.Service]FSharp.Compiler.CompilerConfig+TcConfigBuilder, [FSharp.Compiler.Service]FSharp.Compiler.CompilerImports+TcImports, [FSharp.Compiler.Service]FSharp.Compiler.Interactive.Shell+FsiDynamicCompiler, [FSharp.Compiler.Service]FSharp.Compiler.Interactive.Shell+FsiConsoleOutput, string)][offset 0x00000015][found Char] Unexpected type on the stack. -[IL]: Error [StackUnexpected]: : FSharp.Compiler.Interactive.Shell+clo@3516-789::Invoke([S.P.CoreLib]System.Tuple`3)][offset 0x000001E5][found Char] Unexpected type on the stack. +[IL]: Error [StackUnexpected]: : FSharp.Compiler.Interactive.Shell+clo@3516-802::Invoke([S.P.CoreLib]System.Tuple`3)][offset 0x000001E5][found Char] Unexpected type on the stack. [IL]: Error [StackUnexpected]: : FSharp.Compiler.Interactive.Shell+FsiInteractionProcessor::CompletionsForPartialLID([FSharp.Compiler.Service]FSharp.Compiler.Interactive.Shell+FsiDynamicCompilerState, string)][offset 0x0000001B][found Char] Unexpected type on the stack. [IL]: Error [UnmanagedPointer]: : FSharp.Compiler.Interactive.Shell+Utilities+pointerToNativeInt@110::Invoke(object)][offset 0x00000007] Unmanaged pointers are not a verifiable type. [IL]: Error [StackUnexpected]: : .$FSharpCheckerResults+dataTipOfReferences@2205::Invoke([FSharp.Core]Microsoft.FSharp.Core.Unit)][offset 0x00000084][found Char] Unexpected type on the stack. diff --git a/tests/ILVerify/ilverify_FSharp.Compiler.Service_Release_net9.0.bsl b/tests/ILVerify/ilverify_FSharp.Compiler.Service_Release_net9.0.bsl index b01f7e04acb..48210dddd5c 100644 --- a/tests/ILVerify/ilverify_FSharp.Compiler.Service_Release_net9.0.bsl +++ b/tests/ILVerify/ilverify_FSharp.Compiler.Service_Release_net9.0.bsl @@ -21,7 +21,7 @@ [IL]: Error [StackUnexpected]: : FSharp.Compiler.CodeAnalysis.Hosted.CompilerHelpers::fscCompile([FSharp.Compiler.Service]FSharp.Compiler.CodeAnalysis.LegacyReferenceResolver, string, string[])][offset 0x00000082][found Char] Unexpected type on the stack. [IL]: Error [StackUnexpected]: : FSharp.Compiler.CodeAnalysis.Hosted.CompilerHelpers::fscCompile([FSharp.Compiler.Service]FSharp.Compiler.CodeAnalysis.LegacyReferenceResolver, string, string[])][offset 0x0000008B][found Char] Unexpected type on the stack. [IL]: Error [StackUnexpected]: : FSharp.Compiler.Interactive.Shell+MagicAssemblyResolution::ResolveAssemblyCore([FSharp.Compiler.Service]Internal.Utilities.Library.CompilationThreadToken, [FSharp.Compiler.Service]FSharp.Compiler.Text.Range, [FSharp.Compiler.Service]FSharp.Compiler.CompilerConfig+TcConfigBuilder, [FSharp.Compiler.Service]FSharp.Compiler.CompilerImports+TcImports, [FSharp.Compiler.Service]FSharp.Compiler.Interactive.Shell+FsiDynamicCompiler, [FSharp.Compiler.Service]FSharp.Compiler.Interactive.Shell+FsiConsoleOutput, string)][offset 0x00000015][found Char] Unexpected type on the stack. -[IL]: Error [StackUnexpected]: : FSharp.Compiler.Interactive.Shell+clo@3516-833::Invoke([S.P.CoreLib]System.Tuple`3)][offset 0x000001C7][found Char] Unexpected type on the stack. +[IL]: Error [StackUnexpected]: : FSharp.Compiler.Interactive.Shell+clo@3516-846::Invoke([S.P.CoreLib]System.Tuple`3)][offset 0x000001C7][found Char] Unexpected type on the stack. [IL]: Error [StackUnexpected]: : .$FSharpCheckerResults+GetReferenceResolutionStructuredToolTipText@2205::Invoke([FSharp.Core]Microsoft.FSharp.Core.Unit)][offset 0x00000076][found Char] Unexpected type on the stack. [IL]: Error [StackUnexpected]: : .$ServiceLexing+clo@921-530::Invoke([FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2,Microsoft.FSharp.Core.Unit>)][offset 0x00000032][found Char] Unexpected type on the stack. [IL]: Error [StackUnexpected]: : .$ServiceLexing+clo@921-530::Invoke([FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2,Microsoft.FSharp.Core.Unit>)][offset 0x0000003B][found Char] Unexpected type on the stack. diff --git a/tests/ILVerify/ilverify_FSharp.Compiler.Service_Release_netstandard2.0.bsl b/tests/ILVerify/ilverify_FSharp.Compiler.Service_Release_netstandard2.0.bsl index e093fab1d7d..2df2cf0fbd9 100644 --- a/tests/ILVerify/ilverify_FSharp.Compiler.Service_Release_netstandard2.0.bsl +++ b/tests/ILVerify/ilverify_FSharp.Compiler.Service_Release_netstandard2.0.bsl @@ -28,7 +28,7 @@ [IL]: Error [StackUnexpected]: : FSharp.Compiler.CodeAnalysis.Hosted.CompilerHelpers::fscCompile([FSharp.Compiler.Service]FSharp.Compiler.CodeAnalysis.LegacyReferenceResolver, string, string[])][offset 0x0000008B][found Char] Unexpected type on the stack. [IL]: Error [StackUnexpected]: : FSharp.Compiler.Interactive.Shell+FsiStdinSyphon::GetLine(string, int32)][offset 0x00000032][found Char] Unexpected type on the stack. [IL]: Error [StackUnexpected]: : FSharp.Compiler.Interactive.Shell+MagicAssemblyResolution::ResolveAssemblyCore([FSharp.Compiler.Service]Internal.Utilities.Library.CompilationThreadToken, [FSharp.Compiler.Service]FSharp.Compiler.Text.Range, [FSharp.Compiler.Service]FSharp.Compiler.CompilerConfig+TcConfigBuilder, [FSharp.Compiler.Service]FSharp.Compiler.CompilerImports+TcImports, [FSharp.Compiler.Service]FSharp.Compiler.Interactive.Shell+FsiDynamicCompiler, [FSharp.Compiler.Service]FSharp.Compiler.Interactive.Shell+FsiConsoleOutput, string)][offset 0x00000015][found Char] Unexpected type on the stack. -[IL]: Error [StackUnexpected]: : FSharp.Compiler.Interactive.Shell+clo@3516-833::Invoke([S.P.CoreLib]System.Tuple`3)][offset 0x000001C7][found Char] Unexpected type on the stack. +[IL]: Error [StackUnexpected]: : FSharp.Compiler.Interactive.Shell+clo@3516-846::Invoke([S.P.CoreLib]System.Tuple`3)][offset 0x000001C7][found Char] Unexpected type on the stack. [IL]: Error [StackUnexpected]: : FSharp.Compiler.Interactive.Shell+FsiInteractionProcessor::CompletionsForPartialLID([FSharp.Compiler.Service]FSharp.Compiler.Interactive.Shell+FsiDynamicCompilerState, string)][offset 0x00000024][found Char] Unexpected type on the stack. [IL]: Error [StackUnexpected]: : .$FSharpCheckerResults+GetReferenceResolutionStructuredToolTipText@2205::Invoke([FSharp.Core]Microsoft.FSharp.Core.Unit)][offset 0x00000076][found Char] Unexpected type on the stack. [IL]: Error [StackUnexpected]: : FSharp.Compiler.EditorServices.AssemblyContent+traverseMemberFunctionAndValues@176::Invoke([FSharp.Compiler.Service]FSharp.Compiler.Symbols.FSharpMemberOrFunctionOrValue)][offset 0x0000002B][found Char] Unexpected type on the stack. From 96771a80199a493ede64042486ccb41942b3f129 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Wed, 12 Feb 2025 12:11:22 +0100 Subject: [PATCH 23/29] Update dependencies from https://github.com/dotnet/arcade build 20250211.5 (#18310) Microsoft.SourceBuild.Intermediate.arcade , Microsoft.DotNet.Arcade.Sdk From Version 9.0.0-beta.25077.4 -> To Version 9.0.0-beta.25111.5 Co-authored-by: dotnet-maestro[bot] --- .config/dotnet-tools.json | 2 +- eng/Version.Details.xml | 8 ++++---- global.json | 6 +++--- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/.config/dotnet-tools.json b/.config/dotnet-tools.json index 46cb8a756ca..34ccbbf8056 100644 --- a/.config/dotnet-tools.json +++ b/.config/dotnet-tools.json @@ -59,4 +59,4 @@ "rollForward": false } } -} \ No newline at end of file +} diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index c7056f9a86d..983446e2b7b 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -42,14 +42,14 @@ - + https://github.com/dotnet/arcade - bac7e1caea791275b7c3ccb4cb75fd6a04a26618 + 5da211e1c42254cb35e7ef3d5a8428fb24853169 - + https://github.com/dotnet/arcade - bac7e1caea791275b7c3ccb4cb75fd6a04a26618 + 5da211e1c42254cb35e7ef3d5a8428fb24853169 diff --git a/global.json b/global.json index 5ba1a798140..34fb2765a67 100644 --- a/global.json +++ b/global.json @@ -1,10 +1,10 @@ { "sdk": { - "version": "9.0.102", + "version": "9.0.103", "allowPrerelease": true }, "tools": { - "dotnet": "9.0.102", + "dotnet": "9.0.103", "vs": { "version": "17.8", "components": [ @@ -17,7 +17,7 @@ "perl": "5.38.2.2" }, "msbuild-sdks": { - "Microsoft.DotNet.Arcade.Sdk": "9.0.0-beta.25077.4", + "Microsoft.DotNet.Arcade.Sdk": "9.0.0-beta.25111.5", "Microsoft.DotNet.Helix.Sdk": "8.0.0-beta.23255.2" } } From 79e8531d168b4c1daf7593cf52a392799ba7a130 Mon Sep 17 00:00:00 2001 From: Brian Rourke Boll Date: Wed, 12 Feb 2025 06:16:43 -0500 Subject: [PATCH 24/29] =?UTF-8?q?Classify=20`nameof<'T>`=20&=20`match=20?= =?UTF-8?q?=E2=80=A6=20with=20nameof=20ident=20->=20=E2=80=A6`=20correctly?= =?UTF-8?q?=20(#18300)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Resolve `nameof` in `nameof<'T>` * Resolve `nameof` in `match … with nameof ident -> …` * Add `nameof` classification tests * Update release notes * Might as well make them compilable * Show `nameof` as keyword in `nameof<…>` even when the type parameter is invalid * Touchup --- .../.FSharp.Compiler.Service/9.0.300.md | 3 +- src/Compiler/Checking/CheckPatterns.fs | 5 +- .../Checking/Expressions/CheckExpressions.fs | 6 ++ .../SemanticClassificationServiceTests.fs | 61 ++++++++++++++++++- 4 files changed, 71 insertions(+), 4 deletions(-) diff --git a/docs/release-notes/.FSharp.Compiler.Service/9.0.300.md b/docs/release-notes/.FSharp.Compiler.Service/9.0.300.md index f71fa86121d..f64f090744b 100644 --- a/docs/release-notes/.FSharp.Compiler.Service/9.0.300.md +++ b/docs/release-notes/.FSharp.Compiler.Service/9.0.300.md @@ -1,4 +1,5 @@ ### Fixed +* Fix classification of `nameof` in `nameof<'T>`, `match … with nameof ident -> …`. ([Issue #10026](https://github.com/dotnet/fsharp/issues/10026), [PR #18300](https://github.com/dotnet/fsharp/pull/18300)) * Fix Realsig+ generates nested closures with incorrect Generic ([Issue #17797](https://github.com/dotnet/fsharp/issues/17797), [PR #17877](https://github.com/dotnet/fsharp/pull/17877)) * Fix optimizer internal error for records with static fields ([Issue #18165](https://github.com/dotnet/fsharp/issues/18165), [PR #18280](https://github.com/dotnet/fsharp/pull/18280)) * Fix nullness warning with flexible types ([Issue #18056](https://github.com/dotnet/fsharp/issues/18056), [PR #18266](https://github.com/dotnet/fsharp/pull/18266)) @@ -25,4 +26,4 @@ * Added nullability annotations to `.Using` builder method for `async`, `task` and compiler-internal builders ([PR #18292](https://github.com/dotnet/fsharp/pull/18292)) ### Breaking Changes -* Struct unions with overlapping fields now generate mappings needed for reading via reflection ([Issue #18121](https://github.com/dotnet/fsharp/issues/17797), [PR #18274](https://github.com/dotnet/fsharp/pull/17877)) \ No newline at end of file +* Struct unions with overlapping fields now generate mappings needed for reading via reflection ([Issue #18121](https://github.com/dotnet/fsharp/issues/17797), [PR #18274](https://github.com/dotnet/fsharp/pull/17877)) diff --git a/src/Compiler/Checking/CheckPatterns.fs b/src/Compiler/Checking/CheckPatterns.fs index 5d447da6021..cdffd9acb7f 100644 --- a/src/Compiler/Checking/CheckPatterns.fs +++ b/src/Compiler/Checking/CheckPatterns.fs @@ -583,7 +583,10 @@ and TcPatLongIdentNewDef warnOnUpperForId warnOnUpper (cenv: cenv) env ad valRep | [arg] when g.langVersion.SupportsFeature LanguageFeature.NameOf && IsNameOf cenv env ad m id -> match TcNameOfExpr cenv env tpenv (ConvSynPatToSynExpr arg) with - | Expr.Const(Const.String s, m, _) -> TcConstPat warnOnUpper cenv env vFlags patEnv ty (SynConst.String(s, SynStringKind.Regular, m)) m + | Expr.Const(Const.String s, m, _) -> + // Record the resolution of the `nameof` usage so that we can classify it correctly later. + CallNameResolutionSink cenv.tcSink (id.idRange, env.NameEnv, Item.Value g.nameof_vref, emptyTyparInst, ItemOccurrence.Use, env.eAccessRights) + TcConstPat warnOnUpper cenv env vFlags patEnv ty (SynConst.String(s, SynStringKind.Regular, m)) m | _ -> failwith "Impossible: TcNameOfExpr must return an Expr.Const of type string" | _ -> diff --git a/src/Compiler/Checking/Expressions/CheckExpressions.fs b/src/Compiler/Checking/Expressions/CheckExpressions.fs index d34d9cf2978..d80470b9e53 100644 --- a/src/Compiler/Checking/Expressions/CheckExpressions.fs +++ b/src/Compiler/Checking/Expressions/CheckExpressions.fs @@ -9265,6 +9265,12 @@ and TcValueItemThen cenv overallTy env vref tpenv mItem afterResolution delayed // Allow `nameof<'T>` for a generic parameter match vref with | _ when isNameOfValRef g vref && g.langVersion.SupportsFeature LanguageFeature.NameOf -> + // Record the resolution of the `nameof` usage so that we can classify it correctly later. + do + match afterResolution with + | AfterResolution.RecordResolution (_, callSink, _, _) -> callSink emptyTyparInst + | AfterResolution.DoNothing -> () + match tys with | [SynType.Var(SynTypar(id, _, false) as tp, _m)] -> let _tpR, tpenv = TcTypeOrMeasureParameter None cenv env ImplicitlyBoundTyparsAllowed.NoNewTypars tpenv tp diff --git a/vsintegration/tests/FSharp.Editor.Tests/SemanticClassificationServiceTests.fs b/vsintegration/tests/FSharp.Editor.Tests/SemanticClassificationServiceTests.fs index 64313dd6bd5..eae06773f68 100644 --- a/vsintegration/tests/FSharp.Editor.Tests/SemanticClassificationServiceTests.fs +++ b/vsintegration/tests/FSharp.Editor.Tests/SemanticClassificationServiceTests.fs @@ -43,8 +43,12 @@ type SemanticClassificationServiceTests() = match ranges |> List.tryFind (fun item -> Range.rangeContainsPos item.Range markerPos) with | None -> failwith "Cannot find colorization data for end of marker" | Some item -> - FSharpClassificationTypes.getClassificationTypeName item.Type - |> Assert.shouldBeEqualWith classificationType "Classification data doesn't match for end of marker" + let actual = FSharpClassificationTypes.getClassificationTypeName item.Type + + actual + |> Assert.shouldBeEqualWith + classificationType + $"Classification data doesn't match for end of marker: {classificationType} ≠ {actual} ({item.Type})" let verifyNoClassificationDataAtEndOfMarker (fileContents: string, marker: string, classificationType: string) = let text = SourceText.From(fileContents) @@ -183,3 +187,56 @@ let g() = """ verifyNoClassificationDataAtEndOfMarker (sourceText, marker, classificationType) + + [] + [] + [] + [] + [] + [] + [] + [] + [] + [] + [] + [] + [] + [] + [] + [] + [] + [] + [] + member _.``nameof ident, nameof<'T>, match … with nameof ident``(marker: string, classificationType: string) = + let sourceText = + """ +module ``Normal usage of nameof should show up as a keyword`` = + let f x = (*1*)nameof x + let g (x : 'T) = (*2*)nameof<'T> + let h x y = match x with (*3*)nameof y -> () | _ -> () + +module ``Redefined nameof should shadow the intrinsic one`` = + let a x = match x with (*4*)nameof -> () + let b (*5*)nameof = (*6*)nameof + let (*7*)nameof = "redefined" + let _ = (*8*)nameof + + type (*9*)nameof () = class end + let _ = (*10*)nameof () + let _ = new (*11*)nameof () + + module (*12*)nameof = + let f x = x + + let _ = (*13*)nameof.f 3 + + let c (x : '(*14*)nameof) = x + let d (x : (*15*)'nameof) = x + +module ``It should still show up as a keyword even if the type parameter is invalid`` = + let _ = (*16*)nameof<> + let a (x : 'a) (y : 'b) = (*17*)nameof<'c> // FS0039: The type parameter 'c is not defined. + let _ = (*18*)nameof // FS3250: Expression does not have a name. +""" + + verifyClassificationAtEndOfMarker (sourceText, marker, classificationType) From 2ea701e432b2d55332bbc1852416c99c34bcab2d Mon Sep 17 00:00:00 2001 From: Jakub Majocha <1760221+majocha@users.noreply.github.com> Date: Wed, 12 Feb 2025 17:44:19 +0100 Subject: [PATCH 25/29] Cancellable: hide UsingToken and simplify inlined run (#18309) * simplify * add comment * already shipped --- src/Compiler/Utilities/Cancellable.fs | 54 ++++++++++++++------------ src/Compiler/Utilities/Cancellable.fsi | 3 -- 2 files changed, 29 insertions(+), 28 deletions(-) diff --git a/src/Compiler/Utilities/Cancellable.fs b/src/Compiler/Utilities/Cancellable.fs index 9e40de9dd2d..20e220b7e9f 100644 --- a/src/Compiler/Utilities/Cancellable.fs +++ b/src/Compiler/Utilities/Cancellable.fs @@ -3,6 +3,16 @@ namespace FSharp.Compiler open System open System.Threading +// This code provides two methods for handling cancellation in synchronous code: +// 1. Explicitly, by calling Cancellable.CheckAndThrow(). +// 2. Implicitly, by wrapping the code in a cancellable computation. +// The cancellable computation propagates the CancellationToken and checks for cancellation implicitly. +// When it is impractical to use the cancellable computation, such as in deeply nested functions, Cancellable.CheckAndThrow() can be used. +// It checks a CancellationToken local to the current async execution context, held in AsyncLocal. +// Before calling Cancellable.CheckAndThrow(), this token must be set. +// The token is guaranteed to be set during execution of cancellable computation. +// Otherwise, it can be passed explicitly from the ambient async computation using Cancellable.UseToken(). + [] type Cancellable = static let tokenHolder = AsyncLocal() @@ -47,9 +57,7 @@ open System open System.Threading open FSharp.Compiler -#if !FSHARPCORE_USE_PACKAGE open FSharp.Core.CompilerServices.StateMachineHelpers -#endif [] type ValueOrCancelled<'TResult> = @@ -65,12 +73,7 @@ module Cancellable = if ct.IsCancellationRequested then ValueOrCancelled.Cancelled(OperationCanceledException ct) else - try - use _ = Cancellable.UsingToken(ct) - oper ct - with - | :? OperationCanceledException as e when ct.IsCancellationRequested -> ValueOrCancelled.Cancelled e - | :? OperationCanceledException as e -> InvalidOperationException("Wrong cancellation token", e) |> raise + oper ct let fold f acc seq = Cancellable(fun ct -> @@ -84,6 +87,7 @@ module Cancellable = acc) let runWithoutCancellation comp = + use _ = Cancellable.UsingToken CancellationToken.None let res = run CancellationToken.None comp match res with @@ -92,14 +96,19 @@ module Cancellable = let toAsync c = async { + use! _holder = Cancellable.UseToken() + let! ct = Async.CancellationToken - let res = run ct c return! - Async.FromContinuations(fun (cont, _econt, ccont) -> - match res with - | ValueOrCancelled.Value v -> cont v - | ValueOrCancelled.Cancelled ce -> ccont ce) + Async.FromContinuations(fun (cont, econt, ccont) -> + try + match run ct c with + | ValueOrCancelled.Value v -> cont v + | ValueOrCancelled.Cancelled ce -> ccont ce + with + | :? OperationCanceledException as ce when ct.IsCancellationRequested -> ccont ce + | :? OperationCanceledException as e -> InvalidOperationException("Wrong cancellation token", e) |> econt) } let token () = Cancellable(ValueOrCancelled.Value) @@ -113,9 +122,8 @@ type CancellableBuilder() = member inline _.Bind(comp, [] k) = Cancellable(fun ct -> -#if !FSHARPCORE_USE_PACKAGE + __debugPoint "" -#endif match Cancellable.run ct comp with | ValueOrCancelled.Value v1 -> Cancellable.run ct (k v1) @@ -123,9 +131,8 @@ type CancellableBuilder() = member inline _.BindReturn(comp, [] k) = Cancellable(fun ct -> -#if !FSHARPCORE_USE_PACKAGE + __debugPoint "" -#endif match Cancellable.run ct comp with | ValueOrCancelled.Value v1 -> ValueOrCancelled.Value(k v1) @@ -133,9 +140,8 @@ type CancellableBuilder() = member inline _.Combine(comp1, comp2) = Cancellable(fun ct -> -#if !FSHARPCORE_USE_PACKAGE + __debugPoint "" -#endif match Cancellable.run ct comp1 with | ValueOrCancelled.Value() -> Cancellable.run ct comp2 @@ -143,9 +149,8 @@ type CancellableBuilder() = member inline _.TryWith(comp, [] handler) = Cancellable(fun ct -> -#if !FSHARPCORE_USE_PACKAGE + __debugPoint "" -#endif let compRes = try @@ -164,9 +169,9 @@ type CancellableBuilder() = member inline _.Using(resource: _ MaybeNull, [] comp) = Cancellable(fun ct -> -#if !FSHARPCORE_USE_PACKAGE + __debugPoint "" -#endif + let body = comp resource let compRes = @@ -188,9 +193,8 @@ type CancellableBuilder() = member inline _.TryFinally(comp, [] compensation) = Cancellable(fun ct -> -#if !FSHARPCORE_USE_PACKAGE + __debugPoint "" -#endif let compRes = try diff --git a/src/Compiler/Utilities/Cancellable.fsi b/src/Compiler/Utilities/Cancellable.fsi index 72c098d2234..e74404c7eec 100644 --- a/src/Compiler/Utilities/Cancellable.fsi +++ b/src/Compiler/Utilities/Cancellable.fsi @@ -7,9 +7,6 @@ open System.Threading type Cancellable = static member internal UseToken: unit -> Async - /// For use in testing only. Cancellable.token should be set only by the cancellable computation. - static member internal UsingToken: CancellationToken -> IDisposable - static member HasCancellationToken: bool static member Token: CancellationToken From 898c6c7a5b39f6bc0cfb42c21e3fcc167b192ab4 Mon Sep 17 00:00:00 2001 From: Viktor Hofer Date: Fri, 14 Feb 2025 20:09:16 +0100 Subject: [PATCH 26/29] Contributes to https://github.com/dotnet/sdk/pull/46829 (#18318) NuGet added a new feature that automatically prunes package and project references that are provided by the shared framework that is targeted. Resolve the one warning that got emitted when building the repository in non-source-only mode. --- src/Compiler/FSharp.Compiler.Service.fsproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Compiler/FSharp.Compiler.Service.fsproj b/src/Compiler/FSharp.Compiler.Service.fsproj index b345d6ed1ca..493248a11d3 100644 --- a/src/Compiler/FSharp.Compiler.Service.fsproj +++ b/src/Compiler/FSharp.Compiler.Service.fsproj @@ -597,7 +597,7 @@ - + From a2f2b0057b153aab4b0afe558e4c5b303bebac06 Mon Sep 17 00:00:00 2001 From: Jakub Majocha <1760221+majocha@users.noreply.github.com> Date: Tue, 18 Feb 2025 12:23:44 +0100 Subject: [PATCH 27/29] do not share (#18326) --- tests/FSharp.Compiler.Service.Tests/TokenizerTests.fs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/FSharp.Compiler.Service.Tests/TokenizerTests.fs b/tests/FSharp.Compiler.Service.Tests/TokenizerTests.fs index d2c2a83139f..53b2127a833 100644 --- a/tests/FSharp.Compiler.Service.Tests/TokenizerTests.fs +++ b/tests/FSharp.Compiler.Service.Tests/TokenizerTests.fs @@ -4,8 +4,6 @@ open FSharp.Compiler.Tokenization open FSharp.Test open Xunit -let sourceTok = FSharpSourceTokenizer([], Some "C:\\test.fsx", None, None) - let rec parseLine(line: string, state: FSharpTokenizerLexState ref, tokenizer: FSharpLineTokenizer) = seq { match tokenizer.ScanToken(state.Value) with | Some(tok), nstate -> @@ -17,8 +15,10 @@ let rec parseLine(line: string, state: FSharpTokenizerLexState ref, tokenizer: F state.Value <- nstate } let tokenizeLines (lines:string[]) = + let sourceTok = FSharpSourceTokenizer([], Some "C:\\test.fsx", None, None) [ let state = ref FSharpTokenizerLexState.Initial for n, line in lines |> Seq.zip [ 0 .. lines.Length-1 ] do + let tokenizer = sourceTok.CreateLineTokenizer(line) yield n, parseLine(line, state, tokenizer) |> List.ofSeq ] From f939050eb1b6cde83eb71780127d38810d3d28d6 Mon Sep 17 00:00:00 2001 From: Tomas Grosup Date: Fri, 21 Feb 2025 12:05:10 +0100 Subject: [PATCH 28/29] Bugfix :: Nullness :: Allow nullable return type for first branches of match and ifthenelse expressions (#18322) --- .../.FSharp.Compiler.Service/9.0.300.md | 1 + .../Checking/Expressions/CheckExpressions.fs | 2 + .../Expressions/CheckExpressionsOps.fs | 5 ++ src/Compiler/TypedTree/TypedTreeOps.fs | 13 ++-- src/Compiler/TypedTree/TypedTreeOps.fsi | 2 + .../Nullness/NullableReferenceTypesTests.fs | 77 +++++++++++++++++++ 6 files changed, 95 insertions(+), 5 deletions(-) diff --git a/docs/release-notes/.FSharp.Compiler.Service/9.0.300.md b/docs/release-notes/.FSharp.Compiler.Service/9.0.300.md index f64f090744b..0b8957725cb 100644 --- a/docs/release-notes/.FSharp.Compiler.Service/9.0.300.md +++ b/docs/release-notes/.FSharp.Compiler.Service/9.0.300.md @@ -3,6 +3,7 @@ * Fix Realsig+ generates nested closures with incorrect Generic ([Issue #17797](https://github.com/dotnet/fsharp/issues/17797), [PR #17877](https://github.com/dotnet/fsharp/pull/17877)) * Fix optimizer internal error for records with static fields ([Issue #18165](https://github.com/dotnet/fsharp/issues/18165), [PR #18280](https://github.com/dotnet/fsharp/pull/18280)) * Fix nullness warning with flexible types ([Issue #18056](https://github.com/dotnet/fsharp/issues/18056), [PR #18266](https://github.com/dotnet/fsharp/pull/18266)) +* Allow first branches of match and if expressions to return nullable results ([Issue #18015](https://github.com/dotnet/fsharp/issues/18015), [PR #18322](https://github.com/dotnet/fsharp/pull/18322)) * Fix internal error when missing measure attribute in an unsolved measure typar. ([Issue #7491](https://github.com/dotnet/fsharp/issues/7491), [PR #18234](https://github.com/dotnet/fsharp/pull/18234)== * Set `Cancellable.token` from async computation ([Issue #18235](https://github.com/dotnet/fsharp/issues/18235), [PR #18238](https://github.com/dotnet/fsharp/pull/18238)) * Fix missing nullness warning when static upcast dropped nullness ([Issue #18232](https://github.com/dotnet/fsharp/issues/18232), [PR #18261](https://github.com/dotnet/fsharp/pull/18261)) diff --git a/src/Compiler/Checking/Expressions/CheckExpressions.fs b/src/Compiler/Checking/Expressions/CheckExpressions.fs index d80470b9e53..df64c4da62e 100644 --- a/src/Compiler/Checking/Expressions/CheckExpressions.fs +++ b/src/Compiler/Checking/Expressions/CheckExpressions.fs @@ -10634,6 +10634,7 @@ and TcLinearExprs bodyChecker cenv env overallTy tpenv isCompExpr synExpr cont = | Some synElseExpr -> let env = { env with eContextInfo = ContextInfo.ElseBranchResult synElseExpr.Range } + TryAllowFlexibleNullnessInControlFlow (*isFirst=*) true g overallTy.Commit // tailcall TcLinearExprs bodyChecker cenv env overallTy tpenv isCompExpr synElseExpr (fun (elseExpr, tpenv) -> let resExpr = primMkCond spIfToThen m overallTy.Commit boolExpr thenExpr elseExpr @@ -10697,6 +10698,7 @@ and TcMatchClause cenv inputTy (resultTy: OverallTy) env isFirst tpenv synMatchC | DebugPointAtTarget.No -> resultEnv let resultExpr, tpenv = TcExprThatCanBeCtorBody cenv resultTy resultEnv tpenv synResultExpr + TryAllowFlexibleNullnessInControlFlow isFirst cenv.g resultTy.Commit let target = TTarget(vspecs, resultExpr, None) diff --git a/src/Compiler/Checking/Expressions/CheckExpressionsOps.fs b/src/Compiler/Checking/Expressions/CheckExpressionsOps.fs index 3552b1345f7..4b9de82d758 100644 --- a/src/Compiler/Checking/Expressions/CheckExpressionsOps.fs +++ b/src/Compiler/Checking/Expressions/CheckExpressionsOps.fs @@ -18,6 +18,11 @@ open FSharp.Compiler.TypedTreeBasics open FSharp.Compiler.TypedTreeOps open FSharp.Compiler.SyntaxTreeOps +let TryAllowFlexibleNullnessInControlFlow isFirst (g: TcGlobals.TcGlobals) ty = + match isFirst, g.checkNullness, GetTyparTyIfSupportsNull g ty with + | true, true, ValueSome tp -> tp.SetSupportsNullFlex(true) + | _ -> () + let CopyAndFixupTypars g m rigid tpsorig = FreshenAndFixupTypars g m rigid [] [] tpsorig diff --git a/src/Compiler/TypedTree/TypedTreeOps.fs b/src/Compiler/TypedTree/TypedTreeOps.fs index f83e48a7c8f..4cabe94d952 100644 --- a/src/Compiler/TypedTree/TypedTreeOps.fs +++ b/src/Compiler/TypedTree/TypedTreeOps.fs @@ -9171,11 +9171,14 @@ let isReferenceTyparTy g ty = | ValueNone -> false -let isSupportsNullTyparTy g ty = +let GetTyparTyIfSupportsNull g ty = if isReferenceTyparTy g ty then - (destTyparTy g ty).Constraints |> List.exists (function TyparConstraint.SupportsNull _ -> true | _ -> false) + let tp = destTyparTy g ty + if tp.Constraints |> List.exists (function TyparConstraint.SupportsNull _ -> true | _ -> false) then + ValueSome tp + else ValueNone else - false + ValueNone let TypeNullNever g ty = let underlyingTy = stripTyEqnsAndMeasureEqns g ty @@ -9203,7 +9206,7 @@ let TypeNullIsExtraValue g m ty = | ValueNone -> // Consider type parameters - isSupportsNullTyparTy g ty + (GetTyparTyIfSupportsNull g ty).IsSome // Any mention of a type with AllowNullLiteral(true) is considered to be with-null let intrinsicNullnessOfTyconRef g (tcref: TyconRef) = @@ -9317,7 +9320,7 @@ let TypeNullIsExtraValueNew g m ty = | NullnessInfo.WithNull -> true) || // Check if the type has a ': null' constraint - isSupportsNullTyparTy g ty + (GetTyparTyIfSupportsNull g ty).IsSome /// The pre-nullness logic about whether a type uses 'null' as a true representation value let TypeNullIsTrueValue g ty = diff --git a/src/Compiler/TypedTree/TypedTreeOps.fsi b/src/Compiler/TypedTree/TypedTreeOps.fsi index 932e465b0e9..7e98ce5bc78 100755 --- a/src/Compiler/TypedTree/TypedTreeOps.fsi +++ b/src/Compiler/TypedTree/TypedTreeOps.fsi @@ -1829,6 +1829,8 @@ val TypeHasAllowNull: TyconRef -> TcGlobals -> range -> bool val TypeNullIsExtraValueNew: TcGlobals -> range -> TType -> bool +val GetTyparTyIfSupportsNull: TcGlobals -> TType -> Typar voption + val TypeNullNever: TcGlobals -> TType -> bool val TypeHasDefaultValue: TcGlobals -> range -> TType -> bool diff --git a/tests/FSharp.Compiler.ComponentTests/Language/Nullness/NullableReferenceTypesTests.fs b/tests/FSharp.Compiler.ComponentTests/Language/Nullness/NullableReferenceTypesTests.fs index 018b81c9384..ad4788aa0ce 100644 --- a/tests/FSharp.Compiler.ComponentTests/Language/Nullness/NullableReferenceTypesTests.fs +++ b/tests/FSharp.Compiler.ComponentTests/Language/Nullness/NullableReferenceTypesTests.fs @@ -146,6 +146,83 @@ let doNotWarnOnDowncastRepeatedNestedNullable(o:objnull) = o :? list<((AB | null Error 3060, Line 7, Col 51, Line 7, Col 97, "This type test or downcast will erase the provided type 'List | null' to the type 'List'"] +[] +let ``Can infer nullable type if first match handler returns null`` () = + FSharp """module TestLib + +let myFunc x = + match x with + | 0 -> null + | i -> "x" + """ + |> asLibrary + |> typeCheckWithStrictNullness + |> shouldSucceed + +[] +let ``Can NOT infer nullable type if second match handler returns null`` () = + FSharp """module TestLib + +let myFunc x defaultValue = + match x with + | 0 -> defaultValue + | 1 -> null + | i -> "y" + """ + |> asLibrary + |> typeCheckWithStrictNullness + |> shouldFail + |> withDiagnostics [Error 3261, Line 7, Col 12, Line 7, Col 15, "Nullness warning: The type 'string' does not support 'null'.. See also test.fs(7,11)-(7,14)."] + +[] +let ``Can infer nullable type if first match handler returns masked null`` () = + FSharp """module TestLib + +let thisIsNull : string|null = null +let myFunc x = + match x with + | 0 -> thisIsNull + | i -> "x" + """ + |> asLibrary + |> typeCheckWithStrictNullness + |> shouldSucceed + +[] +let ``Can infer nullable type from first branch of ifthenelse`` () = + FSharp """module TestLib + +let myFunc x = + if x = 0 then null else "x" + """ + |> asLibrary + |> typeCheckWithStrictNullness + |> shouldSucceed + +[] +let ``Can NOT infer nullable type from second branch of ifthenelse`` () = + FSharp """module TestLib + +let myFunc x = + if x = 0 then "x" else null + """ + |> asLibrary + |> typeCheckWithStrictNullness + |> shouldFail + |> withDiagnostics [Error 3261, Line 4, Col 28, Line 4, Col 32, "Nullness warning: The type 'string' does not support 'null'."] + +[] +let ``Can NOT infer nullable type from second branch of nested elifs`` () = + FSharp """module TestLib + +let myFunc x = + if x = 0 then "x" elif x=1 then null else "y" + """ + |> asLibrary + |> typeCheckWithStrictNullness + |> shouldFail + |> withDiagnostics [Error 3261, Line 4, Col 37, Line 4, Col 41, "Nullness warning: The type 'string' does not support 'null'."] + [] let ``Can convert generic value to objnull arg`` () = FSharp """module TestLib From 27db996c58a511386ad754e34f4b57877aa1d99e Mon Sep 17 00:00:00 2001 From: Tomas Grosup Date: Fri, 21 Feb 2025 12:08:48 +0100 Subject: [PATCH 29/29] Bugfix for breaking change when using Option.ofObj :: Type parameter constraint `null` implies `not struct` (#18323) --- .../release-notes/.FSharp.Compiler.Service/9.0.300.md | 1 + src/Compiler/Checking/ConstraintSolver.fs | 2 ++ src/Compiler/CodeGen/IlxGen.fs | 1 + .../EmittedIL/Nullness/SupportsNull.fs | 1 + .../Language/Nullness/NullableReferenceTypesTests.fs | 11 +++++++++++ 5 files changed, 16 insertions(+) diff --git a/docs/release-notes/.FSharp.Compiler.Service/9.0.300.md b/docs/release-notes/.FSharp.Compiler.Service/9.0.300.md index 0b8957725cb..da9198c332c 100644 --- a/docs/release-notes/.FSharp.Compiler.Service/9.0.300.md +++ b/docs/release-notes/.FSharp.Compiler.Service/9.0.300.md @@ -18,6 +18,7 @@ * Add support for C# `Experimental` attribute. ([PR #18253](https://github.com/dotnet/fsharp/pull/18253)) * Nullness warnings are issued for signature<>implementation conformance ([PR #18186](https://github.com/dotnet/fsharp/pull/18186)) * Symbols: Add FSharpAssembly.IsFSharp ([PR #18290](https://github.com/dotnet/fsharp/pull/18290)) +* Type parameter constraint `null` in generic code will now automatically imply `not struct` ([Issue #18320](https://github.com/dotnet/fsharp/issues/18320), [PR #18323](https://github.com/dotnet/fsharp/pull/18323)) ### Changed diff --git a/src/Compiler/Checking/ConstraintSolver.fs b/src/Compiler/Checking/ConstraintSolver.fs index 50026fe382a..2578107176d 100644 --- a/src/Compiler/Checking/ConstraintSolver.fs +++ b/src/Compiler/Checking/ConstraintSolver.fs @@ -2478,6 +2478,8 @@ and CheckConstraintImplication (csenv: ConstraintSolverEnv) tpc1 tpc2 = | TyparConstraint.SupportsEquality _, TyparConstraint.SupportsEquality _ // comparison implies equality | TyparConstraint.SupportsComparison _, TyparConstraint.SupportsEquality _ + // 'null' implies reference type ('not struct') + | TyparConstraint.SupportsNull _, TyparConstraint.IsReferenceType _ | TyparConstraint.SupportsNull _, TyparConstraint.SupportsNull _ | TyparConstraint.NotSupportsNull _, TyparConstraint.NotSupportsNull _ | TyparConstraint.IsNonNullableStruct _, TyparConstraint.IsNonNullableStruct _ diff --git a/src/Compiler/CodeGen/IlxGen.fs b/src/Compiler/CodeGen/IlxGen.fs index 53cfb3e77cd..1faeaddf82f 100644 --- a/src/Compiler/CodeGen/IlxGen.fs +++ b/src/Compiler/CodeGen/IlxGen.fs @@ -5679,6 +5679,7 @@ and GenGenericParam cenv eenv (tp: Typar) = tp.Constraints |> List.exists (function | TyparConstraint.IsReferenceType _ + // 'null' automatically implies 'not struct' | TyparConstraint.SupportsNull _ -> true | _ -> false) diff --git a/tests/FSharp.Compiler.ComponentTests/EmittedIL/Nullness/SupportsNull.fs b/tests/FSharp.Compiler.ComponentTests/EmittedIL/Nullness/SupportsNull.fs index 0e2484fa142..fd107853ce4 100644 --- a/tests/FSharp.Compiler.ComponentTests/EmittedIL/Nullness/SupportsNull.fs +++ b/tests/FSharp.Compiler.ComponentTests/EmittedIL/Nullness/SupportsNull.fs @@ -26,6 +26,7 @@ let iAcceptNullWithNullAnnotation(arg: 'a | null when 'a: not struct) = else 0 +// This test case emits the `class T` constraint in IL let iAcceptNullExplicitAnnotation(arg: 'T when 'T:null) = if isNull arg then 1 diff --git a/tests/FSharp.Compiler.ComponentTests/Language/Nullness/NullableReferenceTypesTests.fs b/tests/FSharp.Compiler.ComponentTests/Language/Nullness/NullableReferenceTypesTests.fs index ad4788aa0ce..50467c12e0a 100644 --- a/tests/FSharp.Compiler.ComponentTests/Language/Nullness/NullableReferenceTypesTests.fs +++ b/tests/FSharp.Compiler.ComponentTests/Language/Nullness/NullableReferenceTypesTests.fs @@ -17,6 +17,17 @@ let typeCheckWithStrictNullness cu = |> withNullnessOptions |> typecheck + +[] +let ``Can imply notstruct for classconstraint`` () = + FSharp """module Foo = + let failIfNull<'a when 'a : null> (a : 'a) : 'a option = + (a |> Option.ofObj) + """ + |> asLibrary + |> typecheck // This has nullable off! + |> shouldSucceed + [] let ``Warning on nullness hidden behind interface upcast`` () = FSharp """module Test