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

Avoid synthesizing the parameterless struct constructor unnecessarily #72314

Merged
merged 1 commit into from
Feb 28, 2024
Merged
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
Original file line number Diff line number Diff line change
Expand Up @@ -4663,7 +4663,9 @@ private void AddSynthesizedConstructorsIfNecessary(MembersAndInitializersBuilder
}

//kick out early if we've seen everything we're looking for
if (hasInstanceConstructor && hasStaticConstructor)
if (hasInstanceConstructor &&
hasParameterlessInstanceConstructor &&
hasStaticConstructor)
{
break;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4792,5 +4792,111 @@ .maxstack 2
}
");
}

[Theory]
[InlineData("class")]
[InlineData("struct")]
[WorkItem("https://devdiv.visualstudio.com/DevDiv/_workitems/edit/1598252")]
public void StaticAndInstanceConstructors_01(string type)
{
string source = $$"""
using System;
{{type}} S
{
static S()
{
Console.WriteLine("static constructor");
}
public S(int p)
{
Console.WriteLine("instance constructor: {0}", p);
}
public S() : this(0)
{
}
}
class Program
{
static void Main()
{
_ = new S();
}
}
""";

var comp = CreateCompilation(source, options: TestOptions.ReleaseExe);
VerifyExplicitlyDeclaredInstanceConstructors(
comp.GlobalNamespace.GetTypeMember("S"),
"S..ctor(System.Int32 p)",
"S..ctor()");
VerifyExplicitlyDeclaredInstanceConstructors(
((Compilation)comp).GlobalNamespace.GetTypeMember("S"),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is the difference when obtaining the type symbol in this way, versus without the cast?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The symbols from Compilation are public API ISymbol, while the symbols from CSharpCompilation are internal Symbol. Since the ISymbol instances are generated from the Symbol instances, this additional test may not be that useful, but it seemed simple to include.

"S..ctor(System.Int32 p)",
"S..ctor()");

CompileAndVerify(comp, expectedOutput: """
static constructor
instance constructor: 0
""");
}

[Theory]
[InlineData("class")]
[InlineData("struct")]
public void StaticAndInstanceConstructors_02(string type)
{
string source = $$"""
using System;
{{type}} S
{
static S()
{
Console.WriteLine("static constructor");
}
public S()
{
Console.WriteLine("instance constructor");
}
}
class Program
{
static void Main()
{
_ = new S();
}
}
""";

var comp = CreateCompilation(source, options: TestOptions.ReleaseExe);
VerifyExplicitlyDeclaredInstanceConstructors(
comp.GlobalNamespace.GetTypeMember("S"),
"S..ctor()");
VerifyExplicitlyDeclaredInstanceConstructors(
((Compilation)comp).GlobalNamespace.GetTypeMember("S"),
"S..ctor()");

CompileAndVerify(comp, expectedOutput: """
static constructor
instance constructor
""");
}

private static void VerifyExplicitlyDeclaredInstanceConstructors(NamedTypeSymbol type, params string[] expectedConstructors)
{
var constructors = type.InstanceConstructors;
var members = type.GetMembers(".ctor");
Assert.True(members.SequenceEqual(constructors));
Assert.True(constructors.All(c => c is { IsStatic: false, IsImplicitConstructor: false }));
Assert.Equal(expectedConstructors, constructors.ToTestDisplayStrings());
}

private static void VerifyExplicitlyDeclaredInstanceConstructors(INamedTypeSymbol type, params string[] expectedConstructors)
{
var constructors = type.InstanceConstructors;
var members = type.GetMembers(".ctor");
Assert.True(members.SequenceEqual(constructors));
Assert.True(constructors.All(c => c is { IsStatic: false, IsImplicitlyDeclared: false }));
Assert.Equal(expectedConstructors, constructors.ToTestDisplayStrings());
}
}
}
Loading