Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Disallow initializers on partial constructor definitions #77275

Open
wants to merge 1 commit into
base: features/PartialEventsCtors
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions src/Compilers/CSharp/Portable/CSharpResources.resx
Original file line number Diff line number Diff line change
Expand Up @@ -8065,4 +8065,7 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ
<data name="ERR_PartialEventInitializer" xml:space="preserve">
<value>'{0}': partial event cannot have initializer</value>
</data>
<data name="ERR_PartialConstructorInitializer" xml:space="preserve">
<value>'{0}': only the implementing declaration of a partial constructor can have an initializer</value>
</data>
</root>
1 change: 1 addition & 0 deletions src/Compilers/CSharp/Portable/Errors/ErrorCode.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2366,6 +2366,7 @@ internal enum ErrorCode
ERR_PartialMemberDuplicateDefinition = 9402,
ERR_PartialMemberDuplicateImplementation = 9403,
ERR_PartialEventInitializer = 9404,
ERR_PartialConstructorInitializer = 9405,

// Note: you will need to do the following after adding errors:
// 1) Update ErrorFacts.IsBuildOnlyDiagnostic (src/Compilers/CSharp/Portable/Errors/ErrorFacts.cs)
Expand Down
1 change: 1 addition & 0 deletions src/Compilers/CSharp/Portable/Errors/ErrorFacts.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2484,6 +2484,7 @@ or ErrorCode.ERR_PartialMemberMissingDefinition
or ErrorCode.ERR_PartialMemberDuplicateDefinition
or ErrorCode.ERR_PartialMemberDuplicateImplementation
or ErrorCode.ERR_PartialEventInitializer
or ErrorCode.ERR_PartialConstructorInitializer
=> 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.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,11 @@ private SourceConstructorSymbol(
}
}

if (IsPartialDefinition && syntax.Initializer is { } initializer)
{
diagnostics.Add(ErrorCode.ERR_PartialConstructorInitializer, initializer, this);
}

if (methodKind == MethodKind.StaticConstructor)
{
CheckFeatureAvailabilityAndRuntimeSupport(syntax, location, hasAnyBody, diagnostics);
Expand Down
5 changes: 5 additions & 0 deletions src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

157 changes: 157 additions & 0 deletions src/Compilers/CSharp/Test/Emit3/PartialEventsAndConstructorsTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -778,6 +778,163 @@ partial event System.Action I.E { add { } remove { } }
Diagnostic(ErrorCode.ERR_PartialMemberNotExplicit, "E").WithLocation(8, 35));
}

[Fact]
public void ConstructorInitializers_This_Duplicate()
{
var source = """
partial class C
{
partial C() : this(1) { }
partial C() : this(2);

C(int x) { }
}
""";
CreateCompilation(source).VerifyDiagnostics(
// (4,17): error CS9405: 'C.C()': only the implementing declaration of a partial constructor can have an initializer
// partial C() : this(2);
Diagnostic(ErrorCode.ERR_PartialConstructorInitializer, ": this(2)").WithArguments("C.C()").WithLocation(4, 17));
}

[Fact]
public void ConstructorInitializers_This_OnDefinition()
{
var source = """
partial class C
{
partial C() { }
partial C() : this(1);

C(int x) { }
}
""";
CreateCompilation(source).VerifyDiagnostics(
// (4,17): error CS9405: 'C.C()': only the implementing declaration of a partial constructor can have an initializer
// partial C() : this(1);
Diagnostic(ErrorCode.ERR_PartialConstructorInitializer, ": this(1)").WithArguments("C.C()").WithLocation(4, 17));
}

[Fact]
public void ConstructorInitializers_This_OnImplementation()
{
var source = """
var c = new C();

partial class C
{
public partial C() : this(1) { }
public partial C();

C(int x) { System.Console.Write(x); }
}
""";
CompileAndVerify(source, expectedOutput: "1").VerifyDiagnostics();
}

[Fact]
public void ConstructorInitializers_Base_Duplicate()
{
var source = """
abstract class B
{
protected B(int x) { }
}

partial class C : B
{
partial C() : base(1) { }
partial C() : base(2);
}
""";
CreateCompilation(source).VerifyDiagnostics(
// (9,17): error CS9405: 'C.C()': only the implementing declaration of a partial constructor can have an initializer
// partial C() : base(2);
Diagnostic(ErrorCode.ERR_PartialConstructorInitializer, ": base(2)").WithArguments("C.C()").WithLocation(9, 17));
}

[Fact]
public void ConstructorInitializers_Base_OnDefinition_01()
{
var source = """
abstract class B
{
protected B(int x) { }
}

partial class C : B
{
partial C() { }
partial C() : base(1);
}
""";
CreateCompilation(source).VerifyDiagnostics(
// (8,13): error CS7036: There is no argument given that corresponds to the required parameter 'x' of 'B.B(int)'
// partial C() { }
Diagnostic(ErrorCode.ERR_NoCorrespondingArgument, "C").WithArguments("x", "B.B(int)").WithLocation(8, 13),
// (9,17): error CS9405: 'C.C()': only the implementing declaration of a partial constructor can have an initializer
// partial C() : base(1);
Diagnostic(ErrorCode.ERR_PartialConstructorInitializer, ": base(1)").WithArguments("C.C()").WithLocation(9, 17));
}

[Fact]
public void ConstructorInitializers_Base_OnDefinition_02()
{
var source = """
abstract class B
{
protected B(int x) { }
protected B() { }
}

partial class C : B
{
partial C() { }
partial C() : base(1);
}
""";
CreateCompilation(source).VerifyDiagnostics(
// (10,17): error CS9405: 'C.C()': only the implementing declaration of a partial constructor can have an initializer
// partial C() : base(1);
Diagnostic(ErrorCode.ERR_PartialConstructorInitializer, ": base(1)").WithArguments("C.C()").WithLocation(10, 17));
}

[Fact]
public void ConstructorInitializers_Base_OnImplementation()
{
var source = """
var c = new C();

abstract class B
{
protected B(int x) { System.Console.Write(x); }
}

partial class C : B
{
public partial C() : base(1) { }
public partial C();
}
""";
CompileAndVerify(source, expectedOutput: "1").VerifyDiagnostics();
}

[Fact]
public void VariableInitializer()
{
var source = """
var c = new C();

partial class C
{
int x = 5;

public partial C() { System.Console.Write(x); }
public partial C();
}
""";
CompileAndVerify(source, expectedOutput: "5").VerifyDiagnostics();
}

[Fact]
public void Extern_01()
{
Expand Down