diff --git a/src/Analyzers/CSharp/CodeFixes/Nullable/CSharpDeclareAsNullableCodeFixProvider.cs b/src/Analyzers/CSharp/CodeFixes/Nullable/CSharpDeclareAsNullableCodeFixProvider.cs
index 1576ed85a8762..3b49e503aec70 100644
--- a/src/Analyzers/CSharp/CodeFixes/Nullable/CSharpDeclareAsNullableCodeFixProvider.cs
+++ b/src/Analyzers/CSharp/CodeFixes/Nullable/CSharpDeclareAsNullableCodeFixProvider.cs
@@ -216,6 +216,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/Binder/BinderFactory.BinderFactoryVisitor.cs b/src/Compilers/CSharp/Portable/Binder/BinderFactory.BinderFactoryVisitor.cs
index 86c3bbd550cf6..84dd51c1cd3b0 100644
--- a/src/Compilers/CSharp/Portable/Binder/BinderFactory.BinderFactoryVisitor.cs
+++ b/src/Compilers/CSharp/Portable/Binder/BinderFactory.BinderFactoryVisitor.cs
@@ -290,6 +290,7 @@ public override Binder VisitAccessorDeclaration(AccessorDeclarationSyntax parent
if ((object)propertySymbol != null)
{
accessor = (parent.Kind() == SyntaxKind.GetAccessorDeclaration) ? propertySymbol.GetMethod : propertySymbol.SetMethod;
+ Debug.Assert(accessor is not null || parent.HasErrors);
}
break;
}
@@ -597,18 +598,25 @@ bool checkSymbol(Symbol sym, TextSpan memberSpan, SymbolKind kind, out Symbol re
return false;
}
- if (sym.Kind == SymbolKind.Method)
+ if (kind is SymbolKind.Method or SymbolKind.Property)
{
if (InSpan(sym.GetFirstLocation(), this.syntaxTree, memberSpan))
{
return true;
}
- // If this is a partial method, the method represents the defining part,
- // not the implementation (method.Locations includes both parts). If the
- // span is in fact in the implementation, return that method instead.
- var implementation = ((MethodSymbol)sym).PartialImplementationPart;
- if ((object)implementation != null)
+ // If this is a partial member, the member represents the defining part,
+ // not the implementation (member.Locations includes both parts). If the
+ // span is in fact in the implementation, return that member instead.
+ if (sym switch
+#pragma warning disable format
+ {
+ MethodSymbol method => (Symbol)method.PartialImplementationPart,
+ SourcePropertySymbol property => property.PartialImplementationPart,
+ _ => throw ExceptionUtilities.UnexpectedValue(sym)
+ }
+#pragma warning restore format
+ is { } implementation)
{
if (InSpan(implementation.GetFirstLocation(), this.syntaxTree, memberSpan))
{
diff --git a/src/Compilers/CSharp/Portable/CSharpResources.resx b/src/Compilers/CSharp/Portable/CSharpResources.resx
index 4c09a80debc1a..70558cc8ba160 100644
--- a/src/Compilers/CSharp/Portable/CSharpResources.resx
+++ b/src/Compilers/CSharp/Portable/CSharpResources.resx
@@ -1171,7 +1171,7 @@
Cannot implicitly convert type '{0}' to '{1}'. An explicit conversion exists (are you missing a cast?)
- The 'partial' modifier can only appear immediately before 'class', 'record', 'struct', 'interface', or a method return type.
+ The 'partial' modifier can only appear immediately before 'class', 'record', 'struct', 'interface', or a method or property return type.Imported type '{0}' is invalid. It contains a circular base type dependency.
@@ -2207,14 +2207,14 @@ If such a class is used as a base class and if the deriving class defines a dest
Inconsistent lambda parameter usage; parameter types must be all explicit or all implicit
-
- A partial method cannot have the 'abstract' modifier
+
+ A partial member cannot have the 'abstract' modifier
-
- A partial method must be declared within a partial type
+
+ A partial member must be declared within a partial type
-
- A partial method may not explicitly implement an interface method
+
+ A partial member may not explicitly implement an interface memberBoth partial method declarations must be extension methods or neither may be an extension method
@@ -2225,14 +2225,14 @@ If such a class is used as a base class and if the deriving class defines a dest
A partial method may not have multiple implementing declarations
-
- Both partial method declarations must use a params parameter or neither may use a params parameter
+
+ Both partial member declarations must use a params parameter or neither may use a params parameterNo defining declaration found for implementing declaration of partial method '{0}'
-
- Both partial method declarations, '{0}' and '{1}', must use the same tuple element names.
+
+ Both partial member declarations, '{0}' and '{1}', must use the same tuple element names.Partial method declarations of '{0}' have inconsistent constraints for type parameter '{1}'
@@ -2240,11 +2240,11 @@ If such a class is used as a base class and if the deriving class defines a dest
Cannot create delegate from method '{0}' because it is a partial method without an implementing declaration
-
- Both partial method declarations must be static or neither may be static
+
+ Both partial member declarations must be static or neither may be static
-
- Both partial method declarations must be unsafe or neither may be unsafe
+
+ Both partial member declarations must be unsafe or neither may be unsafePartial methods with only a defining declaration or removed conditional methods cannot be used in expression trees
@@ -5737,8 +5737,8 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ
Field-like event '{0}' cannot be 'readonly'.
-
- Both partial method declarations must be readonly or neither may be readonly
+
+ Both partial member declarations must be readonly or neither may be readonly'{0}': 'readonly' can only be used on accessors if the property or indexer has both a get and a set accessor
@@ -6521,17 +6521,17 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ
Partial method '{0}' must have accessibility modifiers because it has a 'virtual', 'override', 'sealed', 'new', or 'extern' modifier.
-
- Both partial method declarations must have identical accessibility modifiers.
+
+ Both partial member declarations must have identical accessibility modifiers.
-
- Both partial method declarations must have identical combinations of 'virtual', 'override', 'sealed', and 'new' modifiers.
+
+ Both partial member declarations must have identical combinations of 'virtual', 'override', 'sealed', and 'new' modifiers.Both partial method declarations must have the same return type.
-
- Partial method declarations must have matching ref return values.
+
+ Partial member declarations must have matching ref return values.Partial method declarations '{0}' and '{1}' have signature differences.
@@ -7032,7 +7032,7 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ
The 'scoped' modifier of parameter doesn't match target.
- The 'scoped' modifier of parameter '{0}' doesn't match partial method declaration.
+ The 'scoped' modifier of parameter '{0}' doesn't match partial definition.A fixed field must not be a ref field.
@@ -7956,4 +7956,37 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ
foreach statement cannot operate on enumerators of type '{0}' because it is a type parameter that allows ref struct and it is not known at compile time to implement IDisposable.
-
\ No newline at end of file
+
+ Partial property '{0}' must have an implementation part.
+
+
+ Partial property '{0}' must have a definition part.
+
+
+ A partial property may not have multiple defining declarations, and cannot be an auto-property.
+
+
+ A partial property may not have multiple implementing declarations
+
+
+ Property accessor '{0}' must be implemented because it is declared on the definition part
+
+
+ Property accessor '{0}' does not implement any accessor declared on the definition part
+
+
+ Property accessor '{0}' must be '{1}' to match the definition part
+
+
+ Both partial property declarations must have the same type.
+
+
+ Partial property declarations '{0}' and '{1}' have signature differences.
+
+
+ Partial property declarations have signature differences.
+
+
+ Both partial property declarations must be required or neither may be required
+
+
diff --git a/src/Compilers/CSharp/Portable/Compilation/SyntaxTreeSemanticModel.cs b/src/Compilers/CSharp/Portable/Compilation/SyntaxTreeSemanticModel.cs
index 602946b93212e..10b7050bbd0b3 100644
--- a/src/Compilers/CSharp/Portable/Compilation/SyntaxTreeSemanticModel.cs
+++ b/src/Compilers/CSharp/Portable/Compilation/SyntaxTreeSemanticModel.cs
@@ -1799,10 +1799,14 @@ private Symbol GetDeclaredMember(NamespaceOrTypeSymbol container, TextSpan decla
zeroWidthMatch = symbol;
}
- // Handle the case of the implementation of a partial method.
- var partial = symbol.Kind == SymbolKind.Method
- ? ((MethodSymbol)symbol).PartialImplementationPart
- : null;
+ // Handle the case of the implementation of a partial member.
+ Symbol partial = symbol switch
+ {
+ MethodSymbol method => method.PartialImplementationPart,
+ SourcePropertySymbol property => property.PartialImplementationPart,
+ _ => null
+ };
+
if ((object)partial != null)
{
var loc = partial.GetFirstLocation();
@@ -2033,9 +2037,7 @@ private ParameterSymbol GetMethodParameterSymbol(
return null;
}
- return
- GetParameterSymbol(method.Parameters, parameter, cancellationToken) ??
- ((object)method.PartialDefinitionPart == null ? null : GetParameterSymbol(method.PartialDefinitionPart.Parameters, parameter, cancellationToken));
+ return GetParameterSymbol(method.Parameters, parameter, cancellationToken);
}
private ParameterSymbol GetIndexerParameterSymbol(
@@ -2127,11 +2129,8 @@ private ParameterSymbol GetDelegateParameterSymbol(
}
///
- /// Given a type parameter declaration (field or method), get the corresponding symbol
+ /// Given a type parameter declaration (on a type or method), get the corresponding symbol
///
- ///
- /// The cancellation token.
- ///
public override ITypeParameterSymbol GetDeclaredSymbol(TypeParameterSyntax typeParameter, CancellationToken cancellationToken = default(CancellationToken))
{
if (typeParameter == null)
@@ -2165,10 +2164,7 @@ private ParameterSymbol GetDelegateParameterSymbol(
return this.GetTypeParameterSymbol(typeSymbol.TypeParameters, typeParameter).GetPublicSymbol();
case MethodSymbol methodSymbol:
- return (this.GetTypeParameterSymbol(methodSymbol.TypeParameters, typeParameter) ??
- ((object)methodSymbol.PartialDefinitionPart == null
- ? null
- : this.GetTypeParameterSymbol(methodSymbol.PartialDefinitionPart.TypeParameters, typeParameter))).GetPublicSymbol();
+ return this.GetTypeParameterSymbol(methodSymbol.TypeParameters, typeParameter).GetPublicSymbol();
}
}
diff --git a/src/Compilers/CSharp/Portable/Compiler/DocumentationCommentCompiler.cs b/src/Compilers/CSharp/Portable/Compiler/DocumentationCommentCompiler.cs
index 56852488935b3..dcae3e0001579 100644
--- a/src/Compilers/CSharp/Portable/Compiler/DocumentationCommentCompiler.cs
+++ b/src/Compilers/CSharp/Portable/Compiler/DocumentationCommentCompiler.cs
@@ -258,7 +258,14 @@ public override void DefaultVisit(Symbol symbol)
bool shouldSkipPartialDefinitionComments = false;
if (symbol.IsPartialDefinition())
{
- if (symbol is MethodSymbol { PartialImplementationPart: MethodSymbol implementationPart })
+ Symbol? implementationPart = symbol switch
+ {
+ MethodSymbol method => method.PartialImplementationPart,
+ SourcePropertySymbol property => property.PartialImplementationPart,
+ _ => null
+ };
+
+ if (implementationPart is not null)
{
Visit(implementationPart);
diff --git a/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs b/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs
index 4f8a380ef0913..b4ba341c47edb 100644
--- a/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs
+++ b/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs
@@ -529,20 +529,20 @@ internal enum ErrorCode
ERR_InvalidAnonymousTypeMemberDeclarator = 746,
ERR_InvalidInitializerElementInitializer = 747,
ERR_InconsistentLambdaParameterUsage = 748,
- ERR_PartialMethodInvalidModifier = 750,
- ERR_PartialMethodOnlyInPartialClass = 751,
+ ERR_PartialMemberCannotBeAbstract = 750,
+ ERR_PartialMemberOnlyInPartialClass = 751,
// ERR_PartialMethodCannotHaveOutParameters = 752, Removed as part of 'extended partial methods' feature
// ERR_PartialMethodOnlyMethods = 753, Removed as it is subsumed by ERR_PartialMisplaced
- ERR_PartialMethodNotExplicit = 754,
+ ERR_PartialMemberNotExplicit = 754,
ERR_PartialMethodExtensionDifference = 755,
ERR_PartialMethodOnlyOneLatent = 756,
ERR_PartialMethodOnlyOneActual = 757,
- ERR_PartialMethodParamsDifference = 758,
+ ERR_PartialMemberParamsDifference = 758,
ERR_PartialMethodMustHaveLatent = 759,
ERR_PartialMethodInconsistentConstraints = 761,
ERR_PartialMethodToDelegate = 762,
- ERR_PartialMethodStaticDifference = 763,
- ERR_PartialMethodUnsafeDifference = 764,
+ ERR_PartialMemberStaticDifference = 763,
+ ERR_PartialMemberUnsafeDifference = 764,
ERR_PartialMethodInExpressionTree = 765,
// ERR_PartialMethodMustReturnVoid = 766, Removed as part of 'extended partial methods' feature
ERR_ExplicitImplCollisionOnRefOut = 767,
@@ -1392,7 +1392,7 @@ internal enum ErrorCode
ERR_CantChangeTupleNamesOnOverride = 8139,
ERR_DuplicateInterfaceWithTupleNamesInBaseList = 8140,
ERR_ImplBadTupleNames = 8141,
- ERR_PartialMethodInconsistentTupleNames = 8142,
+ ERR_PartialMemberInconsistentTupleNames = 8142,
ERR_ExpressionTreeContainsTupleLiteral = 8143,
ERR_ExpressionTreeContainsTupleConversion = 8144,
#endregion tuple diagnostics introduced in C# 7
@@ -1709,7 +1709,7 @@ internal enum ErrorCode
ERR_InvalidPropertyReadOnlyMods = 8660,
ERR_DuplicatePropertyReadOnlyMods = 8661,
ERR_FieldLikeEventCantBeReadOnly = 8662,
- ERR_PartialMethodReadOnlyDifference = 8663,
+ ERR_PartialMemberReadOnlyDifference = 8663,
ERR_ReadOnlyModMissingAccessor = 8664,
ERR_OverrideRefConstraintNotSatisfied = 8665,
ERR_OverrideValConstraintNotSatisfied = 8666,
@@ -1809,8 +1809,8 @@ internal enum ErrorCode
ERR_PartialMethodWithNonVoidReturnMustHaveAccessMods = 8796,
ERR_PartialMethodWithOutParamMustHaveAccessMods = 8797,
ERR_PartialMethodWithExtendedModMustHaveAccessMods = 8798,
- ERR_PartialMethodAccessibilityDifference = 8799,
- ERR_PartialMethodExtendedModDifference = 8800,
+ ERR_PartialMemberAccessibilityDifference = 8799,
+ ERR_PartialMemberExtendedModDifference = 8800,
ERR_SimpleProgramLocalIsReferencedOutsideOfTopLevelStatement = 8801,
ERR_SimpleProgramMultipleUnitsWithTopLevelStatements = 8802,
@@ -1832,7 +1832,7 @@ internal enum ErrorCode
ERR_ModuleInitializerMethodAndContainingTypesMustNotBeGeneric = 8816,
ERR_PartialMethodReturnTypeDifference = 8817,
- ERR_PartialMethodRefReturnDifference = 8818,
+ ERR_PartialMemberRefReturnDifference = 8818,
WRN_NullabilityMismatchInReturnTypeOnPartial = 8819,
ERR_StaticAnonymousFunctionCannotCaptureVariable = 8820,
@@ -2325,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/ErrorFacts.cs b/src/Compilers/CSharp/Portable/Errors/ErrorFacts.cs
index 03a75fda22f79..e7c10d9f6e241 100644
--- a/src/Compilers/CSharp/Portable/Errors/ErrorFacts.cs
+++ b/src/Compilers/CSharp/Portable/Errors/ErrorFacts.cs
@@ -561,6 +561,7 @@ internal static int GetWarningLevel(ErrorCode code)
case ErrorCode.WRN_DynamicDispatchToParamsCollectionMethod:
case ErrorCode.WRN_DynamicDispatchToParamsCollectionIndexer:
case ErrorCode.WRN_DynamicDispatchToParamsCollectionConstructor:
+ case ErrorCode.WRN_PartialPropertySignatureDifference:
return 1;
default:
@@ -1076,18 +1077,18 @@ or ErrorCode.ERR_ExpectedContextualKeywordBy
or ErrorCode.ERR_InvalidAnonymousTypeMemberDeclarator
or ErrorCode.ERR_InvalidInitializerElementInitializer
or ErrorCode.ERR_InconsistentLambdaParameterUsage
- or ErrorCode.ERR_PartialMethodInvalidModifier
- or ErrorCode.ERR_PartialMethodOnlyInPartialClass
- or ErrorCode.ERR_PartialMethodNotExplicit
+ or ErrorCode.ERR_PartialMemberCannotBeAbstract
+ or ErrorCode.ERR_PartialMemberOnlyInPartialClass
+ or ErrorCode.ERR_PartialMemberNotExplicit
or ErrorCode.ERR_PartialMethodExtensionDifference
or ErrorCode.ERR_PartialMethodOnlyOneLatent
or ErrorCode.ERR_PartialMethodOnlyOneActual
- or ErrorCode.ERR_PartialMethodParamsDifference
+ or ErrorCode.ERR_PartialMemberParamsDifference
or ErrorCode.ERR_PartialMethodMustHaveLatent
or ErrorCode.ERR_PartialMethodInconsistentConstraints
or ErrorCode.ERR_PartialMethodToDelegate
- or ErrorCode.ERR_PartialMethodStaticDifference
- or ErrorCode.ERR_PartialMethodUnsafeDifference
+ or ErrorCode.ERR_PartialMemberStaticDifference
+ or ErrorCode.ERR_PartialMemberUnsafeDifference
or ErrorCode.ERR_PartialMethodInExpressionTree
or ErrorCode.ERR_ExplicitImplCollisionOnRefOut
or ErrorCode.ERR_IndirectRecursiveConstructorCall
@@ -1750,7 +1751,7 @@ or ErrorCode.ERR_ExplicitTupleElementNamesAttribute
or ErrorCode.ERR_CantChangeTupleNamesOnOverride
or ErrorCode.ERR_DuplicateInterfaceWithTupleNamesInBaseList
or ErrorCode.ERR_ImplBadTupleNames
- or ErrorCode.ERR_PartialMethodInconsistentTupleNames
+ or ErrorCode.ERR_PartialMemberInconsistentTupleNames
or ErrorCode.ERR_ExpressionTreeContainsTupleLiteral
or ErrorCode.ERR_ExpressionTreeContainsTupleConversion
or ErrorCode.ERR_AutoPropertyCannotBeRefReturning
@@ -1986,7 +1987,7 @@ or ErrorCode.ERR_AutoPropertyWithSetterCantBeReadOnly
or ErrorCode.ERR_InvalidPropertyReadOnlyMods
or ErrorCode.ERR_DuplicatePropertyReadOnlyMods
or ErrorCode.ERR_FieldLikeEventCantBeReadOnly
- or ErrorCode.ERR_PartialMethodReadOnlyDifference
+ or ErrorCode.ERR_PartialMemberReadOnlyDifference
or ErrorCode.ERR_ReadOnlyModMissingAccessor
or ErrorCode.ERR_OverrideRefConstraintNotSatisfied
or ErrorCode.ERR_OverrideValConstraintNotSatisfied
@@ -2056,8 +2057,8 @@ or ErrorCode.ERR_PartialMethodWithAccessibilityModsMustHaveImplementation
or ErrorCode.ERR_PartialMethodWithNonVoidReturnMustHaveAccessMods
or ErrorCode.ERR_PartialMethodWithOutParamMustHaveAccessMods
or ErrorCode.ERR_PartialMethodWithExtendedModMustHaveAccessMods
- or ErrorCode.ERR_PartialMethodAccessibilityDifference
- or ErrorCode.ERR_PartialMethodExtendedModDifference
+ or ErrorCode.ERR_PartialMemberAccessibilityDifference
+ or ErrorCode.ERR_PartialMemberExtendedModDifference
or ErrorCode.ERR_SimpleProgramLocalIsReferencedOutsideOfTopLevelStatement
or ErrorCode.ERR_SimpleProgramMultipleUnitsWithTopLevelStatements
or ErrorCode.ERR_TopLevelStatementAfterNamespaceOrType
@@ -2075,7 +2076,7 @@ or ErrorCode.ERR_ModuleInitializerMethodMustBeAccessibleOutsideTopLevelType
or ErrorCode.ERR_ModuleInitializerMethodMustBeStaticParameterlessVoid
or ErrorCode.ERR_ModuleInitializerMethodAndContainingTypesMustNotBeGeneric
or ErrorCode.ERR_PartialMethodReturnTypeDifference
- or ErrorCode.ERR_PartialMethodRefReturnDifference
+ or ErrorCode.ERR_PartialMemberRefReturnDifference
or ErrorCode.WRN_NullabilityMismatchInReturnTypeOnPartial
or ErrorCode.ERR_StaticAnonymousFunctionCannotCaptureVariable
or ErrorCode.ERR_StaticAnonymousFunctionCannotCaptureThis
@@ -2450,6 +2451,16 @@ or ErrorCode.ERR_NotRefStructConstraintNotSatisfied
or ErrorCode.ERR_RefStructDoesNotSupportDefaultInterfaceImplementationForMember
or ErrorCode.ERR_BadNonVirtualInterfaceMemberAccessOnAllowsRefLike
or ErrorCode.ERR_BadAllowByRefLikeEnumerator
+ or ErrorCode.ERR_PartialPropertyMissingImplementation
+ or ErrorCode.ERR_PartialPropertyMissingDefinition
+ or ErrorCode.ERR_PartialPropertyDuplicateDefinition
+ or ErrorCode.ERR_PartialPropertyDuplicateImplementation
+ or ErrorCode.ERR_PartialPropertyMissingAccessor
+ or ErrorCode.ERR_PartialPropertyUnexpectedAccessor
+ or ErrorCode.ERR_PartialPropertyInitMismatch
+ or ErrorCode.ERR_PartialPropertyTypeDifference
+ or ErrorCode.WRN_PartialPropertySignatureDifference
+ or ErrorCode.ERR_PartialPropertyRequiredDifference
=> false,
};
#pragma warning restore CS8524 // The switch expression does not handle some values of its input type (it is not exhaustive) involving an unnamed enum value.
diff --git a/src/Compilers/CSharp/Portable/Errors/MessageID.cs b/src/Compilers/CSharp/Portable/Errors/MessageID.cs
index 18fa9dbb51d6e..9c5288962c68b 100644
--- a/src/Compilers/CSharp/Portable/Errors/MessageID.cs
+++ b/src/Compilers/CSharp/Portable/Errors/MessageID.cs
@@ -286,6 +286,8 @@ internal enum MessageID
IDS_FeatureRefUnsafeInIteratorAsync = MessageBase + 12843,
IDS_FeatureRefStructInterfaces = MessageBase + 12844,
+
+ IDS_FeaturePartialProperties = MessageBase + 12845,
}
// Message IDs may refer to strings that need to be localized.
@@ -472,6 +474,7 @@ internal static LanguageVersion RequiredVersion(this MessageID feature)
case MessageID.IDS_FeatureParamsCollections:
case MessageID.IDS_FeatureRefUnsafeInIteratorAsync:
case MessageID.IDS_FeatureRefStructInterfaces:
+ case MessageID.IDS_FeaturePartialProperties:
return LanguageVersion.Preview;
// C# 12.0 features.
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 ac6ebf95db21f..6e81f32c0f79e 100644
--- a/src/Compilers/CSharp/Portable/Generated/ErrorFacts.Generated.cs
+++ b/src/Compilers/CSharp/Portable/Generated/ErrorFacts.Generated.cs
@@ -342,6 +342,7 @@ public static bool IsWarning(ErrorCode code)
case ErrorCode.WRN_DynamicDispatchToParamsCollectionIndexer:
case ErrorCode.WRN_DynamicDispatchToParamsCollectionConstructor:
case ErrorCode.WRN_BadYieldInLock:
+ case ErrorCode.WRN_PartialPropertySignatureDifference:
return true;
default:
return false;
diff --git a/src/Compilers/CSharp/Portable/Symbols/MemberSymbolExtensions.cs b/src/Compilers/CSharp/Portable/Symbols/MemberSymbolExtensions.cs
index 3855f36d82f99..b55fd58855437 100644
--- a/src/Compilers/CSharp/Portable/Symbols/MemberSymbolExtensions.cs
+++ b/src/Compilers/CSharp/Portable/Symbols/MemberSymbolExtensions.cs
@@ -474,7 +474,7 @@ internal static bool ShouldEmit(this MethodSymbol method)
}
// Don't emit partial methods without an implementation part.
- if (method.IsPartialMethod() && method.PartialImplementationPart is null)
+ if (method.IsPartialMember() && method.PartialImplementationPart is null)
{
return false;
}
@@ -545,22 +545,31 @@ internal static bool IsExplicitInterfaceImplementation(this Symbol member)
}
}
- internal static bool IsPartialMethod(this Symbol member)
+ internal static bool IsPartialMember(this Symbol member)
{
- var sms = member as SourceMemberMethodSymbol;
- return sms?.IsPartial == true;
+ Debug.Assert(member.IsDefinition);
+ return member
+ is SourceOrdinaryMethodSymbol { IsPartial: true }
+ or SourcePropertySymbol { IsPartial: true }
+ or SourcePropertyAccessorSymbol { IsPartial: true };
}
internal static bool IsPartialImplementation(this Symbol member)
{
- var sms = member as SourceOrdinaryMethodSymbol;
- return sms?.IsPartialImplementation == true;
+ Debug.Assert(member.IsDefinition);
+ return member
+ is SourceOrdinaryMethodSymbol { IsPartialImplementation: true }
+ or SourcePropertySymbol { IsPartialImplementation: true }
+ or SourcePropertyAccessorSymbol { IsPartialImplementation: true };
}
internal static bool IsPartialDefinition(this Symbol member)
{
- var sms = member as SourceOrdinaryMethodSymbol;
- return sms?.IsPartialDefinition == true;
+ Debug.Assert(member.IsDefinition);
+ return member
+ is SourceOrdinaryMethodSymbol { IsPartialDefinition: true }
+ or SourcePropertySymbol { IsPartialDefinition: true }
+ or SourcePropertyAccessorSymbol { IsPartialDefinition: true };
}
internal static bool ContainsTupleNames(this Symbol member)
diff --git a/src/Compilers/CSharp/Portable/Symbols/PropertySymbolExtensions.cs b/src/Compilers/CSharp/Portable/Symbols/PropertySymbolExtensions.cs
index 2de2705522cc4..5f3f9ce715734 100644
--- a/src/Compilers/CSharp/Portable/Symbols/PropertySymbolExtensions.cs
+++ b/src/Compilers/CSharp/Portable/Symbols/PropertySymbolExtensions.cs
@@ -10,6 +10,11 @@ namespace Microsoft.CodeAnalysis.CSharp.Symbols
{
internal static class PropertySymbolExtensions
{
+ public static bool IsParams(this PropertySymbol property)
+ {
+ return property.ParameterCount != 0 && property.Parameters[property.ParameterCount - 1].IsParams;
+ }
+
///
/// If the property has a GetMethod, return that. Otherwise check the overridden
/// property, if any. Repeat for each overridden property.
diff --git a/src/Compilers/CSharp/Portable/Symbols/PublicModel/MethodSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/PublicModel/MethodSymbol.cs
index e66a1da90da85..c3c9b8c4b1d61 100644
--- a/src/Compilers/CSharp/Portable/Symbols/PublicModel/MethodSymbol.cs
+++ b/src/Compilers/CSharp/Portable/Symbols/PublicModel/MethodSymbol.cs
@@ -298,7 +298,7 @@ IMethodSymbol IMethodSymbol.PartialDefinitionPart
}
}
- bool IMethodSymbol.IsPartialDefinition => _underlying.IsPartialDefinition();
+ bool IMethodSymbol.IsPartialDefinition => _underlying.IsDefinition && _underlying.IsPartialDefinition();
INamedTypeSymbol IMethodSymbol.AssociatedAnonymousDelegate
{
diff --git a/src/Compilers/CSharp/Portable/Symbols/PublicModel/PropertySymbol.cs b/src/Compilers/CSharp/Portable/Symbols/PublicModel/PropertySymbol.cs
index 90182156c74f3..3072bfb1875da 100644
--- a/src/Compilers/CSharp/Portable/Symbols/PublicModel/PropertySymbol.cs
+++ b/src/Compilers/CSharp/Portable/Symbols/PublicModel/PropertySymbol.cs
@@ -109,6 +109,14 @@ ImmutableArray IPropertySymbol.RefCustomModifiers
RefKind IPropertySymbol.RefKind => _underlying.RefKind;
+#nullable enable
+ IPropertySymbol? IPropertySymbol.PartialDefinitionPart => (_underlying as SourcePropertySymbol)?.PartialDefinitionPart.GetPublicSymbol();
+
+ IPropertySymbol? IPropertySymbol.PartialImplementationPart => (_underlying as SourcePropertySymbol)?.PartialImplementationPart.GetPublicSymbol();
+
+ bool IPropertySymbol.IsPartialDefinition => (_underlying as SourcePropertySymbol)?.IsPartialDefinition ?? false;
+#nullable disable
+
#region ISymbol Members
protected override void Accept(SymbolVisitor visitor)
diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/FieldSymbolWithAttributesAndModifiers.cs b/src/Compilers/CSharp/Portable/Symbols/Source/FieldSymbolWithAttributesAndModifiers.cs
index 67d199cf3ff56..bfec737594640 100644
--- a/src/Compilers/CSharp/Portable/Symbols/Source/FieldSymbolWithAttributesAndModifiers.cs
+++ b/src/Compilers/CSharp/Portable/Symbols/Source/FieldSymbolWithAttributesAndModifiers.cs
@@ -26,7 +26,7 @@ internal abstract class FieldSymbolWithAttributesAndModifiers : FieldSymbol, IAt
///
/// Gets the syntax list of custom attributes applied on the symbol.
///
- protected abstract SyntaxList AttributeDeclarationSyntaxList { get; }
+ protected abstract OneOrMany> GetAttributeDeclarations();
protected abstract IAttributeTargetSymbol AttributeOwner { get; }
@@ -86,7 +86,7 @@ private CustomAttributesBag GetAttributesBag()
return bag;
}
- if (LoadAndValidateAttributes(OneOrMany.Create(this.AttributeDeclarationSyntaxList), ref _lazyCustomAttributesBag))
+ if (LoadAndValidateAttributes(this.GetAttributeDeclarations(), ref _lazyCustomAttributesBag))
{
var completed = state.NotePartComplete(CompletionPart.Attributes);
Debug.Assert(completed);
diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/GlobalExpressionVariable.cs b/src/Compilers/CSharp/Portable/Symbols/Source/GlobalExpressionVariable.cs
index 64b9a72c48268..3403885c3079f 100644
--- a/src/Compilers/CSharp/Portable/Symbols/Source/GlobalExpressionVariable.cs
+++ b/src/Compilers/CSharp/Portable/Symbols/Source/GlobalExpressionVariable.cs
@@ -56,7 +56,7 @@ internal static GlobalExpressionVariable Create(
: new GlobalExpressionVariable(containingType, modifiers, typeSyntax, name, syntaxReference, locationSpan);
}
- protected override SyntaxList AttributeDeclarationSyntaxList => default(SyntaxList);
+ protected override OneOrMany> GetAttributeDeclarations() => OneOrMany>.Empty;
protected override TypeSyntax TypeSyntax => (TypeSyntax)_typeSyntaxOpt?.GetSyntax();
protected override SyntaxTokenList ModifiersTokenList => default(SyntaxTokenList);
public override bool HasInitializer => false;
diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceComplexParameterSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceComplexParameterSymbol.cs
index f3a9a363d034d..fad54f4249416 100644
--- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceComplexParameterSymbol.cs
+++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceComplexParameterSymbol.cs
@@ -454,30 +454,57 @@ AttributeLocation IAttributeTargetSymbol.AllowedAttributeLocations
}
}
+#nullable enable
///
/// Symbol to copy bound attributes from, or null if the attributes are not shared among multiple source parameter symbols.
///
///
- /// Used for parameters of partial implementation. We bind the attributes only on the definition
- /// part and copy them over to the implementation.
+ /// This is inconsistent with analogous 'BoundAttributesSource' on other symbols.
+ /// Usually the definition part is the source, but for parameters the implementation part is the source.
+ /// This affects the location of diagnostics among other things.
///
- private SourceParameterSymbol BoundAttributesSource
+ private SourceParameterSymbol? BoundAttributesSource
+ => PartialImplementationPart;
+
+ protected SourceParameterSymbol? PartialImplementationPart
{
get
{
- var sourceMethod = this.ContainingSymbol as SourceOrdinaryMethodSymbol;
- if ((object)sourceMethod == null)
+ ImmutableArray implParameters = this.ContainingSymbol switch
+ {
+ SourceMemberMethodSymbol { PartialImplementationPart.Parameters: { } parameters } => parameters,
+ SourcePropertySymbol { PartialImplementationPart.Parameters: { } parameters } => parameters,
+ _ => default
+ };
+
+ if (implParameters.IsDefault)
{
return null;
}
- var impl = sourceMethod.SourcePartialImplementation;
- if ((object)impl == null)
+ Debug.Assert(!this.ContainingSymbol.IsPartialImplementation());
+ return (SourceParameterSymbol)implParameters[this.Ordinal];
+ }
+ }
+
+ protected SourceParameterSymbol? PartialDefinitionPart
+ {
+ get
+ {
+ ImmutableArray defParameters = this.ContainingSymbol switch
+ {
+ SourceMemberMethodSymbol { PartialDefinitionPart.Parameters: { } parameters } => parameters,
+ SourcePropertySymbol { PartialDefinitionPart.Parameters: { } parameters } => parameters,
+ _ => default
+ };
+
+ if (defParameters.IsDefault)
{
return null;
}
- return (SourceParameterSymbol)impl.Parameters[this.Ordinal];
+ Debug.Assert(!this.ContainingSymbol.IsPartialDefinition());
+ return (SourceParameterSymbol)defParameters[this.Ordinal];
}
}
@@ -495,44 +522,22 @@ internal sealed override SyntaxList AttributeDeclarationLis
///
internal virtual OneOrMany> GetAttributeDeclarations()
{
- // C# spec:
- // The attributes on the parameters of the resulting method declaration
- // are the combined attributes of the corresponding parameters of the defining
- // and the implementing partial method declaration in unspecified order.
- // Duplicates are not removed.
-
- SyntaxList attributes = AttributeDeclarationList;
-
- var sourceMethod = this.ContainingSymbol as SourceOrdinaryMethodSymbol;
- if ((object)sourceMethod == null)
- {
- return OneOrMany.Create(attributes);
- }
+ // Attributes on parameters in partial members are owned by the parameter in the implementation part.
+ // If this symbol has a non-null PartialImplementationPart, we should have accessed this method through that implementation symbol.
+ Debug.Assert(PartialImplementationPart is null);
- SyntaxList otherAttributes;
-
- // if this is a definition get the implementation and vice versa
- SourceOrdinaryMethodSymbol otherPart = sourceMethod.OtherPartOfPartial;
- if ((object)otherPart != null)
+ if (PartialDefinitionPart is { } definitionPart)
{
- otherAttributes = ((SourceParameterSymbol)otherPart.Parameters[this.Ordinal]).AttributeDeclarationList;
+ return OneOrMany.Create(
+ AttributeDeclarationList,
+ definitionPart.AttributeDeclarationList);
}
else
{
- otherAttributes = default(SyntaxList);
- }
-
- if (attributes.Equals(default(SyntaxList)))
- {
- return OneOrMany.Create(otherAttributes);
- }
- else if (otherAttributes.Equals(default(SyntaxList)))
- {
- return OneOrMany.Create(attributes);
+ return OneOrMany.Create(AttributeDeclarationList);
}
-
- return OneOrMany.Create(ImmutableArray.Create(attributes, otherAttributes));
}
+#nullable disable
///
/// Returns data decoded from well-known attributes applied to the symbol or null if there are no applied attributes.
@@ -1030,33 +1035,26 @@ private bool IsValidCallerInfoContext(AttributeSyntax node) => !ContainingSymbol
&& !ContainingSymbol.IsOperator()
&& !IsOnPartialImplementation(node);
+#nullable enable
///
/// Is the attribute syntax appearing on a parameter of a partial method implementation part?
/// Since attributes are merged between the parts of a partial, we need to look at the syntax where the
/// attribute appeared in the source to see if it corresponds to a partial method implementation part.
///
- ///
- ///
private bool IsOnPartialImplementation(AttributeSyntax node)
{
- var method = ContainingSymbol as MethodSymbol;
- if ((object)method == null) return false;
- var impl = method.IsPartialImplementation() ? method : method.PartialImplementationPart;
- if ((object)impl == null) return false;
- var paramList =
- node // AttributeSyntax
- .Parent // AttributeListSyntax
- .Parent // ParameterSyntax
- .Parent as ParameterListSyntax; // ParameterListSyntax
- if (paramList == null) return false;
- var methDecl = paramList.Parent as MethodDeclarationSyntax;
- if (methDecl == null) return false;
- foreach (var r in impl.DeclaringSyntaxReferences)
- {
- if (r.GetSyntax() == methDecl) return true;
- }
- return false;
+ // If we are asking this, the candidate attribute had better be contained in *some* attribute associated with this parameter syntactically
+ Debug.Assert(this.GetAttributeDeclarations().Any(attrLists => attrLists.Any(attrList => attrList.Contains(node))));
+
+ var implParameter = this.ContainingSymbol.IsPartialImplementation() ? this : PartialImplementationPart;
+ if (implParameter?.AttributeDeclarationList is not { } implParameterAttributeList)
+ {
+ return false;
+ }
+
+ return implParameterAttributeList.Any(attrList => attrList.Attributes.Contains(node));
}
+#nullable disable
private void ValidateCallerLineNumberAttribute(AttributeSyntax node, BindingDiagnosticBag diagnostics)
{
diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceEnumConstantSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceEnumConstantSymbol.cs
index 4216680ce2790..a2f5dd94a71f9 100644
--- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceEnumConstantSymbol.cs
+++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceEnumConstantSymbol.cs
@@ -86,17 +86,14 @@ protected sealed override DeclarationModifiers Modifiers
}
}
- protected override SyntaxList AttributeDeclarationSyntaxList
+ protected override OneOrMany> GetAttributeDeclarations()
{
- get
+ if (this.containingType.AnyMemberHasAttributes)
{
- if (this.containingType.AnyMemberHasAttributes)
- {
- return this.SyntaxNode.AttributeLists;
- }
-
- return default(SyntaxList);
+ return OneOrMany.Create(this.SyntaxNode.AttributeLists);
}
+
+ return OneOrMany>.Empty;
}
#nullable enable
diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberContainerSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberContainerSymbol.cs
index 97628686b76fa..40e7f04cc0ebf 100644
--- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberContainerSymbol.cs
+++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberContainerSymbol.cs
@@ -3574,78 +3574,169 @@ private void MergePartialMembers(
memberNames.AddRange(membersByName.Keys);
//key and value will be the same object
- var methodsBySignature = new Dictionary(MemberSignatureComparer.PartialMethodsComparer);
+ var membersBySignature = new Dictionary(MemberSignatureComparer.PartialMethodsComparer);
foreach (var name in memberNames)
{
- methodsBySignature.Clear();
+ membersBySignature.Clear();
foreach (var symbol in membersByName[name])
{
- var method = symbol as SourceMemberMethodSymbol;
- if (method is null || !method.IsPartial)
+ if (!symbol.IsPartialMember())
{
- continue; // only partial methods need to be merged
+ continue;
}
- if (methodsBySignature.TryGetValue(method, out var prev))
+ if (!membersBySignature.TryGetValue(symbol, out var prev))
{
- var prevPart = (SourceOrdinaryMethodSymbol)prev;
- var methodPart = (SourceOrdinaryMethodSymbol)method;
+ membersBySignature.Add(symbol, symbol);
+ continue;
+ }
- if (methodPart.IsPartialImplementation &&
- (prevPart.IsPartialImplementation || (prevPart.OtherPartOfPartial is MethodSymbol otherImplementation && (object)otherImplementation != methodPart)))
- {
- // A partial method may not have multiple implementing declarations
- diagnostics.Add(ErrorCode.ERR_PartialMethodOnlyOneActual, methodPart.GetFirstLocation());
- }
- else if (methodPart.IsPartialDefinition &&
- (prevPart.IsPartialDefinition || (prevPart.OtherPartOfPartial is MethodSymbol otherDefinition && (object)otherDefinition != methodPart)))
- {
- // A partial method may not have multiple defining declarations
- diagnostics.Add(ErrorCode.ERR_PartialMethodOnlyOneLatent, methodPart.GetFirstLocation());
- }
- else
- {
- if ((object)membersByName == _lazyEarlyAttributeDecodingMembersDictionary)
+ switch (symbol, prev)
+ {
+ case (SourceOrdinaryMethodSymbol currentMethod, SourceOrdinaryMethodSymbol prevMethod):
+ mergePartialMethods(ref membersByName, name, currentMethod, prevMethod, diagnostics);
+ break;
+
+ case (SourcePropertySymbol currentProperty, SourcePropertySymbol prevProperty):
+ mergePartialProperties(ref membersByName, name, currentProperty, prevProperty, diagnostics);
+ break;
+
+ case (SourcePropertyAccessorSymbol, SourcePropertyAccessorSymbol):
+ break; // accessor symbols and their diagnostics are handled by processing the associated property
+
+ default:
+ // This is an error scenario. We simply don't merge the symbols in this case and a duplicate name diagnostic is reported separately.
+ // One way this case can be reached is if type contains both `public partial int P { get; }` and `public partial int P_get();`.
+ Debug.Assert(symbol is SourceOrdinaryMethodSymbol or SourcePropertySymbol or SourcePropertyAccessorSymbol);
+ Debug.Assert(prev is SourceOrdinaryMethodSymbol or SourcePropertySymbol or SourcePropertyAccessorSymbol);
+ break;
+ }
+ }
+
+ foreach (var symbol in membersBySignature.Values)
+ {
+ switch (symbol)
+ {
+ case SourceOrdinaryMethodSymbol method:
+ // partial implementations not paired with a definition
+ if (method.IsPartialImplementation && method.OtherPartOfPartial is null)
+ {
+ diagnostics.Add(ErrorCode.ERR_PartialMethodMustHaveLatent, method.GetFirstLocation(), method);
+ }
+ else if (method is { IsPartialDefinition: true, OtherPartOfPartial: null, HasExplicitAccessModifier: true })
{
- // Avoid mutating the cached dictionary and especially avoid doing this possibly on multiple threads in parallel.
- membersByName = new Dictionary, ImmutableArray>(membersByName, ReadOnlyMemoryOfCharComparer.Instance);
+ diagnostics.Add(ErrorCode.ERR_PartialMethodWithAccessibilityModsMustHaveImplementation, method.GetFirstLocation(), method);
}
+ break;
- membersByName[name] = FixPartialMember(membersByName[name], prevPart, methodPart);
- }
+ case SourcePropertySymbol property:
+ if (property.OtherPartOfPartial is null)
+ {
+ diagnostics.Add(
+ property.IsPartialDefinition ? ErrorCode.ERR_PartialPropertyMissingImplementation : ErrorCode.ERR_PartialPropertyMissingDefinition,
+ property.GetFirstLocation(),
+ property);
+ }
+ break;
+
+ case SourcePropertyAccessorSymbol:
+ break; // diagnostics for missing partial accessors are handled in 'mergePartialProperties'.
+
+ default:
+ throw ExceptionUtilities.UnexpectedValue(symbol);
}
- else
+ }
+ }
+
+ memberNames.Free();
+
+ void mergePartialMethods(ref Dictionary, ImmutableArray> membersByName, ReadOnlyMemory name, SourceOrdinaryMethodSymbol currentMethod, SourceOrdinaryMethodSymbol prevMethod, BindingDiagnosticBag diagnostics)
+ {
+ if (currentMethod.IsPartialImplementation &&
+ (prevMethod.IsPartialImplementation || (prevMethod.OtherPartOfPartial is MethodSymbol otherImplementation && (object)otherImplementation != currentMethod)))
+ {
+ // A partial method may not have multiple implementing declarations
+ diagnostics.Add(ErrorCode.ERR_PartialMethodOnlyOneActual, currentMethod.GetFirstLocation());
+ }
+ else if (currentMethod.IsPartialDefinition &&
+ (prevMethod.IsPartialDefinition || (prevMethod.OtherPartOfPartial is MethodSymbol otherDefinition && (object)otherDefinition != currentMethod)))
+ {
+ // A partial method may not have multiple defining declarations
+ diagnostics.Add(ErrorCode.ERR_PartialMethodOnlyOneLatent, currentMethod.GetFirstLocation());
+ }
+ else
+ {
+ if ((object)membersByName == _lazyEarlyAttributeDecodingMembersDictionary)
{
- methodsBySignature.Add(method, method);
+ // Avoid mutating the cached dictionary and especially avoid doing this possibly on multiple threads in parallel.
+ membersByName = new Dictionary, ImmutableArray>(membersByName, ReadOnlyMemoryOfCharComparer.Instance);
}
+
+ membersByName[name] = FixPartialMember(membersByName[name], prevMethod, currentMethod);
}
+ }
- foreach (SourceOrdinaryMethodSymbol method in methodsBySignature.Values)
+ void mergePartialProperties(ref Dictionary, ImmutableArray> membersByName, ReadOnlyMemory name, SourcePropertySymbol currentProperty, SourcePropertySymbol prevProperty, BindingDiagnosticBag diagnostics)
+ {
+ if (currentProperty.IsPartialImplementation &&
+ (prevProperty.IsPartialImplementation || (prevProperty.OtherPartOfPartial is SourcePropertySymbol otherImplementation && (object)otherImplementation != currentProperty)))
+ {
+ diagnostics.Add(ErrorCode.ERR_PartialPropertyDuplicateImplementation, currentProperty.GetFirstLocation());
+ }
+ else if (currentProperty.IsPartialDefinition &&
+ (prevProperty.IsPartialDefinition || (prevProperty.OtherPartOfPartial is SourcePropertySymbol otherDefinition && (object)otherDefinition != currentProperty)))
+ {
+ diagnostics.Add(ErrorCode.ERR_PartialPropertyDuplicateDefinition, currentProperty.GetFirstLocation());
+ }
+ else
{
- // partial implementations not paired with a definition
- if (method.IsPartialImplementation && method.OtherPartOfPartial is null)
+ var (currentGet, prevGet) = ((SourcePropertyAccessorSymbol?)currentProperty.GetMethod, (SourcePropertyAccessorSymbol?)prevProperty.GetMethod);
+ if (currentGet != null || prevGet != null)
{
- diagnostics.Add(ErrorCode.ERR_PartialMethodMustHaveLatent, method.GetFirstLocation(), method);
+ var accessorName = (currentGet ?? prevGet)!.Name.AsMemory();
+ mergeAccessors(ref membersByName, accessorName, currentGet, prevGet);
}
- else if (method is { IsPartialDefinition: true, OtherPartOfPartial: null, HasExplicitAccessModifier: true })
+
+ var (currentSet, prevSet) = ((SourcePropertyAccessorSymbol?)currentProperty.SetMethod, (SourcePropertyAccessorSymbol?)prevProperty.SetMethod);
+ if (currentSet != null || prevSet != null)
+ {
+ var accessorName = (currentSet ?? prevSet)!.Name.AsMemory();
+ mergeAccessors(ref membersByName, accessorName, currentSet, prevSet);
+ }
+
+ if ((object)membersByName == _lazyEarlyAttributeDecodingMembersDictionary)
{
- diagnostics.Add(ErrorCode.ERR_PartialMethodWithAccessibilityModsMustHaveImplementation, method.GetFirstLocation(), method);
+ // Avoid mutating the cached dictionary and especially avoid doing this possibly on multiple threads in parallel.
+ membersByName = new Dictionary, ImmutableArray>(membersByName, ReadOnlyMemoryOfCharComparer.Instance);
}
+
+ membersByName[name] = FixPartialMember(membersByName[name], prevProperty, currentProperty);
}
- }
- memberNames.Free();
+ void mergeAccessors(ref Dictionary, ImmutableArray> membersByName, ReadOnlyMemory name, SourcePropertyAccessorSymbol? currentAccessor, SourcePropertyAccessorSymbol? prevAccessor)
+ {
+ Debug.Assert(currentAccessor != null || prevAccessor != null);
+ if (currentAccessor != null && prevAccessor != null)
+ {
+ var implementationAccessor = currentProperty.IsPartialDefinition ? prevAccessor : currentAccessor;
+ membersByName[name] = Remove(membersByName[name], implementationAccessor);
+ }
+ else
+ {
+ var (foundAccessor, containingProperty, otherProperty) = prevAccessor != null ? (prevAccessor, prevProperty, currentProperty) : (currentAccessor!, currentProperty, prevProperty);
+ // When an accessor is present on definition but not on implementation, the accessor is said to be missing on the implementation.
+ // When an accessor is present on implementation but not on definition, the accessor is said to be unexpected on the implementation.
+ var (errorCode, propertyToBlame) = foundAccessor.IsPartialDefinition
+ ? (ErrorCode.ERR_PartialPropertyMissingAccessor, otherProperty)
+ : (ErrorCode.ERR_PartialPropertyUnexpectedAccessor, containingProperty);
+ diagnostics.Add(errorCode, propertyToBlame.GetFirstLocation(), foundAccessor);
+ }
+ }
+ }
}
- ///
- /// Fix up a partial method by combining its defining and implementing declarations, updating the array of symbols (by name),
- /// and returning the combined symbol.
- ///
- /// The symbols array containing both the latent and implementing declaration
- /// One of the two declarations
- /// The other declaration
- /// An updated symbols array containing only one method symbol representing the two parts
+ /// Links together the definition and implementation parts of a partial method. Returns a member list which has the implementation part removed.
private static ImmutableArray FixPartialMember(ImmutableArray symbols, SourceOrdinaryMethodSymbol part1, SourceOrdinaryMethodSymbol part2)
{
SourceOrdinaryMethodSymbol definition;
@@ -3667,6 +3758,28 @@ private static ImmutableArray FixPartialMember(ImmutableArray sy
return Remove(symbols, implementation);
}
+ /// Links together the definition and implementation parts of a partial property. Returns a member list which has the implementation part removed.
+ private static ImmutableArray FixPartialMember(ImmutableArray symbols, SourcePropertySymbol part1, SourcePropertySymbol part2)
+ {
+ SourcePropertySymbol definition;
+ SourcePropertySymbol implementation;
+ if (part1.IsPartialDefinition)
+ {
+ definition = part1;
+ implementation = part2;
+ }
+ else
+ {
+ definition = part2;
+ implementation = part1;
+ }
+
+ SourcePropertySymbol.InitializePartialPropertyParts(definition, implementation);
+
+ // a partial property is represented in the member list by its definition part:
+ return Remove(symbols, implementation);
+ }
+
private static ImmutableArray Remove(ImmutableArray symbols, Symbol symbol)
{
var builder = ArrayBuilder.GetInstance();
diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberFieldSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberFieldSymbol.cs
index 8f635798af17d..c5366989a30bc 100644
--- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberFieldSymbol.cs
+++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberFieldSymbol.cs
@@ -408,17 +408,14 @@ private static BaseFieldDeclarationSyntax GetFieldDeclaration(CSharpSyntaxNode d
return (BaseFieldDeclarationSyntax)declarator.Parent.Parent;
}
- protected override SyntaxList AttributeDeclarationSyntaxList
+ protected override OneOrMany> GetAttributeDeclarations()
{
- get
+ if (this.containingType.AnyMemberHasAttributes)
{
- if (this.containingType.AnyMemberHasAttributes)
- {
- return GetFieldDeclaration(this.SyntaxNode).AttributeLists;
- }
-
- return default(SyntaxList);
+ return OneOrMany.Create(GetFieldDeclaration(this.SyntaxNode).AttributeLists);
}
+
+ return OneOrMany>.Empty;
}
public sealed override RefKind RefKind => GetTypeAndRefKind(ConsList.Empty).RefKind;
diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceMethodSymbolWithAttributes.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceMethodSymbolWithAttributes.cs
index e5765d5060ace..70a019b8eb217 100644
--- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceMethodSymbolWithAttributes.cs
+++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceMethodSymbolWithAttributes.cs
@@ -1457,7 +1457,7 @@ internal override void PostDecodeWellKnownAttributes(ImmutableArray
- /// Returns the implementation part of a partial method definition,
- /// or null if this is not a partial method or it is the definition part.
- ///
internal SourceOrdinaryMethodSymbol SourcePartialDefinition
{
get
@@ -347,10 +343,6 @@ internal SourceOrdinaryMethodSymbol SourcePartialDefinition
}
}
- ///
- /// Returns the definition part of a partial method implementation,
- /// or null if this is not a partial method or it is the implementation part.
- ///
internal SourceOrdinaryMethodSymbol SourcePartialImplementation
{
get
@@ -401,6 +393,10 @@ protected sealed override SourceMemberMethodSymbol BoundAttributesSource
internal sealed override OneOrMany> GetAttributeDeclarations()
{
+ // Attributes on partial methods 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);
+
if ((object)this.SourcePartialImplementation != null)
{
return OneOrMany.Create(ImmutableArray.Create(AttributeDeclarationSyntaxList, this.SourcePartialImplementation.AttributeDeclarationSyntaxList));
@@ -471,6 +467,10 @@ protected sealed override void PartialMethodChecks(BindingDiagnosticBag diagnost
/// parts of a partial method. Diagnostics are reported on the
/// implementing part, matching Dev10 behavior.
///
+ ///
+ /// This method is analogous to .
+ /// Whenever new checks are added to this method, the other method should also have those checks added, if applicable.
+ ///
private static void PartialMethodChecks(SourceOrdinaryMethodSymbol definition, SourceOrdinaryMethodSymbol implementation, BindingDiagnosticBag diagnostics)
{
Debug.Assert(!ReferenceEquals(definition, implementation));
@@ -484,22 +484,22 @@ private static void PartialMethodChecks(SourceOrdinaryMethodSymbol definition, S
else if (MemberSignatureComparer.ConsideringTupleNamesCreatesDifference(definition, implementation))
{
hasTypeDifferences = true;
- diagnostics.Add(ErrorCode.ERR_PartialMethodInconsistentTupleNames, implementation.GetFirstLocation(), definition, implementation);
+ diagnostics.Add(ErrorCode.ERR_PartialMemberInconsistentTupleNames, implementation.GetFirstLocation(), definition, implementation);
}
if (definition.RefKind != implementation.RefKind)
{
- diagnostics.Add(ErrorCode.ERR_PartialMethodRefReturnDifference, implementation.GetFirstLocation());
+ diagnostics.Add(ErrorCode.ERR_PartialMemberRefReturnDifference, implementation.GetFirstLocation());
}
if (definition.IsStatic != implementation.IsStatic)
{
- diagnostics.Add(ErrorCode.ERR_PartialMethodStaticDifference, implementation.GetFirstLocation());
+ diagnostics.Add(ErrorCode.ERR_PartialMemberStaticDifference, implementation.GetFirstLocation());
}
if (definition.IsDeclaredReadOnly != implementation.IsDeclaredReadOnly)
{
- diagnostics.Add(ErrorCode.ERR_PartialMethodReadOnlyDifference, implementation.GetFirstLocation());
+ diagnostics.Add(ErrorCode.ERR_PartialMemberReadOnlyDifference, implementation.GetFirstLocation());
}
if (definition.IsExtensionMethod != implementation.IsExtensionMethod)
@@ -509,18 +509,18 @@ private static void PartialMethodChecks(SourceOrdinaryMethodSymbol definition, S
if (definition.IsUnsafe != implementation.IsUnsafe && definition.CompilationAllowsUnsafe()) // Don't cascade.
{
- diagnostics.Add(ErrorCode.ERR_PartialMethodUnsafeDifference, implementation.GetFirstLocation());
+ diagnostics.Add(ErrorCode.ERR_PartialMemberUnsafeDifference, implementation.GetFirstLocation());
}
if (definition.IsParams() != implementation.IsParams())
{
- diagnostics.Add(ErrorCode.ERR_PartialMethodParamsDifference, implementation.GetFirstLocation());
+ diagnostics.Add(ErrorCode.ERR_PartialMemberParamsDifference, implementation.GetFirstLocation());
}
if (definition.HasExplicitAccessModifier != implementation.HasExplicitAccessModifier
|| definition.DeclaredAccessibility != implementation.DeclaredAccessibility)
{
- diagnostics.Add(ErrorCode.ERR_PartialMethodAccessibilityDifference, implementation.GetFirstLocation());
+ diagnostics.Add(ErrorCode.ERR_PartialMemberAccessibilityDifference, implementation.GetFirstLocation());
}
if (definition.IsVirtual != implementation.IsVirtual
@@ -528,7 +528,7 @@ private static void PartialMethodChecks(SourceOrdinaryMethodSymbol definition, S
|| definition.IsSealed != implementation.IsSealed
|| definition.IsNew != implementation.IsNew)
{
- diagnostics.Add(ErrorCode.ERR_PartialMethodExtendedModDifference, implementation.GetFirstLocation());
+ diagnostics.Add(ErrorCode.ERR_PartialMemberExtendedModDifference, implementation.GetFirstLocation());
}
PartialMethodConstraintsChecks(definition, implementation, diagnostics);
@@ -806,7 +806,7 @@ private void CheckModifiers(bool isExplicitInterfaceImplementation, Location loc
if (IsPartial && IsAbstract)
{
- diagnostics.Add(ErrorCode.ERR_PartialMethodInvalidModifier, location);
+ diagnostics.Add(ErrorCode.ERR_PartialMemberCannotBeAbstract, location);
}
else if (IsPartial && !HasExplicitAccessModifier && !ReturnsVoid)
{
@@ -1000,11 +1000,14 @@ internal static void InitializePartialMethodParts(SourceOrdinaryMethodSymbolComp
Debug.Assert(definition.IsPartialDefinition);
Debug.Assert(implementation.IsPartialImplementation);
- Debug.Assert(definition._otherPartOfPartial is null || definition._otherPartOfPartial == implementation);
- Debug.Assert(implementation._otherPartOfPartial is null || implementation._otherPartOfPartial == definition);
+ Debug.Assert(definition._otherPartOfPartial is not { } alreadySetImplPart || alreadySetImplPart == implementation);
+ Debug.Assert(implementation._otherPartOfPartial is not { } alreadySetDefPart || alreadySetDefPart == definition);
definition._otherPartOfPartial = implementation;
implementation._otherPartOfPartial = definition;
+
+ Debug.Assert(definition._otherPartOfPartial == implementation);
+ Debug.Assert(implementation._otherPartOfPartial == definition);
}
protected sealed override MethodSymbol FindExplicitlyImplementedMethod(BindingDiagnosticBag diagnostics)
diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceParameterSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceParameterSymbol.cs
index 15f02aa85bb9e..15c514be372ef 100644
--- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceParameterSymbol.cs
+++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceParameterSymbol.cs
@@ -79,7 +79,7 @@ public static SourceParameterSymbol Create(
!isExtensionMethodThis &&
(syntax.Default == null) &&
(syntax.AttributeLists.Count == 0) &&
- !owner.IsPartialMethod() &&
+ !owner.IsPartialMember() &&
scope == ScopedKind.None)
{
return new SourceSimpleParameterSymbol(owner, parameterType, ordinal, refKind, name, location);
diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertyAccessorSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertyAccessorSymbol.cs
index d61cec7b4c355..c625366d197a9 100644
--- a/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertyAccessorSymbol.cs
+++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertyAccessorSymbol.cs
@@ -145,7 +145,18 @@ private SourcePropertyAccessorSymbol(
bool isNullableAnalysisEnabled,
BindingDiagnosticBag diagnostics) :
base(containingType, syntax.GetReference(), location, isIterator: false,
- MakeModifiersAndFlags(property, propertyModifiers, isNullableAnalysisEnabled))
+ MakeModifiersAndFlags(
+ containingType,
+ property,
+ propertyModifiers,
+ location,
+ hasBlockBody: false,
+ hasExpressionBody: true,
+ modifiers: [],
+ methodKind: MethodKind.PropertyGet,
+ isNullableAnalysisEnabled,
+ diagnostics,
+ out var modifierErrors))
{
_property = property;
_isAutoPropertyAccessor = false;
@@ -158,21 +169,6 @@ private SourcePropertyAccessorSymbol(
this.CheckModifiers(location, hasBody: true, isAutoPropertyOrExpressionBodied: true, diagnostics: diagnostics);
}
- private static (DeclarationModifiers, Flags) MakeModifiersAndFlags(SourcePropertySymbol property, DeclarationModifiers propertyModifiers, bool isNullableAnalysisEnabled)
- {
- // The modifiers for the accessor are the same as the modifiers for the property,
- // minus the indexer and readonly bit
- var declarationModifiers = GetAccessorModifiers(propertyModifiers);
-
- // ReturnsVoid property is overridden in this class so
- // returnsVoid argument to MakeFlags is ignored.
- Flags flags = MakeFlags(MethodKind.PropertyGet, property.RefKind, declarationModifiers, returnsVoid: false, returnsVoidIsSet: false,
- isExpressionBodied: true, isExtensionMethod: false, isNullableAnalysisEnabled: isNullableAnalysisEnabled,
- isVarArg: false, isExplicitInterfaceImplementation: property.IsExplicitInterfaceImplementation, hasThisInitializer: false);
-
- return (declarationModifiers, flags);
- }
-
#nullable enable
protected SourcePropertyAccessorSymbol(
NamedTypeSymbol containingType,
@@ -538,7 +534,7 @@ private void CheckModifiers(Location location, bool hasBody, bool isAutoProperty
// '{0}' is a new virtual member in sealed type '{1}'
diagnostics.Add(ErrorCode.ERR_NewVirtualInSealed, location, this, ContainingType);
}
- else if (!hasBody && !IsExtern && !IsAbstract && !isAutoPropertyOrExpressionBodied)
+ else if (!hasBody && !IsExtern && !IsAbstract && !isAutoPropertyOrExpressionBodied && !IsPartial)
{
diagnostics.Add(ErrorCode.ERR_ConcreteMissingBody, location, this);
}
@@ -635,16 +631,38 @@ public sealed override ImmutableArray ExplicitInterfaceImplementat
internal sealed override OneOrMany> GetAttributeDeclarations()
{
- var syntax = this.GetSyntax();
- switch (syntax.Kind())
+ if (PartialImplementationPart is { } implementation)
{
- case SyntaxKind.GetAccessorDeclaration:
- case SyntaxKind.SetAccessorDeclaration:
- case SyntaxKind.InitAccessorDeclaration:
- return OneOrMany.Create(((AccessorDeclarationSyntax)syntax).AttributeLists);
+ return OneOrMany.Create(AttributeDeclarationList, ((SourcePropertyAccessorSymbol)implementation).AttributeDeclarationList);
}
- return base.GetAttributeDeclarations();
+ // If we are asking this question on a partial implementation symbol,
+ // it must be from a context which prefers to order implementation attributes before definition attributes.
+ // For example, the 'value' parameter of a set accessor.
+ if (PartialDefinitionPart is { } definition)
+ {
+ Debug.Assert(MethodKind == MethodKind.PropertySet);
+ return OneOrMany.Create(AttributeDeclarationList, ((SourcePropertyAccessorSymbol)definition).AttributeDeclarationList);
+ }
+
+ return OneOrMany.Create(AttributeDeclarationList);
+ }
+
+ private SyntaxList AttributeDeclarationList
+ {
+ get
+ {
+ var syntax = this.GetSyntax();
+ switch (syntax.Kind())
+ {
+ case SyntaxKind.GetAccessorDeclaration:
+ case SyntaxKind.SetAccessorDeclaration:
+ case SyntaxKind.InitAccessorDeclaration:
+ return ((AccessorDeclarationSyntax)syntax).AttributeLists;
+ }
+
+ return default;
+ }
}
#nullable enable
@@ -807,5 +825,42 @@ internal override void AddSynthesizedAttributes(PEModuleBuilder moduleBuilder, r
}
}
}
+
+#nullable enable
+ protected sealed override SourceMemberMethodSymbol? BoundAttributesSource => (SourceMemberMethodSymbol?)PartialDefinitionPart;
+
+ public sealed override MethodSymbol? PartialImplementationPart => _property is SourcePropertySymbol { IsPartialDefinition: true, OtherPartOfPartial: { } other }
+ ? (MethodKind == MethodKind.PropertyGet ? other.GetMethod : other.SetMethod)
+ : null;
+
+ public sealed override MethodSymbol? PartialDefinitionPart => _property is SourcePropertySymbol { IsPartialImplementation: true, OtherPartOfPartial: { } other }
+ ? (MethodKind == MethodKind.PropertyGet ? other.GetMethod : other.SetMethod)
+ : null;
+
+ internal bool IsPartialDefinition => _property is SourcePropertySymbol { IsPartialDefinition: true };
+ internal bool IsPartialImplementation => _property is SourcePropertySymbol { IsPartialImplementation: true };
+
+ public sealed override bool IsExtern => PartialImplementationPart is { } implementation ? implementation.IsExtern : base.IsExtern;
+
+ internal void PartialAccessorChecks(SourcePropertyAccessorSymbol implementationAccessor, BindingDiagnosticBag diagnostics)
+ {
+ Debug.Assert(IsPartialDefinition);
+
+ if (LocalAccessibility != implementationAccessor.LocalAccessibility)
+ {
+ diagnostics.Add(ErrorCode.ERR_PartialMemberAccessibilityDifference, implementationAccessor.GetFirstLocation());
+ }
+
+ if (LocalDeclaredReadOnly != implementationAccessor.LocalDeclaredReadOnly)
+ {
+ diagnostics.Add(ErrorCode.ERR_PartialMemberReadOnlyDifference, implementationAccessor.GetFirstLocation());
+ }
+
+ if (_usesInit != implementationAccessor._usesInit)
+ {
+ var accessorName = _usesInit ? "init" : "set";
+ diagnostics.Add(ErrorCode.ERR_PartialPropertyInitMismatch, implementationAccessor.GetFirstLocation(), implementationAccessor, accessorName);
+ }
+ }
}
}
diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertySymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertySymbol.cs
index eb6c3ff553bfa..2deeefb254519 100644
--- a/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertySymbol.cs
+++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertySymbol.cs
@@ -2,10 +2,11 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
-using System.Collections.Generic;
+using System;
using System.Collections.Immutable;
using System.Diagnostics;
using System.Linq;
+using System.Threading;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Roslyn.Utilities;
@@ -13,6 +14,8 @@ namespace Microsoft.CodeAnalysis.CSharp.Symbols
{
internal sealed class SourcePropertySymbol : SourcePropertySymbolBase
{
+ private SourcePropertySymbol? _otherPartOfPartial;
+
internal static SourcePropertySymbol Create(SourceMemberContainerTypeSymbol containingType, Binder bodyBinder, PropertyDeclarationSyntax syntax, BindingDiagnosticBag diagnostics)
{
var nameToken = syntax.Identifier;
@@ -37,7 +40,6 @@ private static SourcePropertySymbol Create(
GetAccessorDeclarations(
syntax,
diagnostics,
- out bool isAutoProperty,
out bool hasAccessorList,
out bool accessorsHaveImplementation,
out bool isInitOnly,
@@ -47,7 +49,7 @@ private static SourcePropertySymbol Create(
var explicitInterfaceSpecifier = GetExplicitInterfaceSpecifier(syntax);
SyntaxTokenList modifiersTokenList = GetModifierTokensSyntax(syntax);
bool isExplicitInterfaceImplementation = explicitInterfaceSpecifier is object;
- var modifiers = MakeModifiers(
+ var (modifiers, hasExplicitAccessMod) = MakeModifiers(
containingType,
modifiersTokenList,
isExplicitInterfaceImplementation,
@@ -57,6 +59,7 @@ private static SourcePropertySymbol Create(
diagnostics,
out _);
+ bool isAutoProperty = (modifiers & DeclarationModifiers.Partial) == 0 && !accessorsHaveImplementation;
bool isExpressionBodied = !hasAccessorList && GetArrowExpression(syntax) != null;
binder = binder.SetOrClearUnsafeRegionIfNecessary(modifiersTokenList);
@@ -73,9 +76,11 @@ private static SourcePropertySymbol Create(
explicitInterfaceType,
aliasQualifierOpt,
modifiers,
+ hasExplicitAccessMod: hasExplicitAccessMod,
isAutoProperty: isAutoProperty,
isExpressionBodied: isExpressionBodied,
isInitOnly: isInitOnly,
+ accessorsHaveImplementation: accessorsHaveImplementation,
memberName,
location,
diagnostics);
@@ -90,9 +95,11 @@ private SourcePropertySymbol(
TypeSymbol? explicitInterfaceType,
string? aliasQualifierOpt,
DeclarationModifiers modifiers,
+ bool hasExplicitAccessMod,
bool isAutoProperty,
bool isExpressionBodied,
bool isInitOnly,
+ bool accessorsHaveImplementation,
string memberName,
Location location,
BindingDiagnosticBag diagnostics)
@@ -106,9 +113,11 @@ private SourcePropertySymbol(
aliasQualifierOpt,
modifiers,
hasInitializer: HasInitializer(syntax),
+ hasExplicitAccessMod: hasExplicitAccessMod,
isAutoProperty: isAutoProperty,
isExpressionBodied: isExpressionBodied,
isInitOnly: isInitOnly,
+ accessorsHaveImplementation: accessorsHaveImplementation,
syntax.Type.SkipScoped(out _).GetRefKindInLocalOrReturn(diagnostics),
memberName,
syntax.AttributeLists,
@@ -136,6 +145,12 @@ private SourcePropertySymbol(
MessageID.IDS_FeatureAutoPropertyInitializer.CheckFeatureAvailability(diagnostics, initializer.EqualsToken);
}
+ internal override void ForceComplete(SourceLocation? locationOpt, Predicate? filter, CancellationToken cancellationToken)
+ {
+ PartialImplementationPart?.ForceComplete(locationOpt, filter, cancellationToken);
+ base.ForceComplete(locationOpt, filter, cancellationToken);
+ }
+
private TypeSyntax GetTypeSyntax(SyntaxNode syntax) => ((BasePropertyDeclarationSyntax)syntax).Type;
protected override Location TypeLocation
@@ -155,15 +170,34 @@ private static SyntaxTokenList GetModifierTokensSyntax(SyntaxNode syntax)
private static bool HasInitializer(SyntaxNode syntax)
=> syntax is PropertyDeclarationSyntax { Initializer: { } };
- public override SyntaxList AttributeDeclarationSyntaxList
- => ((BasePropertyDeclarationSyntax)CSharpSyntaxNode).AttributeLists;
+ public override OneOrMany> GetAttributeDeclarations()
+ {
+ // 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
+ // 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)
+ {
+ return OneOrMany.Create(
+ ((BasePropertyDeclarationSyntax)CSharpSyntaxNode).AttributeLists,
+ ((BasePropertyDeclarationSyntax)implementationPart.CSharpSyntaxNode).AttributeLists);
+ }
+ else
+ {
+ return OneOrMany.Create(((BasePropertyDeclarationSyntax)CSharpSyntaxNode).AttributeLists);
+ }
+ }
+
+ protected override SourcePropertySymbolBase? BoundAttributesSource => PartialDefinitionPart;
public override IAttributeTargetSymbol AttributesOwner => this;
private static void GetAccessorDeclarations(
CSharpSyntaxNode syntaxNode,
BindingDiagnosticBag diagnostics,
- out bool isAutoProperty,
out bool hasAccessorList,
out bool accessorsHaveImplementation,
out bool isInitOnly,
@@ -171,7 +205,6 @@ private static void GetAccessorDeclarations(
out CSharpSyntaxNode? setSyntax)
{
var syntax = (BasePropertyDeclarationSyntax)syntaxNode;
- isAutoProperty = true;
hasAccessorList = syntax.AccessorList != null;
getSyntax = null;
setSyntax = null;
@@ -223,15 +256,14 @@ private static void GetAccessorDeclarations(
if (accessor.Body != null || accessor.ExpressionBody != null)
{
- isAutoProperty = false;
accessorsHaveImplementation = true;
}
}
}
else
{
- isAutoProperty = false;
accessorsHaveImplementation = GetArrowExpression(syntax) is object;
+ Debug.Assert(accessorsHaveImplementation); // it's not clear how this even parsed as a property if it has no accessor list and no arrow expression.
}
}
@@ -264,7 +296,7 @@ private static AccessorDeclarationSyntax GetSetAccessorDeclaration(BasePropertyD
throw ExceptionUtilities.Unreachable();
}
- private static DeclarationModifiers MakeModifiers(
+ private static (DeclarationModifiers modifiers, bool hasExplicitAccessMod) MakeModifiers(
NamedTypeSymbol containingType,
SyntaxTokenList modifiers,
bool isExplicitInterfaceImplementation,
@@ -278,7 +310,7 @@ private static DeclarationModifiers MakeModifiers(
var defaultAccess = isInterface && !isExplicitInterfaceImplementation ? DeclarationModifiers.Public : DeclarationModifiers.Private;
// Check that the set of modifiers is allowed
- var allowedModifiers = DeclarationModifiers.Unsafe;
+ var allowedModifiers = DeclarationModifiers.Partial | DeclarationModifiers.Unsafe;
var defaultInterfaceImplementationModifiers = DeclarationModifiers.None;
if (!isExplicitInterfaceImplementation)
@@ -339,8 +371,32 @@ private static DeclarationModifiers MakeModifiers(
allowedModifiers |= DeclarationModifiers.Extern;
+ // In order to detect whether explicit accessibility mods were provided, we pass the default value
+ // for 'defaultAccess' and manually add in the 'defaultAccess' flags after the call.
+ bool hasExplicitAccessMod;
var mods = ModifierUtils.MakeAndCheckNonTypeMemberModifiers(isOrdinaryMethod: false, isForInterfaceMember: isInterface,
- modifiers, defaultAccess, allowedModifiers, location, diagnostics, out modifierErrors);
+ modifiers, defaultAccess: DeclarationModifiers.None, allowedModifiers, location, diagnostics, out modifierErrors);
+ if ((mods & DeclarationModifiers.AccessibilityMask) == 0)
+ {
+ hasExplicitAccessMod = false;
+ mods |= defaultAccess;
+ }
+ else
+ {
+ hasExplicitAccessMod = true;
+ }
+
+ if ((mods & DeclarationModifiers.Partial) != 0)
+ {
+ Debug.Assert(location.SourceTree is not null);
+
+ LanguageVersion availableVersion = ((CSharpParseOptions)location.SourceTree.Options).LanguageVersion;
+ LanguageVersion requiredVersion = MessageID.IDS_FeaturePartialProperties.RequiredVersion();
+ if (availableVersion < requiredVersion)
+ {
+ ModifierUtils.ReportUnsupportedModifiersForLanguageVersion(mods, DeclarationModifiers.Partial, location, diagnostics, availableVersion, requiredVersion);
+ }
+ }
ModifierUtils.CheckFeatureAvailabilityForStaticAbstractMembersInInterfacesIfNeeded(mods, isExplicitInterfaceImplementation, location, diagnostics);
@@ -369,7 +425,7 @@ private static DeclarationModifiers MakeModifiers(
mods &= ~DeclarationModifiers.Required;
}
- return mods;
+ return (mods, hasExplicitAccessMod);
}
protected override SourcePropertyAccessorSymbol CreateGetAccessorSymbol(bool isAutoPropertyAccessor, BindingDiagnosticBag diagnostics)
@@ -552,9 +608,142 @@ internal override void AfterAddingTypeMembersChecks(ConversionsBase conversions,
}
diagnostics.Add(Location, useSiteInfo);
+
+ if (IsPartialDefinition && OtherPartOfPartial is { } implementation)
+ {
+ PartialPropertyChecks(implementation, diagnostics);
+ implementation.CheckInitializerIfNeeded(diagnostics);
+ }
+ }
+
+ ///
+ /// This method is analogous to .
+ /// Whenever new checks are added to this method, the other method should also have those checks added, if applicable.
+ ///
+ private void PartialPropertyChecks(SourcePropertySymbol implementation, BindingDiagnosticBag diagnostics)
+ {
+ Debug.Assert(this.IsPartialDefinition);
+ Debug.Assert((object)this != implementation);
+ Debug.Assert((object?)this.OtherPartOfPartial == implementation);
+
+ // The purpose of this flag is to avoid cascading a type difference error with an additional redundant warning.
+ bool hasTypeDifferences = !TypeWithAnnotations.Equals(implementation.TypeWithAnnotations, TypeCompareKind.AllIgnoreOptions);
+
+ if (hasTypeDifferences)
+ {
+ diagnostics.Add(ErrorCode.ERR_PartialPropertyTypeDifference, implementation.GetFirstLocation());
+ }
+ else if (MemberSignatureComparer.ConsideringTupleNamesCreatesDifference(this, implementation))
+ {
+ hasTypeDifferences = true;
+ diagnostics.Add(ErrorCode.ERR_PartialMemberInconsistentTupleNames, implementation.GetFirstLocation(), this, implementation);
+ }
+
+ if (RefKind != implementation.RefKind)
+ {
+ hasTypeDifferences = true;
+ diagnostics.Add(ErrorCode.ERR_PartialMemberRefReturnDifference, implementation.GetFirstLocation());
+ }
+
+ if ((!hasTypeDifferences && !MemberSignatureComparer.PartialMethodsStrictComparer.Equals(this, implementation))
+ || !Parameters.SequenceEqual(implementation.Parameters, (a, b) => a.Name == b.Name))
+ {
+ diagnostics.Add(ErrorCode.WRN_PartialPropertySignatureDifference, implementation.GetFirstLocation(),
+ new FormattedSymbol(this, SymbolDisplayFormat.MinimallyQualifiedFormat),
+ new FormattedSymbol(implementation, SymbolDisplayFormat.MinimallyQualifiedFormat));
+ }
+
+ if (IsRequired != implementation.IsRequired)
+ {
+ diagnostics.Add(ErrorCode.ERR_PartialPropertyRequiredDifference, implementation.GetFirstLocation());
+ }
+
+ if (IsStatic != implementation.IsStatic)
+ {
+ diagnostics.Add(ErrorCode.ERR_PartialMemberStaticDifference, implementation.GetFirstLocation());
+ }
+
+ if (HasReadOnlyModifier != implementation.HasReadOnlyModifier)
+ {
+ diagnostics.Add(ErrorCode.ERR_PartialMemberReadOnlyDifference, implementation.GetFirstLocation());
+ }
+
+ if ((_modifiers & DeclarationModifiers.Unsafe) != (implementation._modifiers & DeclarationModifiers.Unsafe) && this.CompilationAllowsUnsafe()) // Don't cascade.
+ {
+ diagnostics.Add(ErrorCode.ERR_PartialMemberUnsafeDifference, implementation.GetFirstLocation());
+ }
+
+ if (this.IsParams() != implementation.IsParams())
+ {
+ diagnostics.Add(ErrorCode.ERR_PartialMemberParamsDifference, implementation.GetFirstLocation());
+ }
+
+ if (DeclaredAccessibility != implementation.DeclaredAccessibility
+ || HasExplicitAccessModifier != implementation.HasExplicitAccessModifier)
+ {
+ diagnostics.Add(ErrorCode.ERR_PartialMemberAccessibilityDifference, implementation.GetFirstLocation());
+ }
+
+ if (IsVirtual != implementation.IsVirtual
+ || IsOverride != implementation.IsOverride
+ || IsSealed != implementation.IsSealed
+ || IsNew != implementation.IsNew)
+ {
+ diagnostics.Add(ErrorCode.ERR_PartialMemberExtendedModDifference, implementation.GetFirstLocation());
+ }
+
+ Debug.Assert(this.ParameterCount == implementation.ParameterCount);
+ for (var i = 0; i < this.ParameterCount; i++)
+ {
+ // An error is only reported for a modifier difference here, regardless of whether the difference is safe or not.
+ // Presence of UnscopedRefAttribute is also not considered when checking partial signatures, because when the attribute is used, it will affect both parts the same way.
+ var definitionParameter = (SourceParameterSymbol)this.Parameters[i];
+ var implementationParameter = (SourceParameterSymbol)implementation.Parameters[i];
+ if (definitionParameter.DeclaredScope != implementationParameter.DeclaredScope)
+ {
+ diagnostics.Add(ErrorCode.ERR_ScopedMismatchInParameterOfPartial, implementation.GetFirstLocation(), new FormattedSymbol(implementation.Parameters[i], SymbolDisplayFormat.ShortFormat));
+ }
+ }
+
+ if (this.GetMethod is { } definitionGetAccessor && implementation.GetMethod is { } implementationGetAccessor)
+ {
+ ((SourcePropertyAccessorSymbol)definitionGetAccessor).PartialAccessorChecks((SourcePropertyAccessorSymbol)implementationGetAccessor, diagnostics);
+ }
+
+ if (this.SetMethod is { } definitionSetAccessor && implementation.SetMethod is { } implementationSetAccessor)
+ {
+ ((SourcePropertyAccessorSymbol)definitionSetAccessor).PartialAccessorChecks((SourcePropertyAccessorSymbol)implementationSetAccessor, diagnostics);
+ }
}
private static BaseParameterListSyntax? GetParameterListSyntax(CSharpSyntaxNode syntax)
=> (syntax as IndexerDeclarationSyntax)?.ParameterList;
+
+ public sealed override bool IsExtern => PartialImplementationPart is { } implementation ? implementation.IsExtern : HasExternModifier;
+
+ internal SourcePropertySymbol? OtherPartOfPartial => _otherPartOfPartial;
+
+ internal bool IsPartialDefinition => IsPartial && !AccessorsHaveImplementation && !HasExternModifier;
+
+ internal bool IsPartialImplementation => IsPartial && (AccessorsHaveImplementation || HasExternModifier);
+
+ internal SourcePropertySymbol? PartialDefinitionPart => IsPartialImplementation ? OtherPartOfPartial : null;
+
+ internal SourcePropertySymbol? PartialImplementationPart => IsPartialDefinition ? OtherPartOfPartial : null;
+
+ internal static void InitializePartialPropertyParts(SourcePropertySymbol definition, SourcePropertySymbol implementation)
+ {
+ Debug.Assert(definition.IsPartialDefinition);
+ Debug.Assert(implementation.IsPartialImplementation);
+
+ Debug.Assert(definition._otherPartOfPartial is not { } alreadySetImplPart || alreadySetImplPart == implementation);
+ Debug.Assert(implementation._otherPartOfPartial is not { } alreadySetDefPart || alreadySetDefPart == definition);
+
+ definition._otherPartOfPartial = implementation;
+ implementation._otherPartOfPartial = definition;
+
+ Debug.Assert(definition._otherPartOfPartial == implementation);
+ Debug.Assert(implementation._otherPartOfPartial == definition);
+ }
}
}
diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertySymbolBase.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertySymbolBase.cs
index 78c9c04f76aae..d4fbc4a85099d 100644
--- a/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertySymbolBase.cs
+++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertySymbolBase.cs
@@ -5,6 +5,7 @@
#nullable disable
using System;
+using System.Collections.Generic;
using System.Collections.Immutable;
using System.Diagnostics;
using System.Globalization;
@@ -12,6 +13,7 @@
using System.Runtime.CompilerServices;
using System.Threading;
using Microsoft.CodeAnalysis.CSharp.Emit;
+using Microsoft.CodeAnalysis.CSharp.Symbols;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.PooledObjects;
using Roslyn.Utilities;
@@ -33,6 +35,8 @@ private enum Flags : byte
IsAutoProperty = 1 << 1,
IsExplicitInterfaceImplementation = 1 << 2,
HasInitializer = 1 << 3,
+ AccessorsHaveImplementation = 1 << 4,
+ HasExplicitAccessModifier = 1 << 5,
}
// TODO (tomat): consider splitting into multiple subclasses/rare data.
@@ -78,9 +82,11 @@ protected SourcePropertySymbolBase(
string? aliasQualifierOpt,
DeclarationModifiers modifiers,
bool hasInitializer,
+ bool hasExplicitAccessMod,
bool isAutoProperty,
bool isExpressionBodied,
bool isInitOnly,
+ bool accessorsHaveImplementation,
RefKind refKind,
string memberName,
SyntaxList indexerNameAttributeLists,
@@ -89,6 +95,7 @@ protected SourcePropertySymbolBase(
{
Debug.Assert(!isExpressionBodied || !isAutoProperty);
Debug.Assert(!isExpressionBodied || !hasInitializer);
+ Debug.Assert(!isExpressionBodied || accessorsHaveImplementation);
Debug.Assert((modifiers & DeclarationModifiers.Required) == 0 || this is SourcePropertySymbol);
_syntaxRef = syntax.GetReference();
@@ -110,6 +117,11 @@ protected SourcePropertySymbolBase(
bool isIndexer = IsIndexer;
isAutoProperty = isAutoProperty && !(containingType.IsInterface && !IsStatic) && !IsAbstract && !IsExtern && !isIndexer;
+ if (hasExplicitAccessMod)
+ {
+ _propertyFlags |= Flags.HasExplicitAccessModifier;
+ }
+
if (isAutoProperty)
{
_propertyFlags |= Flags.IsAutoProperty;
@@ -125,6 +137,11 @@ protected SourcePropertySymbolBase(
_propertyFlags |= Flags.IsExpressionBodied;
}
+ if (accessorsHaveImplementation)
+ {
+ _propertyFlags |= Flags.AccessorsHaveImplementation;
+ }
+
if (isIndexer)
{
if (indexerNameAttributeLists.Count == 0 || isExplicitInterfaceImplementation)
@@ -262,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)
+ {
+ return;
+ }
+
+ if (ContainingType.IsInterface && !IsStatic)
{
- diagnostics.Add(ErrorCode.ERR_InstancePropertyInitializerInInterface, location);
+ diagnostics.Add(ErrorCode.ERR_InstancePropertyInitializerInInterface, Location);
}
- else if (!isAutoProperty)
+ else if (!IsAutoProperty)
{
- diagnostics.Add(ErrorCode.ERR_InitializerOnNonAutoProperty, location);
+ diagnostics.Add(ErrorCode.ERR_InitializerOnNonAutoProperty, Location);
}
}
@@ -469,19 +486,25 @@ public override bool IsAbstract
get { return (_modifiers & DeclarationModifiers.Abstract) != 0; }
}
- public override bool IsExtern
+ protected bool HasExternModifier
{
- get { return (_modifiers & DeclarationModifiers.Extern) != 0; }
+ get
+ {
+ return (_modifiers & DeclarationModifiers.Extern) != 0;
+ }
}
- public override bool IsStatic
+ public override bool IsExtern
{
- get { return (_modifiers & DeclarationModifiers.Static) != 0; }
+ get
+ {
+ return HasExternModifier;
+ }
}
- internal bool IsFixed
+ public override bool IsStatic
{
- get { return false; }
+ get { return (_modifiers & DeclarationModifiers.Static) != 0; }
}
///
@@ -618,9 +641,15 @@ public bool HasSkipLocalsInitAttribute
internal bool IsAutoPropertyWithGetAccessor
=> IsAutoProperty && _getMethod is object;
+ protected bool HasExplicitAccessModifier
+ => (_propertyFlags & Flags.HasExplicitAccessModifier) != 0;
+
protected bool IsAutoProperty
=> (_propertyFlags & Flags.IsAutoProperty) != 0;
+ protected bool AccessorsHaveImplementation
+ => (_propertyFlags & Flags.AccessorsHaveImplementation) != 0;
+
///
/// Backing field for automatically implemented property, or
/// for a property with an initializer.
@@ -663,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)
{
@@ -870,6 +895,18 @@ private void CheckModifiers(bool isExplicitInterfaceImplementation, Location loc
// '{0}' cannot be sealed because it is not an override
diagnostics.Add(ErrorCode.ERR_SealedNonOverride, location, this);
}
+ else if (IsPartial && !ContainingType.IsPartial())
+ {
+ diagnostics.Add(ErrorCode.ERR_PartialMemberOnlyInPartialClass, location);
+ }
+ else if (IsPartial && isExplicitInterfaceImplementation)
+ {
+ diagnostics.Add(ErrorCode.ERR_PartialMemberNotExplicit, location);
+ }
+ else if (IsPartial && IsAbstract)
+ {
+ diagnostics.Add(ErrorCode.ERR_PartialMemberCannotBeAbstract, location);
+ }
else if (IsAbstract && ContainingType.TypeKind == TypeKind.Struct)
{
// The modifier '{0}' is not valid for this item
@@ -1030,7 +1067,13 @@ private SynthesizedSealedPropertyAccessor MakeSynthesizedSealedAccessor()
#region Attributes
- public abstract SyntaxList AttributeDeclarationSyntaxList { get; }
+ public abstract OneOrMany> GetAttributeDeclarations();
+
+ ///
+ /// Symbol to copy bound attributes from, or null if the attributes are not shared among multiple source property symbols.
+ /// Analogous to .
+ ///
+ protected abstract SourcePropertySymbolBase BoundAttributesSource { get; }
public abstract IAttributeTargetSymbol AttributesOwner { get; }
@@ -1057,10 +1100,32 @@ private CustomAttributesBag GetAttributesBag()
return bag;
}
+ var copyFrom = this.BoundAttributesSource;
+
+ // 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();
- if (LoadAndValidateAttributes(OneOrMany.Create(AttributeDeclarationSyntaxList), ref _lazyCustomAttributesBag))
+ 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(!IsAutoProperty);
+
+ var attributesBag = copyFrom.GetAttributesBag();
+ bagCreatedOnThisThread = Interlocked.CompareExchange(ref _lazyCustomAttributesBag, attributesBag, null) == null;
+ }
+ else
+ {
+ bagCreatedOnThisThread = LoadAndValidateAttributes(GetAttributeDeclarations(), ref _lazyCustomAttributesBag);
+ }
+
+ if (bagCreatedOnThisThread)
{
var completed = _state.NotePartComplete(CompletionPart.Attributes);
Debug.Assert(completed);
@@ -1437,6 +1502,8 @@ internal sealed override bool RequiresCompletion
get { return true; }
}
+ internal bool IsPartial => (_modifiers & DeclarationModifiers.Partial) != 0;
+
internal sealed override bool HasComplete(CompletionPart part)
{
return _state.HasComplete(part);
diff --git a/src/Compilers/CSharp/Portable/Symbols/Synthesized/Records/SynthesizedPrimaryConstructorParameterBackingFieldSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Synthesized/Records/SynthesizedPrimaryConstructorParameterBackingFieldSymbol.cs
index 6552a867d6ae9..5f3d127451425 100644
--- a/src/Compilers/CSharp/Portable/Symbols/Synthesized/Records/SynthesizedPrimaryConstructorParameterBackingFieldSymbol.cs
+++ b/src/Compilers/CSharp/Portable/Symbols/Synthesized/Records/SynthesizedPrimaryConstructorParameterBackingFieldSymbol.cs
@@ -33,8 +33,8 @@ protected override IAttributeTargetSymbol AttributeOwner
internal override Location ErrorLocation
=> ParameterSymbol.TryGetFirstLocation() ?? NoLocation.Singleton;
- protected override SyntaxList AttributeDeclarationSyntaxList
- => default;
+ protected override OneOrMany> GetAttributeDeclarations()
+ => OneOrMany>.Empty;
public override Symbol? AssociatedSymbol
=> null;
diff --git a/src/Compilers/CSharp/Portable/Symbols/Synthesized/Records/SynthesizedRecordEqualityContractProperty.cs b/src/Compilers/CSharp/Portable/Symbols/Synthesized/Records/SynthesizedRecordEqualityContractProperty.cs
index c64029e821ca8..1dc7444d03efb 100644
--- a/src/Compilers/CSharp/Portable/Symbols/Synthesized/Records/SynthesizedRecordEqualityContractProperty.cs
+++ b/src/Compilers/CSharp/Portable/Symbols/Synthesized/Records/SynthesizedRecordEqualityContractProperty.cs
@@ -31,9 +31,11 @@ public SynthesizedRecordEqualityContractProperty(SourceMemberContainerTypeSymbol
(_, false) => DeclarationModifiers.Protected | DeclarationModifiers.Override
},
hasInitializer: false,
+ hasExplicitAccessMod: false,
isAutoProperty: false,
isExpressionBodied: false,
isInitOnly: false,
+ accessorsHaveImplementation: true,
RefKind.None,
PropertyName,
indexerNameAttributeLists: new SyntaxList(),
@@ -47,8 +49,10 @@ public SynthesizedRecordEqualityContractProperty(SourceMemberContainerTypeSymbol
public override ImmutableArray DeclaringSyntaxReferences => ImmutableArray.Empty;
- public override SyntaxList AttributeDeclarationSyntaxList
- => new SyntaxList();
+ public override OneOrMany> GetAttributeDeclarations()
+ => OneOrMany>.Empty;
+
+ protected override SourcePropertySymbolBase? BoundAttributesSource => null;
public override IAttributeTargetSymbol AttributesOwner => this;
diff --git a/src/Compilers/CSharp/Portable/Symbols/Synthesized/Records/SynthesizedRecordPropertySymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Synthesized/Records/SynthesizedRecordPropertySymbol.cs
index b3b268b23fe80..2d905f6daf0f8 100644
--- a/src/Compilers/CSharp/Portable/Symbols/Synthesized/Records/SynthesizedRecordPropertySymbol.cs
+++ b/src/Compilers/CSharp/Portable/Symbols/Synthesized/Records/SynthesizedRecordPropertySymbol.cs
@@ -5,6 +5,7 @@
using System.Collections.Immutable;
using System.Diagnostics;
using Microsoft.CodeAnalysis.CSharp.Syntax;
+using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.CSharp.Symbols
{
@@ -28,9 +29,11 @@ public SynthesizedRecordPropertySymbol(
aliasQualifierOpt: null,
modifiers: DeclarationModifiers.Public | (isOverride ? DeclarationModifiers.Override : DeclarationModifiers.None),
hasInitializer: true, // Synthesized record properties always have a synthesized initializer
+ hasExplicitAccessMod: false,
isAutoProperty: true,
isExpressionBodied: false,
isInitOnly: ShouldUseInit(containingType),
+ accessorsHaveImplementation: true,
RefKind.None,
backingParameter.Name,
indexerNameAttributeLists: new SyntaxList(),
@@ -40,13 +43,15 @@ public SynthesizedRecordPropertySymbol(
BackingParameter = (SourceParameterSymbol)backingParameter;
}
+ protected override SourcePropertySymbolBase? BoundAttributesSource => null;
+
public override IAttributeTargetSymbol AttributesOwner => BackingParameter as IAttributeTargetSymbol ?? this;
protected override Location TypeLocation
=> ((ParameterSyntax)CSharpSyntaxNode).Type!.Location;
- public override SyntaxList AttributeDeclarationSyntaxList
- => BackingParameter.AttributeDeclarationList;
+ public override OneOrMany> GetAttributeDeclarations()
+ => OneOrMany.Create(BackingParameter.AttributeDeclarationList);
protected override SourcePropertyAccessorSymbol CreateGetAccessorSymbol(bool isAutoPropertyAccessor, BindingDiagnosticBag diagnostics)
{
diff --git a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedBackingFieldSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedBackingFieldSymbol.cs
index cf1ddb35d1427..323447d1aa226 100644
--- a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedBackingFieldSymbol.cs
+++ b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedBackingFieldSymbol.cs
@@ -100,8 +100,8 @@ protected override IAttributeTargetSymbol AttributeOwner
internal override Location ErrorLocation
=> _property.Location;
- protected override SyntaxList AttributeDeclarationSyntaxList
- => _property.AttributeDeclarationSyntaxList;
+ protected override OneOrMany> GetAttributeDeclarations()
+ => _property.GetAttributeDeclarations();
public override Symbol AssociatedSymbol
=> _property;
@@ -163,15 +163,18 @@ private void CheckForFieldTargetedAttribute(BindingDiagnosticBag diagnostics)
return;
}
- foreach (var attribute in AttributeDeclarationSyntaxList)
+ foreach (var attributeList in GetAttributeDeclarations())
{
- if (attribute.Target?.GetAttributeLocation() == AttributeLocation.Field)
+ foreach (var attribute in attributeList)
{
- diagnostics.Add(
- new CSDiagnosticInfo(ErrorCode.WRN_AttributesOnBackingFieldsNotAvailable,
- languageVersion.ToDisplayString(),
- new CSharpRequiredLanguageVersion(MessageID.IDS_FeatureAttributesOnBackingFields.RequiredVersion())),
- attribute.Target.Location);
+ if (attribute.Target?.GetAttributeLocation() == AttributeLocation.Field)
+ {
+ diagnostics.Add(
+ new CSDiagnosticInfo(ErrorCode.WRN_AttributesOnBackingFieldsNotAvailable,
+ languageVersion.ToDisplayString(),
+ new CSharpRequiredLanguageVersion(MessageID.IDS_FeatureAttributesOnBackingFields.RequiredVersion())),
+ attribute.Target.Location);
+ }
}
}
}
diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf
index 482f74b8c1b7e..358a573db20a3 100644
--- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf
+++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf
@@ -1642,26 +1642,51 @@
Parametr params musí mít platný typ kolekce.
-
-
- Obě deklarace částečných metod musí mít shodné modifikátory přístupnosti.
+
+
+ Both partial member declarations must have identical accessibility modifiers.
-
-
- Obě deklarace částečných metod musí mít shodné kombinace modifikátorů virtual, override, sealed a new.
+
+
+ A partial member cannot have the 'abstract' modifier
+
+
+
+
+ Both partial member declarations, '{0}' and '{1}', must use the same tuple element names.
-
-
- Obě deklarace částečné metody musí mít modifikátor readonly, nebo nesmí mít modifikátor readonly žádná z nich.
+
+
+ A partial member must be declared within a partial type
-
-
+
+
+ Both partial member declarations must use a params parameter or neither may use a params parameter
+
+
+
+
+ Both partial member declarations must be readonly or neither may be readonly
+
+
+
+
+ Obě deklarace částečných metod musí mít shodné kombinace modifikátorů virtual, override, sealed a new.
+
+
+
+
Deklarace částečných metod musí mít odpovídající referenční návratové hodnoty.
+
+
+ Both partial member declarations must be unsafe or neither may be unsafe
+
+ Obě deklarace částečných metod musí mít stejný návratový typ.
@@ -1687,6 +1712,51 @@
Částečná metoda {0} musí mít modifikátory přístupnosti, protože má parametry out.
+
+
+ A partial property may not have multiple defining declarations, and cannot be an auto-property.
+
+
+
+
+ A partial property may not have multiple implementing declarations
+
+
+
+
+ Property accessor '{0}' must be '{1}' to match the definition part
+
+
+
+
+ Property accessor '{0}' must be implemented because it is declared on the definition part
+
+
+
+
+ Partial property '{0}' must have a definition part.
+
+
+
+
+ Partial property '{0}' must have an implementation part.
+
+
+
+
+ Both partial property declarations must be required or neither may be required
+
+
+
+
+ Both partial property declarations must have the same type.
+
+
+
+
+ Property accessor '{0}' does not implement any accessor declared on the definition part
+
+ Konstanta řetězce null není podporována jako vzor pro {0}. Místo toho použijte prázdný řetězec.
@@ -1953,8 +2023,8 @@
-
- Modifikátor scoped parametru {0} neodpovídá částečné deklaraci metody.
+
+ Modifikátor scoped parametru {0} neodpovídá částečné deklaraci metody.
@@ -3047,6 +3117,16 @@
Parametr má modifikátor params ve výrazu lambda, ale ne v cílovém typu delegáta.
+
+
+ Partial property declarations '{0}' and '{1}' have signature differences.
+
+
+
+
+ Partial property declarations have signature differences.
+
+ Parametr primárního konstruktoru {0} je stínován členem z báze.
@@ -4765,12 +4845,12 @@
- Typ odkazu s možnou hodnotou null v typu parametru {0} neodpovídá deklaraci částečné metody.
+ Typ odkazu s možnou hodnotou null v typu parametru {0} neodpovídá deklaraci částečné metody.
- Typ odkazu s možnou hodnotou null v typu parametru neodpovídá deklaraci částečné metody.
+ Typ odkazu s možnou hodnotou null v typu parametru neodpovídá deklaraci částečné metody.
@@ -4815,12 +4895,12 @@
- Typ odkazu s možnou hodnotou null v návratovém typu neodpovídá deklaraci částečné metody.
+ Typ odkazu s možnou hodnotou null v návratovém typu neodpovídá deklaraci částečné metody.
- Typ odkazu s možnou hodnotou null v návratovém typu neodpovídá deklaraci částečné metody
+ Typ odkazu s možnou hodnotou null v návratovém typu neodpovídá deklaraci částečné metody
@@ -6524,8 +6604,8 @@
-
- Modifikátor partial se může objevit jen bezprostředně před klíčovými slovy class, record, struct, interface nebo návratovým typem metody.
+
+ Modifikátor partial se může objevit jen bezprostředně před klíčovými slovy class, record, struct, interface nebo návratovým typem metody.
@@ -8132,18 +8212,8 @@ Pokud se taková třída používá jako základní třída a pokud odvozující
Nekonzistentní použití parametru lambda. Typy parametrů musí být buď všechny explicitní, nebo všechny implicitní.
-
-
- Částečná metoda nemůže mít modifikátor abstract.
-
-
-
-
- Částečná metoda musí být deklarovaná uvnitř částečného typu.
-
-
-
-
+
+
Částečná metoda nesmí explicitně implementovat metodu rozhraní.
@@ -8162,21 +8232,11 @@ Pokud se taková třída používá jako základní třída a pokud odvozující
Částečná metoda nesmí mít víc implementujících deklarací.
-
-
- Obě deklarace částečné metody musí používat parametr params nebo ho nepoužívat.
-
- Nenašla se žádná definující deklarace pro implementující deklaraci částečné metody {0}.
-
-
- V deklaracích metod, {0} a {1} se musí používat stejné názvy prvků řazené kolekce členů.
-
- Částečné deklarace metod {0} mají nekonzistentní omezení parametru typu {1}.
@@ -8187,16 +8247,11 @@ Pokud se taková třída používá jako základní třída a pokud odvozující
Nejde vytvořit delegáta z metody {0}, protože se jedná o částečnou metodu bez implementující deklarace.
-
-
+
+
Obě deklarace částečné metody musí být statické, nebo nesmí být statická žádná z nich.
-
-
- Obě deklarace částečné metody musí být nezabezpečené, nebo nesmí být nezabezpečená žádná z nich.
-
- Ve stromech výrazů nejde používat částečné metody, pro které existuje jenom definující deklarace, nebo odebrané podmíněné metody.
diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf
index 458820646f0bd..e70454ee1c2f7 100644
--- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf
+++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf
@@ -1642,26 +1642,51 @@
Der Params-Parameter muss einen gültigen Sammlungstyp aufweisen
-
-
- Beide partiellen Methodendeklarationen müssen identische Zugriffsmodifizierer aufweisen.
+
+
+ Both partial member declarations must have identical accessibility modifiers.
-
-
- Beide partiellen Methodendeklarationen müssen identische Kombinationen der Modifizierer "virtual", "override", "sealed" und "new" verwenden.
+
+
+ A partial member cannot have the 'abstract' modifier
+
+
+
+
+ Both partial member declarations, '{0}' and '{1}', must use the same tuple element names.
-
-
- Entweder beide oder keine der partiellen Methodendeklarationen müssen als "readonly" festgelegt werden.
+
+
+ A partial member must be declared within a partial type
-
-
+
+
+ Both partial member declarations must use a params parameter or neither may use a params parameter
+
+
+
+
+ Both partial member declarations must be readonly or neither may be readonly
+
+
+
+
+ Beide partiellen Methodendeklarationen müssen identische Kombinationen der Modifizierer "virtual", "override", "sealed" und "new" verwenden.
+
+
+
+
Deklarationen partieller Methoden müssen übereinstimmende Ref-Rückgabewerte aufweisen.
+
+
+ Both partial member declarations must be unsafe or neither may be unsafe
+
+ Beide Deklarationen der partiellen Methode müssen den gleichen Rückgabetyp aufweisen.
@@ -1687,6 +1712,51 @@
Die partielle Methode "{0}" muss Zugriffsmodifizierer aufweisen, weil sie out-Parameter verwendet.
+
+
+ A partial property may not have multiple defining declarations, and cannot be an auto-property.
+
+
+
+
+ A partial property may not have multiple implementing declarations
+
+
+
+
+ Property accessor '{0}' must be '{1}' to match the definition part
+
+
+
+
+ Property accessor '{0}' must be implemented because it is declared on the definition part
+
+
+
+
+ Partial property '{0}' must have a definition part.
+
+
+
+
+ Partial property '{0}' must have an implementation part.
+
+
+
+
+ Both partial property declarations must be required or neither may be required
+
+
+
+
+ Both partial property declarations must have the same type.
+
+
+
+
+ Property accessor '{0}' does not implement any accessor declared on the definition part
+
+ Eine Nullkonstante der Zeichenfolge wird nicht als Muster für "{0}" unterstützt. Verwenden Sie stattdessen eine leere Zeichenfolge.
@@ -1953,8 +2023,8 @@
-
- Der Modifikator ‚Scoped‘ des Parameters ‚{0}‘ stimmt nicht mit der partiellen Methodendeklaration überein.
+
+ Der Modifikator ‚Scoped‘ des Parameters ‚{0}‘ stimmt nicht mit der partiellen Methodendeklaration überein.
@@ -3047,6 +3117,16 @@
Der Parameter verfügt über den Modifizierer „params“ in der Lambdafunktion, aber nicht im Delegattyp des Ziels.
+
+
+ Partial property declarations '{0}' and '{1}' have signature differences.
+
+
+
+
+ Partial property declarations have signature differences.
+
+ Der primäre Konstruktorparameter "{0}" wird von einem Member aus der Basis überschatten.
@@ -4765,12 +4845,12 @@
- Die NULL-Zulässigkeit von Verweistypen im Typ des Parameters "{0}" entspricht nicht der Deklaration der partiellen Methode.
+ Die NULL-Zulässigkeit von Verweistypen im Typ des Parameters "{0}" entspricht nicht der Deklaration der partiellen Methode.
- Die NULL-Zulässigkeit von Verweistypen im Typ des Parameters entspricht nicht der Deklaration der partiellen Methode.
+ Die NULL-Zulässigkeit von Verweistypen im Typ des Parameters entspricht nicht der Deklaration der partiellen Methode.
@@ -4815,12 +4895,12 @@
- Die NULL-Zulässigkeit von Verweistypen im Rückgabetyp entspricht nicht der Deklaration der partiellen Methode.
+ Die NULL-Zulässigkeit von Verweistypen im Rückgabetyp entspricht nicht der Deklaration der partiellen Methode.
- Die NULL-Zulässigkeit von Verweistypen im Rückgabetyp entspricht nicht der Deklaration der partiellen Methode.
+ Die NULL-Zulässigkeit von Verweistypen im Rückgabetyp entspricht nicht der Deklaration der partiellen Methode.
@@ -6524,8 +6604,8 @@
-
- Der partial-Modifizierer kann nur unmittelbar vor "class", "record", "struct", "interface" oder einem Methodenrückgabetyp verwendet werden.
+
+ Der partial-Modifizierer kann nur unmittelbar vor "class", "record", "struct", "interface" oder einem Methodenrückgabetyp verwendet werden.
@@ -8132,18 +8212,8 @@ Wenn solch eine Klasse als Basisklasse verwendet wird und die ableitende Klasse
Inkonsistente Verwendung des lambda-Parameters. Alle Parametertypen müssen entweder explizit oder implizit sein.
-
-
- Eine partielle Methode darf nicht den Modifizierer "abstract" aufweisen.
-
-
-
-
- Eine partielle Methode muss innerhalb eines partiellen Typs deklariert sein.
-
-
-
-
+
+
Eine partielle Methode darf Schnittstellenmethoden nicht explizit implementieren.
@@ -8162,21 +8232,11 @@ Wenn solch eine Klasse als Basisklasse verwendet wird und die ableitende Klasse
Eine partielle Methode darf nicht über mehrere implementierende Deklarationen verfügen.
-
-
- Beide partiellen Methodendeklarationen müssen einen params-Parameter verwenden, oder keine von beiden darf einen params-Parameter verwenden.
-
- Für die implementierende Deklaration der partiellen Methode "{0}" wurde keine definierende Deklaration gefunden.
-
-
- Die beiden partiellen Methodendeklarationen ("{0}" und "{1}") müssen die gleichen Tupelelementnamen verwenden.
-
- Partielle Methodendeklarationen von "{0}" weisen inkonsistente Einschränkungen für den Typparameter "{1}" auf.
@@ -8187,16 +8247,11 @@ Wenn solch eine Klasse als Basisklasse verwendet wird und die ableitende Klasse
Aus der {0}-Methode kann kein Delegat erstellt werden, da es sich um eine partielle Methode ohne implementierende Deklaration handelt.
-
-
+
+
Beide partiellen Methodendeklarationen müssen statisch sein, oder keine von beiden darf statisch sein.
-
-
- Beide partiellen Methodendeklarationen müssen unsicher sein, oder keine von beiden darf unsicher sein.
-
- In Ausdrucksbäumen dürfen weder partielle Methoden mit nur einer definierenden Deklaration noch entfernte bedingte Methoden verwendet werden.
diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf
index de96942b43ca1..9a4a1bed9796f 100644
--- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf
+++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf
@@ -1642,26 +1642,51 @@
El parámetro params debe tener un tipo de colección válido
-
-
- Ambas declaraciones de método parcial deben tener modificadores de accesibilidad idénticos.
+
+
+ Both partial member declarations must have identical accessibility modifiers.
-
-
- Ambas declaraciones de método parcial deben tener combinaciones idénticas de los modificadores "virtual", "override", "sealed" y "new".
+
+
+ A partial member cannot have the 'abstract' modifier
+
+
+
+
+ Both partial member declarations, '{0}' and '{1}', must use the same tuple element names.
-
-
- Ambas declaraciones de métodos parciales deben ser de solo lectura o ninguna de ellas puede ser de solo lectura
+
+
+ A partial member must be declared within a partial type
-
-
+
+
+ Both partial member declarations must use a params parameter or neither may use a params parameter
+
+
+
+
+ Both partial member declarations must be readonly or neither may be readonly
+
+
+
+
+ Ambas declaraciones de método parcial deben tener combinaciones idénticas de los modificadores "virtual", "override", "sealed" y "new".
+
+
+
+
Las declaraciones de método parcial deben tener valores devueltos de referencia que coincidan.
+
+
+ Both partial member declarations must be unsafe or neither may be unsafe
+
+ Ambas declaraciones de método parcial deben tener el mismo tipo de valor devuelto.
@@ -1687,6 +1712,51 @@
El método parcial "{0}" debe tener modificadores de accesibilidad porque tiene parámetros "out".
+
+
+ A partial property may not have multiple defining declarations, and cannot be an auto-property.
+
+
+
+
+ A partial property may not have multiple implementing declarations
+
+
+
+
+ Property accessor '{0}' must be '{1}' to match the definition part
+
+
+
+
+ Property accessor '{0}' must be implemented because it is declared on the definition part
+
+
+
+
+ Partial property '{0}' must have a definition part.
+
+
+
+
+ Partial property '{0}' must have an implementation part.
+
+
+
+
+ Both partial property declarations must be required or neither may be required
+
+
+
+
+ Both partial property declarations must have the same type.
+
+
+
+
+ Property accessor '{0}' does not implement any accessor declared on the definition part
+
+ No se admite una constante de cadena 'null' como patrón para '{0}'. Use una cadena vacía en su lugar.
@@ -1953,8 +2023,8 @@
-
- El modificador 'scoped' del parámetro '{0}' no coincide con la declaración de método parcial.
+
+ El modificador 'scoped' del parámetro '{0}' no coincide con la declaración de método parcial.
@@ -3047,6 +3117,16 @@
El parámetro tiene modificador de parámetros en lambda, pero no en el tipo delegado de destino.
+
+
+ Partial property declarations '{0}' and '{1}' have signature differences.
+
+
+
+
+ Partial property declarations have signature differences.
+
+ El parámetro del constructor principal "{0}" está sombreado por un miembro de la base.
@@ -4765,12 +4845,12 @@
- La nulabilidad de los tipos de referencia del tipo de parámetro"{0}" no coincide con la declaración de método parcial.
+ La nulabilidad de los tipos de referencia del tipo de parámetro"{0}" no coincide con la declaración de método parcial.
- La nulabilidad de los tipos de referencia del tipo de parámetro no coincide con la declaración de método parcial
+ La nulabilidad de los tipos de referencia del tipo de parámetro no coincide con la declaración de método parcial
@@ -4815,12 +4895,12 @@
- La nulabilidad de los tipos de referencia del tipo devuelto no coincide con la declaración de método parcial.
+ La nulabilidad de los tipos de referencia del tipo devuelto no coincide con la declaración de método parcial.
- La nulabilidad de los tipos de referencia del tipo devuelto no coincide con la declaración de método parcial.
+ La nulabilidad de los tipos de referencia del tipo devuelto no coincide con la declaración de método parcial.
@@ -6524,8 +6604,8 @@
-
- El modificador "partial" solo puede aparecer inmediatamente antes de "class", "record", "struct", "interface" o de un tipo de valor devuelto del método.
+
+ El modificador "partial" solo puede aparecer inmediatamente antes de "class", "record", "struct", "interface" o de un tipo de valor devuelto del método.
@@ -8132,18 +8212,8 @@ Si se utiliza una clase de este tipo como clase base y si la clase derivada defi
Uso incoherente del parámetro lambda; los tipos de parámetro deben ser todos explícitos o todos implícitos
-
-
- Un método parcial no puede tener el modificador "abstract"
-
-
-
-
- Un método parcial debe declararse dentro de un tipo parcial
-
-
-
-
+
+
Un método parcial no puede implementar explícitamente un método de interfaz
@@ -8162,21 +8232,11 @@ Si se utiliza una clase de este tipo como clase base y si la clase derivada defi
Un método parcial no puede tener varias declaraciones de implementación
-
-
- Ambas declaraciones de métodos parciales deben usar un parámetro params; si no, ninguna podrá usarlo
-
- No se encontró ninguna declaración de definición para la declaración de implementación del método parcial '{0}'
-
-
- Ambas declaraciones de método parcial, '{0}' y '{1}', deben usar los mismos nombres de elementos de tupla.
-
- Las declaraciones de métodos parciales de "{0}" tienen restricciones incoherentes para el parámetro de tipo "{1}"
@@ -8187,16 +8247,11 @@ Si se utiliza una clase de este tipo como clase base y si la clase derivada defi
No se puede crear un delegado a partir del método '{0}' porque es un método parcial sin declaración de implementación
-
-
+
+
Ambas declaraciones de método parcial deben ser estáticas o ninguna de ellas puede ser estática
-
-
- Ambas declaraciones de métodos parciales deben ser no seguras o ninguna de ellas puede ser no segura
-
- En los árboles de expresión no se pueden usar métodos parciales con solo una declaración de definición ni métodos condicionales quitados
diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf
index cd8e3b4571564..e907385f43c1d 100644
--- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf
+++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf
@@ -1642,26 +1642,51 @@
Le paramètre params doit avoir un type de collection valide
-
-
- Les deux déclarations de méthodes partielles doivent avoir des modificateurs d'accessibilité identiques.
+
+
+ Both partial member declarations must have identical accessibility modifiers.
-
-
- Les deux déclarations de méthodes partielles doivent avoir des combinaisons identiques des modificateurs 'virtual', 'override', 'sealed' et 'new'.
+
+
+ A partial member cannot have the 'abstract' modifier
+
+
+
+
+ Both partial member declarations, '{0}' and '{1}', must use the same tuple element names.
-
-
- Soit les deux déclarations de méthodes partielles sont readonly, soit aucune ne l'est
+
+
+ A partial member must be declared within a partial type
-
-
+
+
+ Both partial member declarations must use a params parameter or neither may use a params parameter
+
+
+
+
+ Both partial member declarations must be readonly or neither may be readonly
+
+
+
+
+ Les deux déclarations de méthodes partielles doivent avoir des combinaisons identiques des modificateurs 'virtual', 'override', 'sealed' et 'new'.
+
+
+
+
Les déclarations de méthodes partielles doivent avoir des valeurs de retour ref correspondantes.
+
+
+ Both partial member declarations must be unsafe or neither may be unsafe
+
+ Les deux déclarations de méthodes partielles doivent avoir le même type de retour.
@@ -1687,6 +1712,51 @@
La méthode partielle '{0}' doit avoir des modificateurs d'accessibilité, car elle a des paramètres 'out'.
+
+
+ A partial property may not have multiple defining declarations, and cannot be an auto-property.
+
+
+
+
+ A partial property may not have multiple implementing declarations
+
+
+
+
+ Property accessor '{0}' must be '{1}' to match the definition part
+
+
+
+
+ Property accessor '{0}' must be implemented because it is declared on the definition part
+
+
+
+
+ Partial property '{0}' must have a definition part.
+
+
+
+
+ Partial property '{0}' must have an implementation part.
+
+
+
+
+ Both partial property declarations must be required or neither may be required
+
+
+
+
+ Both partial property declarations must have the same type.
+
+
+
+
+ Property accessor '{0}' does not implement any accessor declared on the definition part
+
+ Une constante « null » de chaîne n’est pas prise en charge en tant que modèle pour «{0}». Utilisez plutôt une chaîne vide.
@@ -1953,8 +2023,8 @@
-
- Le modificateur 'scoped' du paramètre '{0}' ne correspond pas à la déclaration de méthode partielle.
+
+ Le modificateur 'scoped' du paramètre '{0}' ne correspond pas à la déclaration de méthode partielle.
@@ -3047,6 +3117,16 @@
Le paramètre a un modificateur de paramètres dans l’expression lambda mais pas dans le type délégué cible.
+
+
+ Partial property declarations '{0}' and '{1}' have signature differences.
+
+
+
+
+ Partial property declarations have signature differences.
+
+ Le paramètre de constructeur principal « {0} » est ombré par un membre de la base.
@@ -4765,12 +4845,12 @@
- La nullabilité des types référence dans le type de paramètre '{0}' ne correspond pas à la déclaration de méthode partielle.
+ La nullabilité des types référence dans le type de paramètre '{0}' ne correspond pas à la déclaration de méthode partielle.
- La nullabilité des types référence dans le type de paramètre ne correspond pas à la déclaration de méthode partielle.
+ La nullabilité des types référence dans le type de paramètre ne correspond pas à la déclaration de méthode partielle.
@@ -4815,12 +4895,12 @@
- La nullabilité des types référence dans le type de retour ne correspond pas à la déclaration de méthode partielle.
+ La nullabilité des types référence dans le type de retour ne correspond pas à la déclaration de méthode partielle.
- La nullabilité des types référence dans le type de retour ne correspond pas à la déclaration de méthode partielle.
+ La nullabilité des types référence dans le type de retour ne correspond pas à la déclaration de méthode partielle.
@@ -6524,8 +6604,8 @@
-
- Le modificateur 'partial' peut apparaître uniquement juste avant 'class', 'record', 'struct', 'interface' ou un type de retour de méthode.
+
+ Le modificateur 'partial' peut apparaître uniquement juste avant 'class', 'record', 'struct', 'interface' ou un type de retour de méthode.
@@ -8132,18 +8212,8 @@ Si une telle classe est utilisée en tant que classe de base et si la classe dé
Utilisation du paramètre lambda incohérente ; les types de paramètres doivent être tous explicites ou tous implicites
-
-
- Une méthode partielle ne peut pas avoir le modificateur 'abstract'
-
-
-
-
- Une méthode partielle doit être déclarée au sein d'un type partiel
-
-
-
-
+
+
Une méthode partielle ne peut pas implémenter explicitement une méthode d'interface
@@ -8162,21 +8232,11 @@ Si une telle classe est utilisée en tant que classe de base et si la classe dé
Une méthode partielle ne peut pas avoir plusieurs déclarations d'implémentation
-
-
- Soit les deux déclarations de méthode partielles utilisent un paramètre params, soit aucune des deux
-
- Aucune déclaration de définition trouvée pour la déclaration d'implémentation de la méthode partielle '{0}'
-
-
- Les deux déclarations de méthodes partielles, '{0}' et '{1}', doivent utiliser les mêmes noms d'éléments tuples.
-
- Les déclarations de méthodes partielles de '{0}' ont des contraintes incohérentes pour le paramètre de type '{1}'
@@ -8187,16 +8247,11 @@ Si une telle classe est utilisée en tant que classe de base et si la classe dé
Impossible de créer un délégué à partir de la méthode '{0}', car il s'agit d'une méthode partielle sans déclaration d'implémentation
-
-
+
+
Soit les deux déclarations de méthode partielles sont statiques, soit aucune ne l'est
-
-
- Soit les deux déclarations de méthode partielles sont unsafe, soit aucune ne l'est
-
- Les méthodes partielles avec uniquement une déclaration de définition ou des méthodes conditionnelles supprimées ne peuvent pas être utilisées dans des arborescences d'expressions
diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf
index ee6c972ccf03d..b64ad3c5a9d50 100644
--- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf
+++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf
@@ -1642,26 +1642,51 @@
Il parametro params deve avere un tipo di raccolta valido
-
-
- I modificatori di accessibilità devono essere identici in entrambe le dichiarazioni di metodo parziale.
+
+
+ Both partial member declarations must have identical accessibility modifiers.
-
-
- Entrambe le dichiarazioni di metodo parziale devono contenere combinazioni identiche di modificatori 'virtual', 'override', 'sealed' e 'new'.
+
+
+ A partial member cannot have the 'abstract' modifier
+
+
+
+
+ Both partial member declarations, '{0}' and '{1}', must use the same tuple element names.
-
-
- Nessuna o entrambe le dichiarazioni di metodi parziali devono essere di tipo readonly
+
+
+ A partial member must be declared within a partial type
-
-
+
+
+ Both partial member declarations must use a params parameter or neither may use a params parameter
+
+
+
+
+ Both partial member declarations must be readonly or neither may be readonly
+
+
+
+
+ Entrambe le dichiarazioni di metodo parziale devono contenere combinazioni identiche di modificatori 'virtual', 'override', 'sealed' e 'new'.
+
+
+
+
Le dichiarazioni di metodo parziale devono contenere valori restituiti di riferimento corrispondenti.
+
+
+ Both partial member declarations must be unsafe or neither may be unsafe
+
+ Il tipo restituito deve essere identico in entrambe le dichiarazioni di metodo parziale.
@@ -1687,6 +1712,51 @@
Il metodo parziale '{0}' deve contenere modificatori di accessibilità perché include parametri 'out'.
+
+
+ A partial property may not have multiple defining declarations, and cannot be an auto-property.
+
+
+
+
+ A partial property may not have multiple implementing declarations
+
+
+
+
+ Property accessor '{0}' must be '{1}' to match the definition part
+
+
+
+
+ Property accessor '{0}' must be implemented because it is declared on the definition part
+
+
+
+
+ Partial property '{0}' must have a definition part.
+
+
+
+
+ Partial property '{0}' must have an implementation part.
+
+
+
+
+ Both partial property declarations must be required or neither may be required
+
+
+
+
+ Both partial property declarations must have the same type.
+
+
+
+
+ Property accessor '{0}' does not implement any accessor declared on the definition part
+
+ Una costante di tipo stringa 'null' non è supportata come criterio per ?{0}'. Usare invece una stringa vuota.
@@ -1953,8 +2023,8 @@
-
- Il modificatore 'scoped' del parametro '{0}' non corrisponde alla dichiarazione di metodo parziale.
+
+ Il modificatore 'scoped' del parametro '{0}' non corrisponde alla dichiarazione di metodo parziale.
@@ -3047,6 +3117,16 @@
Il parametro contiene un modificatore di parametri in lambda ma non nel tipo delegato di destinazione.
+
+
+ Partial property declarations '{0}' and '{1}' have signature differences.
+
+
+
+
+ Partial property declarations have signature differences.
+
+ Il parametro del costruttore primario '{0}' è ombreggiato da un membro della base.
@@ -4765,12 +4845,12 @@ target:module Compila un modulo che può essere aggiunto ad altro
- Il supporto dei valori Null dei tipi riferimento nel tipo di parametro '{0}' non corrisponde alla dichiarazione di metodo parziale.
+ Il supporto dei valori Null dei tipi riferimento nel tipo di parametro '{0}' non corrisponde alla dichiarazione di metodo parziale.
- Il supporto dei valori Null dei tipi riferimento nel tipo di parametro non corrisponde alla dichiarazione di metodo parziale.
+ Il supporto dei valori Null dei tipi riferimento nel tipo di parametro non corrisponde alla dichiarazione di metodo parziale.
@@ -4815,12 +4895,12 @@ target:module Compila un modulo che può essere aggiunto ad altro
- Il supporto dei valori Null dei tipi riferimento nel tipo restituito non corrisponde alla dichiarazione di metodo parziale.
+ Il supporto dei valori Null dei tipi riferimento nel tipo restituito non corrisponde alla dichiarazione di metodo parziale.
- Il supporto dei valori Null dei tipi riferimento nel tipo restituito non corrisponde alla dichiarazione di metodo parziale.
+ Il supporto dei valori Null dei tipi riferimento nel tipo restituito non corrisponde alla dichiarazione di metodo parziale.
@@ -6524,8 +6604,8 @@ target:module Compila un modulo che può essere aggiunto ad altro
-
- Il modificatore 'partial' può trovarsi solo immediatamente prima di 'class', 'record', 'struct', 'interface' o il tipo restituito di un metodo.
+
+ Il modificatore 'partial' può trovarsi solo immediatamente prima di 'class', 'record', 'struct', 'interface' o il tipo restituito di un metodo.
@@ -8132,18 +8212,8 @@ Se si usa tale classe come classe base e se la classe di derivazione definisce u
Utilizzo non coerente dei parametri lambda: i parametri devono essere tutti di tipo esplicito o implicito
-
-
- Un metodo parziale non può contenere il modificatore 'abstract'
-
-
-
-
- Un metodo parziale deve essere dichiarato in un tipo parziale
-
-
-
-
+
+
Un metodo parziale non può implementare in modo esplicito un metodo di interfaccia
@@ -8162,21 +8232,11 @@ Se si usa tale classe come classe base e se la classe di derivazione definisce u
Un metodo parziale non può avere più dichiarazioni di implementazione
-
-
- Entrambe le dichiarazioni di metodo parziale devono usare un parametro params, altrimenti nessuna delle due potrà usarla
-
- Non sono state trovate dichiarazioni di definizione per la dichiarazione di implementazione del metodo parziale '{0}'
-
-
- Entrambe le dichiarazioni di metodo parziale '{0}' e '{1}' devono usare gli stessi nomi di elementi di tupla.
-
- Le dichiarazioni di metodo parziali di '{0}' contengono vincoli incoerenti per il parametro di tipo '{1}'
@@ -8187,16 +8247,11 @@ Se si usa tale classe come classe base e se la classe di derivazione definisce u
Non è possibile creare il delegato dal metodo '{0}' perché è un metodo parziale senza una dichiarazione di implementazione
-
-
+
+
Entrambe le dichiarazioni di metodo parziale devono essere statiche, altrimenti nessuna delle due potrà esserlo
-
-
- Nessuna o entrambe le dichiarazioni di metodi parziali devono essere di tipo unsafe
-
- Non è possibile usare negli alberi delle espressioni metodi parziali contenenti solo una dichiarazione di definizione o metodi condizionali rimossi
diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf
index 049964d81ce3a..0f66f576146bd 100644
--- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf
+++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf
@@ -1642,26 +1642,51 @@
params パラメーターには有効なコレクションの種類が必要です
-
-
- 両方の部分メソッド宣言には、同じアクセシビリティ修飾子を指定する必要があります。
+
+
+ Both partial member declarations must have identical accessibility modifiers.
-
-
- 両方の部分メソッド宣言には、'virtual'、'override'、'sealed'、'new' 修飾子の同じ組み合わせを指定する必要があります。
+
+
+ A partial member cannot have the 'abstract' modifier
+
+
+
+
+ Both partial member declarations, '{0}' and '{1}', must use the same tuple element names.
-
-
- 部分メソッド宣言は、両方とも readonly であるか、両方とも readonly でないかのいずれかである必要があります
+
+
+ A partial member must be declared within a partial type
-
-
+
+
+ Both partial member declarations must use a params parameter or neither may use a params parameter
+
+
+
+
+ Both partial member declarations must be readonly or neither may be readonly
+
+
+
+
+ 両方の部分メソッド宣言には、'virtual'、'override'、'sealed'、'new' 修飾子の同じ組み合わせを指定する必要があります。
+
+
+
+
部分メソッドの宣言には、一致する ref 戻り値が必要です。
+
+
+ Both partial member declarations must be unsafe or neither may be unsafe
+
+ 部分メソッドの両方の宣言には、同じ戻り値の型を指定しなければなりません。
@@ -1687,6 +1712,51 @@
部分メソッド '{0}' には、'out' パラメーターが指定されているため、アクセシビリティ修飾子が必要です。
+
+
+ A partial property may not have multiple defining declarations, and cannot be an auto-property.
+
+
+
+
+ A partial property may not have multiple implementing declarations
+
+
+
+
+ Property accessor '{0}' must be '{1}' to match the definition part
+
+
+
+
+ Property accessor '{0}' must be implemented because it is declared on the definition part
+
+
+
+
+ Partial property '{0}' must have a definition part.
+
+
+
+
+ Partial property '{0}' must have an implementation part.
+
+
+
+
+ Both partial property declarations must be required or neither may be required
+
+
+
+
+ Both partial property declarations must have the same type.
+
+
+
+
+ Property accessor '{0}' does not implement any accessor declared on the definition part
+
+ 文字列 'null' 定数は、'{0}' のパターンとしてサポートされていません。代わりに空の文字列を使用してください。
@@ -1953,8 +2023,8 @@
-
- パラメーター '{0}' の 'scoped' 修飾子が部分メソッド宣言と一致しません。
+
+ パラメーター '{0}' の 'scoped' 修飾子が部分メソッド宣言と一致しません。
@@ -3047,6 +3117,16 @@
パラメーターにラムダの params 修飾子がありますが、ターゲット デリゲート型にはありません。
+
+
+ Partial property declarations '{0}' and '{1}' have signature differences.
+
+
+
+
+ Partial property declarations have signature differences.
+
+ プライマリ コンストラクター パラメーター '{0}' は基底のメンバーによってシャドウされます。
@@ -4765,12 +4845,12 @@
- パラメーター '{0}' の型における参照型の Null 許容性が、部分メソッド宣言と一致しません。
+ パラメーター '{0}' の型における参照型の Null 許容性が、部分メソッド宣言と一致しません。
- パラメーターの型における参照型の Null 許容性が、部分メソッド宣言と一致しません。
+ パラメーターの型における参照型の Null 許容性が、部分メソッド宣言と一致しません。
@@ -4815,12 +4895,12 @@
- 戻り値の型における参照型の Null 値の許容が、部分メソッド宣言と一致しません。
+ 戻り値の型における参照型の Null 値の許容が、部分メソッド宣言と一致しません。
- 戻り値の型における参照型の Null 値の許容が、部分メソッド宣言と一致しません。
+ 戻り値の型における参照型の Null 値の許容が、部分メソッド宣言と一致しません。
@@ -6524,8 +6604,8 @@
-
- 'partial' 修飾子は、'class'、'record'、'struct'、'interface'、またはメソッドの戻り値の型の直前にのみ指定できます。
+
+ 'partial' 修飾子は、'class'、'record'、'struct'、'interface'、またはメソッドの戻り値の型の直前にのみ指定できます。
@@ -8132,18 +8212,8 @@ If such a class is used as a base class and if the deriving class defines a dest
ラムダ パラメーターの使用方法に一貫性がありません。パラメーター型はすべて明示的であるか、またはすべて暗黙的である必要があります
-
-
- 部分メソッドに 'abstract' 修飾子を指定することはできません
-
-
-
-
- 部分メソッドは、部分型内で宣言される必要があります
-
-
-
-
+
+
部分メソッドは、インターフェイス メソッドを明示的に実装できないことがあります
@@ -8162,21 +8232,11 @@ If such a class is used as a base class and if the deriving class defines a dest
部分メソッドでは、複数の実装宣言を含むことができない場合があります
-
-
- 部分メソッド宣言は、両方とも params パラメーターを使用するか、両方とも params パラメーターを使用しないかのいずれかである必要があります
-
- 部分メソッド '{0}' の実装宣言に対する定義宣言が見つかりませんでした
-
-
- 部分メソッド宣言 '{0}' および '{1}' は、どちらも同じタプル要素名を使用する必要があります。
-
- '{0}' の部分メソッド宣言には、型パラメーター '{1}' に対して矛盾する制約が含まれています
@@ -8187,16 +8247,11 @@ If such a class is used as a base class and if the deriving class defines a dest
メソッド '{0}' は実装宣言がない部分メソッドであるため、このメソッドからデリゲートを作成できません
-
-
+
+
部分メソッド宣言は、両方とも static であるか、両方とも static でないかのいずれかである必要があります
-
-
- 部分メソッド宣言は、両方とも unsafe であるか、両方とも unsafe でないかのいずれかである必要があります
-
- 定義宣言だけを含む部分メソッドまたは削除された条件付きメソッドは、式ツリーで使用できません
diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf
index dd8ef848b9a66..682e122e79c06 100644
--- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf
+++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf
@@ -1642,26 +1642,51 @@
params 매개 변수는 유효한 컬렉션 형식이어야 합니다.
-
-
- 두 부분 메서드 선언에는 동일한 접근성 한정자가 있어야 합니다.
+
+
+ Both partial member declarations must have identical accessibility modifiers.
-
-
- 두 부분 메서드 선언에는 동일한 조합의 'virtual', 'override', 'sealed' 및 'new' 한정자가 있어야 합니다.
+
+
+ A partial member cannot have the 'abstract' modifier
+
+
+
+
+ Both partial member declarations, '{0}' and '{1}', must use the same tuple element names.
-
-
- 두 부분 메서드(Partial method) 선언 모두 readonly이거나 readonly가 아니어야 합니다.
+
+
+ A partial member must be declared within a partial type
-
-
+
+
+ Both partial member declarations must use a params parameter or neither may use a params parameter
+
+
+
+
+ Both partial member declarations must be readonly or neither may be readonly
+
+
+
+
+ 두 부분 메서드 선언에는 동일한 조합의 'virtual', 'override', 'sealed' 및 'new' 한정자가 있어야 합니다.
+
+
+
+
부분 메서드 선언에는 일치하는 참조 반환 값이 있어야 합니다.
+
+
+ Both partial member declarations must be unsafe or neither may be unsafe
+
+ 두 부분 메서드 선언의 반환 형식이 같아야 합니다.
@@ -1687,6 +1712,51 @@
부분 메서드 '{0}'에는 'out' 매개 변수가 있으므로 접근성 한정자가 있어야 합니다.
+
+
+ A partial property may not have multiple defining declarations, and cannot be an auto-property.
+
+
+
+
+ A partial property may not have multiple implementing declarations
+
+
+
+
+ Property accessor '{0}' must be '{1}' to match the definition part
+
+
+
+
+ Property accessor '{0}' must be implemented because it is declared on the definition part
+
+
+
+
+ Partial property '{0}' must have a definition part.
+
+
+
+
+ Partial property '{0}' must have an implementation part.
+
+
+
+
+ Both partial property declarations must be required or neither may be required
+
+
+
+
+ Both partial property declarations must have the same type.
+
+
+
+
+ Property accessor '{0}' does not implement any accessor declared on the definition part
+
+ 문자열 'Null' 상수는 '{0}'에 대한 패턴으로 지원되지 않습니다. 대신 빈 문자열을 사용하세요.
@@ -1953,8 +2023,8 @@
-
- 매개 변수 '{0}'의 '범위 지정' 한정자가 부분 메서드 선언과 일치하지 않습니다.
+
+ 매개 변수 '{0}'의 '범위 지정' 한정자가 부분 메서드 선언과 일치하지 않습니다.
@@ -3047,6 +3117,16 @@
매개 변수에 람다의 매개 변수 한정자가 있지만 대상 대리자 형식에는 없습니다.
+
+
+ Partial property declarations '{0}' and '{1}' have signature differences.
+
+
+
+
+ Partial property declarations have signature differences.
+
+ 기본의 멤버가 '{0}' 기본 생성자 매개 변수를 그림자처럼 따릅니다.
@@ -4765,12 +4845,12 @@
- '{0}' 매개 변수 형식에 있는 참조 형식 Null 허용 여부가 부분 메서드(Partial Method) 선언과 일치하지 않습니다.
+ '{0}' 매개 변수 형식에 있는 참조 형식 Null 허용 여부가 부분 메서드(Partial Method) 선언과 일치하지 않습니다.
- 매개 변수 형식에 있는 참조 형식 Null 허용 여부가 부분 메서드(Partial Method) 선언과 일치하지 않습니다.
+ 매개 변수 형식에 있는 참조 형식 Null 허용 여부가 부분 메서드(Partial Method) 선언과 일치하지 않습니다.
@@ -4815,12 +4895,12 @@
- 반환 형식에 있는 참조 형식 Null 허용 여부가 부분 메서드 선언과 일치하지 않습니다.
+ 반환 형식에 있는 참조 형식 Null 허용 여부가 부분 메서드 선언과 일치하지 않습니다.
- 반환 형식에 있는 참조 형식 Null 허용 여부가 부분 메서드 선언과 일치하지 않습니다.
+ 반환 형식에 있는 참조 형식 Null 허용 여부가 부분 메서드 선언과 일치하지 않습니다.
@@ -6524,8 +6604,8 @@
-
- 'partial' 한정자는 'class', 'record', 'struct', 'interface' 또는 메서드 반환 형식 바로 앞에만 올 수 있습니다.
+
+ 'partial' 한정자는 'class', 'record', 'struct', 'interface' 또는 메서드 반환 형식 바로 앞에만 올 수 있습니다.
@@ -8132,18 +8212,8 @@ If such a class is used as a base class and if the deriving class defines a dest
람다 매개 변수가 일관성 없이 사용되었습니다. 매개 변수 형식은 모두 명시적이거나 암시적이어야 합니다.
-
-
- 부분 메서드에는 'abstract' 한정자가 있을 수 없습니다.
-
-
-
-
- 부분 형식(Partial Type) 내에 부분 메서드가 선언되어야 합니다.
-
-
-
-
+
+
부분 메서드(Partial Method)는 인터페이스 메서드를 명시적으로 구현할 수 없습니다.
@@ -8162,21 +8232,11 @@ If such a class is used as a base class and if the deriving class defines a dest
부분 메서드(Partial Method)에는 하나의 구현 선언만 사용할 수 있습니다.
-
-
- 두 부분 메서드(Partial Method) 선언 모두 params 매개 변수를 사용하거나 params 매개 변수를 사용할 수 없습니다.
-
- '{0}' 부분 메서드(Partial Method)의 구현 선언에 대한 정의 선언이 없습니다.
-
-
- 두 부분 메서드(Partial Method) 선언 '{0}' 및 '{1}' 모두에서 동일한 튜플 요소 이름을 사용해야 합니다.
-
- '{0}'의 부분 메서드(Partial method) 선언의 '{1}' 형식 매개 변수에 대한 제약 조건이 일관되지 않습니다.
@@ -8187,16 +8247,11 @@ If such a class is used as a base class and if the deriving class defines a dest
'{0}'은(는) 구현 선언이 없는 부분 메서드(Partial Method)이므로 이 메서드로부터 대리자를 만들 수 없습니다.
-
-
+
+
두 부분 메서드(Partial Method) 선언 모두 static이거나 static이 아니어야 합니다.
-
-
- 두 부분 메서드(Partial Method) 선언 모두 unsafe이거나 unsafe가 아니어야 합니다.
-
- 정의 선언만 있는 부분 메서드(Partial Method) 또는 제거된 조건부 메서드는 식 트리에 사용할 수 없습니다.
diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf
index 871593fc5cad5..c9daf489d2411 100644
--- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf
+++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf
@@ -1642,26 +1642,51 @@
Parametr params musi mieć prawidłowy typ kolekcji
-
-
- Obie deklaracje metody częściowej muszą mieć identyczne modyfikatory dostępności.
+
+
+ Both partial member declarations must have identical accessibility modifiers.
-
-
- Obie deklaracje metody częściowej muszą mieć identyczne kombinacje modyfikatorów „virtual”, „override”, „sealed” i „new”.
+
+
+ A partial member cannot have the 'abstract' modifier
+
+
+
+
+ Both partial member declarations, '{0}' and '{1}', must use the same tuple element names.
-
-
- Obie metody częściowe muszą być zadeklarowane jako readonly lub żadna nie może być zadeklarowana jako readonly
+
+
+ A partial member must be declared within a partial type
-
-
+
+
+ Both partial member declarations must use a params parameter or neither may use a params parameter
+
+
+
+
+ Both partial member declarations must be readonly or neither may be readonly
+
+
+
+
+ Obie deklaracje metody częściowej muszą mieć identyczne kombinacje modyfikatorów „virtual”, „override”, „sealed” i „new”.
+
+
+
+
Deklaracje metody częściowej muszą mieć pasujące wartości zwracane przez odwołanie.
+
+
+ Both partial member declarations must be unsafe or neither may be unsafe
+
+ Obie częściowe deklaracje metod muszą mieć taki sam zwracany typ.
@@ -1687,6 +1712,51 @@
Metoda częściowa „{0}” musi mieć modyfikatory dostępności, ponieważ ma parametry „out”.
+
+
+ A partial property may not have multiple defining declarations, and cannot be an auto-property.
+
+
+
+
+ A partial property may not have multiple implementing declarations
+
+
+
+
+ Property accessor '{0}' must be '{1}' to match the definition part
+
+
+
+
+ Property accessor '{0}' must be implemented because it is declared on the definition part
+
+
+
+
+ Partial property '{0}' must have a definition part.
+
+
+
+
+ Partial property '{0}' must have an implementation part.
+
+
+
+
+ Both partial property declarations must be required or neither may be required
+
+
+
+
+ Both partial property declarations must have the same type.
+
+
+
+
+ Property accessor '{0}' does not implement any accessor declared on the definition part
+
+ Stała ciągu „null” nie jest obsługiwana jako wzorzec dla „{0}”. Zamiast tego użyj pustego ciągu.
@@ -1953,8 +2023,8 @@
-
- Modyfikator „scoped” parametru „{0}” nie jest zgodny z częściową deklaracją metody.
+
+ Modyfikator „scoped” parametru „{0}” nie jest zgodny z częściową deklaracją metody.
@@ -3047,6 +3117,16 @@
Parametr ma modyfikator params w wyrażeniu lambda, ale nie ma w docelowym typie delegata.
+
+
+ Partial property declarations '{0}' and '{1}' have signature differences.
+
+
+
+
+ Partial property declarations have signature differences.
+
+ Podstawowy parametr konstruktora „{0}” jest w tle przez składową z bazy.
@@ -4765,12 +4845,12 @@
- Obsługa wartości null dla typów referencyjnych w typie parametru „{0}” jest niezgodna z częściową deklaracją metody.
+ Obsługa wartości null dla typów referencyjnych w typie parametru „{0}” jest niezgodna z częściową deklaracją metody.
- Obsługa wartości null dla typów referencyjnych w typie parametru jest niezgodna z częściową deklaracją metody.
+ Obsługa wartości null dla typów referencyjnych w typie parametru jest niezgodna z częściową deklaracją metody.
@@ -4815,12 +4895,12 @@
- Nullowalność typów referencyjnych w zwracanym typie jest niezgodna z częściową deklaracją metody.
+ Nullowalność typów referencyjnych w zwracanym typie jest niezgodna z częściową deklaracją metody.
- Nullowalność typów referencyjnych w zwracanym typie jest niezgodna z częściową deklaracją metody.
+ Nullowalność typów referencyjnych w zwracanym typie jest niezgodna z częściową deklaracją metody.
@@ -6524,8 +6604,8 @@
-
- Modyfikator „partial” może pojawić się tylko bezpośrednio przed słowem kluczowym „class”, „record” „struct”, „interface” lub zwracanym typem metody.
+
+ Modyfikator „partial” może pojawić się tylko bezpośrednio przed słowem kluczowym „class”, „record” „struct”, „interface” lub zwracanym typem metody.
@@ -8132,18 +8212,8 @@ Jeśli taka klasa zostanie użyta jako klasa bazowa i klasa pochodna definiuje d
Niespójne użycie parametrów lambda. Wszystkie typy parametrów muszą być albo jawne, albo niejawne.
-
-
- Metoda częściowa nie może mieć modyfikatora „abstract”
-
-
-
-
- Metoda częściowa musi być zadeklarowana w typie częściowym.
-
-
-
-
+
+
Metoda częściowa nie może jawnie implementować metody interfejsu.
@@ -8162,21 +8232,11 @@ Jeśli taka klasa zostanie użyta jako klasa bazowa i klasa pochodna definiuje d
Metoda częściowa nie może mieć wielu deklaracji implementujących.
-
-
- Obie częściowe deklaracje metody muszą używać parametru params lub żadna nie może go używać
-
- Nie znaleziono deklaracji definiującej na potrzeby implementowania częściowej metody „{0}”
-
-
- Obydwie częściowe deklaracje metody, „{0}” i „{1}”, muszą korzystać z tych samych nazw elementów krotki.
-
- Deklaracje metod częściowych elementu „{0}” mają niespójne ograniczenia dla parametru typu „{1}”
@@ -8187,16 +8247,11 @@ Jeśli taka klasa zostanie użyta jako klasa bazowa i klasa pochodna definiuje d
Nie można utworzyć delegata z metody „{0}”, ponieważ jest to metoda częściowa bez deklaracji implementującej.
-
-
+
+
Obie deklaracje metody częściowej muszą być statyczne albo żadna z nich nie może być statyczna.
-
-
- Obie deklaracje metody częściowej muszą być niezabezpieczone albo żadna z nich nie może być niezabezpieczona.
-
- W drzewach wyrażeń nie można używać metod częściowych zawierających tylko deklarację definiującą ani usuniętych metod warunkowych.
diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf
index a4f21ff34b491..6a17c009cf8d4 100644
--- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf
+++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf
@@ -1642,26 +1642,51 @@
O parâmetro params deve ter um tipo de coleção válido
-
-
- As duas declarações de métodos parciais precisam ter modificadores de acessibilidade idênticos.
+
+
+ Both partial member declarations must have identical accessibility modifiers.
-
-
- As duas declarações de métodos parciais precisam ter combinações idênticas dos modificadores 'virtual', 'override', 'sealed' e 'new'.
+
+
+ A partial member cannot have the 'abstract' modifier
+
+
+
+
+ Both partial member declarations, '{0}' and '{1}', must use the same tuple element names.
-
-
- As duas declarações de métodos parciais precisam ser readonly ou nenhuma deve ser readonly
+
+
+ A partial member must be declared within a partial type
-
-
+
+
+ Both partial member declarations must use a params parameter or neither may use a params parameter
+
+
+
+
+ Both partial member declarations must be readonly or neither may be readonly
+
+
+
+
+ As duas declarações de métodos parciais precisam ter combinações idênticas dos modificadores 'virtual', 'override', 'sealed' e 'new'.
+
+
+
+
As declarações de método parcial precisam ter valores de retorno de referência correspondentes.
+
+
+ Both partial member declarations must be unsafe or neither may be unsafe
+
+ As duas declarações de método parcial precisam ter o mesmo tipo de retorno.
@@ -1687,6 +1712,51 @@
O método parcial '{0}' precisa ter modificadores de acessibilidade porque ele tem parâmetros 'out'.
+
+
+ A partial property may not have multiple defining declarations, and cannot be an auto-property.
+
+
+
+
+ A partial property may not have multiple implementing declarations
+
+
+
+
+ Property accessor '{0}' must be '{1}' to match the definition part
+
+
+
+
+ Property accessor '{0}' must be implemented because it is declared on the definition part
+
+
+
+
+ Partial property '{0}' must have a definition part.
+
+
+
+
+ Partial property '{0}' must have an implementation part.
+
+
+
+
+ Both partial property declarations must be required or neither may be required
+
+
+
+
+ Both partial property declarations must have the same type.
+
+
+
+
+ Property accessor '{0}' does not implement any accessor declared on the definition part
+
+ Uma constante cadeia de caracteres 'null' não é suportada como padrão para '{0}'. Use uma cadeia de caracteres vazia em seu lugar.
@@ -1953,8 +2023,8 @@
-
- O modificador 'scoped' do parâmetro '{0}' não corresponde à declaração de método parcial.
+
+ O modificador 'scoped' do parâmetro '{0}' não corresponde à declaração de método parcial.
@@ -3047,6 +3117,16 @@
O parâmetro tem modificador de parâmetros em lambda, mas não no tipo delegado de destino.
+
+
+ Partial property declarations '{0}' and '{1}' have signature differences.
+
+
+
+
+ Partial property declarations have signature differences.
+
+ O parâmetro '{0}' do construtor primário é sombreado por um membro da base.
@@ -4765,12 +4845,12 @@
- A anulabilidade de tipos de referência em tipo de parâmetro '{0}' não corresponde à declaração de método parcial.
+ A anulabilidade de tipos de referência em tipo de parâmetro '{0}' não corresponde à declaração de método parcial.
- A anulabilidade de tipos de referência em tipo de parâmetro não corresponde à declaração de método parcial.
+ A anulabilidade de tipos de referência em tipo de parâmetro não corresponde à declaração de método parcial.
@@ -4815,12 +4895,12 @@
- A nulidade dos tipos de referência no tipo de retorno não corresponde à declaração de método parcial.
+ A nulidade dos tipos de referência no tipo de retorno não corresponde à declaração de método parcial.
- A nulidade dos tipos de referência no tipo de retorno não corresponde à declaração de método parcial.
+ A nulidade dos tipos de referência no tipo de retorno não corresponde à declaração de método parcial.
@@ -6524,8 +6604,8 @@
-
- O modificador 'partial' só pode aparecer imediatamente antes de 'class', de 'record', de 'struct', de 'interface' ou de um tipo de retorno de método.
+
+ O modificador 'partial' só pode aparecer imediatamente antes de 'class', de 'record', de 'struct', de 'interface' ou de um tipo de retorno de método.
@@ -8132,18 +8212,8 @@ Se tal classe for usada como uma classe base e se a classe derivada definir um d
Utilização inconsistente do parâmetro lambda; todos os tipos de parâmetros devem ser explícitos ou implícitos
-
-
- Um método parcial não pode ter o modificador 'abstract'
-
-
-
-
- Um método parcial precisa ser declarado em um tipo parcial
-
-
-
-
+
+
Um método parcial não pode implementar explicitamente um método de interface
@@ -8162,21 +8232,11 @@ Se tal classe for usada como uma classe base e se a classe derivada definir um d
Um método parcial não pode ter várias declarações de implementação
-
-
- As duas declarações do método parcial devem usar um parâmetro params ou nenhuma delas pode usar um parâmetro params
-
- Nenhuma declaração de definição encontrada para implementar a declaração de método parcial "{0}"
-
-
- Ambas as declarações de método parciais, '{0}' e '{1}', devem usar os mesmos elementos de nome de tupla.
-
- Declarações de método parciais de '{0}' têm restrições inconsistentes para o parâmetro de tipo '{1}'
@@ -8187,16 +8247,11 @@ Se tal classe for usada como uma classe base e se a classe derivada definir um d
Não é possível criar representante do método "{0}" porque ele é um método parcial sem declaração de implementação
-
-
+
+
As duas declarações de métodos parciais devem ser estáticas ou nenhuma delas deve ser desse tipo
-
-
- As duas declarações de métodos parciais devem ser inseguras ou nenhuma delas deve ser desse tipo
-
- Os métodos parciais com apenas uma declaração de definição ou métodos condicionais removidos não podem ser usados em árvores de expressão
diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf
index 7bc750767181d..6d5a28f4c0302 100644
--- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf
+++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf
@@ -1642,26 +1642,51 @@
Параметр params должен иметь допустимый тип коллекции.
-
-
- Оба объявления разделяемого метода должны иметь одинаковые модификаторы доступа.
+
+
+ Both partial member declarations must have identical accessibility modifiers.
-
-
- Оба объявления разделяемого метода должны иметь одинаковые сочетания модификаторов "virtual", "override", "sealed" и "new".
+
+
+ A partial member cannot have the 'abstract' modifier
+
+
+
+
+ Both partial member declarations, '{0}' and '{1}', must use the same tuple element names.
-
-
- Либо оба объявления разделяемого метода должны иметь модификатор readonly, либо ни одно из них не должно иметь модификатор readonly.
+
+
+ A partial member must be declared within a partial type
-
-
+
+
+ Both partial member declarations must use a params parameter or neither may use a params parameter
+
+
+
+
+ Both partial member declarations must be readonly or neither may be readonly
+
+
+
+
+ Оба объявления разделяемого метода должны иметь одинаковые сочетания модификаторов "virtual", "override", "sealed" и "new".
+
+
+
+
Объявления разделяемого метода должны иметь одинаковые типы возвращаемого значения ref.
+
+
+ Both partial member declarations must be unsafe or neither may be unsafe
+
+ Оба объявления разделяемого метода должны иметь одинаковый тип возвращаемого значения.
@@ -1687,6 +1712,51 @@
Разделяемый метод "{0}" должен иметь модификаторы доступа, так как он содержит параметры "out".
+
+
+ A partial property may not have multiple defining declarations, and cannot be an auto-property.
+
+
+
+
+ A partial property may not have multiple implementing declarations
+
+
+
+
+ Property accessor '{0}' must be '{1}' to match the definition part
+
+
+
+
+ Property accessor '{0}' must be implemented because it is declared on the definition part
+
+
+
+
+ Partial property '{0}' must have a definition part.
+
+
+
+
+ Partial property '{0}' must have an implementation part.
+
+
+
+
+ Both partial property declarations must be required or neither may be required
+
+
+
+
+ Both partial property declarations must have the same type.
+
+
+
+
+ Property accessor '{0}' does not implement any accessor declared on the definition part
+
+ Строковая константа "null" не поддерживается в качестве шаблона для "{0}". Используйте вместо этого пустую строку.
@@ -1953,8 +2023,8 @@
-
- Модификатор "scoped" параметра "{0}" не соответствует объявлению разделяемого метода.
+
+ Модификатор "scoped" параметра "{0}" не соответствует объявлению разделяемого метода.
@@ -3047,6 +3117,16 @@
У параметра есть модификатор params в лямбде, но не в типе целевого делегата.
+
+
+ Partial property declarations '{0}' and '{1}' have signature differences.
+
+
+
+
+ Partial property declarations have signature differences.
+
+ Параметр "{0}" первичной конструкции затемнен элементом из базы.
@@ -4766,12 +4846,12 @@
- Допустимость значения NULL для ссылочных типов в типе параметра "{0}" не совпадает с частичным объявлением метода.
+ Допустимость значения NULL для ссылочных типов в типе параметра "{0}" не совпадает с частичным объявлением метода.
- Допустимость значения NULL для ссылочных типов в типе параметра не совпадает с частичным объявлением метода.
+ Допустимость значения NULL для ссылочных типов в типе параметра не совпадает с частичным объявлением метода.
@@ -4816,12 +4896,12 @@
- Допустимость значения NULL для ссылочных типов в типе возвращаемого значения не совпадает с объявлением разделяемого метода.
+ Допустимость значения NULL для ссылочных типов в типе возвращаемого значения не совпадает с объявлением разделяемого метода.
- Допустимость значения NULL для ссылочных типов в типе возвращаемого значения не совпадает с объявлением разделяемого метода.
+ Допустимость значения NULL для ссылочных типов в типе возвращаемого значения не совпадает с объявлением разделяемого метода.
@@ -6525,8 +6605,8 @@
-
- Модификатор "partial" может использоваться только перед ключевыми словами "class", "record", "struct" и "interface" и перед возвращаемым типом метода.
+
+ Модификатор "partial" может использоваться только перед ключевыми словами "class", "record", "struct" и "interface" и перед возвращаемым типом метода.
@@ -8133,18 +8213,8 @@ If such a class is used as a base class and if the deriving class defines a dest
Несовместимое использование лямбда-параметра; типы параметров должны быть либо все явными, либо все неявными.
-
-
- Разделяемый метод не может иметь модификатор "abstract".
-
-
-
-
- Разделяемый метод должен быть объявлен в разделяемом типе.
-
-
-
-
+
+
Разделяемый метод не может явно реализовывать метод интерфейса.
@@ -8163,21 +8233,11 @@ If such a class is used as a base class and if the deriving class defines a dest
Разделяемый метод не может иметь несколько реализующих объявлений.
-
-
- Параметр params должен использоваться в обоих объявлениях разделяемого метода или не должен использоваться ни в одном из них.
-
- Отсутствует определяющее объявление для реализующего объявления разделяемого метода "{0}".
-
-
- Оба объявления частичного метода, "{0}" и "{1}", должны использовать одинаковые имена элементов кортежа.
-
- Несогласованные ограничения для параметра типа "{1}" в частичных объявлениях метода "{0}".
@@ -8188,16 +8248,11 @@ If such a class is used as a base class and if the deriving class defines a dest
Невозможно создать делегат на основе метода "{0}, так как он является разделяемым методом без реализующего объявления.
-
-
+
+
Объявления разделяемого метода либо оба должны иметь модификаторы static, либо ни одно из объявлений не должно иметь модификатора static.
-
-
- Либо оба объявления разделяемого метода должны иметь модификаторы unsafe, либо ни одно из объявлений не должно иметь модификатора unsafe.
-
- В деревьях выражений не могут использоваться разделяемые методы, имеющие только определяющее объявление или только удаленные условные методы.
diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf
index 61a78dded475d..830360d27c15b 100644
--- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf
+++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf
@@ -1642,26 +1642,51 @@
Params parametresi geçerli bir koleksiyon türüne sahip olmalıdır
-
-
- Her iki kısmi metot bildirimi aynı erişilebilirlik değiştiricilerine sahip olmalıdır.
+
+
+ Both partial member declarations must have identical accessibility modifiers.
-
-
- Her iki kısmi metot bildirimi 'virtual', 'override', 'sealed' ve 'new' değiştiricilerinde oluşan aynı bileşimlere sahip olmalıdır.
+
+
+ A partial member cannot have the 'abstract' modifier
+
+
+
+
+ Both partial member declarations, '{0}' and '{1}', must use the same tuple element names.
-
-
- İki kısmi yöntem bildiriminin de saltokunur olması ya da hiçbirinin saltokunur olmaması gerekir
+
+
+ A partial member must be declared within a partial type
-
-
+
+
+ Both partial member declarations must use a params parameter or neither may use a params parameter
+
+
+
+
+ Both partial member declarations must be readonly or neither may be readonly
+
+
+
+
+ Her iki kısmi metot bildirimi 'virtual', 'override', 'sealed' ve 'new' değiştiricilerinde oluşan aynı bileşimlere sahip olmalıdır.
+
+
+
+
Kısmi yöntem bildirimlerinin eşleşen başvuru dönüş değerleri olmalıdır.
+
+
+ Both partial member declarations must be unsafe or neither may be unsafe
+
+ Her iki kısmi yöntem bildirimi aynı dönüş türüne sahip olmalıdır.
@@ -1687,6 +1712,51 @@
'{0}' kısmi metodunun 'out' parametreleri olduğundan erişilebilirlik değiştiricileri olmalıdır.
+
+
+ A partial property may not have multiple defining declarations, and cannot be an auto-property.
+
+
+
+
+ A partial property may not have multiple implementing declarations
+
+
+
+
+ Property accessor '{0}' must be '{1}' to match the definition part
+
+
+
+
+ Property accessor '{0}' must be implemented because it is declared on the definition part
+
+
+
+
+ Partial property '{0}' must have a definition part.
+
+
+
+
+ Partial property '{0}' must have an implementation part.
+
+
+
+
+ Both partial property declarations must be required or neither may be required
+
+
+
+
+ Both partial property declarations must have the same type.
+
+
+
+
+ Property accessor '{0}' does not implement any accessor declared on the definition part
+
+ Dize 'null' sabiti, '{0}' için desen olarak desteklenmiyor. Bunun yerine boş bir dize kullanın.
@@ -1953,8 +2023,8 @@
-
- '{0}' parametresinin 'scoped' değiştiricisi, kısmi yöntem bildirimiyle eşleşmiyor.
+
+ '{0}' parametresinin 'scoped' değiştiricisi, kısmi yöntem bildirimiyle eşleşmiyor.
@@ -3047,6 +3117,16 @@
Parametre, lambda içinde parametre değiştiricisi içeriyor ancak hedef temsilci türünde içermiyor.
+
+
+ Partial property declarations '{0}' and '{1}' have signature differences.
+
+
+
+
+ Partial property declarations have signature differences.
+
+ '{0}' birincil oluşturucu parametresi, temel üye tarafından gölgelendi.
@@ -4765,12 +4845,12 @@
- '{0}' parametre türündeki başvuru türlerinin boş değer atanabilirliği kısmi metot bildirimi ile eşleşmiyor.
+ '{0}' parametre türündeki başvuru türlerinin boş değer atanabilirliği kısmi metot bildirimi ile eşleşmiyor.
- Parametre türündeki başvuru türlerinin boş değer atanabilirliği kısmi metot bildirimi ile eşleşmiyor.
+ Parametre türündeki başvuru türlerinin boş değer atanabilirliği kısmi metot bildirimi ile eşleşmiyor.
@@ -4815,12 +4895,12 @@
- Dönüş türündeki başvuru türlerinin null değer atanabilirliği kısmi metot bildirimiyle eşleşmiyor.
+ Dönüş türündeki başvuru türlerinin null değer atanabilirliği kısmi metot bildirimiyle eşleşmiyor.
- Dönüş türündeki başvuru türlerinin null değer atanabilirliği kısmi metot bildirimiyle eşleşmiyor.
+ Dönüş türündeki başvuru türlerinin null değer atanabilirliği kısmi metot bildirimiyle eşleşmiyor.
@@ -6524,8 +6604,8 @@
-
- 'partial' değiştiricisi yalnızca 'class', 'record', 'struct', 'interface' ifadelerinden veya metot dönüş türünden hemen önce gelebilir.
+
+ 'partial' değiştiricisi yalnızca 'class', 'record', 'struct', 'interface' ifadelerinden veya metot dönüş türünden hemen önce gelebilir.
@@ -8132,18 +8212,8 @@ Bu sınıf temel sınıf olarak kullanılırsa ve türetilen sınıf bir yıkıc
Tutarsız lambda parametresi kullanımı; parametre türlerinin tümü explicit veya tümü implicit olmalıdır
-
-
- Kısmi metot 'abstract' değiştiricisine sahip olamaz
-
-
-
-
- Parçalı bir metodun parçalı tür içinde bildirilmesi gerekir
-
-
-
-
+
+
Kısmi bir yöntem bir arabirim yöntemini açık olarak uygulayamaz
@@ -8162,21 +8232,11 @@ Bu sınıf temel sınıf olarak kullanılırsa ve türetilen sınıf bir yıkıc
Kısmi yöntemin birden fazla uygulama bildirimi olamaz
-
-
- Her iki kısmi yöntem bildirimi de bir params parametresi kullanmalı ya da hiçbiri kullanmamalıdır
-
- '{0}' kısmi yönteminin bildirimini uygulamak için tanımlayıcı bildirim bulunamadı
-
-
- Kısmi metot bildirimlerinin ikisi de ('{0}' ve '{1}') aynı demet öğesi adını kullanmalıdır.
-
- '{0}' öğesinin kısmi metot bildirimleri, '{1}' tür parametresi için tutarsız kısıtlamalara sahip
@@ -8187,16 +8247,11 @@ Bu sınıf temel sınıf olarak kullanılırsa ve türetilen sınıf bir yıkıc
Uygulama bildirimi olmayan bir kısmi yöntem olduğundan '{0}' yönteminden temsilci oluşturulamıyor
-
-
+
+
İki kısmi yöntem bildiriminin de statik olması ya da hiçbirinin statik olmaması gerekir
-
-
- İki kısmi yöntem bildiriminin de güvensiz olması ya da hiçbirinin güvensiz olmaması gerekir
-
- Yalnızca bir tanımlama bildirimi olan kısmi yöntemler veya kaldırılmış koşullu yöntemler ifade ağaçlarında kullanılamaz
diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf
index b0175426fa302..10f5f4a9cf404 100644
--- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf
+++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf
@@ -1642,26 +1642,51 @@
Params 参数必须具有有效的集合类型
-
-
- 两个分部方法声明必须具有相同的可访问性修饰符。
+
+
+ Both partial member declarations must have identical accessibility modifiers.
-
-
- 两个分部方法声明必须具有 "virtual"、"override"、"sealed" 和 "new" 修饰符的相同组合。
+
+
+ A partial member cannot have the 'abstract' modifier
+
+
+
+
+ Both partial member declarations, '{0}' and '{1}', must use the same tuple element names.
-
-
- 两个分部方法声明必须都是只读声明,或者两者都不能是只读声明
+
+
+ A partial member must be declared within a partial type
-
-
+
+
+ Both partial member declarations must use a params parameter or neither may use a params parameter
+
+
+
+
+ Both partial member declarations must be readonly or neither may be readonly
+
+
+
+
+ 两个分部方法声明必须具有 "virtual"、"override"、"sealed" 和 "new" 修饰符的相同组合。
+
+
+
+
分部方法声明必须具有匹配的引用返回值。
+
+
+ Both partial member declarations must be unsafe or neither may be unsafe
+
+ 两个分部方法声明必须具有相同的返回类型。
@@ -1687,6 +1712,51 @@
分部方法“{0}”必须具有可访问性修饰符,因为它具有 "out" 参数。
+
+
+ A partial property may not have multiple defining declarations, and cannot be an auto-property.
+
+
+
+
+ A partial property may not have multiple implementing declarations
+
+
+
+
+ Property accessor '{0}' must be '{1}' to match the definition part
+
+
+
+
+ Property accessor '{0}' must be implemented because it is declared on the definition part
+
+
+
+
+ Partial property '{0}' must have a definition part.
+
+
+
+
+ Partial property '{0}' must have an implementation part.
+
+
+
+
+ Both partial property declarations must be required or neither may be required
+
+
+
+
+ Both partial property declarations must have the same type.
+
+
+
+
+ Property accessor '{0}' does not implement any accessor declared on the definition part
+
+ 不支持将字符串 'null' 常量作为 '{0}' 的模式。请改用空字符串。
@@ -1953,8 +2023,8 @@
-
- 参数 "{0}" 的 "scoped" 修饰符与部分方法声明不匹配。
+
+ 参数 "{0}" 的 "scoped" 修饰符与部分方法声明不匹配。
@@ -3047,6 +3117,16 @@
参数在 lambda 中具有参数修饰符,但在目标委托类型中没有参数修饰符。
+
+
+ Partial property declarations '{0}' and '{1}' have signature differences.
+
+
+
+
+ Partial property declarations have signature differences.
+
+ 主要构造函数参数“{0}”由基成员隐藏。
@@ -4765,12 +4845,12 @@
- 参数“{0}”类型中引用类型的为 Null 性与分部方法声明不匹配。
+ 参数“{0}”类型中引用类型的为 Null 性与分部方法声明不匹配。
- 参数类型中引用类型的为 Null 性与分部方法声明不匹配。
+ 参数类型中引用类型的为 Null 性与分部方法声明不匹配。
@@ -4815,12 +4895,12 @@
- 返回类型中引用类型的为 Null 性与分部方法声明不匹配。
+ 返回类型中引用类型的为 Null 性与分部方法声明不匹配。
- 返回类型中引用类型的为 Null 性与分部方法声明不匹配。
+ 返回类型中引用类型的为 Null 性与分部方法声明不匹配。
@@ -6524,8 +6604,8 @@
-
- "partial" 修饰符的后面只能紧跟 "class"、"record"、"struct"、"interface" 或方法返回类型。
+
+ "partial" 修饰符的后面只能紧跟 "class"、"record"、"struct"、"interface" 或方法返回类型。
@@ -8132,18 +8212,8 @@ If such a class is used as a base class and if the deriving class defines a dest
lambda 参数的用法不一致;参数类型必须全部为显式或全部为隐式
-
-
- 分部方法不能具有 "abstract" 修饰符
-
-
-
-
- 分部方法必须在分部类型内声明
-
-
-
-
+
+
分部方法不能显式实现接口方法
@@ -8162,21 +8232,11 @@ If such a class is used as a base class and if the deriving class defines a dest
分部方法不能有多个实现声明
-
-
- 两种分部方法声明必须要么都使用 params 参数,要么都不使用 params 参数
-
- 没有为分部方法“{0}”的实现声明找到定义声明
-
-
- 两种分部方法声明(“{0}”和“{1}”)都必须使用相同的元组元素名称。
-
- “{0}”的分部方法声明对类型参数“{1}”的约束不一致
@@ -8187,16 +8247,11 @@ If such a class is used as a base class and if the deriving class defines a dest
无法通过方法“{0}”创建委托,因为该方法是没有实现声明的分部方法
-
-
+
+
两个分部方法声明必须都是静态声明,或者两者都不能是静态声明
-
-
- 两个分部方法声明必须都是不安全声明,或者两者都不能是不安全声明
-
- 不能在表达式树中使用只有定义声明的分部方法或已移除的条件方法
diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf
index 59932f5945760..17836b6cf64a1 100644
--- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf
+++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf
@@ -1642,26 +1642,51 @@
params 參數必須具有有效的集合型別
-
-
- 兩個部分方法宣告都必須有完全相同的存取範圍修飾詞。
+
+
+ Both partial member declarations must have identical accessibility modifiers.
-
-
- 兩個部分方法宣告都必須有完全相同的 'virtual'、'override'、'sealed' 及 'new' 修飾元組合。
+
+
+ A partial member cannot have the 'abstract' modifier
+
+
+
+
+ Both partial member declarations, '{0}' and '{1}', must use the same tuple element names.
-
-
- 兩個部份方法宣告必須都為唯讀,或者都不為唯讀
+
+
+ A partial member must be declared within a partial type
-
-
+
+
+ Both partial member declarations must use a params parameter or neither may use a params parameter
+
+
+
+
+ Both partial member declarations must be readonly or neither may be readonly
+
+
+
+
+ 兩個部分方法宣告都必須有完全相同的 'virtual'、'override'、'sealed' 及 'new' 修飾元組合。
+
+
+
+
部分方法宣告必須有相符的參考傳回值。
+
+
+ Both partial member declarations must be unsafe or neither may be unsafe
+
+ 兩個部分方法宣告都必須有相同的傳回型別。
@@ -1687,6 +1712,51 @@
因為部分方法 '{0}' 有 'out' 參數,所以其必須有存取範圍修飾詞。
+
+
+ A partial property may not have multiple defining declarations, and cannot be an auto-property.
+
+
+
+
+ A partial property may not have multiple implementing declarations
+
+
+
+
+ Property accessor '{0}' must be '{1}' to match the definition part
+
+
+
+
+ Property accessor '{0}' must be implemented because it is declared on the definition part
+
+
+
+
+ Partial property '{0}' must have a definition part.
+
+
+
+
+ Partial property '{0}' must have an implementation part.
+
+
+
+
+ Both partial property declarations must be required or neither may be required
+
+
+
+
+ Both partial property declarations must have the same type.
+
+
+
+
+ Property accessor '{0}' does not implement any accessor declared on the definition part
+
+ 不支援字串 'null' 常數做為 '{0}' 的模式。請改為使用空字串。
@@ -1953,8 +2023,8 @@
-
- 參數 '{0}' 的 'scoped' 修飾元不符合部分方法宣告。
+
+ 參數 '{0}' 的 'scoped' 修飾元不符合部分方法宣告。
@@ -3047,6 +3117,16 @@
參數在 Lambda 中具有參數修飾元,但不在目標委派類型中。
+
+
+ Partial property declarations '{0}' and '{1}' have signature differences.
+
+
+
+
+ Partial property declarations have signature differences.
+
+ 主要建構函式參數 '{0}' 會伴隨著來自基底的成員。
@@ -4765,12 +4845,12 @@ strument:TestCoverage 產生檢測要收集
- 參數 '{0}' 型別中參考型別的可 Null 性與部分方法宣告不符合。
+ 參數 '{0}' 型別中參考型別的可 Null 性與部分方法宣告不符合。
- 參數型別中參考型別的可 Null 性與部分方法宣告不符合。
+ 參數型別中參考型別的可 Null 性與部分方法宣告不符合。
@@ -4815,12 +4895,12 @@ strument:TestCoverage 產生檢測要收集
- 傳回型別中參考型別的可 Null 性與部分方法宣告不符。
+ 傳回型別中參考型別的可 Null 性與部分方法宣告不符。
- 傳回型別中參考型別的可 Null 性與部分方法宣告不符。
+ 傳回型別中參考型別的可 Null 性與部分方法宣告不符。
@@ -6524,8 +6604,8 @@ strument:TestCoverage 產生檢測要收集
-
- 'partial' 修飾元只可緊接在 'class'、'record'、'struct'、'interface' 或方法傳回型別之前。
+
+ 'partial' 修飾元只可緊接在 'class'、'record'、'struct'、'interface' 或方法傳回型別之前。
@@ -8132,18 +8212,8 @@ If such a class is used as a base class and if the deriving class defines a dest
Lambda 參數用法不一致; 參數類型必須全部為明確類型或全部為隱含類型
-
-
- 部分方法不能有 'abstract' 修飾元
-
-
-
-
- 在部分型別中必須宣告部分方法
-
-
-
-
+
+
部分方法不可明確地實作介面方法
@@ -8162,21 +8232,11 @@ If such a class is used as a base class and if the deriving class defines a dest
部分方法不能有多重實作的宣告
-
-
- 兩個部分方法宣告都必須使用 params 參數,或兩者都不使用 params 參數
-
- 找不到用以實作部分方法 '{0}' 宣告的定義宣告
-
-
- 部份方法宣告 '{0}' 與 '{1}' 必須使用相同的元組元素名稱。
-
- '{0}' 的部分方法宣告對型別參數 '{1}' 有不一致的條件約束
@@ -8187,16 +8247,11 @@ If such a class is used as a base class and if the deriving class defines a dest
無法從方法 '{0}' 建立委派,因為它是無實作宣告的部分方法
-
-
+
+
兩個部分方法宣告必須都是靜態,或者都不是靜態
-
-
- 兩個部分方法宣告必須都是 unsafe,或者都不是 unsafe
-
- 在運算式樹狀結構中,不可使用只具有定義宣告或已移除條件式方法的部分方法
diff --git a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenTupleTest.cs b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenTupleTest.cs
index 7f3182aab7847..936f8a364de18 100644
--- a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenTupleTest.cs
+++ b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenTupleTest.cs
@@ -21007,15 +21007,15 @@ partial void M3((int a, int b) y) { }
";
var comp = CreateCompilation(source);
comp.VerifyDiagnostics(
- // (10,18): error CS8142: Both partial method declarations, 'C.M1((int a, int b))' and 'C.M1((int notA, int notB))', must use the same tuple element names.
+ // (10,18): error CS8142: Both partial member declarations, 'C.M1((int a, int b))' and 'C.M1((int notA, int notB))', must use the same tuple element names.
// partial void M1((int notA, int notB) y) { }
- Diagnostic(ErrorCode.ERR_PartialMethodInconsistentTupleNames, "M1").WithArguments("C.M1((int a, int b))", "C.M1((int notA, int notB))").WithLocation(10, 18),
+ Diagnostic(ErrorCode.ERR_PartialMemberInconsistentTupleNames, "M1").WithArguments("C.M1((int a, int b))", "C.M1((int notA, int notB))").WithLocation(10, 18),
// (10,18): warning CS8826: Partial method declarations 'void C.M1((int a, int b) x)' and 'void C.M1((int notA, int notB) y)' have signature differences.
// partial void M1((int notA, int notB) y) { }
Diagnostic(ErrorCode.WRN_PartialMethodTypeDifference, "M1").WithArguments("void C.M1((int a, int b) x)", "void C.M1((int notA, int notB) y)").WithLocation(10, 18),
- // (11,18): error CS8142: Both partial method declarations, 'C.M2((int a, int b))' and 'C.M2((int, int))', must use the same tuple element names.
+ // (11,18): error CS8142: Both partial member declarations, 'C.M2((int a, int b))' and 'C.M2((int, int))', must use the same tuple element names.
// partial void M2((int, int) y) { }
- Diagnostic(ErrorCode.ERR_PartialMethodInconsistentTupleNames, "M2").WithArguments("C.M2((int a, int b))", "C.M2((int, int))").WithLocation(11, 18),
+ Diagnostic(ErrorCode.ERR_PartialMemberInconsistentTupleNames, "M2").WithArguments("C.M2((int a, int b))", "C.M2((int, int))").WithLocation(11, 18),
// (11,18): warning CS8826: Partial method declarations 'void C.M2((int a, int b) x)' and 'void C.M2((int, int) y)' have signature differences.
// partial void M2((int, int) y) { }
Diagnostic(ErrorCode.WRN_PartialMethodTypeDifference, "M2").WithArguments("void C.M2((int a, int b) x)", "void C.M2((int, int) y)").WithLocation(11, 18),
diff --git a/src/Compilers/CSharp/Test/Emit/CodeGen/SwitchTests.cs b/src/Compilers/CSharp/Test/Emit/CodeGen/SwitchTests.cs
index f3e87f6d8dee1..bb837a94bb3fc 100644
--- a/src/Compilers/CSharp/Test/Emit/CodeGen/SwitchTests.cs
+++ b/src/Compilers/CSharp/Test/Emit/CodeGen/SwitchTests.cs
@@ -5262,20 +5262,20 @@ internal enum ErrorCode
ERR_InvalidAnonymousTypeMemberDeclarator = 746,
ERR_InvalidInitializerElementInitializer = 747,
ERR_InconsistentLambdaParameterUsage = 748,
- ERR_PartialMethodInvalidModifier = 750,
- ERR_PartialMethodOnlyInPartialClass = 751,
+ ERR_PartialMemberCannotBeAbstract = 750,
+ ERR_PartialMemberOnlyInPartialClass = 751,
ERR_PartialMethodCannotHaveOutParameters = 752,
ERR_PartialMethodOnlyMethods = 753,
- ERR_PartialMethodNotExplicit = 754,
+ ERR_PartialMemberNotExplicit = 754,
ERR_PartialMethodExtensionDifference = 755,
ERR_PartialMethodOnlyOneLatent = 756,
ERR_PartialMethodOnlyOneActual = 757,
- ERR_PartialMethodParamsDifference = 758,
+ ERR_PartialMemberParamsDifference = 758,
ERR_PartialMethodMustHaveLatent = 759,
ERR_PartialMethodInconsistentConstraints = 761,
ERR_PartialMethodToDelegate = 762,
- ERR_PartialMethodStaticDifference = 763,
- ERR_PartialMethodUnsafeDifference = 764,
+ ERR_PartialMemberStaticDifference = 763,
+ ERR_PartialMemberUnsafeDifference = 764,
ERR_PartialMethodInExpressionTree = 765,
ERR_PartialMethodMustReturnVoid = 766,
ERR_ExplicitImplCollisionOnRefOut = 767,
diff --git a/src/Compilers/CSharp/Test/Emit/PrivateProtected.cs b/src/Compilers/CSharp/Test/Emit/PrivateProtected.cs
index 059a107ff10ba..9f1745a691031 100644
--- a/src/Compilers/CSharp/Test/Emit/PrivateProtected.cs
+++ b/src/Compilers/CSharp/Test/Emit/PrivateProtected.cs
@@ -523,10 +523,7 @@ private public interface I {} // 8
Diagnostic(ErrorCode.ERR_BadMemberProtection, "V").WithLocation(10, 40),
// (12,24): error CS0107: More than one protection modifier
// private public int this[int index] => 1; // 9
- Diagnostic(ErrorCode.ERR_BadMemberProtection, "this").WithLocation(12, 24),
- // (12,43): error CS0107: More than one protection modifier
- // private public int this[int index] => 1; // 9
- Diagnostic(ErrorCode.ERR_BadMemberProtection, "1").WithLocation(12, 43)
+ Diagnostic(ErrorCode.ERR_BadMemberProtection, "this").WithLocation(12, 24)
);
}
diff --git a/src/Compilers/CSharp/Test/Emit2/Attributes/AttributeTests_CallerInfoAttributes.cs b/src/Compilers/CSharp/Test/Emit2/Attributes/AttributeTests_CallerInfoAttributes.cs
index dd9319f97b459..bf4053c6fd9f2 100644
--- a/src/Compilers/CSharp/Test/Emit2/Attributes/AttributeTests_CallerInfoAttributes.cs
+++ b/src/Compilers/CSharp/Test/Emit2/Attributes/AttributeTests_CallerInfoAttributes.cs
@@ -3231,6 +3231,19 @@ public static void Main()
// (14,10): warning CS4025: The CallerFilePathAttribute applied to parameter 'path' will have no effect because it applies to a member that is used in contexts that do not allow optional arguments
// [CallerFilePath] string path) { }
Diagnostic(ErrorCode.WRN_CallerFilePathParamForUnconsumedLocation, "CallerFilePath").WithArguments("path"));
+
+ CompileAndVerify(source, options: TestOptions.DebugExe.WithMetadataImportOptions(MetadataImportOptions.All), symbolValidator: verify);
+
+ void verify(ModuleSymbol module)
+ {
+ // https://github.com/dotnet/roslyn/issues/73482
+ // These are ignored in source but they still get written out to metadata.
+ // This means if the method is accessible from another compilation, then the attribute will be respected there, but not in the declaring compilation.
+ var goo = module.GlobalNamespace.GetMember("D.Goo");
+ AssertEx.Equal(["System.Runtime.CompilerServices.CallerLineNumberAttribute"], goo.Parameters[0].GetAttributes().SelectAsArray(attr => attr.ToString()));
+ AssertEx.Equal(["System.Runtime.CompilerServices.CallerMemberNameAttribute"], goo.Parameters[1].GetAttributes().SelectAsArray(attr => attr.ToString()));
+ AssertEx.Equal(["System.Runtime.CompilerServices.CallerFilePathAttribute"], goo.Parameters[2].GetAttributes().SelectAsArray(attr => attr.ToString()));
+ }
}
[Fact]
@@ -5836,5 +5849,106 @@ public CallerArgumentExpressionAttribute([CallerArgumentExpression(nameof(parame
// public CallerArgumentExpressionAttribute([CallerArgumentExpression(nameof(parameterName))] string parameterName)
Diagnostic(ErrorCode.ERR_BadCallerArgumentExpressionParamWithoutDefaultValue, "CallerArgumentExpression").WithLocation(5, 51));
}
+
+ [Fact]
+ public void CallerMemberName_SetterValueParam()
+ {
+ // There is no way in C# to call a setter without passing an argument for the value, so the CallerMemberName effectively does nothing.
+ var source = """
+ using System;
+ using System.Runtime.CompilerServices;
+ using System.Runtime.InteropServices;
+
+ public partial class C
+ {
+ public static void Main()
+ {
+ var c = new C();
+ c[1] = "1";
+ }
+
+ public string this[int x]
+ {
+ [param: Optional, DefaultParameterValue("0")]
+ [param: CallerMemberName]
+ set
+ {
+ Console.Write(value);
+ }
+ }
+ }
+ """;
+
+ var verifier = CompileAndVerify(source, expectedOutput: "1");
+ verifier.VerifyDiagnostics();
+
+ var source1 = """
+ class D
+ {
+ void M()
+ {
+ var c = new C();
+ c.set_Item(1);
+ }
+ }
+ """;
+ var comp1 = CreateCompilation(source1, references: [verifier.Compilation.EmitToImageReference()]);
+ comp1.VerifyEmitDiagnostics(
+ // (6,11): error CS0571: 'C.this[int].set': cannot explicitly call operator or accessor
+ // c.set_Item(1);
+ Diagnostic(ErrorCode.ERR_CantCallSpecialMethod, "set_Item").WithArguments("C.this[int].set").WithLocation(6, 11));
+ }
+
+ [Fact]
+ public void CallerArgumentExpression_SetterValueParam()
+ {
+ var source = """
+ using System;
+ using System.Runtime.CompilerServices;
+
+ namespace System.Runtime.CompilerServices
+ {
+ [AttributeUsage(AttributeTargets.Parameter, AllowMultiple = true, Inherited = false)]
+ public sealed class CallerArgumentExpressionAttribute : Attribute
+ {
+ public CallerArgumentExpressionAttribute(string parameterName)
+ {
+ ParameterName = parameterName;
+ }
+ public string ParameterName { get; }
+ }
+ }
+
+ partial class C
+ {
+ public static void Main()
+ {
+ var c = new C();
+ c[1] = GetNumber();
+ }
+
+ public static int GetNumber() => 1;
+
+ public int this[int x, [CallerArgumentExpression("value")] string argumentExpression = "0"]
+ {
+ set
+ {
+ Console.Write(argumentExpression);
+ }
+ }
+ }
+ """;
+ var verifier = CompileAndVerify(source, expectedOutput: "0", symbolValidator: verify);
+ verifier.VerifyDiagnostics(
+ // (27,29): warning CS8963: The CallerArgumentExpressionAttribute applied to parameter 'argumentExpression' will have no effect. It is applied with an invalid parameter name.
+ // public int this[int x, [CallerArgumentExpression("value")] string argumentExpression = "0"]
+ Diagnostic(ErrorCode.WRN_CallerArgumentExpressionAttributeHasInvalidParameterName, "CallerArgumentExpression").WithArguments("argumentExpression").WithLocation(27, 29));
+
+ void verify(ModuleSymbol module)
+ {
+ var indexer = (PropertySymbol)module.GlobalNamespace.GetMember("C").Indexers.Single();
+ AssertEx.Equal(["""System.Runtime.CompilerServices.CallerArgumentExpressionAttribute("value")"""], indexer.Parameters[1].GetAttributes().SelectAsArray(attr => attr.ToString()));
+ }
+ }
}
}
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/Emit2/Diagnostics/GetDiagnosticsTests.cs b/src/Compilers/CSharp/Test/Emit2/Diagnostics/GetDiagnosticsTests.cs
index 0d264412df26c..92cfc8eb21ea7 100644
--- a/src/Compilers/CSharp/Test/Emit2/Diagnostics/GetDiagnosticsTests.cs
+++ b/src/Compilers/CSharp/Test/Emit2/Diagnostics/GetDiagnosticsTests.cs
@@ -238,6 +238,69 @@ partial void PartialMethod() { }
Assert.True(completedCompilationUnits.Contains(tree1.FilePath));
}
+ [Fact]
+ public void TestCompilationEventsForPartialProperty()
+ {
+ var source1 = @"
+namespace N1
+{
+ partial class Class
+ {
+ int NonPartialProp1 { get; set; }
+ partial int DefOnlyPartialProp { get; set; }
+ partial int ImplOnlyPartialProp { get => 1; set { } }
+ partial int PartialProp { get; set; }
+ }
+}
+";
+ var source2 = @"
+namespace N1
+{
+ partial class Class
+ {
+ int NonPartialProp2 { get; set; }
+ partial int PartialProp { get => 1; set { } }
+ }
+}
+";
+
+ var tree1 = CSharpSyntaxTree.ParseText(source1, path: "file1");
+ var tree2 = CSharpSyntaxTree.ParseText(source2, path: "file2");
+ var eventQueue = new AsyncQueue();
+ var compilation = CreateCompilationWithMscorlib45(new[] { tree1, tree2 }).WithEventQueue(eventQueue);
+
+ // Invoke SemanticModel.GetDiagnostics to force populate the event queue for symbols in the first source file.
+ var model = compilation.GetSemanticModel(tree1);
+ model.GetDiagnostics(tree1.GetRoot().FullSpan);
+
+ Assert.True(eventQueue.Count > 0);
+ bool compilationStartedFired;
+ HashSet declaredSymbolNames, completedCompilationUnits;
+ Assert.True(DequeueCompilationEvents(eventQueue, out compilationStartedFired, out declaredSymbolNames, out completedCompilationUnits));
+
+ // Verify symbol declared events fired for all symbols declared in the first source file.
+ Assert.True(compilationStartedFired);
+
+ // NB: NonPartialProp2 is missing here because we only asked for diagnostics in tree1
+ AssertEx.Equal([
+ "",
+ "Class",
+ "DefOnlyPartialProp",
+ "get_ImplOnlyPartialProp",
+ "get_NonPartialProp1",
+ "get_PartialProp",
+ "ImplOnlyPartialProp",
+ "N1",
+ "NonPartialProp1",
+ "PartialProp",
+ "set_ImplOnlyPartialProp",
+ "set_NonPartialProp1",
+ "set_PartialProp"
+ ], declaredSymbolNames.OrderBy(name => name));
+
+ AssertEx.Equal(["file1"], completedCompilationUnits.OrderBy(name => name));
+ }
+
[Fact, WorkItem(8178, "https://github.com/dotnet/roslyn/issues/8178")]
public void TestEarlyCancellation()
{
@@ -286,12 +349,7 @@ private static bool DequeueCompilationEvents(AsyncQueue eventQ
var added = declaredSymbolNames.Add(symbol.Name);
if (!added)
{
- var method = symbol.GetSymbol() as Symbols.MethodSymbol;
- Assert.NotNull(method);
-
- var isPartialMethod = method.PartialDefinitionPart != null ||
- method.PartialImplementationPart != null;
- Assert.True(isPartialMethod, "Unexpected multiple symbol declared events for symbol " + symbol);
+ Assert.True(symbol.GetSymbol().IsPartialMember(), "Unexpected multiple symbol declared events for symbol " + symbol);
}
}
else
diff --git a/src/Compilers/CSharp/Test/Emit2/Semantics/ParamsCollectionTests.cs b/src/Compilers/CSharp/Test/Emit2/Semantics/ParamsCollectionTests.cs
index f36059c8f8684..e8aa55df720ae 100644
--- a/src/Compilers/CSharp/Test/Emit2/Semantics/ParamsCollectionTests.cs
+++ b/src/Compilers/CSharp/Test/Emit2/Semantics/ParamsCollectionTests.cs
@@ -9835,19 +9835,19 @@ partial void Test3(scoped Span a)
Assert.NotEqual(comp.GetMember("C1.Test3").Parameters.Single().EffectiveScope, comp.GetMember("C1.Test3").PartialImplementationPart.Parameters.Single().EffectiveScope);
comp.VerifyDiagnostics(
- // (13,18): error CS0758: Both partial method declarations must use a params parameter or neither may use a params parameter
+ // (13,18): error CS0758: Both partial member declarations must use a params parameter or neither may use a params parameter
// partial void Test1(params Span a)
- Diagnostic(ErrorCode.ERR_PartialMethodParamsDifference, "Test1").WithLocation(13, 18),
- // (13,18): error CS8988: The 'scoped' modifier of parameter 'a' doesn't match partial method declaration.
+ Diagnostic(ErrorCode.ERR_PartialMemberParamsDifference, "Test1").WithLocation(13, 18),
+ // (13,18): error CS8988: The 'scoped' modifier of parameter 'a' doesn't match partial definition.
// partial void Test1(params Span a)
Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfPartial, "Test1").WithArguments("a").WithLocation(13, 18),
- // (17,18): error CS0758: Both partial method declarations must use a params parameter or neither may use a params parameter
+ // (17,18): error CS0758: Both partial member declarations must use a params parameter or neither may use a params parameter
// partial void Test2(params scoped Span a)
- Diagnostic(ErrorCode.ERR_PartialMethodParamsDifference, "Test2").WithLocation(17, 18),
- // (17,18): error CS8988: The 'scoped' modifier of parameter 'a' doesn't match partial method declaration.
+ Diagnostic(ErrorCode.ERR_PartialMemberParamsDifference, "Test2").WithLocation(17, 18),
+ // (17,18): error CS8988: The 'scoped' modifier of parameter 'a' doesn't match partial definition.
// partial void Test2(params scoped Span a)
Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfPartial, "Test2").WithArguments("a").WithLocation(17, 18),
- // (21,18): error CS8988: The 'scoped' modifier of parameter 'a' doesn't match partial method declaration.
+ // (21,18): error CS8988: The 'scoped' modifier of parameter 'a' doesn't match partial definition.
// partial void Test3(scoped Span a)
Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfPartial, "Test3").WithArguments("a").WithLocation(21, 18)
);
@@ -9888,19 +9888,19 @@ partial void Test3(Span a)
Assert.NotEqual(comp.GetMember("C1.Test3").Parameters.Single().EffectiveScope, comp.GetMember("C1.Test3").PartialImplementationPart.Parameters.Single().EffectiveScope);
comp.VerifyDiagnostics(
- // (13,18): error CS0758: Both partial method declarations must use a params parameter or neither may use a params parameter
+ // (13,18): error CS0758: Both partial member declarations must use a params parameter or neither may use a params parameter
// partial void Test1(Span a)
- Diagnostic(ErrorCode.ERR_PartialMethodParamsDifference, "Test1").WithLocation(13, 18),
- // (13,18): error CS8988: The 'scoped' modifier of parameter 'a' doesn't match partial method declaration.
+ Diagnostic(ErrorCode.ERR_PartialMemberParamsDifference, "Test1").WithLocation(13, 18),
+ // (13,18): error CS8988: The 'scoped' modifier of parameter 'a' doesn't match partial definition.
// partial void Test1(Span a)
Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfPartial, "Test1").WithArguments("a").WithLocation(13, 18),
- // (17,18): error CS0758: Both partial method declarations must use a params parameter or neither may use a params parameter
+ // (17,18): error CS0758: Both partial member declarations must use a params parameter or neither may use a params parameter
// partial void Test2(Span a)
- Diagnostic(ErrorCode.ERR_PartialMethodParamsDifference, "Test2").WithLocation(17, 18),
- // (17,18): error CS8988: The 'scoped' modifier of parameter 'a' doesn't match partial method declaration.
+ Diagnostic(ErrorCode.ERR_PartialMemberParamsDifference, "Test2").WithLocation(17, 18),
+ // (17,18): error CS8988: The 'scoped' modifier of parameter 'a' doesn't match partial definition.
// partial void Test2(Span a)
Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfPartial, "Test2").WithArguments("a").WithLocation(17, 18),
- // (21,18): error CS8988: The 'scoped' modifier of parameter 'a' doesn't match partial method declaration.
+ // (21,18): error CS8988: The 'scoped' modifier of parameter 'a' doesn't match partial definition.
// partial void Test3(Span a)
Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfPartial, "Test3").WithArguments("a").WithLocation(21, 18)
);
@@ -9947,15 +9947,15 @@ partial void Test3([UnscopedRef] Span a)
Assert.Equal(comp.GetMember("C1.Test3").Parameters.Single().EffectiveScope, comp.GetMember("C1.Test3").PartialImplementationPart.Parameters.Single().EffectiveScope);
comp.VerifyDiagnostics(
- // (14,18): error CS0758: Both partial method declarations must use a params parameter or neither may use a params parameter
+ // (14,18): error CS0758: Both partial member declarations must use a params parameter or neither may use a params parameter
// partial void Test1([UnscopedRef] Span a)
- Diagnostic(ErrorCode.ERR_PartialMethodParamsDifference, "Test1").WithLocation(14, 18),
+ Diagnostic(ErrorCode.ERR_PartialMemberParamsDifference, "Test1").WithLocation(14, 18),
// (14,25): error CS9063: UnscopedRefAttribute cannot be applied to this parameter because it is unscoped by default.
// partial void Test1([UnscopedRef] Span a)
Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedTarget, "UnscopedRef").WithLocation(14, 25),
- // (18,18): error CS0758: Both partial method declarations must use a params parameter or neither may use a params parameter
+ // (18,18): error CS0758: Both partial member declarations must use a params parameter or neither may use a params parameter
// partial void Test2([UnscopedRef] Span a)
- Diagnostic(ErrorCode.ERR_PartialMethodParamsDifference, "Test2").WithLocation(18, 18),
+ Diagnostic(ErrorCode.ERR_PartialMemberParamsDifference, "Test2").WithLocation(18, 18),
// (18,25): error CS9063: UnscopedRefAttribute cannot be applied to this parameter because it is unscoped by default.
// partial void Test2([UnscopedRef] Span a)
Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedTarget, "UnscopedRef").WithLocation(18, 25),
@@ -10006,9 +10006,9 @@ public partial Span Test3([UnscopedRef] params Span a)
Assert.Equal(comp.GetMember("C1.Test3").Parameters.Single().EffectiveScope, comp.GetMember("C1.Test3").PartialImplementationPart.Parameters.Single().EffectiveScope);
comp.VerifyDiagnostics(
- // (20,31): error CS0758: Both partial method declarations must use a params parameter or neither may use a params parameter
+ // (20,31): error CS0758: Both partial member declarations must use a params parameter or neither may use a params parameter
// public partial Span Test3([UnscopedRef] params Span a)
- Diagnostic(ErrorCode.ERR_PartialMethodParamsDifference, "Test3").WithLocation(20, 31)
+ Diagnostic(ErrorCode.ERR_PartialMemberParamsDifference, "Test3").WithLocation(20, 31)
);
}
@@ -14435,18 +14435,18 @@ partial void Test3(int a)
// (5,24): error CS0225: The params parameter must have a valid collection type
// partial void Test1(params int a)
Diagnostic(ErrorCode.ERR_ParamsMustBeCollection, "params").WithLocation(5, 24),
- // (11,18): error CS0758: Both partial method declarations must use a params parameter or neither may use a params parameter
+ // (11,18): error CS0758: Both partial member declarations must use a params parameter or neither may use a params parameter
// partial void Test2(params int a)
- Diagnostic(ErrorCode.ERR_PartialMethodParamsDifference, "Test2").WithLocation(11, 18),
+ Diagnostic(ErrorCode.ERR_PartialMemberParamsDifference, "Test2").WithLocation(11, 18),
// (11,24): error CS0225: The params parameter must have a valid collection type
// partial void Test2(params int a)
Diagnostic(ErrorCode.ERR_ParamsMustBeCollection, "params").WithLocation(11, 24),
// (15,24): error CS0225: The params parameter must have a valid collection type
// partial void Test3(params int a);
Diagnostic(ErrorCode.ERR_ParamsMustBeCollection, "params").WithLocation(15, 24),
- // (17,18): error CS0758: Both partial method declarations must use a params parameter or neither may use a params parameter
+ // (17,18): error CS0758: Both partial member declarations must use a params parameter or neither may use a params parameter
// partial void Test3(int a)
- Diagnostic(ErrorCode.ERR_PartialMethodParamsDifference, "Test3").WithLocation(17, 18)
+ Diagnostic(ErrorCode.ERR_PartialMemberParamsDifference, "Test3").WithLocation(17, 18)
);
}
diff --git a/src/Compilers/CSharp/Test/Emit2/Semantics/RecordTests.cs b/src/Compilers/CSharp/Test/Emit2/Semantics/RecordTests.cs
index 12b140332a903..fc5a188c754b5 100644
--- a/src/Compilers/CSharp/Test/Emit2/Semantics/RecordTests.cs
+++ b/src/Compilers/CSharp/Test/Emit2/Semantics/RecordTests.cs
@@ -19236,9 +19236,6 @@ protected virtual System.Type EqualityContract
// (10,27): error CS8879: Record member 'B.EqualityContract' must be private.
// protected System.Type EqualityContract
Diagnostic(ErrorCode.ERR_NonPrivateAPIInRecord, "EqualityContract").WithArguments("B.EqualityContract").WithLocation(10, 27),
- // (11,12): warning CS0628: 'B.EqualityContract.get': new protected member declared in sealed type
- // => throw null;
- Diagnostic(ErrorCode.WRN_ProtectedInSealed, "throw null").WithArguments("B.EqualityContract.get").WithLocation(11, 12),
// (16,35): warning CS0628: 'C.EqualityContract': new protected member declared in sealed type
// protected virtual System.Type EqualityContract
Diagnostic(ErrorCode.WRN_ProtectedInSealed, "EqualityContract").WithArguments("C.EqualityContract").WithLocation(16, 35),
@@ -19321,9 +19318,6 @@ protected sealed override System.Type EqualityContract
// (13,27): warning CS0114: 'C.EqualityContract' hides inherited member 'A.EqualityContract'. To make the current member override that implementation, add the override keyword. Otherwise add the new keyword.
// protected System.Type EqualityContract
Diagnostic(ErrorCode.WRN_NewOrOverrideExpected, "EqualityContract").WithArguments("C.EqualityContract", "A.EqualityContract").WithLocation(13, 27),
- // (14,12): warning CS0628: 'C.EqualityContract.get': new protected member declared in sealed type
- // => throw null;
- Diagnostic(ErrorCode.WRN_ProtectedInSealed, "throw null").WithArguments("C.EqualityContract.get").WithLocation(14, 12),
// (19,35): warning CS0628: 'D.EqualityContract': new protected member declared in sealed type
// protected virtual System.Type EqualityContract
Diagnostic(ErrorCode.WRN_ProtectedInSealed, "EqualityContract").WithArguments("D.EqualityContract").WithLocation(19, 35),
@@ -19997,10 +19991,7 @@ public void EqualityContract_19()
Diagnostic(ErrorCode.ERR_NonPrivateAPIInRecord, "EqualityContract").WithArguments("A.EqualityContract").WithLocation(3, 34),
// (3,34): error CS8877: Record member 'A.EqualityContract' may not be static.
// protected static System.Type EqualityContract => throw null;
- Diagnostic(ErrorCode.ERR_StaticAPIInRecord, "EqualityContract").WithArguments("A.EqualityContract").WithLocation(3, 34),
- // (3,54): warning CS0628: 'A.EqualityContract.get': new protected member declared in sealed type
- // protected static System.Type EqualityContract => throw null;
- Diagnostic(ErrorCode.WRN_ProtectedInSealed, "throw null").WithArguments("A.EqualityContract.get").WithLocation(3, 54)
+ Diagnostic(ErrorCode.ERR_StaticAPIInRecord, "EqualityContract").WithArguments("A.EqualityContract").WithLocation(3, 34)
);
}
@@ -26049,9 +26040,9 @@ public void RecordWithPartialMethodExplicitImplementation()
partial void M();
}";
CreateCompilation(source).VerifyDiagnostics(
- // (3,18): error CS0751: A partial method must be declared within a partial type
+ // (3,18): error CS0751: A partial member must be declared within a partial type
// partial void M();
- Diagnostic(ErrorCode.ERR_PartialMethodOnlyInPartialClass, "M").WithLocation(3, 18)
+ Diagnostic(ErrorCode.ERR_PartialMemberOnlyInPartialClass, "M").WithLocation(3, 18)
);
}
diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/BindingTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/BindingTests.cs
index ce4baa3ec6c98..141b23ed071f5 100644
--- a/src/Compilers/CSharp/Test/Semantic/Semantics/BindingTests.cs
+++ b/src/Compilers/CSharp/Test/Semantic/Semantics/BindingTests.cs
@@ -2210,12 +2210,12 @@ public void InterfaceWithPartialMethodExplicitImplementation()
partial void I.M();
}";
CreateCompilation(source, parseOptions: TestOptions.Regular7, targetFramework: TargetFramework.NetCoreApp).VerifyDiagnostics(
- // (3,20): error CS0754: A partial method may not explicitly implement an interface method
+ // (3,20): error CS0754: A partial member may not explicitly implement an interface member
// partial void I.M();
- Diagnostic(ErrorCode.ERR_PartialMethodNotExplicit, "M").WithLocation(3, 20),
- // (3,20): error CS0751: A partial method must be declared within a partial type
+ Diagnostic(ErrorCode.ERR_PartialMemberNotExplicit, "M").WithLocation(3, 20),
+ // (3,20): error CS0751: A partial member must be declared within a partial type
// partial void I.M();
- Diagnostic(ErrorCode.ERR_PartialMethodOnlyInPartialClass, "M").WithLocation(3, 20),
+ Diagnostic(ErrorCode.ERR_PartialMemberOnlyInPartialClass, "M").WithLocation(3, 20),
// (3,20): error CS8652: The feature 'default interface implementation' is not available in C# 7.0. Please use language version 8.0 or greater.
// partial void I.M();
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7, "M").WithArguments("default interface implementation", "8.0").WithLocation(3, 20),
diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/InheritanceBindingTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/InheritanceBindingTests.cs
index 148527fd407a4..bcd93d2fedcf3 100644
--- a/src/Compilers/CSharp/Test/Semantic/Semantics/InheritanceBindingTests.cs
+++ b/src/Compilers/CSharp/Test/Semantic/Semantics/InheritanceBindingTests.cs
@@ -108,9 +108,9 @@ private protected void IGoo.Method14() { }
// (37,22): error CS0539: 'AbstractGoo.Method12()' in explicit interface declaration is not found among members of the interface that can be implemented
// static void IGoo.Method12() { }
Diagnostic(ErrorCode.ERR_InterfaceMemberNotFound, "Method12").WithArguments("AbstractGoo.Method12()").WithLocation(37, 22),
- // (38,23): error CS0754: A partial method may not explicitly implement an interface method
+ // (38,23): error CS0754: A partial member may not explicitly implement an interface member
// partial void IGoo.Method13();
- Diagnostic(ErrorCode.ERR_PartialMethodNotExplicit, "Method13").WithLocation(38, 23),
+ Diagnostic(ErrorCode.ERR_PartialMemberNotExplicit, "Method13").WithLocation(38, 23),
// (20,38): error CS0535: 'AbstractGoo' does not implement interface member 'IGoo.Method12()'
// abstract partial class AbstractGoo : IGoo
Diagnostic(ErrorCode.ERR_UnimplementedInterfaceMember, "IGoo").WithArguments("AbstractGoo", "IGoo.Method12()").WithLocation(20, 38),
diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/ReadOnlyStructsTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/ReadOnlyStructsTests.cs
index 3c90e3dc7bb35..bf3e005bd40d0 100644
--- a/src/Compilers/CSharp/Test/Semantic/Semantics/ReadOnlyStructsTests.cs
+++ b/src/Compilers/CSharp/Test/Semantic/Semantics/ReadOnlyStructsTests.cs
@@ -410,9 +410,9 @@ readonly partial void M()
";
var comp = CreateCompilation(csharp);
comp.VerifyDiagnostics(
- // (10,27): error CS8662: Both partial method declarations must be readonly or neither may be readonly
+ // (10,27): error CS8662: Both partial member declarations must be readonly or neither may be readonly
// readonly partial void M()
- Diagnostic(ErrorCode.ERR_PartialMethodReadOnlyDifference, "M").WithLocation(10, 27),
+ Diagnostic(ErrorCode.ERR_PartialMemberReadOnlyDifference, "M").WithLocation(10, 27),
// (12,9): error CS1604: Cannot assign to 'i' because it is read-only
// i++;
Diagnostic(ErrorCode.ERR_AssgReadonlyLocal, "i").WithArguments("i").WithLocation(12, 9));
@@ -443,9 +443,9 @@ partial void M()
";
var comp = CreateCompilation(csharp);
comp.VerifyDiagnostics(
- // (10,18): error CS8662: Both partial method declarations must be readonly or neither may be readonly
+ // (10,18): error CS8662: Both partial member declarations must be readonly or neither may be readonly
// partial void M()
- Diagnostic(ErrorCode.ERR_PartialMethodReadOnlyDifference, "M").WithLocation(10, 18));
+ Diagnostic(ErrorCode.ERR_PartialMemberReadOnlyDifference, "M").WithLocation(10, 18));
var method = comp.GetMember("S").GetMethod("M");
// Symbol APIs always return the declaration part of the partial method.
diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/RecordStructTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/RecordStructTests.cs
index fd22894c7dc8c..2dbf82572b301 100644
--- a/src/Compilers/CSharp/Test/Semantic/Semantics/RecordStructTests.cs
+++ b/src/Compilers/CSharp/Test/Semantic/Semantics/RecordStructTests.cs
@@ -3119,9 +3119,9 @@ public void RecordWithPartialMethodExplicitImplementation()
partial void M();
}";
CreateCompilation(source).VerifyDiagnostics(
- // (3,18): error CS0751: A partial method must be declared within a partial type
+ // (3,18): error CS0751: A partial member must be declared within a partial type
// partial void M();
- Diagnostic(ErrorCode.ERR_PartialMethodOnlyInPartialClass, "M").WithLocation(3, 18)
+ Diagnostic(ErrorCode.ERR_PartialMemberOnlyInPartialClass, "M").WithLocation(3, 18)
);
}
diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/RefFieldTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/RefFieldTests.cs
index 392842983ba7d..f037d2a226ec2 100644
--- a/src/Compilers/CSharp/Test/Semantic/Semantics/RefFieldTests.cs
+++ b/src/Compilers/CSharp/Test/Semantic/Semantics/RefFieldTests.cs
@@ -16653,22 +16653,22 @@ static partial void M6(in R r) { } // 6
var expectedDiagnostics = new[]
{
- // (3,25): error CS8988: The 'scoped' modifier of parameter 'r' doesn't match partial method declaration.
+ // (3,25): error CS8988: The 'scoped' modifier of parameter 'r' doesn't match partial definition.
// static partial void M1(scoped R r) { } // 1
Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfPartial, "M1").WithArguments("r").WithLocation(3, 25),
- // (4,25): error CS8988: The 'scoped' modifier of parameter 'r' doesn't match partial method declaration.
+ // (4,25): error CS8988: The 'scoped' modifier of parameter 'r' doesn't match partial definition.
// static partial void M2(R r) { } // 2
Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfPartial, "M2").WithArguments("r").WithLocation(4, 25),
- // (5,25): error CS8988: The 'scoped' modifier of parameter 'r' doesn't match partial method declaration.
+ // (5,25): error CS8988: The 'scoped' modifier of parameter 'r' doesn't match partial definition.
// static partial void M3(scoped ref R r) { } // 3
Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfPartial, "M3").WithArguments("r").WithLocation(5, 25),
- // (6,25): error CS8988: The 'scoped' modifier of parameter 'r' doesn't match partial method declaration.
+ // (6,25): error CS8988: The 'scoped' modifier of parameter 'r' doesn't match partial definition.
// static partial void M4(ref R r) { } // 4
Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfPartial, "M4").WithArguments("r").WithLocation(6, 25),
- // (7,25): error CS8988: The 'scoped' modifier of parameter 'r' doesn't match partial method declaration.
+ // (7,25): error CS8988: The 'scoped' modifier of parameter 'r' doesn't match partial definition.
// static partial void M5(scoped in R r) { } // 5
Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfPartial, "M5").WithArguments("r").WithLocation(7, 25),
- // (8,25): error CS8988: The 'scoped' modifier of parameter 'r' doesn't match partial method declaration.
+ // (8,25): error CS8988: The 'scoped' modifier of parameter 'r' doesn't match partial definition.
// static partial void M6(in R r) { } // 6
Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfPartial, "M6").WithArguments("r").WithLocation(8, 25)
};
@@ -16718,16 +16718,16 @@ private partial void F4(ref int i) { } // 4
var expectedDiagnostics = new[]
{
- // (3,26): error CS8988: The 'scoped' modifier of parameter 'i' doesn't match partial method declaration.
+ // (3,26): error CS8988: The 'scoped' modifier of parameter 'i' doesn't match partial definition.
// private partial void F1(scoped ref int i) { } // 1
Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfPartial, "F1").WithArguments("i").WithLocation(3, 26),
- // (4,26): error CS8988: The 'scoped' modifier of parameter 'i' doesn't match partial method declaration.
+ // (4,26): error CS8988: The 'scoped' modifier of parameter 'i' doesn't match partial definition.
// private partial void F2(ref int i) { } // 2
Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfPartial, "F2").WithArguments("i").WithLocation(4, 26),
- // (5,26): error CS8988: The 'scoped' modifier of parameter 'i' doesn't match partial method declaration.
+ // (5,26): error CS8988: The 'scoped' modifier of parameter 'i' doesn't match partial definition.
// private partial void F3(scoped in int i) { } // 3
Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfPartial, "F3").WithArguments("i").WithLocation(5, 26),
- // (6,26): error CS8988: The 'scoped' modifier of parameter 'i' doesn't match partial method declaration.
+ // (6,26): error CS8988: The 'scoped' modifier of parameter 'i' doesn't match partial definition.
// private partial void F4(ref int i) { } // 4
Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfPartial, "F4").WithArguments("i").WithLocation(6, 26)
};
diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/TopLevelStatementsTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/TopLevelStatementsTests.cs
index a8723ce4cb72b..44615f646a7e6 100644
--- a/src/Compilers/CSharp/Test/Semantic/Semantics/TopLevelStatementsTests.cs
+++ b/src/Compilers/CSharp/Test/Semantic/Semantics/TopLevelStatementsTests.cs
@@ -4422,9 +4422,9 @@ public void LocalFunctionStatement_04()
// (14,14): error CS0759: No defining declaration found for implementing declaration of partial method '.localG()'
// partial void localG() => System.Console.WriteLine();
Diagnostic(ErrorCode.ERR_PartialMethodMustHaveLatent, "localG").WithArguments(".localG()").WithLocation(14, 14),
- // (14,14): error CS0751: A partial method must be declared within a partial type
+ // (14,14): error CS0751: A partial member must be declared within a partial type
// partial void localG() => System.Console.WriteLine();
- Diagnostic(ErrorCode.ERR_PartialMethodOnlyInPartialClass, "localG").WithLocation(14, 14),
+ Diagnostic(ErrorCode.ERR_PartialMemberOnlyInPartialClass, "localG").WithLocation(14, 14),
// (15,1): error CS0103: The name 'localG' does not exist in the current context
// localG();
Diagnostic(ErrorCode.ERR_NameNotInContext, "localG").WithArguments("localG").WithLocation(15, 1),
diff --git a/src/Compilers/CSharp/Test/Symbol/DocumentationComments/DocumentationCommentCompilerTests.cs b/src/Compilers/CSharp/Test/Symbol/DocumentationComments/DocumentationCommentCompilerTests.cs
index c2b267aa23460..a795619ee010d 100644
--- a/src/Compilers/CSharp/Test/Symbol/DocumentationComments/DocumentationCommentCompilerTests.cs
+++ b/src/Compilers/CSharp/Test/Symbol/DocumentationComments/DocumentationCommentCompilerTests.cs
@@ -914,6 +914,7 @@ partial class C
[Fact]
public void PartialMethod_NoImplementation()
{
+ // Whole document XML does not include the member, but single symbol XML does include it
var source = @"
partial class C
{
@@ -923,20 +924,25 @@ partial class C
";
var tree = SyntaxFactory.ParseSyntaxTree(source, options: TestOptions.RegularWithDocumentationComments);
-
var comp = CreateCompilation(tree, assemblyName: "Test");
- var actual = GetDocumentationCommentText(comp);
- var expected = @"
-
-
-
- Test
-
-
-
-
-".Trim();
- Assert.Equal(expected, actual);
+ var method = comp.GlobalNamespace.GetMember("C.M");
+
+ AssertEx.AssertLinesEqual(expected: """
+
+
+
+ Test
+
+
+
+
+ """, actual: GetDocumentationCommentText(comp));
+
+ AssertEx.AssertLinesEqual("""
+
+ Summary 2
+
+ """, DocumentationCommentCompiler.GetDocumentationCommentXml(method, processIncludes: true, cancellationToken: default));
}
[Fact]
@@ -1490,6 +1496,690 @@ void verify(CSharpTestSource source)
}
}
+ /// Counterpart to .
+ [Fact]
+ public void PartialProperty_NoImplementation()
+ {
+ // Whole document XML does not include the member, but single symbol XML does include it
+ var source = @"
+partial class C
+{
+ /** Summary 2*/
+ public partial int P { get; set; }
+}
+";
+
+ var tree = SyntaxFactory.ParseSyntaxTree(source, options: TestOptions.RegularWithDocumentationComments);
+ var comp = CreateCompilation(tree, assemblyName: "Test");
+ var property = comp.GlobalNamespace.GetMember("C.P");
+
+ AssertEx.AssertLinesEqual(expected: """
+
+
+
+ Test
+
+
+
+
+ """, actual: GetDocumentationCommentText(comp));
+
+ AssertEx.AssertLinesEqual("""
+
+ Summary 2
+
+ """, DocumentationCommentCompiler.GetDocumentationCommentXml(property, processIncludes: true, cancellationToken: default));
+ }
+
+ /// Counterpart to .
+ [Fact]
+ public void PartialProperties_MultipleFiles()
+ {
+ var source1 = @"
+/// Summary 0
+public partial class C
+{
+ /** Summary 1*/
+ public partial int P => 42;
+}
+";
+
+ var source2 = @"
+public partial class C
+{
+ /** Summary 2*/
+ public partial int P { get; }
+}
+";
+
+ var tree1 = SyntaxFactory.ParseSyntaxTree(source1, options: TestOptions.RegularPreviewWithDocumentationComments);
+ var tree2 = SyntaxFactory.ParseSyntaxTree(source2, options: TestOptions.RegularPreviewWithDocumentationComments);
+
+ // Files passed in order.
+ var compA = CreateCompilation(new[] { tree1, tree2 }, assemblyName: "Test");
+ var actualA = GetDocumentationCommentText(compA);
+ var expected = @"
+
+
+
+ Test
+
+
+
+ Summary 0
+
+
+ Summary 1
+
+
+
+".Trim();
+ AssertEx.Equal(expected, actualA);
+
+ // Files passed in reverse order.
+ var compB = CreateCompilation(new[] { tree2, tree1 }, assemblyName: "Test");
+ var actualB = GetDocumentationCommentText(compB);
+ Assert.Equal(expected, actualB);
+ }
+
+ /// Counterpart to .
+ [Fact]
+ public void PartialIndexers_MultipleFiles()
+ {
+ var source1 = @"
+/// Summary 0
+public partial class C
+{
+ /** Summary 1*/
+ public partial int this[int p] => 42;
+}
+";
+
+ var source2 = @"
+public partial class C
+{
+ /** Summary 2*/
+ public partial int this[int p] { get; }
+}
+";
+
+ var tree1 = SyntaxFactory.ParseSyntaxTree(source1, options: TestOptions.RegularPreviewWithDocumentationComments);
+ var tree2 = SyntaxFactory.ParseSyntaxTree(source2, options: TestOptions.RegularPreviewWithDocumentationComments);
+
+ // Files passed in order.
+ var compA = CreateCompilation(new[] { tree1, tree2 }, assemblyName: "Test");
+ var actualA = GetDocumentationCommentText(compA);
+ var expected = @"
+
+
+
+ Test
+
+
+
+ Summary 0
+
+
+ Summary 1
+
+
+
+".Trim();
+ AssertEx.Equal(expected, actualA);
+
+ // Files passed in reverse order.
+ var compB = CreateCompilation(new[] { tree2, tree1 }, assemblyName: "Test");
+ var actualB = GetDocumentationCommentText(compB);
+ Assert.Equal(expected, actualB);
+ }
+
+ /// Counterpart to .
+ [Fact]
+ public void PartialIndexer_NoImplementation()
+ {
+ // Whole document XML does not include the member, but single symbol XML does include it
+ var source = """
+ partial class C
+ {
+ /// Summary 2
+ /// My param
+ public partial int this[int p] { get; set; }
+ }
+ """;
+
+ var tree = SyntaxFactory.ParseSyntaxTree(source, options: TestOptions.RegularWithDocumentationComments);
+ var comp = CreateCompilation(tree, assemblyName: "Test");
+ var property = comp.GlobalNamespace.GetMember("C").Indexers.Single();
+
+ AssertEx.AssertLinesEqual(expected: """
+
+
+
+ Test
+
+
+
+
+ """, actual: GetDocumentationCommentText(comp));
+
+ AssertEx.AssertLinesEqual("""
+
+ Summary 2
+ My param
+
+ """, DocumentationCommentCompiler.GetDocumentationCommentXml(property, processIncludes: true, cancellationToken: default));
+ }
+
+ /// Counterpart to .
+ [Fact]
+ public void PartialProperties_MultipleFiles_DefinitionComment()
+ {
+ var source1 = @"
+/// Summary 0
+public partial class C
+{
+ public partial int P => 42;
+}
+";
+
+ var source2 = @"
+public partial class C
+{
+ /** Summary 2*/
+ public partial int P { get; }
+}
+";
+
+ var tree1 = SyntaxFactory.ParseSyntaxTree(source1, options: TestOptions.RegularPreviewWithDocumentationComments);
+ var tree2 = SyntaxFactory.ParseSyntaxTree(source2, options: TestOptions.RegularPreviewWithDocumentationComments);
+
+ // Files passed in order.
+ var compA = CreateCompilation(new[] { tree1, tree2 }, assemblyName: "Test");
+ compA.VerifyDiagnostics();
+ var actualA = GetDocumentationCommentText(compA);
+ var expected = @"
+
+
+
+ Test
+
+
+
+ Summary 0
+
+
+ Summary 2
+
+
+
+".Trim();
+ AssertEx.Equal(expected, actualA);
+
+ // Files passed in reverse order.
+ var compB = CreateCompilation(new[] { tree2, tree1 }, assemblyName: "Test");
+ compB.VerifyDiagnostics();
+ var actualB = GetDocumentationCommentText(compB);
+ Assert.Equal(expected, actualB);
+ }
+
+ /// Counterpart to .
+ [Fact]
+ public void PartialProperties_MultipleFiles_ImplementationComment()
+ {
+ var source1 = @"
+/// Summary 0
+public partial class C
+{
+ /** Summary 1*/
+ public partial int P => 42;
+}
+";
+
+ var source2 = @"
+public partial class C
+{
+ public partial int P { get; }
+}
+";
+
+ var tree1 = SyntaxFactory.ParseSyntaxTree(source1, options: TestOptions.RegularPreviewWithDocumentationComments);
+ var tree2 = SyntaxFactory.ParseSyntaxTree(source2, options: TestOptions.RegularPreviewWithDocumentationComments);
+
+ // Files passed in order.
+ var compA = CreateCompilation(new[] { tree1, tree2 }, assemblyName: "Test");
+ compA.VerifyDiagnostics();
+ var actualA = GetDocumentationCommentText(compA);
+ var expected = @"
+
+
+
+ Test
+
+
+
+ Summary 0
+
+
+ Summary 1
+
+
+
+".Trim();
+ AssertEx.Equal(expected, actualA);
+
+ // Files passed in reverse order.
+ var compB = CreateCompilation(new[] { tree2, tree1 }, assemblyName: "Test");
+ compB.VerifyDiagnostics();
+ var actualB = GetDocumentationCommentText(compB);
+ Assert.Equal(expected, actualB);
+ }
+
+ /// Counterpart to .
+ [Fact]
+ public void PartialProperties_MultipleFiles_NoComment()
+ {
+ var source1 = @"
+/// Summary 0
+public partial class C
+{
+ public partial int P => 42;
+}
+";
+
+ var source2 = @"
+public partial class C
+{
+ public partial int P { get; }
+}
+";
+
+ var tree1 = SyntaxFactory.ParseSyntaxTree(source1, options: TestOptions.RegularPreviewWithDocumentationComments);
+ var tree2 = SyntaxFactory.ParseSyntaxTree(source2, options: TestOptions.RegularPreviewWithDocumentationComments);
+
+ var expectedDiagnostics = new[]
+ {
+ // (4,24): warning CS1591: Missing XML comment for publicly visible type or member 'C.P'
+ // public partial int P { get; }
+ Diagnostic(ErrorCode.WRN_MissingXMLComment, "P").WithArguments("C.P").WithLocation(4, 24)
+ };
+
+ // Files passed in order.
+ var compA = CreateCompilation(new[] { tree1, tree2 }, assemblyName: "Test");
+ compA.VerifyDiagnostics(expectedDiagnostics);
+ var actualA = GetDocumentationCommentText(compA, expectedDiagnostics);
+ var expected = @"
+
+
+
+ Test
+
+
+
+ Summary 0
+
+
+
+".Trim();
+ AssertEx.Equal(expected, actualA);
+
+ // Files passed in reverse order.
+ var compB = CreateCompilation(new[] { tree2, tree1 }, assemblyName: "Test");
+ compB.VerifyDiagnostics(expectedDiagnostics);
+ var actualB = GetDocumentationCommentText(compB, expectedDiagnostics);
+ Assert.Equal(expected, actualB);
+ }
+
+ /// Counterpart to .
+ [Fact]
+ public void PartialProperties_MultipleFiles_Overlap()
+ {
+ var source1 = @"
+partial class C
+{
+ /** Remarks 1 */
+ public partial int P => 42;
+}
+";
+
+ var source2 = @"
+partial class C
+{
+ /** Summary 2*/
+ public partial int P { get; }
+}
+";
+
+ var tree1 = SyntaxFactory.ParseSyntaxTree(source1, options: TestOptions.RegularPreviewWithDocumentationComments);
+ var tree2 = SyntaxFactory.ParseSyntaxTree(source2, options: TestOptions.RegularPreviewWithDocumentationComments);
+
+ // Files passed in order.
+ var compA = CreateCompilation(new[] { tree1, tree2 }, assemblyName: "Test");
+ compA.VerifyDiagnostics();
+ var actualA = GetDocumentationCommentText(compA);
+ var expected = @"
+
+
+
+ Test
+
+
+
+ Remarks 1
+
+
+
+".Trim();
+ AssertEx.Equal(expected, actualA);
+
+ // Files passed in reverse order.
+ var compB = CreateCompilation(new[] { tree2, tree1 }, assemblyName: "Test");
+ compB.VerifyDiagnostics();
+ var actualB = GetDocumentationCommentText(compB);
+ Assert.Equal(expected, actualB);
+ }
+
+ /// Counterpart to .
+ [Fact]
+ public void PartialProperties_MultipleFiles_ImplComment_Invalid()
+ {
+ var source1 = @"
+partial class C
+{
+ ///
+ public partial int P => 42;
+}
+";
+
+ var source2 = @"
+partial class C
+{
+ /** Summary 2*/
+ public partial int P { get; }
+}
+";
+
+ var tree1 = SyntaxFactory.ParseSyntaxTree(source1, options: TestOptions.RegularPreviewWithDocumentationComments);
+ var tree2 = SyntaxFactory.ParseSyntaxTree(source2, options: TestOptions.RegularPreviewWithDocumentationComments);
+
+ var expectedDiagnostics = new[]
+ {
+ // (4,20): warning CS1570: XML comment has badly formed XML -- 'End tag 'a' does not match the start tag 'summary'.'
+ // ///
+ Diagnostic(ErrorCode.WRN_XMLParseError, "a").WithArguments("a", "summary").WithLocation(4, 20),
+ // (4,22): warning CS1570: XML comment has badly formed XML -- 'End tag was not expected at this location.'
+ // ///
+ Diagnostic(ErrorCode.WRN_XMLParseError, "<").WithLocation(4, 22)
+ };
+
+ // Files passed in order.
+ var compA = CreateCompilation(new[] { tree1, tree2 }, assemblyName: "Test");
+ compA.VerifyDiagnostics(expectedDiagnostics);
+ var actualA = GetDocumentationCommentText(compA);
+ var expected = @"
+
+
+
+ Test
+
+
+
+
+
+".Trim();
+ AssertEx.Equal(expected, actualA);
+
+ // Files passed in reverse order.
+ var compB = CreateCompilation(new[] { tree2, tree1 }, assemblyName: "Test");
+ compB.VerifyDiagnostics(expectedDiagnostics);
+ var actualB = GetDocumentationCommentText(compB);
+ Assert.Equal(expected, actualB);
+ }
+
+ /// Counterpart to .
+ [Fact]
+ public void PartialIndexer_Paramref_01()
+ {
+ var source1 = @"
+partial class C
+{
+ /** Accepts . */
+ public partial int this[int p1] => 42;
+}
+";
+
+ var source2 = @"
+partial class C
+{
+ public partial int this[int p2] { get; }
+}
+";
+
+ var tree1 = SyntaxFactory.ParseSyntaxTree(source1, options: TestOptions.RegularPreviewWithDocumentationComments);
+ var tree2 = SyntaxFactory.ParseSyntaxTree(source2, options: TestOptions.RegularPreviewWithDocumentationComments);
+
+ // Files passed in order.
+ verify(new[] { tree1, tree2 });
+
+ // Files passed in reverse order.
+ verify(new[] { tree2, tree1 });
+
+ void verify(CSharpTestSource source)
+ {
+ var compilation = CreateCompilation(source, assemblyName: "Test");
+ var verifier = CompileAndVerify(compilation, symbolValidator: module =>
+ {
+ var indexer = module.GlobalNamespace.GetMember("C").Indexers.Single();
+ Assert.Equal("p2", indexer.Parameters.Single().Name);
+ });
+ verifier.VerifyDiagnostics(
+ // (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));
+
+ var actual = GetDocumentationCommentText(compilation);
+ var expected = """
+
+
+
+ Test
+
+
+
+ Accepts .
+
+
+
+ """.Trim();
+ AssertEx.Equal(expected, actual);
+ }
+ }
+
+ /// Counterpart to .
+ [Fact]
+ public void PartialIndexer_Paramref_02()
+ {
+ var source1 = @"
+partial class C
+{
+ /** Accepts . */
+ public partial int this[int p1] => 42;
+}
+";
+
+ var source2 = @"
+partial class C
+{
+ public partial int this[int p2] { get; }
+}
+";
+ var tree1 = SyntaxFactory.ParseSyntaxTree(source1, options: TestOptions.RegularPreviewWithDocumentationComments);
+ var tree2 = SyntaxFactory.ParseSyntaxTree(source2, options: TestOptions.RegularPreviewWithDocumentationComments);
+
+ // Files passed in order.
+ verify(new[] { tree1, tree2 });
+
+ // Files passed in reverse order.
+ verify(new[] { tree2, tree1 });
+
+ void verify(CSharpTestSource source)
+ {
+ var compilation = CreateCompilation(source, assemblyName: "Test");
+ var verifier = CompileAndVerify(compilation, symbolValidator: module =>
+ {
+ var indexer = module.GlobalNamespace.GetMember("C").Indexers.Single();
+ Assert.Equal("p2", indexer.Parameters.Single().Name);
+ });
+ verifier.VerifyDiagnostics(
+ // (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 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));
+
+ var actual = GetDocumentationCommentText(compilation,
+ // (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));
+ var expected = @"
+
+
+
+ Test
+
+
+
+ Accepts .
+
+
+
+ ".Trim();
+ AssertEx.Equal(expected, actual);
+ }
+ }
+
+ /// Counterpart to .
+ [Fact]
+ public void PartialIndexer_Paramref_03()
+ {
+ var source1 = @"
+partial class C
+{
+ public partial int this[int p1] => 42;
+}
+";
+
+ var source2 = @"
+partial class C
+{
+ /** Accepts . */
+ public partial int this[int p2] { get; }
+}
+";
+ var tree1 = SyntaxFactory.ParseSyntaxTree(source1, options: TestOptions.RegularPreviewWithDocumentationComments);
+ var tree2 = SyntaxFactory.ParseSyntaxTree(source2, options: TestOptions.RegularPreviewWithDocumentationComments);
+
+ // Files passed in order.
+ verify(new[] { tree1, tree2 });
+
+ // Files passed in reverse order.
+ verify(new[] { tree2, tree1 });
+
+ void verify(CSharpTestSource source)
+ {
+ var compilation = CreateCompilation(source, assemblyName: "Test");
+ var verifier = CompileAndVerify(compilation, symbolValidator: module =>
+ {
+ var indexer = module.GlobalNamespace.GetMember("C").Indexers.Single();
+ Assert.Equal("p2", indexer.Parameters.Single().Name);
+ });
+ verifier.VerifyDiagnostics(
+ // (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
+ // /** Accepts . */
+ Diagnostic(ErrorCode.WRN_UnmatchedParamRefTag, "p1").WithArguments("p1", "C.this[int]").WithLocation(4, 42));
+
+ var actual = GetDocumentationCommentText(compilation,
+ // (4,42): warning CS1734: XML comment on 'C.this[int]' has a paramref tag for 'p1', but there is no parameter by that name
+ // /** Accepts . */
+ Diagnostic(ErrorCode.WRN_UnmatchedParamRefTag, "p1").WithArguments("p1", "C.this[int]").WithLocation(4, 42));
+ var expected = @"
+
+
+
+ Test
+
+
+
+ Accepts .
+
+
+
+".Trim();
+ AssertEx.Equal(expected, actual);
+ }
+ }
+
+ /// Counterpart to .
+ [Fact]
+ public void PartialIndexer_Paramref_04()
+ {
+ var source1 = @"
+partial class C
+{
+ public partial int this[int p1] => 42;
+}
+";
+
+ var source2 = @"
+partial class C
+{
+ /** Accepts . */
+ public partial int this[int p2] { get; }
+}
+";
+ var tree1 = SyntaxFactory.ParseSyntaxTree(source1, options: TestOptions.RegularPreviewWithDocumentationComments);
+ var tree2 = SyntaxFactory.ParseSyntaxTree(source2, options: TestOptions.RegularPreviewWithDocumentationComments);
+
+ // Files passed in order.
+ verify(new[] { tree1, tree2 });
+
+ // Files passed in reverse order.
+ verify(new[] { tree2, tree1 });
+
+ void verify(CSharpTestSource source)
+ {
+ var compilation = CreateCompilation(source, assemblyName: "Test");
+ var verifier = CompileAndVerify(compilation, symbolValidator: module =>
+ {
+ var indexer = module.GlobalNamespace.GetMember("C").Indexers.Single();
+ Assert.Equal("p2", indexer.Parameters.Single().Name);
+ });
+ verifier.VerifyDiagnostics(
+ // (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));
+
+ var actual = GetDocumentationCommentText(compilation);
+ var expected = """
+
+
+
+ Test
+
+
+
+ Accepts .
+
+
+
+ """.Trim();
+ AssertEx.Equal(expected, actual);
+ }
+ }
+
#endregion Partial methods
#region Crefs
diff --git a/src/Compilers/CSharp/Test/Symbol/Symbols/DefaultInterfaceImplementationTests.cs b/src/Compilers/CSharp/Test/Symbol/Symbols/DefaultInterfaceImplementationTests.cs
index f40628bbb009d..6466391693427 100644
--- a/src/Compilers/CSharp/Test/Symbol/Symbols/DefaultInterfaceImplementationTests.cs
+++ b/src/Compilers/CSharp/Test/Symbol/Symbols/DefaultInterfaceImplementationTests.cs
@@ -10889,7 +10889,7 @@ public Test2(int x) {}
Assert.False(m1.IsAsync);
Assert.False(m1.IsOverride);
Assert.Equal(Accessibility.Private, m1.DeclaredAccessibility);
- Assert.True(m1.IsPartialMethod());
+ Assert.True(m1.IsPartialMember());
Assert.Null(m1.PartialImplementationPart);
var m2 = i1.GetMember("M2");
@@ -10903,7 +10903,7 @@ public Test2(int x) {}
Assert.False(m2.IsAsync);
Assert.False(m2.IsOverride);
Assert.Equal(Accessibility.Private, m2.DeclaredAccessibility);
- Assert.True(m2.IsPartialMethod());
+ Assert.True(m2.IsPartialMember());
Assert.Equal(2, m2.GetAttributes().Length);
Assert.Equal("Test2(1)", m2.GetAttributes()[0].ToString());
@@ -10920,7 +10920,7 @@ public Test2(int x) {}
Assert.False(m2Impl.IsAsync);
Assert.False(m2Impl.IsOverride);
Assert.Equal(Accessibility.Private, m2Impl.DeclaredAccessibility);
- Assert.True(m2Impl.IsPartialMethod());
+ Assert.True(m2Impl.IsPartialMember());
Assert.Same(m2, m2Impl.PartialDefinitionPart);
Assert.Equal(2, m2Impl.GetAttributes().Length);
@@ -10996,7 +10996,7 @@ public Test2(int x) {}
Assert.False(m1.IsAsync);
Assert.False(m1.IsOverride);
Assert.Equal(Accessibility.Private, m1.DeclaredAccessibility);
- Assert.True(m1.IsPartialMethod());
+ Assert.True(m1.IsPartialMember());
Assert.Null(m1.PartialImplementationPart);
var m2 = i1.GetMember("M2");
@@ -11010,7 +11010,7 @@ public Test2(int x) {}
Assert.False(m2.IsAsync);
Assert.False(m2.IsOverride);
Assert.Equal(Accessibility.Private, m2.DeclaredAccessibility);
- Assert.True(m2.IsPartialMethod());
+ Assert.True(m2.IsPartialMember());
Assert.Equal(2, m2.GetAttributes().Length);
Assert.Equal("Test2(1)", m2.GetAttributes()[0].ToString());
@@ -11027,7 +11027,7 @@ public Test2(int x) {}
Assert.False(m2Impl.IsAsync);
Assert.False(m2Impl.IsOverride);
Assert.Equal(Accessibility.Private, m2Impl.DeclaredAccessibility);
- Assert.True(m2Impl.IsPartialMethod());
+ Assert.True(m2Impl.IsPartialMember());
Assert.Same(m2, m2Impl.PartialDefinitionPart);
Assert.Equal(2, m2Impl.GetAttributes().Length);
@@ -11275,24 +11275,24 @@ interface I2
// (4,25): error CS8796: Partial method 'I1.M1()' must have accessibility modifiers because it has a 'virtual', 'override', 'sealed', 'new', or 'extern' modifier.
// sealed partial void M1();
Diagnostic(ErrorCode.ERR_PartialMethodWithExtendedModMustHaveAccessMods, "M1").WithArguments("I1.M1()").WithLocation(4, 25),
- // (5,27): error CS0750: A partial method cannot have the 'abstract' modifier
+ // (5,27): error CS0750: A partial member cannot have the 'abstract' modifier
// abstract partial void M2();
- Diagnostic(ErrorCode.ERR_PartialMethodInvalidModifier, "M2").WithLocation(5, 27),
+ Diagnostic(ErrorCode.ERR_PartialMemberCannotBeAbstract, "M2").WithLocation(5, 27),
// (6,26): error CS8796: Partial method 'I1.M3()' must have accessibility modifiers because it has a 'virtual', 'override', 'sealed', 'new', or 'extern' modifier.
// virtual partial void M3();
Diagnostic(ErrorCode.ERR_PartialMethodWithExtendedModMustHaveAccessMods, "M3").WithArguments("I1.M3()").WithLocation(6, 26),
- // (10,21): error CS0754: A partial method may not explicitly implement an interface method
+ // (10,21): error CS0754: A partial member may not explicitly implement an interface member
// partial void I2.M7();
- Diagnostic(ErrorCode.ERR_PartialMethodNotExplicit, "M7").WithLocation(10, 21),
+ Diagnostic(ErrorCode.ERR_PartialMemberNotExplicit, "M7").WithLocation(10, 21),
// (15,25): error CS8796: Partial method 'I1.M4()' must have accessibility modifiers because it has a 'virtual', 'override', 'sealed', 'new', or 'extern' modifier.
// sealed partial void M4() {}
Diagnostic(ErrorCode.ERR_PartialMethodWithExtendedModMustHaveAccessMods, "M4").WithArguments("I1.M4()").WithLocation(15, 25),
- // (15,25): error CS8798: Both partial method declarations must have identical combinations of 'virtual', 'override', 'sealed', and 'new' modifiers.
+ // (15,25): error CS8798: Both partial member declarations must have identical combinations of 'virtual', 'override', 'sealed', and 'new' modifiers.
// sealed partial void M4() {}
- Diagnostic(ErrorCode.ERR_PartialMethodExtendedModDifference, "M4").WithLocation(15, 25),
- // (16,27): error CS0750: A partial method cannot have the 'abstract' modifier
+ Diagnostic(ErrorCode.ERR_PartialMemberExtendedModDifference, "M4").WithLocation(15, 25),
+ // (16,27): error CS0750: A partial member cannot have the 'abstract' modifier
// abstract partial void M5();
- Diagnostic(ErrorCode.ERR_PartialMethodInvalidModifier, "M5").WithLocation(16, 27),
+ Diagnostic(ErrorCode.ERR_PartialMemberCannotBeAbstract, "M5").WithLocation(16, 27),
// (16,27): error CS0756: A partial method may not have multiple defining declarations
// abstract partial void M5();
Diagnostic(ErrorCode.ERR_PartialMethodOnlyOneLatent, "M5").WithLocation(16, 27),
@@ -11302,15 +11302,15 @@ interface I2
// (17,26): error CS8796: Partial method 'I1.M6()' must have accessibility modifiers because it has a 'virtual', 'override', 'sealed', 'new', or 'extern' modifier.
// virtual partial void M6() {}
Diagnostic(ErrorCode.ERR_PartialMethodWithExtendedModMustHaveAccessMods, "M6").WithArguments("I1.M6()").WithLocation(17, 26),
- // (17,26): error CS8798: Both partial method declarations must have identical combinations of 'virtual', 'override', 'sealed', and 'new' modifiers.
+ // (17,26): error CS8798: Both partial member declarations must have identical combinations of 'virtual', 'override', 'sealed', and 'new' modifiers.
// virtual partial void M6() {}
- Diagnostic(ErrorCode.ERR_PartialMethodExtendedModDifference, "M6").WithLocation(17, 26),
- // (19,21): error CS0754: A partial method may not explicitly implement an interface method
+ Diagnostic(ErrorCode.ERR_PartialMemberExtendedModDifference, "M6").WithLocation(17, 26),
+ // (19,21): error CS0754: A partial member may not explicitly implement an interface member
// partial void I2.M7() {}
- Diagnostic(ErrorCode.ERR_PartialMethodNotExplicit, "M7").WithLocation(19, 21),
- // (25,18): error CS0751: A partial method must be declared within a partial type
+ Diagnostic(ErrorCode.ERR_PartialMemberNotExplicit, "M7").WithLocation(19, 21),
+ // (25,18): error CS0751: A partial member must be declared within a partial type
// partial void M8();
- Diagnostic(ErrorCode.ERR_PartialMethodOnlyInPartialClass, "M8").WithLocation(25, 18)
+ Diagnostic(ErrorCode.ERR_PartialMemberOnlyInPartialClass, "M8").WithLocation(25, 18)
);
}
@@ -11426,12 +11426,12 @@ partial void M3() {}
// (5,25): error CS0761: Partial method declarations of 'I1.M1()' have inconsistent constraints for type parameter 'T'
// static partial void M1() {}
Diagnostic(ErrorCode.ERR_PartialMethodInconsistentConstraints, "M1").WithArguments("I1.M1()", "T").WithLocation(5, 25),
- // (8,25): error CS0758: Both partial method declarations must use a params parameter or neither may use a params parameter
+ // (8,25): error CS0758: Both partial member declarations must use a params parameter or neither may use a params parameter
// static partial void M2(int[] x) {}
- Diagnostic(ErrorCode.ERR_PartialMethodParamsDifference, "M2").WithLocation(8, 25),
- // (11,18): error CS0763: Both partial method declarations must be static or neither may be static
+ Diagnostic(ErrorCode.ERR_PartialMemberParamsDifference, "M2").WithLocation(8, 25),
+ // (11,18): error CS0763: Both partial member declarations must be static or neither may be static
// partial void M3() {}
- Diagnostic(ErrorCode.ERR_PartialMethodStaticDifference, "M3").WithLocation(11, 18)
+ Diagnostic(ErrorCode.ERR_PartialMemberStaticDifference, "M3").WithLocation(11, 18)
);
}
@@ -51897,12 +51897,12 @@ class Test1 : I2
validate(compilation1.SourceModule);
compilation1.VerifyDiagnostics(
- // (9,30): error CS0754: A partial method may not explicitly implement an interface method
+ // (9,30): error CS0754: A partial member may not explicitly implement an interface member
// abstract partial void I1.M1();
- Diagnostic(ErrorCode.ERR_PartialMethodNotExplicit, "M1").WithLocation(9, 30 + implModifiers.Length),
- // (9,30): error CS0750: A partial method cannot have the 'abstract' modifier
+ Diagnostic(ErrorCode.ERR_PartialMemberNotExplicit, "M1").WithLocation(9, 30 + implModifiers.Length),
+ // (9,30): error CS0750: A partial member cannot have the 'abstract' modifier
// abstract partial void I1.M1();
- Diagnostic(ErrorCode.ERR_PartialMethodInvalidModifier, "M1").WithLocation(9, 30 + implModifiers.Length),
+ Diagnostic(ErrorCode.ERR_PartialMemberCannotBeAbstract, "M1").WithLocation(9, 30 + implModifiers.Length),
// (12,15): error CS0535: 'Test1' does not implement interface member 'I1.M1()'
// class Test1 : I2
Diagnostic(ErrorCode.ERR_UnimplementedInterfaceMember, "I2").WithArguments("Test1", "I1.M1()").WithLocation(12, 15)
diff --git a/src/Compilers/CSharp/Test/Symbol/Symbols/ExtendedPartialMethodsTests.cs b/src/Compilers/CSharp/Test/Symbol/Symbols/ExtendedPartialMethodsTests.cs
index 661d83856bae3..a92361f6fa327 100644
--- a/src/Compilers/CSharp/Test/Symbol/Symbols/ExtendedPartialMethodsTests.cs
+++ b/src/Compilers/CSharp/Test/Symbol/Symbols/ExtendedPartialMethodsTests.cs
@@ -289,7 +289,7 @@ internal partial void M1() { }
comp.VerifyDiagnostics(
// (5,28): error CS8797: Both partial method declarations must have equivalent accessibility modifiers.
// internal partial void M1() { }
- Diagnostic(ErrorCode.ERR_PartialMethodAccessibilityDifference, "M1").WithLocation(5, 28)
+ Diagnostic(ErrorCode.ERR_PartialMemberAccessibilityDifference, "M1").WithLocation(5, 28)
);
}
@@ -304,9 +304,9 @@ partial void M1() { }
}";
var comp = CreateCompilation(text, parseOptions: TestOptions.RegularWithExtendedPartialMethods);
comp.VerifyDiagnostics(
- // (5,19): error CS8797: Both partial method declarations must have identical accessibility modifiers.
+ // (5,19): error CS8797: Both partial member declarations must have identical accessibility modifiers.
// partial void M1() { }
- Diagnostic(ErrorCode.ERR_PartialMethodAccessibilityDifference, "M1").WithLocation(5, 19)
+ Diagnostic(ErrorCode.ERR_PartialMemberAccessibilityDifference, "M1").WithLocation(5, 19)
);
}
@@ -321,9 +321,9 @@ private partial void M1() { }
}";
var comp = CreateCompilation(text, parseOptions: TestOptions.RegularWithExtendedPartialMethods);
comp.VerifyDiagnostics(
- // (5,27): error CS8797: Both partial method declarations must have identical accessibility modifiers.
+ // (5,27): error CS8797: Both partial member declarations must have identical accessibility modifiers.
// private partial void M1() { }
- Diagnostic(ErrorCode.ERR_PartialMethodAccessibilityDifference, "M1").WithLocation(5, 27)
+ Diagnostic(ErrorCode.ERR_PartialMemberAccessibilityDifference, "M1").WithLocation(5, 27)
);
}
@@ -440,7 +440,7 @@ internal partial void M1() { }
comp.VerifyDiagnostics(
// (5,27): error CS8798: Both partial method declarations must have equal combinations of 'virtual', 'override', 'sealed', or 'new' modifiers.
// internal partial void M1() { }
- Diagnostic(ErrorCode.ERR_PartialMethodExtendedModDifference, "M1").WithLocation(5, 27)
+ Diagnostic(ErrorCode.ERR_PartialMemberExtendedModDifference, "M1").WithLocation(5, 27)
);
}
@@ -457,7 +457,7 @@ internal virtual partial void M1() { }
comp.VerifyDiagnostics(
// (5,35): error CS8798: Both partial method declarations must have equal combinations of 'virtual', 'override', 'sealed', or 'new' modifiers.
// internal virtual partial void M1() { }
- Diagnostic(ErrorCode.ERR_PartialMethodExtendedModDifference, "M1").WithLocation(5, 35)
+ Diagnostic(ErrorCode.ERR_PartialMemberExtendedModDifference, "M1").WithLocation(5, 35)
);
}
@@ -792,7 +792,7 @@ internal partial void M1() { }
comp.VerifyDiagnostics(
// (9,27): error CS8798: Both partial method declarations must have equal combinations of 'virtual', 'override', 'sealed', or 'new' modifiers.
// internal partial void M1() { }
- Diagnostic(ErrorCode.ERR_PartialMethodExtendedModDifference, "M1").WithLocation(9, 27)
+ Diagnostic(ErrorCode.ERR_PartialMemberExtendedModDifference, "M1").WithLocation(9, 27)
);
}
@@ -816,7 +816,7 @@ internal override partial void M1() { }
Diagnostic(ErrorCode.WRN_NewOrOverrideExpected, "M1").WithArguments("D.M1()", "C.M1()").WithLocation(8, 27),
// (9,36): error CS8798: Both partial method declarations must have equal combinations of 'virtual', 'override', 'sealed', or 'new' modifiers.
// internal override partial void M1() { }
- Diagnostic(ErrorCode.ERR_PartialMethodExtendedModDifference, "M1").WithLocation(9, 36)
+ Diagnostic(ErrorCode.ERR_PartialMemberExtendedModDifference, "M1").WithLocation(9, 36)
);
}
@@ -965,7 +965,7 @@ internal override partial void M1() { }
comp.VerifyDiagnostics(
// (9,36): error CS8798: Both partial method declarations must have equal combinations of 'virtual', 'override', 'sealed', or 'new' modifiers.
// internal override partial void M1() { }
- Diagnostic(ErrorCode.ERR_PartialMethodExtendedModDifference, "M1").WithLocation(9, 36)
+ Diagnostic(ErrorCode.ERR_PartialMemberExtendedModDifference, "M1").WithLocation(9, 36)
);
}
@@ -986,7 +986,7 @@ internal sealed override partial void M1() { }
comp.VerifyDiagnostics(
// (9,43): error CS8798: Both partial method declarations must have equal combinations of 'virtual', 'override', 'sealed', or 'new' modifiers.
// internal sealed override partial void M1() { }
- Diagnostic(ErrorCode.ERR_PartialMethodExtendedModDifference, "M1").WithLocation(9, 43)
+ Diagnostic(ErrorCode.ERR_PartialMemberExtendedModDifference, "M1").WithLocation(9, 43)
);
}
@@ -1177,6 +1177,74 @@ static void validator(ModuleSymbol module)
}
}
+ [Fact]
+ public void Extern_Symbols_NoDllImport()
+ {
+ const string text1 = @"
+public partial class C
+{
+ public static partial void M1();
+
+ public static extern partial void M1();
+
+ public static void M2() { M1(); }
+}";
+
+ const string text2 = @"
+public partial class C
+{
+ public static partial void M1();
+
+ public static extern partial void M1();
+
+ public static void M2() { M1(); }
+}";
+ const string expectedIL = @"
+{
+ // Code size 6 (0x6)
+ .maxstack 0
+ IL_0000: call ""void C.M1()""
+ IL_0005: ret
+}";
+
+ var verifier = CompileAndVerify(
+ text1,
+ parseOptions: TestOptions.RegularWithExtendedPartialMethods,
+ sourceSymbolValidator: module => validator(module, isSource: true),
+ symbolValidator: module => validator(module, isSource: false),
+ // PEVerify fails when extern methods lack an implementation
+ verify: Verification.Skipped);
+ verifier.VerifyDiagnostics();
+ verifier.VerifyIL("C.M2", expectedIL);
+
+ verifier = CompileAndVerify(
+ text2,
+ parseOptions: TestOptions.RegularWithExtendedPartialMethods,
+ sourceSymbolValidator: module => validator(module, isSource: true),
+ symbolValidator: module => validator(module, isSource: false),
+ // PEVerify fails when extern methods lack an implementation
+ verify: Verification.Skipped);
+ verifier.VerifyDiagnostics();
+ verifier.VerifyIL("C.M2", expectedIL);
+
+ static void validator(ModuleSymbol module, bool isSource)
+ {
+ var type = module.ContainingAssembly.GetTypeByMetadataName("C");
+ var method = type.GetMember("M1");
+
+ // 'IsExtern' is not round tripped when DllImport is missing
+ Assert.Equal(isSource, method.IsExtern);
+ if (method.PartialImplementationPart is MethodSymbol implementation)
+ {
+ Assert.True(method.IsPartialDefinition());
+ Assert.Equal(isSource, implementation.IsExtern);
+ }
+
+ var importData = method.GetDllImportData();
+ Assert.Null(importData);
+ }
+ }
+
[Fact]
public void Async_01()
{
@@ -1446,7 +1514,7 @@ internal partial void M1() { }
comp.VerifyDiagnostics(
// (10,27): error CS8798: Both partial method declarations must have equal combinations of 'virtual', 'override', 'sealed', or 'new' modifiers.
// internal partial void M1() { }
- Diagnostic(ErrorCode.ERR_PartialMethodExtendedModDifference, "M1").WithLocation(10, 27)
+ Diagnostic(ErrorCode.ERR_PartialMemberExtendedModDifference, "M1").WithLocation(10, 27)
);
}
@@ -1471,7 +1539,7 @@ partial class D : C
Diagnostic(ErrorCode.WRN_NewRequired, "M1").WithArguments("D.M1()", "C.M1()").WithLocation(9, 27),
// (10,31): error CS8798: Both partial method declarations must have equal combinations of 'virtual', 'override', 'sealed', or 'new' modifiers.
// internal new partial void M1() { }
- Diagnostic(ErrorCode.ERR_PartialMethodExtendedModDifference, "M1").WithLocation(10, 31)
+ Diagnostic(ErrorCode.ERR_PartialMemberExtendedModDifference, "M1").WithLocation(10, 31)
);
}
@@ -1819,12 +1887,12 @@ partial void I.M() { } // 2
";
var comp = CreateCompilation(text);
comp.VerifyDiagnostics(
- // (9,20): error CS0754: A partial method may not explicitly implement an interface method
+ // (9,20): error CS0754: A partial member may not explicitly implement an interface member
// partial void I.M(); // 1
- Diagnostic(ErrorCode.ERR_PartialMethodNotExplicit, "M").WithLocation(9, 20),
- // (10,20): error CS0754: A partial method may not explicitly implement an interface method
+ Diagnostic(ErrorCode.ERR_PartialMemberNotExplicit, "M").WithLocation(9, 20),
+ // (10,20): error CS0754: A partial member may not explicitly implement an interface member
// partial void I.M() { } // 2
- Diagnostic(ErrorCode.ERR_PartialMethodNotExplicit, "M").WithLocation(10, 20));
+ Diagnostic(ErrorCode.ERR_PartialMemberNotExplicit, "M").WithLocation(10, 20));
}
[Fact]
@@ -1844,15 +1912,15 @@ partial class C : I
";
var comp = CreateCompilation(text, parseOptions: TestOptions.RegularWithExtendedPartialMethods);
comp.VerifyDiagnostics(
- // (9,19): error CS0754: A partial method may not explicitly implement an interface method
+ // (9,19): error CS0754: A partial member may not explicitly implement an interface member
// partial int I.M();
- Diagnostic(ErrorCode.ERR_PartialMethodNotExplicit, "M").WithLocation(9, 19),
+ Diagnostic(ErrorCode.ERR_PartialMemberNotExplicit, "M").WithLocation(9, 19),
// (9,19): error CS8794: Partial method 'C.I.M()' must have accessibility modifiers because it has a non-void return type.
// partial int I.M();
Diagnostic(ErrorCode.ERR_PartialMethodWithNonVoidReturnMustHaveAccessMods, "M").WithArguments("C.I.M()").WithLocation(9, 19),
- // (10,19): error CS0754: A partial method may not explicitly implement an interface method
+ // (10,19): error CS0754: A partial member may not explicitly implement an interface member
// partial int I.M() => 42;
- Diagnostic(ErrorCode.ERR_PartialMethodNotExplicit, "M").WithLocation(10, 19),
+ Diagnostic(ErrorCode.ERR_PartialMemberNotExplicit, "M").WithLocation(10, 19),
// (10,19): error CS8794: Partial method 'C.I.M()' must have accessibility modifiers because it has a non-void return type.
// partial int I.M() => 42;
Diagnostic(ErrorCode.ERR_PartialMethodWithNonVoidReturnMustHaveAccessMods, "M").WithArguments("C.I.M()").WithLocation(10, 19));
@@ -2932,15 +3000,15 @@ partial class C
}";
var comp = CreateCompilation(source, parseOptions: TestOptions.RegularWithExtendedPartialMethods);
comp.VerifyDiagnostics(
- // (5,24): error CS8818: Partial method declarations must have matching ref return values.
+ // (5,24): error CS8818: Partial member declarations must have matching ref return values.
// public partial int M1() => throw null!; // 1
- Diagnostic(ErrorCode.ERR_PartialMethodRefReturnDifference, "M1").WithLocation(5, 24),
+ Diagnostic(ErrorCode.ERR_PartialMemberRefReturnDifference, "M1").WithLocation(5, 24),
// (5,24): warning CS8826: Partial method declarations 'ref int C.M1()' and 'int C.M1()' have signature differences.
// public partial int M1() => throw null!; // 1
Diagnostic(ErrorCode.WRN_PartialMethodTypeDifference, "M1").WithArguments("ref int C.M1()", "int C.M1()").WithLocation(5, 24),
- // (8,28): error CS8818: Partial method declarations must have matching ref return values.
+ // (8,28): error CS8818: Partial member declarations must have matching ref return values.
// public partial ref int M2() => throw null!; // 2
- Diagnostic(ErrorCode.ERR_PartialMethodRefReturnDifference, "M2").WithLocation(8, 28),
+ Diagnostic(ErrorCode.ERR_PartialMemberRefReturnDifference, "M2").WithLocation(8, 28),
// (8,28): warning CS8826: Partial method declarations 'int C.M2()' and 'ref int C.M2()' have signature differences.
// public partial ref int M2() => throw null!; // 2
Diagnostic(ErrorCode.WRN_PartialMethodTypeDifference, "M2").WithArguments("int C.M2()", "ref int C.M2()").WithLocation(8, 28));
@@ -2998,9 +3066,9 @@ partial class C
}";
var comp = CreateCompilation(source, parseOptions: TestOptions.RegularWithExtendedPartialMethods);
comp.VerifyDiagnostics(
- // (5,37): error CS8142: Both partial method declarations, 'C.M1()' and 'C.M1()', must use the same tuple element names.
+ // (5,37): error CS8142: Both partial member declarations, 'C.M1()' and 'C.M1()', must use the same tuple element names.
// public partial (int x1, int y1) M1() => default; // 1
- Diagnostic(ErrorCode.ERR_PartialMethodInconsistentTupleNames, "M1").WithArguments("C.M1()", "C.M1()").WithLocation(5, 37));
+ Diagnostic(ErrorCode.ERR_PartialMemberInconsistentTupleNames, "M1").WithArguments("C.M1()", "C.M1()").WithLocation(5, 37));
}
[Fact, WorkItem(44930, "https://github.com/dotnet/roslyn/issues/44930")]
@@ -3085,15 +3153,15 @@ partial class C
}";
var comp = CreateCompilation(source, parseOptions: TestOptions.RegularWithExtendedPartialMethods);
comp.VerifyDiagnostics(
- // (5,37): error CS8818: Partial method declarations must have matching ref return values.
+ // (5,37): error CS8818: Partial member declarations must have matching ref return values.
// public partial ref readonly int M1() => throw null!; // 1
- Diagnostic(ErrorCode.ERR_PartialMethodRefReturnDifference, "M1").WithLocation(5, 37),
+ Diagnostic(ErrorCode.ERR_PartialMemberRefReturnDifference, "M1").WithLocation(5, 37),
// (5,37): warning CS8826: Partial method declarations 'ref int C.M1()' and 'ref readonly int C.M1()' have signature differences.
// public partial ref readonly int M1() => throw null!; // 1
Diagnostic(ErrorCode.WRN_PartialMethodTypeDifference, "M1").WithArguments("ref int C.M1()", "ref readonly int C.M1()").WithLocation(5, 37),
- // (8,28): error CS8818: Partial method declarations must have matching ref return values.
+ // (8,28): error CS8818: Partial member declarations must have matching ref return values.
// public partial ref int M2() => throw null!; // 2
- Diagnostic(ErrorCode.ERR_PartialMethodRefReturnDifference, "M2").WithLocation(8, 28),
+ Diagnostic(ErrorCode.ERR_PartialMemberRefReturnDifference, "M2").WithLocation(8, 28),
// (8,28): warning CS8826: Partial method declarations 'ref readonly int C.M2()' and 'ref int C.M2()' have signature differences.
// public partial ref int M2() => throw null!; // 2
Diagnostic(ErrorCode.WRN_PartialMethodTypeDifference, "M2").WithArguments("ref readonly int C.M2()", "ref int C.M2()").WithLocation(8, 28));
@@ -3208,9 +3276,9 @@ public void DifferentReturnTypes_18()
// (4,27): error CS8817: Both partial method declarations must have the same return type.
// public partial string F1() => null;
Diagnostic(ErrorCode.ERR_PartialMethodReturnTypeDifference, "F1").WithLocation(4, 27),
- // (4,27): error CS8818: Partial method declarations must have matching ref return values.
+ // (4,27): error CS8818: Partial member declarations must have matching ref return values.
// public partial string F1() => null;
- Diagnostic(ErrorCode.ERR_PartialMethodRefReturnDifference, "F1").WithLocation(4, 27));
+ Diagnostic(ErrorCode.ERR_PartialMemberRefReturnDifference, "F1").WithLocation(4, 27));
}
[Fact]
@@ -3224,9 +3292,9 @@ public void DifferentReturnTypes_19()
}";
var comp = CreateCompilation(source, parseOptions: TestOptions.RegularWithExtendedPartialMethods);
comp.VerifyDiagnostics(
- // (4,31): error CS8818: Partial method declarations must have matching ref return values.
+ // (4,31): error CS8818: Partial member declarations must have matching ref return values.
// public partial (int, int) F1() => default;
- Diagnostic(ErrorCode.ERR_PartialMethodRefReturnDifference, "F1").WithLocation(4, 31),
+ Diagnostic(ErrorCode.ERR_PartialMemberRefReturnDifference, "F1").WithLocation(4, 31),
// (4,31): warning CS8826: Partial method declarations 'ref (int x, int y) C.F1()' and '(int, int) C.F1()' have signature differences.
// public partial (int, int) F1() => default;
Diagnostic(ErrorCode.WRN_PartialMethodTypeDifference, "F1").WithArguments("ref (int x, int y) C.F1()", "(int, int) C.F1()").WithLocation(4, 31));
@@ -3354,18 +3422,18 @@ internal partial void F4((T, U) t) { } // 3
static void verifyDiagnostics(CSharpCompilation comp)
{
comp.VerifyDiagnostics(
- // (5,18): error CS8142: Both partial method declarations, 'C.F2((T, U))' and 'C.F2((T x, U y))', must use the same tuple element names.
+ // (5,18): error CS8142: Both partial member declarations, 'C.F2((T, U))' and 'C.F2((T x, U y))', must use the same tuple element names.
// partial void F2((T x, U y) t) { } // 1
- Diagnostic(ErrorCode.ERR_PartialMethodInconsistentTupleNames, "F2").WithArguments("C.F2((T, U))", "C.F2((T x, U y))").WithLocation(5, 18),
- // (8,18): error CS8142: Both partial method declarations, 'C.F3((dynamic, object))' and 'C.F3((object x, dynamic y))', must use the same tuple element names.
+ Diagnostic(ErrorCode.ERR_PartialMemberInconsistentTupleNames, "F2").WithArguments("C.F2((T, U))", "C.F2((T x, U y))").WithLocation(5, 18),
+ // (8,18): error CS8142: Both partial member declarations, 'C.F3((dynamic, object))' and 'C.F3((object x, dynamic y))', must use the same tuple element names.
// partial void F3((object x, dynamic y) t) { } // 2
- Diagnostic(ErrorCode.ERR_PartialMethodInconsistentTupleNames, "F3").WithArguments("C.F3((dynamic, object))", "C.F3((object x, dynamic y))").WithLocation(8, 18),
- // (10,27): error CS8142: Both partial method declarations, 'C.F4((T x, U y))' and 'C.F4((T, U))', must use the same tuple element names.
+ Diagnostic(ErrorCode.ERR_PartialMemberInconsistentTupleNames, "F3").WithArguments("C.F3((dynamic, object))", "C.F3((object x, dynamic y))").WithLocation(8, 18),
+ // (10,27): error CS8142: Both partial member declarations, 'C.F4((T x, U y))' and 'C.F4((T, U))', must use the same tuple element names.
// internal partial void F4((T, U) t) { } // 3
- Diagnostic(ErrorCode.ERR_PartialMethodInconsistentTupleNames, "F4").WithArguments("C.F4((T x, U y))", "C.F4((T, U))").WithLocation(10, 27),
- // (13,29): error CS8142: Both partial method declarations, 'C.F6()' and 'C.F6()', must use the same tuple element names.
+ Diagnostic(ErrorCode.ERR_PartialMemberInconsistentTupleNames, "F4").WithArguments("C.F4((T x, U y))", "C.F4((T, U))").WithLocation(10, 27),
+ // (13,29): error CS8142: Both partial member declarations, 'C.F6()' and 'C.F6()', must use the same tuple element names.
// internal partial (T, U) F6() => default; // 4
- Diagnostic(ErrorCode.ERR_PartialMethodInconsistentTupleNames, "F6").WithArguments("C.F6()", "C.F6()").WithLocation(13, 29));
+ Diagnostic(ErrorCode.ERR_PartialMemberInconsistentTupleNames, "F6").WithArguments("C.F6()", "C.F6()").WithLocation(13, 29));
}
}
diff --git a/src/Compilers/CSharp/Test/Symbol/Symbols/LocalFunctionTests.cs b/src/Compilers/CSharp/Test/Symbol/Symbols/LocalFunctionTests.cs
index 0d5d2a56ac694..204624bfe5c6c 100644
--- a/src/Compilers/CSharp/Test/Symbol/Symbols/LocalFunctionTests.cs
+++ b/src/Compilers/CSharp/Test/Symbol/Symbols/LocalFunctionTests.cs
@@ -156,9 +156,9 @@ static partial void local() { }
// (5,29): error CS0759: No defining declaration found for implementing declaration of partial method 'C.local()'
// static partial void local() { }
Diagnostic(ErrorCode.ERR_PartialMethodMustHaveLatent, "local").WithArguments("C.local()").WithLocation(5, 29),
- // (5,29): error CS0751: A partial method must be declared within a partial type
+ // (5,29): error CS0751: A partial member must be declared within a partial type
// static partial void local() { }
- Diagnostic(ErrorCode.ERR_PartialMethodOnlyInPartialClass, "local").WithLocation(5, 29),
+ Diagnostic(ErrorCode.ERR_PartialMemberOnlyInPartialClass, "local").WithLocation(5, 29),
// (7,1): error CS1022: Type or namespace definition, or end-of-file expected
// }
Diagnostic(ErrorCode.ERR_EOFExpected, "}").WithLocation(7, 1));
@@ -182,9 +182,9 @@ partial void local() { }
// (5,22): error CS0759: No defining declaration found for implementing declaration of partial method 'C.local()'
// partial void local() { }
Diagnostic(ErrorCode.ERR_PartialMethodMustHaveLatent, "local").WithArguments("C.local()").WithLocation(5, 22),
- // (5,22): error CS0751: A partial method must be declared within a partial type
+ // (5,22): error CS0751: A partial member must be declared within a partial type
// partial void local() { }
- Diagnostic(ErrorCode.ERR_PartialMethodOnlyInPartialClass, "local").WithLocation(5, 22),
+ Diagnostic(ErrorCode.ERR_PartialMemberOnlyInPartialClass, "local").WithLocation(5, 22),
// (7,1): error CS1022: Type or namespace definition, or end-of-file expected
// }
Diagnostic(ErrorCode.ERR_EOFExpected, "}").WithLocation(7, 1));
diff --git a/src/Compilers/CSharp/Test/Symbol/Symbols/PartialPropertiesTests.cs b/src/Compilers/CSharp/Test/Symbol/Symbols/PartialPropertiesTests.cs
new file mode 100644
index 0000000000000..e44733027dd10
--- /dev/null
+++ b/src/Compilers/CSharp/Test/Symbol/Symbols/PartialPropertiesTests.cs
@@ -0,0 +1,4977 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Reflection;
+using System.Reflection.Metadata.Ecma335;
+using System.Runtime.InteropServices;
+using Microsoft.CodeAnalysis.CSharp.Symbols;
+using Microsoft.CodeAnalysis.CSharp.Syntax;
+using Microsoft.CodeAnalysis.CSharp.Test.Utilities;
+using Microsoft.CodeAnalysis.Test.Utilities;
+using Roslyn.Test.Utilities;
+using Roslyn.Utilities;
+using Xunit;
+
+namespace Microsoft.CodeAnalysis.CSharp.UnitTests.Symbols
+{
+ public class PartialPropertiesTests : CSharpTestBase
+ {
+ [Theory]
+ [InlineData("partial int P { get; set; }")]
+ [InlineData("partial int P { get; }")]
+ [InlineData("partial int P { set; }")]
+ [InlineData("partial int P { get; init; }")]
+ [InlineData("partial int P { init; }")]
+ public void MissingDeclaration_01(string definitionPart)
+ {
+ // definition without implementation
+ var source = $$"""
+ partial class C
+ {
+ {{definitionPart}}
+ }
+ """;
+ var comp = CreateCompilation([source, IsExternalInitTypeDefinition]);
+ comp.VerifyEmitDiagnostics(
+ // (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)
+ );
+
+ var cClass = comp.GetMember("C");
+ var prop = cClass.GetMember("P");
+ Assert.True(prop.IsPartialDefinition);
+ Assert.Null(prop.PartialImplementationPart);
+
+ var members = cClass.GetMembers().SelectAsArray(m => m.ToTestDisplayString());
+ switch (definitionPart)
+ {
+ case "partial int P { get; set; }":
+ AssertEx.Equal([
+ "System.Int32 C.P { get; set; }",
+ "System.Int32 C.P.get",
+ "void C.P.set",
+ "C..ctor()"
+ ], members);
+ break;
+ case "partial int P { get; }":
+ AssertEx.Equal([
+ "System.Int32 C.P { get; }",
+ "System.Int32 C.P.get",
+ "C..ctor()"
+ ], members);
+ break;
+ case "partial int P { set; }":
+ AssertEx.Equal([
+ "System.Int32 C.P { set; }",
+ "void C.P.set",
+ "C..ctor()"
+ ], members);
+ break;
+ case "partial int P { get; init; }":
+ AssertEx.Equal([
+ "System.Int32 C.P { get; init; }",
+ "System.Int32 C.P.get",
+ "void modreq(System.Runtime.CompilerServices.IsExternalInit) C.P.init",
+ "C..ctor()"
+ ], members);
+ break;
+ case "partial int P { init; }":
+ AssertEx.Equal([
+ "System.Int32 C.P { init; }",
+ "void modreq(System.Runtime.CompilerServices.IsExternalInit) C.P.init",
+ "C..ctor()"
+ ], members);
+ break;
+ default:
+ throw ExceptionUtilities.Unreachable();
+ }
+ }
+
+ [Theory]
+ [InlineData("partial int P { get => throw null!; set { } }")]
+ [InlineData("partial int P { get => throw null!; }")]
+ [InlineData("partial int P { set { } }")]
+ [InlineData("partial int P { get => throw null!; init { } }")]
+ [InlineData("partial int P { init { } }")]
+ public void MissingDeclaration_02(string implementationPart)
+ {
+ // implementation without definition
+ var source = $$"""
+ partial class C
+ {
+ {{implementationPart}}
+ }
+ """;
+ var comp = CreateCompilation([source, IsExternalInitTypeDefinition]);
+ comp.VerifyEmitDiagnostics(
+ // (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)
+ );
+
+ var cClass = comp.GetMember("C");
+ var prop = cClass.GetMember("P");
+ Assert.True(prop.IsPartialImplementation);
+ Assert.Null(prop.PartialDefinitionPart);
+
+ var members = cClass.GetMembers().SelectAsArray(m => m.ToTestDisplayString());
+ switch (implementationPart)
+ {
+ case "partial int P { get => throw null!; set { } }":
+ AssertEx.Equal([
+ "System.Int32 C.P { get; set; }",
+ "System.Int32 C.P.get",
+ "void C.P.set",
+ "C..ctor()"
+ ], members);
+ break;
+ case "partial int P { get => throw null!; }":
+ AssertEx.Equal([
+ "System.Int32 C.P { get; }",
+ "System.Int32 C.P.get",
+ "C..ctor()"
+ ], members);
+ break;
+ case "partial int P { set { } }":
+ AssertEx.Equal([
+ "System.Int32 C.P { set; }",
+ "void C.P.set",
+ "C..ctor()"
+ ], members);
+ break;
+ case "partial int P { get => throw null!; init { } }":
+ AssertEx.Equal([
+ "System.Int32 C.P { get; init; }",
+ "System.Int32 C.P.get",
+ "void modreq(System.Runtime.CompilerServices.IsExternalInit) C.P.init",
+ "C..ctor()"
+ ], members);
+ break;
+ case "partial int P { init { } }":
+ AssertEx.Equal([
+ "System.Int32 C.P { init; }",
+ "void modreq(System.Runtime.CompilerServices.IsExternalInit) C.P.init",
+ "C..ctor()"
+ ], members);
+ break;
+ default:
+ throw ExceptionUtilities.Unreachable();
+ }
+ }
+
+ [Fact]
+ public void DuplicateDeclaration_01()
+ {
+ // duplicate definition
+ var source = """
+ partial class C
+ {
+ partial int P { get; set; }
+ partial int P { get; set; }
+ }
+ """;
+ var comp = CreateCompilation(source);
+ comp.VerifyEmitDiagnostics(
+ // (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 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)
+ );
+ }
+
+ [Fact]
+ public void DuplicateDeclaration_02()
+ {
+ // duplicate definition with single implementation
+ var source = """
+ partial class C
+ {
+ partial int P { get; set; }
+ partial int P { get; set; }
+ partial int P { get => throw null!; set { } }
+ }
+ """;
+ var comp = CreateCompilation(source);
+ comp.VerifyEmitDiagnostics(
+ // (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)
+ );
+ }
+
+ [Fact]
+ public void DuplicateDeclaration_03()
+ {
+ // duplicate implementation
+ var source = """
+ partial class C
+ {
+ partial int P { get => throw null!; set { } }
+ partial int P { get => throw null!; set { } }
+ }
+ """;
+ var comp = CreateCompilation(source);
+ comp.VerifyEmitDiagnostics(
+ // (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 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'
+ // partial int P { get => throw null!; set { } }
+ Diagnostic(ErrorCode.ERR_DuplicateNameInClass, "P").WithArguments("C", "P").WithLocation(4, 17)
+ );
+ }
+
+ [Fact]
+ public void DuplicateDeclaration_04()
+ {
+ // duplicate implementation with single definition
+ var source = """
+ partial class C
+ {
+ partial int P { get; set; }
+ partial int P { get => throw null!; set { } }
+ partial int P { get => throw null!; set { } }
+ }
+ """;
+ var comp = CreateCompilation(source);
+ comp.VerifyEmitDiagnostics(
+ // (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'
+ // partial int P { get => throw null!; set { } }
+ Diagnostic(ErrorCode.ERR_DuplicateNameInClass, "P").WithArguments("C", "P").WithLocation(5, 17)
+ );
+ }
+
+ [Fact]
+ public void DuplicateDeclaration_05()
+ {
+ // duplicate implementation and duplicate definition
+ var source = """
+ partial class C
+ {
+ partial int P { get; set; }
+ partial int P { get; set; }
+ partial int P { get => throw null!; set { } }
+ partial int P { get => throw null!; set { } }
+ }
+ """;
+ var comp = CreateCompilation(source);
+ comp.VerifyEmitDiagnostics(
+ // (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 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'
+ // partial int P { get => throw null!; set { } }
+ Diagnostic(ErrorCode.ERR_DuplicateNameInClass, "P").WithArguments("C", "P").WithLocation(6, 17)
+ );
+ }
+
+ [Fact]
+ public void DuplicateDeclaration_06()
+ {
+ // partial method and partial property have the same name
+ var source = """
+ partial class C
+ {
+ public partial int P { get; set; }
+ public partial int P() => 1;
+ }
+ """;
+ var comp = CreateCompilation(source);
+ comp.VerifyEmitDiagnostics(
+ // (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()'
+ // public partial int P() => 1;
+ Diagnostic(ErrorCode.ERR_PartialMethodMustHaveLatent, "P").WithArguments("C.P()").WithLocation(4, 24),
+ // (4,24): error CS0102: The type 'C' already contains a definition for 'P'
+ // public partial int P() => 1;
+ Diagnostic(ErrorCode.ERR_DuplicateNameInClass, "P").WithArguments("C", "P").WithLocation(4, 24)
+ );
+ }
+
+ [Fact]
+ public void DuplicateDeclaration_07()
+ {
+ // partial method and partial property accessor have the same metadata name
+ var source = """
+ partial class C
+ {
+ public partial int P { get; }
+ public partial int get_P() => 1;
+ }
+ """;
+ var comp = CreateCompilation(source);
+ comp.VerifyEmitDiagnostics(
+ // (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
+ // public partial int P { get; }
+ Diagnostic(ErrorCode.ERR_MemberReserved, "get").WithArguments("get_P", "C").WithLocation(3, 28)
+ );
+ }
+
+ [Fact]
+ public void DuplicateDeclaration_08()
+ {
+ // multiple implementing declarations where accessors are "split" across declarations
+ var source = """
+ partial class C
+ {
+ public partial int P { get; set; }
+ public partial int P { get => 1; }
+ public partial int P { set { } }
+ }
+ """;
+ var comp = CreateCompilation(source);
+ comp.VerifyEmitDiagnostics(
+ // (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 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'
+ // public partial int P { set { } }
+ Diagnostic(ErrorCode.ERR_DuplicateNameInClass, "P").WithArguments("C", "P").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; set; }", prop.ToTestDisplayString());
+ Assert.Equal("System.Int32 C.P { get; }", prop.PartialImplementationPart.ToTestDisplayString());
+
+ Assert.True(duplicateProp.IsPartialImplementation);
+ Assert.Null(duplicateProp.PartialDefinitionPart);
+ 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()
+ {
+ // partial indexer and partial property Item
+ var source = """
+ partial class C
+ {
+ public partial int this[int i] { get; }
+ public partial int Item => 1;
+ }
+ """;
+ var comp = CreateCompilation(source);
+ comp.VerifyEmitDiagnostics(
+ // (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 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)
+ );
+ }
+
+ [Fact]
+ public void DuplicateDeclaration_10()
+ {
+ // partial parameterless (error) indexer and partial property Item
+ var source = """
+ partial class C
+ {
+ public partial int this[] { get; }
+ public partial int Item => 1;
+ }
+ """;
+ var comp = CreateCompilation(source);
+ comp.VerifyEmitDiagnostics(
+ // (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'
+ // public partial int this[] { get; }
+ Diagnostic(ErrorCode.ERR_DuplicateNameInClass, "this").WithArguments("C", "Item").WithLocation(3, 24),
+ // (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 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)
+ );
+ }
+
+ [Fact]
+ public void MissingAccessor_01()
+ {
+ // implementation missing setter
+ var source = """
+ partial class C
+ {
+ partial int P { get; set; }
+ partial int P { get => throw null!; }
+ }
+ """;
+ var comp = CreateCompilation(source);
+ comp.VerifyEmitDiagnostics(
+ // (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)
+ );
+ }
+
+ [Fact]
+ public void MissingAccessor_02()
+ {
+ // implementation missing getter
+ var source = """
+ partial class C
+ {
+ partial int P { get; set; }
+ partial int P { set { } }
+ }
+ """;
+ var comp = CreateCompilation(source);
+ comp.VerifyEmitDiagnostics(
+ // (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)
+ );
+ }
+
+ [Fact]
+ public void MissingAccessor_03()
+ {
+ // implementation missing init
+ var source = """
+ partial class C
+ {
+ partial int P { get; init; }
+ partial int P { get => throw null!; }
+ }
+ """;
+ var comp = CreateCompilation([source, IsExternalInitTypeDefinition]);
+ comp.VerifyEmitDiagnostics(
+ // (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)
+ );
+ }
+
+ [Theory]
+ [InlineData("get")]
+ [InlineData("set")]
+ [InlineData("init")]
+ public void MissingAccessor_04(string accessorKind)
+ {
+ // duplicate property definitions, one with a single accessor, one empty
+ var source = $$"""
+ partial class C
+ {
+ partial int P { {{accessorKind}}; }
+ partial int P { }
+ }
+ """;
+ var comp = CreateCompilation([source, IsExternalInitTypeDefinition]);
+ comp.VerifyEmitDiagnostics(
+ // (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 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'
+ // partial int P { }
+ Diagnostic(ErrorCode.ERR_DuplicateNameInClass, "P").WithArguments("C", "P").WithLocation(4, 17),
+ // (4,17): error CS0548: 'C.P': property or indexer must have at least one accessor
+ // partial int P { }
+ Diagnostic(ErrorCode.ERR_PropertyWithNoAccessors, "P").WithArguments("C.P").WithLocation(4, 17)
+ );
+ }
+
+ [Theory]
+ [InlineData("get")]
+ [InlineData("set")]
+ [InlineData("init")]
+ public void MissingAccessor_05(string accessorKind)
+ {
+ // implementation single accessor, definition empty
+ var source = $$"""
+ partial class C
+ {
+ partial int P { {{accessorKind}} => throw null!; }
+ partial int P { }
+ }
+ """;
+ var comp = CreateCompilation([source, IsExternalInitTypeDefinition]);
+ comp.VerifyEmitDiagnostics(
+ // (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
+ // partial int P { }
+ Diagnostic(ErrorCode.ERR_PropertyWithNoAccessors, "P").WithArguments("C.P").WithLocation(4, 17)
+ );
+ }
+
+ [Fact]
+ public void UnexpectedAccessor_01()
+ {
+ // implementation unexpected setter
+ var source = """
+ partial class C
+ {
+ partial int P { get; }
+ partial int P { get => throw null!; set { } }
+ }
+ """;
+ var comp = CreateCompilation(source);
+ comp.VerifyEmitDiagnostics(
+ // (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)
+ );
+ }
+
+ [Fact]
+ public void UnexpectedAccessor_02()
+ {
+ // implementation unexpected getter
+ var source = """
+ partial class C
+ {
+ partial int P { set; }
+ partial int P { get => throw null!; set { } }
+ }
+ """;
+ var comp = CreateCompilation(source);
+ comp.VerifyEmitDiagnostics(
+ // (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)
+ );
+ }
+
+ [Fact]
+ public void UnexpectedAccessor_03()
+ {
+ // implementation unexpected init
+ var source = """
+ partial class C
+ {
+ partial int P { get; }
+ partial int P { get => throw null!; init { } }
+ }
+ """;
+ var comp = CreateCompilation([source, IsExternalInitTypeDefinition]);
+ comp.VerifyEmitDiagnostics(
+ // (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)
+ );
+ }
+
+ [Fact]
+ public void AccessorKind_01()
+ {
+ // definition has set but implementation has init
+ var source = """
+ partial class C
+ {
+ partial int P { get; set; }
+ partial int P { get => throw null!; init { } }
+ }
+ """;
+
+ var comp = CreateCompilation([source, IsExternalInitTypeDefinition]);
+ comp.VerifyEmitDiagnostics(
+ // (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)
+ );
+ }
+
+ [Fact]
+ public void AccessorKind_02()
+ {
+ // definition has init but implementation has set
+ var source = """
+ partial class C
+ {
+ partial int P { get; init; }
+ partial int P { get => throw null!; set { } }
+ }
+ """;
+ var comp = CreateCompilation([source, IsExternalInitTypeDefinition]);
+ comp.VerifyEmitDiagnostics(
+ // (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)
+ );
+ }
+
+ [Fact]
+ public void Extern_01()
+ {
+ var source = """
+ public partial class C
+ {
+ public partial int P { get; set; }
+ public extern partial int P { get; set; }
+ }
+ """;
+
+ var verifier = CompileAndVerify(
+ [source, IsExternalInitTypeDefinition],
+ sourceSymbolValidator: verifySource,
+ symbolValidator: verifyMetadata,
+ // PEVerify fails when extern methods lack an implementation
+ verify: Verification.Skipped);
+ verifier.VerifyDiagnostics();
+
+ void verifySource(ModuleSymbol module)
+ {
+ var prop = module.GlobalNamespace.GetMember("C.P");
+ Assert.True(prop.GetPublicSymbol().IsExtern);
+ Assert.True(prop.GetMethod!.GetPublicSymbol().IsExtern);
+ Assert.True(prop.SetMethod!.GetPublicSymbol().IsExtern);
+ Assert.True(prop.PartialImplementationPart!.GetPublicSymbol().IsExtern);
+ Assert.True(prop.PartialImplementationPart!.GetMethod!.GetPublicSymbol().IsExtern);
+ Assert.True(prop.PartialImplementationPart!.SetMethod!.GetPublicSymbol().IsExtern);
+ }
+
+ void verifyMetadata(ModuleSymbol module)
+ {
+ var prop = module.GlobalNamespace.GetMember("C.P");
+ // IsExtern doesn't round trip from metadata when DllImportAttribute is missing
+ // This is consistent with the behavior for methods
+ Assert.False(prop.GetPublicSymbol().IsExtern);
+ Assert.False(prop.GetMethod!.GetPublicSymbol().IsExtern);
+ Assert.False(prop.SetMethod!.GetPublicSymbol().IsExtern);
+ }
+ }
+
+ [Fact]
+ public void Extern_02()
+ {
+ var source = """
+ partial class C
+ {
+ extern partial int P { get; set; }
+ extern partial int P { get; set; }
+ }
+ """;
+ var comp = CreateCompilation([source, IsExternalInitTypeDefinition]);
+ comp.VerifyEmitDiagnostics(
+ // (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 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'
+ // extern partial int P { get; set; }
+ Diagnostic(ErrorCode.ERR_DuplicateNameInClass, "P").WithArguments("C", "P").WithLocation(4, 24)
+ );
+
+ var members = comp.GetMembers("C.P").SelectAsArray(m => (SourcePropertySymbol)m);
+ Assert.Equal(2, members.Length);
+ Assert.True(members[0].IsExtern);
+ Assert.True(members[0].IsPartialImplementation);
+ Assert.True(members[1].IsExtern);
+ Assert.True(members[1].IsPartialImplementation);
+ }
+
+ /// Based on as a starting point.
+ [Fact]
+ public void Extern_03()
+ {
+ var source = """
+ using System.Runtime.InteropServices;
+
+ public partial class C
+ {
+ public static partial int P { get; set; }
+ public static extern partial int P
+ {
+ [DllImport("something.dll")]
+ get;
+
+ [DllImport("something.dll")]
+ set;
+ }
+ }
+ """;
+ var verifier = CompileAndVerify(
+ [source, IsExternalInitTypeDefinition],
+ symbolValidator: module => verify(module, isSource: false),
+ sourceSymbolValidator: module => verify(module, isSource: true));
+ verifier.VerifyDiagnostics();
+
+ void verify(ModuleSymbol module, bool isSource)
+ {
+ var prop = module.GlobalNamespace.GetMember("C.P");
+ Assert.True(prop.GetPublicSymbol().IsExtern);
+ verifyAccessor(prop.GetMethod!);
+ verifyAccessor(prop.SetMethod!);
+
+ if (isSource)
+ {
+ var implPart = ((SourcePropertySymbol)prop).PartialImplementationPart!;
+ Assert.True(implPart.GetPublicSymbol().IsExtern);
+ verifyAccessor(implPart.GetMethod!);
+ verifyAccessor(implPart.SetMethod!);
+ }
+ }
+
+ void verifyAccessor(MethodSymbol accessor)
+ {
+ Assert.True(accessor.GetPublicSymbol().IsExtern);
+
+ var importData = accessor.GetDllImportData()!;
+ Assert.NotNull(importData);
+ Assert.Equal("something.dll", importData.ModuleName);
+ Assert.Equal(accessor.MetadataName, importData.EntryPointName); // e.g. 'get_P'
+ Assert.Equal(CharSet.None, importData.CharacterSet);
+ Assert.False(importData.SetLastError);
+ Assert.False(importData.ExactSpelling);
+ Assert.Equal(MethodImplAttributes.PreserveSig, accessor.ImplementationAttributes);
+ Assert.Equal(CallingConvention.Winapi, importData.CallingConvention);
+ Assert.Null(importData.BestFitMapping);
+ Assert.Null(importData.ThrowOnUnmappableCharacter);
+ }
+ }
+
+ /// Based on 'AttributeTests_WellKnownAttributes.TestPseudoAttributes_DllImport_OperatorsAndAccessors'.
+ [Theory]
+ [CombinatorialData]
+ public void TestPseudoAttributes_DllImport(bool attributesOnDefinition)
+ {
+ var source = $$"""
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+public partial class C
+{
+ public static partial int F
+ {
+ {{(attributesOnDefinition ? @"[DllImport(""a"")]" : "")}} get;
+ {{(attributesOnDefinition ? @"[DllImport(""b"")]" : "")}} set;
+ }
+
+ public extern static partial int F
+ {
+ {{(attributesOnDefinition ? "" : @"[DllImport(""a"")]")}} get;
+ {{(attributesOnDefinition ? "" : @"[DllImport(""b"")]")}} set;
+ }
+}
+""";
+ CompileAndVerify(source, parseOptions: TestOptions.RegularPreview.WithNoRefSafetyRulesAttribute(), assemblyValidator: (assembly) =>
+ {
+ var metadataReader = assembly.GetMetadataReader();
+
+ // no backing fields should be generated -- all members are "extern" members:
+ Assert.Equal(0, metadataReader.FieldDefinitions.AsEnumerable().Count());
+
+ Assert.Equal(2, metadataReader.GetTableRowCount(TableIndex.ModuleRef));
+ Assert.Equal(2, metadataReader.GetTableRowCount(TableIndex.ImplMap));
+ var visitedEntryPoints = new Dictionary();
+
+ foreach (var method in metadataReader.GetImportedMethods())
+ {
+ string moduleName = metadataReader.GetString(metadataReader.GetModuleReference(method.GetImport().Module).Name);
+ string entryPointName = metadataReader.GetString(method.Name);
+ switch (entryPointName)
+ {
+ case "get_F":
+ Assert.Equal("a", moduleName);
+ break;
+
+ case "set_F":
+ Assert.Equal("b", moduleName);
+ break;
+
+ default:
+ throw TestExceptionUtilities.UnexpectedValue(entryPointName);
+ }
+
+ // This throws if we visit one entry point name twice.
+ visitedEntryPoints.Add(entryPointName, true);
+ }
+
+ Assert.Equal(2, visitedEntryPoints.Count);
+ });
+ }
+
+ [Fact]
+ public void Semantics_01()
+ {
+ // happy definition + implementation case
+ var source = """
+ using System;
+
+ var c = new C { P = 1 };
+ Console.Write(c.P);
+
+ partial class C
+ {
+ public partial int P { get; set; }
+ }
+
+ partial class C
+ {
+ private int _p;
+ public partial int P { get => _p; set => _p = value; }
+ }
+ """;
+ var verifier = CompileAndVerify(source, expectedOutput: "1");
+ verifier.VerifyDiagnostics();
+ verifier.VerifyIL("C.P.get", """
+ {
+ // Code size 7 (0x7)
+ .maxstack 1
+ IL_0000: ldarg.0
+ IL_0001: ldfld "int C._p"
+ IL_0006: ret
+ }
+ """);
+ verifier.VerifyIL("C.P.set", """
+ {
+ // Code size 8 (0x8)
+ .maxstack 2
+ IL_0000: ldarg.0
+ IL_0001: ldarg.1
+ IL_0002: stfld "int C._p"
+ IL_0007: ret
+ }
+ """);
+
+ var comp = (CSharpCompilation)verifier.Compilation;
+ var cClass = comp.GetMember("C");
+ var members = cClass.GetMembers().SelectAsArray(m => m.ToTestDisplayString());
+ AssertEx.Equal([
+ "System.Int32 C.P { get; set; }",
+ "System.Int32 C.P.get",
+ "void C.P.set",
+ "System.Int32 C._p",
+ "C..ctor()"
+ ], members);
+
+ var propDefinition = comp.GetMember("C.P");
+ Assert.True(propDefinition.IsPartialDefinition);
+
+ var propImplementation = propDefinition.PartialImplementationPart!;
+ Assert.True(propImplementation.IsPartialImplementation);
+
+ Assert.Same(propDefinition, propImplementation.PartialDefinitionPart);
+ Assert.Null(propImplementation.PartialImplementationPart);
+ Assert.Same(propImplementation, propDefinition.PartialImplementationPart);
+ Assert.Null(propDefinition.PartialDefinitionPart);
+
+ Assert.Same(propDefinition.GetMethod, comp.GetMember("C.get_P"));
+ Assert.Same(propDefinition.SetMethod, comp.GetMember("C.set_P"));
+
+ verifyAccessor(propDefinition.GetMethod!, propImplementation.GetMethod!);
+ verifyAccessor(propDefinition.SetMethod!, propImplementation.SetMethod!);
+
+ void verifyAccessor(MethodSymbol definitionAccessor, MethodSymbol implementationAccessor)
+ {
+ Assert.True(definitionAccessor.IsPartialDefinition());
+ Assert.True(implementationAccessor.IsPartialImplementation());
+
+ Assert.Same(implementationAccessor, definitionAccessor.PartialImplementationPart);
+ Assert.Null(definitionAccessor.PartialDefinitionPart);
+ Assert.Same(definitionAccessor, implementationAccessor.PartialDefinitionPart);
+ Assert.Null(implementationAccessor.PartialImplementationPart);
+ }
+ }
+
+ [Theory]
+ [InlineData("public partial int P { get => _p; }")]
+ [InlineData("public partial int P => _p;")]
+ public void Semantics_02(string implementationPart)
+ {
+ // get-only
+ var source = $$"""
+ using System;
+
+ var c = new C();
+ Console.Write(c.P);
+
+ partial class C
+ {
+ public partial int P { get; }
+ }
+
+ partial class C
+ {
+ private int _p = 1;
+ {{implementationPart}}
+ }
+ """;
+ var verifier = CompileAndVerify(source, expectedOutput: "1");
+ verifier.VerifyDiagnostics();
+ verifier.VerifyIL("C.P.get", """
+ {
+ // Code size 7 (0x7)
+ .maxstack 1
+ IL_0000: ldarg.0
+ IL_0001: ldfld "int C._p"
+ IL_0006: ret
+ }
+ """);
+
+ var comp = (CSharpCompilation)verifier.Compilation;
+ var cClass = comp.GetMember("C");
+ var members = cClass.GetMembers().SelectAsArray(m => m.ToTestDisplayString());
+ AssertEx.Equal([
+ "System.Int32 C.P { get; }",
+ "System.Int32 C.P.get",
+ "System.Int32 C._p",
+ "C..ctor()"
+ ], members);
+
+ var propDefinition = comp.GetMember("C.P");
+ Assert.True(propDefinition.IsPartialDefinition);
+
+ var propImplementation = propDefinition.PartialImplementationPart!;
+ Assert.True(propImplementation.IsPartialImplementation);
+
+ Assert.Same(propDefinition, propImplementation.PartialDefinitionPart);
+ Assert.Null(propImplementation.PartialImplementationPart);
+ Assert.Same(propImplementation, propDefinition.PartialImplementationPart);
+ Assert.Null(propDefinition.PartialDefinitionPart);
+
+ Assert.Null(propDefinition.SetMethod);
+ Assert.Null(propImplementation.SetMethod);
+
+ var definitionAccessor = propDefinition.GetMethod!;
+ var implementationAccessor = propImplementation.GetMethod!;
+ Assert.True(definitionAccessor.IsPartialDefinition());
+ Assert.True(implementationAccessor.IsPartialImplementation());
+
+ Assert.Same(implementationAccessor, definitionAccessor.PartialImplementationPart);
+ Assert.Null(definitionAccessor.PartialDefinitionPart);
+ Assert.Same(definitionAccessor, implementationAccessor.PartialDefinitionPart);
+ Assert.Null(implementationAccessor.PartialImplementationPart);
+ }
+
+ [Theory]
+ [InlineData("set")]
+ [InlineData("init")]
+ public void Semantics_03(string accessorKind)
+ {
+ // set/init-only
+ var source = $$"""
+ using System;
+
+ var c = new C() { P = 1 };
+
+ partial class C
+ {
+ public partial int P { {{accessorKind}}; }
+ }
+
+ partial class C
+ {
+ public partial int P
+ {
+ {{accessorKind}}
+ {
+ Console.Write(value);
+ }
+ }
+ }
+ """;
+ var verifier = CompileAndVerify([source, IsExternalInitTypeDefinition], expectedOutput: "1");
+ verifier.VerifyDiagnostics();
+ verifier.VerifyIL($"C.P.{accessorKind}", """
+ {
+ // Code size 7 (0x7)
+ .maxstack 1
+ IL_0000: ldarg.1
+ IL_0001: call "void System.Console.Write(int)"
+ IL_0006: ret
+ }
+ """);
+
+ var comp = (CSharpCompilation)verifier.Compilation;
+ var cClass = comp.GetMember("C");
+ var members = cClass.GetMembers().SelectAsArray(m => m.ToTestDisplayString());
+
+ if (accessorKind == "set")
+ {
+ AssertEx.Equal([
+ "System.Int32 C.P { set; }",
+ "void C.P.set",
+ "C..ctor()"
+ ], members);
+ }
+ else
+ {
+ AssertEx.Equal([
+ "System.Int32 C.P { init; }",
+ "void modreq(System.Runtime.CompilerServices.IsExternalInit) C.P.init",
+ "C..ctor()"
+ ],
+ members);
+ }
+
+ var propDefinition = comp.GetMember("C.P");
+ Assert.True(propDefinition.IsPartialDefinition);
+
+ var propImplementation = propDefinition.PartialImplementationPart!;
+ Assert.True(propImplementation.IsPartialImplementation);
+
+ Assert.Same(propDefinition, propImplementation.PartialDefinitionPart);
+ Assert.Null(propImplementation.PartialImplementationPart);
+ Assert.Same(propImplementation, propDefinition.PartialImplementationPart);
+ Assert.Null(propDefinition.PartialDefinitionPart);
+
+ Assert.Null(propDefinition.GetMethod);
+ Assert.Null(propImplementation.GetMethod);
+
+ var definitionAccessor = propDefinition.SetMethod!;
+ var implementationAccessor = propImplementation.SetMethod!;
+ Assert.True(definitionAccessor.IsPartialDefinition());
+ Assert.True(implementationAccessor.IsPartialImplementation());
+
+ Assert.Same(implementationAccessor, definitionAccessor.PartialImplementationPart);
+ Assert.Null(definitionAccessor.PartialDefinitionPart);
+ Assert.Same(definitionAccessor, implementationAccessor.PartialDefinitionPart);
+ Assert.Null(implementationAccessor.PartialImplementationPart);
+ }
+
+ [Theory]
+ [InlineData("public partial int P { get => _p; set => _p = value; }")]
+ [InlineData("public partial int P { set => _p = value; get => _p; }")]
+ public void Semantics_04(string implementationPart)
+ {
+ // ordering difference between def and impl
+ var source = $$"""
+ using System;
+
+ var c = new C() { P = 1 };
+ Console.Write(c.P);
+
+ partial class C
+ {
+ public partial int P { get; set; }
+
+ private int _p;
+ {{implementationPart}}
+ }
+ """;
+
+ var verifier = CompileAndVerify(source, expectedOutput: "1");
+ verifier.VerifyDiagnostics();
+ var comp = (CSharpCompilation)verifier.Compilation;
+
+ var members = comp.GetMember("C").GetMembers().SelectAsArray(m => m.ToTestDisplayString());
+ AssertEx.Equal([
+ "System.Int32 C.P { get; set; }",
+ "System.Int32 C.P.get",
+ "void C.P.set",
+ "System.Int32 C._p",
+ "C..ctor()"
+ ], members);
+
+ var reference = comp.EmitToImageReference();
+ var comp1 = CreateCompilation([], options: TestOptions.DebugDll.WithMetadataImportOptions(MetadataImportOptions.All), references: [reference]);
+ var members1 = comp1.GetMember("C").GetMembers().SelectAsArray(m => m.ToTestDisplayString());
+ AssertEx.Equal([
+ "System.Int32 C._p",
+ "System.Int32 C.P.get",
+ "void C.P.set",
+ "C..ctor()",
+ "System.Int32 C.P { get; set; }"
+ ], members1);
+ }
+
+ [Theory]
+ [InlineData("public partial int P { get => _p; set => _p = value; }")]
+ [InlineData("public partial int P { set => _p = value; get => _p; }")]
+ public void Semantics_05(string implementationPart)
+ {
+ // ordering difference between def and impl (def set before get)
+ var source = $$"""
+ using System;
+
+ var c = new C() { P = 1 };
+ Console.Write(c.P);
+
+ partial class C
+ {
+ public partial int P { set; get; }
+
+ private int _p;
+ {{implementationPart}}
+ }
+ """;
+
+ var verifier = CompileAndVerify(source, expectedOutput: "1");
+ verifier.VerifyDiagnostics();
+ var comp = (CSharpCompilation)verifier.Compilation;
+
+ var members = comp.GetMember("C").GetMembers().SelectAsArray(m => m.ToTestDisplayString());
+ // set accessor appears before get accessor, otherwise member order and symbol display is the same as Semantics_04
+ AssertEx.Equal([
+ "System.Int32 C.P { get; set; }",
+ "void C.P.set",
+ "System.Int32 C.P.get",
+ "System.Int32 C._p",
+ "C..ctor()"
+ ], members);
+
+ var reference = comp.EmitToImageReference();
+ var comp1 = CreateCompilation([], options: TestOptions.DebugDll.WithMetadataImportOptions(MetadataImportOptions.All), references: [reference]);
+ var members1 = comp1.GetMember("C").GetMembers().SelectAsArray(m => m.ToTestDisplayString());
+ AssertEx.Equal([
+ "System.Int32 C._p",
+ "void C.P.set",
+ "System.Int32 C.P.get",
+ "C..ctor()",
+ "System.Int32 C.P { get; set; }"
+ ], members1);
+ }
+
+ [Fact]
+ public void ModifierDifference_Accessibility_Property()
+ {
+ var source = """
+ partial class C
+ {
+ public partial int P1 { get; set; }
+ partial int P2 { get; set; }
+ }
+
+ partial class C
+ {
+ partial int P1 { get => throw null!; set { } }
+ protected partial int P2 { get => throw null!; set { } }
+ }
+ """;
+
+ var comp = CreateCompilation(source);
+ comp.VerifyEmitDiagnostics(
+ // (9,17): error CS8799: Both partial member declarations must have identical accessibility modifiers.
+ // partial int P1 { get => throw null!; set { } }
+ Diagnostic(ErrorCode.ERR_PartialMemberAccessibilityDifference, "P1").WithLocation(9, 17),
+ // (10,27): error CS8799: Both partial member declarations must have identical accessibility modifiers.
+ // protected partial int P2 { get => throw null!; set { } }
+ Diagnostic(ErrorCode.ERR_PartialMemberAccessibilityDifference, "P2").WithLocation(10, 27));
+ }
+
+ // Property accessor modifiers can only include:
+ // - accessibility modifiers
+ // - readonly modifier
+ // The test burden for accessors is further reduced by the fact that explicit accessibility
+ // is only permitted when it is more restrictive than the containing property.
+
+ [Fact]
+ public void ModifierDifference_Accessibility_Accessors()
+ {
+ // access modifier mismatch on accessors
+ var source = """
+ partial class C
+ {
+ public partial int P { get; private set; }
+ }
+
+ partial class C
+ {
+ public partial int P { internal get => throw null!; set { } }
+ }
+ """;
+
+ var comp = CreateCompilation(source);
+
+ comp.VerifyEmitDiagnostics(
+ // (8,37): error CS8799: Both partial member declarations must have identical accessibility modifiers.
+ // public partial int P { internal get => throw null!; set { } }
+ Diagnostic(ErrorCode.ERR_PartialMemberAccessibilityDifference, "get").WithLocation(8, 37),
+ // (8,57): error CS8799: Both partial member declarations must have identical accessibility modifiers.
+ // public partial int P { internal get => throw null!; set { } }
+ Diagnostic(ErrorCode.ERR_PartialMemberAccessibilityDifference, "set").WithLocation(8, 57));
+ }
+
+ [Fact]
+ public void Semantics_Readonly_01()
+ {
+ var source = """
+ using System;
+
+ class Program
+ {
+ static void Main()
+ {
+ M(new S());
+ }
+
+ static void M(in S s)
+ {
+ Console.Write(s.P1);
+ Console.Write(s.P2);
+ // We can't exercise S.P2.set here because non-readonly setters will error instead of implicitly copying the receiver.
+ s.P3 = 3;
+ Console.Write(s.P3);
+ Console.Write(s.P4);
+ }
+ }
+
+ partial struct S
+ {
+ public readonly partial int P1 { get; }
+ public readonly partial int P1 { get => 1; }
+
+ public partial int P2 { readonly get; set; }
+ public partial int P2 { readonly get => 2; set { } }
+
+ public partial int P3 { get; readonly set; }
+ public partial int P3 { get => 3; readonly set { } }
+
+ public partial int P4 { get; }
+ public partial int P4 { get => 4; }
+ }
+ """;
+
+ var verifier = CompileAndVerify(source, expectedOutput: "1234");
+ verifier.VerifyDiagnostics();
+
+ // non-readonly accessors need to copy the value to temp before invoking.
+ verifier.VerifyIL("Program.M", """
+ {
+ // Code size 68 (0x44)
+ .maxstack 2
+ .locals init (S V_0)
+ IL_0000: ldarg.0
+ IL_0001: call "readonly int S.P1.get"
+ IL_0006: call "void System.Console.Write(int)"
+ IL_000b: ldarg.0
+ IL_000c: call "readonly int S.P2.get"
+ IL_0011: call "void System.Console.Write(int)"
+ IL_0016: ldarg.0
+ IL_0017: ldc.i4.3
+ IL_0018: call "readonly void S.P3.set"
+ IL_001d: ldarg.0
+ IL_001e: ldobj "S"
+ IL_0023: stloc.0
+ IL_0024: ldloca.s V_0
+ IL_0026: call "int S.P3.get"
+ IL_002b: call "void System.Console.Write(int)"
+ IL_0030: ldarg.0
+ IL_0031: ldobj "S"
+ IL_0036: stloc.0
+ IL_0037: ldloca.s V_0
+ IL_0039: call "int S.P4.get"
+ IL_003e: call "void System.Console.Write(int)"
+ IL_0043: ret
+ }
+ """);
+
+ var comp = (CSharpCompilation)verifier.Compilation;
+ }
+
+ [Fact]
+ public void ModifierDifference_Readonly_Property()
+ {
+ // readonly modifier mismatch on property
+ var source = """
+ partial struct S
+ {
+ readonly partial int P1 { get; set; }
+ partial int P2 { get; set; }
+ readonly partial int P3 { get; set; }
+ }
+
+ partial struct S
+ {
+ partial int P1 { get => throw null!; set { } }
+ readonly partial int P2 { get => throw null!; set { } }
+ readonly partial int P3 { get => throw null!; set { } }
+ }
+ """;
+
+ var comp = CreateCompilation(source);
+
+ comp.VerifyEmitDiagnostics(
+ // (10,17): error CS8663: Both partial member declarations must be readonly or neither may be readonly
+ // partial int P1 { get => throw null!; set { } }
+ Diagnostic(ErrorCode.ERR_PartialMemberReadOnlyDifference, "P1").WithLocation(10, 17),
+ // (11,26): error CS8663: Both partial member declarations must be readonly or neither may be readonly
+ // readonly partial int P2 { get => throw null!; set { } }
+ Diagnostic(ErrorCode.ERR_PartialMemberReadOnlyDifference, "P2").WithLocation(11, 26));
+ }
+
+ [Fact]
+ public void ModifierDifference_Readonly_Accessors()
+ {
+ // readonly modifier mismatch on accessors
+ var source = """
+ partial struct S
+ {
+ public partial int P { readonly get; set; }
+ }
+
+ partial struct S
+ {
+ public partial int P { get => throw null!; readonly set { } }
+ }
+ """;
+
+ var comp = CreateCompilation(source);
+
+ comp.VerifyEmitDiagnostics(
+ // (8,28): error CS8663: Both partial member declarations must be readonly or neither may be readonly
+ // public partial int P { get => throw null!; readonly set { } }
+ Diagnostic(ErrorCode.ERR_PartialMemberReadOnlyDifference, "get").WithLocation(8, 28),
+ // (8,57): error CS8663: Both partial member declarations must be readonly or neither may be readonly
+ // public partial int P { get => throw null!; readonly set { } }
+ Diagnostic(ErrorCode.ERR_PartialMemberReadOnlyDifference, "set").WithLocation(8, 57));
+ }
+
+ [Fact]
+ public void Accessibility_ExplicitDefault()
+ {
+ // properties can explicitly specify the default accessibility
+ var source = """
+ using System;
+
+ partial class C
+ {
+ private partial int P1 { get; }
+
+ static void Main()
+ {
+ Console.Write(new C().P1);
+ }
+ }
+
+ partial class C
+ {
+ private partial int P1 { get => 1; }
+ }
+ """;
+
+ var verifier = CompileAndVerify(source, expectedOutput: "1");
+ verifier.VerifyDiagnostics();
+ }
+
+ [Fact]
+ public void Accessibility_ExplicitDefault_IsRespected()
+ {
+ var source = """
+ using System;
+
+ class Program
+ {
+ static void Main()
+ {
+ Console.Write(new C().P1); // 1
+ }
+
+ }
+
+ partial class C
+ {
+ private partial int P1 { get; }
+ }
+
+ partial class C
+ {
+ private partial int P1 { get => 1; }
+ }
+ """;
+
+ var comp = CreateCompilation(source);
+ comp.VerifyEmitDiagnostics(
+ // (7,31): error CS0122: 'C.P1' is inaccessible due to its protection level
+ // Console.Write(new C().P1); // 1
+ Diagnostic(ErrorCode.ERR_BadAccess, "P1").WithArguments("C.P1").WithLocation(7, 31));
+
+ var p1Def = comp.GetMember("C.P1");
+ Assert.True(p1Def.IsPartialDefinition);
+ Assert.Equal(Accessibility.Private, p1Def.DeclaredAccessibility);
+
+ var p1DefPublic = p1Def.GetPublicSymbol();
+ Assert.Equal(Accessibility.Private, p1DefPublic.DeclaredAccessibility);
+ }
+
+ [Fact]
+ public void ModifierDifference_Accessibility_ExplicitDefault_01()
+ {
+ // only one part explicitly specifies the default accessibility
+ var source = """
+ partial class C
+ {
+ private partial int P1 { get; set; }
+ partial int P2 { get; set; }
+ }
+
+ partial class C
+ {
+ partial int P1 { get => throw null!; set { } }
+ private partial int P2 { get => throw null!; set { } }
+ }
+ """;
+
+ var comp = CreateCompilation(source);
+ comp.VerifyEmitDiagnostics(
+ // (9,17): error CS8799: Both partial member declarations must have identical accessibility modifiers.
+ // partial int P1 { get => throw null!; set { } }
+ Diagnostic(ErrorCode.ERR_PartialMemberAccessibilityDifference, "P1").WithLocation(9, 17),
+ // (10,25): error CS8799: Both partial member declarations must have identical accessibility modifiers.
+ // private partial int P2 { get => throw null!; set { } }
+ Diagnostic(ErrorCode.ERR_PartialMemberAccessibilityDifference, "P2").WithLocation(10, 25));
+ }
+
+ [Fact]
+ public void ModifierDifference_Accessibility_ExplicitDefault_02()
+ {
+ var source = """
+ using System;
+
+ partial class C
+ {
+ private partial int P1 { get; set; }
+ partial int P2 { private get; private set; }
+ }
+
+ partial class C
+ {
+ partial int P1 { private get => 1; private set; }
+ partial int P2 { private get => 1; private set { } }
+ }
+ """;
+
+ var comp = CreateCompilation(source);
+ comp.VerifyEmitDiagnostics(
+ // (6,17): error CS0274: Cannot specify accessibility modifiers for both accessors of the property or indexer 'C.P2'
+ // partial int P2 { private get; private set; }
+ Diagnostic(ErrorCode.ERR_DuplicatePropertyAccessMods, "P2").WithArguments("C.P2").WithLocation(6, 17),
+ // (6,30): error CS0273: The accessibility modifier of the 'C.P2.get' accessor must be more restrictive than the property or indexer 'C.P2'
+ // partial int P2 { private get; private set; }
+ Diagnostic(ErrorCode.ERR_InvalidPropertyAccessMod, "get").WithArguments("C.P2.get", "C.P2").WithLocation(6, 30),
+ // (6,43): error CS0273: The accessibility modifier of the 'C.P2.set' accessor must be more restrictive than the property or indexer 'C.P2'
+ // partial int P2 { private get; private set; }
+ Diagnostic(ErrorCode.ERR_InvalidPropertyAccessMod, "set").WithArguments("C.P2.set", "C.P2").WithLocation(6, 43),
+ // (11,17): error CS8799: Both partial member declarations must have identical accessibility modifiers.
+ // partial int P1 { private get => 1; private set; }
+ Diagnostic(ErrorCode.ERR_PartialMemberAccessibilityDifference, "P1").WithLocation(11, 17),
+ // (11,30): error CS8799: Both partial member declarations must have identical accessibility modifiers.
+ // partial int P1 { private get => 1; private set; }
+ Diagnostic(ErrorCode.ERR_PartialMemberAccessibilityDifference, "get").WithLocation(11, 30),
+ // (11,48): error CS8799: Both partial member declarations must have identical accessibility modifiers.
+ // partial int P1 { private get => 1; private set; }
+ Diagnostic(ErrorCode.ERR_PartialMemberAccessibilityDifference, "set").WithLocation(11, 48));
+ }
+
+ [Fact]
+ public void TypeDifference_01()
+ {
+ var source = """
+ using System.Collections.Generic;
+
+ partial class C
+ {
+ partial int P1 { get; set; }
+ partial string P1 { get => ""; set { } }
+
+ partial List P2 { get; set; }
+ partial List P2 { get => []; set { } }
+
+ partial IEnumerable