From 43f2329f0e4738b0e05812e68e9f82b78945d74c Mon Sep 17 00:00:00 2001 From: Charles Stoner Date: Tue, 9 Apr 2019 16:05:51 -0700 Subject: [PATCH] Compare constraints lazily across partial type declarations (#34850) --- .../Symbols/Source/SourceNamedTypeSymbol.cs | 40 +++++-- .../Semantics/NullableReferenceTypesTests.cs | 109 ++++++++++++++++++ 2 files changed, 138 insertions(+), 11 deletions(-) diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceNamedTypeSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceNamedTypeSymbol.cs index ebfec1674f156..364fd5b5f848b 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceNamedTypeSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceNamedTypeSymbol.cs @@ -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) { @@ -299,16 +299,6 @@ private ImmutableArray 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)); @@ -319,6 +309,34 @@ private ImmutableArray MakeTypeParameterConstrain return results; } + private ImmutableArray MakeTypeParameterConstraintsLate( + ImmutableArray 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 GetConstraintClauses(CSharpSyntaxNode node) { switch (node.Kind()) diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/NullableReferenceTypesTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/NullableReferenceTypesTests.cs index a63de06e94093..a550a065dece5 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/NullableReferenceTypesTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/NullableReferenceTypesTests.cs @@ -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 where T : IEquatable +{ +}"; + var source2 = +@"using System; +partial class C where T : IEquatable +{ +}"; + var comp = CreateCompilation(new[] { source1, source2 }); + comp.VerifyDiagnostics( + // (3,15): error CS0265: Partial declarations of 'C' have inconsistent constraints for type parameter 'T' + // partial class C where T : IEquatable + Diagnostic(ErrorCode.ERR_PartialWrongConstraints, "C").WithArguments("C", "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 where T : class?, IEquatable +{ +}"; + var source2 = +@"using System; +partial class C where T : class, IEquatable +{ +}"; + var comp = CreateCompilation(new[] { source1, source2 }); + comp.VerifyDiagnostics( + // (3,15): error CS0265: Partial declarations of 'C' have inconsistent constraints for type parameter 'T' + // partial class C where T : IEquatable + Diagnostic(ErrorCode.ERR_PartialWrongConstraints, "C").WithArguments("C", "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 where T : IEquatable +{ +}"; + var source2 = +@"using System; +class C where T : IEquatable +{ +}"; + var comp = CreateCompilation(new[] { source1, source2 }); + comp.VerifyDiagnostics( + // (2,7): error CS0101: The namespace '' already contains a definition for 'C' + // class C where T : IEquatable + Diagnostic(ErrorCode.ERR_DuplicateNameInNS, "C").WithArguments("C", "").WithLocation(2, 7), + // (3,7): error CS0265: Partial declarations of 'C' have inconsistent constraints for type parameter 'T' + // class C where T : IEquatable + Diagnostic(ErrorCode.ERR_PartialWrongConstraints, "C").WithArguments("C", "T").WithLocation(3, 7)); + } + + [Fact] + public void PartialClassWithConstraints_04() + { + var source1 = +@"#nullable enable +using System; +partial class C +{ + static partial void F() where T : IEquatable; +}"; + var source2 = +@"using System; +partial class C +{ + static partial void F() where T : IEquatable { } +}"; + 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() where T : class?, IEquatable; +}"; + var source2 = +@"using System; +partial class C +{ + static partial void F() where T : class, IEquatable { } +}"; + var comp = CreateCompilation(new[] { source1, source2 }); + comp.VerifyDiagnostics(); + } } }