-
Notifications
You must be signed in to change notification settings - Fork 4k
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
Conversation
a955c94
to
6be761e
Compare
@@ -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> |
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.
<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"> |
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.
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 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.
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.
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); |
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.
} | ||
static void Explicit() | ||
{ | ||
var d1 = (D1)M2; |
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.
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.
Good catch, thanks.
} | ||
|
||
[Fact] | ||
public void DelegateConversions_04() |
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.
Done with review pass (commit 1) |
src/Compilers/CSharp/Test/Emit2/Attributes/AttributeTests_LifetimeAnnotation.cs
Show resolved
Hide resolved
var boundLambda = unboundLambda.Bind((NamedTypeSymbol)destination, isExpressionTree: destination.IsGenericOrNonGenericExpressionType(out _)); | ||
diagnostics.AddRange(boundLambda.Diagnostics); | ||
|
||
bool hasErrors = CheckValidScopedMethodConversion(syntax, boundLambda.Symbol, destination, invokedAsExtensionMethod: false, diagnostics); |
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 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; |
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.
@@ -1351,6 +1382,8 @@ static ErrorCode getRefMismatchErrorCode(TypeKind type) | |||
{ | |||
return true; | |||
} | |||
|
|||
bool result = CheckValidScopedMethodConversion(syntax, selectedMethod, delegateOrFuncPtrType, isExtensionMethod, diagnostics); |
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.
hasErrors = !conversion.IsImplicit; | ||
if (!hasErrors) | ||
{ | ||
hasErrors = CheckValidScopedMethodConversion(unboundLambda.Syntax, boundLambda.Symbol, type, invokedAsExtensionMethod: false, diagnostics); |
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.
@@ -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>'. |
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.
@@ -5062,6 +5089,903 @@ static void Main() | |||
}); | |||
} | |||
|
|||
[Fact] | |||
public void DelegateConversions_01() |
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.
Done with review pass (commit 2) |
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.
LGTM (commit 3)
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.