Skip to content

Commit 818fe86

Browse files
authored
Disallow initializers on partial constructor definitions (#77275)
1 parent 548aef4 commit 818fe86

18 files changed

+232
-0
lines changed

src/Compilers/CSharp/Portable/CSharpResources.resx

+3
Original file line numberDiff line numberDiff line change
@@ -8065,4 +8065,7 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ
80658065
<data name="ERR_PartialEventInitializer" xml:space="preserve">
80668066
<value>'{0}': partial event cannot have initializer</value>
80678067
</data>
8068+
<data name="ERR_PartialConstructorInitializer" xml:space="preserve">
8069+
<value>'{0}': only the implementing declaration of a partial constructor can have an initializer</value>
8070+
</data>
80688071
</root>

src/Compilers/CSharp/Portable/Errors/ErrorCode.cs

+1
Original file line numberDiff line numberDiff line change
@@ -2366,6 +2366,7 @@ internal enum ErrorCode
23662366
ERR_PartialMemberDuplicateDefinition = 9402,
23672367
ERR_PartialMemberDuplicateImplementation = 9403,
23682368
ERR_PartialEventInitializer = 9404,
2369+
ERR_PartialConstructorInitializer = 9405,
23692370

23702371
// Note: you will need to do the following after adding errors:
23712372
// 1) Update ErrorFacts.IsBuildOnlyDiagnostic (src/Compilers/CSharp/Portable/Errors/ErrorFacts.cs)

src/Compilers/CSharp/Portable/Errors/ErrorFacts.cs

+1
Original file line numberDiff line numberDiff line change
@@ -2484,6 +2484,7 @@ or ErrorCode.ERR_PartialMemberMissingDefinition
24842484
or ErrorCode.ERR_PartialMemberDuplicateDefinition
24852485
or ErrorCode.ERR_PartialMemberDuplicateImplementation
24862486
or ErrorCode.ERR_PartialEventInitializer
2487+
or ErrorCode.ERR_PartialConstructorInitializer
24872488
=> false,
24882489
};
24892490
#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.

src/Compilers/CSharp/Portable/Symbols/Source/SourceConstructorSymbol.cs

+5
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,11 @@ private SourceConstructorSymbol(
6565
}
6666
}
6767

68+
if (IsPartialDefinition && syntax.Initializer is { } initializer)
69+
{
70+
diagnostics.Add(ErrorCode.ERR_PartialConstructorInitializer, initializer, this);
71+
}
72+
6873
if (methodKind == MethodKind.StaticConstructor)
6974
{
7075
CheckFeatureAvailabilityAndRuntimeSupport(syntax, location, hasAnyBody, diagnostics);

src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf

+5
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf

+5
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf

+5
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf

+5
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf

+5
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf

+5
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf

+5
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf

+5
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf

+5
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf

+5
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf

+5
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf

+5
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf

+5
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/Compilers/CSharp/Test/Emit3/PartialEventsAndConstructorsTests.cs

+157
Original file line numberDiff line numberDiff line change
@@ -1029,6 +1029,163 @@ partial event System.Action I.E { add { } remove { } }
10291029
Diagnostic(ErrorCode.ERR_PartialMemberNotExplicit, "E").WithLocation(8, 35));
10301030
}
10311031

1032+
[Fact]
1033+
public void ConstructorInitializers_This_Duplicate()
1034+
{
1035+
var source = """
1036+
partial class C
1037+
{
1038+
partial C() : this(1) { }
1039+
partial C() : this(2);
1040+
1041+
C(int x) { }
1042+
}
1043+
""";
1044+
CreateCompilation(source).VerifyDiagnostics(
1045+
// (4,17): error CS9405: 'C.C()': only the implementing declaration of a partial constructor can have an initializer
1046+
// partial C() : this(2);
1047+
Diagnostic(ErrorCode.ERR_PartialConstructorInitializer, ": this(2)").WithArguments("C.C()").WithLocation(4, 17));
1048+
}
1049+
1050+
[Fact]
1051+
public void ConstructorInitializers_This_OnDefinition()
1052+
{
1053+
var source = """
1054+
partial class C
1055+
{
1056+
partial C() { }
1057+
partial C() : this(1);
1058+
1059+
C(int x) { }
1060+
}
1061+
""";
1062+
CreateCompilation(source).VerifyDiagnostics(
1063+
// (4,17): error CS9405: 'C.C()': only the implementing declaration of a partial constructor can have an initializer
1064+
// partial C() : this(1);
1065+
Diagnostic(ErrorCode.ERR_PartialConstructorInitializer, ": this(1)").WithArguments("C.C()").WithLocation(4, 17));
1066+
}
1067+
1068+
[Fact]
1069+
public void ConstructorInitializers_This_OnImplementation()
1070+
{
1071+
var source = """
1072+
var c = new C();
1073+
1074+
partial class C
1075+
{
1076+
public partial C() : this(1) { }
1077+
public partial C();
1078+
1079+
C(int x) { System.Console.Write(x); }
1080+
}
1081+
""";
1082+
CompileAndVerify(source, expectedOutput: "1").VerifyDiagnostics();
1083+
}
1084+
1085+
[Fact]
1086+
public void ConstructorInitializers_Base_Duplicate()
1087+
{
1088+
var source = """
1089+
abstract class B
1090+
{
1091+
protected B(int x) { }
1092+
}
1093+
1094+
partial class C : B
1095+
{
1096+
partial C() : base(1) { }
1097+
partial C() : base(2);
1098+
}
1099+
""";
1100+
CreateCompilation(source).VerifyDiagnostics(
1101+
// (9,17): error CS9405: 'C.C()': only the implementing declaration of a partial constructor can have an initializer
1102+
// partial C() : base(2);
1103+
Diagnostic(ErrorCode.ERR_PartialConstructorInitializer, ": base(2)").WithArguments("C.C()").WithLocation(9, 17));
1104+
}
1105+
1106+
[Fact]
1107+
public void ConstructorInitializers_Base_OnDefinition_01()
1108+
{
1109+
var source = """
1110+
abstract class B
1111+
{
1112+
protected B(int x) { }
1113+
}
1114+
1115+
partial class C : B
1116+
{
1117+
partial C() { }
1118+
partial C() : base(1);
1119+
}
1120+
""";
1121+
CreateCompilation(source).VerifyDiagnostics(
1122+
// (8,13): error CS7036: There is no argument given that corresponds to the required parameter 'x' of 'B.B(int)'
1123+
// partial C() { }
1124+
Diagnostic(ErrorCode.ERR_NoCorrespondingArgument, "C").WithArguments("x", "B.B(int)").WithLocation(8, 13),
1125+
// (9,17): error CS9405: 'C.C()': only the implementing declaration of a partial constructor can have an initializer
1126+
// partial C() : base(1);
1127+
Diagnostic(ErrorCode.ERR_PartialConstructorInitializer, ": base(1)").WithArguments("C.C()").WithLocation(9, 17));
1128+
}
1129+
1130+
[Fact]
1131+
public void ConstructorInitializers_Base_OnDefinition_02()
1132+
{
1133+
var source = """
1134+
abstract class B
1135+
{
1136+
protected B(int x) { }
1137+
protected B() { }
1138+
}
1139+
1140+
partial class C : B
1141+
{
1142+
partial C() { }
1143+
partial C() : base(1);
1144+
}
1145+
""";
1146+
CreateCompilation(source).VerifyDiagnostics(
1147+
// (10,17): error CS9405: 'C.C()': only the implementing declaration of a partial constructor can have an initializer
1148+
// partial C() : base(1);
1149+
Diagnostic(ErrorCode.ERR_PartialConstructorInitializer, ": base(1)").WithArguments("C.C()").WithLocation(10, 17));
1150+
}
1151+
1152+
[Fact]
1153+
public void ConstructorInitializers_Base_OnImplementation()
1154+
{
1155+
var source = """
1156+
var c = new C();
1157+
1158+
abstract class B
1159+
{
1160+
protected B(int x) { System.Console.Write(x); }
1161+
}
1162+
1163+
partial class C : B
1164+
{
1165+
public partial C() : base(1) { }
1166+
public partial C();
1167+
}
1168+
""";
1169+
CompileAndVerify(source, expectedOutput: "1").VerifyDiagnostics();
1170+
}
1171+
1172+
[Fact]
1173+
public void VariableInitializer()
1174+
{
1175+
var source = """
1176+
var c = new C();
1177+
1178+
partial class C
1179+
{
1180+
int x = 5;
1181+
1182+
public partial C() { System.Console.Write(x); }
1183+
public partial C();
1184+
}
1185+
""";
1186+
CompileAndVerify(source, expectedOutput: "5").VerifyDiagnostics();
1187+
}
1188+
10321189
[Fact]
10331190
public void Extern_01()
10341191
{

0 commit comments

Comments
 (0)