From 05a38481a6aaa384387bff15130bf122d64a0733 Mon Sep 17 00:00:00 2001 From: AlekseyTs Date: Wed, 18 Sep 2019 19:02:10 -0700 Subject: [PATCH] Add cycle detection for more scenarios involving looking in base interfaces. (#38738) Fixes #38735. --- .../CSharp/Portable/Binder/Binder_Lookup.cs | 23 +++++++++----- .../DefaultInterfaceImplementationTests.cs | 31 +++++++++++++++++++ 2 files changed, 47 insertions(+), 7 deletions(-) diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Lookup.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Lookup.cs index c02b2ef2f64..aef055a24c8 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder_Lookup.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder_Lookup.cs @@ -951,6 +951,8 @@ private static ImmutableArray GetBaseInterfaces(NamedTypeSymbol return ImmutableArray.Empty; } + var cycleGuard = ConsList.Empty.Prepend(type.OriginalDefinition); + // Consumers of the result depend on the sorting performed by AllInterfacesWithDefinitionUseSiteDiagnostics. // Let's use similar sort algorithm. var result = ArrayBuilder.GetInstance(); @@ -958,7 +960,7 @@ private static ImmutableArray GetBaseInterfaces(NamedTypeSymbol for (int i = interfaces.Length - 1; i >= 0; i--) { - addAllInterfaces(interfaces[i], visited, result, basesBeingResolved); + addAllInterfaces(interfaces[i], visited, result, basesBeingResolved, cycleGuard); } result.ReverseContents(); @@ -970,17 +972,24 @@ private static ImmutableArray GetBaseInterfaces(NamedTypeSymbol return result.ToImmutableAndFree(); - static void addAllInterfaces(NamedTypeSymbol @interface, HashSet visited, ArrayBuilder result, ConsList basesBeingResolved) + static void addAllInterfaces(NamedTypeSymbol @interface, HashSet visited, ArrayBuilder result, ConsList basesBeingResolved, ConsList cycleGuard) { - if (@interface.IsInterface && visited.Add(@interface)) + NamedTypeSymbol originalDefinition; + + if (@interface.IsInterface && !cycleGuard.ContainsReference(originalDefinition = @interface.OriginalDefinition) && visited.Add(@interface)) { - if (!basesBeingResolved.ContainsReference(@interface.OriginalDefinition)) + if (!basesBeingResolved.ContainsReference(originalDefinition)) { ImmutableArray baseInterfaces = @interface.GetDeclaredInterfaces(basesBeingResolved); - for (int i = baseInterfaces.Length - 1; i >= 0; i--) + + if (!baseInterfaces.IsEmpty) { - var baseInterface = baseInterfaces[i]; - addAllInterfaces(baseInterface, visited, result, basesBeingResolved); + cycleGuard = cycleGuard.Prepend(originalDefinition); + for (int i = baseInterfaces.Length - 1; i >= 0; i--) + { + var baseInterface = baseInterfaces[i]; + addAllInterfaces(baseInterface, visited, result, basesBeingResolved, cycleGuard); + } } } diff --git a/src/Compilers/CSharp/Test/Symbol/Symbols/DefaultInterfaceImplementationTests.cs b/src/Compilers/CSharp/Test/Symbol/Symbols/DefaultInterfaceImplementationTests.cs index c3b6d7150c1..2078e7df553 100644 --- a/src/Compilers/CSharp/Test/Symbol/Symbols/DefaultInterfaceImplementationTests.cs +++ b/src/Compilers/CSharp/Test/Symbol/Symbols/DefaultInterfaceImplementationTests.cs @@ -29512,6 +29512,37 @@ public interface I14 : I11.I13 ); } + [Fact] + [WorkItem(38735, "https://github.com/dotnet/roslyn/issues/38735")] + public void NestedTypes_52() + { + var source1 = +@" +interface I1 : IA.NF { } + +interface IQ { } + +interface IA : IB> { } + +interface IB : IA> { } +"; + + var compilation1 = CreateCompilation(source1, options: TestOptions.DebugDll, + parseOptions: TestOptions.Regular); + + compilation1.VerifyDiagnostics( + // (2,24): error CS0426: The type name 'NF' does not exist in the type 'IA' + // interface I1 : IA.NF { } + Diagnostic(ErrorCode.ERR_DottedTypeNameNotFoundInAgg, "NF").WithArguments("NF", "IA").WithLocation(2, 24), + // (6,11): error CS0529: Inherited interface 'IB>' causes a cycle in the interface hierarchy of 'IA' + // interface IA : IB> { } + Diagnostic(ErrorCode.ERR_CycleInInterfaceInheritance, "IA").WithArguments("IA", "IB>").WithLocation(6, 11), + // (8,11): error CS0529: Inherited interface 'IA>' causes a cycle in the interface hierarchy of 'IB' + // interface IB : IA> { } + Diagnostic(ErrorCode.ERR_CycleInInterfaceInheritance, "IB").WithArguments("IB", "IA>").WithLocation(8, 11) + ); + } + [Fact] [WorkItem(32540, "https://github.com/dotnet/roslyn/issues/32540")] public void MethodImplementationInDerived_01() -- GitLab