Skip to content

Commit 4afdc9f

Browse files
authored
Eenable LanguageFeature.UnmanagedConstraintCsharpInterop for F# 10.0 (#18737)
1 parent 0fff0de commit 4afdc9f

File tree

3 files changed

+57
-5
lines changed

3 files changed

+57
-5
lines changed

src/Compiler/Facilities/LanguageFeatures.fs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -236,10 +236,10 @@ type LanguageVersion(versionText) =
236236
LanguageFeature.BetterAnonymousRecordParsing, languageVersion100
237237
LanguageFeature.ScopedNowarn, languageVersion100
238238
LanguageFeature.AllowTypedLetOrUseBang, languageVersion100
239+
LanguageFeature.UnmanagedConstraintCsharpInterop, languageVersion100
239240
LanguageFeature.AllowAccessModifiersToAutoPropertiesGettersAndSetters, languageVersion100
240241

241242
// F# preview (still preview in 10.0)
242-
LanguageFeature.UnmanagedConstraintCsharpInterop, previewVersion // not enabled because: https://github.com/dotnet/fsharp/issues/17509
243243
LanguageFeature.FromEndSlicing, previewVersion // Unfinished features --- needs work
244244
]
245245

src/Compiler/TypedTree/TypedTreeOps.fs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9970,6 +9970,7 @@ let isCompiledOrWitnessPassingConstraint (g: TcGlobals) cx =
99709970
| TyparConstraint.IsNonNullableStruct _
99719971
| TyparConstraint.IsReferenceType _
99729972
| TyparConstraint.RequiresDefaultConstructor _
9973+
| TyparConstraint.IsUnmanaged _ // implies "struct" and also causes a modreq
99739974
| TyparConstraint.CoercesTo _ -> true
99749975
| TyparConstraint.MayResolveMember _ when g.langVersion.SupportsFeature LanguageFeature.WitnessPassing -> true
99759976
| _ -> false

tests/FSharp.Compiler.ComponentTests/Conformance/Constraints/Unmanaged.fs

Lines changed: 55 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -471,21 +471,72 @@ printf "%s" (CsharpStruct<int>.Hi<MultiCaseUnion>())
471471
IL_0000: ret
472472
} """]
473473

474-
[<Fact>]
475-
let ``FSharp does not generate modreq for VBNET to consume in v7`` () =
474+
[<FactForNETCOREAPP>]
475+
let ``FSharp generates modreq for CSharp to consume in v9`` () =
476476
Fsx "let testMyFunction (x: 'TUnmanaged when 'TUnmanaged : unmanaged) = ()"
477-
|> withLangVersion70
477+
|> withLangVersion10
478478
|> compile
479479
|> shouldSucceed
480480
|> verifyIL ["""
481-
.method public static void testMyFunction<TUnmanaged>(!!TUnmanaged x) cil managed
481+
.method public static void testMyFunction<valuetype (class [runtime]System.ValueType modreq([runtime]System.Runtime.InteropServices.UnmanagedType)) TUnmanaged>(!!TUnmanaged x) cil managed
482482
{
483+
.param type TUnmanaged
484+
.custom instance void [runtime]System.Runtime.CompilerServices.IsUnmanagedAttribute::.ctor() = ( 01 00 00 00 )
483485
484486
.maxstack 8
485487
IL_0000: ret
486488
} """]
487489

488490

491+
[<Fact>]
492+
let ``Unmanaged constraint in lambda reproduces issue 17509`` () =
493+
// This test reproduces the issue https://github.com/dotnet/fsharp/issues/17509
494+
// When UnmanagedConstraintCsharpInterop is enabled, it generates invalid IL
495+
// causing a TypeLoadException at runtime
496+
Fsx """
497+
open System
498+
499+
let printTypeConstraintsNative<'T when 'T : unmanaged> () = printf $"Hello: {typeof<'T>.FullName} is unmanaged"
500+
501+
let Main() =
502+
let func (x:int) : 'T when 'T : unmanaged = Unchecked.defaultof<'T>
503+
let initFinite = Seq.init<nativeint> 3 func
504+
printf "%A" initFinite
505+
506+
printTypeConstraintsNative<nativeint>()
507+
Main()
508+
"""
509+
|> withLangVersionPreview
510+
|> asExe
511+
|> compileAndRun
512+
|> shouldSucceed
513+
|> verifyOutput "Hello: System.IntPtr is unmanagedseq [0n; 0n; 0n]"
514+
515+
[<FactForNETCOREAPP>]
516+
let ``Unmanaged constraint in lambda generates invalid IL for Specialize method with preview version`` () =
517+
Fsx """
518+
let Main() =
519+
let func (x:int) : 'T when 'T : unmanaged = Unchecked.defaultof<'T>
520+
let initFinite = Seq.init<nativeint> 3 func
521+
printfn "%A" initFinite
522+
Main()
523+
"""
524+
|> withLangVersionPreview
525+
|> asExe
526+
|> compile
527+
|> shouldSucceed
528+
|> verifyIL ["""
529+
.method assembly strict virtual instance class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2<int32,!!T> DirectInvoke<valuetype (class [runtime]System.ValueType modreq([runtime]System.Runtime.InteropServices.UnmanagedType)) T>() cil managed
530+
{
531+
.param type T
532+
.custom instance void [runtime]System.Runtime.CompilerServices.IsUnmanagedAttribute::.ctor() = ( 01 00 00 00 )
533+
534+
.maxstack 8
535+
IL_0000: ldsfld class Test/'func@3-1'<!0> class Test/'func@3-1'<!!T>::@_instance
536+
IL_0005: ret
537+
} """]
538+
539+
489540
[<Fact>]
490541
let ``C# can consume F#-defined struct with unmanaged constraint - valid`` () =
491542
let fsharpLib =

0 commit comments

Comments
 (0)