-
Notifications
You must be signed in to change notification settings - Fork 5.3k
Description
Background and motivation
While we were working with trimming, we found that we often want to express "code only needed if a type is preserved", but currently we do not have such thing in C#.
For example, in XAML frameworks, we use URLs to locate resources. With source generator, the code of the resource locator which is generated by a source generator may consist with a method with plenty of if statements, for example:
// auto-generated by a source generator
object? LoadResource(string path)
{
if (path == "ms-appx://MyAssembly/My/Fancy/XamlControl1Style") return XamlLoader.Load<XamlControl1Style>();
if (path == "ms-appx://MyAssembly/Another/XamlControl2Style") return XamlLoader.Load<XamlControl2Style>();
return null;
}With this source generator approach, we can achieve trimming compatibility. However, this would result in all types referenced in LoadResource being preserved even they are not being actually used. In this case, we only want XamlControl1Style to be preserved if XamlControl1 is referenced in other pieces of code.
API Proposal
namespace System.Diagnostics.CodeAnalysis;
public class ControlFlow
{
public static bool MakeWeakTypeReference<T>() => true;
}API Usage
object? LoadResource(string path)
{
if (ControlFlow.MakeWeakTypeReference<XamlControl1>())
if (path == "ms-appx://MyAssembly/My/Fancy/XamlControl1Style")
return XamlLoader.Load<XamlControl1Style>();
if (ControlFlow.MakeWeakTypeReference<XamlControl2>())
if (path == "ms-appx://MyAssembly/Another/XamlControl2Style")
return XamlLoader.Load<XamlControl2Style>();
return null;
}It behaves as a no-op which always returns true, but if there are no other type references to XamlControl1, the whole block of the if statement can be safely trimmed, which produces code after trimming like below:
object? LoadResource(string path)
{
if (path == "ms-appx://MyAssembly/Another/XamlControl2Style")
return XamlLoader.Load<XamlControl2Style>();
return null;
}Therefore, all types related to XamlControl1 and XamlControl1Type can also be trimmed away.
This should also support and and or so that we can express multiple types as a single prerequisite:
if (ControlFlow.MakeWeakTypeReference<Foo>() && ControlFlow.MakeWeakTypeReference<Bar>())
{
// only preserved if both Foo and Bar are referenced
}
if (ControlFlow.MakeWeakTypeReference<Foo>() || ControlFlow.MakeWeakTypeReference<Bar>())
{
// only preserved if either Foo or Bar is referenced
}
// Bogus
if (!ControlFlow.MakeWeakTypeReference<Foo>())
{
// no-op, can never reach because `!ControlFlow.MakeWeakTypeReference<Foo>()` is always false, maybe a warning should be emitted by the compiler or illink?
}Alternative Designs
No response
Risks
No response
Metadata
Metadata
Assignees
Labels
Type
Projects
Status