diff --git a/src/Analyzers/CSharp/CodeFixes/Nullable/CSharpDeclareAsNullableCodeFixProvider.cs b/src/Analyzers/CSharp/CodeFixes/Nullable/CSharpDeclareAsNullableCodeFixProvider.cs index 29af1616f6c1b..6882dc66da3d5 100644 --- a/src/Analyzers/CSharp/CodeFixes/Nullable/CSharpDeclareAsNullableCodeFixProvider.cs +++ b/src/Analyzers/CSharp/CodeFixes/Nullable/CSharpDeclareAsNullableCodeFixProvider.cs @@ -234,6 +234,7 @@ SyntaxKind.IndexerDeclaration or var symbol = model.GetSymbolInfo(invocation.Expression, cancellationToken).Symbol; if (symbol is not IMethodSymbol method || method.PartialImplementationPart is not null) { + // https://github.com/dotnet/roslyn/issues/73772: should we also bail out on a partial property? // We don't handle partial methods yet return null; } diff --git a/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs b/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs index c662639e55e9d..b4ba341c47edb 100644 --- a/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs +++ b/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs @@ -2310,18 +2310,6 @@ internal enum ErrorCode ERR_InterceptsLocationDataInvalidPosition = 9235, INF_TooManyBoundLambdas = 9236, - // PROTOTYPE(partial-properties): pack - ERR_PartialPropertyMissingImplementation = 9300, - ERR_PartialPropertyMissingDefinition = 9301, - ERR_PartialPropertyDuplicateDefinition = 9302, - ERR_PartialPropertyDuplicateImplementation = 9303, - ERR_PartialPropertyMissingAccessor = 9304, - ERR_PartialPropertyUnexpectedAccessor = 9305, - ERR_PartialPropertyInitMismatch = 9306, - ERR_PartialPropertyTypeDifference = 9307, - WRN_PartialPropertySignatureDifference = 9308, - ERR_PartialPropertyRequiredDifference = 9309, - #endregion WRN_BadYieldInLock = 9237, @@ -2337,6 +2325,17 @@ internal enum ErrorCode ERR_BadNonVirtualInterfaceMemberAccessOnAllowsRefLike = 9246, ERR_BadAllowByRefLikeEnumerator = 9247, + ERR_PartialPropertyMissingImplementation = 9248, + ERR_PartialPropertyMissingDefinition = 9249, + ERR_PartialPropertyDuplicateDefinition = 9250, + ERR_PartialPropertyDuplicateImplementation = 9251, + ERR_PartialPropertyMissingAccessor = 9252, + ERR_PartialPropertyUnexpectedAccessor = 9253, + ERR_PartialPropertyInitMismatch = 9254, + ERR_PartialPropertyTypeDifference = 9255, + WRN_PartialPropertySignatureDifference = 9256, + ERR_PartialPropertyRequiredDifference = 9257, + // Note: you will need to do the following after adding errors: // 1) Update ErrorFacts.IsBuildOnlyDiagnostic (src/Compilers/CSharp/Portable/Errors/ErrorFacts.cs) diff --git a/src/Compilers/CSharp/Portable/Errors/MessageID.cs b/src/Compilers/CSharp/Portable/Errors/MessageID.cs index 449d25f533388..9c5288962c68b 100644 --- a/src/Compilers/CSharp/Portable/Errors/MessageID.cs +++ b/src/Compilers/CSharp/Portable/Errors/MessageID.cs @@ -287,8 +287,7 @@ internal enum MessageID IDS_FeatureRefStructInterfaces = MessageBase + 12844, - // PROTOTYPE(partial-properties): pack - IDS_FeaturePartialProperties = MessageBase + 13000, + IDS_FeaturePartialProperties = MessageBase + 12845, } // Message IDs may refer to strings that need to be localized. diff --git a/src/Compilers/CSharp/Portable/FlowAnalysis/NullableWalker.Variables.cs b/src/Compilers/CSharp/Portable/FlowAnalysis/NullableWalker.Variables.cs index 4eb4abe18b34c..dd3ed1448840d 100644 --- a/src/Compilers/CSharp/Portable/FlowAnalysis/NullableWalker.Variables.cs +++ b/src/Compilers/CSharp/Portable/FlowAnalysis/NullableWalker.Variables.cs @@ -396,6 +396,7 @@ internal Variables GetRootScope() internal Variables? GetVariablesForMethodScope(MethodSymbol method) { + // https://github.com/dotnet/roslyn/issues/73772: is this needed if we also delete the weird cascading in EnterParameters? method = method.PartialImplementationPart ?? method; var variables = this; while (true) diff --git a/src/Compilers/CSharp/Portable/FlowAnalysis/NullableWalker.cs b/src/Compilers/CSharp/Portable/FlowAnalysis/NullableWalker.cs index 81109ab290733..faf378f8cfdaa 100644 --- a/src/Compilers/CSharp/Portable/FlowAnalysis/NullableWalker.cs +++ b/src/Compilers/CSharp/Portable/FlowAnalysis/NullableWalker.cs @@ -2764,6 +2764,7 @@ private void EnterParameters() } // The partial definition part may include optional parameters whose default values we want to simulate assigning at the beginning of the method + // https://github.com/dotnet/roslyn/issues/73772: is this actually used/meaningful? methodSymbol = methodSymbol.PartialDefinitionPart ?? methodSymbol; var methodParameters = methodSymbol.Parameters; diff --git a/src/Compilers/CSharp/Portable/Generated/ErrorFacts.Generated.cs b/src/Compilers/CSharp/Portable/Generated/ErrorFacts.Generated.cs index 9475412e96ddf..6e81f32c0f79e 100644 --- a/src/Compilers/CSharp/Portable/Generated/ErrorFacts.Generated.cs +++ b/src/Compilers/CSharp/Portable/Generated/ErrorFacts.Generated.cs @@ -341,8 +341,8 @@ public static bool IsWarning(ErrorCode code) case ErrorCode.WRN_DynamicDispatchToParamsCollectionMethod: case ErrorCode.WRN_DynamicDispatchToParamsCollectionIndexer: case ErrorCode.WRN_DynamicDispatchToParamsCollectionConstructor: - case ErrorCode.WRN_PartialPropertySignatureDifference: case ErrorCode.WRN_BadYieldInLock: + case ErrorCode.WRN_PartialPropertySignatureDifference: return true; default: return false; diff --git a/src/Compilers/CSharp/Portable/Symbols/PublicModel/MethodSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/PublicModel/MethodSymbol.cs index 054c99f464c2b..c3c9b8c4b1d61 100644 --- a/src/Compilers/CSharp/Portable/Symbols/PublicModel/MethodSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/PublicModel/MethodSymbol.cs @@ -298,8 +298,6 @@ IMethodSymbol IMethodSymbol.PartialDefinitionPart } } - // PROTOTYPE(partial-properties): Perhaps this API should be implemented as '_underlying.OriginalDefinition.IsPartialDefinition()' instead. - // However, this would be a behavior change. Callers may have been assuming that if the API returned true, then the receiver is an original definition symbol. bool IMethodSymbol.IsPartialDefinition => _underlying.IsDefinition && _underlying.IsPartialDefinition(); INamedTypeSymbol IMethodSymbol.AssociatedAnonymousDelegate diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertySymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertySymbol.cs index 5f79f0dae2f0a..2deeefb254519 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertySymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertySymbol.cs @@ -14,7 +14,6 @@ namespace Microsoft.CodeAnalysis.CSharp.Symbols { internal sealed class SourcePropertySymbol : SourcePropertySymbolBase { - // PROTOTYPE(partial-properties): Verify that the increase in memory consumption from this is acceptable private SourcePropertySymbol? _otherPartOfPartial; internal static SourcePropertySymbol Create(SourceMemberContainerTypeSymbol containingType, Binder bodyBinder, PropertyDeclarationSyntax syntax, BindingDiagnosticBag diagnostics) @@ -175,7 +174,10 @@ public override OneOrMany> GetAttributeDeclarati { // Attributes on partial properties are owned by the definition part. // If this symbol has a non-null PartialDefinitionPart, we should have accessed this method through that definition symbol instead - Debug.Assert(PartialDefinitionPart is null); + Debug.Assert(PartialDefinitionPart is null + // We might still get here when asking for the attributes on a backing field. + // This is an error scenario (requires using a property initializer and field-targeted attributes on partial property implementation part). + || this.BackingField is not null); if (PartialImplementationPart is { } implementationPart) { @@ -610,6 +612,7 @@ internal override void AfterAddingTypeMembersChecks(ConversionsBase conversions, if (IsPartialDefinition && OtherPartOfPartial is { } implementation) { PartialPropertyChecks(implementation, diagnostics); + implementation.CheckInitializerIfNeeded(diagnostics); } } diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertySymbolBase.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertySymbolBase.cs index 39f81325f36f6..d4fbc4a85099d 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertySymbolBase.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertySymbolBase.cs @@ -95,7 +95,7 @@ protected SourcePropertySymbolBase( { Debug.Assert(!isExpressionBodied || !isAutoProperty); Debug.Assert(!isExpressionBodied || !hasInitializer); - Debug.Assert(!isExpressionBodied || accessorsHaveImplementation); // PROTOTYPE(partial-properties): further adjust asserts? + Debug.Assert(!isExpressionBodied || accessorsHaveImplementation); Debug.Assert((modifiers & DeclarationModifiers.Required) == 0 || this is SourcePropertySymbol); _syntaxRef = syntax.GetReference(); @@ -279,20 +279,20 @@ explicitlyImplementedProperty is null ? internal bool IsExpressionBodied => (_propertyFlags & Flags.IsExpressionBodied) != 0; - private void CheckInitializer( - bool isAutoProperty, - bool isInterface, - bool isStatic, - Location location, - BindingDiagnosticBag diagnostics) + protected void CheckInitializerIfNeeded(BindingDiagnosticBag diagnostics) { - if (isInterface && !isStatic) + if ((_propertyFlags & Flags.HasInitializer) == 0) { - diagnostics.Add(ErrorCode.ERR_InstancePropertyInitializerInInterface, location); + return; } - else if (!isAutoProperty) + + if (ContainingType.IsInterface && !IsStatic) { - diagnostics.Add(ErrorCode.ERR_InitializerOnNonAutoProperty, location); + diagnostics.Add(ErrorCode.ERR_InstancePropertyInitializerInInterface, Location); + } + else if (!IsAutoProperty) + { + diagnostics.Add(ErrorCode.ERR_InitializerOnNonAutoProperty, Location); } } @@ -692,11 +692,7 @@ internal override void AfterAddingTypeMembersChecks(ConversionsBase conversions, this.CheckAccessibility(Location, diagnostics, isExplicitInterfaceImplementation); this.CheckModifiers(isExplicitInterfaceImplementation, Location, IsIndexer, diagnostics); - bool hasInitializer = (_propertyFlags & Flags.HasInitializer) != 0; - if (hasInitializer) - { - CheckInitializer(IsAutoProperty, ContainingType.IsInterface, IsStatic, Location, diagnostics); - } + CheckInitializerIfNeeded(diagnostics); if (RefKind != RefKind.None && IsRequired) { @@ -1109,20 +1105,23 @@ private CustomAttributesBag GetAttributesBag() // prevent infinite recursion: Debug.Assert(!ReferenceEquals(copyFrom, this)); + // The property is responsible for completion of the backing field + // NB: when the **field keyword feature** is implemented, it's possible that synthesized field symbols will also be merged or shared between partial property parts. + // If we do that then this check should possibly be moved, and asserts adjusted accordingly. + _ = BackingField?.GetAttributes(); + bool bagCreatedOnThisThread; if (copyFrom is not null) { // When partial properties get the ability to have a backing field, // the implementer will have to decide how the BackingField symbol works in 'copyFrom' scenarios. - Debug.Assert(BackingField is null); + Debug.Assert(!IsAutoProperty); var attributesBag = copyFrom.GetAttributesBag(); bagCreatedOnThisThread = Interlocked.CompareExchange(ref _lazyCustomAttributesBag, attributesBag, null) == null; } else { - // The property is responsible for completion of the backing field - _ = BackingField?.GetAttributes(); bagCreatedOnThisThread = LoadAndValidateAttributes(GetAttributeDeclarations(), ref _lazyCustomAttributesBag); } diff --git a/src/Compilers/CSharp/Test/Emit2/Attributes/AttributeTests_WellKnownAttributes.cs b/src/Compilers/CSharp/Test/Emit2/Attributes/AttributeTests_WellKnownAttributes.cs index ca2be38186095..5ce634fdea9c3 100644 --- a/src/Compilers/CSharp/Test/Emit2/Attributes/AttributeTests_WellKnownAttributes.cs +++ b/src/Compilers/CSharp/Test/Emit2/Attributes/AttributeTests_WellKnownAttributes.cs @@ -11220,6 +11220,45 @@ void local1() Assert.True(verifier.HasLocalsInit("C.g__local1|3_0")); } + [Theory] + [InlineData("[SkipLocalsInit]", "")] + [InlineData("", "[SkipLocalsInit]")] + public void SkipLocalsInit_PartialPropertyAccessor_ContainsLocalFunction(string defAttrs, string implAttrs) + { + // SkipLocalsInit applied to either part affects the property and nested functions + var source = $$""" +using System.Runtime.CompilerServices; + +public partial class C +{ + {{defAttrs}} + partial int PropWithAttribute { get; } + + {{implAttrs}} + partial int PropWithAttribute + { + get + { + int w = 1; + w = w + w + w + w; + + void local1() + { + int x = 1; + x = x + x + x + x; + } + + return 0; + } + } +} +"""; + + var verifier = CompileAndVerifyWithSkipLocalsInit(source); + Assert.False(verifier.HasLocalsInit("C.PropWithAttribute.get")); + Assert.False(verifier.HasLocalsInit("C.g__local1|1_0")); + } + [Fact] public void SkipLocalsInit_EventAccessor_ContainsLocalFunction() { diff --git a/src/Compilers/CSharp/Test/Symbol/DocumentationComments/DocumentationCommentCompilerTests.cs b/src/Compilers/CSharp/Test/Symbol/DocumentationComments/DocumentationCommentCompilerTests.cs index 60a90b842ad31..a795619ee010d 100644 --- a/src/Compilers/CSharp/Test/Symbol/DocumentationComments/DocumentationCommentCompilerTests.cs +++ b/src/Compilers/CSharp/Test/Symbol/DocumentationComments/DocumentationCommentCompilerTests.cs @@ -1972,7 +1972,7 @@ void verify(CSharpTestSource source) Assert.Equal("p2", indexer.Parameters.Single().Name); }); verifier.VerifyDiagnostics( - // (5,24): warning CS9308: Partial property declarations 'int C.this[int p2]' and 'int C.this[int p1]' have signature differences. + // (5,24): warning CS9256: Partial property declarations 'int C.this[int p2]' and 'int C.this[int p1]' have signature differences. // public partial int this[int p1] => 42; Diagnostic(ErrorCode.WRN_PartialPropertySignatureDifference, "this").WithArguments("int C.this[int p2]", "int C.this[int p1]").WithLocation(5, 24)); @@ -2033,7 +2033,7 @@ void verify(CSharpTestSource source) // (4,42): warning CS1734: XML comment on 'C.this[int]' has a paramref tag for 'p2', but there is no parameter by that name // /** Accepts . */ Diagnostic(ErrorCode.WRN_UnmatchedParamRefTag, "p2").WithArguments("p2", "C.this[int]").WithLocation(4, 42), - // (5,24): warning CS9308: Partial property declarations 'int C.this[int p2]' and 'int C.this[int p1]' have signature differences. + // (5,24): warning CS9256: Partial property declarations 'int C.this[int p2]' and 'int C.this[int p1]' have signature differences. // public partial int this[int p1] => 42; Diagnostic(ErrorCode.WRN_PartialPropertySignatureDifference, "this").WithArguments("int C.this[int p2]", "int C.this[int p1]").WithLocation(5, 24)); @@ -2094,7 +2094,7 @@ void verify(CSharpTestSource source) Assert.Equal("p2", indexer.Parameters.Single().Name); }); verifier.VerifyDiagnostics( - // (4,24): warning CS9308: Partial property declarations 'int C.this[int p2]' and 'int C.this[int p1]' have signature differences. + // (4,24): warning CS9256: Partial property declarations 'int C.this[int p2]' and 'int C.this[int p1]' have signature differences. // public partial int this[int p1] => 42; Diagnostic(ErrorCode.WRN_PartialPropertySignatureDifference, "this").WithArguments("int C.this[int p2]", "int C.this[int p1]").WithLocation(4, 24), // (4,42): warning CS1734: XML comment on 'C.this[int]' has a paramref tag for 'p1', but there is no parameter by that name @@ -2158,7 +2158,7 @@ void verify(CSharpTestSource source) Assert.Equal("p2", indexer.Parameters.Single().Name); }); verifier.VerifyDiagnostics( - // (4,24): warning CS9308: Partial property declarations 'int C.this[int p2]' and 'int C.this[int p1]' have signature differences. + // (4,24): warning CS9256: Partial property declarations 'int C.this[int p2]' and 'int C.this[int p1]' have signature differences. // public partial int this[int p1] => 42; Diagnostic(ErrorCode.WRN_PartialPropertySignatureDifference, "this").WithArguments("int C.this[int p2]", "int C.this[int p1]").WithLocation(4, 24)); diff --git a/src/Compilers/CSharp/Test/Symbol/Symbols/PartialPropertiesTests.cs b/src/Compilers/CSharp/Test/Symbol/Symbols/PartialPropertiesTests.cs index 74500cb2a4ff4..e44733027dd10 100644 --- a/src/Compilers/CSharp/Test/Symbol/Symbols/PartialPropertiesTests.cs +++ b/src/Compilers/CSharp/Test/Symbol/Symbols/PartialPropertiesTests.cs @@ -37,7 +37,7 @@ partial class C """; var comp = CreateCompilation([source, IsExternalInitTypeDefinition]); comp.VerifyEmitDiagnostics( - // (3,17): error CS9300: Partial property 'C.P' must have an implementation part. + // (3,17): error CS9248: Partial property 'C.P' must have an implementation part. // partial int P { get; set; } Diagnostic(ErrorCode.ERR_PartialPropertyMissingImplementation, "P").WithArguments("C.P").WithLocation(3, 17) ); @@ -109,7 +109,7 @@ partial class C """; var comp = CreateCompilation([source, IsExternalInitTypeDefinition]); comp.VerifyEmitDiagnostics( - // (3,17): error CS9301: Partial property 'C.P' must have a definition part. + // (3,17): error CS9249: Partial property 'C.P' must have a definition part. // partial int P { get => throw null!; set { } } Diagnostic(ErrorCode.ERR_PartialPropertyMissingDefinition, "P").WithArguments("C.P").WithLocation(3, 17) ); @@ -177,10 +177,10 @@ partial class C """; var comp = CreateCompilation(source); comp.VerifyEmitDiagnostics( - // (3,17): error CS9300: Partial property 'C.P' must have an implementation part. + // (3,17): error CS9248: Partial property 'C.P' must have an implementation part. // partial int P { get; set; } Diagnostic(ErrorCode.ERR_PartialPropertyMissingImplementation, "P").WithArguments("C.P").WithLocation(3, 17), - // (4,17): error CS9302: A partial property may not have multiple defining declarations, and cannot be an auto-property. + // (4,17): error CS9250: A partial property may not have multiple defining declarations, and cannot be an auto-property. // partial int P { get; set; } Diagnostic(ErrorCode.ERR_PartialPropertyDuplicateDefinition, "P").WithLocation(4, 17), // (4,17): error CS0102: The type 'C' already contains a definition for 'P' @@ -203,7 +203,7 @@ partial class C """; var comp = CreateCompilation(source); comp.VerifyEmitDiagnostics( - // (4,17): error CS9302: A partial property may not have multiple defining declarations, and cannot be an auto-property. + // (4,17): error CS9250: A partial property may not have multiple defining declarations, and cannot be an auto-property. // partial int P { get; set; } Diagnostic(ErrorCode.ERR_PartialPropertyDuplicateDefinition, "P").WithLocation(4, 17), // (4,17): error CS0102: The type 'C' already contains a definition for 'P' @@ -225,10 +225,10 @@ partial class C """; var comp = CreateCompilation(source); comp.VerifyEmitDiagnostics( - // (3,17): error CS9301: Partial property 'C.P' must have a definition part. + // (3,17): error CS9249: Partial property 'C.P' must have a definition part. // partial int P { get => throw null!; set { } } Diagnostic(ErrorCode.ERR_PartialPropertyMissingDefinition, "P").WithArguments("C.P").WithLocation(3, 17), - // (4,17): error CS9303: A partial property may not have multiple implementing declarations + // (4,17): error CS9251: A partial property may not have multiple implementing declarations // partial int P { get => throw null!; set { } } Diagnostic(ErrorCode.ERR_PartialPropertyDuplicateImplementation, "P").WithLocation(4, 17), // (4,17): error CS0102: The type 'C' already contains a definition for 'P' @@ -251,7 +251,7 @@ partial class C """; var comp = CreateCompilation(source); comp.VerifyEmitDiagnostics( - // (5,17): error CS9303: A partial property may not have multiple implementing declarations + // (5,17): error CS9251: A partial property may not have multiple implementing declarations // partial int P { get => throw null!; set { } } Diagnostic(ErrorCode.ERR_PartialPropertyDuplicateImplementation, "P").WithLocation(5, 17), // (5,17): error CS0102: The type 'C' already contains a definition for 'P' @@ -275,13 +275,13 @@ partial class C """; var comp = CreateCompilation(source); comp.VerifyEmitDiagnostics( - // (4,17): error CS9302: A partial property may not have multiple defining declarations, and cannot be an auto-property. + // (4,17): error CS9250: A partial property may not have multiple defining declarations, and cannot be an auto-property. // partial int P { get; set; } Diagnostic(ErrorCode.ERR_PartialPropertyDuplicateDefinition, "P").WithLocation(4, 17), // (4,17): error CS0102: The type 'C' already contains a definition for 'P' // partial int P { get; set; } Diagnostic(ErrorCode.ERR_DuplicateNameInClass, "P").WithArguments("C", "P").WithLocation(4, 17), - // (6,17): error CS9303: A partial property may not have multiple implementing declarations + // (6,17): error CS9251: A partial property may not have multiple implementing declarations // partial int P { get => throw null!; set { } } Diagnostic(ErrorCode.ERR_PartialPropertyDuplicateImplementation, "P").WithLocation(6, 17), // (6,17): error CS0102: The type 'C' already contains a definition for 'P' @@ -303,7 +303,7 @@ partial class C """; var comp = CreateCompilation(source); comp.VerifyEmitDiagnostics( - // (3,24): error CS9300: Partial property 'C.P' must have an implementation part. + // (3,24): error CS9248: Partial property 'C.P' must have an implementation part. // public partial int P { get; set; } Diagnostic(ErrorCode.ERR_PartialPropertyMissingImplementation, "P").WithArguments("C.P").WithLocation(3, 24), // (4,24): error CS0759: No defining declaration found for implementing declaration of partial method 'C.P()' @@ -328,7 +328,7 @@ partial class C """; var comp = CreateCompilation(source); comp.VerifyEmitDiagnostics( - // (3,24): error CS9300: Partial property 'C.P' must have an implementation part. + // (3,24): error CS9248: Partial property 'C.P' must have an implementation part. // public partial int P { get; } Diagnostic(ErrorCode.ERR_PartialPropertyMissingImplementation, "P").WithArguments("C.P").WithLocation(3, 24), // (3,28): error CS0082: Type 'C' already reserves a member called 'get_P' with the same parameter types @@ -351,10 +351,10 @@ public partial int P { set { } } """; var comp = CreateCompilation(source); comp.VerifyEmitDiagnostics( - // (4,24): error CS9304: Property accessor 'C.P.set' must be implemented because it is declared on the definition part + // (4,24): error CS9252: Property accessor 'C.P.set' must be implemented because it is declared on the definition part // public partial int P { get => 1; } Diagnostic(ErrorCode.ERR_PartialPropertyMissingAccessor, "P").WithArguments("C.P.set").WithLocation(4, 24), - // (5,24): error CS9303: A partial property may not have multiple implementing declarations + // (5,24): error CS9251: A partial property may not have multiple implementing declarations // public partial int P { set { } } Diagnostic(ErrorCode.ERR_PartialPropertyDuplicateImplementation, "P").WithLocation(5, 24), // (5,24): error CS0102: The type 'C' already contains a definition for 'P' @@ -374,6 +374,43 @@ public partial int P { set { } } Assert.Equal("System.Int32 C.P { set; }", duplicateProp.ToTestDisplayString()); } + [Fact] + public void DuplicateDeclaration_08_Definition() + { + // multiple defining declarations where accessors are "split" across declarations + var source = """ + partial class C + { + public partial int P { get; } + public partial int P { set; } + public partial int P { get => 1; set { } } + } + """; + var comp = CreateCompilation(source); + comp.VerifyEmitDiagnostics( + // (4,24): error CS9250: A partial property may not have multiple defining declarations, and cannot be an auto-property. + // public partial int P { set; } + Diagnostic(ErrorCode.ERR_PartialPropertyDuplicateDefinition, "P").WithLocation(4, 24), + // (4,24): error CS0102: The type 'C' already contains a definition for 'P' + // public partial int P { set; } + Diagnostic(ErrorCode.ERR_DuplicateNameInClass, "P").WithArguments("C", "P").WithLocation(4, 24), + // (5,24): error CS9253: Property accessor 'C.P.set' does not implement any accessor declared on the definition part + // public partial int P { get => 1; set { } } + Diagnostic(ErrorCode.ERR_PartialPropertyUnexpectedAccessor, "P").WithArguments("C.P.set").WithLocation(5, 24) + ); + + if (comp.GetMembers("C.P") is not [SourcePropertySymbol prop, SourcePropertySymbol duplicateProp]) + throw ExceptionUtilities.UnexpectedValue(comp.GetMembers("C.P")); + + Assert.True(prop.IsPartialDefinition); + Assert.Equal("System.Int32 C.P { get; }", prop.ToTestDisplayString()); + Assert.Equal("System.Int32 C.P { get; set; }", prop.PartialImplementationPart.ToTestDisplayString()); + + Assert.True(duplicateProp.IsPartialDefinition); + Assert.Null(duplicateProp.PartialImplementationPart); + Assert.Equal("System.Int32 C.P { set; }", duplicateProp.ToTestDisplayString()); + } + [Fact] public void DuplicateDeclaration_09() { @@ -387,13 +424,13 @@ partial class C """; var comp = CreateCompilation(source); comp.VerifyEmitDiagnostics( - // (3,24): error CS9300: Partial property 'C.this[int]' must have an implementation part. + // (3,24): error CS9248: Partial property 'C.this[int]' must have an implementation part. // public partial int this[int i] { get; } Diagnostic(ErrorCode.ERR_PartialPropertyMissingImplementation, "this").WithArguments("C.this[int]").WithLocation(3, 24), // (3,24): error CS0102: The type 'C' already contains a definition for 'Item' // public partial int this[int i] { get; } Diagnostic(ErrorCode.ERR_DuplicateNameInClass, "this").WithArguments("C", "Item").WithLocation(3, 24), - // (4,24): error CS9301: Partial property 'C.Item' must have a definition part. + // (4,24): error CS9249: Partial property 'C.Item' must have a definition part. // public partial int Item => 1; Diagnostic(ErrorCode.ERR_PartialPropertyMissingDefinition, "Item").WithArguments("C.Item").WithLocation(4, 24) ); @@ -412,7 +449,7 @@ partial class C """; var comp = CreateCompilation(source); comp.VerifyEmitDiagnostics( - // (3,24): error CS9300: Partial property 'C.this' must have an implementation part. + // (3,24): error CS9248: Partial property 'C.this' must have an implementation part. // public partial int this[] { get; } Diagnostic(ErrorCode.ERR_PartialPropertyMissingImplementation, "this").WithArguments("C.this").WithLocation(3, 24), // (3,24): error CS0102: The type 'C' already contains a definition for 'Item' @@ -421,7 +458,7 @@ partial class C // (3,29): error CS1551: Indexers must have at least one parameter // public partial int this[] { get; } Diagnostic(ErrorCode.ERR_IndexerNeedsParam, "]").WithLocation(3, 29), - // (4,24): error CS9301: Partial property 'C.Item' must have a definition part. + // (4,24): error CS9249: Partial property 'C.Item' must have a definition part. // public partial int Item => 1; Diagnostic(ErrorCode.ERR_PartialPropertyMissingDefinition, "Item").WithArguments("C.Item").WithLocation(4, 24) ); @@ -440,7 +477,7 @@ partial class C """; var comp = CreateCompilation(source); comp.VerifyEmitDiagnostics( - // (4,17): error CS9304: Property accessor 'C.P.set' must be implemented because it is declared on the definition part + // (4,17): error CS9252: Property accessor 'C.P.set' must be implemented because it is declared on the definition part // partial int P { get => throw null!; } Diagnostic(ErrorCode.ERR_PartialPropertyMissingAccessor, "P").WithArguments("C.P.set").WithLocation(4, 17) ); @@ -459,7 +496,7 @@ partial int P { set { } } """; var comp = CreateCompilation(source); comp.VerifyEmitDiagnostics( - // (4,17): error CS9304: Property accessor 'C.P.get' must be implemented because it is declared on the definition part + // (4,17): error CS9252: Property accessor 'C.P.get' must be implemented because it is declared on the definition part // partial int P { set { } } Diagnostic(ErrorCode.ERR_PartialPropertyMissingAccessor, "P").WithArguments("C.P.get").WithLocation(4, 17) ); @@ -478,7 +515,7 @@ partial class C """; var comp = CreateCompilation([source, IsExternalInitTypeDefinition]); comp.VerifyEmitDiagnostics( - // (4,17): error CS9304: Property accessor 'C.P.init' must be implemented because it is declared on the definition part + // (4,17): error CS9252: Property accessor 'C.P.init' must be implemented because it is declared on the definition part // partial int P { get => throw null!; } Diagnostic(ErrorCode.ERR_PartialPropertyMissingAccessor, "P").WithArguments("C.P.init").WithLocation(4, 17) ); @@ -500,10 +537,10 @@ partial int P { } """; var comp = CreateCompilation([source, IsExternalInitTypeDefinition]); comp.VerifyEmitDiagnostics( - // (3,17): error CS9300: Partial property 'C.P' must have an implementation part. + // (3,17): error CS9248: Partial property 'C.P' must have an implementation part. // partial int P { {{accessorKind}}; } Diagnostic(ErrorCode.ERR_PartialPropertyMissingImplementation, "P").WithArguments("C.P").WithLocation(3, 17), - // (4,17): error CS9302: A partial property may not have multiple defining declarations, and cannot be an auto-property. + // (4,17): error CS9250: A partial property may not have multiple defining declarations, and cannot be an auto-property. // partial int P { } Diagnostic(ErrorCode.ERR_PartialPropertyDuplicateDefinition, "P").WithLocation(4, 17), // (4,17): error CS0102: The type 'C' already contains a definition for 'P' @@ -531,7 +568,7 @@ partial int P { } """; var comp = CreateCompilation([source, IsExternalInitTypeDefinition]); comp.VerifyEmitDiagnostics( - // (3,17): error CS9305: Property accessor 'C.P.{accessorKind}' does not implement any accessor declared on the definition part + // (3,17): error CS9253: Property accessor 'C.P.{accessorKind}' does not implement any accessor declared on the definition part // partial int P { {{accessorKind}} => throw null!; } Diagnostic(ErrorCode.ERR_PartialPropertyUnexpectedAccessor, "P").WithArguments($"C.P.{accessorKind}").WithLocation(3, 17), // (4,17): error CS0548: 'C.P': property or indexer must have at least one accessor @@ -553,7 +590,7 @@ partial class C """; var comp = CreateCompilation(source); comp.VerifyEmitDiagnostics( - // (4,17): error CS9305: Property accessor 'C.P.set' does not implement any accessor declared on the definition part + // (4,17): error CS9253: Property accessor 'C.P.set' does not implement any accessor declared on the definition part // partial int P { get => throw null!; set { } } Diagnostic(ErrorCode.ERR_PartialPropertyUnexpectedAccessor, "P").WithArguments("C.P.set").WithLocation(4, 17) ); @@ -572,7 +609,7 @@ partial class C """; var comp = CreateCompilation(source); comp.VerifyEmitDiagnostics( - // (4,17): error CS9305: Property accessor 'C.P.get' does not implement any accessor declared on the definition part + // (4,17): error CS9253: Property accessor 'C.P.get' does not implement any accessor declared on the definition part // partial int P { get => throw null!; set { } } Diagnostic(ErrorCode.ERR_PartialPropertyUnexpectedAccessor, "P").WithArguments("C.P.get").WithLocation(4, 17) ); @@ -591,7 +628,7 @@ partial class C """; var comp = CreateCompilation([source, IsExternalInitTypeDefinition]); comp.VerifyEmitDiagnostics( - // (4,17): error CS9305: Property accessor 'C.P.init' does not implement any accessor declared on the definition part + // (4,17): error CS9253: Property accessor 'C.P.init' does not implement any accessor declared on the definition part // partial int P { get => throw null!; init { } } Diagnostic(ErrorCode.ERR_PartialPropertyUnexpectedAccessor, "P").WithArguments("C.P.init").WithLocation(4, 17) ); @@ -611,7 +648,7 @@ partial class C var comp = CreateCompilation([source, IsExternalInitTypeDefinition]); comp.VerifyEmitDiagnostics( - // (4,41): error CS9306: Property accessor 'C.P.init' must be 'set' to match the definition part + // (4,41): error CS9254: Property accessor 'C.P.init' must be 'set' to match the definition part // partial int P { get => throw null!; init { } } Diagnostic(ErrorCode.ERR_PartialPropertyInitMismatch, "init").WithArguments("C.P.init", "set").WithLocation(4, 41) ); @@ -630,7 +667,7 @@ partial class C """; var comp = CreateCompilation([source, IsExternalInitTypeDefinition]); comp.VerifyEmitDiagnostics( - // (4,41): error CS9306: Property accessor 'C.P.set' must be 'init' to match the definition part + // (4,41): error CS9254: Property accessor 'C.P.set' must be 'init' to match the definition part // partial int P { get => throw null!; set { } } Diagnostic(ErrorCode.ERR_PartialPropertyInitMismatch, "set").WithArguments("C.P.set", "init").WithLocation(4, 41) ); @@ -689,10 +726,10 @@ partial class C """; var comp = CreateCompilation([source, IsExternalInitTypeDefinition]); comp.VerifyEmitDiagnostics( - // (3,24): error CS9301: Partial property 'C.P' must have a definition part. + // (3,24): error CS9249: Partial property 'C.P' must have a definition part. // extern partial int P { get; set; } Diagnostic(ErrorCode.ERR_PartialPropertyMissingDefinition, "P").WithArguments("C.P").WithLocation(3, 24), - // (4,24): error CS9303: A partial property may not have multiple implementing declarations + // (4,24): error CS9251: A partial property may not have multiple implementing declarations // extern partial int P { get; set; } Diagnostic(ErrorCode.ERR_PartialPropertyDuplicateImplementation, "P").WithLocation(4, 24), // (4,24): error CS0102: The type 'C' already contains a definition for 'P' @@ -1512,13 +1549,13 @@ partial class C """; var comp = CreateCompilation(source); comp.VerifyEmitDiagnostics( - // (6,20): error CS9307: Both partial property declarations must have the same type. + // (6,20): error CS9255: Both partial property declarations must have the same type. // partial string P1 { get => ""; set { } } Diagnostic(ErrorCode.ERR_PartialPropertyTypeDifference, "P1").WithLocation(6, 20), - // (9,26): error CS9307: Both partial property declarations must have the same type. + // (9,26): error CS9255: Both partial property declarations must have the same type. // partial List P2 { get => []; set { } } Diagnostic(ErrorCode.ERR_PartialPropertyTypeDifference, "P2").WithLocation(9, 26), - // (12,33): error CS9307: Both partial property declarations must have the same type. + // (12,33): error CS9255: Both partial property declarations must have the same type. // partial IEnumerable P3 { get => []; set { } } Diagnostic(ErrorCode.ERR_PartialPropertyTypeDifference, "P3").WithLocation(12, 33)); } @@ -1545,16 +1582,16 @@ partial class C """; var comp = CreateCompilation(source); comp.VerifyEmitDiagnostics( - // (5,20): error CS9308: Partial property declarations 'string? C.P1' and 'string C.P1' have signature differences. + // (5,20): error CS9256: Partial property declarations 'string? C.P1' and 'string C.P1' have signature differences. // partial string P1 { get => ""; set { } } Diagnostic(ErrorCode.WRN_PartialPropertySignatureDifference, "P1").WithArguments("string? C.P1", "string C.P1").WithLocation(5, 20), - // (8,21): error CS9308: Partial property declarations 'string C.P2' and 'string? C.P2' have signature differences. + // (8,21): error CS9256: Partial property declarations 'string C.P2' and 'string? C.P2' have signature differences. // partial string? P2 { get => ""; set { } } Diagnostic(ErrorCode.WRN_PartialPropertySignatureDifference, "P2").WithArguments("string C.P2", "string? C.P2").WithLocation(8, 21), - // (11,22): error CS9308: Partial property declarations 'string?[] C.P3' and 'string[] C.P3' have signature differences. + // (11,22): error CS9256: Partial property declarations 'string?[] C.P3' and 'string[] C.P3' have signature differences. // partial string[] P3 { get => []; set { } } Diagnostic(ErrorCode.WRN_PartialPropertySignatureDifference, "P3").WithArguments("string?[] C.P3", "string[] C.P3").WithLocation(11, 22), - // (14,23): error CS9308: Partial property declarations 'string[] C.P4' and 'string?[] C.P4' have signature differences. + // (14,23): error CS9256: Partial property declarations 'string[] C.P4' and 'string?[] C.P4' have signature differences. // partial string?[] P4 { get => []; set { } } Diagnostic(ErrorCode.WRN_PartialPropertySignatureDifference, "P4").WithArguments("string[] C.P4", "string?[] C.P4").WithLocation(14, 23)); } @@ -1583,10 +1620,10 @@ partial class C var comp = CreateCompilation(source, options: TestOptions.DebugDll.WithNullableContextOptions(NullableContextOptions.Enable)); comp.VerifyEmitDiagnostics( - // (4,27): warning CS9308: Partial property declarations 'string? C.P1' and 'string C.P1' have signature differences. + // (4,27): warning CS9256: Partial property declarations 'string? C.P1' and 'string C.P1' have signature differences. // public partial string P1 { get => ""; set { } } Diagnostic(ErrorCode.WRN_PartialPropertySignatureDifference, "P1").WithArguments("string? C.P1", "string C.P1").WithLocation(4, 27), - // (7,28): warning CS9308: Partial property declarations 'string C.P2' and 'string? C.P2' have signature differences. + // (7,28): warning CS9256: Partial property declarations 'string C.P2' and 'string? C.P2' have signature differences. // public partial string? P2 { get => ""; set { } } Diagnostic(ErrorCode.WRN_PartialPropertySignatureDifference, "P2").WithArguments("string C.P2", "string? C.P2").WithLocation(7, 28), // (10,27): warning CS8826: Partial method declarations 'string? C.M1()' and 'string C.M1()' have signature differences. @@ -1598,10 +1635,10 @@ partial class C comp = CreateCompilation(source, options: TestOptions.DebugDll.WithNullableContextOptions(NullableContextOptions.Annotations)); comp.VerifyEmitDiagnostics( - // (4,27): warning CS9308: Partial property declarations 'string? C.P1' and 'string C.P1' have signature differences. + // (4,27): warning CS9256: Partial property declarations 'string? C.P1' and 'string C.P1' have signature differences. // public partial string P1 { get => ""; set { } } Diagnostic(ErrorCode.WRN_PartialPropertySignatureDifference, "P1").WithArguments("string? C.P1", "string C.P1").WithLocation(4, 27), - // (7,28): warning CS9308: Partial property declarations 'string C.P2' and 'string? C.P2' have signature differences. + // (7,28): warning CS9256: Partial property declarations 'string C.P2' and 'string? C.P2' have signature differences. // public partial string? P2 { get => ""; set { } } Diagnostic(ErrorCode.WRN_PartialPropertySignatureDifference, "P2").WithArguments("string C.P2", "string? C.P2").WithLocation(7, 28), // (10,27): warning CS8826: Partial method declarations 'string? C.M1()' and 'string C.M1()' have signature differences. @@ -1648,6 +1685,91 @@ partial class C Assert.Equal(NullableAnnotation.Oblivious, p3.TypeWithAnnotations.NullableAnnotation); } + [Fact] + public void NullableDifference_Analysis() + { + // The implementation part signature is used to analyze the implementation part bodies. + // The definition part signature is used to analyze use sites. + // This is consistent with methods. + var source = """ + #nullable enable + partial class C + { + public partial string this[string? x] { get; set; } + public partial string? this[string x] // 1 + { + get => x.ToString(); + set => x.ToString(); + } + + public partial string? this[string x, bool ignored] { get; set; } + public partial string this[string? x, bool ignored] // 2 + { + get => x.ToString(); // 3 + set => x.ToString(); // 4 + } + + public partial string this[bool ignored] { get; } + public partial string? this[bool ignored] // 5 + { + get => null; + } + + public partial string? this[int ignored] { get; } + public partial string this[int ignored] // 6 + { + get => null; // 7 + } + + void Usage() + { + this[x: null].ToString(); + this[x: null, ignored: false].ToString(); // 8, 9 + } + } + """; + + var verifier = CompileAndVerify(source, symbolValidator: verify, sourceSymbolValidator: verify); + verifier.VerifyDiagnostics( + // (5,28): warning CS9256: Partial property declarations 'string C.this[string? x]' and 'string? C.this[string x]' have signature differences. + // public partial string? this[string x] // 1 + Diagnostic(ErrorCode.WRN_PartialPropertySignatureDifference, "this").WithArguments("string C.this[string? x]", "string? C.this[string x]").WithLocation(5, 28), + // (12,27): warning CS9256: Partial property declarations 'string? C.this[string x, bool ignored]' and 'string C.this[string? x, bool ignored]' have signature differences. + // public partial string this[string? x, bool ignored] // 2 + Diagnostic(ErrorCode.WRN_PartialPropertySignatureDifference, "this").WithArguments("string? C.this[string x, bool ignored]", "string C.this[string? x, bool ignored]").WithLocation(12, 27), + // (14,16): warning CS8602: Dereference of a possibly null reference. + // get => x.ToString(); // 3 + Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "x").WithLocation(14, 16), + // (15,16): warning CS8602: Dereference of a possibly null reference. + // set => x.ToString(); // 4 + Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "x").WithLocation(15, 16), + // (19,28): warning CS9256: Partial property declarations 'string C.this[bool ignored]' and 'string? C.this[bool ignored]' have signature differences. + // public partial string? this[bool ignored] // 5 + Diagnostic(ErrorCode.WRN_PartialPropertySignatureDifference, "this").WithArguments("string C.this[bool ignored]", "string? C.this[bool ignored]").WithLocation(19, 28), + // (25,27): warning CS9256: Partial property declarations 'string? C.this[int ignored]' and 'string C.this[int ignored]' have signature differences. + // public partial string this[int ignored] // 6 + Diagnostic(ErrorCode.WRN_PartialPropertySignatureDifference, "this").WithArguments("string? C.this[int ignored]", "string C.this[int ignored]").WithLocation(25, 27), + // (27,16): warning CS8603: Possible null reference return. + // get => null; // 7 + Diagnostic(ErrorCode.WRN_NullReferenceReturn, "null").WithLocation(27, 16), + // (33,9): warning CS8602: Dereference of a possibly null reference. + // this[x: null, ignored: false].ToString(); // 8, 9 + Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "this[x: null, ignored: false]").WithLocation(33, 9), + // (33,17): warning CS8625: Cannot convert null literal to non-nullable reference type. + // this[x: null, ignored: false].ToString(); // 8, 9 + Diagnostic(ErrorCode.WRN_NullAsNonNullable, "null").WithLocation(33, 17)); + + void verify(ModuleSymbol module) + { + var indexers = module.GlobalNamespace.GetMember("C").Indexers; + Assert.Equal(4, indexers.Length); + AssertEx.Equal("System.String C.this[System.String? x] { get; set; }", indexers[0].ToTestDisplayString()); + AssertEx.Equal("System.String? C.this[System.String x, System.Boolean ignored] { get; set; }", indexers[1].ToTestDisplayString()); + AssertEx.Equal("System.String C.this[System.Boolean ignored] { get; }", indexers[2].ToTestDisplayString()); + AssertEx.Equal("System.String? C.this[System.Int32 ignored] { get; }", indexers[3].ToTestDisplayString()); + } + } + [Fact] public void TypeDifference_03() { @@ -1788,7 +1910,7 @@ partial class C var comp = CreateCompilation(source); comp.VerifyEmitDiagnostics( - // (6,52): error CS9307: Both partial property declarations must have the same type. + // (6,52): error CS9255: Both partial property declarations must have the same type. // public partial ref readonly (long x, string y) Prop => throw null!; Diagnostic(ErrorCode.ERR_PartialPropertyTypeDifference, "Prop").WithLocation(6, 52), // (6,52): error CS8818: Partial member declarations must have matching ref return values. @@ -2134,13 +2256,13 @@ abstract partial class C var comp = CreateCompilation(source); comp.VerifyEmitDiagnostics( - // (3,33): error CS9300: Partial property 'C.P1' must have an implementation part. + // (3,33): error CS9248: Partial property 'C.P1' must have an implementation part. // public abstract partial int P1 { get; set; } Diagnostic(ErrorCode.ERR_PartialPropertyMissingImplementation, "P1").WithArguments("C.P1").WithLocation(3, 33), // (3,33): error CS0750: A partial member cannot have the 'abstract' modifier // public abstract partial int P1 { get; set; } Diagnostic(ErrorCode.ERR_PartialMemberCannotBeAbstract, "P1").WithLocation(3, 33), - // (5,33): error CS9301: Partial property 'C.P2' must have a definition part. + // (5,33): error CS9249: Partial property 'C.P2' must have a definition part. // public abstract partial int P2 { get => ""; set { } } Diagnostic(ErrorCode.ERR_PartialPropertyMissingDefinition, "P2").WithArguments("C.P2").WithLocation(5, 33), // (5,33): error CS0750: A partial member cannot have the 'abstract' modifier @@ -2251,10 +2373,10 @@ static void Main() var comp = CreateCompilation([source, RequiredMemberAttribute, SetsRequiredMembersAttribute, CompilerFeatureRequiredAttribute]); comp.VerifyEmitDiagnostics( - // (4,27): error CS9309: Both partial property declarations must be required or neither may be required + // (4,27): error CS9257: Both partial property declarations must be required or neither may be required // public partial string P1 { get => ""; set { } } Diagnostic(ErrorCode.ERR_PartialPropertyRequiredDifference, "P1").WithLocation(4, 27), - // (7,36): error CS9309: Both partial property declarations must be required or neither may be required + // (7,36): error CS9257: Both partial property declarations must be required or neither may be required // public required partial string P2 { get => ""; set { } } Diagnostic(ErrorCode.ERR_PartialPropertyRequiredDifference, "P2").WithLocation(7, 36), // (11,17): error CS9035: Required member 'C.P1' must be set in the object initializer or attribute constructor. @@ -2286,7 +2408,7 @@ partial class C var comp = CreateCompilation(source); comp.VerifyEmitDiagnostics( - // (15,26): error CS9307: Both partial property declarations must have the same type. + // (15,26): error CS9255: Both partial property declarations must have the same type. // public partial MyInt P3 { get => 3; set { } } Diagnostic(ErrorCode.ERR_PartialPropertyTypeDifference, "P3").WithLocation(15, 26)); } @@ -2322,13 +2444,13 @@ partial class C3 : I // (8,19): error CS0754: A partial member may not explicitly implement an interface member // partial int I.P { get; set; } Diagnostic(ErrorCode.ERR_PartialMemberNotExplicit, "P").WithLocation(8, 19), - // (14,19): error CS9300: Partial property 'C2.I.P' must have an implementation part. + // (14,19): error CS9248: Partial property 'C2.I.P' must have an implementation part. // partial int I.P { get; set; } Diagnostic(ErrorCode.ERR_PartialPropertyMissingImplementation, "P").WithArguments("C2.I.P").WithLocation(14, 19), // (14,19): error CS0754: A partial member may not explicitly implement an interface member // partial int I.P { get; set; } Diagnostic(ErrorCode.ERR_PartialMemberNotExplicit, "P").WithLocation(14, 19), - // (19,19): error CS9301: Partial property 'C3.I.P' must have a definition part. + // (19,19): error CS9249: Partial property 'C3.I.P' must have a definition part. // partial int I.P { get => 1; set { } } Diagnostic(ErrorCode.ERR_PartialPropertyMissingDefinition, "P").WithArguments("C3.I.P").WithLocation(19, 19), // (19,19): error CS0754: A partial member may not explicitly implement an interface member @@ -2356,13 +2478,13 @@ class C // (3,17): error CS0751: A partial member must be declared within a partial type // partial int P1 { get; set; } Diagnostic(ErrorCode.ERR_PartialMemberOnlyInPartialClass, "P1").WithLocation(3, 17), - // (6,17): error CS9300: Partial property 'C.P2' must have an implementation part. + // (6,17): error CS9248: Partial property 'C.P2' must have an implementation part. // partial int P2 { get; set; } Diagnostic(ErrorCode.ERR_PartialPropertyMissingImplementation, "P2").WithArguments("C.P2").WithLocation(6, 17), // (6,17): error CS0751: A partial member must be declared within a partial type // partial int P2 { get; set; } Diagnostic(ErrorCode.ERR_PartialMemberOnlyInPartialClass, "P2").WithLocation(6, 17), - // (8,17): error CS9301: Partial property 'C.P3' must have a definition part. + // (8,17): error CS9249: Partial property 'C.P3' must have a definition part. // partial int P3 { get => 1; set { } } Diagnostic(ErrorCode.ERR_PartialPropertyMissingDefinition, "P3").WithArguments("C.P3").WithLocation(8, 17), // (8,17): error CS0751: A partial member must be declared within a partial type @@ -2423,22 +2545,22 @@ partial class C2 var comp = CreateCompilation(source); comp.VerifyEmitDiagnostics( - // (3,24): error CS9300: Partial property 'C1.this[int]' must have an implementation part. + // (3,24): error CS9248: Partial property 'C1.this[int]' must have an implementation part. // public partial int this[int i] { get; set; } Diagnostic(ErrorCode.ERR_PartialPropertyMissingImplementation, "this").WithArguments("C1.this[int]").WithLocation(3, 24), - // (4,24): error CS9301: Partial property 'C1.this[ref int]' must have a definition part. + // (4,24): error CS9249: Partial property 'C1.this[ref int]' must have a definition part. // public partial int this[ref int i] { get => i; set { } } Diagnostic(ErrorCode.ERR_PartialPropertyMissingDefinition, "this").WithArguments($"C1.this[{refKind} int]").WithLocation(4, 24), // (4,29): error CS0631: ref and out are not valid in this context // public partial int this[ref int i] { get => i; set { } } Diagnostic(ErrorCode.ERR_IllegalRefParam, refKind).WithLocation(4, 29), - // (9,24): error CS9300: Partial property 'C2.this[ref int]' must have an implementation part. + // (9,24): error CS9248: Partial property 'C2.this[ref int]' must have an implementation part. // public partial int this[ref int i] { get; set; } Diagnostic(ErrorCode.ERR_PartialPropertyMissingImplementation, "this").WithArguments($"C2.this[{refKind} int]").WithLocation(9, 24), // (9,29): error CS0631: ref and out are not valid in this context // public partial int this[ref int i] { get; set; } Diagnostic(ErrorCode.ERR_IllegalRefParam, refKind).WithLocation(9, 29), - // (10,24): error CS9301: Partial property 'C2.this[int]' must have a definition part. + // (10,24): error CS9249: Partial property 'C2.this[int]' must have a definition part. // public partial int this[int i] { get => i; set { } } Diagnostic(ErrorCode.ERR_PartialPropertyMissingDefinition, "this").WithArguments("C2.this[int]").WithLocation(10, 24)); } @@ -2464,16 +2586,16 @@ partial class C2 var comp = CreateCompilation(source); comp.VerifyEmitDiagnostics( - // (3,24): error CS9300: Partial property 'C1.this[int]' must have an implementation part. + // (3,24): error CS9248: Partial property 'C1.this[int]' must have an implementation part. // public partial int this[int i] { get; set; } Diagnostic(ErrorCode.ERR_PartialPropertyMissingImplementation, "this").WithArguments("C1.this[int]").WithLocation(3, 24), - // (4,24): error CS9301: Partial property 'C1.this[in int]' must have a definition part. + // (4,24): error CS9249: Partial property 'C1.this[in int]' must have a definition part. // public partial int this[in int i] { get => i; set { } } Diagnostic(ErrorCode.ERR_PartialPropertyMissingDefinition, "this").WithArguments($"C1.this[{refKind} int]").WithLocation(4, 24), - // (9,24): error CS9300: Partial property 'C2.this[in int]' must have an implementation part. + // (9,24): error CS9248: Partial property 'C2.this[in int]' must have an implementation part. // public partial int this[in int i] { get; set; } Diagnostic(ErrorCode.ERR_PartialPropertyMissingImplementation, "this").WithArguments($"C2.this[{refKind} int]").WithLocation(9, 24), - // (10,24): error CS9301: Partial property 'C2.this[int]' must have a definition part. + // (10,24): error CS9249: Partial property 'C2.this[int]' must have a definition part. // public partial int this[int i] { get => i; set { } } Diagnostic(ErrorCode.ERR_PartialPropertyMissingDefinition, "this").WithArguments("C2.this[int]").WithLocation(10, 24)); } @@ -2497,13 +2619,13 @@ partial class C2 var comp = CreateCompilation(source); comp.VerifyEmitDiagnostics( - // (3,24): error CS9300: Partial property 'C1.this[ref int]' must have an implementation part. + // (3,24): error CS9248: Partial property 'C1.this[ref int]' must have an implementation part. // public partial int this[ref int i] { get; set; } Diagnostic(ErrorCode.ERR_PartialPropertyMissingImplementation, "this").WithArguments("C1.this[ref int]").WithLocation(3, 24), // (3,29): error CS0631: ref and out are not valid in this context // public partial int this[ref int i] { get; set; } Diagnostic(ErrorCode.ERR_IllegalRefParam, "ref").WithLocation(3, 29), - // (4,24): error CS9301: Partial property 'C1.this[out int]' must have a definition part. + // (4,24): error CS9249: Partial property 'C1.this[out int]' must have a definition part. // public partial int this[out int i] { get => i = 0; set => i = 0; } Diagnostic(ErrorCode.ERR_PartialPropertyMissingDefinition, "this").WithArguments("C1.this[out int]").WithLocation(4, 24), // (4,24): error CS0111: Type 'C1' already defines a member called 'this' with the same parameter types @@ -2512,13 +2634,13 @@ partial class C2 // (4,29): error CS0631: ref and out are not valid in this context // public partial int this[out int i] { get => i = 0; set => i = 0; } Diagnostic(ErrorCode.ERR_IllegalRefParam, "out").WithLocation(4, 29), - // (9,24): error CS9300: Partial property 'C2.this[out int]' must have an implementation part. + // (9,24): error CS9248: Partial property 'C2.this[out int]' must have an implementation part. // public partial int this[out int i] { get; set; } Diagnostic(ErrorCode.ERR_PartialPropertyMissingImplementation, "this").WithArguments("C2.this[out int]").WithLocation(9, 24), // (9,29): error CS0631: ref and out are not valid in this context // public partial int this[out int i] { get; set; } Diagnostic(ErrorCode.ERR_IllegalRefParam, "out").WithLocation(9, 29), - // (10,24): error CS9301: Partial property 'C2.this[ref int]' must have a definition part. + // (10,24): error CS9249: Partial property 'C2.this[ref int]' must have a definition part. // public partial int this[ref int i] { get => i; set { } } Diagnostic(ErrorCode.ERR_PartialPropertyMissingDefinition, "this").WithArguments("C2.this[ref int]").WithLocation(10, 24), // (10,24): error CS0111: Type 'C2' already defines a member called 'this' with the same parameter types @@ -2549,19 +2671,19 @@ partial class C2 var comp = CreateCompilation(source); comp.VerifyEmitDiagnostics( - // (3,24): error CS9300: Partial property 'C1.this[in int]' must have an implementation part. + // (3,24): error CS9248: Partial property 'C1.this[in int]' must have an implementation part. // public partial int this[in int i] { get; set; } Diagnostic(ErrorCode.ERR_PartialPropertyMissingImplementation, "this").WithArguments("C1.this[in int]").WithLocation(3, 24), - // (4,24): error CS9301: Partial property 'C1.this[ref readonly int]' must have a definition part. + // (4,24): error CS9249: Partial property 'C1.this[ref readonly int]' must have a definition part. // public partial int this[ref readonly int i] { get => i; set { } } Diagnostic(ErrorCode.ERR_PartialPropertyMissingDefinition, "this").WithArguments("C1.this[ref readonly int]").WithLocation(4, 24), // (4,24): error CS0111: Type 'C1' already defines a member called 'this' with the same parameter types // public partial int this[ref readonly int i] { get => i; set { } } Diagnostic(ErrorCode.ERR_MemberAlreadyExists, "this").WithArguments("this", "C1").WithLocation(4, 24), - // (9,24): error CS9300: Partial property 'C2.this[ref readonly int]' must have an implementation part. + // (9,24): error CS9248: Partial property 'C2.this[ref readonly int]' must have an implementation part. // public partial int this[ref readonly int i] { get; set; } Diagnostic(ErrorCode.ERR_PartialPropertyMissingImplementation, "this").WithArguments("C2.this[ref readonly int]").WithLocation(9, 24), - // (10,24): error CS9301: Partial property 'C2.this[in int]' must have a definition part. + // (10,24): error CS9249: Partial property 'C2.this[in int]' must have a definition part. // public partial int this[in int i] { get => i; set { } } Diagnostic(ErrorCode.ERR_PartialPropertyMissingDefinition, "this").WithArguments("C2.this[in int]").WithLocation(10, 24), // (10,24): error CS0111: Type 'C2' already defines a member called 'this' with the same parameter types @@ -2593,10 +2715,10 @@ partial class C2 var comp = CreateCompilation(source); comp.VerifyEmitDiagnostics( - // (3,24): error CS9300: Partial property 'C1.this[in int]' must have an implementation part. + // (3,24): error CS9248: Partial property 'C1.this[in int]' must have an implementation part. // public partial int this[in int i] { get; set; } Diagnostic(ErrorCode.ERR_PartialPropertyMissingImplementation, "this").WithArguments($"C1.this[{goodRefKind} int]").WithLocation(3, 24), - // (4,24): error CS9301: Partial property 'C1.this[ref int]' must have a definition part. + // (4,24): error CS9249: Partial property 'C1.this[ref int]' must have a definition part. // public partial int this[ref int i] { get => i; set { } } Diagnostic(ErrorCode.ERR_PartialPropertyMissingDefinition, "this").WithArguments($"C1.this[{badRefKind} int]").WithLocation(4, 24), // (4,24): error CS0111: Type 'C1' already defines a member called 'this' with the same parameter types @@ -2605,13 +2727,13 @@ partial class C2 // (4,29): error CS0631: ref and out are not valid in this context // public partial int this[ref int i] { get => i; set { } } Diagnostic(ErrorCode.ERR_IllegalRefParam, badRefKind).WithLocation(4, 29), - // (9,24): error CS9300: Partial property 'C2.this[ref int]' must have an implementation part. + // (9,24): error CS9248: Partial property 'C2.this[ref int]' must have an implementation part. // public partial int this[ref int i] { get; set; } Diagnostic(ErrorCode.ERR_PartialPropertyMissingImplementation, "this").WithArguments($"C2.this[{badRefKind} int]").WithLocation(9, 24), // (9,29): error CS0631: ref and out are not valid in this context // public partial int this[ref int i] { get; set; } Diagnostic(ErrorCode.ERR_IllegalRefParam, badRefKind).WithLocation(9, 29), - // (10,24): error CS9301: Partial property 'C2.this[in int]' must have a definition part. + // (10,24): error CS9249: Partial property 'C2.this[in int]' must have a definition part. // public partial int this[in int i] { get => i; set { } } Diagnostic(ErrorCode.ERR_PartialPropertyMissingDefinition, "this").WithArguments($"C2.this[{goodRefKind} int]").WithLocation(10, 24), // (10,24): error CS0111: Type 'C2' already defines a member called 'this' with the same parameter types @@ -2632,10 +2754,10 @@ partial class C var comp = CreateCompilation(source); comp.VerifyEmitDiagnostics( - // (3,24): error CS9300: Partial property 'C.this[int]' must have an implementation part. + // (3,24): error CS9248: Partial property 'C.this[int]' must have an implementation part. // public partial int this[int i] { get; set; } Diagnostic(ErrorCode.ERR_PartialPropertyMissingImplementation, "this").WithArguments("C.this[int]").WithLocation(3, 24), - // (4,24): error CS9301: Partial property 'C.this[string]' must have a definition part. + // (4,24): error CS9249: Partial property 'C.this[string]' must have a definition part. // public partial int this[string s] { get => 1; set { } } Diagnostic(ErrorCode.ERR_PartialPropertyMissingDefinition, "this").WithArguments("C.this[string]").WithLocation(4, 24)); } @@ -2654,7 +2776,7 @@ partial class C var comp = CreateCompilation(source); comp.VerifyEmitDiagnostics( - // (5,24): warning CS9308: Partial property declarations 'int C.this[string s]' and 'int C.this[string? s]' have signature differences. + // (5,24): warning CS9256: Partial property declarations 'int C.this[string s]' and 'int C.this[string? s]' have signature differences. // public partial int this[string? s] { get => 1; set { } } Diagnostic(ErrorCode.WRN_PartialPropertySignatureDifference, "this").WithArguments("int C.this[string s]", "int C.this[string? s]").WithLocation(5, 24)); } @@ -2673,7 +2795,7 @@ partial class C var comp = CreateCompilation(source); comp.VerifyEmitDiagnostics( - // (5,24): warning CS9308: Partial property declarations 'int C.this[dynamic[] s]' and 'int C.this[object[] s]' have signature differences. + // (5,24): warning CS9256: Partial property declarations 'int C.this[dynamic[] s]' and 'int C.this[object[] s]' have signature differences. // public partial int this[object[] s] { get => 1; set { } } Diagnostic(ErrorCode.WRN_PartialPropertySignatureDifference, "this").WithArguments("int C.this[dynamic[] s]", "int C.this[object[] s]").WithLocation(5, 24)); } @@ -3095,19 +3217,19 @@ partial class C var comp = CreateCompilation(source); comp.VerifyEmitDiagnostics( - // (3,24): error CS9300: Partial property 'C.this[int]' must have an implementation part. + // (3,24): error CS9248: Partial property 'C.this[int]' must have an implementation part. // public partial int this[int x] { get; set; } // missing impl Diagnostic(ErrorCode.ERR_PartialPropertyMissingImplementation, "this").WithArguments("C.this[int]").WithLocation(3, 24), - // (5,24): error CS9301: Partial property 'C.this[int, int]' must have a definition part. + // (5,24): error CS9249: Partial property 'C.this[int, int]' must have a definition part. // public partial int this[int x, int y] { get => 1; set { } } // missing decl Diagnostic(ErrorCode.ERR_PartialPropertyMissingDefinition, "this").WithArguments("C.this[int, int]").WithLocation(5, 24), - // (8,24): error CS9302: A partial property may not have multiple defining declarations, and cannot be an auto-property. + // (8,24): error CS9250: A partial property may not have multiple defining declarations, and cannot be an auto-property. // public partial int this[int x, int y, int z] { get; set; } Diagnostic(ErrorCode.ERR_PartialPropertyDuplicateDefinition, "this").WithLocation(8, 24), // (8,24): error CS0111: Type 'C' already defines a member called 'this' with the same parameter types // public partial int this[int x, int y, int z] { get; set; } Diagnostic(ErrorCode.ERR_MemberAlreadyExists, "this").WithArguments("this", "C").WithLocation(8, 24), - // (13,24): error CS9303: A partial property may not have multiple implementing declarations + // (13,24): error CS9251: A partial property may not have multiple implementing declarations // public partial int this[int x, int y, int z, int a] { get => 1; set { } } Diagnostic(ErrorCode.ERR_PartialPropertyDuplicateImplementation, "this").WithLocation(13, 24), // (13,24): error CS0111: Type 'C' already defines a member called 'this' with the same parameter types @@ -3128,7 +3250,7 @@ partial class C var comp = CreateCompilation(source); comp.VerifyEmitDiagnostics( - // (4,29): error CS9307: Both partial property declarations must have the same type. + // (4,29): error CS9255: Both partial property declarations must have the same type. // public partial string[] this[int x] { get => []; set { } } Diagnostic(ErrorCode.ERR_PartialPropertyTypeDifference, "this").WithLocation(4, 29)); } @@ -3627,6 +3749,170 @@ partial class C AssertEx.Equal([], property.GetAttributes().ToStrings()); } + [Fact] + public void PropertyInitializer() + { + var source = """ + partial class C + { + public partial string P1 { get; set; } = "a"; + public partial string P1 { get => ""; set { } } + + public partial string P2 { get; set; } + public partial string P2 { get => ""; set { } } = "b"; + + public partial string P3 { get; set; } = "c"; + public partial string P3 { get => ""; set { } } = "d"; + } + """; + + var comp = CreateCompilation(source); + comp.VerifyEmitDiagnostics( + // (3,27): error CS8050: Only auto-implemented properties can have initializers. + // public partial string P1 { get; set; } = "a"; + Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "P1").WithLocation(3, 27), + // (7,27): error CS8050: Only auto-implemented properties can have initializers. + // public partial string P2 { get => ""; set { } } = "b"; + Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "P2").WithLocation(7, 27), + // (9,27): error CS8050: Only auto-implemented properties can have initializers. + // public partial string P3 { get; set; } = "c"; + Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "P3").WithLocation(9, 27), + // (10,27): error CS8050: Only auto-implemented properties can have initializers. + // public partial string P3 { get => ""; set { } } = "d"; + Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "P3").WithLocation(10, 27)); + } + + [Fact] + public void PropertyInitializer_ContainsErrors() + { + var source = """ + partial class C + { + public partial string P1 { get; set; } = ERROR; + public partial string P1 { get => ""; set { } } + + public partial string P2 { get; set; } + public partial string P2 { get => ""; set { } } = ERROR; + + public partial string P3 { get; set; } = ERROR; + public partial string P3 { get => ""; set { } } = ERROR; + } + """; + + var comp = CreateCompilation(source); + comp.VerifyEmitDiagnostics( + // (3,27): error CS8050: Only auto-implemented properties can have initializers. + // public partial string P1 { get; set; } = ERROR; + Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "P1").WithLocation(3, 27), + // (3,46): error CS0103: The name 'ERROR' does not exist in the current context + // public partial string P1 { get; set; } = ERROR; + Diagnostic(ErrorCode.ERR_NameNotInContext, "ERROR").WithArguments("ERROR").WithLocation(3, 46), + // (7,27): error CS8050: Only auto-implemented properties can have initializers. + // public partial string P2 { get => ""; set { } } = ERROR; + Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "P2").WithLocation(7, 27), + // (7,55): error CS0103: The name 'ERROR' does not exist in the current context + // public partial string P2 { get => ""; set { } } = ERROR; + Diagnostic(ErrorCode.ERR_NameNotInContext, "ERROR").WithArguments("ERROR").WithLocation(7, 55), + // (9,27): error CS8050: Only auto-implemented properties can have initializers. + // public partial string P3 { get; set; } = ERROR; + Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "P3").WithLocation(9, 27), + // (9,46): error CS0103: The name 'ERROR' does not exist in the current context + // public partial string P3 { get; set; } = ERROR; + Diagnostic(ErrorCode.ERR_NameNotInContext, "ERROR").WithArguments("ERROR").WithLocation(9, 46), + // (10,27): error CS8050: Only auto-implemented properties can have initializers. + // public partial string P3 { get => ""; set { } } = ERROR; + Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "P3").WithLocation(10, 27), + // (10,55): error CS0103: The name 'ERROR' does not exist in the current context + // public partial string P3 { get => ""; set { } } = ERROR; + Diagnostic(ErrorCode.ERR_NameNotInContext, "ERROR").WithArguments("ERROR").WithLocation(10, 55)); + } + + [Fact] + public void PropertyInitializer_AndFieldTargetedAttribute() + { + // A synthesized field symbol is created when property has an initializer, even if the property is not an auto-property. + var source = """ + public class Attr1 : System.Attribute { } + public class Attr2 : System.Attribute { } + + partial class C + { + [field: Attr1] + public partial string P1 { get; set; } = "a"; + [field: Attr2] + public partial string P1 { get => ""; set { } } + + [field: Attr1] + public partial string P2 { get; set; } + [field: Attr2] + public partial string P2 { get => ""; set { } } = "b"; + + [field: Attr1] + public partial string P3 { get; set; } = "c"; + [field: Attr2] + public partial string P3 { get => ""; set { } } = "d"; + } + """; + + var comp = CreateCompilation(source); + comp.VerifyEmitDiagnostics( + // (6,6): warning CS0657: 'field' is not a valid attribute location for this declaration. Valid attribute locations for this declaration are 'property'. All attributes in this block will be ignored. + // [field: Attr1] + Diagnostic(ErrorCode.WRN_AttributeLocationOnBadDeclaration, "field").WithArguments("field", "property").WithLocation(6, 6), + // (7,27): error CS8050: Only auto-implemented properties can have initializers. + // public partial string P1 { get; set; } = "a"; + Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "P1").WithLocation(7, 27), + // (8,6): warning CS0657: 'field' is not a valid attribute location for this declaration. Valid attribute locations for this declaration are 'property'. All attributes in this block will be ignored. + // [field: Attr2] + Diagnostic(ErrorCode.WRN_AttributeLocationOnBadDeclaration, "field").WithArguments("field", "property").WithLocation(8, 6), + // (11,6): warning CS0657: 'field' is not a valid attribute location for this declaration. Valid attribute locations for this declaration are 'property'. All attributes in this block will be ignored. + // [field: Attr1] + Diagnostic(ErrorCode.WRN_AttributeLocationOnBadDeclaration, "field").WithArguments("field", "property").WithLocation(11, 6), + // (13,6): warning CS0657: 'field' is not a valid attribute location for this declaration. Valid attribute locations for this declaration are 'property'. All attributes in this block will be ignored. + // [field: Attr2] + Diagnostic(ErrorCode.WRN_AttributeLocationOnBadDeclaration, "field").WithArguments("field", "property").WithLocation(13, 6), + // (14,27): error CS8050: Only auto-implemented properties can have initializers. + // public partial string P2 { get => ""; set { } } = "b"; + Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "P2").WithLocation(14, 27), + // (16,6): warning CS0657: 'field' is not a valid attribute location for this declaration. Valid attribute locations for this declaration are 'property'. All attributes in this block will be ignored. + // [field: Attr1] + Diagnostic(ErrorCode.WRN_AttributeLocationOnBadDeclaration, "field").WithArguments("field", "property").WithLocation(16, 6), + // (17,27): error CS8050: Only auto-implemented properties can have initializers. + // public partial string P3 { get; set; } = "c"; + Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "P3").WithLocation(17, 27), + // (18,6): warning CS0657: 'field' is not a valid attribute location for this declaration. Valid attribute locations for this declaration are 'property'. All attributes in this block will be ignored. + // [field: Attr2] + Diagnostic(ErrorCode.WRN_AttributeLocationOnBadDeclaration, "field").WithArguments("field", "property").WithLocation(18, 6), + // (19,27): error CS8050: Only auto-implemented properties can have initializers. + // public partial string P3 { get => ""; set { } } = "d"; + Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "P3").WithLocation(19, 27)); + + AssertEx.Equal([ + "System.String C.k__BackingField", + "System.String C.P1 { get; set; }", + "System.String C.P1.get", + "void C.P1.set", + "System.String C.P2 { get; set; }", + "System.String C.P2.get", + "void C.P2.set", + "System.String C.k__BackingField", + "System.String C.k__BackingField", + "System.String C.P3 { get; set; }", + "System.String C.P3.get", + "void C.P3.set", + "System.String C.k__BackingField", + "C..ctor()"], + comp.GetMember("C").GetMembers().SelectAsArray(m => m.ToTestDisplayString())); + + Assert.Empty(comp.GetMember("C.k__BackingField").GetAttributes()); + Assert.Empty(comp.GetMember("C.k__BackingField").GetAttributes()); + + var p3Fields = comp.GetMembers("C.k__BackingField"); + Assert.Equal(2, p3Fields.Length); + Assert.Empty(p3Fields[0].GetAttributes()); + Assert.Empty(p3Fields[1].GetAttributes()); + } + [Theory] [InlineData("", "[UnscopedRef] ")] [InlineData("[UnscopedRef] ", "")] @@ -4334,6 +4620,7 @@ partial class C Diagnostic(ErrorCode.ERR_UnmanagedCallersOnlyRequiresStatic, "UnmanagedCallersOnly").WithLocation(17, 30)); } + /// See also [Fact] public void IndexerParameterNameDifference() { @@ -4343,7 +4630,7 @@ public void IndexerParameterNameDifference() partial class C { public partial int this[int p1] { get; set; } - public partial int this[int p2] { get => p2; set { } } + public partial int this[int p2] { get => p2; set => p2.ToString(); } static void Main() { @@ -4353,14 +4640,98 @@ static void Main() } """; - var verifier = CompileAndVerify(source, expectedOutput: "1"); + var verifier = CompileAndVerify(source, expectedOutput: "1", symbolValidator: verify, sourceSymbolValidator: verify); verifier.VerifyDiagnostics( - // (6,24): warning CS9308: Partial property declarations 'int C.this[int p1]' and 'int C.this[int p2]' have signature differences. + // (6,24): warning CS9256: Partial property declarations 'int C.this[int p1]' and 'int C.this[int p2]' have signature differences. // public partial int this[int p2] { get => p2; set { } } Diagnostic(ErrorCode.WRN_PartialPropertySignatureDifference, "this").WithArguments("int C.this[int p1]", "int C.this[int p2]").WithLocation(6, 24)); - var indexer = ((CSharpCompilation)verifier.Compilation).GetMember("C").Indexers.Single(); - Assert.Equal("p1", indexer.Parameters.Single().Name); + void verify(ModuleSymbol module) + { + var indexer = module.GlobalNamespace.GetMember("C").Indexers.Single(); + Assert.Equal("p1", indexer.Parameters.Single().Name); + } + } + + /// See also + [Fact] + public void IndexerParameterNameDifference_Attributes() + { + var source = """ + using System; + + [AttributeUsage(AttributeTargets.All, AllowMultiple = true)] + public class Attr(string s) : Attribute { } // 1 (unread parameter) + + partial class C + { + [Attr(nameof(p1))] + [Attr(nameof(p2))] // 2 + public partial int this[int p1] + { + get; + + [param: Attr(nameof(p1))] // 3 + [param: Attr(nameof(p2))] + set; + } + + [Attr(nameof(p1))] + [Attr(nameof(p2))] // 4 + public partial int this[int p2] // 5 + { + get => p2; + + [param: Attr(nameof(p1))] // 6 + [param: Attr(nameof(p2))] + set => p2.ToString(); + } + + [Attr(nameof(p1))] + [Attr(nameof(p2))] // 7 + public partial void M( + [Attr(nameof(p1))] // 8 + [Attr(nameof(p2))] + int p1); + public partial void M( // 9 + [Attr(nameof(p1))] // 10 + [Attr(nameof(p2))] + int p2) { } + } + """; + + var verifier = CreateCompilation(source); + verifier.VerifyDiagnostics( + // (4,26): warning CS9113: Parameter 's' is unread. + // public class Attr(string s) : Attribute { } // 1 (unread parameter) + Diagnostic(ErrorCode.WRN_UnreadPrimaryConstructorParameter, "s").WithArguments("s").WithLocation(4, 26), + // (9,18): error CS0103: The name 'p2' does not exist in the current context + // [Attr(nameof(p2))] // 2 + Diagnostic(ErrorCode.ERR_NameNotInContext, "p2").WithArguments("p2").WithLocation(9, 18), + // (14,29): error CS0103: The name 'p1' does not exist in the current context + // [param: Attr(nameof(p1))] // 3 + Diagnostic(ErrorCode.ERR_NameNotInContext, "p1").WithArguments("p1").WithLocation(14, 29), + // (20,18): error CS0103: The name 'p2' does not exist in the current context + // [Attr(nameof(p2))] // 4 + Diagnostic(ErrorCode.ERR_NameNotInContext, "p2").WithArguments("p2").WithLocation(20, 18), + // (21,24): warning CS9256: Partial property declarations 'int C.this[int p1]' and 'int C.this[int p2]' have signature differences. + // public partial int this[int p2] // 5 + Diagnostic(ErrorCode.WRN_PartialPropertySignatureDifference, "this").WithArguments("int C.this[int p1]", "int C.this[int p2]").WithLocation(21, 24), + // (25,29): error CS0103: The name 'p1' does not exist in the current context + // [param: Attr(nameof(p1))] // 6 + Diagnostic(ErrorCode.ERR_NameNotInContext, "p1").WithArguments("p1").WithLocation(25, 29), + // (31,18): error CS0103: The name 'p2' does not exist in the current context + // [Attr(nameof(p2))] // 7 + Diagnostic(ErrorCode.ERR_NameNotInContext, "p2").WithArguments("p2").WithLocation(31, 18), + // (33,22): error CS0103: The name 'p1' does not exist in the current context + // [Attr(nameof(p1))] // 8 + Diagnostic(ErrorCode.ERR_NameNotInContext, "p1").WithArguments("p1").WithLocation(33, 22), + // (36,25): warning CS8826: Partial method declarations 'void C.M(int p1)' and 'void C.M(int p2)' have signature differences. + // public partial void M( // 9 + Diagnostic(ErrorCode.WRN_PartialMethodTypeDifference, "M").WithArguments("void C.M(int p1)", "void C.M(int p2)").WithLocation(36, 25), + // (37,22): error CS0103: The name 'p1' does not exist in the current context + // [Attr(nameof(p1))] // 10 + Diagnostic(ErrorCode.ERR_NameNotInContext, "p1").WithArguments("p1").WithLocation(37, 22)); } [Fact] @@ -4602,7 +4973,5 @@ partial class C Assert.Equal("SourceFile(Program.cs[52..53))", defSymbol.Locations.Single().ToString()); Assert.Equal("SourceFile(Program.cs[97..98))", implSymbol.Locations.Single().ToString()); } - - // PROTOTYPE(partial-properties): override partial property where base has modopt } } diff --git a/src/Compilers/CSharp/Test/Symbol/Symbols/Source/CustomModifierCopyTests.cs b/src/Compilers/CSharp/Test/Symbol/Symbols/Source/CustomModifierCopyTests.cs index b1068ddbae44f..27b140fe6ef97 100644 --- a/src/Compilers/CSharp/Test/Symbol/Symbols/Source/CustomModifierCopyTests.cs +++ b/src/Compilers/CSharp/Test/Symbol/Symbols/Source/CustomModifierCopyTests.cs @@ -269,6 +269,71 @@ class Derived : MethodCustomModifierCombinations } } + /// + /// Test copying custom modifiers in/on parameters/return types. + /// + [Fact] + public void TestPartialMethodOverrideCombinations() + { + var text = @" +partial class Derived : MethodCustomModifierCombinations +{ + public override partial int[] Method1111(int[] a) { return a; } + public override partial int[] Method1110(int[] a) { return a; } + public override partial int[] Method1101(int[] a) { return a; } + public override partial int[] Method1100(int[] a) { return a; } + public override partial int[] Method1011(int[] a) { return a; } + public override partial int[] Method1010(int[] a) { return a; } + public override partial int[] Method1001(int[] a) { return a; } + public override partial int[] Method1000(int[] a) { return a; } + public override partial int[] Method0111(int[] a) { return a; } + public override partial int[] Method0110(int[] a) { return a; } + public override partial int[] Method0101(int[] a) { return a; } + public override partial int[] Method0100(int[] a) { return a; } + public override partial int[] Method0011(int[] a) { return a; } + public override partial int[] Method0010(int[] a) { return a; } + public override partial int[] Method0001(int[] a) { return a; } + public override partial int[] Method0000(int[] a) { return a; } + + public override partial int[] Method1111(int[] a); + public override partial int[] Method1110(int[] a); + public override partial int[] Method1101(int[] a); + public override partial int[] Method1100(int[] a); + public override partial int[] Method1011(int[] a); + public override partial int[] Method1010(int[] a); + public override partial int[] Method1001(int[] a); + public override partial int[] Method1000(int[] a); + public override partial int[] Method0111(int[] a); + public override partial int[] Method0110(int[] a); + public override partial int[] Method0101(int[] a); + public override partial int[] Method0100(int[] a); + public override partial int[] Method0011(int[] a); + public override partial int[] Method0010(int[] a); + public override partial int[] Method0001(int[] a); + public override partial int[] Method0000(int[] a); +} +"; + + var ilAssemblyReference = TestReferences.SymbolsTests.CustomModifiers.Modifiers.dll; + + var comp = CreateCompilation(text, new MetadataReference[] { ilAssemblyReference }); + var global = comp.GlobalNamespace; + + comp.VerifyEmitDiagnostics(); + + var @class = global.GetMember("Derived"); + + for (int i = 0; i < 0xf; i++) + { + CheckMethodCustomModifiers( + @class.GetMember("Method" + Convert.ToString(i, 2).PadLeft(4, '0')), + inReturnType: (i & 0x8) != 0, + onReturnType: (i & 0x4) != 0, + inParameterType: (i & 0x2) != 0, + onParameterType: (i & 0x1) != 0); + } + } + /// /// Test copying custom modifiers in/on property types. /// @@ -290,7 +355,61 @@ class Derived : PropertyCustomModifierCombinations var comp = CreateCompilation(text, new MetadataReference[] { ilAssemblyReference }); var global = comp.GlobalNamespace; - comp.VerifyDiagnostics(); + comp.VerifyEmitDiagnostics(); + + var @class = global.GetMember("Derived"); + + for (int i = 0; i < 0x4; i++) + { + PropertySymbol property = @class.GetMember("Property" + Convert.ToString(i, 2).PadLeft(2, '0')); + bool inType = (i & 0x2) != 0; + bool onType = (i & 0x1) != 0; + + CheckPropertyCustomModifiers(property, inType, onType); + CheckMethodCustomModifiers( + property.GetMethod, + inReturnType: inType, + onReturnType: onType, + inParameterType: false, + onParameterType: false); + CheckMethodCustomModifiers( + property.SetMethod, + inReturnType: false, + onReturnType: false, + inParameterType: inType, + onParameterType: onType); + } + } + + /// + /// Test copying custom modifiers in/on partial property types. + /// + [Fact] + public void TestPartialPropertyOverrideCombinations() + { + var text = @" +partial class Derived : PropertyCustomModifierCombinations +{ + public override partial int[] Property11 { get; set; } + public override partial int[] Property11 { get => new int[0]; set { } } + + public override partial int[] Property10 { get; set; } + public override partial int[] Property10 { get => new int[0]; set { } } + + public override partial int[] Property01 { get; set; } + public override partial int[] Property01 { get => new int[0]; set { } } + + public override partial int[] Property00 { get; set; } + public override partial int[] Property00 { get => new int[0]; set { } } +} +"; + + var ilAssemblyReference = TestReferences.SymbolsTests.CustomModifiers.Modifiers.dll; + + var comp = CreateCompilation(text, new MetadataReference[] { ilAssemblyReference }); + var global = comp.GlobalNamespace; + + comp.VerifyEmitDiagnostics(); var @class = global.GetMember("Derived"); diff --git a/src/Compilers/CSharp/Test/Symbol/Symbols/SymbolErrorTests.cs b/src/Compilers/CSharp/Test/Symbol/Symbols/SymbolErrorTests.cs index f4203a5ce3cab..97aca352abf83 100644 --- a/src/Compilers/CSharp/Test/Symbol/Symbols/SymbolErrorTests.cs +++ b/src/Compilers/CSharp/Test/Symbol/Symbols/SymbolErrorTests.cs @@ -14087,10 +14087,10 @@ partial int this[int index] // (4,5): error CS0267: The 'partial' modifier can only appear immediately before 'class', 'record', 'struct', 'interface', or a method or property return type. // partial int f; Diagnostic(ErrorCode.ERR_PartialMisplaced, "partial").WithLocation(4, 5), - // (5,20): error CS9301: Partial property 'C.P' must have a definition part. + // (5,20): error CS9249: Partial property 'C.P' must have a definition part. // partial object P { get { return null; } } Diagnostic(ErrorCode.ERR_PartialPropertyMissingDefinition, "P").WithArguments("C.P").WithLocation(5, 20), - // (6,17): error CS9301: Partial property 'C.this[int]' must have a definition part. + // (6,17): error CS9249: Partial property 'C.this[int]' must have a definition part. // partial int this[int index] Diagnostic(ErrorCode.ERR_PartialPropertyMissingDefinition, "this").WithArguments("C.this[int]").WithLocation(6, 17), // (4,17): warning CS0169: The field 'C.f' is never used diff --git a/src/Compilers/Core/Portable/DiagnosticAnalyzer/AnalyzerManager.AnalyzerExecutionContext.cs b/src/Compilers/Core/Portable/DiagnosticAnalyzer/AnalyzerManager.AnalyzerExecutionContext.cs index db54971ea9269..40acf22276ee5 100644 --- a/src/Compilers/Core/Portable/DiagnosticAnalyzer/AnalyzerManager.AnalyzerExecutionContext.cs +++ b/src/Compilers/Core/Portable/DiagnosticAnalyzer/AnalyzerManager.AnalyzerExecutionContext.cs @@ -204,6 +204,7 @@ void processMembers(IEnumerable members) memberSet.Add(member); // Ensure that we include symbols for both parts of partial methods. + // https://github.com/dotnet/roslyn/issues/73772: also cascade to partial property implementation part if (member is IMethodSymbol method && !(method.PartialImplementationPart is null)) { diff --git a/src/Compilers/Core/Portable/DiagnosticAnalyzer/CompilationWithAnalyzers.cs b/src/Compilers/Core/Portable/DiagnosticAnalyzer/CompilationWithAnalyzers.cs index 2f8d1fa1fd9f7..a23c7ef140d3f 100644 --- a/src/Compilers/Core/Portable/DiagnosticAnalyzer/CompilationWithAnalyzers.cs +++ b/src/Compilers/Core/Portable/DiagnosticAnalyzer/CompilationWithAnalyzers.cs @@ -1118,6 +1118,10 @@ static bool shouldIncludeSymbol(ISymbolInternal symbol, SyntaxTree tree, Cancell } } + // https://github.com/dotnet/roslyn/issues/73772: should we also check IPropertySymbol? + // there is no interface IPropertySymbolInternal + // where are tests for this? + return false; } } diff --git a/src/Compilers/Core/Portable/Emit/EditAndContinue/SymbolChanges.cs b/src/Compilers/Core/Portable/Emit/EditAndContinue/SymbolChanges.cs index 88c563a21e702..89c2cf1fd101a 100644 --- a/src/Compilers/Core/Portable/Emit/EditAndContinue/SymbolChanges.cs +++ b/src/Compilers/Core/Portable/Emit/EditAndContinue/SymbolChanges.cs @@ -414,6 +414,7 @@ private void CalculateChanges( // Partial methods are supplied as implementations but recorded // internally as definitions since definitions are used in emit. + // https://github.com/dotnet/roslyn/issues/73772: should we also make sure to use the definition for a partial property? if (newMember.Kind == SymbolKind.Method) { var newMethod = (IMethodSymbolInternal)newMember; diff --git a/src/Compilers/Core/Portable/Emit/SemanticEdit.cs b/src/Compilers/Core/Portable/Emit/SemanticEdit.cs index be2f00be20c11..14cec150ebc50 100644 --- a/src/Compilers/Core/Portable/Emit/SemanticEdit.cs +++ b/src/Compilers/Core/Portable/Emit/SemanticEdit.cs @@ -142,6 +142,7 @@ public SemanticEdit(SemanticEditKind kind, ISymbol? oldSymbol, ISymbol? newSymbo } } + // https://github.com/dotnet/roslyn/issues/73772: should we also do this check for partial properties? if (oldSymbol is IMethodSymbol { PartialImplementationPart: not null }) { throw new ArgumentException("Partial method implementation required", nameof(oldSymbol)); diff --git a/src/Compilers/Test/Core/Assert/AssertEx.cs b/src/Compilers/Test/Core/Assert/AssertEx.cs index db5502c63f798..244b92a4d6aa9 100644 --- a/src/Compilers/Test/Core/Assert/AssertEx.cs +++ b/src/Compilers/Test/Core/Assert/AssertEx.cs @@ -656,13 +656,7 @@ public static string GetAssertMessage( } else { - itemInspector = static obj => obj switch - { - null => "", - // PROTOTYPE(partial-properties): this is adding unwanted quotes to VerifyIL baselines - string s => $@"""{s}""", - _ => obj.ToString() - }; + itemInspector = new Func(obj => (obj != null) ? obj.ToString() : ""); } } diff --git a/src/EditorFeatures/CSharpTest/SymbolKey/SymbolKeyCompilationsTests.cs b/src/EditorFeatures/CSharpTest/SymbolKey/SymbolKeyCompilationsTests.cs index 51430c5d8c820..b9f1ec2e3ae6c 100644 --- a/src/EditorFeatures/CSharpTest/SymbolKey/SymbolKeyCompilationsTests.cs +++ b/src/EditorFeatures/CSharpTest/SymbolKey/SymbolKeyCompilationsTests.cs @@ -160,6 +160,7 @@ public partial void M() { } var implementation = definition.PartialImplementationPart; // Assert that both the definition and implementation resolve back to themselves + // https://github.com/dotnet/roslyn/issues/73772: add a similar test for properties Assert.Equal(definition, ResolveSymbol(definition, comp, SymbolKeyComparison.None)); Assert.Equal(implementation, ResolveSymbol(implementation, comp, SymbolKeyComparison.None)); } diff --git a/src/Features/Core/Portable/Completion/Providers/AbstractPartialMethodCompletionProvider.cs b/src/Features/Core/Portable/Completion/Providers/AbstractPartialMethodCompletionProvider.cs index 11ef0079da66c..ddf3d0b4c1397 100644 --- a/src/Features/Core/Portable/Completion/Providers/AbstractPartialMethodCompletionProvider.cs +++ b/src/Features/Core/Portable/Completion/Providers/AbstractPartialMethodCompletionProvider.cs @@ -90,6 +90,7 @@ protected override async Task GenerateMemberAsync(ISymbol member, IName if (enclosingSymbol.TypeKind is not (TypeKind.Struct or TypeKind.Class)) return null; + // https://github.com/dotnet/roslyn/issues/73772: should we also add an `AbstractPartialPropertiesProvider`? var symbols = semanticModel.LookupSymbols(position, container: enclosingSymbol) .OfType() .Where(m => IsPartial(m) && m.PartialImplementationPart == null); diff --git a/src/Features/Core/Portable/EditAndContinue/AbstractEditAndContinueAnalyzer.cs b/src/Features/Core/Portable/EditAndContinue/AbstractEditAndContinueAnalyzer.cs index e8d2fd1d3de3c..769cf5bc507d0 100644 --- a/src/Features/Core/Portable/EditAndContinue/AbstractEditAndContinueAnalyzer.cs +++ b/src/Features/Core/Portable/EditAndContinue/AbstractEditAndContinueAnalyzer.cs @@ -3185,6 +3185,7 @@ IFieldSymbol or // The partial type needs to be specified in the following cases: // 1) partial method is updated (in case both implementation and definition are updated) // 2) partial type is updated + // https://github.com/dotnet/roslyn/issues/73772: do we also need to check IPropertySymbol.PartialDefinitionPart here? var partialType = editKind == SemanticEditKind.Update && symbol is IMethodSymbol { PartialDefinitionPart: not null } ? symbolCache.GetKey(symbol.ContainingType, cancellationToken) : IsPartialTypeEdit(oldSymbol, newSymbol, oldTree, newTree) @@ -3354,6 +3355,7 @@ bool PreprocessSymbolEdit(ref ISymbol? oldSymbol, ref ISymbol? newSymbol) var result = symbolKey.Resolve(compilation, ignoreAssemblyKey: true, cancellationToken).Symbol; // If we were looking for a definition and an implementation is returned the definition does not exist. + // https://github.com/dotnet/roslyn/issues/73772: Does PartialDefinitionPart also need to be checked here? return symbol is IMethodSymbol { PartialDefinitionPart: not null } && result is IMethodSymbol { IsPartialDefinition: true } ? null : result; } @@ -3666,6 +3668,7 @@ void AddDelete(ISymbol? symbol) if (symbol is null) return; + // https://github.com/dotnet/roslyn/issues/73772 Debug.Assert(symbol is not IMethodSymbol { IsPartialDefinition: true }); var partialType = symbol is IMethodSymbol { PartialDefinitionPart: not null } ? SymbolKey.Create(symbol.ContainingType, cancellationToken) : (SymbolKey?)null; diff --git a/src/Features/Core/Portable/EditAndContinue/Utilities/Extensions.cs b/src/Features/Core/Portable/EditAndContinue/Utilities/Extensions.cs index 3123b0a18407f..0d2226145bc2a 100644 --- a/src/Features/Core/Portable/EditAndContinue/Utilities/Extensions.cs +++ b/src/Features/Core/Portable/EditAndContinue/Utilities/Extensions.cs @@ -183,6 +183,7 @@ private static bool ParsePrimaryParameterBackingFieldName(string fieldName, [Not => (IMethodSymbol?)constructor.ContainingType.GetMembers(WellKnownMemberNames.DeconstructMethodName).FirstOrDefault( static (symbol, constructor) => symbol is IMethodSymbol method && HasDeconstructorSignature(method, constructor), constructor)?.PartialAsImplementation(); + // https://github.com/dotnet/roslyn/issues/73772: does this helper need to be updated to use IPropertySymbol.PartialImplementationPart? public static ISymbol PartialAsImplementation(this ISymbol symbol) => symbol is IMethodSymbol { PartialImplementationPart: { } impl } ? impl : symbol; diff --git a/src/Features/TestUtilities/EditAndContinue/EditAndContinueTestVerifier.cs b/src/Features/TestUtilities/EditAndContinue/EditAndContinueTestVerifier.cs index b4898d7604f13..cf39e98564710 100644 --- a/src/Features/TestUtilities/EditAndContinue/EditAndContinueTestVerifier.cs +++ b/src/Features/TestUtilities/EditAndContinue/EditAndContinueTestVerifier.cs @@ -322,6 +322,7 @@ SymbolKey CreateSymbolKey(SemanticEditDescription edit) // Symbol key will happily resolve to a definition part that has no implementation, so we validate that // differently + // https://github.com/dotnet/roslyn/issues/73772: what about deletion of partial property? if (expectedOldSymbol is IMethodSymbol { IsPartialDefinition: true } && symbolKey.Resolve(oldCompilation, ignoreAssemblyKey: true).Symbol is IMethodSymbol resolvedMethod) { diff --git a/src/Workspaces/Core/Portable/FindSymbols/FindReferences/Finders/OrdinaryMethodReferenceFinder.cs b/src/Workspaces/Core/Portable/FindSymbols/FindReferences/Finders/OrdinaryMethodReferenceFinder.cs index a046043129790..6813b72dd61ba 100644 --- a/src/Workspaces/Core/Portable/FindSymbols/FindReferences/Finders/OrdinaryMethodReferenceFinder.cs +++ b/src/Workspaces/Core/Portable/FindSymbols/FindReferences/Finders/OrdinaryMethodReferenceFinder.cs @@ -34,6 +34,7 @@ protected override ValueTask> DetermineCascadedSymbolsAs private static ImmutableArray GetOtherPartsOfPartial(IMethodSymbol symbol) { + // https://github.com/dotnet/roslyn/issues/73772: define/use a similar helper for PropertySymbolReferenceFinder+PropertyAccessorSymbolReferenceFinder? if (symbol.PartialDefinitionPart != null) return [symbol.PartialDefinitionPart]; diff --git a/src/Workspaces/Core/Portable/FindSymbols/FindReferences/Finders/ParameterSymbolReferenceFinder.cs b/src/Workspaces/Core/Portable/FindSymbols/FindReferences/Finders/ParameterSymbolReferenceFinder.cs index 5cffb6d4ca570..93978ac446a97 100644 --- a/src/Workspaces/Core/Portable/FindSymbols/FindReferences/Finders/ParameterSymbolReferenceFinder.cs +++ b/src/Workspaces/Core/Portable/FindSymbols/FindReferences/Finders/ParameterSymbolReferenceFinder.cs @@ -241,6 +241,7 @@ private static void CascadeBetweenPartialMethodParameters( IParameterSymbol parameter, ArrayBuilder results) { + // https://github.com/dotnet/roslyn/issues/73772: also cascade partial indexer parameters if (parameter.ContainingSymbol is IMethodSymbol method) { var ordinal = parameter.Ordinal; diff --git a/src/Workspaces/Core/Portable/Rename/ConflictEngine/DeclarationConflictHelpers.cs b/src/Workspaces/Core/Portable/Rename/ConflictEngine/DeclarationConflictHelpers.cs index f683b96b5fe64..7e17a0ca24a75 100644 --- a/src/Workspaces/Core/Portable/Rename/ConflictEngine/DeclarationConflictHelpers.cs +++ b/src/Workspaces/Core/Portable/Rename/ConflictEngine/DeclarationConflictHelpers.cs @@ -55,6 +55,7 @@ private static ImmutableArray GetConflictLocations(ISymbol renamedMemb { if (signatureToConflictingMember.TryGetValue(signature, out var conflictingSymbol)) { + // https://github.com/dotnet/roslyn/issues/73772: add other partial property part as conflicting symbol if (isMethod && conflictingSymbol is IMethodSymbol conflictingMethod && renamedMember is IMethodSymbol renamedMethod) { if (!(conflictingMethod.PartialDefinitionPart != null && Equals(conflictingMethod.PartialDefinitionPart, renamedMethod)) &&