From 8454427af39d41ba40968e9ac2e1ada59a0ceb19 Mon Sep 17 00:00:00 2001 From: Jackson Schuster <36744439+jtschuster@users.noreply.github.com> Date: Sat, 10 Feb 2024 16:08:32 -0800 Subject: [PATCH 01/18] Refactor OverrideInformation to include interface implementing type --- .../src/linker/CompatibilitySuppressions.xml | 4 -- .../src/linker/Linker.Steps/MarkStep.cs | 30 ++++----- .../illink/src/linker/Linker/Annotations.cs | 2 +- .../src/linker/Linker/InterfaceImplementor.cs | 21 +++++++ .../src/linker/Linker/OverrideInformation.cs | 61 +++++-------------- .../illink/src/linker/Linker/TypeMapInfo.cs | 53 ++++++++++------ 6 files changed, 86 insertions(+), 85 deletions(-) create mode 100644 src/tools/illink/src/linker/Linker/InterfaceImplementor.cs diff --git a/src/tools/illink/src/linker/CompatibilitySuppressions.xml b/src/tools/illink/src/linker/CompatibilitySuppressions.xml index 4a0a6296c4e2f..fd0dbb2635cb2 100644 --- a/src/tools/illink/src/linker/CompatibilitySuppressions.xml +++ b/src/tools/illink/src/linker/CompatibilitySuppressions.xml @@ -1481,10 +1481,6 @@ CP0002 M:Mono.Linker.OverrideInformation.get_IsOverrideOfInterfaceMember - - CP0002 - M:Mono.Linker.OverrideInformation.get_IsStaticInterfaceMethodPair - CP0002 M:Mono.Linker.Steps.BaseStep.get_MarkingHelpers diff --git a/src/tools/illink/src/linker/Linker.Steps/MarkStep.cs b/src/tools/illink/src/linker/Linker.Steps/MarkStep.cs index bb5e95e0a38dd..a6886000b66ea 100644 --- a/src/tools/illink/src/linker/Linker.Steps/MarkStep.cs +++ b/src/tools/illink/src/linker/Linker.Steps/MarkStep.cs @@ -701,17 +701,16 @@ void ProcessVirtualMethod (MethodDefinition method) var defaultImplementations = Annotations.GetDefaultInterfaceImplementations (method); if (defaultImplementations is not null) { foreach (var dimInfo in defaultImplementations) { - ProcessDefaultImplementation (dimInfo.ImplementingType, dimInfo.InterfaceImpl, dimInfo.DefaultInterfaceMethod); + ProcessDefaultImplementation (dimInfo); - var ov = new OverrideInformation (method, dimInfo.DefaultInterfaceMethod, Context); - if (IsInterfaceImplementationMethodNeededByTypeDueToInterface (ov, dimInfo.ImplementingType)) - MarkMethod (ov.Override, new DependencyInfo (DependencyKind.Override, ov.Base), ScopeStack.CurrentScope.Origin); + if (IsInterfaceImplementationMethodNeededByTypeDueToInterface (dimInfo)) + MarkMethod (dimInfo.Override, new DependencyInfo (DependencyKind.Override, dimInfo.Base), ScopeStack.CurrentScope.Origin); } } var overridingMethods = Annotations.GetOverrides (method); if (overridingMethods is not null) { - foreach (var ov in overridingMethods) { - if (IsInterfaceImplementationMethodNeededByTypeDueToInterface (ov, ov.Override.DeclaringType)) + foreach (OverrideInformation ov in overridingMethods) { + if (IsInterfaceImplementationMethodNeededByTypeDueToInterface (ov)) MarkMethod (ov.Override, new DependencyInfo (DependencyKind.Override, ov.Base), ScopeStack.CurrentScope.Origin); } } @@ -819,13 +818,14 @@ bool RequiresInterfaceRecursively (TypeDefinition typeToExamine, TypeDefinition return false; } - void ProcessDefaultImplementation (TypeDefinition typeWithDefaultImplementedInterfaceMethod, InterfaceImplementation implementation, MethodDefinition implementationMethod) + void ProcessDefaultImplementation (OverrideInformation ov) { - if ((!implementationMethod.IsStatic && !Annotations.IsInstantiated (typeWithDefaultImplementedInterfaceMethod)) - || implementationMethod.IsStatic && !Annotations.IsRelevantToVariantCasting (typeWithDefaultImplementedInterfaceMethod)) + Debug.Assert (ov.IsOverrideOfInterfaceMember); + if ((!ov.Override.IsStatic && !Annotations.IsInstantiated (ov.InterfaceImplementor!.Implementor)) + || ov.Override.IsStatic && !Annotations.IsRelevantToVariantCasting (ov.InterfaceImplementor!.Implementor)) return; - MarkInterfaceImplementation (implementation); + MarkInterfaceImplementation (ov.InterfaceImplementor!.InterfaceImplementation); } void MarkMarshalSpec (IMarshalInfoProvider spec, in DependencyInfo reason) @@ -2549,7 +2549,7 @@ bool IsMethodNeededByTypeDueToPreservedScope (MethodDefinition method) /// /// Returns true if the override method is required due to the interface that the base method is declared on. See doc at for explanation of logic. /// - bool IsInterfaceImplementationMethodNeededByTypeDueToInterface (OverrideInformation overrideInformation, TypeDefinition typeThatImplsInterface) + bool IsInterfaceImplementationMethodNeededByTypeDueToInterface (OverrideInformation overrideInformation) { var @base = overrideInformation.Base; var method = overrideInformation.Override; @@ -2562,7 +2562,7 @@ bool IsInterfaceImplementationMethodNeededByTypeDueToInterface (OverrideInformat // If the interface implementation is not marked, do not mark the implementation method // A type that doesn't implement the interface isn't required to have methods that implement the interface. - InterfaceImplementation? iface = overrideInformation.MatchingInterfaceImplementation; + InterfaceImplementation? iface = overrideInformation.InterfaceImplementor!.InterfaceImplementation; if (!((iface is not null && Annotations.IsMarked (iface)) || IsInterfaceImplementationMarkedRecursively (method.DeclaringType, @base.DeclaringType))) return false; @@ -2580,12 +2580,12 @@ bool IsInterfaceImplementationMethodNeededByTypeDueToInterface (OverrideInformat // If the method is static and the implementing type is relevant to variant casting, mark the implementation method. // A static method may only be called through a constrained call if the type is relevant to variant casting. if (@base.IsStatic) - return Annotations.IsRelevantToVariantCasting (typeThatImplsInterface) + return Annotations.IsRelevantToVariantCasting (overrideInformation.InterfaceImplementor.Implementor) || IgnoreScope (@base.DeclaringType.Scope); // If the implementing type is marked as instantiated, mark the implementation method. // If the type is not instantiated, do not mark the implementation method - return Annotations.IsInstantiated (typeThatImplsInterface); + return Annotations.IsInstantiated (overrideInformation.InterfaceImplementor.Implementor); } static bool IsSpecialSerializationConstructor (MethodDefinition method) @@ -3256,7 +3256,7 @@ protected virtual void ProcessMethod (MethodDefinition method, in DependencyInfo // Only if the interface method is referenced, then all the methods which implemented must be kept, but not the other way round. if (!markAllOverrides && Context.Resolve (@base) is MethodDefinition baseDefinition - && new OverrideInformation.OverridePair (baseDefinition, method).IsStaticInterfaceMethodPair ()) + && baseDefinition.DeclaringType.IsInterface && baseDefinition.IsStatic && method.IsStatic) continue; MarkMethod (@base, new DependencyInfo (DependencyKind.MethodImplOverride, method), ScopeStack.CurrentScope.Origin); MarkExplicitInterfaceImplementation (method, @base); diff --git a/src/tools/illink/src/linker/Linker/Annotations.cs b/src/tools/illink/src/linker/Linker/Annotations.cs index 8f7747cba3543..a7b3198265e81 100644 --- a/src/tools/illink/src/linker/Linker/Annotations.cs +++ b/src/tools/illink/src/linker/Linker/Annotations.cs @@ -462,7 +462,7 @@ public bool IsPublic (IMetadataTokenProvider provider) /// DefaultInterfaceMethod is the method that implements . /// /// The interface method to find default implementations for - public IEnumerable<(TypeDefinition ImplementingType, InterfaceImplementation InterfaceImpl, MethodDefinition DefaultInterfaceMethod)>? GetDefaultInterfaceImplementations (MethodDefinition method) + public IEnumerable? GetDefaultInterfaceImplementations (MethodDefinition method) { return TypeMapInfo.GetDefaultInterfaceImplementations (method); } diff --git a/src/tools/illink/src/linker/Linker/InterfaceImplementor.cs b/src/tools/illink/src/linker/Linker/InterfaceImplementor.cs new file mode 100644 index 0000000000000..e2beddb001684 --- /dev/null +++ b/src/tools/illink/src/linker/Linker/InterfaceImplementor.cs @@ -0,0 +1,21 @@ +// 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. + +using System.Diagnostics; +using Mono.Cecil; + +namespace Mono.Linker +{ + public class InterfaceImplementor + { + public TypeDefinition Implementor { get; } + public InterfaceImplementation InterfaceImplementation { get; } + + public InterfaceImplementor (TypeDefinition implementor, InterfaceImplementation interfaceImplementation) + { + Debug.Assert(implementor.Interfaces.Contains (interfaceImplementation)); + Implementor = implementor; + InterfaceImplementation = interfaceImplementation; + } + } +} diff --git a/src/tools/illink/src/linker/Linker/OverrideInformation.cs b/src/tools/illink/src/linker/Linker/OverrideInformation.cs index 077353eb2ee7b..bca81f39bedbb 100644 --- a/src/tools/illink/src/linker/Linker/OverrideInformation.cs +++ b/src/tools/illink/src/linker/Linker/OverrideInformation.cs @@ -9,65 +9,32 @@ namespace Mono.Linker [DebuggerDisplay ("{Override}")] public class OverrideInformation { - readonly ITryResolveMetadata resolver; - readonly OverridePair _pair; - private InterfaceImplementation? _matchingInterfaceImplementation; + public MethodDefinition Base { get; } - public OverrideInformation (MethodDefinition @base, MethodDefinition @override, ITryResolveMetadata resolver, InterfaceImplementation? matchingInterfaceImplementation = null) + public MethodDefinition Override { get; } + + public InterfaceImplementor? InterfaceImplementor { get; } + + public OverrideInformation (MethodDefinition @base, MethodDefinition @override, InterfaceImplementor? interfaceImplementor = null) { - _pair = new OverridePair (@base, @override); - _matchingInterfaceImplementation = matchingInterfaceImplementation; - this.resolver = resolver; - } - public readonly record struct OverridePair (MethodDefinition Base, MethodDefinition Override) - { - public bool IsStaticInterfaceMethodPair () => Base.DeclaringType.IsInterface && Base.IsStatic && Override.IsStatic; - public InterfaceImplementation? GetMatchingInterfaceImplementation (ITryResolveMetadata resolver) - { - if (!Base.DeclaringType.IsInterface) - return null; - var interfaceType = Base.DeclaringType; - foreach (var @interface in Override.DeclaringType.Interfaces) { - if (resolver.TryResolve (@interface.InterfaceType)?.Equals (interfaceType) == true) { - return @interface; - } - } - return null; - } + Base = @base; + Override = @override; + InterfaceImplementor = interfaceImplementor; + // Ensure we have an interface implementation if the base method is from an interface and the override method is on a class + Debug.Assert(@base.DeclaringType.IsInterface && (interfaceImplementor != null || @override.DeclaringType.IsInterface) + || !@base.DeclaringType.IsInterface && interfaceImplementor == null); } - public MethodDefinition Base { get => _pair.Base; } - public MethodDefinition Override { get => _pair.Override; } public InterfaceImplementation? MatchingInterfaceImplementation { get { - if (_matchingInterfaceImplementation is not null) - return _matchingInterfaceImplementation; - _matchingInterfaceImplementation = _pair.GetMatchingInterfaceImplementation (resolver); - return _matchingInterfaceImplementation; + return InterfaceImplementor?.InterfaceImplementation; } } public bool IsOverrideOfInterfaceMember { get { - if (MatchingInterfaceImplementation != null) - return true; - - return Base.DeclaringType.IsInterface; + return InterfaceImplementor != null; } } - - public TypeDefinition? InterfaceType { - get { - if (!IsOverrideOfInterfaceMember) - return null; - - if (MatchingInterfaceImplementation != null) - return resolver.TryResolve (MatchingInterfaceImplementation.InterfaceType); - - return Base.DeclaringType; - } - } - - public bool IsStaticInterfaceMethodPair => _pair.IsStaticInterfaceMethodPair (); } } diff --git a/src/tools/illink/src/linker/Linker/TypeMapInfo.cs b/src/tools/illink/src/linker/Linker/TypeMapInfo.cs index a2f118adf9fb7..92611e649ebc1 100644 --- a/src/tools/illink/src/linker/Linker/TypeMapInfo.cs +++ b/src/tools/illink/src/linker/Linker/TypeMapInfo.cs @@ -32,6 +32,7 @@ using System.Collections.Generic; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; +using System.Linq; using Mono.Cecil; namespace Mono.Linker @@ -43,7 +44,7 @@ public class TypeMapInfo readonly LinkContext context; protected readonly Dictionary> base_methods = new Dictionary> (); protected readonly Dictionary> override_methods = new Dictionary> (); - protected readonly Dictionary> default_interface_implementations = new Dictionary> (); + protected readonly Dictionary> default_interface_implementations = new Dictionary> (); public TypeMapInfo (LinkContext context) { @@ -92,41 +93,41 @@ public void EnsureProcessed (AssemblyDefinition assembly) /// DefaultInterfaceMethod is the method that implements . /// /// The interface method to find default implementations for - public IEnumerable<(TypeDefinition ImplementingType, InterfaceImplementation InterfaceImpl, MethodDefinition DefaultImplementationMethod)>? GetDefaultInterfaceImplementations (MethodDefinition baseMethod) + public IEnumerable? GetDefaultInterfaceImplementations (MethodDefinition baseMethod) { default_interface_implementations.TryGetValue (baseMethod, out var ret); return ret; } - public void AddBaseMethod (MethodDefinition method, MethodDefinition @base, InterfaceImplementation? matchingInterfaceImplementation) + public void AddBaseMethod (MethodDefinition method, MethodDefinition @base, InterfaceImplementor? interfaceImplementor) { if (!base_methods.TryGetValue (method, out List? methods)) { methods = new List (); base_methods[method] = methods; } - methods.Add (new OverrideInformation (@base, method, context, matchingInterfaceImplementation)); + methods.Add (new OverrideInformation (@base, method, interfaceImplementor)); } - public void AddOverride (MethodDefinition @base, MethodDefinition @override, InterfaceImplementation? matchingInterfaceImplementation = null) + public void AddOverride (MethodDefinition @base, MethodDefinition @override, InterfaceImplementor? interfaceImplementor = null) { if (!override_methods.TryGetValue (@base, out List? methods)) { methods = new List (); override_methods.Add (@base, methods); } - methods.Add (new OverrideInformation (@base, @override, context, matchingInterfaceImplementation)); + methods.Add (new OverrideInformation (@base, @override, interfaceImplementor)); } - public void AddDefaultInterfaceImplementation (MethodDefinition @base, TypeDefinition implementingType, (InterfaceImplementation, MethodDefinition) matchingInterfaceImplementation) + public void AddDefaultInterfaceImplementation (MethodDefinition @base, InterfaceImplementor interfaceImplementor, MethodDefinition defaultImplementationMethod) { Debug.Assert(@base.DeclaringType.IsInterface); if (!default_interface_implementations.TryGetValue (@base, out var implementations)) { - implementations = new List<(TypeDefinition, InterfaceImplementation, MethodDefinition)> (); + implementations = new List (); default_interface_implementations.Add (@base, implementations); } - implementations.Add ((implementingType, matchingInterfaceImplementation.Item1, matchingInterfaceImplementation.Item2)); + implementations.Add (new (@base, defaultImplementationMethod, interfaceImplementor)); } protected virtual void MapType (TypeDefinition type) @@ -168,14 +169,14 @@ void MapInterfaceMethodsInTypeHierarchy (TypeDefinition type) // Try to find an implementation with a name/sig match on the current type MethodDefinition? exactMatchOnType = TryMatchMethod (type, interfaceMethod); if (exactMatchOnType != null) { - AnnotateMethods (resolvedInterfaceMethod, exactMatchOnType); + AnnotateMethods (resolvedInterfaceMethod, exactMatchOnType, new (type, interfaceImpl.OriginalImpl)); continue; } // Next try to find an implementation with a name/sig match in the base hierarchy var @base = GetBaseMethodInTypeHierarchy (type, interfaceMethod); if (@base != null) { - AnnotateMethods (resolvedInterfaceMethod, @base, interfaceImpl.OriginalImpl); + AnnotateMethods (resolvedInterfaceMethod, @base, new (type, interfaceImpl.OriginalImpl)); continue; } } @@ -211,6 +212,8 @@ void MapVirtualMethod (MethodDefinition method) if (@base == null) return; + Debug.Assert(!@base.DeclaringType.IsInterface); + AnnotateMethods (@base, method); } @@ -220,15 +223,29 @@ void MapOverrides (MethodDefinition method) MethodDefinition? @override = context.TryResolve (override_ref); if (@override == null) continue; - - AnnotateMethods (@override, method); + if (@override.DeclaringType.IsInterface) + { + // Find the matching interface implementation if the base is an interface method + foreach (var @interface in method.DeclaringType.Interfaces) + { + if (context.TryResolve (@interface.InterfaceType) == @override.DeclaringType) + { + AnnotateMethods(@override, method, new InterfaceImplementor(method.DeclaringType, @interface)); + break; + } + } + } + else + { + AnnotateMethods (@override, method); + } } } - void AnnotateMethods (MethodDefinition @base, MethodDefinition @override, InterfaceImplementation? matchingInterfaceImplementation = null) + void AnnotateMethods (MethodDefinition @base, MethodDefinition @override, InterfaceImplementor? interfaceImplementor = null) { - AddBaseMethod (@override, @base, matchingInterfaceImplementation); - AddOverride (@base, @override, matchingInterfaceImplementation); + AddBaseMethod (@override, @base, interfaceImplementor); + AddOverride (@base, @override, interfaceImplementor); } MethodDefinition? GetBaseMethodInTypeHierarchy (MethodDefinition method) @@ -298,7 +315,7 @@ void FindAndAddDefaultInterfaceImplementations (TypeDefinition type, MethodDefin foreach (var potentialImplMethod in potentialImplInterface.Methods) { if (potentialImplMethod == interfaceMethod && !potentialImplMethod.IsAbstract) { - AddDefaultInterfaceImplementation (interfaceMethod, type, (interfaceImpl, potentialImplMethod)); + AddDefaultInterfaceImplementation (interfaceMethod, new (type, interfaceImpl), potentialImplMethod); foundImpl = true; break; } @@ -309,7 +326,7 @@ 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)); + AddDefaultInterfaceImplementation (interfaceMethod, new (type, interfaceImpl), @potentialImplMethod); foundImpl = true; break; } From 54c326d8b64f5f71650c78a0c37ef3a2b6948375 Mon Sep 17 00:00:00 2001 From: Jackson Schuster <36744439+jtschuster@users.noreply.github.com> Date: Sat, 10 Feb 2024 16:27:08 -0800 Subject: [PATCH 02/18] Add NotNullWhenAttribute for InterfaceImplementor --- src/tools/illink/src/linker/Linker.Steps/MarkStep.cs | 10 +++++----- .../illink/src/linker/Linker/OverrideInformation.cs | 2 ++ 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/tools/illink/src/linker/Linker.Steps/MarkStep.cs b/src/tools/illink/src/linker/Linker.Steps/MarkStep.cs index a6886000b66ea..5585c67b3d31d 100644 --- a/src/tools/illink/src/linker/Linker.Steps/MarkStep.cs +++ b/src/tools/illink/src/linker/Linker.Steps/MarkStep.cs @@ -821,11 +821,11 @@ bool RequiresInterfaceRecursively (TypeDefinition typeToExamine, TypeDefinition void ProcessDefaultImplementation (OverrideInformation ov) { Debug.Assert (ov.IsOverrideOfInterfaceMember); - if ((!ov.Override.IsStatic && !Annotations.IsInstantiated (ov.InterfaceImplementor!.Implementor)) - || ov.Override.IsStatic && !Annotations.IsRelevantToVariantCasting (ov.InterfaceImplementor!.Implementor)) + if ((!ov.Override.IsStatic && !Annotations.IsInstantiated (ov.InterfaceImplementor.Implementor)) + || ov.Override.IsStatic && !Annotations.IsRelevantToVariantCasting (ov.InterfaceImplementor.Implementor)) return; - MarkInterfaceImplementation (ov.InterfaceImplementor!.InterfaceImplementation); + MarkInterfaceImplementation (ov.InterfaceImplementor.InterfaceImplementation); } void MarkMarshalSpec (IMarshalInfoProvider spec, in DependencyInfo reason) @@ -2553,7 +2553,7 @@ bool IsInterfaceImplementationMethodNeededByTypeDueToInterface (OverrideInformat { var @base = overrideInformation.Base; var method = overrideInformation.Override; - Debug.Assert (@base.DeclaringType.IsInterface); + Debug.Assert (overrideInformation.IsOverrideOfInterfaceMember); if (@base is null || method is null || @base.DeclaringType is null) return false; @@ -2562,7 +2562,7 @@ bool IsInterfaceImplementationMethodNeededByTypeDueToInterface (OverrideInformat // If the interface implementation is not marked, do not mark the implementation method // A type that doesn't implement the interface isn't required to have methods that implement the interface. - InterfaceImplementation? iface = overrideInformation.InterfaceImplementor!.InterfaceImplementation; + InterfaceImplementation? iface = overrideInformation.InterfaceImplementor.InterfaceImplementation; if (!((iface is not null && Annotations.IsMarked (iface)) || IsInterfaceImplementationMarkedRecursively (method.DeclaringType, @base.DeclaringType))) return false; diff --git a/src/tools/illink/src/linker/Linker/OverrideInformation.cs b/src/tools/illink/src/linker/Linker/OverrideInformation.cs index bca81f39bedbb..ea0d0e47e31a3 100644 --- a/src/tools/illink/src/linker/Linker/OverrideInformation.cs +++ b/src/tools/illink/src/linker/Linker/OverrideInformation.cs @@ -3,6 +3,7 @@ using System.Diagnostics; using Mono.Cecil; +using System.Diagnostics.CodeAnalysis; namespace Mono.Linker { @@ -31,6 +32,7 @@ public InterfaceImplementation? MatchingInterfaceImplementation { } } + [MemberNotNullWhen (true, nameof (InterfaceImplementor), nameof (MatchingInterfaceImplementation))] public bool IsOverrideOfInterfaceMember { get { return InterfaceImplementor != null; From 6bfc58a8f94821292b7a1842b9f337a364a36e19 Mon Sep 17 00:00:00 2001 From: Jackson Schuster <36744439+jtschuster@users.noreply.github.com> Date: Sat, 10 Feb 2024 16:50:49 -0800 Subject: [PATCH 03/18] Don't allow null interfaceImpl when base and override are interface methods in OverrideInformation --- src/tools/illink/src/linker/Linker/OverrideInformation.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/illink/src/linker/Linker/OverrideInformation.cs b/src/tools/illink/src/linker/Linker/OverrideInformation.cs index ea0d0e47e31a3..930b8c3c407b0 100644 --- a/src/tools/illink/src/linker/Linker/OverrideInformation.cs +++ b/src/tools/illink/src/linker/Linker/OverrideInformation.cs @@ -22,7 +22,7 @@ public OverrideInformation (MethodDefinition @base, MethodDefinition @override, Override = @override; InterfaceImplementor = interfaceImplementor; // Ensure we have an interface implementation if the base method is from an interface and the override method is on a class - Debug.Assert(@base.DeclaringType.IsInterface && (interfaceImplementor != null || @override.DeclaringType.IsInterface) + Debug.Assert(@base.DeclaringType.IsInterface && interfaceImplementor != null || !@base.DeclaringType.IsInterface && interfaceImplementor == null); } From ecc5d0c4398b200190664e19f0e952cff11e3803 Mon Sep 17 00:00:00 2001 From: Jackson Schuster <36744439+jtschuster@users.noreply.github.com> Date: Sun, 11 Feb 2024 11:40:44 -0800 Subject: [PATCH 04/18] Add InterfaceType to InterfaceImplementor --- .../src/linker/Linker/InterfaceImplementor.cs | 4 +++- .../src/linker/Linker/OverrideInformation.cs | 17 +++++++---------- .../illink/src/linker/Linker/TypeMapInfo.cs | 10 +++++----- 3 files changed, 15 insertions(+), 16 deletions(-) diff --git a/src/tools/illink/src/linker/Linker/InterfaceImplementor.cs b/src/tools/illink/src/linker/Linker/InterfaceImplementor.cs index e2beddb001684..aba6c3b44ce0b 100644 --- a/src/tools/illink/src/linker/Linker/InterfaceImplementor.cs +++ b/src/tools/illink/src/linker/Linker/InterfaceImplementor.cs @@ -10,12 +10,14 @@ public class InterfaceImplementor { public TypeDefinition Implementor { get; } public InterfaceImplementation InterfaceImplementation { get; } + public TypeDefinition? InterfaceType { get; } - public InterfaceImplementor (TypeDefinition implementor, InterfaceImplementation interfaceImplementation) + public InterfaceImplementor (TypeDefinition implementor, InterfaceImplementation interfaceImplementation, TypeDefinition? interfaceType) { Debug.Assert(implementor.Interfaces.Contains (interfaceImplementation)); Implementor = implementor; InterfaceImplementation = interfaceImplementation; + InterfaceType = interfaceType; } } } diff --git a/src/tools/illink/src/linker/Linker/OverrideInformation.cs b/src/tools/illink/src/linker/Linker/OverrideInformation.cs index 930b8c3c407b0..a80983802bf65 100644 --- a/src/tools/illink/src/linker/Linker/OverrideInformation.cs +++ b/src/tools/illink/src/linker/Linker/OverrideInformation.cs @@ -26,17 +26,14 @@ public OverrideInformation (MethodDefinition @base, MethodDefinition @override, || !@base.DeclaringType.IsInterface && interfaceImplementor == null); } - public InterfaceImplementation? MatchingInterfaceImplementation { - get { - return InterfaceImplementor?.InterfaceImplementation; - } - } + public InterfaceImplementation? MatchingInterfaceImplementation + => InterfaceImplementor?.InterfaceImplementation; + + public TypeDefinition? InterfaceType + => InterfaceImplementor?.InterfaceType; [MemberNotNullWhen (true, nameof (InterfaceImplementor), nameof (MatchingInterfaceImplementation))] - public bool IsOverrideOfInterfaceMember { - get { - return InterfaceImplementor != null; - } - } + public bool IsOverrideOfInterfaceMember + => InterfaceImplementor != null; } } diff --git a/src/tools/illink/src/linker/Linker/TypeMapInfo.cs b/src/tools/illink/src/linker/Linker/TypeMapInfo.cs index 92611e649ebc1..42f8708b36df5 100644 --- a/src/tools/illink/src/linker/Linker/TypeMapInfo.cs +++ b/src/tools/illink/src/linker/Linker/TypeMapInfo.cs @@ -169,14 +169,14 @@ void MapInterfaceMethodsInTypeHierarchy (TypeDefinition type) // Try to find an implementation with a name/sig match on the current type MethodDefinition? exactMatchOnType = TryMatchMethod (type, interfaceMethod); if (exactMatchOnType != null) { - AnnotateMethods (resolvedInterfaceMethod, exactMatchOnType, new (type, interfaceImpl.OriginalImpl)); + AnnotateMethods (resolvedInterfaceMethod, exactMatchOnType, new (type, interfaceImpl.OriginalImpl, context.Resolve(interfaceImpl.OriginalImpl.InterfaceType))); continue; } // Next try to find an implementation with a name/sig match in the base hierarchy var @base = GetBaseMethodInTypeHierarchy (type, interfaceMethod); if (@base != null) { - AnnotateMethods (resolvedInterfaceMethod, @base, new (type, interfaceImpl.OriginalImpl)); + AnnotateMethods (resolvedInterfaceMethod, @base, new (type, interfaceImpl.OriginalImpl, context.Resolve(interfaceImpl.OriginalImpl.InterfaceType))); continue; } } @@ -230,7 +230,7 @@ void MapOverrides (MethodDefinition method) { if (context.TryResolve (@interface.InterfaceType) == @override.DeclaringType) { - AnnotateMethods(@override, method, new InterfaceImplementor(method.DeclaringType, @interface)); + AnnotateMethods(@override, method, new InterfaceImplementor(method.DeclaringType, @interface, context.Resolve(@interface.InterfaceType))); break; } } @@ -315,7 +315,7 @@ void FindAndAddDefaultInterfaceImplementations (TypeDefinition type, MethodDefin foreach (var potentialImplMethod in potentialImplInterface.Methods) { if (potentialImplMethod == interfaceMethod && !potentialImplMethod.IsAbstract) { - AddDefaultInterfaceImplementation (interfaceMethod, new (type, interfaceImpl), potentialImplMethod); + AddDefaultInterfaceImplementation (interfaceMethod, new (type, interfaceImpl, context.Resolve(interfaceImpl.InterfaceType)), potentialImplMethod); foundImpl = true; break; } @@ -326,7 +326,7 @@ 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, new (type, interfaceImpl), @potentialImplMethod); + AddDefaultInterfaceImplementation (interfaceMethod, new (type, interfaceImpl, context.Resolve(interfaceImpl.InterfaceType)), @potentialImplMethod); foundImpl = true; break; } From 310de3004103e2f834ea63e1503c7625fa9d88bc Mon Sep 17 00:00:00 2001 From: Jackson Schuster <36744439+jtschuster@users.noreply.github.com> Date: Tue, 13 Feb 2024 13:50:38 -0800 Subject: [PATCH 05/18] Make new members internal for compat warnings --- src/tools/illink/src/linker/Linker/OverrideInformation.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/tools/illink/src/linker/Linker/OverrideInformation.cs b/src/tools/illink/src/linker/Linker/OverrideInformation.cs index a80983802bf65..04d42bb888bb5 100644 --- a/src/tools/illink/src/linker/Linker/OverrideInformation.cs +++ b/src/tools/illink/src/linker/Linker/OverrideInformation.cs @@ -14,9 +14,9 @@ public class OverrideInformation public MethodDefinition Override { get; } - public InterfaceImplementor? InterfaceImplementor { get; } + internal InterfaceImplementor? InterfaceImplementor { get; } - public OverrideInformation (MethodDefinition @base, MethodDefinition @override, InterfaceImplementor? interfaceImplementor = null) + internal OverrideInformation (MethodDefinition @base, MethodDefinition @override, InterfaceImplementor? interfaceImplementor = null) { Base = @base; Override = @override; From 77195a3e14f75192c9d16184e567304675ee8d2e Mon Sep 17 00:00:00 2001 From: Jackson Schuster <36744439+jtschuster@users.noreply.github.com> Date: Wed, 14 Feb 2024 10:04:27 -0800 Subject: [PATCH 06/18] Make InterfaceImplementor internal for API compat --- src/tools/illink/src/linker/Linker/InterfaceImplementor.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/illink/src/linker/Linker/InterfaceImplementor.cs b/src/tools/illink/src/linker/Linker/InterfaceImplementor.cs index aba6c3b44ce0b..3f019a5487659 100644 --- a/src/tools/illink/src/linker/Linker/InterfaceImplementor.cs +++ b/src/tools/illink/src/linker/Linker/InterfaceImplementor.cs @@ -6,7 +6,7 @@ namespace Mono.Linker { - public class InterfaceImplementor + internal class InterfaceImplementor { public TypeDefinition Implementor { get; } public InterfaceImplementation InterfaceImplementation { get; } From a73cc1f0a2ac77ea416db290da30adab7ca3aaf3 Mon Sep 17 00:00:00 2001 From: Jackson Schuster <36744439+jtschuster@users.noreply.github.com> Date: Wed, 14 Feb 2024 10:18:36 -0800 Subject: [PATCH 07/18] Make TypeMapInfo internal for API Compat --- src/tools/illink/src/linker/Linker/TypeMapInfo.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/illink/src/linker/Linker/TypeMapInfo.cs b/src/tools/illink/src/linker/Linker/TypeMapInfo.cs index 42f8708b36df5..019daa858dac2 100644 --- a/src/tools/illink/src/linker/Linker/TypeMapInfo.cs +++ b/src/tools/illink/src/linker/Linker/TypeMapInfo.cs @@ -38,7 +38,7 @@ namespace Mono.Linker { - public class TypeMapInfo + internal class TypeMapInfo { readonly HashSet assemblies = new HashSet (); readonly LinkContext context; From 76bc2554b2062c381e23772faa388c851ec08c83 Mon Sep 17 00:00:00 2001 From: Jackson Schuster <36744439+jtschuster@users.noreply.github.com> Date: Wed, 14 Feb 2024 10:26:33 -0800 Subject: [PATCH 08/18] Add InterfaceImplementor to suppressions.xml --- src/tools/illink/src/linker/CompatibilitySuppressions.xml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/tools/illink/src/linker/CompatibilitySuppressions.xml b/src/tools/illink/src/linker/CompatibilitySuppressions.xml index fd0dbb2635cb2..7bf0a1e0ce697 100644 --- a/src/tools/illink/src/linker/CompatibilitySuppressions.xml +++ b/src/tools/illink/src/linker/CompatibilitySuppressions.xml @@ -253,6 +253,10 @@ CP0001 T:Mono.Linker.ILogger + + CP0001 + T:Mono.Linker.InterfaceImplementor + CP0001 T:Mono.Linker.InternalErrorException From 11577fa557b9bf028216128dd4018143fab04a3f Mon Sep 17 00:00:00 2001 From: Jackson Schuster <36744439+jtschuster@users.noreply.github.com> Date: Wed, 14 Feb 2024 10:27:27 -0800 Subject: [PATCH 09/18] Make types public again --- src/tools/illink/src/linker/Linker/InterfaceImplementor.cs | 2 +- src/tools/illink/src/linker/Linker/TypeMapInfo.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/tools/illink/src/linker/Linker/InterfaceImplementor.cs b/src/tools/illink/src/linker/Linker/InterfaceImplementor.cs index 3f019a5487659..aba6c3b44ce0b 100644 --- a/src/tools/illink/src/linker/Linker/InterfaceImplementor.cs +++ b/src/tools/illink/src/linker/Linker/InterfaceImplementor.cs @@ -6,7 +6,7 @@ namespace Mono.Linker { - internal class InterfaceImplementor + public class InterfaceImplementor { public TypeDefinition Implementor { get; } public InterfaceImplementation InterfaceImplementation { get; } diff --git a/src/tools/illink/src/linker/Linker/TypeMapInfo.cs b/src/tools/illink/src/linker/Linker/TypeMapInfo.cs index 019daa858dac2..42f8708b36df5 100644 --- a/src/tools/illink/src/linker/Linker/TypeMapInfo.cs +++ b/src/tools/illink/src/linker/Linker/TypeMapInfo.cs @@ -38,7 +38,7 @@ namespace Mono.Linker { - internal class TypeMapInfo + public class TypeMapInfo { readonly HashSet assemblies = new HashSet (); readonly LinkContext context; From 5fb3256d18dd379e4fc138a3de5f8880f6090d7c Mon Sep 17 00:00:00 2001 From: Jackson Schuster <36744439+jtschuster@users.noreply.github.com> Date: Thu, 15 Feb 2024 10:55:12 -0800 Subject: [PATCH 10/18] Use correct InterfaceImplementor in FindAndAddDims --- src/tools/illink/src/linker/Linker/TypeMapInfo.cs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/tools/illink/src/linker/Linker/TypeMapInfo.cs b/src/tools/illink/src/linker/Linker/TypeMapInfo.cs index 42f8708b36df5..929e1e2d54120 100644 --- a/src/tools/illink/src/linker/Linker/TypeMapInfo.cs +++ b/src/tools/illink/src/linker/Linker/TypeMapInfo.cs @@ -182,7 +182,7 @@ void MapInterfaceMethodsInTypeHierarchy (TypeDefinition type) } // Look for a default implementation last. - FindAndAddDefaultInterfaceImplementations (type, resolvedInterfaceMethod); + FindAndAddDefaultInterfaceImplementations (type, type, resolvedInterfaceMethod); } } } @@ -300,12 +300,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 typeThatMayHaveDimProvidingInterface, 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 type.Interfaces) { + foreach (var interfaceImpl in typeThatMayHaveDimProvidingInterface.Interfaces) { var potentialImplInterface = context.TryResolve (interfaceImpl.InterfaceType); if (potentialImplInterface == null) continue; @@ -315,7 +315,7 @@ void FindAndAddDefaultInterfaceImplementations (TypeDefinition type, MethodDefin foreach (var potentialImplMethod in potentialImplInterface.Methods) { if (potentialImplMethod == interfaceMethod && !potentialImplMethod.IsAbstract) { - AddDefaultInterfaceImplementation (interfaceMethod, new (type, interfaceImpl, context.Resolve(interfaceImpl.InterfaceType)), potentialImplMethod); + AddDefaultInterfaceImplementation (interfaceMethod, new (typeThatImplementsInterface, interfaceImpl, context.Resolve(interfaceImpl.InterfaceType)), potentialImplMethod); foundImpl = true; break; } @@ -326,7 +326,7 @@ 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, new (type, interfaceImpl, context.Resolve(interfaceImpl.InterfaceType)), @potentialImplMethod); + AddDefaultInterfaceImplementation (interfaceMethod, new (typeThatImplementsInterface, interfaceImpl, context.Resolve(interfaceImpl.InterfaceType)), @potentialImplMethod); foundImpl = true; break; } @@ -340,7 +340,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, interfaceMethod); } } } From 3b4a69d8878959874dd64c4456686c1717a0194c Mon Sep 17 00:00:00 2001 From: Jackson Schuster <36744439+jtschuster@users.noreply.github.com> Date: Thu, 15 Feb 2024 13:13:45 -0800 Subject: [PATCH 11/18] InterfaceImplementor doesn't need to directly implement the interface --- src/tools/illink/src/linker/Linker/InterfaceImplementor.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/tools/illink/src/linker/Linker/InterfaceImplementor.cs b/src/tools/illink/src/linker/Linker/InterfaceImplementor.cs index aba6c3b44ce0b..854860adba55d 100644 --- a/src/tools/illink/src/linker/Linker/InterfaceImplementor.cs +++ b/src/tools/illink/src/linker/Linker/InterfaceImplementor.cs @@ -14,7 +14,6 @@ public class InterfaceImplementor public InterfaceImplementor (TypeDefinition implementor, InterfaceImplementation interfaceImplementation, TypeDefinition? interfaceType) { - Debug.Assert(implementor.Interfaces.Contains (interfaceImplementation)); Implementor = implementor; InterfaceImplementation = interfaceImplementation; InterfaceType = interfaceType; From 14814ed4eb8569ef7c42d515c83ec774e4a93fbe Mon Sep 17 00:00:00 2001 From: Jackson Schuster <36744439+jtschuster@users.noreply.github.com> Date: Wed, 21 Feb 2024 15:18:24 -0800 Subject: [PATCH 12/18] PR Feedback --- .../src/linker/Linker/InterfaceImplementor.cs | 13 ++++++- .../src/linker/Linker/OverrideInformation.cs | 2 + .../illink/src/linker/Linker/TypeMapInfo.cs | 37 +++++++++---------- 3 files changed, 31 insertions(+), 21 deletions(-) diff --git a/src/tools/illink/src/linker/Linker/InterfaceImplementor.cs b/src/tools/illink/src/linker/Linker/InterfaceImplementor.cs index 854860adba55d..6f0a55aba9b13 100644 --- a/src/tools/illink/src/linker/Linker/InterfaceImplementor.cs +++ b/src/tools/illink/src/linker/Linker/InterfaceImplementor.cs @@ -8,11 +8,20 @@ namespace Mono.Linker { public class InterfaceImplementor { + /// + /// The type that implements . + /// public TypeDefinition Implementor { get; } + /// + /// The .interfaceimpl on that points to + /// public InterfaceImplementation InterfaceImplementation { get; } - public TypeDefinition? InterfaceType { get; } + /// + /// The type of the interface that is implemented by + /// + public TypeDefinition InterfaceType { get; } - public InterfaceImplementor (TypeDefinition implementor, InterfaceImplementation interfaceImplementation, TypeDefinition? interfaceType) + public InterfaceImplementor (TypeDefinition implementor, InterfaceImplementation interfaceImplementation, TypeDefinition interfaceType) { Implementor = implementor; InterfaceImplementation = interfaceImplementation; diff --git a/src/tools/illink/src/linker/Linker/OverrideInformation.cs b/src/tools/illink/src/linker/Linker/OverrideInformation.cs index 04d42bb888bb5..0727d5d25c19a 100644 --- a/src/tools/illink/src/linker/Linker/OverrideInformation.cs +++ b/src/tools/illink/src/linker/Linker/OverrideInformation.cs @@ -24,6 +24,8 @@ internal OverrideInformation (MethodDefinition @base, MethodDefinition @override // Ensure we have an interface implementation if the base method is from an interface and the override method is on a class Debug.Assert(@base.DeclaringType.IsInterface && interfaceImplementor != null || !@base.DeclaringType.IsInterface && interfaceImplementor == null); + // Ensure the interfaceImplementor is for the interface we expect + Debug.Assert (@base.DeclaringType.IsInterface ? interfaceImplementor!.InterfaceType == @base.DeclaringType : true); } public InterfaceImplementation? MatchingInterfaceImplementation diff --git a/src/tools/illink/src/linker/Linker/TypeMapInfo.cs b/src/tools/illink/src/linker/Linker/TypeMapInfo.cs index 929e1e2d54120..a2915ab1a8c8a 100644 --- a/src/tools/illink/src/linker/Linker/TypeMapInfo.cs +++ b/src/tools/illink/src/linker/Linker/TypeMapInfo.cs @@ -32,7 +32,6 @@ using System.Collections.Generic; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; -using System.Linq; using Mono.Cecil; namespace Mono.Linker @@ -169,20 +168,20 @@ void MapInterfaceMethodsInTypeHierarchy (TypeDefinition type) // Try to find an implementation with a name/sig match on the current type MethodDefinition? exactMatchOnType = TryMatchMethod (type, interfaceMethod); if (exactMatchOnType != null) { - AnnotateMethods (resolvedInterfaceMethod, exactMatchOnType, new (type, interfaceImpl.OriginalImpl, context.Resolve(interfaceImpl.OriginalImpl.InterfaceType))); + AnnotateMethods (resolvedInterfaceMethod, exactMatchOnType, new (type, interfaceImpl.OriginalImpl, context.Resolve(interfaceImpl.OriginalImpl.InterfaceType)!)); continue; } // Next try to find an implementation with a name/sig match in the base hierarchy var @base = GetBaseMethodInTypeHierarchy (type, interfaceMethod); if (@base != null) { - AnnotateMethods (resolvedInterfaceMethod, @base, new (type, interfaceImpl.OriginalImpl, context.Resolve(interfaceImpl.OriginalImpl.InterfaceType))); + AnnotateMethods (resolvedInterfaceMethod, @base, new (type, interfaceImpl.OriginalImpl, context.Resolve(interfaceImpl.OriginalImpl.InterfaceType)!)); continue; } } // Look for a default implementation last. - FindAndAddDefaultInterfaceImplementations (type, type, resolvedInterfaceMethod); + FindAndAddDefaultInterfaceImplementations (type, resolvedInterfaceMethod); } } } @@ -219,25 +218,25 @@ void MapVirtualMethod (MethodDefinition method) void MapOverrides (MethodDefinition method) { - foreach (MethodReference override_ref in method.Overrides) { - MethodDefinition? @override = context.TryResolve (override_ref); - if (@override == null) + foreach (MethodReference baseMethodRef in method.Overrides) { + MethodDefinition? baseMethod = context.TryResolve (baseMethodRef); + if (baseMethod == null) continue; - if (@override.DeclaringType.IsInterface) + if (baseMethod.DeclaringType.IsInterface) { // Find the matching interface implementation if the base is an interface method - foreach (var @interface in method.DeclaringType.Interfaces) + foreach (var iface in method.DeclaringType.Interfaces) { - if (context.TryResolve (@interface.InterfaceType) == @override.DeclaringType) + if (context.TryResolve (iface.InterfaceType) == baseMethod.DeclaringType) { - AnnotateMethods(@override, method, new InterfaceImplementor(method.DeclaringType, @interface, context.Resolve(@interface.InterfaceType))); + AnnotateMethods (baseMethod, method, new InterfaceImplementor (method.DeclaringType, iface, context.Resolve (baseMethod.DeclaringType)!)); break; } } } else { - AnnotateMethods (@override, method); + AnnotateMethods (baseMethod, method); } } } @@ -300,12 +299,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 typeThatMayHaveDimProvidingInterface, MethodDefinition interfaceMethod) + 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 typeThatMayHaveDimProvidingInterface.Interfaces) { + foreach (var interfaceImpl in type.Interfaces) { var potentialImplInterface = context.TryResolve (interfaceImpl.InterfaceType); if (potentialImplInterface == null) continue; @@ -315,7 +314,7 @@ void FindAndAddDefaultInterfaceImplementations (TypeDefinition typeThatImplement foreach (var potentialImplMethod in potentialImplInterface.Methods) { if (potentialImplMethod == interfaceMethod && !potentialImplMethod.IsAbstract) { - AddDefaultInterfaceImplementation (interfaceMethod, new (typeThatImplementsInterface, interfaceImpl, context.Resolve(interfaceImpl.InterfaceType)), potentialImplMethod); + AddDefaultInterfaceImplementation (interfaceMethod, new (type, interfaceImpl, context.Resolve(interfaceMethod.DeclaringType)!), potentialImplMethod); foundImpl = true; break; } @@ -324,9 +323,9 @@ void FindAndAddDefaultInterfaceImplementations (TypeDefinition typeThatImplement continue; // 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, new (typeThatImplementsInterface, interfaceImpl, context.Resolve(interfaceImpl.InterfaceType)), @potentialImplMethod); + foreach (var baseMethod in potentialImplMethod.Overrides) { + if (context.TryResolve (baseMethod) == interfaceMethod) { + AddDefaultInterfaceImplementation (interfaceMethod, new (type, interfaceImpl, context.Resolve(interfaceMethod.DeclaringType)!), @potentialImplMethod); foundImpl = true; break; } @@ -340,7 +339,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, interfaceMethod); + FindAndAddDefaultInterfaceImplementations (potentialImplInterface, interfaceMethod); } } } From 56f23e4f2b123bd991ebf4de0b9abd3993c1be12 Mon Sep 17 00:00:00 2001 From: Jackson Schuster <36744439+jtschuster@users.noreply.github.com> Date: Wed, 21 Feb 2024 15:38:47 -0800 Subject: [PATCH 13/18] Don't need to resolve TypeDefinitions --- src/tools/illink/src/linker/Linker/TypeMapInfo.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/tools/illink/src/linker/Linker/TypeMapInfo.cs b/src/tools/illink/src/linker/Linker/TypeMapInfo.cs index a2915ab1a8c8a..ecefaf901d965 100644 --- a/src/tools/illink/src/linker/Linker/TypeMapInfo.cs +++ b/src/tools/illink/src/linker/Linker/TypeMapInfo.cs @@ -227,9 +227,9 @@ void MapOverrides (MethodDefinition method) // Find the matching interface implementation if the base is an interface method foreach (var iface in method.DeclaringType.Interfaces) { - if (context.TryResolve (iface.InterfaceType) == baseMethod.DeclaringType) + if (context.TryResolve (iface.InterfaceType) == baseMethod.DeclaringType) { - AnnotateMethods (baseMethod, method, new InterfaceImplementor (method.DeclaringType, iface, context.Resolve (baseMethod.DeclaringType)!)); + AnnotateMethods (baseMethod, method, new InterfaceImplementor (method.DeclaringType, iface, baseMethod.DeclaringType)); break; } } @@ -314,7 +314,7 @@ void FindAndAddDefaultInterfaceImplementations (TypeDefinition type, MethodDefin foreach (var potentialImplMethod in potentialImplInterface.Methods) { if (potentialImplMethod == interfaceMethod && !potentialImplMethod.IsAbstract) { - AddDefaultInterfaceImplementation (interfaceMethod, new (type, interfaceImpl, context.Resolve(interfaceMethod.DeclaringType)!), potentialImplMethod); + AddDefaultInterfaceImplementation (interfaceMethod, new (type, interfaceImpl, interfaceMethod.DeclaringType), potentialImplMethod); foundImpl = true; break; } @@ -325,7 +325,7 @@ 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 baseMethod in potentialImplMethod.Overrides) { if (context.TryResolve (baseMethod) == interfaceMethod) { - AddDefaultInterfaceImplementation (interfaceMethod, new (type, interfaceImpl, context.Resolve(interfaceMethod.DeclaringType)!), @potentialImplMethod); + AddDefaultInterfaceImplementation (interfaceMethod, new (type, interfaceImpl, interfaceMethod.DeclaringType), @potentialImplMethod); foundImpl = true; break; } From 1d1e88305bd40fe90cf877f50da154d4e44b2779 Mon Sep 17 00:00:00 2001 From: Jackson Schuster <36744439+jtschuster@users.noreply.github.com> Date: Thu, 22 Feb 2024 10:04:43 -0800 Subject: [PATCH 14/18] Use correct InterfaceImpl --- src/tools/illink/illink.sln | 1 + src/tools/illink/src/linker/Linker/TypeMapInfo.cs | 12 ++++++------ 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/tools/illink/illink.sln b/src/tools/illink/illink.sln index 87e99d208c7fb..9b8d904942baa 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 f0466b670821b..0f6b206633ee9 100644 --- a/src/tools/illink/src/linker/Linker/TypeMapInfo.cs +++ b/src/tools/illink/src/linker/Linker/TypeMapInfo.cs @@ -168,14 +168,14 @@ void MapInterfaceMethodsInTypeHierarchy (TypeDefinition type) // Try to find an implementation with a name/sig match on the current type MethodDefinition? exactMatchOnType = TryMatchMethod (type, interfaceMethod); if (exactMatchOnType != null) { - AnnotateMethods (resolvedInterfaceMethod, exactMatchOnType, new (type, interfaceImpl.OriginalImpl, context.Resolve(interfaceImpl.OriginalImpl.InterfaceType)!)); + AnnotateMethods (resolvedInterfaceMethod, exactMatchOnType, new (type, interfaceImpl.OriginalImpl, resolvedInterfaceMethod.DeclaringType)); continue; } // Next try to find an implementation with a name/sig match in the base hierarchy var @base = GetBaseMethodInTypeHierarchy (type, interfaceMethod); if (@base != null) { - AnnotateMethods (resolvedInterfaceMethod, @base, new (type, interfaceImpl.OriginalImpl, context.Resolve(interfaceImpl.OriginalImpl.InterfaceType)!)); + AnnotateMethods (resolvedInterfaceMethod, @base, new (type, interfaceImpl.OriginalImpl, resolvedInterfaceMethod.DeclaringType)); continue; } } @@ -306,7 +306,7 @@ void AnnotateMethods (MethodDefinition @base, MethodDefinition @override, Interf /// /// The InterfaceImplementation on that points to the DeclaringType of . /// - void FindAndAddDefaultInterfaceImplementations (TypeDefinition typeThatImplementsInterface, TypeDefinition typeThatMayHaveDIM, MethodDefinition interfaceMethodToBeImplemented) + void FindAndAddDefaultInterfaceImplementations (TypeDefinition typeThatImplementsInterface, TypeDefinition typeThatMayHaveDIM, MethodDefinition interfaceMethodToBeImplemented, InterfaceImplementation originalInterfaceImpl) { // Go over all interfaces, trying to find a method that is an explicit MethodImpl of the // interface method in question. @@ -321,7 +321,7 @@ void FindAndAddDefaultInterfaceImplementations (TypeDefinition typeThatImplement foreach (var potentialImplMethod in potentialImplInterface.Methods) { if (potentialImplMethod == interfaceMethodToBeImplemented && !potentialImplMethod.IsAbstract) { - AddDefaultInterfaceImplementation (interfaceMethodToBeImplemented, new (typeThatImplementsInterface, interfaceImpl, interfaceMethodToBeImplemented.DeclaringType), potentialImplMethod); + AddDefaultInterfaceImplementation (interfaceMethodToBeImplemented, new (typeThatImplementsInterface, originalInterfaceImpl, interfaceMethodToBeImplemented.DeclaringType), potentialImplMethod); foundImpl = true; break; } @@ -332,7 +332,7 @@ 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 baseMethod in potentialImplMethod.Overrides) { if (context.TryResolve (baseMethod) == interfaceMethodToBeImplemented) { - AddDefaultInterfaceImplementation (interfaceMethodToBeImplemented, new (typeThatImplementsInterface, interfaceImpl, interfaceMethodToBeImplemented.DeclaringType), @potentialImplMethod); + AddDefaultInterfaceImplementation (interfaceMethodToBeImplemented, new (typeThatImplementsInterface, originalInterfaceImpl, interfaceMethodToBeImplemented.DeclaringType), @potentialImplMethod); foundImpl = true; break; } @@ -346,7 +346,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 (typeThatImplementsInterface, potentialImplInterface, interfaceMethodToBeImplemented, originalInterfaceImpl); } } } From 7b218b65b724d751fbb0be421a4e47ceb6ae1f69 Mon Sep 17 00:00:00 2001 From: Jackson Schuster <36744439+jtschuster@users.noreply.github.com> Date: Thu, 22 Feb 2024 14:38:26 -0800 Subject: [PATCH 15/18] Add argument to first call --- src/tools/illink/src/linker/Linker/TypeMapInfo.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/illink/src/linker/Linker/TypeMapInfo.cs b/src/tools/illink/src/linker/Linker/TypeMapInfo.cs index 0f6b206633ee9..e7b3ee3abb63f 100644 --- a/src/tools/illink/src/linker/Linker/TypeMapInfo.cs +++ b/src/tools/illink/src/linker/Linker/TypeMapInfo.cs @@ -181,7 +181,7 @@ void MapInterfaceMethodsInTypeHierarchy (TypeDefinition type) } // Look for a default implementation last. - FindAndAddDefaultInterfaceImplementations (type, type, resolvedInterfaceMethod); + FindAndAddDefaultInterfaceImplementations (type, type, resolvedInterfaceMethod, interfaceImpl.OriginalImpl); } } } From 81ebc93c265a7914b580e4fb62c0c77b078c9adb Mon Sep 17 00:00:00 2001 From: Jackson Schuster <36744439+jtschuster@users.noreply.github.com> Date: Fri, 23 Feb 2024 15:54:20 -0800 Subject: [PATCH 16/18] Look on base types and interfaces for interfaceImpl --- .../src/linker/Linker/InterfaceImplementor.cs | 37 +++++++++++++++++++ .../illink/src/linker/Linker/TypeMapInfo.cs | 16 +++----- 2 files changed, 42 insertions(+), 11 deletions(-) diff --git a/src/tools/illink/src/linker/Linker/InterfaceImplementor.cs b/src/tools/illink/src/linker/Linker/InterfaceImplementor.cs index 6f0a55aba9b13..3dd346504e6fd 100644 --- a/src/tools/illink/src/linker/Linker/InterfaceImplementor.cs +++ b/src/tools/illink/src/linker/Linker/InterfaceImplementor.cs @@ -1,6 +1,9 @@ // 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. +using System; +using System.Collections; +using System.Collections.Generic; using System.Diagnostics; using Mono.Cecil; @@ -27,5 +30,39 @@ public InterfaceImplementor (TypeDefinition implementor, InterfaceImplementation InterfaceImplementation = interfaceImplementation; InterfaceType = interfaceType; } + + public static InterfaceImplementor Create(TypeDefinition implementor, TypeDefinition interfaceType, IMetadataResolver resolver) + { + foreach(InterfaceImplementation iface in implementor.Interfaces) { + if (resolver.Resolve(iface.InterfaceType) == interfaceType) { + return new InterfaceImplementor(implementor, iface, interfaceType); + } + } + var baseTypeRef = implementor.BaseType; + while (baseTypeRef is not null) { + var baseType = resolver.Resolve (baseTypeRef); + foreach(InterfaceImplementation iface in baseType.Interfaces) { + if (resolver.Resolve(iface.InterfaceType) == interfaceType) { + return new InterfaceImplementor(implementor, iface, interfaceType); + } + } + baseTypeRef = baseType.BaseType; + } + + Queue ifacesToCheck = new (); + ifacesToCheck.Enqueue(implementor); + while (ifacesToCheck.Count > 0) { + var myFace = ifacesToCheck.Dequeue (); + + foreach(InterfaceImplementation ifaceImpl in myFace.Interfaces) { + var iface = resolver.Resolve (ifaceImpl.InterfaceType); + if (iface == interfaceType) { + return new InterfaceImplementor(implementor, ifaceImpl, interfaceType); + } + ifacesToCheck.Enqueue (iface); + } + } + throw new InvalidOperationException ($"Type '{implementor.FullName}' does not implement interface '{interfaceType.FullName}' directly or through any base types or interfaces"); + } } } diff --git a/src/tools/illink/src/linker/Linker/TypeMapInfo.cs b/src/tools/illink/src/linker/Linker/TypeMapInfo.cs index e7b3ee3abb63f..5e71a2756a6a1 100644 --- a/src/tools/illink/src/linker/Linker/TypeMapInfo.cs +++ b/src/tools/illink/src/linker/Linker/TypeMapInfo.cs @@ -29,9 +29,11 @@ // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // +using System; using System.Collections.Generic; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; +using System.Linq; using Mono.Cecil; namespace Mono.Linker @@ -222,21 +224,13 @@ void MapOverrides (MethodDefinition method) MethodDefinition? baseMethod = context.TryResolve (baseMethodRef); if (baseMethod == null) continue; - if (baseMethod.DeclaringType.IsInterface) + if (!baseMethod.DeclaringType.IsInterface) { - // Find the matching interface implementation if the base is an interface method - foreach (var iface in method.DeclaringType.Interfaces) - { - if (context.TryResolve (iface.InterfaceType) == baseMethod.DeclaringType) - { - AnnotateMethods (baseMethod, method, new InterfaceImplementor (method.DeclaringType, iface, baseMethod.DeclaringType)); - break; - } - } + AnnotateMethods (baseMethod, method); } else { - AnnotateMethods (baseMethod, method); + AnnotateMethods (baseMethod, method, InterfaceImplementor.Create (method.DeclaringType, baseMethod.DeclaringType, context)); } } } From 2110159d5e39626dd9312f3dbc2f73b981d4fb74 Mon Sep 17 00:00:00 2001 From: Jackson Schuster <36744439+jtschuster@users.noreply.github.com> Date: Wed, 28 Feb 2024 14:01:38 -0800 Subject: [PATCH 17/18] Add test case and invert if Revert "Look on base types and interfaces for interfaceImpl" This reverts commit 81ebc93c265a7914b580e4fb62c0c77b078c9adb. Reapply "Look on base types and interfaces for interfaceImpl" This reverts commit 4320d2195719a68b51efa70fcced1fc5c7c9f6f2. Add test case Simplify test case --- .../src/linker/Linker/InterfaceImplementor.cs | 10 ---- .../illink/src/linker/Linker/TypeMapInfo.cs | 9 ++-- .../Inheritance.InterfacesTests.g.cs | 6 +++ ...nterfaceImplementedThroughBaseInterface.il | 48 +++++++++++++++++++ ...nterfaceImplementedThroughBaseInterface.cs | 34 +++++++++++++ 5 files changed, 91 insertions(+), 16 deletions(-) create mode 100644 src/tools/illink/test/Mono.Linker.Tests.Cases/Inheritance.Interfaces/Dependencies/InterfaceImplementedThroughBaseInterface.il create mode 100644 src/tools/illink/test/Mono.Linker.Tests.Cases/Inheritance.Interfaces/InterfaceImplementedThroughBaseInterface.cs diff --git a/src/tools/illink/src/linker/Linker/InterfaceImplementor.cs b/src/tools/illink/src/linker/Linker/InterfaceImplementor.cs index 3dd346504e6fd..2d09558ba6896 100644 --- a/src/tools/illink/src/linker/Linker/InterfaceImplementor.cs +++ b/src/tools/illink/src/linker/Linker/InterfaceImplementor.cs @@ -38,16 +38,6 @@ public static InterfaceImplementor Create(TypeDefinition implementor, TypeDefini return new InterfaceImplementor(implementor, iface, interfaceType); } } - var baseTypeRef = implementor.BaseType; - while (baseTypeRef is not null) { - var baseType = resolver.Resolve (baseTypeRef); - foreach(InterfaceImplementation iface in baseType.Interfaces) { - if (resolver.Resolve(iface.InterfaceType) == interfaceType) { - return new InterfaceImplementor(implementor, iface, interfaceType); - } - } - baseTypeRef = baseType.BaseType; - } Queue ifacesToCheck = new (); ifacesToCheck.Enqueue(implementor); diff --git a/src/tools/illink/src/linker/Linker/TypeMapInfo.cs b/src/tools/illink/src/linker/Linker/TypeMapInfo.cs index 5e71a2756a6a1..8d31934f9a0bb 100644 --- a/src/tools/illink/src/linker/Linker/TypeMapInfo.cs +++ b/src/tools/illink/src/linker/Linker/TypeMapInfo.cs @@ -224,13 +224,10 @@ void MapOverrides (MethodDefinition method) MethodDefinition? baseMethod = context.TryResolve (baseMethodRef); if (baseMethod == null) continue; - if (!baseMethod.DeclaringType.IsInterface) - { - AnnotateMethods (baseMethod, method); - } - else - { + if (baseMethod.DeclaringType.IsInterface) { AnnotateMethods (baseMethod, method, InterfaceImplementor.Create (method.DeclaringType, baseMethod.DeclaringType, context)); + } else { + AnnotateMethods (baseMethod, method); } } } diff --git a/src/tools/illink/test/ILLink.RoslynAnalyzer.Tests/generated/ILLink.RoslynAnalyzer.Tests.Generator/ILLink.RoslynAnalyzer.Tests.TestCaseGenerator/Inheritance.InterfacesTests.g.cs b/src/tools/illink/test/ILLink.RoslynAnalyzer.Tests/generated/ILLink.RoslynAnalyzer.Tests.Generator/ILLink.RoslynAnalyzer.Tests.TestCaseGenerator/Inheritance.InterfacesTests.g.cs index 2e1a2bbcb3454..649b8449527f7 100644 --- a/src/tools/illink/test/ILLink.RoslynAnalyzer.Tests/generated/ILLink.RoslynAnalyzer.Tests.Generator/ILLink.RoslynAnalyzer.Tests.TestCaseGenerator/Inheritance.InterfacesTests.g.cs +++ b/src/tools/illink/test/ILLink.RoslynAnalyzer.Tests/generated/ILLink.RoslynAnalyzer.Tests.Generator/ILLink.RoslynAnalyzer.Tests.TestCaseGenerator/Inheritance.InterfacesTests.g.cs @@ -15,6 +15,12 @@ public Task CanDisableUnusedInterfaces () return RunTest (allowMissingWarnings: true); } + [Fact] + public Task InterfaceImplementedThroughBaseInterface () + { + return RunTest (allowMissingWarnings: true); + } + [Fact] public Task InterfaceOnUninstantiatedTypeRemoved () { diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases/Inheritance.Interfaces/Dependencies/InterfaceImplementedThroughBaseInterface.il b/src/tools/illink/test/Mono.Linker.Tests.Cases/Inheritance.Interfaces/Dependencies/InterfaceImplementedThroughBaseInterface.il new file mode 100644 index 0000000000000..61080f8b7d066 --- /dev/null +++ b/src/tools/illink/test/Mono.Linker.Tests.Cases/Inheritance.Interfaces/Dependencies/InterfaceImplementedThroughBaseInterface.il @@ -0,0 +1,48 @@ +// 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 interface public auto ansi abstract beforefieldinit IBase +{ + // Methods + .method public hidebysig newslot abstract virtual + instance void M () cil managed + { + } // end of method IBase::M + +} // end of class IBase + +.class interface public auto ansi abstract beforefieldinit IDerived + implements IBase +{ +} // end of class IDerived + +.class public auto ansi beforefieldinit C + extends [System.Runtime]System.Object + implements IDerived +{ + // Methods + .method private final hidebysig newslot virtual + instance void IBase.M () cil managed + { + .override method instance void IBase::M() + // Method begins at RVA 0x2050 + // Code size 2 (0x2) + .maxstack 8 + + IL_0001: ret + } // end of method C::IBase.M + + .method public hidebysig specialname rtspecialname + instance void .ctor () cil managed + { + // Method begins at RVA 0x2053 + // Code size 8 (0x8) + .maxstack 8 + + IL_0007: ret + } // end of method C::.ctor +} diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases/Inheritance.Interfaces/InterfaceImplementedThroughBaseInterface.cs b/src/tools/illink/test/Mono.Linker.Tests.Cases/Inheritance.Interfaces/InterfaceImplementedThroughBaseInterface.cs new file mode 100644 index 0000000000000..e701fb9c28ba6 --- /dev/null +++ b/src/tools/illink/test/Mono.Linker.Tests.Cases/Inheritance.Interfaces/InterfaceImplementedThroughBaseInterface.cs @@ -0,0 +1,34 @@ +// 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. + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Mono.Linker.Tests.Cases.Expectations.Assertions; +using Mono.Linker.Tests.Cases.Expectations.Metadata; + +namespace Mono.Linker.Tests.Cases.Inheritance.Interfaces +{ + [SetupLinkerArgument ("--skip-unresolved", "true")] + [SetupLinkerArgument ("-a", "test.exe", "library")] + [SetupLinkerArgument ("-a", "library.dll", "library")] + [TestCaseRequirements (TestRunCharacteristics.SupportsDefaultInterfaceMethods, "Requires support for default interface methods")] + [Define ("IL_ASSEMBLY_AVAILABLE")] + [SetupCompileBefore ("library.dll", new[] { "Dependencies/InterfaceImplementedThroughBaseInterface.il" })] + [SkipILVerify] + +#if IL_ASSEMBLY_AVAILABLE + [KeptMemberInAssembly ("library.dll", typeof(C), "IBase.M()")] +#endif + [KeptMember(".ctor()")] + public class InterfaceImplementedThroughBaseInterface + { + public static void Main () + { + } + } +} + + From 488ff7248e6fbe11f39bec864575621a68100ded Mon Sep 17 00:00:00 2001 From: Jackson Schuster <36744439+jtschuster@users.noreply.github.com> Date: Wed, 28 Feb 2024 17:53:56 -0800 Subject: [PATCH 18/18] PR feedback: - Rename local - Assert InterfaceType is resolved InterfaceImplementation.InterfaceType --- .../src/linker/Linker/InterfaceImplementor.cs | 13 +++++++------ src/tools/illink/src/linker/Linker/TypeMapInfo.cs | 8 ++++---- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/src/tools/illink/src/linker/Linker/InterfaceImplementor.cs b/src/tools/illink/src/linker/Linker/InterfaceImplementor.cs index 2d09558ba6896..e981ce872703f 100644 --- a/src/tools/illink/src/linker/Linker/InterfaceImplementor.cs +++ b/src/tools/illink/src/linker/Linker/InterfaceImplementor.cs @@ -24,35 +24,36 @@ public class InterfaceImplementor /// public TypeDefinition InterfaceType { get; } - public InterfaceImplementor (TypeDefinition implementor, InterfaceImplementation interfaceImplementation, TypeDefinition interfaceType) + public InterfaceImplementor (TypeDefinition implementor, InterfaceImplementation interfaceImplementation, TypeDefinition interfaceType, IMetadataResolver resolver) { Implementor = implementor; InterfaceImplementation = interfaceImplementation; InterfaceType = interfaceType; + Debug.Assert(resolver.Resolve (interfaceImplementation.InterfaceType) == interfaceType); } public static InterfaceImplementor Create(TypeDefinition implementor, TypeDefinition interfaceType, IMetadataResolver resolver) { foreach(InterfaceImplementation iface in implementor.Interfaces) { if (resolver.Resolve(iface.InterfaceType) == interfaceType) { - return new InterfaceImplementor(implementor, iface, interfaceType); + return new InterfaceImplementor(implementor, iface, interfaceType, resolver); } } Queue ifacesToCheck = new (); ifacesToCheck.Enqueue(implementor); while (ifacesToCheck.Count > 0) { - var myFace = ifacesToCheck.Dequeue (); + var currentIface = ifacesToCheck.Dequeue (); - foreach(InterfaceImplementation ifaceImpl in myFace.Interfaces) { + foreach(InterfaceImplementation ifaceImpl in currentIface.Interfaces) { var iface = resolver.Resolve (ifaceImpl.InterfaceType); if (iface == interfaceType) { - return new InterfaceImplementor(implementor, ifaceImpl, interfaceType); + return new InterfaceImplementor(implementor, ifaceImpl, interfaceType, resolver); } ifacesToCheck.Enqueue (iface); } } - throw new InvalidOperationException ($"Type '{implementor.FullName}' does not implement interface '{interfaceType.FullName}' directly or through any base types or interfaces"); + throw new InvalidOperationException ($"Type '{implementor.FullName}' does not implement interface '{interfaceType.FullName}' directly or through any interfaces"); } } } diff --git a/src/tools/illink/src/linker/Linker/TypeMapInfo.cs b/src/tools/illink/src/linker/Linker/TypeMapInfo.cs index 8d31934f9a0bb..bb2836a804d7b 100644 --- a/src/tools/illink/src/linker/Linker/TypeMapInfo.cs +++ b/src/tools/illink/src/linker/Linker/TypeMapInfo.cs @@ -170,14 +170,14 @@ void MapInterfaceMethodsInTypeHierarchy (TypeDefinition type) // Try to find an implementation with a name/sig match on the current type MethodDefinition? exactMatchOnType = TryMatchMethod (type, interfaceMethod); if (exactMatchOnType != null) { - AnnotateMethods (resolvedInterfaceMethod, exactMatchOnType, new (type, interfaceImpl.OriginalImpl, resolvedInterfaceMethod.DeclaringType)); + AnnotateMethods (resolvedInterfaceMethod, exactMatchOnType, new (type, interfaceImpl.OriginalImpl, resolvedInterfaceMethod.DeclaringType, context)); continue; } // Next try to find an implementation with a name/sig match in the base hierarchy var @base = GetBaseMethodInTypeHierarchy (type, interfaceMethod); if (@base != null) { - AnnotateMethods (resolvedInterfaceMethod, @base, new (type, interfaceImpl.OriginalImpl, resolvedInterfaceMethod.DeclaringType)); + AnnotateMethods (resolvedInterfaceMethod, @base, new (type, interfaceImpl.OriginalImpl, resolvedInterfaceMethod.DeclaringType, context)); continue; } } @@ -312,7 +312,7 @@ void FindAndAddDefaultInterfaceImplementations (TypeDefinition typeThatImplement foreach (var potentialImplMethod in potentialImplInterface.Methods) { if (potentialImplMethod == interfaceMethodToBeImplemented && !potentialImplMethod.IsAbstract) { - AddDefaultInterfaceImplementation (interfaceMethodToBeImplemented, new (typeThatImplementsInterface, originalInterfaceImpl, interfaceMethodToBeImplemented.DeclaringType), potentialImplMethod); + AddDefaultInterfaceImplementation (interfaceMethodToBeImplemented, new (typeThatImplementsInterface, originalInterfaceImpl, interfaceMethodToBeImplemented.DeclaringType, context), potentialImplMethod); foundImpl = true; break; } @@ -323,7 +323,7 @@ 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 baseMethod in potentialImplMethod.Overrides) { if (context.TryResolve (baseMethod) == interfaceMethodToBeImplemented) { - AddDefaultInterfaceImplementation (interfaceMethodToBeImplemented, new (typeThatImplementsInterface, originalInterfaceImpl, interfaceMethodToBeImplemented.DeclaringType), @potentialImplMethod); + AddDefaultInterfaceImplementation (interfaceMethodToBeImplemented, new (typeThatImplementsInterface, originalInterfaceImpl, interfaceMethodToBeImplemented.DeclaringType, context), @potentialImplMethod); foundImpl = true; break; }