Skip to content

Commit

Permalink
Compare constraints lazily across partial type declarations (#34850)
Browse files Browse the repository at this point in the history
  • Loading branch information
cston authored Apr 9, 2019
1 parent 564e387 commit 43f2329
Show file tree
Hide file tree
Showing 2 changed files with 138 additions and 11 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -252,7 +252,7 @@ internal TypeParameterConstraintClause GetTypeParameterConstraintClause(bool ear
{
// Late step.
var diagnostics = DiagnosticBag.GetInstance();
var constraints = ConstraintsHelper.MakeTypeParameterConstraintsLate(TypeParameters, clauses, diagnostics);
var constraints = MakeTypeParameterConstraintsLate(clauses, diagnostics);
Debug.Assert(!constraints.IsEarly());
if (ImmutableInterlocked.InterlockedCompareExchange(ref _lazyTypeParameterConstraints, constraints, clauses) == clauses)
{
Expand Down Expand Up @@ -299,16 +299,6 @@ private ImmutableArray<TypeParameterConstraintClause> MakeTypeParameterConstrain
}
else
{
// Constraints defined on multiple partial declarations.
// Report any mismatched constraints.
for (int i = 0; i < arity; i++)
{
if (!HaveSameConstraints(results[i], constraints[i]))
{
// "Partial declarations of '{0}' have inconsistent constraints for type parameter '{1}'"
diagnostics.Add(ErrorCode.ERR_PartialWrongConstraints, Locations[0], this, typeParameters[i]);
}
}
// Merge in the other partial declaration constraints so all
// partial declarations can be checked in late step.
results = results.ZipAsArray(constraints, (x, y) => x.AddPartialDeclaration(y));
Expand All @@ -319,6 +309,34 @@ private ImmutableArray<TypeParameterConstraintClause> MakeTypeParameterConstrain
return results;
}

private ImmutableArray<TypeParameterConstraintClause> MakeTypeParameterConstraintsLate(
ImmutableArray<TypeParameterConstraintClause> constraintClauses,
DiagnosticBag diagnostics)
{
var typeParameters = TypeParameters;
int arity = typeParameters.Length;

Debug.Assert(constraintClauses.IsEarly());
Debug.Assert(constraintClauses.Length == arity);

for (int i = 0; i < arity; i++)
{
var constraint = constraintClauses[i];
// Constraints defined on multiple partial declarations.
// Report any mismatched constraints.
foreach (var other in constraint.OtherPartialDeclarations)
{
if (!HaveSameConstraints(constraint, other))
{
// "Partial declarations of '{0}' have inconsistent constraints for type parameter '{1}'"
diagnostics.Add(ErrorCode.ERR_PartialWrongConstraints, Locations[0], this, typeParameters[i]);
}
}
}

return ConstraintsHelper.MakeTypeParameterConstraintsLate(typeParameters, constraintClauses, diagnostics);
}

private static SyntaxList<TypeParameterConstraintClauseSyntax> GetConstraintClauses(CSharpSyntaxNode node)
{
switch (node.Kind())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87434,5 +87434,114 @@ static void M(string? x)
var comp = CreateCompilation(new[] { source, EnsuresNotNullAttributeDefinition }, options: WithNonNullTypesTrue());
comp.VerifyDiagnostics();
}

[Fact]
[WorkItem(34841, "https://github.com/dotnet/roslyn/issues/34841")]
public void PartialClassWithConstraints_01()
{
var source1 =
@"#nullable enable
using System;
partial class C<T> where T : IEquatable<T>
{
}";
var source2 =
@"using System;
partial class C<T> where T : IEquatable<T>
{
}";
var comp = CreateCompilation(new[] { source1, source2 });
comp.VerifyDiagnostics(
// (3,15): error CS0265: Partial declarations of 'C<T>' have inconsistent constraints for type parameter 'T'
// partial class C<T> where T : IEquatable<T>
Diagnostic(ErrorCode.ERR_PartialWrongConstraints, "C").WithArguments("C<T>", "T").WithLocation(3, 15));
}

[Fact]
[WorkItem(34841, "https://github.com/dotnet/roslyn/issues/34841")]
public void PartialClassWithConstraints_02()
{
var source1 =
@"#nullable enable
using System;
partial class C<T> where T : class?, IEquatable<T?>
{
}";
var source2 =
@"using System;
partial class C<T> where T : class, IEquatable<T>
{
}";
var comp = CreateCompilation(new[] { source1, source2 });
comp.VerifyDiagnostics(
// (3,15): error CS0265: Partial declarations of 'C<T>' have inconsistent constraints for type parameter 'T'
// partial class C<T> where T : IEquatable<T>
Diagnostic(ErrorCode.ERR_PartialWrongConstraints, "C").WithArguments("C<T>", "T").WithLocation(3, 15));
}

[Fact]
[WorkItem(34841, "https://github.com/dotnet/roslyn/issues/34841")]
public void PartialClassWithConstraints_03()
{
var source1 =
@"#nullable enable
using System;
class C<T> where T : IEquatable<T>
{
}";
var source2 =
@"using System;
class C<T> where T : IEquatable<T>
{
}";
var comp = CreateCompilation(new[] { source1, source2 });
comp.VerifyDiagnostics(
// (2,7): error CS0101: The namespace '<global namespace>' already contains a definition for 'C'
// class C<T> where T : IEquatable<T>
Diagnostic(ErrorCode.ERR_DuplicateNameInNS, "C").WithArguments("C", "<global namespace>").WithLocation(2, 7),
// (3,7): error CS0265: Partial declarations of 'C<T>' have inconsistent constraints for type parameter 'T'
// class C<T> where T : IEquatable<T>
Diagnostic(ErrorCode.ERR_PartialWrongConstraints, "C").WithArguments("C<T>", "T").WithLocation(3, 7));
}

[Fact]
public void PartialClassWithConstraints_04()
{
var source1 =
@"#nullable enable
using System;
partial class C
{
static partial void F<T>() where T : IEquatable<T>;
}";
var source2 =
@"using System;
partial class C
{
static partial void F<T>() where T : IEquatable<T> { }
}";
var comp = CreateCompilation(new[] { source1, source2 });
comp.VerifyDiagnostics();
}

[Fact]
public void PartialClassWithConstraints_05()
{
var source1 =
@"#nullable enable
using System;
partial class C
{
static partial void F<T>() where T : class?, IEquatable<T?>;
}";
var source2 =
@"using System;
partial class C
{
static partial void F<T>() where T : class, IEquatable<T> { }
}";
var comp = CreateCompilation(new[] { source1, source2 });
comp.VerifyDiagnostics();
}
}
}

0 comments on commit 43f2329

Please sign in to comment.