[WIP] Covariant Returns Feature (#35308)
authorFadi Hanna <fadi.mounir@outlook.com>
Mon, 1 Jun 2020 18:24:04 +0000 (11:24 -0700)
committerGitHub <noreply@github.com>
Mon, 1 Jun 2020 18:24:04 +0000 (20:24 +0200)
commitfa141526c036c4b10809d4d7258e885e45a77f54
tree7228423da6007777bd427e836312faedce50abf3
parent4fcb0b10118e2231ad665ed878472dba0999107e
[WIP] Covariant Returns Feature (#35308)

* Covariant Returns Feature: Allowing return types on MethodImpl to be derived types of the return type on the MethodDecl.

Feature limitations:
  - Only supports MethodImpls and MethodDecls on classes (no interfaces/valuetypes).
  - MethodImpl and MethodDecl cannot be on the same type.
  - Interface/valuetypes not supported as covariant return types.

Changes are mostly a boolean flag being passed around to allow for covariant type checking in method signatures.
Generics are handled by correctly keeping track of the substitution chain while traversing the base type hierarchy for type comparison.

All method signature comparisons uses metadata for checking, without loading any type (with some exceptions).

Validation for the `ValidateMethodImplRemainsInEffectAttribute` is performed at the very last step of `CLASS_LOAD_EXACTPARENTS`.

Includes unit tests to cover positive/negative scenarios:
  - Non-generics
  - Generics, with various levels of complexities on generic instantiations and substitutions
  - GVMs
  - Delegates
  - Tests for validation of the existance/absence of the ValidateMethodImplRemainsInEffectAttribute
  - Interface and valuetype scenarios (negative scenarios)

* Adding the missing .ctor methods to the various types

* Perform covariant return signature matching only after an exact match fails

* Add test coverage for implicit override with less derived return type

* Change ValidateMethodImplRemainsInEffect attribute to apply to methods

* Moving covariant return type checking to the final stage of type loading, and use CanCastTo instead of signature-based checking, to be allow for type compatibility based on ECMA I.8.7.1.

* Rename attribute and reference it from System.Runtime instead of S.P.C

* Add test coverage for interface cases.

* Handling for struct cases, and adding test coverage for it.

* Small test fixes

* Fix consistency issue with the way the RequireMethodImplToRemainInEffectAttribute is declared

* Support covariant returns and slot unifications in crossgen2

These changes fix the behavior of the devirtualization algorithm to not incorrectly devirtualize covariant return methods that have the slot unification attribute

* Add unit test coverage for delegates

* Fix handling of covariant and contravariant generic interfaces

Also add tests for those.

* Added test cases to interfaces unit test

Based on PR feedback, I've added test cases to verify the load level
asserts change.

* Fix Nullable handling and add more tests

The attempt to overload method with int32 return value by a method with
Nullable<int32> was asserting in CanCastTo. This change fixes it by
pre-checking this case before calling into CanCastTo.
I've also slightly refactored the
ValidateMethodsWithCovariantReturnTypes by extracting the
compatible-with stuff into IsCompatibleWith method.

Added tests to test various compatible-with differences from the
originally used CanCastTo

- Change the CompatibleWithTest to call virtual methods on test
classes instead of just instantiating the classes.
- Update crossgen2 similar to the runtime to have IsCompatibleWith
method doing the same pre-filtering before calling CanCastTo.

* Rename the attribute to PreserveBaseOverridesAttribute

* Disable covariant returns tests on Mono for now

The mono doesn't implement the feature yet

Co-authored-by: Fadi Hanna <fadim@microsoft.com>
Co-authored-by: Jan Vorlicek <janvorli@microsoft.com>
97 files changed:
docs/design/features/covariant-return-methods.md [new file with mode: 0644]
src/coreclr/src/dlls/mscorrc/mscorrc.rc
src/coreclr/src/dlls/mscorrc/resource.h
src/coreclr/src/tools/Common/TypeSystem/Common/CastingHelper.cs
src/coreclr/src/tools/Common/TypeSystem/Common/MetadataRuntimeInterfacesAlgorithm.cs
src/coreclr/src/tools/Common/TypeSystem/Common/MetadataVirtualMethodAlgorithm.cs
src/coreclr/src/tools/Common/TypeSystem/Common/MethodDesc.cs
src/coreclr/src/tools/Common/TypeSystem/Common/TypeSystemHelpers.cs
src/coreclr/src/vm/class.cpp
src/coreclr/src/vm/classcompat.cpp
src/coreclr/src/vm/clsload.hpp
src/coreclr/src/vm/ecall.cpp
src/coreclr/src/vm/memberload.cpp
src/coreclr/src/vm/method.hpp
src/coreclr/src/vm/methodtable.cpp
src/coreclr/src/vm/methodtable.h
src/coreclr/src/vm/methodtablebuilder.cpp
src/coreclr/src/vm/methodtablebuilder.h
src/coreclr/src/vm/runtimehandles.cpp
src/coreclr/src/vm/siginfo.cpp
src/coreclr/src/vm/siginfo.hpp
src/coreclr/src/vm/typehandle.cpp
src/coreclr/src/vm/wellknownattributes.h
src/coreclr/tests/issues.targets
src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/Interfaces/UnitTest.il [new file with mode: 0644]
src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/Interfaces/UnitTest.ilproj [new file with mode: 0644]
src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/Interfaces/UnsupportedScenario1.il [new file with mode: 0644]
src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/Interfaces/UnsupportedScenario1.ilproj [new file with mode: 0644]
src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/Interfaces/UnsupportedScenario2.il [new file with mode: 0644]
src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/Interfaces/UnsupportedScenario2.ilproj [new file with mode: 0644]
src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/Interfaces/UnsupportedScenario3.il [new file with mode: 0644]
src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/Interfaces/UnsupportedScenario3.ilproj [new file with mode: 0644]
src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/ReturnTypeValidation/ImplicitOverrideSameSigAsDecl.il [new file with mode: 0644]
src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/ReturnTypeValidation/ImplicitOverrideSameSigAsDecl.ilproj [new file with mode: 0644]
src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/ReturnTypeValidation/OverrideSameSigAsDecl.il [new file with mode: 0644]
src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/ReturnTypeValidation/OverrideSameSigAsDecl.ilproj [new file with mode: 0644]
src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/Structs/IncompatibleOverride.il [new file with mode: 0644]
src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/Structs/IncompatibleOverride.ilproj [new file with mode: 0644]
src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/AttributeTesting.il [new file with mode: 0644]
src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/AttributeTesting.ilproj [new file with mode: 0644]
src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/CompatibleWithTest.il [new file with mode: 0644]
src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/CompatibleWithTest.ilproj [new file with mode: 0644]
src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/A.il [new file with mode: 0644]
src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/A.ilproj [new file with mode: 0644]
src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/B.il [new file with mode: 0644]
src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/B.ilproj [new file with mode: 0644]
src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/C.il [new file with mode: 0644]
src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/C.ilproj [new file with mode: 0644]
src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/Dictionary.il [new file with mode: 0644]
src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/Dictionary.ilproj [new file with mode: 0644]
src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/GenBaseType.il [new file with mode: 0644]
src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/GenBaseType.ilproj [new file with mode: 0644]
src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/GenDerive1.il [new file with mode: 0644]
src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/GenDerive1.ilproj [new file with mode: 0644]
src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/GenDerive2.il [new file with mode: 0644]
src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/GenDerive2.ilproj [new file with mode: 0644]
src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/GenDerive3.il [new file with mode: 0644]
src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/GenDerive3.ilproj [new file with mode: 0644]
src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/GenRetType.il [new file with mode: 0644]
src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/GenRetType.ilproj [new file with mode: 0644]
src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/GenTestType.il [new file with mode: 0644]
src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/GenTestType.ilproj [new file with mode: 0644]
src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/GenToNonGen1.il [new file with mode: 0644]
src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/GenToNonGen1.ilproj [new file with mode: 0644]
src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/GenToNonGen2.il [new file with mode: 0644]
src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/GenToNonGen2.ilproj [new file with mode: 0644]
src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/GenToNonGen3.il [new file with mode: 0644]
src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/GenToNonGen3.ilproj [new file with mode: 0644]
src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/NonGenThroughGen1.il [new file with mode: 0644]
src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/NonGenThroughGen1.ilproj [new file with mode: 0644]
src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/NonGenThroughGen2.il [new file with mode: 0644]
src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/NonGenThroughGen2.ilproj [new file with mode: 0644]
src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/NonGenThroughGen3.il [new file with mode: 0644]
src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/NonGenThroughGen3.ilproj [new file with mode: 0644]
src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/NonGenThroughGen4.il [new file with mode: 0644]
src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/NonGenThroughGen4.ilproj [new file with mode: 0644]
src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/NonGenericDerived1.il [new file with mode: 0644]
src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/NonGenericDerived1.ilproj [new file with mode: 0644]
src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/NonGenericDerived2.il [new file with mode: 0644]
src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/NonGenericDerived2.ilproj [new file with mode: 0644]
src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/NonGenericDerived3.il [new file with mode: 0644]
src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/NonGenericDerived3.ilproj [new file with mode: 0644]
src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/NonGenericDerived4.il [new file with mode: 0644]
src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/NonGenericDerived4.ilproj [new file with mode: 0644]
src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/OverrideMoreDerivedReturn.il [new file with mode: 0644]
src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/OverrideMoreDerivedReturn.ilproj [new file with mode: 0644]
src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/UnitTest.il [new file with mode: 0644]
src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/UnitTest.ilproj [new file with mode: 0644]
src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/UnitTestDelegates.il [new file with mode: 0644]
src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/UnitTestDelegates.ilproj [new file with mode: 0644]
src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/UnitTestMultiModule.il [new file with mode: 0644]
src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/UnitTestMultiModule.ilproj [new file with mode: 0644]
src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/UnitTest_GVM.il [new file with mode: 0644]
src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/UnitTest_GVM.ilproj [new file with mode: 0644]
src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems
src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/PreserveBaseOverridesAttribute.cs [new file with mode: 0644]
src/libraries/System.Runtime/ref/System.Runtime.cs