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

Check 'scoped' differences in overrides and interface implementations #61738

Merged
merged 3 commits into from
Jun 9, 2022

Conversation

cston
Copy link
Member

@cston cston commented Jun 7, 2022

Proposal: low-level-struct-improvements.md
Test plan: #59194

Require scoped modifiers to match exactly in overrides and implicit and explicit interface implementations.

Require scoped modifiers to match exactly in implicit and explicit conversions of lambda expressions and method group to delegates.

@cston cston force-pushed the scoped-overrides branch 5 times, most recently from a955c94 to 6be761e Compare June 7, 2022 20:57
@cston cston marked this pull request as ready for review June 7, 2022 21:14
@cston cston requested a review from a team as a code owner June 7, 2022 21:14
@RikkiGibson RikkiGibson self-assigned this Jun 8, 2022
@@ -6778,6 +6778,15 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ
<data name="ERR_ScopedRefAndRefStructOnly" xml:space="preserve">
<value>The 'scoped' modifier can be used for refs and ref struct values only.</value>
</data>
<data name="ERR_ScopedMismatchInParameterOfOverrideOrImplementation" xml:space="preserve">
<value>The 'scoped' declaration of parameter '{0}' doesn't match overridden or implemented member.</value>
Copy link
Contributor

@AlekseyTs AlekseyTs Jun 8, 2022

Choose a reason for hiding this comment

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

declaration

It looks like we refer to 'scoped' as modifier in other messages. Can we use the same term here as well? #Closed

<data name="ERR_ScopedMismatchInParameterOfOverrideOrImplementation" xml:space="preserve">
<value>The 'scoped' declaration of parameter '{0}' doesn't match overridden or implemented member.</value>
</data>
<data name="ERR_ScopedMismatchInParameterOfTargetDelegate" xml:space="preserve">
Copy link
Contributor

@AlekseyTs AlekseyTs Jun 8, 2022

Choose a reason for hiding this comment

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

ERR_ScopedMismatchInParameterOfTargetDelegate

Do we need any checks for function pointer conversions? #Closed

Copy link
Contributor

@RikkiGibson RikkiGibson Jun 8, 2022

Choose a reason for hiding this comment

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

I think we won't need to because scoped can't be used in a function pointer parameter. d'oy, we're talking about a scenario where a method group is converted to function pointer.

Copy link
Member Author

@cston cston Jun 8, 2022

Choose a reason for hiding this comment

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

There could still be a mismatch if the assigned method has a scoped parameter, although the resulting function pointer will be safe presumably because the method has a stronger contract than the function pointer.

static R F1(R x, scoped R y) => x;
delegate*<R, R, R> d1 = &F1;

I'll add a test.

@@ -723,11 +723,18 @@ public override BoundNode VisitConversion(BoundConversion node)
switch (node.ConversionKind)
{
case ConversionKind.MethodGroup:
if (node.Operand is BoundMethodGroup group)
{
checkValidScopedMethodConversion(group.Syntax, node.Conversion.Method, node.Type, invokedAsExtensionMethod: node.IsExtensionMethod, _diagnostics);
Copy link
Contributor

@AlekseyTs AlekseyTs Jun 8, 2022

Choose a reason for hiding this comment

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

checkValidScopedMethodConversion(group.Syntax, node.Conversion.Method, node.Type, invokedAsExtensionMethod: node.IsExtensionMethod, _diagnostics);

I would expect this check and the one below to be performed by the Binder, when it creates the BoundConversion node. #Closed

}
static void Explicit()
{
var d1 = (D1)M2;
Copy link
Contributor

@AlekseyTs AlekseyTs Jun 8, 2022

Choose a reason for hiding this comment

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

(D1)

Are we testing delegate creation with new? #Closed

Copy link
Member Author

Choose a reason for hiding this comment

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

Good catch, thanks.

}

[Fact]
public void DelegateConversions_04()
Copy link
Contributor

@AlekseyTs AlekseyTs Jun 8, 2022

Choose a reason for hiding this comment

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

DelegateConversions_04

Consider adding tests for function pointers as well. #Closed

@AlekseyTs
Copy link
Contributor

Done with review pass (commit 1)

var boundLambda = unboundLambda.Bind((NamedTypeSymbol)destination, isExpressionTree: destination.IsGenericOrNonGenericExpressionType(out _));
diagnostics.AddRange(boundLambda.Diagnostics);

bool hasErrors = CheckValidScopedMethodConversion(syntax, boundLambda.Symbol, destination, invokedAsExtensionMethod: false, diagnostics);
Copy link
Contributor

@AlekseyTs AlekseyTs Jun 9, 2022

Choose a reason for hiding this comment

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

hasErrors

I wouldn't mark node with hasErrors flag because of this. The purpose of the flag is mostly to suppress cascading diagnostics for completely broken scenarios. When we cannot accurately figure out the result type, etc. It is not required to reflect if there are any errors associated with the node. In this case, it doesn't look like the new error can cause a cascading diagnostics. #Closed

}
else if (targetType is FunctionPointerTypeSymbol functionPointerType)
{
delegateMethod = functionPointerType.Signature;
Copy link
Contributor

@AlekseyTs AlekseyTs Jun 9, 2022

Choose a reason for hiding this comment

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

delegateMethod = functionPointerType.Signature

Is wording of ERR_ScopedMismatchInParameterOfTargetDelegate going to be confusing for a function pointer scenario? #Closed

@@ -1351,6 +1382,8 @@ static ErrorCode getRefMismatchErrorCode(TypeKind type)
{
return true;
}

bool result = CheckValidScopedMethodConversion(syntax, selectedMethod, delegateOrFuncPtrType, isExtensionMethod, diagnostics);
Copy link
Contributor

@AlekseyTs AlekseyTs Jun 9, 2022

Choose a reason for hiding this comment

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

result

Similar comment. I don't think new errors should affect the result. Similar to the errors we are likely to report below #Closed

hasErrors = !conversion.IsImplicit;
if (!hasErrors)
{
hasErrors = CheckValidScopedMethodConversion(unboundLambda.Syntax, boundLambda.Symbol, type, invokedAsExtensionMethod: false, diagnostics);
Copy link
Contributor

@AlekseyTs AlekseyTs Jun 9, 2022

Choose a reason for hiding this comment

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

hasErrors

Same comment about hasErrors. #Closed

@@ -4424,25 +4438,43 @@ static unsafe void Main()
// (8,19): error CS8755: 'scoped' cannot be used as a modifier on a function pointer parameter.
// delegate*<scoped R, void> f1 = &F1;
Diagnostic(ErrorCode.ERR_BadFuncPointerParamModifier, "scoped").WithArguments("scoped").WithLocation(8, 19),
// (8,40): error CS8989: The 'scoped' modifier of parameter 'r1' doesn't match target delegate 'delegate*<R, void>'.
Copy link
Contributor

@AlekseyTs AlekseyTs Jun 9, 2022

Choose a reason for hiding this comment

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

target delegate

The usage of "target delegate" feels confusing in this scenario. #Closed

@@ -5062,6 +5089,903 @@ static void Main()
});
}

[Fact]
public void DelegateConversions_01()
Copy link
Contributor

@AlekseyTs AlekseyTs Jun 9, 2022

Choose a reason for hiding this comment

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

DelegateConversions_01

Are we testing conversion to a Linq expression tree? #Closed

@AlekseyTs
Copy link
Contributor

Done with review pass (commit 2)

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 3)

@cston cston merged commit a0ba31c into dotnet:features/ref-fields Jun 9, 2022
@cston cston deleted the scoped-overrides branch June 9, 2022 03:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants