Skip to content

Report error implementing interface with [UnscopedRef] member#66024

Merged
cston merged 9 commits intodotnet:release/dev17.5from
cston:64508
Jan 6, 2023
Merged

Report error implementing interface with [UnscopedRef] member#66024
cston merged 9 commits intodotnet:release/dev17.5from
cston:64508

Conversation

@cston
Copy link
Contributor

@cston cston commented Dec 15, 2022

Fixes #64508

@cston cston marked this pull request as ready for review December 15, 2022 01:37
@cston cston requested a review from a team as a code owner December 15, 2022 01:37
var comp = CreateCompilation(new[] { source, UnscopedRefAttributeDefinition });
comp.VerifyDiagnostics(
// (4,6): error CS9063: UnscopedRefAttribute cannot be applied to this item because it is unscoped by default.
// (4,6): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods, and cannot be applied to constructors or init-only methods.
Copy link
Member

@jcouv jcouv Dec 15, 2022

Choose a reason for hiding this comment

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

cannot be applied to constructors

nit: The diagnostic says "cannot be applied to constructors" but it looks like we don't report this diagnostic on constructors (see UnscopedRefAttribute_Constructor) so it doesn't seem particularly relevant. Consider removing this portion of the diagnostic. #Resolved

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Good catch, thanks. I will leave the diagnostic message as is since the message is correct that the attribute cannot be applied to constructors. However, we typically report ErrorCode.ERR_AttributeOnBadSymbolType instead of this error because the BCL attribute definition does not include AttributeTargets.Constructor. To ensure we are catching this case, regardless of the attribute definition, I've added a version of the constructor test with an attribute that does allow targeting constructors.

@jcouv jcouv self-assigned this Dec 15, 2022
Copy link
Member

@jcouv jcouv left a comment

Choose a reason for hiding this comment

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

LGTM Thanks (iteration 3)

@cston cston requested review from a team and RikkiGibson December 15, 2022 14:51
return false;
}
return method.HasUnscopedRefAttribute ||
method.AssociatedSymbol is PropertySymbol { HasUnscopedRefAttribute: true };
Copy link
Contributor

@AlekseyTs AlekseyTs Dec 19, 2022

Choose a reason for hiding this comment

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

method.AssociatedSymbol is PropertySymbol { HasUnscopedRefAttribute: true };

What about event accessors? #Closed

Copy link
Contributor

Choose a reason for hiding this comment

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

What about event accessors?

There was no response to this question.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Logged #66274 to follow up in a subsequent PR.

else
{
diagnostics.Add(ErrorCode.ERR_UnscopedRefAttributeUnsupportedTarget, arguments.AttributeSyntaxOpt.Location);
diagnostics.Add(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMethodTarget, arguments.AttributeSyntaxOpt.Location);
Copy link
Contributor

@AlekseyTs AlekseyTs Dec 19, 2022

Choose a reason for hiding this comment

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

ERR_UnscopedRefAttributeUnsupportedMethodTarget

The wording is probably going to sound strange for a property. It excludes properties. #Closed

invokedAsExtensionMethod: false);
}

if (implementingMethod.HasUnscopedRefAttributeOnMethodOrProperty())
Copy link
Contributor

@AlekseyTs AlekseyTs Dec 19, 2022

Choose a reason for hiding this comment

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

implementingMethod

It looks like we are going to report this error even for implicit implementations. Is this really what we want? Even for implementations that are in a base method? #Closed

Copy link
Contributor Author

Choose a reason for hiding this comment

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

[UnscopedRef] attribute can only be applied to struct instance methods and properties, so base types can be ignored.


[Fact]
[WorkItem(64508, "https://github.com/dotnet/roslyn/issues/64508")]
public void UnscopedRefAttribute_InterfaceImplementation_01()
Copy link
Contributor

@AlekseyTs AlekseyTs Dec 19, 2022

Choose a reason for hiding this comment

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

UnscopedRefAttribute_InterfaceImplementation_01

Are there any interesting scenarios around events? #Closed

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Added tests.

@AlekseyTs
Copy link
Contributor

Done with review pass (commit 4)

@cston cston changed the base branch from main to release/dev17.5 January 4, 2023 16:22
""";
var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70);
comp.VerifyEmitDiagnostics(
// (9,6): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members.
Copy link
Contributor

@AlekseyTs AlekseyTs Jan 5, 2023

Choose a reason for hiding this comment

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

UnscopedRefAttribute can only be applied to struct instance methods and properties

Are we testing this scenario in a struct? #Closed

Copy link
Contributor

Choose a reason for hiding this comment

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

Or interface?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Are we testing this scenario in a struct?

UnscopedRefAttribute_InterfaceImplementation_04

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Or interface?

UnscopedRefAttribute_InterfaceImplementation_02

Copy link
Contributor

Choose a reason for hiding this comment

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

Or interface?

UnscopedRefAttribute_InterfaceImplementation_02

It doesn't look like UnscopedRefAttribute_InterfaceImplementation_02 tests an implementation in an interface

""";
var comp = CreateCompilation(new[] { source, UnscopedRefAttributeDefinition });
comp.VerifyEmitDiagnostics(
// (10,6): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members.
Copy link
Contributor

@AlekseyTs AlekseyTs Jan 5, 2023

Choose a reason for hiding this comment

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

UnscopedRefAttribute can only be applied to struct instance methods and properties

Are we testing these scenarios in a struct? #Closed

Copy link
Contributor

Choose a reason for hiding this comment

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

Or interface?

""";
var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70);
comp.VerifyEmitDiagnostics(
// (11,31): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members.
Copy link
Contributor

@AlekseyTs AlekseyTs Jan 5, 2023

Choose a reason for hiding this comment

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

UnscopedRefAttribute can only be applied to struct instance methods and propertie

Are we testing these scenarios in a struct? #Closed

Copy link
Contributor

Choose a reason for hiding this comment

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

Or interface?

}";
var comp = CreateCompilation(new[] { source, UnscopedRefAttributeDefinition });
comp.VerifyDiagnostics(
// (6,6): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members.
Copy link
Contributor

@AlekseyTs AlekseyTs Jan 5, 2023

Choose a reason for hiding this comment

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

UnscopedRefAttribute can only be applied to struct instance methods and properties,

Are we testing these scenarios in a struct? #Closed

Copy link
Contributor

Choose a reason for hiding this comment

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

Or interface?

@AlekseyTs
Copy link
Contributor

Done with review pass (commit 7)

class C2 : I<int>
{
private int _f2;
[UnscopedRef] ref int I<int>.F1() => ref _f2; // 4
Copy link
Contributor

@AlekseyTs AlekseyTs Jan 5, 2023

Choose a reason for hiding this comment

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

[UnscopedRef] ref int I.F1() => ref _f2; // 4

Are we testing scenario like this in an interface? #Closed

Copy link
Contributor Author

@cston cston Jan 5, 2023

Choose a reason for hiding this comment

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

UnscopedRefAttribute_InterfaceImplementation_02 has interface members marked as [UnscopedRef]. Does that cover the scenario?

Copy link
Contributor

Choose a reason for hiding this comment

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

UnscopedRefAttribute_InterfaceImplementation_02 has interface members marked as [UnscopedRef]. Does that cover the scenario?

Does it test implementing an interface member in an interface?

""";
var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70);
comp.VerifyEmitDiagnostics(
// (5,6): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members.
Copy link
Contributor

@AlekseyTs AlekseyTs Jan 5, 2023

Choose a reason for hiding this comment

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

UnscopedRefAttribute can only be applied to struct instance methods and properties

Are we testing static members declaration and implementation? #Closed

struct S
{
event D E7 { [UnscopedRef] add { } remove { } } // 3
event D E8 { add { } [UnscopedRef] remove { } } // 4
Copy link
Contributor

@AlekseyTs AlekseyTs Jan 5, 2023

Choose a reason for hiding this comment

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

event D E8 { add { } [UnscopedRef] remove { } } // 4

What about an interface? #Closed

class C
{
[UnscopedRef] event D E1; // 1
[UnscopedRef] event D E2 { add { } remove { } } // 2
Copy link
Contributor

@AlekseyTs AlekseyTs Jan 5, 2023

Choose a reason for hiding this comment

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

[UnscopedRef] event D E2 { add { } remove { } } // 2

I think this form is also supported in an interface #Closed

}
struct S3 : I<object>
{
[UnscopedRef] event D<object> I<object>.E { add { } remove { } } // 6
Copy link
Contributor

@AlekseyTs AlekseyTs Jan 5, 2023

Choose a reason for hiding this comment

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

[UnscopedRef] event D I.E { add { } remove { } } // 6

Are we testing this scenario in an interface? #Closed

struct S2 : I<object>
{
event D<object> I<object>.E1 { [UnscopedRef] add { } remove { } } // 7
event D<object> I<object>.E2 { add { } [UnscopedRef] remove { } } // 8
Copy link
Contributor

@AlekseyTs AlekseyTs Jan 5, 2023

Choose a reason for hiding this comment

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

Are we testing these scenarios in an interface? #Closed

}
struct S : I<object>
{
[UnscopedRef] event D<object> I<object>.E { add { } remove { } } // 3
Copy link
Contributor

@AlekseyTs AlekseyTs Jan 5, 2023

Choose a reason for hiding this comment

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

[UnscopedRef] event D I.E { add { } remove { } } // 3

In an interface? #Closed

public static R<int> P2 { [UnscopedRef] get { return default; } [UnscopedRef] set { } } // 3, 4
public static event D<int> E { [UnscopedRef] add { } [UnscopedRef] remove { } } // 5, 6
}
{{type}} C2 : I<object>
Copy link
Contributor

@AlekseyTs AlekseyTs Jan 5, 2023

Choose a reason for hiding this comment

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

{{type}} C2 : I

In an interface? #Closed

struct S : I<int>
{
private int _f;
[UnscopedRef] public ref int F() => ref _f;
Copy link
Contributor

@AlekseyTs AlekseyTs Jan 5, 2023

Choose a reason for hiding this comment

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

[UnscopedRef] public ref int F() => ref _f;

What is the intent here? It looks like this isn't an interface implementation #Closed

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Testing that it's possible to explicitly implement an interface in addition to providing a corresponding [UnscopedRef] API.

return !method.IsStatic &&
method.ContainingType?.IsStructType() == true &&
!method.IsConstructor() &&
method.MethodKind is (MethodKind.Ordinary or MethodKind.ExplicitInterfaceImplementation or MethodKind.PropertyGet or MethodKind.PropertySet) &&
Copy link
Contributor

@AlekseyTs AlekseyTs Jan 5, 2023

Choose a reason for hiding this comment

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

method.MethodKind is (MethodKind.Ordinary or MethodKind.ExplicitInterfaceImplementation or MethodKind.PropertyGet or MethodKind.PropertySet) &&

What test scenario needed this change? #Closed

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Annotated local functions and lambdas within a struct - see UnscopedRefAttribute_Method_05.

@AlekseyTs
Copy link
Contributor

Done with review pass (commit 8)

Diagnostic(ErrorCode.ERR_RefAssignNarrower, "value.F = ref this").WithArguments("F", "this").WithLocation(20, 16));
}

[ConditionalFact(typeof(CoreClrOnly))]
Copy link
Contributor

Choose a reason for hiding this comment

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

[ConditionalFact(typeof(CoreClrOnly))]

Minor: Since we are targeting specific TargetFramework, [Fact] would work, I think.

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

Copy link
Member

@jcouv jcouv left a comment

Choose a reason for hiding this comment

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

LGTM Thanks (iteration 9)

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.

Report error implementing unannotated interface member with [UnscopedRef] member

3 participants