-
Notifications
You must be signed in to change notification settings - Fork 127
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Don't mark static interface methods when called on a concrete type, and removed the MethodImpl / Override if the interface method is kept. Co-authored-by: vitek-karas <[email protected]> Co-authored-by: vitek-karas <[email protected]>
- Loading branch information
1 parent
e768b2e
commit a073a68
Showing
8 changed files
with
258 additions
and
30 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
# Removal Behavior for interfaces | ||
|
||
## `unusedinterfaces` optimization | ||
|
||
The `unusedinterfaces` optimization controls whether or not trimmin may remove the `interfaceimpl` annotation which denotes whether a class implements an interface. When the optimization is off, the linker will not remove the annotations regardless of the visibility of the interface (even private interface implementations will be kept). However, unused methods from interfaces may still be removed, as well as `.override` directives from methods that implement an interface method. When the optimization is on and the linker can provably determine that an interface will not be used on a type, the annotation will be removed. In order to know whether it is safe to remove an interface implementation, it is necessary to have a "global" view of the code. In other words, if an assembly is passed without selecting `link` for the `action` option for the linker, all classes that implement interfaces from that assembly will keep those interface implementation annotations. For example, if you implement `System.IFormattable` from the `System.Runtime` assembly, but pass the assembly with `--action copy System.Runtime`, the interface implementation will be kept even if your code doesn't use it. | ||
|
||
## Static abstract interface methods | ||
|
||
The linker's behavior for methods declared on interfaces as `static abstract` like below are defined in the following cases using the example interface and class below: | ||
|
||
```C# | ||
interface IFoo | ||
{ | ||
static abstract int GetNum(); | ||
} | ||
|
||
class C : IFoo | ||
{ | ||
static int GetNum() => 1; | ||
} | ||
``` | ||
|
||
### Method call on concrete type | ||
|
||
On a direct call to a static method which implements a static interface method, only the body is rooted, not its associated `MethodImpl`. Similarly, the interface method which it implements is not rooted. | ||
|
||
Example: | ||
|
||
In the following program, `C.GetNum()` would be kept, but `IFoo.GetNum()` would be removed. | ||
|
||
```C# | ||
public class Program | ||
{ | ||
public static void Main() | ||
{ | ||
C.GetNum(); | ||
} | ||
} | ||
``` | ||
|
||
### Method call on a constrained type parameter | ||
|
||
On a call to a static abstract interface method that is accessed through a constrained type parameter, the interface method is rooted, as well as every implementation method on every type. | ||
|
||
Example: | ||
|
||
In the following program, `C.GetNum()`, `IFoo.GetNum()`, and `C2.GetNum()` are all kept. | ||
|
||
```C# | ||
public class C2 : IFoo | ||
{ | ||
static int GetNum() => 2; | ||
} | ||
public class Program | ||
{ | ||
public static void Main() | ||
{ | ||
M<C>(); | ||
} | ||
public static void M<T>() where T : IFoo | ||
{ | ||
T.GetNum(); | ||
} | ||
} | ||
``` | ||
|
||
# `.override` directive and `MethodImpl` marking | ||
|
||
The linker currently does not mark `.override` or `MethodImpl` relationships. It will only remove the relationship if one of the methods is removed. These relationships are not always necessary, and future updates could add the ability to remove these relationships even if both methods are not trimmed. |
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
27 changes: 27 additions & 0 deletions
27
test/Mono.Linker.Tests.Cases.Expectations/Assertions/KeptOverrideAttribute.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,27 @@ | ||
// 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 | ||
{ | ||
/// <summary> | ||
/// Used to ensure that a method should keep an 'override' annotation for a method in the supplied base type. | ||
/// The absence of this attribute does not enforce that the override is removed -- this is different from other Kept attributes | ||
/// To enforce the removal of an override, use <see cref="RemovedOverrideAttribute"/>. | ||
/// Fails in tests if the method doesn't have the override method in the original or linked assembly. | ||
/// </summary> | ||
/// <seealso cref="RemovedOverrideAttribute" /> | ||
[AttributeUsage (AttributeTargets.Method, AllowMultiple = true, Inherited = false)] | ||
public class KeptOverrideAttribute : KeptAttribute | ||
{ | ||
public Type TypeWithOverriddenMethodDeclaration; | ||
|
||
public KeptOverrideAttribute (Type typeWithOverriddenMethod) | ||
{ | ||
if (typeWithOverriddenMethod == null) | ||
throw new ArgumentNullException (nameof (typeWithOverriddenMethod)); | ||
TypeWithOverriddenMethodDeclaration = typeWithOverriddenMethod; | ||
} | ||
} | ||
} |
25 changes: 25 additions & 0 deletions
25
test/Mono.Linker.Tests.Cases.Expectations/Assertions/RemovedOverrideAttribute.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,25 @@ | ||
// 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 | ||
{ | ||
/// <Summary> | ||
/// Used to ensure that a method should remove an 'override' annotation for a method in the supplied base type. | ||
/// Fails in tests if the method has the override method in the linked assembly, | ||
/// or if the override is not found in the original assembly | ||
/// </Summary> | ||
/// <seealso cref="KeptOverrideAttribute" /> | ||
[AttributeUsage (AttributeTargets.Method, AllowMultiple = true, Inherited = false)] | ||
public class RemovedOverrideAttribute : BaseInAssemblyAttribute | ||
{ | ||
public Type TypeWithOverriddenMethodDeclaration; | ||
public RemovedOverrideAttribute (Type typeWithOverriddenMethod) | ||
{ | ||
if (typeWithOverriddenMethod == null) | ||
throw new ArgumentException ("Value cannot be null or empty.", nameof (typeWithOverriddenMethod)); | ||
TypeWithOverriddenMethodDeclaration = typeWithOverriddenMethod; | ||
} | ||
} | ||
} |
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
Oops, something went wrong.