-
Notifications
You must be signed in to change notification settings - Fork 4.6k
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
Covariant Returns Feature #35308
Merged
Merged
Covariant Returns Feature #35308
Changes from 1 commit
Commits
Show all changes
21 commits
Select commit
Hold shift + click to select a range
bf7501f
Covariant Returns Feature: Allowing return types on MethodImpl to be …
fef49b2
Adding the missing .ctor methods to the various types
f10119d
Perform covariant return signature matching only after an exact match…
8d5d87e
Add test coverage for implicit override with less derived return type
a14af6f
Change ValidateMethodImplRemainsInEffect attribute to apply to methods
0e4e472
Moving covariant return type checking to the final stage of type load…
698eafb
Rename attribute and reference it from System.Runtime instead of S.P.C
6848c40
Add test coverage for interface cases.
5a85da8
Handling for struct cases, and adding test coverage for it.
89bb5c3
Small test fixes
cbecf78
Fix consistency issue with the way the RequireMethodImplToRemainInEff…
1154b90
Support covariant returns and slot unifications in crossgen2
f97b9de
some CR feedback
1329fea
Add unit test coverage for delegates
997074f
Fix handling of covariant and contravariant generic interfaces
janvorli ed9fb4c
Added test cases to interfaces unit test
janvorli 6eaaa1a
Fix Nullable handling and add more tests
janvorli 688c263
Reflect Fadi's feedback - limit the GCX_COOP scope
janvorli 3636d03
Reflect PR feedback
janvorli c05f075
Rename the attribute to PreserveBaseOverridesAttribute
janvorli 7ccd3ed
Disable covariant returns tests on Mono for now
janvorli File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
# Covariant Return Methods | ||
|
||
Covariant return methods is a runtime feature designed to support the [covariant return types](https://github.com/dotnet/csharplang/blob/master/proposals/covariant-returns.md) and [records](https://github.com/dotnet/csharplang/blob/master/proposals/records.md) C# language features posed for C# 9.0. | ||
|
||
This feature allows an overriding method to have a more derived reference type than the method it overrides. Covariant return methods can only be described through MethodImpl records, and as an initial implementation, will have the following limitations: | ||
1. Covariant return methods will only be applicable to methods on reference types: the MethodDecl and MethodImpl records can only be on reference types. Methods on interfaces will not be supported. | ||
2. Return types in covariant return methods can only be reference types: covariant interface return types are not supported. | ||
|
||
Supporting interfaces comes with many complications (ex: interface equivalence, default interface methods, variance on generic interfaces, etc...), which is why the feature will initially only support classes. | ||
|
||
MethodImpl checking will allow a return type to vary as long as the override is compatible with the return type of the method overriden (i.e. a derived type). | ||
|
||
If a language wishes for the override to be semantically visible such that users of the more derived type may rely on the covariant return type it shall make the override a newslot method with appropriate visibility AND name to be used outside of the class. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This statement sounds like newslot is not required if the method is not semantically visible (BTW, what exactly does it mean to be semantically visible). Is this correct? |
||
|
||
For virtual method slot MethodImpl overrides, each slot shall be checked for compatible signature on type load. (Implementation note: This behavior can be triggered only if the type has a covariant return type override in its hierarchy, so as to make this pay for play.) | ||
|
||
A new `ValidateMethodImplRemainsInEffectAttribute` shall be added. The presence of this attribute is to require the type loader to ensure that the MethodImpl records specified on the method have not lost their slot unifying behavior due to other actions. In other words, when a MethodImpl on type A overrides some method using a derived return type in the signature, any type deriving from A will be allowed to have a MethodImpl record that overrides the same method as long as the return type used in the signature is the same or more derived than the return type used in the MethodImpl signature on type A. This is used to allow the C# language to require that overrides have the consistent behaviors expected. The expectation is that C# would place this attribute on covariant override methods in classes. | ||
fadimounir marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
## Implementation Notes | ||
|
||
### Signature Checking | ||
|
||
Signature checking for MethodImpl is done through the `MetaSig::CompareElementType` method, which is called from various places in the runtime when comparing method signatures. This method compares the signatures of two types, and will now take a boolean flag that would allow for derived type checking behavior. The boolean flag will be set to `TRUE` appropriately during comparison of the return type signatures between a MethodImpl and MethodDecl records. | ||
|
||
The type signature checking algorithm will perform the following: | ||
1. Traverse and compare the signatures for `type1` and `type2` recursively. | ||
2. If the signatures mismatch at any given point, and the current element type for `type2` is `ELEMENT_TYPE_CLASS` or `ELEMENT_TYPE_GENERICINST`: | ||
+ Check if base type comparison is allowed | ||
+ Compute the parent type's signature and parent type's generic substitution of `type2` | ||
+ Perform a recursive call to re-compare `type1` with the new parent type signature of `type2`. | ||
|
||
Note: if `ELEMENT_TYPE_INTERNAL` is encountered in either of the type signatures, both types will be fully loaded and compared for compatibility. | ||
|
||
### VTable Slot Validation | ||
|
||
Validation will only be performed if the `ValidateMethodImplRemainsInEffectAttribute` exists on the type that needs validation. Validation is only performed on the type where the attribute is added, and does not propagate to its base or derived types (every type that needs to be validated needs to have this attribute). | ||
|
||
Validation is performed at the very last step of `CLASS_LOAD_EXACTPARENTS`, after all base types have been loaded, and the vtable has been fully built. | ||
|
||
The validation algorithm will perform the following: | ||
1. For each slot in the vtable that also exists in the vtable of the base type: | ||
+ Check if the `MethodDesc` on that slot has a different original slot value. If not, continue. | ||
+ Let `hType1` be the `TypeHandle` of the return type of the method on base type. | ||
+ Let `hType2` be the `TypeHandle` of the return type of the method on the current type being validated. | ||
+ Verify that `hType2` is the same type as, or a derived type of `hType1` | ||
|
||
### [Future] Interface Support | ||
|
||
An interface method may be both non-final and have a MethodImpl that declares that it overrides another interface method. If it does, NO other interface method may .override it. Instead further overrides must override the method that it overrode. Also the overriding method may only override 1 method. | ||
|
||
The default interface method resolution algorithm shall change from: | ||
|
||
``` console | ||
Given interface method M and type T. | ||
Let MSearch = M | ||
Let MFound = Most specific implementation within the interfaces for MSearch within type T. If multiple implementations are found, throw Ambiguous match exception. | ||
Return MFound | ||
``` | ||
|
||
To: | ||
|
||
``` console | ||
Given interface method M and type T. | ||
Let MSearch = M | ||
|
||
If (MSearch overrides another method MBase) | ||
Let MSearch = MBase | ||
|
||
Let MFound = Most specific implementation within the interfaces for MSearch within type T. If multiple implementations are found, throw Ambiguous match exception. | ||
Let M Code = NULL | ||
|
||
If ((MFound != Msearch) and (MFound is not final)) | ||
Let M ClassVirtual = ResolveInterfaceMethod for MFound to virtual override on class T without using Default interface method implementation or return NULL if not found. | ||
If (M ClassVirtual != NULL) | ||
Let M Code= ResolveVirtualMethod for MFound on class T to implementation method | ||
|
||
If (M Code != NULL) | ||
Let M Code = MFound | ||
|
||
Check M Code For signature <compatible-with> interface method M. | ||
|
||
Return M Code | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you please add a chapter on this to https://github.com/dotnet/runtime/blob/master/docs/design/specs/Ecma-335-Augments.md ? Try to match the style and language used by ECMA-335 (e.g. in the ideal case - we would just copy&paste it over once we figure out how to make edits to ECMA-335).