@@ -100,7 +100,8 @@ private SourceOrdinaryMethodSymbol(
100
100
_hasAnyBody = hasBody ;
101
101
102
102
bool modifierErrors ;
103
- var declarationModifiers = this . MakeModifiers ( modifiers , methodKind , hasBody , location , diagnostics , out modifierErrors ) ;
103
+ DeclarationModifiers declarationModifiers ;
104
+ ( declarationModifiers , HasExplicitAccessModifier , modifierErrors ) = this . MakeModifiers ( modifiers , methodKind , hasBody , location , diagnostics ) ;
104
105
105
106
var isMetadataVirtualIgnoringModifiers = ( object ) explicitInterfaceType != null ; //explicit impls must be marked metadata virtual
106
107
@@ -289,16 +290,6 @@ private void MethodChecks(MethodDeclarationSyntax syntax, Binder withTypeParamsB
289
290
290
291
if ( IsPartial )
291
292
{
292
- // check that there are no out parameters in a partial
293
- foreach ( var p in this . Parameters )
294
- {
295
- if ( p . RefKind == RefKind . Out )
296
- {
297
- diagnostics . Add ( ErrorCode . ERR_PartialMethodCannotHaveOutParameters , location ) ;
298
- break ;
299
- }
300
- }
301
-
302
293
if ( MethodKind == MethodKind . ExplicitInterfaceImplementation )
303
294
{
304
295
diagnostics . Add ( ErrorCode . ERR_PartialMethodNotExplicit , location ) ;
@@ -611,7 +602,7 @@ internal bool IsPartialDefinition
611
602
{
612
603
get
613
604
{
614
- return this . IsPartial && ! _hasAnyBody ;
605
+ return this . IsPartial && ! _hasAnyBody && ! HasExternModifier ;
615
606
}
616
607
}
617
608
@@ -622,7 +613,7 @@ internal bool IsPartialImplementation
622
613
{
623
614
get
624
615
{
625
- return this . IsPartial && _hasAnyBody ;
616
+ return this . IsPartial && ( _hasAnyBody || HasExternModifier ) ;
626
617
}
627
618
}
628
619
@@ -677,6 +668,16 @@ public override MethodSymbol PartialImplementationPart
677
668
}
678
669
}
679
670
671
+ public sealed override bool IsExtern
672
+ {
673
+ get
674
+ {
675
+ return IsPartialDefinition
676
+ ? _otherPartOfPartial ? . IsExtern ?? false
677
+ : HasExternModifier ;
678
+ }
679
+ }
680
+
680
681
public override string GetDocumentationCommentXml ( CultureInfo preferredCulture = null , bool expandIncludes = false , CancellationToken cancellationToken = default ( CancellationToken ) )
681
682
{
682
683
ref var lazyDocComment = ref expandIncludes ? ref this . lazyExpandedDocComment : ref this . lazyDocComment ;
@@ -756,7 +757,9 @@ internal override bool IsExpressionBodied
756
757
get { return _isExpressionBodied ; }
757
758
}
758
759
759
- private DeclarationModifiers MakeModifiers ( SyntaxTokenList modifiers , MethodKind methodKind , bool hasBody , Location location , DiagnosticBag diagnostics , out bool modifierErrors )
760
+ internal bool HasExplicitAccessModifier { get ; }
761
+
762
+ private ( DeclarationModifiers mods , bool hasExplicitAccessMod , bool modifierErrors ) MakeModifiers ( SyntaxTokenList modifiers , MethodKind methodKind , bool hasBody , Location location , DiagnosticBag diagnostics )
760
763
{
761
764
bool isInterface = this . ContainingType . IsInterface ;
762
765
bool isExplicitInterfaceImplementation = methodKind == MethodKind . ExplicitInterfaceImplementation ;
@@ -808,7 +811,19 @@ private DeclarationModifiers MakeModifiers(SyntaxTokenList modifiers, MethodKind
808
811
allowedModifiers |= DeclarationModifiers . ReadOnly ;
809
812
}
810
813
811
- var mods = ModifierUtils . MakeAndCheckNontypeMemberModifiers ( modifiers , defaultAccess , allowedModifiers , location , diagnostics , out modifierErrors ) ;
814
+ // In order to detect whether explicit accessibility mods were provided, we pass the default value
815
+ // for 'defaultAccess' and manually add in the 'defaultAccess' flags after the call.
816
+ bool hasExplicitAccessMod ;
817
+ var mods = ModifierUtils . MakeAndCheckNontypeMemberModifiers ( modifiers , defaultAccess : DeclarationModifiers . None , allowedModifiers , location , diagnostics , out bool modifierErrors ) ;
818
+ if ( ( mods & DeclarationModifiers . AccessibilityMask ) == 0 )
819
+ {
820
+ hasExplicitAccessMod = false ;
821
+ mods |= defaultAccess ;
822
+ }
823
+ else
824
+ {
825
+ hasExplicitAccessMod = true ;
826
+ }
812
827
813
828
this . CheckUnsafeModifier ( mods , diagnostics ) ;
814
829
@@ -817,7 +832,7 @@ private DeclarationModifiers MakeModifiers(SyntaxTokenList modifiers, MethodKind
817
832
location , diagnostics ) ;
818
833
819
834
mods = AddImpliedModifiers ( mods , isInterface , methodKind , hasBody ) ;
820
- return mods ;
835
+ return ( mods , hasExplicitAccessMod , modifierErrors ) ;
821
836
}
822
837
823
838
private static DeclarationModifiers AddImpliedModifiers ( DeclarationModifiers mods , bool containingTypeIsInterface , MethodKind methodKind , bool hasBody )
@@ -905,26 +920,40 @@ private ImmutableArray<TypeParameterSymbol> MakeTypeParameters(MethodDeclaration
905
920
return result . ToImmutableAndFree ( ) ;
906
921
}
907
922
923
+ private const DeclarationModifiers PartialMethodExtendedModifierMask =
924
+ DeclarationModifiers . Virtual |
925
+ DeclarationModifiers . Override |
926
+ DeclarationModifiers . New |
927
+ DeclarationModifiers . Sealed |
928
+ DeclarationModifiers . Extern ;
929
+
930
+ internal bool HasExtendedPartialModifier => ( DeclarationModifiers & PartialMethodExtendedModifierMask ) != 0 ;
931
+
908
932
private void CheckModifiers ( bool isExplicitInterfaceImplementation , bool hasBody , Location location , DiagnosticBag diagnostics )
909
933
{
910
- const DeclarationModifiers partialMethodInvalidModifierMask = ( DeclarationModifiers . AccessibilityMask & ~ DeclarationModifiers . Private ) |
911
- DeclarationModifiers . Virtual |
912
- DeclarationModifiers . Abstract |
913
- DeclarationModifiers . Override |
914
- DeclarationModifiers . New |
915
- DeclarationModifiers . Sealed |
916
- DeclarationModifiers . Extern ;
917
-
918
934
bool isExplicitInterfaceImplementationInInterface = isExplicitInterfaceImplementation && ContainingType . IsInterface ;
919
935
920
- if ( IsPartial && ! ReturnsVoid )
936
+ if ( IsPartial && HasExplicitAccessModifier )
921
937
{
922
- diagnostics . Add ( ErrorCode . ERR_PartialMethodMustReturnVoid , location ) ;
938
+ Binder . CheckFeatureAvailability ( SyntaxNode , MessageID . IDS_FeatureExtendedPartialMethods , diagnostics , location ) ;
923
939
}
924
- else if ( IsPartial && ( DeclarationModifiers & partialMethodInvalidModifierMask ) != 0 )
940
+
941
+ if ( IsPartial && IsAbstract )
925
942
{
926
943
diagnostics . Add ( ErrorCode . ERR_PartialMethodInvalidModifier , location ) ;
927
944
}
945
+ else if ( IsPartial && ! HasExplicitAccessModifier && ! ReturnsVoid )
946
+ {
947
+ diagnostics . Add ( ErrorCode . ERR_PartialMethodWithNonVoidReturnMustHaveAccessMods , location , this ) ;
948
+ }
949
+ else if ( IsPartial && ! HasExplicitAccessModifier && HasExtendedPartialModifier )
950
+ {
951
+ diagnostics . Add ( ErrorCode . ERR_PartialMethodWithExtendedModMustHaveAccessMods , location , this ) ;
952
+ }
953
+ else if ( IsPartial && ! HasExplicitAccessModifier && Parameters . Any ( p => p . RefKind == RefKind . Out ) )
954
+ {
955
+ diagnostics . Add ( ErrorCode . ERR_PartialMethodWithOutParamMustHaveAccessMods , location , this ) ;
956
+ }
928
957
else if ( this . DeclaredAccessibility == Accessibility . Private && ( IsVirtual || ( IsAbstract && ! isExplicitInterfaceImplementationInInterface ) || IsOverride ) )
929
958
{
930
959
diagnostics . Add ( ErrorCode . ERR_VirtualPrivate , location , this ) ;
@@ -1144,6 +1173,20 @@ private static void PartialMethodChecks(SourceOrdinaryMethodSymbol definition, S
1144
1173
diagnostics . Add ( ErrorCode . ERR_PartialMethodParamsDifference , implementation . Locations [ 0 ] ) ;
1145
1174
}
1146
1175
1176
+ if ( definition . HasExplicitAccessModifier != implementation . HasExplicitAccessModifier
1177
+ || definition . DeclaredAccessibility != implementation . DeclaredAccessibility )
1178
+ {
1179
+ diagnostics . Add ( ErrorCode . ERR_PartialMethodAccessibilityDifference , implementation . Locations [ 0 ] ) ;
1180
+ }
1181
+
1182
+ if ( definition . IsVirtual != implementation . IsVirtual
1183
+ || definition . IsOverride != implementation . IsOverride
1184
+ || definition . IsSealed != implementation . IsSealed
1185
+ || definition . IsNew != implementation . IsNew )
1186
+ {
1187
+ diagnostics . Add ( ErrorCode . ERR_PartialMethodExtendedModDifference , implementation . Locations [ 0 ] ) ;
1188
+ }
1189
+
1147
1190
PartialMethodConstraintsChecks ( definition , implementation , diagnostics ) ;
1148
1191
1149
1192
SourceMemberContainerTypeSymbol . CheckValidNullableMethodOverride (
0 commit comments