Report error implementing interface with [UnscopedRef] member#66024
Report error implementing interface with [UnscopedRef] member#66024cston merged 9 commits intodotnet:release/dev17.5from
[UnscopedRef] member#66024Conversation
…parameter targets
| 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. |
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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.
| return false; | ||
| } | ||
| return method.HasUnscopedRefAttribute || | ||
| method.AssociatedSymbol is PropertySymbol { HasUnscopedRefAttribute: true }; |
There was a problem hiding this comment.
What about event accessors?
There was no response to this question.
There was a problem hiding this comment.
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); |
| invokedAsExtensionMethod: false); | ||
| } | ||
|
|
||
| if (implementingMethod.HasUnscopedRefAttributeOnMethodOrProperty()) |
There was a problem hiding this comment.
[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() |
|
Done with review pass (commit 4) |
| """; | ||
| 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. |
There was a problem hiding this comment.
Are we testing this scenario in a struct?
UnscopedRefAttribute_InterfaceImplementation_04
There was a problem hiding this comment.
Or interface?
UnscopedRefAttribute_InterfaceImplementation_02
There was a problem hiding this comment.
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. |
| """; | ||
| 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. |
| }"; | ||
| 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. |
|
Done with review pass (commit 7) |
| class C2 : I<int> | ||
| { | ||
| private int _f2; | ||
| [UnscopedRef] ref int I<int>.F1() => ref _f2; // 4 |
There was a problem hiding this comment.
UnscopedRefAttribute_InterfaceImplementation_02 has interface members marked as [UnscopedRef]. Does that cover the scenario?
There was a problem hiding this comment.
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. |
| struct S | ||
| { | ||
| event D E7 { [UnscopedRef] add { } remove { } } // 3 | ||
| event D E8 { add { } [UnscopedRef] remove { } } // 4 |
| class C | ||
| { | ||
| [UnscopedRef] event D E1; // 1 | ||
| [UnscopedRef] event D E2 { add { } remove { } } // 2 |
| } | ||
| struct S3 : I<object> | ||
| { | ||
| [UnscopedRef] event D<object> I<object>.E { add { } remove { } } // 6 |
| struct S2 : I<object> | ||
| { | ||
| event D<object> I<object>.E1 { [UnscopedRef] add { } remove { } } // 7 | ||
| event D<object> I<object>.E2 { add { } [UnscopedRef] remove { } } // 8 |
There was a problem hiding this comment.
Are we testing these scenarios in an interface? #Closed
| } | ||
| struct S : I<object> | ||
| { | ||
| [UnscopedRef] event D<object> I<object>.E { add { } remove { } } // 3 |
| 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> |
| struct S : I<int> | ||
| { | ||
| private int _f; | ||
| [UnscopedRef] public ref int F() => ref _f; |
There was a problem hiding this comment.
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) && |
There was a problem hiding this comment.
Annotated local functions and lambdas within a struct - see UnscopedRefAttribute_Method_05.
|
Done with review pass (commit 8) |
| Diagnostic(ErrorCode.ERR_RefAssignNarrower, "value.F = ref this").WithArguments("F", "this").WithLocation(20, 16)); | ||
| } | ||
|
|
||
| [ConditionalFact(typeof(CoreClrOnly))] |
Fixes #64508