forked from dotnet/runtime
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
ILLink: Sweep .override for interface method if the .interfaceImpl is…
… removed (dotnet#102857) When static interface methods are kept but an implementation of the method is only accessed via a direct call on the implementing type, the implementation method and the .override pointing to the interface method are both kept, but not the .interfaceImpl. This causes a TypeLoadException when the .override points to a method on an interface that the type doesn't implement. To fix this, we needed to update the condition for sweeping overrides to include the case where both the interface and the interface method are kept, but the .interfaceImpl is not kept. Tests are for static interface methods, but concrete and generic to test type resolution in SweepStep, which can be finicky. Instance methods shouldn't hit this issue since public interface methods don't have a .override and private methods can't be marked without instantiating the type or reflecting over the type, both of which mark the type's .interfaceImpls, and making the .override valid. For instance methods, we will always mark any methods referenced in a .override as well as their corresponding interface implementation, so we won't end up in a scenario where an instance method would have dangling references in a .override. I did fix up the interface implementation marking (MarkRuntimeInterfaceImplementation) to make sure it can find a recursive interface, and marks the .interfaceImpl with the exact same TypeReference rather than just the same TypeDefinition (for example, IGeneric<int> should be marked, not just the first IGeneric<> interfaceImpl). This was one of the examples where the trimmer would end up doing the right thing (all IGeneric<> implementations would end up marked anyway), but it would do it for a different reason than we expect.
- Loading branch information
1 parent
6b7900d
commit 24a436d
Showing
16 changed files
with
1,145 additions
and
102 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
15 changes: 15 additions & 0 deletions
15
...ono.Linker.Tests.Cases.Expectations/Assertions/KeptOverrideOnMethodInAssemblyAttribute.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
// 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; | ||
|
||
namespace Mono.Linker.Tests.Cases.Expectations.Assertions | ||
{ | ||
[AttributeUsage (AttributeTargets.All, AllowMultiple = true)] | ||
public class KeptOverrideOnMethodInAssemblyAttribute : BaseInAssemblyAttribute | ||
{ | ||
public KeptOverrideOnMethodInAssemblyAttribute (string assemblyName, string typeName, string methodName, string overriddenMethodName) | ||
{ | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
15 changes: 15 additions & 0 deletions
15
....Linker.Tests.Cases.Expectations/Assertions/RemovedOverrideOnMethodInAssemblyAttribute.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
// 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; | ||
|
||
namespace Mono.Linker.Tests.Cases.Expectations.Assertions | ||
{ | ||
[AttributeUsage (AttributeTargets.All, AllowMultiple = true, Inherited = false)] | ||
public class RemovedOverrideOnMethodInAssemblyAttribute : BaseInAssemblyAttribute | ||
{ | ||
public RemovedOverrideOnMethodInAssemblyAttribute (string library, string typeName, string methodName, string overriddenMethodFullName) | ||
{ | ||
} | ||
} | ||
} |
168 changes: 168 additions & 0 deletions
168
...ance.Interfaces/RecursiveInterfaces/Dependencies/OverrideOfRecursiveInterfaceIsRemoved.il
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,168 @@ | ||
// 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 beforefieldinit Program | ||
extends [mscorlib]System.Object | ||
{ | ||
// Nested Types | ||
.class interface nested public auto ansi abstract beforefieldinit IBaseUnused | ||
{ | ||
// Methods | ||
.method public hidebysig abstract virtual static | ||
void M () cil managed | ||
{ | ||
} // end of method IBaseUnused::M | ||
|
||
} // end of class IBaseUnused | ||
|
||
.class interface nested public auto ansi abstract beforefieldinit IBaseUsed | ||
{ | ||
// Methods | ||
.method public hidebysig abstract virtual static | ||
void M () cil managed | ||
{ | ||
} // end of method IBaseUsed::M | ||
|
||
} // end of class IBaseUsed | ||
|
||
.class interface nested private auto ansi abstract beforefieldinit IMiddleUnused | ||
implements Program/IBaseUnused, | ||
Program/IBaseUsed | ||
{ | ||
// Methods | ||
.method public hidebysig abstract virtual static | ||
void O () cil managed | ||
{ | ||
} // end of method IMiddleUnused::O | ||
|
||
} // end of class IMiddleUnused | ||
|
||
.class interface nested private auto ansi abstract beforefieldinit IDerived | ||
implements Program/IMiddleUnused | ||
{ | ||
// Methods | ||
.method public hidebysig abstract virtual static | ||
void N () cil managed | ||
{ | ||
} // end of method IDerived::N | ||
|
||
} // end of class IDerived | ||
|
||
.class nested private auto ansi beforefieldinit A | ||
extends [mscorlib]System.Object | ||
implements Program/IDerived | ||
{ | ||
// Methods | ||
.method public hidebysig static | ||
void M () cil managed | ||
{ | ||
.override method void Program/IBaseUnused::M() | ||
.override method void Program/IBaseUsed::M() | ||
// Method begins at RVA 0x2083 | ||
// Code size 1 (0x1) | ||
.maxstack 8 | ||
|
||
IL_0000: ret | ||
} // end of method A::M | ||
|
||
.method public hidebysig static | ||
void N () cil managed | ||
{ | ||
.override method void Program/IDerived::N() | ||
// Method begins at RVA 0x2083 | ||
// Code size 1 (0x1) | ||
.maxstack 8 | ||
|
||
IL_0000: ret | ||
} // end of method A::N | ||
|
||
.method public hidebysig static | ||
void O () cil managed | ||
{ | ||
.override method void Program/IMiddleUnused::O() | ||
// Method begins at RVA 0x2083 | ||
// Code size 1 (0x1) | ||
.maxstack 8 | ||
|
||
IL_0000: ret | ||
} // end of method A::O | ||
|
||
.method public hidebysig specialname rtspecialname | ||
instance void .ctor () cil managed | ||
{ | ||
// Method begins at RVA 0x207b | ||
// Code size 7 (0x7) | ||
.maxstack 8 | ||
|
||
IL_0000: ldarg.0 | ||
IL_0001: call instance void [mscorlib]System.Object::.ctor() | ||
IL_0006: ret | ||
} // end of method A::.ctor | ||
|
||
} // end of class A | ||
|
||
|
||
// Methods | ||
.method public hidebysig static | ||
void MyTest () cil managed | ||
{ | ||
// Method begins at RVA 0x2050 | ||
// Code size 16 (0x10) | ||
.maxstack 8 | ||
|
||
IL_0000: call void Program::UseNThroughIDerived<class Program/A>() | ||
IL_0005: call void Program::UseMThroughIDerived<class Program/A>() | ||
IL_000a: call void Program/A::M() | ||
IL_000f: call void Program/A::O() | ||
IL_0014: ret | ||
} // end of method Program::MyTest | ||
|
||
.method private hidebysig static | ||
void UseNThroughIDerived<(Program/IDerived) T> () cil managed | ||
{ | ||
.param constraint T, Program/IDerived | ||
.custom instance void [mscorlib]System.Runtime.CompilerServices.NullableAttribute::.ctor(uint8) = ( | ||
01 00 01 00 00 | ||
) | ||
// Method begins at RVA 0x2061 | ||
// Code size 12 (0xc) | ||
.maxstack 8 | ||
|
||
IL_0000: constrained. !!T | ||
IL_0006: call void Program/IDerived::N() | ||
IL_000b: ret | ||
} // end of method Program::UseNThroughIDerived | ||
|
||
.method private hidebysig static | ||
void UseMThroughIDerived<(Program/IBaseUsed) T> () cil managed | ||
{ | ||
.param constraint T, Program/IBaseUnused | ||
.custom instance void [mscorlib]System.Runtime.CompilerServices.NullableAttribute::.ctor(uint8) = ( | ||
01 00 01 00 00 | ||
) | ||
// Method begins at RVA 0x206e | ||
// Code size 12 (0xc) | ||
.maxstack 8 | ||
|
||
IL_0000: constrained. !!T | ||
IL_0006: call void Program/IBaseUsed::M() | ||
IL_000b: ret | ||
} // end of method Program::UseMThroughIDerived | ||
|
||
.method public hidebysig specialname rtspecialname | ||
instance void .ctor () cil managed | ||
{ | ||
// Method begins at RVA 0x207b | ||
// Code size 7 (0x7) | ||
.maxstack 8 | ||
|
||
IL_0000: ldarg.0 | ||
IL_0001: call instance void [mscorlib]System.Object::.ctor() | ||
IL_0006: ret | ||
} // end of method Program::.ctor | ||
|
||
} // end of class Program |
Oops, something went wrong.