Create overload-resolution-priority.md (#627)
This commit is contained in:
Родитель
af513bd5d3
Коммит
6f3c63a943
|
@ -0,0 +1,125 @@
|
|||
# Overload Resolution Priority
|
||||
|
||||
## Summary
|
||||
[summary]: #summary
|
||||
|
||||
We introduced a new attribute, `System.Runtime.CompilerServices.OverloadResolutionPriority`, that can be used by API authors to adjust the relative priority of
|
||||
overloads within a single type as a means of steering API consumers to use specific APIs, even if those APIs would normally be considered ambiguous or otherwise
|
||||
not be chosen by overload resolution rules. See [Overload Resolution Priority in C#](https://github.com/dotnet/csharplang/blob/main/proposals/csharp-13.0/overload-resolution-priority.md).
|
||||
|
||||
## Motivation
|
||||
[motivation]: #motivation
|
||||
|
||||
API authors often run into an issue of what to do with a member after it has been obsoleted. For backwards compatibility purposes, many will keep the existing member around
|
||||
with `ObsoleteAttribute` set to error in perpetuity, in order to avoid breaking consumers who upgrade binaries at runtime. This particularly hits plugin systems, where the
|
||||
author of a plugin does not control the environment in which the plugin runs. The creator of the environment may want to keep an older method present, but block access to it
|
||||
for any newly developed code. However, `ObsoleteAttribute` by itself is not enough. The type or member is still visible in overload resolution, and may cause unwanted overload
|
||||
resolution failures when there is a perfectly good alternative, but that alternative is either ambiguous with the obsoleted member, or the presence of the obsoleted member causes
|
||||
overload resolution to end early without ever considering the good member. For this purpose, we want to have a way for API authors to guide overload resolution on resolving the
|
||||
ambiguity, so that they can evolve their API surface areas and steer users towards performant APIs without having to compromise the user experience.
|
||||
|
||||
## Detailed Design
|
||||
[detailed-design]: #detailed-design
|
||||
|
||||
### Overload resolution priority
|
||||
|
||||
We define a new concept, ***overload_resolution_priority***, which is used during the process of overload resolution. ***overload_resolution_priority*** is a 32-bit integer
|
||||
value. All methods have an ***overload_resolution_priority*** of 0 by default, and this can be changed by applying
|
||||
[`OverloadResolutionPriorityAttribute`](#systemruntimecompilerservicesoverloadresolutionpriorityattribute) to a method. We update section
|
||||
[Overloaded Method Resolution](https://github.com/dotnet/vblang/blob/main/spec/overload-resolution.md#overloaded-method-resolution) of the VB specification as
|
||||
follows (change in **bold**):
|
||||
|
||||
> 2. Next, eliminate all members from the set that are inaccessible or not applicable (Section [Applicability To Argument List](overload-resolution.md#applicability-to-argument-list)) to the argument list
|
||||
|
||||
> **3. Then, the reduced set of candidate members is grouped by declaring type.
|
||||
> If the member is an override, the declaring type and the ***overload_resolution_priority*** come from the least-derived declaration of that member.
|
||||
> Within each group:**
|
||||
|
||||
> - **A maximum ***overload_resolution_priority*** among candidates that do not utilize narrowing conversions or narrowing delegate relaxation is determined.**
|
||||
> - **All members that have a lower ***overload_resolution_priority*** than the maximum found during the previous step, if any, within its declaring type group are removed.**
|
||||
|
||||
> **The reduced groups are then recombined into the set of candidates.**
|
||||
|
||||
> **4**. Next, if one or more arguments are `AddressOf` or lambda expressions, then calculate the *delegate relaxation levels* for each such argument as below. If the worst (lowest) delegate relaxation level in `N` is worse than the lowest delegate relaxation level in `M`, then eliminate `N` from the set. The delegate relaxation levels are as follows:
|
||||
|
||||
As an example, this feature would cause the following code snippet to print "I1", rather than failing compilation due to an ambiguity:
|
||||
|
||||
```vb
|
||||
Public Interface I1
|
||||
End Interface
|
||||
Public Interface I2
|
||||
End Interface
|
||||
Public Interface I3
|
||||
Inherits I1, I2
|
||||
End Interface
|
||||
|
||||
Public Class C
|
||||
<OverloadResolutionPriority(1)>
|
||||
Public Shared Sub M(x As I1)
|
||||
System.Console.WriteLine("I1")
|
||||
End Sub
|
||||
Public Shared Sub M(x As I2)
|
||||
System.Console.WriteLine("I2")
|
||||
End Sub
|
||||
End Class
|
||||
|
||||
Public Class Program
|
||||
Shared Sub Main()
|
||||
Dim i3 As I3 = Nothing
|
||||
C.M(i3)
|
||||
End Sub
|
||||
End Class
|
||||
```
|
||||
|
||||
Negative numbers are allowed to be used, and can be used to mark a specific overload as worse than all other default overloads.
|
||||
|
||||
The **overload_resolution_priority** of a member comes from the least-derived declaration of that member. **overload_resolution_priority** is not
|
||||
inherited or inferred from any interface members a type member may implement, and given a member `Mx` that implements an interface member `Mi`, no
|
||||
warning is issued if `Mx` and `Mi` have different **overload_resolution_priorities**.
|
||||
|
||||
### `System.Runtime.CompilerServices.OverloadResolutionPriorityAttribute`
|
||||
|
||||
There is the following attribute in the BCL:
|
||||
|
||||
```cs
|
||||
namespace System.Runtime.CompilerServices;
|
||||
|
||||
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Constructor | AttributeTargets.Property, AllowMultiple = false, Inherited = false)]
|
||||
public sealed class OverloadResolutionPriorityAttribute(int priority) : Attribute
|
||||
{
|
||||
public int Priority => priority;
|
||||
}
|
||||
```
|
||||
|
||||
All methods in VB have a default ***overload_resolution_priority*** of 0, unless they are attributed with `OverloadResolutionPriorityAttribute`. If they are
|
||||
attributed with that attribute, then their ***overload_resolution_priority*** is the integer value provided to the first argument of the attribute.
|
||||
|
||||
### Langversion Behavior
|
||||
|
||||
Overload Resolution process does not perform filtering by ***overload_resolution_priority*** in VB < 17.13.
|
||||
No errors or warnings issued by the Overload Resolution process due to the fact that ***overload_resolution_priority***
|
||||
was ignored in this case.
|
||||
|
||||
|
||||
## Open Questions
|
||||
|
||||
### Should `OverloadResolutionPriorityAttribute` be disallowed in some locations?
|
||||
|
||||
By analogy with C# we could make it an error to apply `OverloadResolutionPriorityAttribute` to the following locations:
|
||||
|
||||
* Property, or event accessors
|
||||
* Conversion operators
|
||||
* Finalizers
|
||||
* Shared constructors
|
||||
* Overriding properties
|
||||
* Overriding methods
|
||||
|
||||
Attributes encountered on these locations in metadata effectively will have no impact in VB code.
|
||||
|
||||
Reporting an error might be a breaking change because VB allowed the attribute at any location before.
|
||||
|
||||
### Langversion Behavior
|
||||
|
||||
Should a langversion errors be issued when `OverloadResolutionPriorityAttribute` is applied?
|
||||
|
||||
Reporting the error might be a breaking change because VB allowed the attribute in the previous version.
|
Загрузка…
Ссылка в новой задаче