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

Prefer extension methods to intrinsic properties when arguments are provided #16032

Conversation

smoothdeveloper
Copy link
Contributor

@smoothdeveloper smoothdeveloper commented Sep 23, 2023

There are APIs that define extension methods that bear same name as properties, despite it is not possible to define method with same name as a property in C# or F# (and presumably VB.NET).

For cases such as:

  • the type checking can't resolve a property
  • arguments are provided
  • an extension method is in scope a would match the arguments provided

We'd like the extension method to be used as the resolution, instead of a type checking error.

Things to check in tests:

  • not breaking/shadowing indexed properties
  • not breaking/shadowing event handlers
  • not breaking chained calls (x.Y.Z.ToString())
  • not breaking/shadowing function properties
  • not breaking fluent notation
  • shadowing static property with static method in type extension
  • shadowing through type extensions
  • shadowing through opening modules works as expected
  • consuming some of the libraries that extensively use this idiom (Linq, Spectre.Console, NXUI)

Things to do:

  • writing RFC
    • consider how the F# shadowing related to open is going to work with the feature (when opening the namespace with a type after the namespace with the extension method for it, or doing the reverse)
    • discuss what happens with extension properties
    • discuss possible nuances / decisions the support for this could surface
  • Language version check

Related: fsharp/fslang-suggestions#1039

… property of same name exists and arguments are passed to it (assuming property is not a function value).

Lots of things to sort out, this just takes care of the first layer of interaction between CheckExpression and NameResolution.

Given impact on service / tooling, it is not clear that adding an entry in NameResolution.Item is the best choice, may reconsider into changing the return type of ResolveLongIdentInTypePrim instead.
@smoothdeveloper smoothdeveloper requested a review from a team as a code owner September 23, 2023 00:50
@smoothdeveloper
Copy link
Contributor Author

image

@vzarytovskii vzarytovskii marked this pull request as draft October 9, 2023 09:59
@smoothdeveloper
Copy link
Contributor Author

smoothdeveloper commented Oct 9, 2023

image

the right information shows in the tooltip, but it doesn't behave the same as in C#:

image

smoothdeveloper and others added 7 commits October 10, 2023 15:48
…lear how many things will be broken, but it does what is expected in VS
…ithub.com:smoothdeveloper/visualfsharp into extension-method-priority-when-arguments-provided
…out extension method only, rather than the kind of all items (type and ctor method were being split, causing a test to fail and more entries in the completion list not related to accessing properties or extension methods).
@psfinaki
Copy link
Member

psfinaki commented Nov 3, 2023

/azp run

Copy link

Azure Pipelines successfully started running 2 pipeline(s).

@psfinaki
Copy link
Member

/azp run

Copy link

Pull request contains merge conflicts.

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.

Looks good. Let's fix the CI and put some clarifications in the comments and then it can likely go in.

src/Compiler/Service/ServiceDeclarationLists.fs Outdated Show resolved Hide resolved
src/Compiler/Checking/NameResolution.fs Show resolved Hide resolved
src/Compiler/Checking/NameResolution.fs Outdated Show resolved Hide resolved
…w both event and extension method (only event can be called).

The new logic 100% preserves the previous behaviour in absence of the particular condition we are interested for in RFC-1137.

In case the condition for RFC-1137 hits, we partition the items for those to be split apart (property and extension methods), taking care of discarding items as we yield the expected tuples that correspond to each item and the rest is processed as it was originally.

There are still probably loopholes with items showing up separated, but this would only impact if there are actually extension method and property with same name.
…ithub.com:smoothdeveloper/visualfsharp into extension-method-priority-when-arguments-provided
@smoothdeveloper
Copy link
Contributor Author

@psfinaki I made a better implementation for DeclarationListInfo.Create which behaved fine in my tests and would preclude any regression if we don't hit the specific condition the new logic is supposed to occur.

Also created #16255 in case I have a chance of authoring tests around intellisense.

I noticed that even currently, intellisense would list info for items that can't be called:

image

Somehow, Rider shows them in the more appropriate order for this particular case.

To me, this shows that DeclarationListInfo.Create is shaky ground.

Aside, I'm sensing there are blind spots in the RFC and implementation, if we'd only want the feature to work for the expected use cases (extension methods as they are defined in C# and nothing else, etc.) due to type extension in F# allowing pretty much all kinds of constructs and me having taken the short route.

I think this should get some scrutiny and having the team to decide if we keep the knobs set the way it is, or try to shut the door to those possibilities for sake of being conservative.

Nonetheless, this implementation is probably passing the bar for a preview feature.

@psfinaki
Copy link
Member

The current implementation LGTM, will take another look tomorrow with a fresher head. It would be probably helpful to list all the potential blind spots in one place (e.g. RFC ticket, or here) - so that we can refer to it in future discussions.

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.

So I think I would prefer some more extensive method resolution testing - either in this PR or as a followup/side. RFC-wise, this is an awesome job. Thanks!

@smoothdeveloper
Copy link
Contributor Author

@psfinaki, would you mind sharing some ideas over more tests for the method resolution? I tired to have thorough checks, and didn't come up with more examples I wanted to add when I was implementing it.

I can definitely add more tests in the PR if anyone wants new particular cases, just le me know.

@vzarytovskii vzarytovskii enabled auto-merge (squash) November 21, 2023 13:01
@psfinaki
Copy link
Member

So relooking at the PR now - probably this is good as it is, especially given that you've done some manual testing as well. Let's have this in and see the changes in action.

@vzarytovskii vzarytovskii merged commit 4355e04 into dotnet:main Nov 21, 2023
24 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.

4 participants