Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix virtual static call #17013

Merged
merged 16 commits into from
Apr 16, 2024
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/release-notes/.FSharp.Compiler.Service/8.0.300.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
* 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

Expand Down
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,36 @@ 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) => 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<Imp> "a" <> "a_imp" then
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
Loading