Skip to content
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

Disallow ref to in/ref readonly method parameter conversion #71531

Merged
merged 7 commits into from
Jan 16, 2024

Conversation

jjonescz
Copy link
Member

@jjonescz jjonescz commented Jan 8, 2024

Fixes #71383.
Corresponding speclet update: dotnet/csharplang#7820
Test plan: #68056

@jjonescz jjonescz added the New Feature - Ref Readonly Parameters `ref readonly` parameters label Jan 8, 2024
@dotnet-issue-labeler dotnet-issue-labeler bot added Area-Compilers untriaged Issues and PRs which have not yet been triaged by a lead labels Jan 8, 2024
@jjonescz jjonescz marked this pull request as ready for review January 9, 2024 14:55
@jjonescz jjonescz requested a review from a team as a code owner January 9, 2024 14:55
@jjonescz jjonescz marked this pull request as draft January 9, 2024 14:56
@jjonescz jjonescz marked this pull request as ready for review January 9, 2024 14:56
// In method group conversions,
// - 'in' is allowed to be converted to 'ref',
// - 'ref readonly' is allowed to be converted to 'ref' or 'in',
// - 'in' is allowed to be converted to 'ref readonly'.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reading through this chart, occurs to me that out should be allowed to convert to ref. I do not want to change the scope of the PR to include this. Just a thought that occured.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems safe, but that probably needs a separate proposal, right?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agree. Not sure it's worth it, just occurred to me when reading this particular part of the change.

@@ -1937,7 +1937,7 @@ internal bool MethodIsCompatibleWithDelegateOrFunctionPointer(BoundExpression? r
// * Every ref or similar parameter has an identity conversion to the corresponding target parameter
// Note the addition of the reference requirement: it means that for delegate type void D(int i), void M(long l) is
// _applicable_, but not _compatible_.
if (!hasConversion(this, delegateType.TypeKind, Conversions, delegateParameter.Type, methodParameter.Type, delegateParameter.RefKind, methodParameter.RefKind, ref useSiteInfo))
if (!hasConversion(delegateType.TypeKind, Conversions, source: delegateParameter.Type, destination: methodParameter.Type, sourceRefKind: delegateParameter.RefKind, destinationRefKind: methodParameter.RefKind, checkingReturns: false, ref useSiteInfo))
Copy link
Contributor

@AlekseyTs AlekseyTs Jan 11, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if (!hasConversion(delegateType.TypeKind, Conversions, source: delegateParameter.Type, destination: methodParameter.Type, sourceRefKind: delegateParameter.RefKind, destinationRefKind: methodParameter.RefKind, checkingReturns: false, ref useSiteInfo))

It looks like this line became too long to fit an average screen. Consider splitting it #Closed

@@ -1958,7 +1958,7 @@ internal bool MethodIsCompatibleWithDelegateOrFunctionPointer(BoundExpression? r
bool returnsMatch = delegateOrFuncPtrMethod switch
{
{ RefKind: RefKind.None, ReturnsVoid: true } => method.ReturnsVoid,
{ RefKind: var destinationRefKind } => hasConversion(this, delegateType.TypeKind, Conversions, methodReturnType, delegateReturnType, method.RefKind, destinationRefKind, ref useSiteInfo),
{ RefKind: var destinationRefKind } => hasConversion(delegateType.TypeKind, Conversions, source: methodReturnType, destination: delegateReturnType, sourceRefKind: method.RefKind, destinationRefKind: destinationRefKind, checkingReturns: true, ref useSiteInfo),
Copy link
Contributor

@AlekseyTs AlekseyTs Jan 11, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

{ RefKind: var destinationRefKind } => hasConversion(delegateType.TypeKind, Conversions, source: methodReturnType, destination: delegateReturnType, sourceRefKind: method.RefKind, destinationRefKind: destinationRefKind, checkingReturns: true, ref useSiteInfo),

Consider splitting this line too #Closed

// Allowed ref kind mismatches between parameters have already been checked by overload resolution.
if (checkingReturns
? sourceRefKind != destinationRefKind
: (sourceRefKind != RefKind.None) != (destinationRefKind != RefKind.None))
Copy link
Contributor

@AlekseyTs AlekseyTs Jan 11, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(sourceRefKind != RefKind.None) != (destinationRefKind != RefKind.None)

(sourceRefKind == RefKind.None) != (destinationRefKind == RefKind.None)? It feels like there are too many != in the code #Closed

@@ -1488,7 +1488,7 @@ private static LambdaConversionResult IsAnonymousFunctionCompatibleWithDelegate(
{
for (int p = 0; p < delegateParameters.Length; ++p)
{
if (!OverloadResolution.AreRefsCompatibleForMethodConversion(delegateParameters[p].RefKind, anonymousFunction.RefKind(p), compilation) ||
if (!OverloadResolution.AreRefsCompatibleForMethodConversion(source: anonymousFunction.RefKind(p), destination: delegateParameters[p].RefKind, compilation) ||
Copy link
Contributor

@AlekseyTs AlekseyTs Jan 11, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

source:

Naming of parameters feels confusing to me. Data flow from delegate parameter to the lambda parameter. So, I would expect the delegate parameter to be the "source". #Closed

@@ -3305,7 +3305,7 @@ internal EffectiveParameters(ImmutableArray<TypeWithAnnotations> types, Immutabl
return argRefKind;
}
}
else if (AreRefsCompatibleForMethodConversion(paramRefKind, argRefKind, binder.Compilation))
else if (AreRefsCompatibleForMethodConversion(source: paramRefKind, destination: argRefKind, binder.Compilation))
Copy link
Contributor

@AlekseyTs AlekseyTs Jan 11, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

source

Similar comment here about parameter naming. Argument is the "source", its value flows to the parameter #Closed

// In method group conversions, 'in' is allowed to match 'ref' and 'ref readonly' is allowed to match 'ref' or 'in'.
internal static bool AreRefsCompatibleForMethodConversion(RefKind x, RefKind y, CSharpCompilation compilation)
// In method group conversions,
// - 'in' is allowed to be converted to 'ref',
Copy link
Contributor

@AlekseyTs AlekseyTs Jan 11, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

'in' is allowed to be converted to 'ref',

Same comment as for the speclet update. I don't think the language has a concept conversion for modifiers. #Closed

// - 'in' is allowed to be converted to 'ref',
// - 'ref readonly' is allowed to be converted to 'ref' or 'in',
// - 'in' is allowed to be converted to 'ref readonly'.
internal static bool AreRefsCompatibleForMethodConversion(RefKind source, RefKind destination, CSharpCompilation compilation)
Copy link
Contributor

@AlekseyTs AlekseyTs Jan 11, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

source

As mentioned earlier, I find the naming of parameters confusing. Would it make sense to switch to terms like "delegateParameterRefKind" and "candidateMethodParameterRefKind"? #Closed

@AlekseyTs
Copy link
Contributor

Done with review pass (commit 4), tests are not looked at

Copy link
Contributor

@AlekseyTs AlekseyTs left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM (commit 5). I didn't do thorough review of test, relied on @jaredpar sign-off for that.

@jaredpar
Copy link
Member

I didn't do thorough review of test, relied on @jaredpar sign-off for that.

Primarily reviewed those, made sure they lined up with spec and eexpectations.

@jjonescz jjonescz enabled auto-merge (squash) January 15, 2024 13:04
@jjonescz jjonescz merged commit c02fb4f into dotnet:main Jan 16, 2024
25 checks passed
@jjonescz jjonescz deleted the 71383-RefInConversion branch January 16, 2024 09:23
@ghost ghost added this to the Next milestone Jan 16, 2024
@Cosifne Cosifne modified the milestones: Next, 17.10 P1 Jan 30, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Area-Compilers New Feature - Ref Readonly Parameters `ref readonly` parameters untriaged Issues and PRs which have not yet been triaged by a lead
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Delegate creation can result in a delegate violating semantics of an in parameter.
4 participants