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

Conversation

DragonSA
Copy link
Contributor

@DragonSA DragonSA commented Apr 9, 2024

Description

Fix calling an overridden virtual static method via the interface.

The current fsharp calls, ends up calling the default implementation of C# static virtual methods. This fixes this by ensuring that the static virtual metadata is honoured in method resolution.

Checklist

  • Test cases added
  • Release notes entry updated

Sponsorship

Counterpoint Dynamics (Pty) Ltd

Copy link
Contributor

github-actions bot commented Apr 9, 2024

❗ Release notes required


✅ Found changes and release notes in following paths:

Change path Release notes path Description
src/Compiler docs/release-notes/.FSharp.Compiler.Service/8.0.400.md

@vzarytovskii
Copy link
Member

What was the behaviour before? This needs SRTP tests as well. Also need to make sure RFC for IWSAMs mentions virtual members as well.

@KevinRansom
Copy link
Member

@vzarytovskii ...

It compiles the method invocation however it invokes the base class method implementation and not the overridden version.

static virtual members are confusingly necessary for the INumerics stuff because of generics.

It's a good change.

@vzarytovskii
Copy link
Member

@vzarytovskii ...

It compiles the method invocation however it invokes the base class method implementation and not the overridden version.

static virtual members are confusingly necessary for the INumerics stuff because of generics.

It's a good change.

It's a breaking change then? What do we do in case of non-statics?

Copy link
Member

@KevinRansom KevinRansom left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The change is a good one, we need to consider the breaking change. Although my intuition is that it is rare enough and breaks an important dotnet feature so we would take the break.

Although ... the scenario to implement the INumerics, may not have been a goal, I wasn't involved in those design discussions.

@KevinRansom
Copy link
Member

@vzarytovskii interfaces with virtual statics was implemented as part of the INumerics feature. We handle abstract/virtuals/override on instance methods compatibly with C#. I think we probably consume, the framework INumber implementations correctly. This particular bug is likely merely an oversight.

@KevinRansom
Copy link
Member

Oh yeah, and there is no real performance implications.

@vzarytovskii
Copy link
Member

@vzarytovskii interfaces with virtual statics was implemented as part of the INumerics feature. We handle abstract/virtuals/override on instance methods compatibly with C#. I think we probably consume, the framework INumber implementations correctly. This particular bug is likely merely an oversight.

I know, I implemented those in F#.

Question is which method do we call now
A. In case of static virtual
B. In case of non-static virtual

A should match B.

@KevinRansom
Copy link
Member

For virtual inheritence, it should be the most derived. Static should emulate that I should think.

@DragonSA
Copy link
Contributor Author

What was the behaviour before? This needs SRTP tests as well. Also need to make sure RFC for IWSAMs mentions virtual members as well.

The prior behaviour was the override of a virtual static method could not be called by F#.

Just a note that SRTP cannot be used to call the override of Echo, since that is defined on the interface and not the class itself. I've added a test (in 93e3828) to confirm the correct static methods get called.

Regarding the RFC, are you referring to RFC FS-1124, this does not mention virtual static methods.

@vzarytovskii ...
It compiles the method invocation however it invokes the base class method implementation and not the overridden version.
static virtual members are confusingly necessary for the INumerics stuff because of generics.
It's a good change.

It's a breaking change then? What do we do in case of non-statics?

The overridden method is called:

    [<FactForNETCOREAPP>]
    let ``F# can call overwritten virtual member from interface``() =
        let CSharpLib =
            CSharp """
namespace Test;

public interface I
{
    virtual string Echo(string x) => $"I.Echo: {x}";
}
            """
            |> withCSharpLanguageVersion CSharpLanguageVersion.CSharp11
            |> withName "CsLibAssembly"

        FSharp """
type Imp() =
    interface Test.I with
        member _.Echo (x: string) = $"Imp.I.Echo: {x}"

let echo<'T when 'T :> Test.I> (a: 'T) x = a.Echo(x)

match echo (Imp()) "a" with
| "Imp.I.Echo: a" -> printfn "success"
| _ -> failwith "incorrect value"
"""
        |> withReferences [CSharpLib]
        |> withLangVersion80
        |> asExe
        |> compileAndRun
        |> shouldSucceed

@vzarytovskii interfaces with virtual statics was implemented as part of the INumerics feature. We handle abstract/virtuals/override on instance methods compatibly with C#. I think we probably consume, the framework INumber implementations correctly. This particular bug is likely merely an oversight.

I know, I implemented those in F#.

Question is which method do we call now A. In case of static virtual B. In case of non-static virtual

A should match B.

I agree :-). Currently we:
A. In case of static virtual: F# calls the base implementation (C# calls the override) (this change calls the override).
B. In case of non-static: F# calls the override (C# does the same).

Thus, this change is required to bring A and B into alignment.

@DragonSA
Copy link
Contributor Author

Out of interest, what is the protocol for resolving comments? Should I do it once I made the appropriate change/comment, or does the commenter resolve it once satisfied?

@vzarytovskii
Copy link
Member

Regarding the RFC, are you referring to RFC FS-1124, this does not mention virtual static methods.

Yeah, this one. Probably then add a one-liner saying what will be preferred in case of virtual methods.

@DragonSA
Copy link
Contributor Author

Regarding the RFC, are you referring to RFC FS-1124, this does not mention virtual static methods.

Yeah, this one. Probably then add a one-liner saying what will be preferred in case of virtual methods.

I've created fsharp/fslang-design#766

@vzarytovskii
Copy link
Member

Out of interest, what is the protocol for resolving comments? Should I do it once I made the appropriate change/comment, or does the commenter resolve it once satisfied?

Feel free to resolve if you've addressed it

Required for IL comparison.
@edgarfgp
Copy link
Contributor

edgarfgp commented Apr 12, 2024

Thanks @DragonSA and to Counterpoint Dynamics (Pty) for sponsoring this. Really cool 👍

@DragonSA DragonSA marked this pull request as ready for review April 13, 2024 03:35
@DragonSA DragonSA requested a review from a team as a code owner April 13, 2024 03:35
Copy link
Member

@vzarytovskii vzarytovskii left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good, thanks

@dawedawe
Copy link
Contributor

Thanks @DragonSA and to Counterpoint Dynamics (Pty) for sponsoring this. Really cool 👍

Absolutely, thanks for sponsoring ❤️
Would be awesome to see more actions like this.

@vzarytovskii vzarytovskii enabled auto-merge (squash) April 15, 2024 08:46
Copy link
Member

@psfinaki psfinaki left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks!

auto-merge was automatically disabled April 15, 2024 18:05

Head branch was pushed to by a user without write access

@vzarytovskii vzarytovskii enabled auto-merge (squash) April 16, 2024 07:54
@vzarytovskii vzarytovskii merged commit 98250ef into dotnet:main Apr 16, 2024
32 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
Archived in project
Development

Successfully merging this pull request may close these issues.

7 participants