-
Notifications
You must be signed in to change notification settings - Fork 4.2k
Fix scoped variance checks involving ref struct interface implementation #78883
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -1154,7 +1154,7 @@ static void checkValidMethodOverride( | |
MethodSymbol overridingMethod, | ||
BindingDiagnosticBag diagnostics) | ||
{ | ||
if (RequiresValidScopedOverrideForRefSafety(overriddenMethod)) | ||
if (RequiresValidScopedOverrideForRefSafety(overriddenMethod, overridingMethod.TryGetThisParameter(out var thisParam) ? thisParam : null)) | ||
{ | ||
CheckValidScopedOverride( | ||
overriddenMethod, | ||
|
@@ -1378,7 +1378,7 @@ static bool isValidNullableConversion( | |
/// Returns true if the method signature must match, with respect to scoped for ref safety, | ||
/// in overrides, interface implementations, or delegate conversions. | ||
/// </summary> | ||
internal static bool RequiresValidScopedOverrideForRefSafety(MethodSymbol? method) | ||
internal static bool RequiresValidScopedOverrideForRefSafety(MethodSymbol? method, ParameterSymbol? overrideThisParameter) | ||
{ | ||
if (method is null) | ||
{ | ||
|
@@ -1404,7 +1404,8 @@ internal static bool RequiresValidScopedOverrideForRefSafety(MethodSymbol? metho | |
// - The method returns a `ref struct` or returns a `ref` or `ref readonly`, or the method has a `ref` or `out` parameter of `ref struct` type, and | ||
// ... | ||
int nRefParametersRequired; | ||
if (method.ReturnType.IsRefLikeOrAllowsRefLikeType() || | ||
if ((overrideThisParameter is { RefKind: RefKind.Ref or RefKind.Out } && overrideThisParameter.Type.IsRefLikeOrAllowsRefLikeType()) || | ||
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. Should we also check scoped mismatch of the receiver in CheckValidScopedOverride? 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. I do not think there is a need to do this. To my understanding, the only way to adjust the scoped-ness of a this parameter is to use I believe similar enforcement already exists for other forms of unsafe |
||
method.ReturnType.IsRefLikeOrAllowsRefLikeType() || | ||
(method.RefKind is RefKind.Ref or RefKind.RefReadOnly)) | ||
{ | ||
nRefParametersRequired = 1; | ||
|
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.
I do not believe there is a scenario where the this parameter of an interface implementation is an out parameter. Generally only a this parameter of a constructor is an out parameter. But, it seems correct in principle to try to detect it here.
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.
The
IsRefLikeOrAllowsRefLikeType
call checks for both aref struct
and a type parameter with theallows ref struct
anti-constraint. Is that latter check necessary? I would assume we only needIsRefLikeType
check here. Is there a case I'm missing?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.
I don't think we expect the this-parameter of an override/implementation to be a type parameter ever. We could use the IsRefLikeType check and assert that we don't have a type parameter here.
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.
I am going to keep the code as-is because if a this-parameter of type-parameter type hypothetically made it into here, it feels reasonable to handle it in the way this implementation is handling it. It doesn't seem like a condition where we have to rethink everything if the language changes to make it possible to occur one day.