diff --git a/src/Compiler/Facilities/LanguageFeatures.fs b/src/Compiler/Facilities/LanguageFeatures.fs index e72782ccf2b..c4b3661bac7 100644 --- a/src/Compiler/Facilities/LanguageFeatures.fs +++ b/src/Compiler/Facilities/LanguageFeatures.fs @@ -236,10 +236,10 @@ type LanguageVersion(versionText) = LanguageFeature.BetterAnonymousRecordParsing, languageVersion100 LanguageFeature.ScopedNowarn, languageVersion100 LanguageFeature.AllowTypedLetOrUseBang, languageVersion100 + LanguageFeature.UnmanagedConstraintCsharpInterop, languageVersion100 LanguageFeature.AllowAccessModifiersToAutoPropertiesGettersAndSetters, languageVersion100 // F# preview (still preview in 10.0) - LanguageFeature.UnmanagedConstraintCsharpInterop, previewVersion // not enabled because: https://github.com/dotnet/fsharp/issues/17509 LanguageFeature.FromEndSlicing, previewVersion // Unfinished features --- needs work ] diff --git a/src/Compiler/TypedTree/TypedTreeOps.fs b/src/Compiler/TypedTree/TypedTreeOps.fs index b14dbd753b1..368dd9a99ce 100644 --- a/src/Compiler/TypedTree/TypedTreeOps.fs +++ b/src/Compiler/TypedTree/TypedTreeOps.fs @@ -9970,6 +9970,7 @@ let isCompiledOrWitnessPassingConstraint (g: TcGlobals) cx = | TyparConstraint.IsNonNullableStruct _ | TyparConstraint.IsReferenceType _ | TyparConstraint.RequiresDefaultConstructor _ + | TyparConstraint.IsUnmanaged _ // implies "struct" and also causes a modreq | TyparConstraint.CoercesTo _ -> true | TyparConstraint.MayResolveMember _ when g.langVersion.SupportsFeature LanguageFeature.WitnessPassing -> true | _ -> false diff --git a/tests/FSharp.Compiler.ComponentTests/Conformance/Constraints/Unmanaged.fs b/tests/FSharp.Compiler.ComponentTests/Conformance/Constraints/Unmanaged.fs index 5b9af3c8f20..173f18537a5 100644 --- a/tests/FSharp.Compiler.ComponentTests/Conformance/Constraints/Unmanaged.fs +++ b/tests/FSharp.Compiler.ComponentTests/Conformance/Constraints/Unmanaged.fs @@ -471,21 +471,72 @@ printf "%s" (CsharpStruct.Hi()) IL_0000: ret } """] - [] - let ``FSharp does not generate modreq for VBNET to consume in v7`` () = + [] + let ``FSharp generates modreq for CSharp to consume in v9`` () = Fsx "let testMyFunction (x: 'TUnmanaged when 'TUnmanaged : unmanaged) = ()" - |> withLangVersion70 + |> withLangVersion10 |> compile |> shouldSucceed |> verifyIL [""" - .method public static void testMyFunction(!!TUnmanaged x) cil managed + .method public static void testMyFunction(!!TUnmanaged x) cil managed { + .param type TUnmanaged + .custom instance void [runtime]System.Runtime.CompilerServices.IsUnmanagedAttribute::.ctor() = ( 01 00 00 00 ) .maxstack 8 IL_0000: ret } """] + [] + let ``Unmanaged constraint in lambda reproduces issue 17509`` () = + // This test reproduces the issue https://github.com/dotnet/fsharp/issues/17509 + // When UnmanagedConstraintCsharpInterop is enabled, it generates invalid IL + // causing a TypeLoadException at runtime + Fsx """ +open System + +let printTypeConstraintsNative<'T when 'T : unmanaged> () = printf $"Hello: {typeof<'T>.FullName} is unmanaged" + +let Main() = + let func (x:int) : 'T when 'T : unmanaged = Unchecked.defaultof<'T> + let initFinite = Seq.init 3 func + printf "%A" initFinite + +printTypeConstraintsNative() +Main() + """ + |> withLangVersionPreview + |> asExe + |> compileAndRun + |> shouldSucceed + |> verifyOutput "Hello: System.IntPtr is unmanagedseq [0n; 0n; 0n]" + + [] + let ``Unmanaged constraint in lambda generates invalid IL for Specialize method with preview version`` () = + Fsx """ +let Main() = + let func (x:int) : 'T when 'T : unmanaged = Unchecked.defaultof<'T> + let initFinite = Seq.init 3 func + printfn "%A" initFinite +Main() + """ + |> withLangVersionPreview + |> asExe + |> compile + |> shouldSucceed + |> verifyIL [""" + .method assembly strict virtual instance class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2 DirectInvoke() cil managed + { + .param type T + .custom instance void [runtime]System.Runtime.CompilerServices.IsUnmanagedAttribute::.ctor() = ( 01 00 00 00 ) + + .maxstack 8 + IL_0000: ldsfld class Test/'func@3-1' class Test/'func@3-1'::@_instance + IL_0005: ret + } """] + + [] let ``C# can consume F#-defined struct with unmanaged constraint - valid`` () = let fsharpLib =