dotnet / roslyn

The Roslyn .NET compiler provides C# and Visual Basic languages with rich code analysis APIs.
https://docs.microsoft.com/dotnet/csharp/roslyn-sdk/
MIT License
18.98k stars 4.03k forks source link

Overload resolution API #69898

Open syrompetka opened 1 year ago

syrompetka commented 1 year ago

Background and Motivation

Overload resolution logic is very complicated and "hidden" inside Roslyn internals. I'd like to be able to resolve best method overload by list of argument type and/or parameter modifiers. For example in Reflection API System.Type has GetMethod(string name, Type[] types, ParameterModifier[] modifiers)

Proposed API

Inroduce new method for ITypeSymbol GetMethod: IMethodSymbol? GetMethod(string name, Type[] parameterTypes, RefKind[]? parameterRefKinds)

jaredpar commented 1 year ago

How does this help overload resolution though? That is a much more complex process than looking for a method with a particular signature.

syrompetka commented 1 year ago

How does this help overload resolution though?

I have a bunch of variables (and their types) and a class with dozen of Add methods. I need to find valid method to invoke with these variables (if there is one)

That is a much more complex process than looking for a method with a particular signature.

Exactly. And this process is completely hidden "under the hood" and not reusable.

jaredpar commented 1 year ago

And this process is completely hidden "under the hood" and not reusable.

How would you recommend it be exposed?

I have a bunch of variables (and their types) and a class with dozen of Add methods. I need to find valid method to invoke with these variables (if there is one)

What is the issue with calling GetMembers(string name) and then matching on the type arguments?

syrompetka commented 1 year ago

What is the issue with calling GetMembers(string name) and then matching on the type arguments?

parameters can be subclasses of method argument types parameters can have redefinded conversion operators method can have default arguments method can have param argument

To make such mathchin properly I'll have to reimplement all the matching logic.

jaredpar commented 1 year ago

Doing all that work though just tells if you if a given method is a valid candidate for the arguments, it does not tell if you if it would be the result of overload resolution.

syrompetka commented 1 year ago

Looks like we have some terminology mismatch ... Finding valid method for the arguments isn't it "overload resolution"?

jaredpar commented 1 year ago

Couple of terminology bits for an expression it the form of e.M(x1, ... xN):

Overload resolution is the process by which that expression is evaluated and a single applicable candidate method. The process begins by finding all candidate methods for the invocation, filtering down to the applicable candidate methods and then picking the best one of that set. If exactly one best is chosen then overload resolution succeeds, otherwise it fails.

Based on your comments here you seem to be mostly asking for ways to determine if a given candidate method is applicable to to a given set of types. The actual process is a bit more complicated though because really overload resolution operates on expressions, not types. This is important because some expressions types can change based on what types they're evaluated against.

Note: i've simplified overload resolution quite a bit here, mostly just trying to get the parts pulled out that are most likely to be relevant to an API discussion

syrompetka commented 1 year ago

Based on your comments here you seem to be mostly asking for ways to determine if a given candidate method is applicable to to a given set of types.

Mmm, no. I'm asking for a way to find the best method from a set of methods with same name by a given set parameters (or types of these parameters).

Initially:

I'd like to be able to resolve best method overload by list of argument type and/or parameter modifiers.

jaredpar commented 1 year ago

I'd like to be able to resolve best method overload by list of argument type and/or parameter modifiers.

That is going to give you incomplete information. In order to know the correct result of overload resolution you need the following:

  1. The set of using in play as this impacts extension methods
  2. The namespace in which the evaluation occurs as this impacts the set of available candidate methods.
  3. The type in which the evaluation occurs as this impacts set of available candidates as well as whether not candidates are applicable (which type you are in can change whether certain conversions are legal, what members are accessible, etc ...)
  4. The collection of expressions, not the types. The reason for this is many expressions have no type, or a natural type, which is influenced by the type they are evaluated against. Example here would be () => 42 has a natural type of Func<int> but it would also convert to delegate int D1(); if that was in a parameter list.
syrompetka commented 1 year ago

Stuff usually happens inside SyntaxVisitor/Rewriter in corresponding "Visit" method. I already have ITypeInfo which means I have SemanticModel for current SyntaxTree. Isn't there enough information about available usings, namespaces, etc?

Moving from types to expressions would be even better.

syrompetka commented 1 year ago

BTW, there is already LightweightOverloadResolution.cs in Roslyn codebase that mimics standart resolution for IntelliSence purposes.