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

Dealing with more than one parameterless constructor #55824

Merged
merged 2 commits into from
Aug 24, 2021
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
27 changes: 24 additions & 3 deletions src/Compilers/CSharp/Portable/Symbols/MemberSymbolExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -403,12 +403,33 @@ internal static bool IncludeFieldInitializersInBody(this MethodSymbol methodSymb

internal static bool IsDefaultValueTypeConstructor(this NamedTypeSymbol type, ConstructorInitializerSyntax initializerSyntax)
{
if (initializerSyntax.ArgumentList.Arguments.Count > 0)
if (initializerSyntax.ArgumentList.Arguments.Count > 0 || !type.IsValueType)
{
return false;
}
var constructor = type.InstanceConstructors.SingleOrDefault(m => m.ParameterCount == 0);
return constructor?.IsDefaultValueTypeConstructor(requireZeroInit: true) == true;

// If exactly one parameterless constructor, return whether it's the default value type constructor
// Otherwise, return false
bool foundParameterlessCtor = false;
bool result = false;
foreach (var constructor in type.InstanceConstructors)
{
if (constructor.ParameterCount != 0)
{
continue;
}

if (foundParameterlessCtor)
{
// finding more than one parameterless constructor is an error scenario (reported elsewhere)
return false;
}

foundParameterlessCtor = true;
result = constructor.IsDefaultValueTypeConstructor(requireZeroInit: true);
}

return result;
333fred marked this conversation as resolved.
Show resolved Hide resolved
}

/// <summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1258,5 +1258,111 @@ .maxstack 1
IL_0006: ret
}");
}

[Fact, WorkItem(55797, "https://github.com/dotnet/roslyn/issues/55797")]
public void TwoParameterlessConstructors()
{
string source = @"
public class C
{
public C() : Garbage()
{
}
}
";
var comp = CreateCompilation(source);
comp.VerifyDiagnostics(
// (4,12): error CS0501: 'C.C()' must declare a body because it is not marked abstract, extern, or partial
// public C() : Garbage()
Diagnostic(ErrorCode.ERR_ConcreteMissingBody, "C").WithArguments("C.C()").WithLocation(4, 12),
// (4,18): error CS1018: Keyword 'this' or 'base' expected
// public C() : Garbage()
Diagnostic(ErrorCode.ERR_ThisOrBaseExpected, "Garbage").WithLocation(4, 18),
// (4,18): error CS1002: ; expected
// public C() : Garbage()
Diagnostic(ErrorCode.ERR_SemicolonExpected, "Garbage").WithLocation(4, 18),
// (4,18): error CS1520: Method must have a return type
// public C() : Garbage()
Diagnostic(ErrorCode.ERR_MemberNeedsType, "Garbage").WithLocation(4, 18),
// (4,18): error CS0121: The call is ambiguous between the following methods or properties: 'C.C()' and 'C.C()'
// public C() : Garbage()
Diagnostic(ErrorCode.ERR_AmbigCall, "").WithArguments("C.C()", "C.C()").WithLocation(4, 18)
);
}

[Fact, WorkItem(55797, "https://github.com/dotnet/roslyn/issues/55797")]
public void TwoParameterlessConstructors_2()
{
string source = @"
public class C
{
public C() : this()
{
}
public C()
{
}
}
";
var comp = CreateCompilation(source);
comp.VerifyDiagnostics(
// (4,18): error CS0121: The call is ambiguous between the following methods or properties: 'C.C()' and 'C.C()'
// public C() : this()
Diagnostic(ErrorCode.ERR_AmbigCall, "this").WithArguments("C.C()", "C.C()").WithLocation(4, 18),
// (7,12): error CS0111: Type 'C' already defines a member called 'C' with the same parameter types
// public C()
Diagnostic(ErrorCode.ERR_MemberAlreadyExists, "C").WithArguments("C", "C").WithLocation(7, 12)
);
}

[Fact, WorkItem(55797, "https://github.com/dotnet/roslyn/issues/55797")]
public void TwoParameterlessConstructors_3()
{
string source = @"
public class C
{
public C() : this()
{
}
public C2()
{
}
}
";
var comp = CreateCompilation(source);
comp.VerifyDiagnostics(
// (4,18): error CS0121: The call is ambiguous between the following methods or properties: 'C.C()' and 'C.C()'
// public C() : this()
Diagnostic(ErrorCode.ERR_AmbigCall, "this").WithArguments("C.C()", "C.C()").WithLocation(4, 18),
// (7,12): error CS1520: Method must have a return type
// public C2()
Diagnostic(ErrorCode.ERR_MemberNeedsType, "C2").WithLocation(7, 12)
);
}
333fred marked this conversation as resolved.
Show resolved Hide resolved

[Fact, WorkItem(55797, "https://github.com/dotnet/roslyn/issues/55797")]
public void TwoParameterlessConstructors_Struct()
{
string source = @"
public struct C
{
public C() : this()
{
}
public C2()
{
}
}
";
var comp = CreateCompilation(source);
comp.VerifyDiagnostics(
// (4,18): error CS0121: The call is ambiguous between the following methods or properties: 'C.C()' and 'C.C()'
// public C() : this()
Diagnostic(ErrorCode.ERR_AmbigCall, "this").WithArguments("C.C()", "C.C()").WithLocation(4, 18),
// (7,12): error CS1520: Method must have a return type
// public C2()
Diagnostic(ErrorCode.ERR_MemberNeedsType, "C2").WithLocation(7, 12)
);
}
}
}