-
Notifications
You must be signed in to change notification settings - Fork 5.4k
Description
This new attribute will be used by the covariant return types and records C# language features posed for C# 9.0.
Today when we have an explicit override to a method (using MethodImpls), this override gets a new vtable slot on the type, and the slot for the overriden method gets updated to point to the new overriding method. Example:
// Pseudo code with some IL
class A {
void VirtualFunction() { }
}
class B : A {
void VirtualFunction() { .override A.VirtualFunction }
}
// VTable for type A:
// [0]: A.VirtualFunction
// VTable for type B:
// [0]: B.VirtualFunction
// [1]: B.VirtualFunctionNow when a new derived type explicitly overrides A.VirtualFunction, it would also get a new vtable slot, and only the vtable slot of the method being overriden gets updated with the new override. Example:
class C : B {
void VirtualFunction() { .override A.VirtualFunction }
}
// VTable for type A:
// [0]: A.VirtualFunction
//
// VTable for type B:
// [0]: B.VirtualFunction
// [1]: B.VirtualFunction
//
// VTable for type C:
// [0]: C.VirtualFunction
// [1]: B.VirtualFunction -> This slot does not get overriden
// [2]: C.VirtualFunctionWith the new records and covariant return feature, a change of behavior is required to vtable slot overrides when a method gets explictly overriden. In the example above, the second slot on type C would also need to be updated to point to the latest override of the method:
// VTable for type C:
// [0]: C.VirtualFunction
// [1]: C.VirtualFunction -> This slot needs to be updated as well
// [2]: C.VirtualFunctionThe reason for this change is to ensure that any virtual call to the method, whether it uses the base signature or derived signature of the method, we always execute the most derived override:
// Given an object of type C:
callvirt A.VirtualFunction -> Executes C.VirtualFunction
callvirt B.VirtualFunction -> Executes C.VirtualFunction
callvirt C.VirtualFunction -> Executes C.VirtualFunctionTo achieve this, a new attribute will be introduced and applied to the MethodImpls that need to propagate to all applicable vtable slots: RequireMethodImplToRemainInEffect attribute. Example:
class A {
void VirtualFunction() { }
}
class B : A {
void VirtualFunction() { .override A.VirtualFunction }
}
class C : B {
[RequireMethodImplToRemainInEffect]
void VirtualFunction() { .override A.VirtualFunction }
}This attribute will only be applicable to methods with explicit overrides (MethodImpls), and takes no arguments. The proposed namespace for this attribute is the System.Runtime.CompilerServices namespace. Here is the proposed implementation of the attribute:
namespace System.Runtime.CompilerServices
{
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = false)]
public sealed class RequireMethodImplToRemainInEffectAttribute : Attribute
{
}
}