Skip to content

Commit

Permalink
Fix virtual static call (dotnet#17013)
Browse files Browse the repository at this point in the history
* Fix calling virtual static methods via interface

* InterfaceTests: fix test label and minor code cleanup

* 8.0.300: add fix to release notes

* InterfaceTests: fix braces in quoted code

* StaticsInInterfaces: clarify test cases on virtual static

* StaticsInInterfaces: test SRTP works with overridden virtual static methods

* StaticInInterfaces: add back white spaces

Required for IL comparison.

* Release notes

* Update 8.0.400.md

* Update 8.0.400.md

---------

Co-authored-by: Kevin Ransom (msft) <[email protected]>
Co-authored-by: Vlad Zarytovskii <[email protected]>
Co-authored-by: Petr <[email protected]>
  • Loading branch information
4 people authored Apr 16, 2024
1 parent 807d41d commit 98250ef
Show file tree
Hide file tree
Showing 4 changed files with 59 additions and 15 deletions.
1 change: 1 addition & 0 deletions docs/release-notes/.FSharp.Compiler.Service/8.0.400.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@

* Various parenthesization API fixes. ([PR #16977](https://github.com/dotnet/fsharp/pull/16977))
* Fix bug in optimization of for-loops over integral ranges with steps and units of measure. ([Issue #17025](https://github.com/dotnet/fsharp/issues/17025), [PR #17040](https://github.com/dotnet/fsharp/pull/17040))
* Fix calling an overridden virtual static method via the interface ([PR #17013](https://github.com/dotnet/fsharp/pull/17013))
4 changes: 2 additions & 2 deletions src/Compiler/Checking/MethodCalls.fs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -606,6 +606,49 @@ module Test =
#endif
]

[<FactForNETCOREAPP>]
let ``F# can call overwritten static virtual member from interface``() =
let CSharpLib =
CSharp """
namespace Test;
public interface I
{
static virtual string Echo(string x) => $"I.Echo: {x}";
}
"""
|> withCSharpLanguageVersion CSharpLanguageVersion.CSharp11
|> withName "CsLibAssembly"

FSharp """
type Imp() =
interface Test.I with
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<Imp> "a" with
| "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<Imp> "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]
|> withLangVersion80
|> asExe
|> compileAndRun
|> shouldSucceed

[<FactForNETCOREAPP>]
let ``C# can call constrained method defined in F#`` () =
let FSharpLib =
Expand Down
26 changes: 13 additions & 13 deletions tests/FSharp.Compiler.ComponentTests/Language/InterfaceTests.fs
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ open Xunit
open FSharp.Test.Compiler

[<Fact>]
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 """
[<Interface>]
type I =
member _.X () = 1
Expand All @@ -18,8 +18,8 @@ type I =
]

[<Fact>]
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 """
[<Interface>]
type I =
member _.Prop = "x"
Expand All @@ -32,8 +32,8 @@ type I =
]

[<Fact>]
let ``Concrete static members are allowed in interfaces in lang preview``() =
FSharp $"""
let ``Concrete static members are allowed in interfaces in lang version80``() =
FSharp """
[<Interface>]
type I<'T> =
static member Echo (x: 'T) = x
Expand All @@ -49,7 +49,7 @@ if I<int>.Echo 42 <> 42 || I<int>.Prop <> 0 || not (isNull I<string>.Prop) then

[<Fact>]
let ``Concrete static members are not allowed in interfaces in lang version70``() =
FSharp $"""
FSharp """
[<Interface>]
type I<'T> =
static member Echo (x: 'T) = x
Expand All @@ -63,8 +63,8 @@ type I<'T> =
]

[<Fact>]
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 """
[<Interface>]
type I<'T> =
static member Prop = Unchecked.defaultof<'T>
Expand All @@ -81,8 +81,8 @@ if I<int>.Echo 42 <> 42 || I<int>.Prop <> 0 || not (isNull I<string>.Prop) then


[<Fact>]
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 """
[<Interface>]
type I =
static member Echo (x: string) = x
Expand All @@ -92,12 +92,12 @@ 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"
"""
|> withLangVersion80
|> asExe
|> compileAndRun
|> shouldSucceed
|> shouldSucceed

0 comments on commit 98250ef

Please sign in to comment.