From cae111aa2e68b57c9aea73b22c0bb5f3ff814fed Mon Sep 17 00:00:00 2001 From: Jackson Schuster <36744439+jtschuster@users.noreply.github.com> Date: Thu, 15 Feb 2024 20:16:23 -0800 Subject: [PATCH 1/3] Add test case for interfaces without impls for whole hierarchy --- src/tools/illink/illink.sln | 1 + .../illink/src/linker/Linker/TypeMapInfo.cs | 34 ++++++-- .../linker/Linker/TypeReferenceExtensions.cs | 31 ++++--- ...terfaces.DefaultInterfaceMethodsTests.g.cs | 6 ++ ...mProvidedByUnreferencedIfaceInHierarchy.il | 87 +++++++++++++++++++ ...mProvidedByUnreferencedIfaceInHierarchy.il | 70 +++++++++++++++ ...mProvidedByUnreferencedIfaceInHierarchy.cs | 68 +++++++++++++++ ...mProvidedByUnreferencedIfaceInHierarchy.cs | 71 +++++++++++++++ 8 files changed, 350 insertions(+), 18 deletions(-) create mode 100644 src/tools/illink/test/Mono.Linker.Tests.Cases/Inheritance.Interfaces/DefaultInterfaceMethods/Dependencies/DimProvidedByUnreferencedIfaceInHierarchy.il create mode 100644 src/tools/illink/test/Mono.Linker.Tests.Cases/Inheritance.Interfaces/DefaultInterfaceMethods/Dependencies/StaticDimProvidedByUnreferencedIfaceInHierarchy.il create mode 100644 src/tools/illink/test/Mono.Linker.Tests.Cases/Inheritance.Interfaces/DefaultInterfaceMethods/DimProvidedByUnreferencedIfaceInHierarchy.cs create mode 100644 src/tools/illink/test/Mono.Linker.Tests.Cases/Inheritance.Interfaces/DefaultInterfaceMethods/StaticDimProvidedByUnreferencedIfaceInHierarchy.cs diff --git a/src/tools/illink/illink.sln b/src/tools/illink/illink.sln index 87e99d208c7fb6..9b8d904942baaf 100644 --- a/src/tools/illink/illink.sln +++ b/src/tools/illink/illink.sln @@ -223,6 +223,7 @@ Global SolutionGuid = {E43A3901-42B0-48CA-BB36-5CD40A99A6EE} EndGlobalSection GlobalSection(SharedMSBuildProjectFiles) = preSolution + test\Trimming.Tests.Shared\Trimming.Tests.Shared.projitems*{400a1561-b6b6-482d-9e4c-3ddaede5bd07}*SharedItemsImports = 5 src\ILLink.Shared\ILLink.Shared.projitems*{dd28e2b1-057b-4b4d-a04d-b2ebd9e76e46}*SharedItemsImports = 5 src\ILLink.Shared\ILLink.Shared.projitems*{f1a44a78-34ee-408b-8285-9a26f0e7d4f2}*SharedItemsImports = 5 src\ILLink.Shared\ILLink.Shared.projitems*{ff598e93-8e9e-4091-9f50-61a7572663ae}*SharedItemsImports = 13 diff --git a/src/tools/illink/src/linker/Linker/TypeMapInfo.cs b/src/tools/illink/src/linker/Linker/TypeMapInfo.cs index a2f118adf9fb78..f326af5d7a0a1a 100644 --- a/src/tools/illink/src/linker/Linker/TypeMapInfo.cs +++ b/src/tools/illink/src/linker/Linker/TypeMapInfo.cs @@ -141,6 +141,24 @@ protected virtual void MapType (TypeDefinition type) MapType (nested); } + static HashSet GetRecursiveInterfaces (TypeDefinition type) + { + if (!type.HasInterfaces) + return []; + + HashSet interfaces = new HashSet (); + GetInterfacesOnType (type, interfaces); + return interfaces; + + static void GetInterfacesOnType (TypeDefinition type, HashSet interfaces) + { + foreach (var iface in type.Interfaces) { + interfaces.Add (iface.InterfaceType); + GetInterfacesOnType(type, interfaces); + } + } + } + void MapInterfaceMethodsInTypeHierarchy (TypeDefinition type) { if (!type.HasInterfaces) @@ -181,7 +199,7 @@ void MapInterfaceMethodsInTypeHierarchy (TypeDefinition type) } // Look for a default implementation last. - FindAndAddDefaultInterfaceImplementations (type, resolvedInterfaceMethod); + FindAndAddDefaultInterfaceImplementations (type, type, resolvedInterfaceMethod); } } } @@ -283,12 +301,12 @@ void AnnotateMethods (MethodDefinition @base, MethodDefinition @override, Interf // Note that this returns a list to potentially cover the diamond case (more than one // most specific implementation of the given interface methods). ILLink needs to preserve // all the implementations so that the proper exception can be thrown at runtime. - void FindAndAddDefaultInterfaceImplementations (TypeDefinition type, MethodDefinition interfaceMethod) + void FindAndAddDefaultInterfaceImplementations (TypeDefinition typeThatImplementsInterface, TypeDefinition typeThatMayHaveDIM, MethodDefinition interfaceMethodToBeImplemented) { // Go over all interfaces, trying to find a method that is an explicit MethodImpl of the // interface method in question. - foreach (var interfaceImpl in type.Interfaces) { + foreach (var interfaceImpl in typeThatMayHaveDIM.Interfaces) { var potentialImplInterface = context.TryResolve (interfaceImpl.InterfaceType); if (potentialImplInterface == null) continue; @@ -296,9 +314,9 @@ void FindAndAddDefaultInterfaceImplementations (TypeDefinition type, MethodDefin bool foundImpl = false; foreach (var potentialImplMethod in potentialImplInterface.Methods) { - if (potentialImplMethod == interfaceMethod && + if (potentialImplMethod == interfaceMethodToBeImplemented && !potentialImplMethod.IsAbstract) { - AddDefaultInterfaceImplementation (interfaceMethod, type, (interfaceImpl, potentialImplMethod)); + AddDefaultInterfaceImplementation (interfaceMethodToBeImplemented, typeThatImplementsInterface, (interfaceImpl, potentialImplMethod)); foundImpl = true; break; } @@ -308,8 +326,8 @@ void FindAndAddDefaultInterfaceImplementations (TypeDefinition type, MethodDefin // This method is an override of something. Let's see if it's the method we are looking for. foreach (var @override in potentialImplMethod.Overrides) { - if (context.TryResolve (@override) == interfaceMethod) { - AddDefaultInterfaceImplementation (interfaceMethod, type, (interfaceImpl, @potentialImplMethod)); + if (context.TryResolve (@override) == interfaceMethodToBeImplemented) { + AddDefaultInterfaceImplementation (interfaceMethodToBeImplemented, typeThatImplementsInterface, (interfaceImpl, @potentialImplMethod)); foundImpl = true; break; } @@ -323,7 +341,7 @@ void FindAndAddDefaultInterfaceImplementations (TypeDefinition type, MethodDefin // We haven't found a MethodImpl on the current interface, but one of the interfaces // this interface requires could still provide it. if (!foundImpl) { - FindAndAddDefaultInterfaceImplementations (potentialImplInterface, interfaceMethod); + FindAndAddDefaultInterfaceImplementations (typeThatImplementsInterface, potentialImplInterface, interfaceMethodToBeImplemented); } } } diff --git a/src/tools/illink/src/linker/Linker/TypeReferenceExtensions.cs b/src/tools/illink/src/linker/Linker/TypeReferenceExtensions.cs index 5092fe1158e34b..28680c1b644e3f 100644 --- a/src/tools/illink/src/linker/Linker/TypeReferenceExtensions.cs +++ b/src/tools/illink/src/linker/Linker/TypeReferenceExtensions.cs @@ -151,22 +151,33 @@ void parseArrayDimensions (ArrayType at) return null; } - public static IEnumerable<(TypeReference InflatedInterface, InterfaceImplementation OriginalImpl)> GetInflatedInterfaces (this TypeReference typeRef, ITryResolveMetadata resolver) + public static HashSet<(TypeReference InflatedInterface, InterfaceImplementation OriginalImpl)> GetInflatedInterfaces (this TypeReference typeRef, ITryResolveMetadata resolver) { var typeDef = resolver.TryResolve (typeRef); if (typeDef?.HasInterfaces != true) - yield break; + return []; + HashSet<(TypeReference, InterfaceImplementation)> inflatedInterfaces = new (); + AddInflatedInterfacesRecursively (typeRef, typeDef, resolver, inflatedInterfaces); + return inflatedInterfaces; - if (typeRef is GenericInstanceType genericInstance) { - foreach (var interfaceImpl in typeDef.Interfaces) { - // InflateGenericType only returns null when inflating generic parameters (and the generic instance type doesn't resolve). - // Here we are not inflating a generic parameter but an interface type reference. - yield return (InflateGenericType (genericInstance, interfaceImpl.InterfaceType, resolver), interfaceImpl)!; + static void AddInflatedInterfacesRecursively(TypeReference typeRef, TypeDefinition interfaceProvider, ITryResolveMetadata resolver, HashSet<(TypeReference, InterfaceImplementation)> inflatedInterfaces) + { + if (typeRef is GenericInstanceType genericInstance) { + foreach (var interfaceImpl in interfaceProvider.Interfaces) { + // InflateGenericType only returns null when inflating generic parameters (and the generic instance type doesn't resolve). + // Here we are not inflating a generic parameter but an interface type reference. + inflatedInterfaces.Add((InflateGenericType (genericInstance, interfaceImpl.InterfaceType, resolver), interfaceImpl)!); + if (resolver.TryResolve (interfaceImpl.InterfaceType) is { } baseIface) + AddInflatedInterfacesRecursively (typeRef, baseIface, resolver, inflatedInterfaces); + } + } else { + foreach (var interfaceImpl in interfaceProvider.Interfaces) { + inflatedInterfaces.Add ((interfaceImpl.InterfaceType, interfaceImpl)); + if (resolver.TryResolve (interfaceImpl.InterfaceType) is { } baseIface) + AddInflatedInterfacesRecursively (typeRef, baseIface, resolver, inflatedInterfaces); + } } - } else { - foreach (var interfaceImpl in typeDef.Interfaces) - yield return (interfaceImpl.InterfaceType, interfaceImpl); } } diff --git a/src/tools/illink/test/ILLink.RoslynAnalyzer.Tests/generated/ILLink.RoslynAnalyzer.Tests.Generator/ILLink.RoslynAnalyzer.Tests.TestCaseGenerator/Inheritance.Interfaces.DefaultInterfaceMethodsTests.g.cs b/src/tools/illink/test/ILLink.RoslynAnalyzer.Tests/generated/ILLink.RoslynAnalyzer.Tests.Generator/ILLink.RoslynAnalyzer.Tests.TestCaseGenerator/Inheritance.Interfaces.DefaultInterfaceMethodsTests.g.cs index 4b3f387a390151..f89602a1950551 100644 --- a/src/tools/illink/test/ILLink.RoslynAnalyzer.Tests/generated/ILLink.RoslynAnalyzer.Tests.Generator/ILLink.RoslynAnalyzer.Tests.TestCaseGenerator/Inheritance.Interfaces.DefaultInterfaceMethodsTests.g.cs +++ b/src/tools/illink/test/ILLink.RoslynAnalyzer.Tests/generated/ILLink.RoslynAnalyzer.Tests.Generator/ILLink.RoslynAnalyzer.Tests.TestCaseGenerator/Inheritance.Interfaces.DefaultInterfaceMethodsTests.g.cs @@ -15,6 +15,12 @@ public Task DefaultInterfaceMethodCallIntoClass () return RunTest (allowMissingWarnings: true); } + [Fact] + public Task DimProvidedByUnreferencedIfaceInHierarchy () + { + return RunTest (allowMissingWarnings: true); + } + [Fact] public Task GenericDefaultInterfaceMethods () { diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases/Inheritance.Interfaces/DefaultInterfaceMethods/Dependencies/DimProvidedByUnreferencedIfaceInHierarchy.il b/src/tools/illink/test/Mono.Linker.Tests.Cases/Inheritance.Interfaces/DefaultInterfaceMethods/Dependencies/DimProvidedByUnreferencedIfaceInHierarchy.il new file mode 100644 index 00000000000000..416f1202c682ca --- /dev/null +++ b/src/tools/illink/test/Mono.Linker.Tests.Cases/Inheritance.Interfaces/DefaultInterfaceMethods/Dependencies/DimProvidedByUnreferencedIfaceInHierarchy.il @@ -0,0 +1,87 @@ + +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +.assembly extern mscorlib { } + +.assembly 'library' { } + +.class public auto ansi abstract sealed beforefieldinit Program + extends [mscorlib]System.Object +{ + // Nested Types + .class interface nested public auto ansi abstract beforefieldinit IFoo + { + // Methods + .method public hidebysig newslot abstract virtual + instance void Method () cil managed + { + } // end of method IFoo::Method + + } // end of class IFoo + + .class interface nested public auto ansi abstract beforefieldinit IBar + implements Program/IFoo + { + // Methods + .method public final hidebysig virtual + instance void Program.IFoo.Method () cil managed + { + .override method instance void Program/IFoo::Method() + // Method begins at RVA 0x2068 + // Code size 2 (0x2) + .maxstack 8 + + IL_0000: nop + IL_0001: ret + } // end of method IBar::Program.IFoo.Method + + } // end of class IBar + + .class interface nested public auto ansi abstract beforefieldinit IBaz + implements Program/IBar + { + } // end of class IBaz + + .class nested public auto ansi beforefieldinit MyFoo + extends [mscorlib]System.Object + implements Program/IBaz + { + // Methods + .method public hidebysig specialname rtspecialname + instance void .ctor () cil managed + { + // Method begins at RVA 0x2076 + // Code size 8 (0x8) + .maxstack 8 + + IL_0000: ldarg.0 + IL_0001: call instance void [mscorlib]System.Object::.ctor() + IL_0006: nop + IL_0007: ret + } // end of method MyFoo::.ctor + + } // end of class MyFoo + + + // Methods + .method public hidebysig static + void CallMethod ( + class Program/IFoo foo + ) cil managed + { + .custom instance void [mscorlib]mscorlib.CompilerServices.NullableContextAttribute::.ctor(uint8) = ( + 01 00 01 00 00 + ) + // Method begins at RVA 0x2050 + // Code size 9 (0x9) + .maxstack 8 + + IL_0000: nop + IL_0001: ldarg.0 + IL_0002: callvirt instance void Program/IFoo::Method() + IL_0007: nop + IL_0008: ret + } // end of method Program::CallMethod + +} // end of class Program diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases/Inheritance.Interfaces/DefaultInterfaceMethods/Dependencies/StaticDimProvidedByUnreferencedIfaceInHierarchy.il b/src/tools/illink/test/Mono.Linker.Tests.Cases/Inheritance.Interfaces/DefaultInterfaceMethods/Dependencies/StaticDimProvidedByUnreferencedIfaceInHierarchy.il new file mode 100644 index 00000000000000..949d5e6fbf4aba --- /dev/null +++ b/src/tools/illink/test/Mono.Linker.Tests.Cases/Inheritance.Interfaces/DefaultInterfaceMethods/Dependencies/StaticDimProvidedByUnreferencedIfaceInHierarchy.il @@ -0,0 +1,70 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +.assembly extern mscorlib { } + +.assembly 'library' { } + +.class public auto ansi abstract sealed beforefieldinit Program + extends [mscorlib]System.Object +{ + // Nested Types + .class interface nested public auto ansi abstract beforefieldinit IBase + { + // Methods + .method public hidebysig abstract virtual static + void Method () cil managed + { + } // end of method IBase::Method + + } // end of class IBase + + .class interface nested public auto ansi abstract beforefieldinit I2 + implements Program/IBase + { + // Methods + .method public hidebysig static + void Program.IBase.Method () cil managed + { + .override method void Program/IBase::Method() + // Method begins at RVA 0x205f + // Code size 2 (0x2) + .maxstack 8 + + IL_0000: nop + IL_0001: ret + } // end of method I2::Program.IBase.Method + + } // end of class I2 + + .class interface nested public auto ansi abstract beforefieldinit I3 + implements Program/I2 + { + } // end of class I3 + + .class interface nested public auto ansi abstract beforefieldinit I4 + implements Program/I3 + { + } // end of class I4 + + + // Methods + .method public hidebysig static + void CallMethod<(Program/IBase) T> () cil managed + { + .param constraint T, Program/IBase + .custom instance void [mscorlib]mscorlib.CompilerServices.NullableAttribute::.ctor(uint8) = ( + 01 00 01 00 00 + ) + // Method begins at RVA 0x2050 + // Code size 14 (0xe) + .maxstack 8 + + IL_0000: nop + IL_0001: constrained. !!T + IL_0007: call void Program/IBase::Method() + IL_000c: nop + IL_000d: ret + } // end of method Program::CallMethod + +} // end of class Program diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases/Inheritance.Interfaces/DefaultInterfaceMethods/DimProvidedByUnreferencedIfaceInHierarchy.cs b/src/tools/illink/test/Mono.Linker.Tests.Cases/Inheritance.Interfaces/DefaultInterfaceMethods/DimProvidedByUnreferencedIfaceInHierarchy.cs new file mode 100644 index 00000000000000..cfc9e4a367d23e --- /dev/null +++ b/src/tools/illink/test/Mono.Linker.Tests.Cases/Inheritance.Interfaces/DefaultInterfaceMethods/DimProvidedByUnreferencedIfaceInHierarchy.cs @@ -0,0 +1,68 @@ + + +using Mono.Linker.Tests.Cases.Expectations.Assertions; +using Mono.Linker.Tests.Cases.Expectations.Metadata; + +namespace Mono.Linker.Tests.Cases.Inheritance.Interfaces.DefaultInterfaceMethods +{ + [SetupLinkerArgument ("--skip-unresolved", "true")] + [TestCaseRequirements (TestRunCharacteristics.SupportsDefaultInterfaceMethods, "Requires support for default interface methods")] + [Define ("IL_ASSEMBLY_AVAILABLE")] + [SetupCompileBefore ("library.dll", new[] { "Dependencies/DimProvidedByUnreferencedIfaceInHierarchy.il" })] + [SkipILVerify] + +#if IL_ASSEMBLY_AVAILABLE + [KeptMemberInAssembly ("library.dll", typeof(Program.IBar), "Program.IFoo.Method()")] + [KeptMemberInAssembly ("library.dll", typeof(Program.IFoo), "Method()")] + [KeptTypeInAssembly ("library.dll", typeof(Program.IBar))] + [KeptInterfaceOnTypeInAssembly ("library.dll", typeof (Program.IBar), "library.dll", typeof (Program.IFoo))] + // https://github.com/dotnet/runtime/issues/98536 + //[KeptInterfaceOnTypeInAssembly ("library.dll", typeof (Program.MyFoo), "library.dll", typeof (Program.IBaz))] + //[KeptTypeInAssembly ("library.dll", typeof(Program.IBaz))] + //[KeptInterfaceOnTypeInAssembly ("library.dll", typeof (Program.IBaz), "library.dll", typeof (Program.IBar))] + [KeptMemberInAssembly ("library.dll", typeof(Program), "CallMethod(Program/IFoo)")] +#endif + class DimProvidedByUnreferencedIfaceInHierarchy + { + static void Main () + { +#if IL_ASSEMBLY_AVAILABLE + Program.IFoo foo = new Program.MyFoo (); + Program.CallMethod(foo); +#endif + } + } +} + + + +// public static class Program +// { +// [Kept] +// interface IFoo +// { +// void Method(); +// } + +// [Kept] +// interface IBar : IFoo +// { +// [Kept] +// void IFoo.Method() { } +// } + +// [Kept] +// interface IBaz: IBar /* not IFoo */ +// { +// } + +// [Kept] +// [KeptInterface(typeof(IBaz))] +// class MyFoo : IBaz /* not IBar, not IFoo */ +// { } + +// static void CallMethod(IFoo foo) +// { +// foo.Method(); +// } +// } diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases/Inheritance.Interfaces/DefaultInterfaceMethods/StaticDimProvidedByUnreferencedIfaceInHierarchy.cs b/src/tools/illink/test/Mono.Linker.Tests.Cases/Inheritance.Interfaces/DefaultInterfaceMethods/StaticDimProvidedByUnreferencedIfaceInHierarchy.cs new file mode 100644 index 00000000000000..a65ad7d2f754c0 --- /dev/null +++ b/src/tools/illink/test/Mono.Linker.Tests.Cases/Inheritance.Interfaces/DefaultInterfaceMethods/StaticDimProvidedByUnreferencedIfaceInHierarchy.cs @@ -0,0 +1,71 @@ + + +using Mono.Linker.Tests.Cases.Expectations.Assertions; +using Mono.Linker.Tests.Cases.Expectations.Metadata; + +namespace Mono.Linker.Tests.Cases.Inheritance.Interfaces.DefaultInterfaceMethods +{ + [SetupLinkerArgument ("--skip-unresolved", "true")] + [TestCaseRequirements (TestRunCharacteristics.SupportsDefaultInterfaceMethods, "Requires support for default interface methods")] + [Define ("IL_ASSEMBLY_AVAILABLE")] + [SetupCompileBefore ("library.dll", new[] { "Dependencies/StaticDimProvidedByUnreferencedIfaceInHierarchy.il" })] + [SkipILVerify] + +#if IL_ASSEMBLY_AVAILABLE + [KeptMemberInAssembly ("library.dll", typeof(Program), "CallMethod<#1>()")] + [KeptTypeInAssembly ("library.dll", typeof(Program.IBase))] + [KeptMemberInAssembly ("library.dll", typeof(Program.IBase), "Method()")] + [KeptTypeInAssembly ("library.dll", typeof(Program.I2))] + [KeptMemberInAssembly ("library.dll", typeof(Program.I2), "Program.IBase.Method()")] + [KeptInterfaceOnTypeInAssembly ("library.dll", typeof (Program.I2), "library.dll", typeof (Program.IBase))] + // https://github.com/dotnet/runtime/issues/98536 + //[KeptTypeInAssembly ("library.dll", typeof(Program.I3))] + //[KeptInterfaceOnTypeInAssembly ("library.dll", typeof (Program.I3), "library.dll", typeof (Program.I2))] + [KeptTypeInAssembly ("library.dll", typeof(Program.I4))] + // https://github.com/dotnet/runtime/issues/98536 + //[KeptInterfaceOnTypeInAssembly ("library.dll", typeof (Program.I4), "library.dll", typeof (Program.I3))] +#endif + class StaticDimProvidedByUnreferencedIfaceInHierarchy + { + static void Main () + { +#if IL_ASSEMBLY_AVAILABLE + Program.CallMethod(); +#endif + } + } +} + + + +// public static class Program +// { +// [Kept] +// interface IBase +// { +// [Kept] +// static abstract void Method(); +// } + +// [Kept] +// [KeptInterface(typeof(IBase)] +// interface I2 : IBase +// { +// [Kept] +// static void IBase.Method() { } +// } + +// [Kept] +// [KeptInterface(typeof(I2)] +// interface I3 : I2 { } + +// [Kept] +// [KeptInterface(typeof(I3)] +// interface I4 : I3 { } + +// [Kept] +// static void CallMethod() where T : IBase +// { +// T.Method(); +// } +// } From 00d42b7af56d5d6e15f6147cabe500012e0f8113 Mon Sep 17 00:00:00 2001 From: Jackson Schuster <36744439+jtschuster@users.noreply.github.com> Date: Thu, 15 Feb 2024 20:18:04 -0800 Subject: [PATCH 2/3] Undo source changes --- src/tools/illink/illink.sln | 1 - .../illink/src/linker/Linker/TypeMapInfo.cs | 34 +++++-------------- .../linker/Linker/TypeReferenceExtensions.cs | 31 ++++++----------- 3 files changed, 18 insertions(+), 48 deletions(-) diff --git a/src/tools/illink/illink.sln b/src/tools/illink/illink.sln index 9b8d904942baaf..87e99d208c7fb6 100644 --- a/src/tools/illink/illink.sln +++ b/src/tools/illink/illink.sln @@ -223,7 +223,6 @@ Global SolutionGuid = {E43A3901-42B0-48CA-BB36-5CD40A99A6EE} EndGlobalSection GlobalSection(SharedMSBuildProjectFiles) = preSolution - test\Trimming.Tests.Shared\Trimming.Tests.Shared.projitems*{400a1561-b6b6-482d-9e4c-3ddaede5bd07}*SharedItemsImports = 5 src\ILLink.Shared\ILLink.Shared.projitems*{dd28e2b1-057b-4b4d-a04d-b2ebd9e76e46}*SharedItemsImports = 5 src\ILLink.Shared\ILLink.Shared.projitems*{f1a44a78-34ee-408b-8285-9a26f0e7d4f2}*SharedItemsImports = 5 src\ILLink.Shared\ILLink.Shared.projitems*{ff598e93-8e9e-4091-9f50-61a7572663ae}*SharedItemsImports = 13 diff --git a/src/tools/illink/src/linker/Linker/TypeMapInfo.cs b/src/tools/illink/src/linker/Linker/TypeMapInfo.cs index f326af5d7a0a1a..a2f118adf9fb78 100644 --- a/src/tools/illink/src/linker/Linker/TypeMapInfo.cs +++ b/src/tools/illink/src/linker/Linker/TypeMapInfo.cs @@ -141,24 +141,6 @@ protected virtual void MapType (TypeDefinition type) MapType (nested); } - static HashSet GetRecursiveInterfaces (TypeDefinition type) - { - if (!type.HasInterfaces) - return []; - - HashSet interfaces = new HashSet (); - GetInterfacesOnType (type, interfaces); - return interfaces; - - static void GetInterfacesOnType (TypeDefinition type, HashSet interfaces) - { - foreach (var iface in type.Interfaces) { - interfaces.Add (iface.InterfaceType); - GetInterfacesOnType(type, interfaces); - } - } - } - void MapInterfaceMethodsInTypeHierarchy (TypeDefinition type) { if (!type.HasInterfaces) @@ -199,7 +181,7 @@ void MapInterfaceMethodsInTypeHierarchy (TypeDefinition type) } // Look for a default implementation last. - FindAndAddDefaultInterfaceImplementations (type, type, resolvedInterfaceMethod); + FindAndAddDefaultInterfaceImplementations (type, resolvedInterfaceMethod); } } } @@ -301,12 +283,12 @@ void AnnotateMethods (MethodDefinition @base, MethodDefinition @override, Interf // Note that this returns a list to potentially cover the diamond case (more than one // most specific implementation of the given interface methods). ILLink needs to preserve // all the implementations so that the proper exception can be thrown at runtime. - void FindAndAddDefaultInterfaceImplementations (TypeDefinition typeThatImplementsInterface, TypeDefinition typeThatMayHaveDIM, MethodDefinition interfaceMethodToBeImplemented) + void FindAndAddDefaultInterfaceImplementations (TypeDefinition type, MethodDefinition interfaceMethod) { // Go over all interfaces, trying to find a method that is an explicit MethodImpl of the // interface method in question. - foreach (var interfaceImpl in typeThatMayHaveDIM.Interfaces) { + foreach (var interfaceImpl in type.Interfaces) { var potentialImplInterface = context.TryResolve (interfaceImpl.InterfaceType); if (potentialImplInterface == null) continue; @@ -314,9 +296,9 @@ void FindAndAddDefaultInterfaceImplementations (TypeDefinition typeThatImplement bool foundImpl = false; foreach (var potentialImplMethod in potentialImplInterface.Methods) { - if (potentialImplMethod == interfaceMethodToBeImplemented && + if (potentialImplMethod == interfaceMethod && !potentialImplMethod.IsAbstract) { - AddDefaultInterfaceImplementation (interfaceMethodToBeImplemented, typeThatImplementsInterface, (interfaceImpl, potentialImplMethod)); + AddDefaultInterfaceImplementation (interfaceMethod, type, (interfaceImpl, potentialImplMethod)); foundImpl = true; break; } @@ -326,8 +308,8 @@ void FindAndAddDefaultInterfaceImplementations (TypeDefinition typeThatImplement // This method is an override of something. Let's see if it's the method we are looking for. foreach (var @override in potentialImplMethod.Overrides) { - if (context.TryResolve (@override) == interfaceMethodToBeImplemented) { - AddDefaultInterfaceImplementation (interfaceMethodToBeImplemented, typeThatImplementsInterface, (interfaceImpl, @potentialImplMethod)); + if (context.TryResolve (@override) == interfaceMethod) { + AddDefaultInterfaceImplementation (interfaceMethod, type, (interfaceImpl, @potentialImplMethod)); foundImpl = true; break; } @@ -341,7 +323,7 @@ void FindAndAddDefaultInterfaceImplementations (TypeDefinition typeThatImplement // We haven't found a MethodImpl on the current interface, but one of the interfaces // this interface requires could still provide it. if (!foundImpl) { - FindAndAddDefaultInterfaceImplementations (typeThatImplementsInterface, potentialImplInterface, interfaceMethodToBeImplemented); + FindAndAddDefaultInterfaceImplementations (potentialImplInterface, interfaceMethod); } } } diff --git a/src/tools/illink/src/linker/Linker/TypeReferenceExtensions.cs b/src/tools/illink/src/linker/Linker/TypeReferenceExtensions.cs index 28680c1b644e3f..5092fe1158e34b 100644 --- a/src/tools/illink/src/linker/Linker/TypeReferenceExtensions.cs +++ b/src/tools/illink/src/linker/Linker/TypeReferenceExtensions.cs @@ -151,33 +151,22 @@ void parseArrayDimensions (ArrayType at) return null; } - public static HashSet<(TypeReference InflatedInterface, InterfaceImplementation OriginalImpl)> GetInflatedInterfaces (this TypeReference typeRef, ITryResolveMetadata resolver) + public static IEnumerable<(TypeReference InflatedInterface, InterfaceImplementation OriginalImpl)> GetInflatedInterfaces (this TypeReference typeRef, ITryResolveMetadata resolver) { var typeDef = resolver.TryResolve (typeRef); if (typeDef?.HasInterfaces != true) - return []; - HashSet<(TypeReference, InterfaceImplementation)> inflatedInterfaces = new (); - AddInflatedInterfacesRecursively (typeRef, typeDef, resolver, inflatedInterfaces); - return inflatedInterfaces; + yield break; - static void AddInflatedInterfacesRecursively(TypeReference typeRef, TypeDefinition interfaceProvider, ITryResolveMetadata resolver, HashSet<(TypeReference, InterfaceImplementation)> inflatedInterfaces) - { - if (typeRef is GenericInstanceType genericInstance) { - foreach (var interfaceImpl in interfaceProvider.Interfaces) { - // InflateGenericType only returns null when inflating generic parameters (and the generic instance type doesn't resolve). - // Here we are not inflating a generic parameter but an interface type reference. - inflatedInterfaces.Add((InflateGenericType (genericInstance, interfaceImpl.InterfaceType, resolver), interfaceImpl)!); - if (resolver.TryResolve (interfaceImpl.InterfaceType) is { } baseIface) - AddInflatedInterfacesRecursively (typeRef, baseIface, resolver, inflatedInterfaces); - } - } else { - foreach (var interfaceImpl in interfaceProvider.Interfaces) { - inflatedInterfaces.Add ((interfaceImpl.InterfaceType, interfaceImpl)); - if (resolver.TryResolve (interfaceImpl.InterfaceType) is { } baseIface) - AddInflatedInterfacesRecursively (typeRef, baseIface, resolver, inflatedInterfaces); - } + if (typeRef is GenericInstanceType genericInstance) { + foreach (var interfaceImpl in typeDef.Interfaces) { + // InflateGenericType only returns null when inflating generic parameters (and the generic instance type doesn't resolve). + // Here we are not inflating a generic parameter but an interface type reference. + yield return (InflateGenericType (genericInstance, interfaceImpl.InterfaceType, resolver), interfaceImpl)!; } + } else { + foreach (var interfaceImpl in typeDef.Interfaces) + yield return (interfaceImpl.InterfaceType, interfaceImpl); } } From 49b3464695be3a5f97111d5bf3511a49c1b7c4a3 Mon Sep 17 00:00:00 2001 From: Jackson Schuster <36744439+jtschuster@users.noreply.github.com> Date: Fri, 16 Feb 2024 10:19:11 -0800 Subject: [PATCH 3/3] Comment out all failing assertions --- .../DimProvidedByUnreferencedIfaceInHierarchy.cs | 12 ++++++------ ...aticDimProvidedByUnreferencedIfaceInHierarchy.cs | 13 ++++++------- 2 files changed, 12 insertions(+), 13 deletions(-) diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases/Inheritance.Interfaces/DefaultInterfaceMethods/DimProvidedByUnreferencedIfaceInHierarchy.cs b/src/tools/illink/test/Mono.Linker.Tests.Cases/Inheritance.Interfaces/DefaultInterfaceMethods/DimProvidedByUnreferencedIfaceInHierarchy.cs index cfc9e4a367d23e..7b749d20d46c24 100644 --- a/src/tools/illink/test/Mono.Linker.Tests.Cases/Inheritance.Interfaces/DefaultInterfaceMethods/DimProvidedByUnreferencedIfaceInHierarchy.cs +++ b/src/tools/illink/test/Mono.Linker.Tests.Cases/Inheritance.Interfaces/DefaultInterfaceMethods/DimProvidedByUnreferencedIfaceInHierarchy.cs @@ -12,14 +12,14 @@ namespace Mono.Linker.Tests.Cases.Inheritance.Interfaces.DefaultInterfaceMethods [SkipILVerify] #if IL_ASSEMBLY_AVAILABLE - [KeptMemberInAssembly ("library.dll", typeof(Program.IBar), "Program.IFoo.Method()")] [KeptMemberInAssembly ("library.dll", typeof(Program.IFoo), "Method()")] - [KeptTypeInAssembly ("library.dll", typeof(Program.IBar))] - [KeptInterfaceOnTypeInAssembly ("library.dll", typeof (Program.IBar), "library.dll", typeof (Program.IFoo))] // https://github.com/dotnet/runtime/issues/98536 - //[KeptInterfaceOnTypeInAssembly ("library.dll", typeof (Program.MyFoo), "library.dll", typeof (Program.IBaz))] - //[KeptTypeInAssembly ("library.dll", typeof(Program.IBaz))] - //[KeptInterfaceOnTypeInAssembly ("library.dll", typeof (Program.IBaz), "library.dll", typeof (Program.IBar))] + // [KeptTypeInAssembly ("library.dll", typeof(Program.IBar))] + // [KeptMemberInAssembly ("library.dll", typeof(Program.IBar), "Program.IFoo.Method()")] + // [KeptInterfaceOnTypeInAssembly ("library.dll", typeof (Program.IBar), "library.dll", typeof (Program.IFoo))] + // [KeptInterfaceOnTypeInAssembly ("library.dll", typeof (Program.MyFoo), "library.dll", typeof (Program.IBaz))] + // [KeptTypeInAssembly ("library.dll", typeof(Program.IBaz))] + // [KeptInterfaceOnTypeInAssembly ("library.dll", typeof (Program.IBaz), "library.dll", typeof (Program.IBar))] [KeptMemberInAssembly ("library.dll", typeof(Program), "CallMethod(Program/IFoo)")] #endif class DimProvidedByUnreferencedIfaceInHierarchy diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases/Inheritance.Interfaces/DefaultInterfaceMethods/StaticDimProvidedByUnreferencedIfaceInHierarchy.cs b/src/tools/illink/test/Mono.Linker.Tests.Cases/Inheritance.Interfaces/DefaultInterfaceMethods/StaticDimProvidedByUnreferencedIfaceInHierarchy.cs index a65ad7d2f754c0..1cb85f6c0e0c4f 100644 --- a/src/tools/illink/test/Mono.Linker.Tests.Cases/Inheritance.Interfaces/DefaultInterfaceMethods/StaticDimProvidedByUnreferencedIfaceInHierarchy.cs +++ b/src/tools/illink/test/Mono.Linker.Tests.Cases/Inheritance.Interfaces/DefaultInterfaceMethods/StaticDimProvidedByUnreferencedIfaceInHierarchy.cs @@ -15,15 +15,14 @@ namespace Mono.Linker.Tests.Cases.Inheritance.Interfaces.DefaultInterfaceMethods [KeptMemberInAssembly ("library.dll", typeof(Program), "CallMethod<#1>()")] [KeptTypeInAssembly ("library.dll", typeof(Program.IBase))] [KeptMemberInAssembly ("library.dll", typeof(Program.IBase), "Method()")] - [KeptTypeInAssembly ("library.dll", typeof(Program.I2))] - [KeptMemberInAssembly ("library.dll", typeof(Program.I2), "Program.IBase.Method()")] - [KeptInterfaceOnTypeInAssembly ("library.dll", typeof (Program.I2), "library.dll", typeof (Program.IBase))] - // https://github.com/dotnet/runtime/issues/98536 - //[KeptTypeInAssembly ("library.dll", typeof(Program.I3))] - //[KeptInterfaceOnTypeInAssembly ("library.dll", typeof (Program.I3), "library.dll", typeof (Program.I2))] [KeptTypeInAssembly ("library.dll", typeof(Program.I4))] // https://github.com/dotnet/runtime/issues/98536 - //[KeptInterfaceOnTypeInAssembly ("library.dll", typeof (Program.I4), "library.dll", typeof (Program.I3))] + // [KeptTypeInAssembly ("library.dll", typeof(Program.I2))] + // [KeptMemberInAssembly ("library.dll", typeof(Program.I2), "Program.IBase.Method()")] + // [KeptInterfaceOnTypeInAssembly ("library.dll", typeof (Program.I2), "library.dll", typeof (Program.IBase))] + // [KeptTypeInAssembly ("library.dll", typeof(Program.I3))] + // [KeptInterfaceOnTypeInAssembly ("library.dll", typeof (Program.I3), "library.dll", typeof (Program.I2))] + // [KeptInterfaceOnTypeInAssembly ("library.dll", typeof (Program.I4), "library.dll", typeof (Program.I3))] #endif class StaticDimProvidedByUnreferencedIfaceInHierarchy {