From 86dc9ebf88057977da080517996a8a47b4d1faf2 Mon Sep 17 00:00:00 2001 From: David Naylor Date: Mon, 8 Apr 2024 08:58:18 +0200 Subject: [PATCH 01/10] Fix calling virtual static methods via interface --- src/Compiler/Checking/MethodCalls.fs | 4 +-- .../Interop/StaticsInInterfaces.fs | 30 +++++++++++++++++++ 2 files changed, 32 insertions(+), 2 deletions(-) diff --git a/src/Compiler/Checking/MethodCalls.fs b/src/Compiler/Checking/MethodCalls.fs index 5f60bfce120..47342714394 100644 --- a/src/Compiler/Checking/MethodCalls.fs +++ b/src/Compiler/Checking/MethodCalls.fs @@ -906,8 +906,8 @@ let IsBaseCall objArgs = /// For example, when calling an interface method on a struct, or a method on a constrained /// variable type. let ComputeConstrainedCallInfo g amap m staticTyOpt args (minfo: MethInfo) = - match args, staticTyOpt with - | _, Some staticTy when not minfo.IsExtensionMember && not minfo.IsInstance && minfo.IsAbstract -> Some staticTy + match args, staticTyOpt with + | _, Some staticTy when not minfo.IsExtensionMember && not minfo.IsInstance && (minfo.IsAbstract || minfo.IsVirtual) -> Some staticTy | (objArgExpr :: _), _ when minfo.IsInstance && not minfo.IsExtensionMember -> let methObjTy = minfo.ApparentEnclosingType diff --git a/tests/FSharp.Compiler.ComponentTests/Interop/StaticsInInterfaces.fs b/tests/FSharp.Compiler.ComponentTests/Interop/StaticsInInterfaces.fs index b16f787ba23..f8175f85d1d 100644 --- a/tests/FSharp.Compiler.ComponentTests/Interop/StaticsInInterfaces.fs +++ b/tests/FSharp.Compiler.ComponentTests/Interop/StaticsInInterfaces.fs @@ -606,6 +606,36 @@ module Test = #endif ] + [] + let ``F# can call overwritten static virtual member from interface``() = + let CSharpLib = + CSharp """ +namespace Test; + +public interface I +{ + static virtual string Echo(string x) => x; +} + """ + |> withCSharpLanguageVersion CSharpLanguageVersion.CSharp11 + |> withName "CsLibAssembly" + + FSharp """ +type Imp() = + interface Test.I with + static member Echo (x: string) = x + "_imp" + +let echo<'T when 'T :> Test.I> x = 'T.Echo(x) + +if echo "a" <> "a_imp" then + failwith "incorrect value" +""" + |> withReferences [CSharpLib] + |> withLangVersion80 + |> asExe + |> compileAndRun + |> shouldSucceed + [] let ``C# can call constrained method defined in F#`` () = let FSharpLib = From 47757a7b39bdbecf291c898d164c25dceb50d23c Mon Sep 17 00:00:00 2001 From: David Naylor Date: Mon, 8 Apr 2024 08:59:30 +0200 Subject: [PATCH 02/10] InterfaceTests: fix test label and minor code cleanup --- .../Language/InterfaceTests.fs | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/tests/FSharp.Compiler.ComponentTests/Language/InterfaceTests.fs b/tests/FSharp.Compiler.ComponentTests/Language/InterfaceTests.fs index 261a8d9ef4c..181c7ea3bba 100644 --- a/tests/FSharp.Compiler.ComponentTests/Language/InterfaceTests.fs +++ b/tests/FSharp.Compiler.ComponentTests/Language/InterfaceTests.fs @@ -4,8 +4,8 @@ open Xunit open FSharp.Test.Compiler [] -let ``Concrete instance method is not allowed in interfaces in lang preview``() = - FSharp $""" +let ``Concrete instance method is not allowed in interfaces in lang version80``() = + FSharp """ [] type I = member _.X () = 1 @@ -18,8 +18,8 @@ type I = ] [] -let ``Concrete instance property is not allowed in interfaces in lang preview``() = - FSharp $""" +let ``Concrete instance property is not allowed in interfaces in lang version80``() = + FSharp """ [] type I = member _.Prop = "x" @@ -32,8 +32,8 @@ type I = ] [] -let ``Concrete static members are allowed in interfaces in lang preview``() = - FSharp $""" +let ``Concrete static members are allowed in interfaces in lang version80``() = + FSharp """ [] type I<'T> = static member Echo (x: 'T) = x @@ -49,7 +49,7 @@ if I.Echo 42 <> 42 || I.Prop <> 0 || not (isNull I.Prop) then [] let ``Concrete static members are not allowed in interfaces in lang version70``() = - FSharp $""" + FSharp """ [] type I<'T> = static member Echo (x: 'T) = x @@ -63,8 +63,8 @@ type I<'T> = ] [] -let ``Concrete static members are allowed in interfaces as intrinsics in lang preview``() = - FSharp $""" +let ``Concrete static members are allowed in interfaces as intrinsics in lang version80``() = + FSharp """ [] type I<'T> = static member Prop = Unchecked.defaultof<'T> @@ -81,8 +81,8 @@ if I.Echo 42 <> 42 || I.Prop <> 0 || not (isNull I.Prop) then [] -let ``Interface with concrete static members can be implemented in lang preview``() = - FSharp $""" +let ``Interface with concrete static members can be implemented in lang version80``() = + FSharp """ [] type I = static member Echo (x: string) = x From e86b94d3ad9926a2a6addc3f68264df0552c743e Mon Sep 17 00:00:00 2001 From: David Naylor Date: Tue, 9 Apr 2024 19:13:36 +0200 Subject: [PATCH 03/10] 8.0.300: add fix to release notes --- docs/release-notes/.FSharp.Compiler.Service/8.0.300.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/release-notes/.FSharp.Compiler.Service/8.0.300.md b/docs/release-notes/.FSharp.Compiler.Service/8.0.300.md index 42793d26880..0e89b92c085 100644 --- a/docs/release-notes/.FSharp.Compiler.Service/8.0.300.md +++ b/docs/release-notes/.FSharp.Compiler.Service/8.0.300.md @@ -29,6 +29,7 @@ * Enforce AttributeTargets on delegates ([PR #16891](https://github.com/dotnet/fsharp/pull/16891)) * Completion: fix completion in empty dot lambda prefix ([#16829](https://github.com/dotnet/fsharp/pull/16829)) * Fix StackOverflow when checking non-recursive bindings in module or namespace in `fscAnyCpu`/`fsiAnyCpu`. ([PR #16908](https://github.com/dotnet/fsharp/pull/16908)) +* Fix calling an overridden virtual static method via the interface ([PR #17013](https://github.com/dotnet/fsharp/pull/17013)) ### Added From 9071990a04cd7c4976c867b5b9fcea21e3ffe588 Mon Sep 17 00:00:00 2001 From: David Naylor Date: Tue, 9 Apr 2024 20:00:37 +0200 Subject: [PATCH 04/10] InterfaceTests: fix braces in quoted code --- .../FSharp.Compiler.ComponentTests/Language/InterfaceTests.fs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/FSharp.Compiler.ComponentTests/Language/InterfaceTests.fs b/tests/FSharp.Compiler.ComponentTests/Language/InterfaceTests.fs index 181c7ea3bba..645bcfd800b 100644 --- a/tests/FSharp.Compiler.ComponentTests/Language/InterfaceTests.fs +++ b/tests/FSharp.Compiler.ComponentTests/Language/InterfaceTests.fs @@ -92,7 +92,7 @@ type Imp () = interface I with member _.Blah = 3 -let o = {{ new I with member _.Blah = 4 }} +let o = { new I with member _.Blah = 4 } if I.Echo "yup" <> "yup" || (Imp() :> I).Blah <> 3 || o.Blah <> 4 then failwith "failed" @@ -100,4 +100,4 @@ if I.Echo "yup" <> "yup" || (Imp() :> I).Blah <> 3 || o.Blah <> 4 then |> withLangVersion80 |> asExe |> compileAndRun - |> shouldSucceed \ No newline at end of file + |> shouldSucceed From b16cf83519b36c5e4f537eaa53bd88de1ae7f7d7 Mon Sep 17 00:00:00 2001 From: David Naylor Date: Thu, 11 Apr 2024 06:16:38 +0200 Subject: [PATCH 05/10] StaticsInInterfaces: clarify test cases on virtual static --- .../Interop/StaticsInInterfaces.fs | 158 +++++++++--------- 1 file changed, 80 insertions(+), 78 deletions(-) diff --git a/tests/FSharp.Compiler.ComponentTests/Interop/StaticsInInterfaces.fs b/tests/FSharp.Compiler.ComponentTests/Interop/StaticsInInterfaces.fs index f8175f85d1d..0fbd4db3dd8 100644 --- a/tests/FSharp.Compiler.ComponentTests/Interop/StaticsInInterfaces.fs +++ b/tests/FSharp.Compiler.ComponentTests/Interop/StaticsInInterfaces.fs @@ -12,7 +12,7 @@ module ``Static Methods In Interfaces`` = | CS cs -> CS { cs with LangVersion = ver } | _ -> failwith "Only supported in C#" - let csharpBaseClass = + let csharpBaseClass = CSharp """ namespace StaticsInInterfaces { @@ -38,7 +38,7 @@ module ``Static Methods In Interfaces`` = }""" |> withCSharpLanguageVersion CSharpLanguageVersion.Preview |> withName "csLib" - + let csharpOperators = CSharp """ namespace StaticsInInterfaces @@ -110,7 +110,7 @@ let main _ = [] let ``F# can call static methods declared in interfaces from C#`` () = - let csharpLib = csharpBaseClass + let csharpLib = csharpBaseClass let fsharpSource = """ @@ -145,18 +145,18 @@ let main _ = .class interface public auto ansi abstract IGetNext`1<(class IGetNext`1) T> { // Methods - .method public hidebysig abstract virtual static + .method public hidebysig abstract virtual static !T Next ( !T other - ) cil managed + ) cil managed { } // end of method IGetNext`1::Next } // end of class IGetNext`1 And the following implementation: - .method public hidebysig static - class RepeatSequence Next (class RepeatSequence other) cil managed + .method public hidebysig static + class RepeatSequence Next (class RepeatSequence other) cil managed { .override method !0 class IGetNext`1::Next(!0) ... @@ -165,11 +165,11 @@ let main _ = [] let ``F# generates valid IL for abstract static interface methods`` () = - let csharpLib = csharpBaseClass + let csharpLib = csharpBaseClass let fsharpSource = """ -module StaticsTesting +module StaticsTesting open StaticsInInterfaces type MyRepeatSequence() = @@ -192,69 +192,69 @@ type MyRepeatSequence2() = extends [runtime]System.Object implements class [csLib]StaticsInInterfaces.IGetNext`1 { - .custom instance void [FSharp.Core]Microsoft.FSharp.Core.CompilationMappingAttribute::.ctor(valuetype [FSharp.Core]Microsoft.FSharp.Core.SourceConstructFlags) = ( 01 00 03 00 00 00 00 00 ) + .custom instance void [FSharp.Core]Microsoft.FSharp.Core.CompilationMappingAttribute::.ctor(valuetype [FSharp.Core]Microsoft.FSharp.Core.SourceConstructFlags) = ( 01 00 03 00 00 00 00 00 ) .method public specialname rtspecialname instance void .ctor() cil managed { - + .maxstack 8 IL_0000: ldarg.0 IL_0001: callvirt instance void [runtime]System.Object::.ctor() IL_0006: ldarg.0 IL_0007: pop IL_0008: ret - } - + } + .method public hidebysig static class StaticsTesting/MyRepeatSequence 'StaticsInInterfaces.IGetNext.Next'(class StaticsTesting/MyRepeatSequence other) cil managed { .override method !0 class [csLib]StaticsInInterfaces.IGetNext`1::Next(!0) - + .maxstack 8 IL_0000: ldarg.0 IL_0001: ret - } - - } - + } + + } + .class auto ansi serializable nested public MyRepeatSequence2 extends [runtime]System.Object implements class [csLib]StaticsInInterfaces.IGetNext`1 { - .custom instance void [FSharp.Core]Microsoft.FSharp.Core.CompilationMappingAttribute::.ctor(valuetype [FSharp.Core]Microsoft.FSharp.Core.SourceConstructFlags) = ( 01 00 03 00 00 00 00 00 ) + .custom instance void [FSharp.Core]Microsoft.FSharp.Core.CompilationMappingAttribute::.ctor(valuetype [FSharp.Core]Microsoft.FSharp.Core.SourceConstructFlags) = ( 01 00 03 00 00 00 00 00 ) .method public specialname rtspecialname instance void .ctor() cil managed { - + .maxstack 8 IL_0000: ldarg.0 IL_0001: callvirt instance void [runtime]System.Object::.ctor() IL_0006: ldarg.0 IL_0007: pop IL_0008: ret - } - + } + .method public static class StaticsTesting/MyRepeatSequence2 Next(class StaticsTesting/MyRepeatSequence2 other) cil managed { - + .maxstack 8 IL_0000: ldarg.0 IL_0001: ret - } - + } + .method public hidebysig static class StaticsTesting/MyRepeatSequence2 'StaticsInInterfaces.IGetNext.Next'(class StaticsTesting/MyRepeatSequence2 other) cil managed { .override method !0 class [csLib]StaticsInInterfaces.IGetNext`1::Next(!0) - + .maxstack 8 IL_0000: ldarg.0 IL_0001: ret - } - + } + } """] - + [] let ``F# can implement static methods declared in interfaces from C#`` () = - let csharpLib = csharpBaseClass + let csharpLib = csharpBaseClass let fsharpSource = """ @@ -376,28 +376,28 @@ module Test = .class public abstract auto ansi sealed Tests.Test extends [runtime]System.Object { - .custom instance void [FSharp.Core]Microsoft.FSharp.Core.CompilationMappingAttribute::.ctor(valuetype [FSharp.Core]Microsoft.FSharp.Core.SourceConstructFlags) = ( 01 00 07 00 00 00 00 00 ) + .custom instance void [FSharp.Core]Microsoft.FSharp.Core.CompilationMappingAttribute::.ctor(valuetype [FSharp.Core]Microsoft.FSharp.Core.SourceConstructFlags) = ( 01 00 07 00 00 00 00 00 ) .class interface abstract auto ansi serializable nested public IAdditionOperator`1 { - .custom instance void [FSharp.Core]Microsoft.FSharp.Core.CompilationMappingAttribute::.ctor(valuetype [FSharp.Core]Microsoft.FSharp.Core.SourceConstructFlags) = ( 01 00 03 00 00 00 00 00 ) - .method public hidebysig static abstract virtual + .custom instance void [FSharp.Core]Microsoft.FSharp.Core.CompilationMappingAttribute::.ctor(valuetype [FSharp.Core]Microsoft.FSharp.Core.SourceConstructFlags) = ( 01 00 03 00 00 00 00 00 ) + .method public hidebysig static abstract virtual !T op_Addition(!T A_0, !T A_1) cil managed { - } + } - } + } .class auto ansi serializable nested public C extends [runtime]System.Object implements class Tests.Test/IAdditionOperator`1 { - .custom instance void [FSharp.Core]Microsoft.FSharp.Core.CompilationMappingAttribute::.ctor(valuetype [FSharp.Core]Microsoft.FSharp.Core.SourceConstructFlags) = ( 01 00 03 00 00 00 00 00 ) + .custom instance void [FSharp.Core]Microsoft.FSharp.Core.CompilationMappingAttribute::.ctor(valuetype [FSharp.Core]Microsoft.FSharp.Core.SourceConstructFlags) = ( 01 00 03 00 00 00 00 00 ) .field assembly int32 c - .method public specialname rtspecialname + .method public specialname rtspecialname instance void .ctor(int32 c) cil managed { - + .maxstack 8 IL_0000: ldarg.0 IL_0001: callvirt instance void [runtime]System.Object::.ctor() @@ -407,25 +407,25 @@ module Test = IL_0009: ldarg.1 IL_000a: stfld int32 Tests.Test/C::c IL_000f: ret - } + } - .method public hidebysig specialname + .method public hidebysig specialname instance int32 get_Value() cil managed { - + .maxstack 8 IL_0000: ldarg.0 IL_0001: ldfld int32 Tests.Test/C::c IL_0006: ret - } + } - .method public hidebysig static class Tests.Test/C + .method public hidebysig static class Tests.Test/C 'Tests.Test.IAdditionOperator.op_Addition'(class Tests.Test/C x, class Tests.Test/C y) cil managed { .override method !0 class Tests.Test/IAdditionOperator`1::op_Addition(!0, !0) - + .maxstack 8 IL_0000: ldarg.0 IL_0001: ldfld int32 Tests.Test/C::c @@ -434,18 +434,18 @@ module Test = IL_000c: add IL_000d: newobj instance void Tests.Test/C::.ctor(int32) IL_0012: ret - } + } .property instance int32 Value() { .get instance int32 Tests.Test/C::get_Value() - } - } + } + } .method public static !!T f<(class Tests.Test/IAdditionOperator`1) T>(!!T x, !!T y) cil managed { - + .maxstack 8 IL_0000: ldarg.0 IL_0001: ldarg.1 @@ -453,13 +453,13 @@ module Test = IL_0008: call !0 class Tests.Test/IAdditionOperator`1::op_Addition(!0, !0) IL_000d: ret - } + } .method public static int32 main(string[] _arg1) cil managed { .entrypoint - .custom instance void [FSharp.Core]Microsoft.FSharp.Core.EntryPointAttribute::.ctor() = ( 01 00 00 00 ) - + .custom instance void [FSharp.Core]Microsoft.FSharp.Core.EntryPointAttribute::.ctor() = ( 01 00 00 00 ) + .maxstack 4 .locals init (class Tests.Test/C V_0, class Tests.Test/C V_1) @@ -484,37 +484,37 @@ module Test = IL_002e: ldc.i4.0 IL_002f: ret - } + } -} +} """ #else """ .class public abstract auto ansi sealed Tests.Test extends [runtime]System.Object { - .custom instance void [FSharp.Core]Microsoft.FSharp.Core.CompilationMappingAttribute::.ctor(valuetype [FSharp.Core]Microsoft.FSharp.Core.SourceConstructFlags) = ( 01 00 07 00 00 00 00 00 ) + .custom instance void [FSharp.Core]Microsoft.FSharp.Core.CompilationMappingAttribute::.ctor(valuetype [FSharp.Core]Microsoft.FSharp.Core.SourceConstructFlags) = ( 01 00 07 00 00 00 00 00 ) .class interface abstract auto ansi serializable nested public IAdditionOperator`1 { - .custom instance void [FSharp.Core]Microsoft.FSharp.Core.CompilationMappingAttribute::.ctor(valuetype [FSharp.Core]Microsoft.FSharp.Core.SourceConstructFlags) = ( 01 00 03 00 00 00 00 00 ) - .method public hidebysig static abstract virtual + .custom instance void [FSharp.Core]Microsoft.FSharp.Core.CompilationMappingAttribute::.ctor(valuetype [FSharp.Core]Microsoft.FSharp.Core.SourceConstructFlags) = ( 01 00 03 00 00 00 00 00 ) + .method public hidebysig static abstract virtual !T op_Addition(!T A_0, !T A_1) cil managed { - } + } - } + } .class auto ansi serializable nested public C extends [runtime]System.Object implements class Tests.Test/IAdditionOperator`1 { - .custom instance void [FSharp.Core]Microsoft.FSharp.Core.CompilationMappingAttribute::.ctor(valuetype [FSharp.Core]Microsoft.FSharp.Core.SourceConstructFlags) = ( 01 00 03 00 00 00 00 00 ) + .custom instance void [FSharp.Core]Microsoft.FSharp.Core.CompilationMappingAttribute::.ctor(valuetype [FSharp.Core]Microsoft.FSharp.Core.SourceConstructFlags) = ( 01 00 03 00 00 00 00 00 ) .field assembly int32 c - .method public specialname rtspecialname + .method public specialname rtspecialname instance void .ctor(int32 c) cil managed { - + .maxstack 8 IL_0000: ldarg.0 IL_0001: callvirt instance void [runtime]System.Object::.ctor() @@ -524,25 +524,25 @@ module Test = IL_0009: ldarg.1 IL_000a: stfld int32 Tests.Test/C::c IL_000f: ret - } + } - .method public hidebysig specialname + .method public hidebysig specialname instance int32 get_Value() cil managed { - + .maxstack 8 IL_0000: ldarg.0 IL_0001: ldfld int32 Tests.Test/C::c IL_0006: ret - } + } - .method public hidebysig static class Tests.Test/C + .method public hidebysig static class Tests.Test/C 'Tests.Test.IAdditionOperator.op_Addition'(class Tests.Test/C x, class Tests.Test/C y) cil managed { .override method !0 class Tests.Test/IAdditionOperator`1::op_Addition(!0, !0) - + .maxstack 8 IL_0000: ldarg.0 IL_0001: ldfld int32 Tests.Test/C::c @@ -551,18 +551,18 @@ module Test = IL_000c: add IL_000d: newobj instance void Tests.Test/C::.ctor(int32) IL_0012: ret - } + } .property instance int32 Value() { .get instance int32 Tests.Test/C::get_Value() - } - } + } + } .method public static !!T f<(class Tests.Test/IAdditionOperator`1) T>(!!T x, !!T y) cil managed { - + .maxstack 8 IL_0000: ldarg.0 IL_0001: ldarg.1 @@ -570,13 +570,13 @@ module Test = IL_0008: call !0 class Tests.Test/IAdditionOperator`1::op_Addition(!0, !0) IL_000d: ret - } + } .method public static int32 main(string[] _arg1) cil managed { .entrypoint - .custom instance void [FSharp.Core]Microsoft.FSharp.Core.EntryPointAttribute::.ctor() = ( 01 00 00 00 ) - + .custom instance void [FSharp.Core]Microsoft.FSharp.Core.EntryPointAttribute::.ctor() = ( 01 00 00 00 ) + .maxstack 4 .locals init (class Tests.Test/C V_0, class Tests.Test/C V_1) @@ -601,7 +601,7 @@ module Test = IL_002e: ldc.i4.0 IL_002f: ret - } + } """ #endif ] @@ -623,12 +623,14 @@ public interface I FSharp """ type Imp() = interface Test.I with - static member Echo (x: string) = x + "_imp" + static member Echo (x: string) = $"{x}_imp" let echo<'T when 'T :> Test.I> x = 'T.Echo(x) -if echo "a" <> "a_imp" then - failwith "incorrect value" +match echo "a" with +| "a_imp" -> printfn "success" +| "a" -> failwith "incorrectly invoked the base interface 'Echo'" +| _ -> failwith "incorrect value" """ |> withReferences [CSharpLib] |> withLangVersion80 From 93e382869180f1eb7e063704ff0aab4701312d0a Mon Sep 17 00:00:00 2001 From: David Naylor Date: Thu, 11 Apr 2024 18:53:24 +0200 Subject: [PATCH 06/10] StaticsInInterfaces: test SRTP works with overridden virtual static methods --- .../Interop/StaticsInInterfaces.fs | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/tests/FSharp.Compiler.ComponentTests/Interop/StaticsInInterfaces.fs b/tests/FSharp.Compiler.ComponentTests/Interop/StaticsInInterfaces.fs index 0fbd4db3dd8..3c49d29f1f9 100644 --- a/tests/FSharp.Compiler.ComponentTests/Interop/StaticsInInterfaces.fs +++ b/tests/FSharp.Compiler.ComponentTests/Interop/StaticsInInterfaces.fs @@ -614,7 +614,7 @@ namespace Test; public interface I { - static virtual string Echo(string x) => x; + static virtual string Echo(string x) => $"I.Echo: {x}"; } """ |> withCSharpLanguageVersion CSharpLanguageVersion.CSharp11 @@ -623,13 +623,24 @@ public interface I FSharp """ type Imp() = interface Test.I with - static member Echo (x: string) = $"{x}_imp" + static member Echo (x: string) = $"Imp.I.Echo: {x}" + + static member Echo (x: string) = $"Imp.Echo: {x}" let echo<'T when 'T :> Test.I> x = 'T.Echo(x) +let inline echo_srtp<'T when 'T : (static member Echo: string -> string)> x = 'T.Echo(x) + match echo "a" with -| "a_imp" -> printfn "success" -| "a" -> failwith "incorrectly invoked the base interface 'Echo'" +| "Imp.I.Echo: a" -> printfn "success" +| "Imp.Echo: a" -> failwith "incorrectly invoked the class 'Echo'" +| "I.Echo: a" -> failwith "incorrectly invoked the base interface 'Echo'" +| _ -> failwith "incorrect value" + +match echo_srtp "a" with +| "Imp.Echo: a" -> printfn "success" +| "Imp.I.Echo: a" -> failwith "incorrectly invoked the interface 'Echo'" +| "I.Echo: a" -> failwith "incorrectly invoked the base interface 'Echo'" | _ -> failwith "incorrect value" """ |> withReferences [CSharpLib] From 623d545461f05c8b95c5345f7eb7d54897cab7fc Mon Sep 17 00:00:00 2001 From: David Naylor Date: Fri, 12 Apr 2024 08:45:01 +0200 Subject: [PATCH 07/10] StaticInInterfaces: add back white spaces Required for IL comparison. --- .../Interop/StaticsInInterfaces.fs | 150 +++++++++--------- 1 file changed, 75 insertions(+), 75 deletions(-) diff --git a/tests/FSharp.Compiler.ComponentTests/Interop/StaticsInInterfaces.fs b/tests/FSharp.Compiler.ComponentTests/Interop/StaticsInInterfaces.fs index 3c49d29f1f9..4eb6c169a6f 100644 --- a/tests/FSharp.Compiler.ComponentTests/Interop/StaticsInInterfaces.fs +++ b/tests/FSharp.Compiler.ComponentTests/Interop/StaticsInInterfaces.fs @@ -12,7 +12,7 @@ module ``Static Methods In Interfaces`` = | CS cs -> CS { cs with LangVersion = ver } | _ -> failwith "Only supported in C#" - let csharpBaseClass = + let csharpBaseClass = CSharp """ namespace StaticsInInterfaces { @@ -38,7 +38,7 @@ module ``Static Methods In Interfaces`` = }""" |> withCSharpLanguageVersion CSharpLanguageVersion.Preview |> withName "csLib" - + let csharpOperators = CSharp """ namespace StaticsInInterfaces @@ -110,7 +110,7 @@ let main _ = [] let ``F# can call static methods declared in interfaces from C#`` () = - let csharpLib = csharpBaseClass + let csharpLib = csharpBaseClass let fsharpSource = """ @@ -145,18 +145,18 @@ let main _ = .class interface public auto ansi abstract IGetNext`1<(class IGetNext`1) T> { // Methods - .method public hidebysig abstract virtual static + .method public hidebysig abstract virtual static !T Next ( !T other - ) cil managed + ) cil managed { } // end of method IGetNext`1::Next } // end of class IGetNext`1 And the following implementation: - .method public hidebysig static - class RepeatSequence Next (class RepeatSequence other) cil managed + .method public hidebysig static + class RepeatSequence Next (class RepeatSequence other) cil managed { .override method !0 class IGetNext`1::Next(!0) ... @@ -165,11 +165,11 @@ let main _ = [] let ``F# generates valid IL for abstract static interface methods`` () = - let csharpLib = csharpBaseClass + let csharpLib = csharpBaseClass let fsharpSource = """ -module StaticsTesting +module StaticsTesting open StaticsInInterfaces type MyRepeatSequence() = @@ -192,69 +192,69 @@ type MyRepeatSequence2() = extends [runtime]System.Object implements class [csLib]StaticsInInterfaces.IGetNext`1 { - .custom instance void [FSharp.Core]Microsoft.FSharp.Core.CompilationMappingAttribute::.ctor(valuetype [FSharp.Core]Microsoft.FSharp.Core.SourceConstructFlags) = ( 01 00 03 00 00 00 00 00 ) + .custom instance void [FSharp.Core]Microsoft.FSharp.Core.CompilationMappingAttribute::.ctor(valuetype [FSharp.Core]Microsoft.FSharp.Core.SourceConstructFlags) = ( 01 00 03 00 00 00 00 00 ) .method public specialname rtspecialname instance void .ctor() cil managed { - + .maxstack 8 IL_0000: ldarg.0 IL_0001: callvirt instance void [runtime]System.Object::.ctor() IL_0006: ldarg.0 IL_0007: pop IL_0008: ret - } - + } + .method public hidebysig static class StaticsTesting/MyRepeatSequence 'StaticsInInterfaces.IGetNext.Next'(class StaticsTesting/MyRepeatSequence other) cil managed { .override method !0 class [csLib]StaticsInInterfaces.IGetNext`1::Next(!0) - + .maxstack 8 IL_0000: ldarg.0 IL_0001: ret - } - - } - + } + + } + .class auto ansi serializable nested public MyRepeatSequence2 extends [runtime]System.Object implements class [csLib]StaticsInInterfaces.IGetNext`1 { - .custom instance void [FSharp.Core]Microsoft.FSharp.Core.CompilationMappingAttribute::.ctor(valuetype [FSharp.Core]Microsoft.FSharp.Core.SourceConstructFlags) = ( 01 00 03 00 00 00 00 00 ) + .custom instance void [FSharp.Core]Microsoft.FSharp.Core.CompilationMappingAttribute::.ctor(valuetype [FSharp.Core]Microsoft.FSharp.Core.SourceConstructFlags) = ( 01 00 03 00 00 00 00 00 ) .method public specialname rtspecialname instance void .ctor() cil managed { - + .maxstack 8 IL_0000: ldarg.0 IL_0001: callvirt instance void [runtime]System.Object::.ctor() IL_0006: ldarg.0 IL_0007: pop IL_0008: ret - } - + } + .method public static class StaticsTesting/MyRepeatSequence2 Next(class StaticsTesting/MyRepeatSequence2 other) cil managed { - + .maxstack 8 IL_0000: ldarg.0 IL_0001: ret - } - + } + .method public hidebysig static class StaticsTesting/MyRepeatSequence2 'StaticsInInterfaces.IGetNext.Next'(class StaticsTesting/MyRepeatSequence2 other) cil managed { .override method !0 class [csLib]StaticsInInterfaces.IGetNext`1::Next(!0) - + .maxstack 8 IL_0000: ldarg.0 IL_0001: ret - } - + } + } """] - + [] let ``F# can implement static methods declared in interfaces from C#`` () = - let csharpLib = csharpBaseClass + let csharpLib = csharpBaseClass let fsharpSource = """ @@ -376,28 +376,28 @@ module Test = .class public abstract auto ansi sealed Tests.Test extends [runtime]System.Object { - .custom instance void [FSharp.Core]Microsoft.FSharp.Core.CompilationMappingAttribute::.ctor(valuetype [FSharp.Core]Microsoft.FSharp.Core.SourceConstructFlags) = ( 01 00 07 00 00 00 00 00 ) + .custom instance void [FSharp.Core]Microsoft.FSharp.Core.CompilationMappingAttribute::.ctor(valuetype [FSharp.Core]Microsoft.FSharp.Core.SourceConstructFlags) = ( 01 00 07 00 00 00 00 00 ) .class interface abstract auto ansi serializable nested public IAdditionOperator`1 { - .custom instance void [FSharp.Core]Microsoft.FSharp.Core.CompilationMappingAttribute::.ctor(valuetype [FSharp.Core]Microsoft.FSharp.Core.SourceConstructFlags) = ( 01 00 03 00 00 00 00 00 ) - .method public hidebysig static abstract virtual + .custom instance void [FSharp.Core]Microsoft.FSharp.Core.CompilationMappingAttribute::.ctor(valuetype [FSharp.Core]Microsoft.FSharp.Core.SourceConstructFlags) = ( 01 00 03 00 00 00 00 00 ) + .method public hidebysig static abstract virtual !T op_Addition(!T A_0, !T A_1) cil managed { - } + } - } + } .class auto ansi serializable nested public C extends [runtime]System.Object implements class Tests.Test/IAdditionOperator`1 { - .custom instance void [FSharp.Core]Microsoft.FSharp.Core.CompilationMappingAttribute::.ctor(valuetype [FSharp.Core]Microsoft.FSharp.Core.SourceConstructFlags) = ( 01 00 03 00 00 00 00 00 ) + .custom instance void [FSharp.Core]Microsoft.FSharp.Core.CompilationMappingAttribute::.ctor(valuetype [FSharp.Core]Microsoft.FSharp.Core.SourceConstructFlags) = ( 01 00 03 00 00 00 00 00 ) .field assembly int32 c - .method public specialname rtspecialname + .method public specialname rtspecialname instance void .ctor(int32 c) cil managed { - + .maxstack 8 IL_0000: ldarg.0 IL_0001: callvirt instance void [runtime]System.Object::.ctor() @@ -407,25 +407,25 @@ module Test = IL_0009: ldarg.1 IL_000a: stfld int32 Tests.Test/C::c IL_000f: ret - } + } - .method public hidebysig specialname + .method public hidebysig specialname instance int32 get_Value() cil managed { - + .maxstack 8 IL_0000: ldarg.0 IL_0001: ldfld int32 Tests.Test/C::c IL_0006: ret - } + } - .method public hidebysig static class Tests.Test/C + .method public hidebysig static class Tests.Test/C 'Tests.Test.IAdditionOperator.op_Addition'(class Tests.Test/C x, class Tests.Test/C y) cil managed { .override method !0 class Tests.Test/IAdditionOperator`1::op_Addition(!0, !0) - + .maxstack 8 IL_0000: ldarg.0 IL_0001: ldfld int32 Tests.Test/C::c @@ -434,18 +434,18 @@ module Test = IL_000c: add IL_000d: newobj instance void Tests.Test/C::.ctor(int32) IL_0012: ret - } + } .property instance int32 Value() { .get instance int32 Tests.Test/C::get_Value() - } - } + } + } .method public static !!T f<(class Tests.Test/IAdditionOperator`1) T>(!!T x, !!T y) cil managed { - + .maxstack 8 IL_0000: ldarg.0 IL_0001: ldarg.1 @@ -453,13 +453,13 @@ module Test = IL_0008: call !0 class Tests.Test/IAdditionOperator`1::op_Addition(!0, !0) IL_000d: ret - } + } .method public static int32 main(string[] _arg1) cil managed { .entrypoint - .custom instance void [FSharp.Core]Microsoft.FSharp.Core.EntryPointAttribute::.ctor() = ( 01 00 00 00 ) - + .custom instance void [FSharp.Core]Microsoft.FSharp.Core.EntryPointAttribute::.ctor() = ( 01 00 00 00 ) + .maxstack 4 .locals init (class Tests.Test/C V_0, class Tests.Test/C V_1) @@ -484,37 +484,37 @@ module Test = IL_002e: ldc.i4.0 IL_002f: ret - } + } -} +} """ #else """ .class public abstract auto ansi sealed Tests.Test extends [runtime]System.Object { - .custom instance void [FSharp.Core]Microsoft.FSharp.Core.CompilationMappingAttribute::.ctor(valuetype [FSharp.Core]Microsoft.FSharp.Core.SourceConstructFlags) = ( 01 00 07 00 00 00 00 00 ) + .custom instance void [FSharp.Core]Microsoft.FSharp.Core.CompilationMappingAttribute::.ctor(valuetype [FSharp.Core]Microsoft.FSharp.Core.SourceConstructFlags) = ( 01 00 07 00 00 00 00 00 ) .class interface abstract auto ansi serializable nested public IAdditionOperator`1 { - .custom instance void [FSharp.Core]Microsoft.FSharp.Core.CompilationMappingAttribute::.ctor(valuetype [FSharp.Core]Microsoft.FSharp.Core.SourceConstructFlags) = ( 01 00 03 00 00 00 00 00 ) - .method public hidebysig static abstract virtual + .custom instance void [FSharp.Core]Microsoft.FSharp.Core.CompilationMappingAttribute::.ctor(valuetype [FSharp.Core]Microsoft.FSharp.Core.SourceConstructFlags) = ( 01 00 03 00 00 00 00 00 ) + .method public hidebysig static abstract virtual !T op_Addition(!T A_0, !T A_1) cil managed { - } + } - } + } .class auto ansi serializable nested public C extends [runtime]System.Object implements class Tests.Test/IAdditionOperator`1 { - .custom instance void [FSharp.Core]Microsoft.FSharp.Core.CompilationMappingAttribute::.ctor(valuetype [FSharp.Core]Microsoft.FSharp.Core.SourceConstructFlags) = ( 01 00 03 00 00 00 00 00 ) + .custom instance void [FSharp.Core]Microsoft.FSharp.Core.CompilationMappingAttribute::.ctor(valuetype [FSharp.Core]Microsoft.FSharp.Core.SourceConstructFlags) = ( 01 00 03 00 00 00 00 00 ) .field assembly int32 c - .method public specialname rtspecialname + .method public specialname rtspecialname instance void .ctor(int32 c) cil managed { - + .maxstack 8 IL_0000: ldarg.0 IL_0001: callvirt instance void [runtime]System.Object::.ctor() @@ -524,25 +524,25 @@ module Test = IL_0009: ldarg.1 IL_000a: stfld int32 Tests.Test/C::c IL_000f: ret - } + } - .method public hidebysig specialname + .method public hidebysig specialname instance int32 get_Value() cil managed { - + .maxstack 8 IL_0000: ldarg.0 IL_0001: ldfld int32 Tests.Test/C::c IL_0006: ret - } + } - .method public hidebysig static class Tests.Test/C + .method public hidebysig static class Tests.Test/C 'Tests.Test.IAdditionOperator.op_Addition'(class Tests.Test/C x, class Tests.Test/C y) cil managed { .override method !0 class Tests.Test/IAdditionOperator`1::op_Addition(!0, !0) - + .maxstack 8 IL_0000: ldarg.0 IL_0001: ldfld int32 Tests.Test/C::c @@ -551,18 +551,18 @@ module Test = IL_000c: add IL_000d: newobj instance void Tests.Test/C::.ctor(int32) IL_0012: ret - } + } .property instance int32 Value() { .get instance int32 Tests.Test/C::get_Value() - } - } + } + } .method public static !!T f<(class Tests.Test/IAdditionOperator`1) T>(!!T x, !!T y) cil managed { - + .maxstack 8 IL_0000: ldarg.0 IL_0001: ldarg.1 @@ -570,13 +570,13 @@ module Test = IL_0008: call !0 class Tests.Test/IAdditionOperator`1::op_Addition(!0, !0) IL_000d: ret - } + } .method public static int32 main(string[] _arg1) cil managed { .entrypoint - .custom instance void [FSharp.Core]Microsoft.FSharp.Core.EntryPointAttribute::.ctor() = ( 01 00 00 00 ) - + .custom instance void [FSharp.Core]Microsoft.FSharp.Core.EntryPointAttribute::.ctor() = ( 01 00 00 00 ) + .maxstack 4 .locals init (class Tests.Test/C V_0, class Tests.Test/C V_1) @@ -601,7 +601,7 @@ module Test = IL_002e: ldc.i4.0 IL_002f: ret - } + } """ #endif ] From f9539f3f98566f0ffeb2fda14e997ae11d78c941 Mon Sep 17 00:00:00 2001 From: Vlad Zarytovskii Date: Mon, 15 Apr 2024 10:48:17 +0200 Subject: [PATCH 08/10] Release notes --- docs/release-notes/.FSharp.Compiler.Service/8.0.300.md | 1 - docs/release-notes/.FSharp.Compiler.Service/8.0.400.md | 9 +++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) create mode 100644 docs/release-notes/.FSharp.Compiler.Service/8.0.400.md diff --git a/docs/release-notes/.FSharp.Compiler.Service/8.0.300.md b/docs/release-notes/.FSharp.Compiler.Service/8.0.300.md index 5a15ace3cb6..57bc1578db3 100644 --- a/docs/release-notes/.FSharp.Compiler.Service/8.0.300.md +++ b/docs/release-notes/.FSharp.Compiler.Service/8.0.300.md @@ -31,7 +31,6 @@ * Obsolete attribute is ignored in constructor property assignment ([PR #16900](https://github.com/dotnet/fsharp/pull/16900)) * Completion: fix completion in empty dot lambda prefix ([#16829](https://github.com/dotnet/fsharp/pull/16829)) * Fix StackOverflow when checking non-recursive bindings in module or namespace in `fscAnyCpu`/`fsiAnyCpu`. ([PR #16908](https://github.com/dotnet/fsharp/pull/16908)) -* Fix calling an overridden virtual static method via the interface ([PR #17013](https://github.com/dotnet/fsharp/pull/17013)) ### Added diff --git a/docs/release-notes/.FSharp.Compiler.Service/8.0.400.md b/docs/release-notes/.FSharp.Compiler.Service/8.0.400.md new file mode 100644 index 00000000000..96789fc0196 --- /dev/null +++ b/docs/release-notes/.FSharp.Compiler.Service/8.0.400.md @@ -0,0 +1,9 @@ +### Fixed + +* Fix calling an overridden virtual static method via the interface ([PR #17013](https://github.com/dotnet/fsharp/pull/17013)) + +### Added + + + +### Changed From eaee876ab5d57ea5944d39a8f55ee816b3799c2b Mon Sep 17 00:00:00 2001 From: Petr Date: Mon, 15 Apr 2024 14:55:46 +0200 Subject: [PATCH 09/10] Update 8.0.400.md --- docs/release-notes/.FSharp.Compiler.Service/8.0.400.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/release-notes/.FSharp.Compiler.Service/8.0.400.md b/docs/release-notes/.FSharp.Compiler.Service/8.0.400.md index 17da912ace5..5d855142a66 100644 --- a/docs/release-notes/.FSharp.Compiler.Service/8.0.400.md +++ b/docs/release-notes/.FSharp.Compiler.Service/8.0.400.md @@ -1,6 +1,7 @@ ### Fixed * Fix calling an overridden virtual static method via the interface ([PR #17013](https://github.com/dotnet/fsharp/pull/17013)) +* Various parenthesization API fixes. ([PR #16977](https://github.com/dotnet/fsharp/pull/16977)) ### Added @@ -8,4 +9,3 @@ ### Changed -Various parenthesization API fixes. ([PR #16977](https://github.com/dotnet/fsharp/pull/16977)) From cdfb00266701372236beeee724e42b04f0657d79 Mon Sep 17 00:00:00 2001 From: Petr Date: Mon, 15 Apr 2024 14:56:20 +0200 Subject: [PATCH 10/10] Update 8.0.400.md --- docs/release-notes/.FSharp.Compiler.Service/8.0.400.md | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/docs/release-notes/.FSharp.Compiler.Service/8.0.400.md b/docs/release-notes/.FSharp.Compiler.Service/8.0.400.md index 5d855142a66..b8fe382ebba 100644 --- a/docs/release-notes/.FSharp.Compiler.Service/8.0.400.md +++ b/docs/release-notes/.FSharp.Compiler.Service/8.0.400.md @@ -1,11 +1,4 @@ ### Fixed -* Fix calling an overridden virtual static method via the interface ([PR #17013](https://github.com/dotnet/fsharp/pull/17013)) * Various parenthesization API fixes. ([PR #16977](https://github.com/dotnet/fsharp/pull/16977)) - -### Added - - - -### Changed - +* Fix calling an overridden virtual static method via the interface ([PR #17013](https://github.com/dotnet/fsharp/pull/17013))