Skip to content

Preserve static type info for return value of ctor #101212

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 10 commits into from
Apr 30, 2024
Merged
2 changes: 2 additions & 0 deletions src/coreclr/tools/Common/Compiler/Dataflow/MethodProxy.cs
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,8 @@ internal partial ImmutableArray<GenericParameterProxy> GetGenericParameters()
return builder.ToImmutableArray();
}

internal partial bool IsConstructor() => Method.IsConstructor;

internal partial bool IsStatic() => Method.Signature.IsStatic;

internal partial bool HasImplicitThis() => !Method.Signature.IsStatic;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ internal partial record MethodReturnValue
{
public MethodReturnValue(MethodDesc method, DynamicallyAccessedMemberTypes dynamicallyAccessedMemberTypes)
{
StaticType = method.Signature.ReturnType;
StaticType = method.IsConstructor ? method.OwningType : method.Signature.ReturnType;
Method = method;
DynamicallyAccessedMemberTypes = dynamicallyAccessedMemberTypes;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -656,12 +656,6 @@ public static bool HandleCall(
if (Intrinsics.GetIntrinsicIdForMethod(callingMethodDefinition) == IntrinsicId.RuntimeReflectionExtensions_GetMethodInfo)
break;

if (param.IsEmpty())
{
// The static value is unknown and the below `foreach` won't execute
reflectionMarker.Dependencies.Add(reflectionMarker.Factory.ReflectedDelegate(null), "Delegate.Method access on unknown delegate type");
}

foreach (var valueNode in param.AsEnumerable())
{
TypeDesc? staticType = (valueNode as IValueWithStaticType)?.StaticType?.Type;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@ internal partial ImmutableArray<GenericParameterProxy> GetGenericParameters ()
return builder.ToImmutableArray ();
}

internal partial bool IsConstructor () => Method.IsConstructor ();

internal partial bool IsStatic () => Method.IsStatic;

internal partial bool HasImplicitThis () => Method.HasImplicitThis ();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1167,7 +1167,7 @@ GenericParameterValue genericParam

// For now, if the intrinsic doesn't set a return value, fall back on the annotations.
// Note that this will be DynamicallyAccessedMembers.None for the intrinsics which don't return types.
returnValue ??= calledMethod.ReturnsVoid () ? MultiValueLattice.Top : annotatedMethodReturnValue;
returnValue ??= (calledMethod.ReturnsVoid () && !calledMethod.IsConstructor ()) ? MultiValueLattice.Top : annotatedMethodReturnValue;

if (MethodIsTypeConstructor (calledMethod))
returnValue = UnknownValue.Instance;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ internal bool HasParameterOfType (ParameterIndex parameterIndex, string fullType
internal partial bool HasGenericParameters ();
internal partial bool HasGenericParametersCount (int genericParameterCount);
internal partial ImmutableArray<GenericParameterProxy> GetGenericParameters ();
internal partial bool IsConstructor ();
internal partial bool IsStatic ();
internal partial bool HasImplicitThis ();
internal partial bool ReturnsVoid ();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -683,7 +683,7 @@ internal partial bool MethodRequiresDataFlowAnalysis (MethodProxy method)
=> RequiresDataFlowAnalysis (method.Method);

internal partial MethodReturnValue GetMethodReturnValue (MethodProxy method, DynamicallyAccessedMemberTypes dynamicallyAccessedMemberTypes)
=> new MethodReturnValue (method.Method.ReturnType.ResolveToTypeDefinition (_context), method.Method, dynamicallyAccessedMemberTypes);
=> MethodReturnValue.Create (method.Method, dynamicallyAccessedMemberTypes, _context);

internal partial MethodReturnValue GetMethodReturnValue (MethodProxy method)
=> GetMethodReturnValue (method, GetReturnParameterAnnotation (method.Method));
Expand Down
2 changes: 2 additions & 0 deletions src/tools/illink/src/linker/Linker.Dataflow/MethodProxy.cs
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,8 @@ internal partial ImmutableArray<GenericParameterProxy> GetGenericParameters ()
return builder.ToImmutableArray ();
}

internal partial bool IsConstructor () => Method.IsConstructor;

internal partial bool IsStatic () => Method.IsStatic;

internal partial bool HasImplicitThis () => Method.HasImplicitThis ();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
using System.Diagnostics.CodeAnalysis;
using ILLink.Shared.DataFlow;
using Mono.Cecil;
using Mono.Linker;
using Mono.Linker.Dataflow;
using TypeDefinition = Mono.Cecil.TypeDefinition;

Expand All @@ -16,7 +17,13 @@ namespace ILLink.Shared.TrimAnalysis
/// </summary>
internal partial record MethodReturnValue
{
public MethodReturnValue (TypeDefinition? staticType, MethodDefinition method, DynamicallyAccessedMemberTypes dynamicallyAccessedMemberTypes)
public static MethodReturnValue Create (MethodDefinition method, DynamicallyAccessedMemberTypes dynamicallyAccessedMemberTypes, LinkContext context)
{
var staticType = method.IsConstructor ? method.DeclaringType : method.ReturnType.ResolveToTypeDefinition (context);
return new MethodReturnValue (staticType, method, dynamicallyAccessedMemberTypes);
}

private MethodReturnValue (TypeDefinition? staticType, MethodDefinition method, DynamicallyAccessedMemberTypes dynamicallyAccessedMemberTypes)
{
StaticType = staticType == null ? null : new (staticType);
Method = method;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,6 @@ public Task GenericParameterDataFlowMarking ()
return RunTest (allowMissingWarnings: true);
}

[Fact]
public Task MakeGenericDataflowIntrinsics ()
{
return RunTest (allowMissingWarnings: true);
}

[Fact]
public Task MethodByRefParameterDataFlow ()
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,9 @@ class TestType
}

[Kept]
// MyReflectOverType is not intrinsically understood by the analysis, so
// it doesn't satisfy the PublicFields | NonPublicFields requirement.
[ExpectedWarning ("IL2075")]
public static void Test ()
{
new MyReflectOverType (typeof (TestType)).GetFields (BindingFlags.Instance | BindingFlags.Public);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,10 @@ static void AssignToThis ()
s.AssignToThisCaptured ();
}

// Analyzer warns that 'this' doesn't satisfy annotations on GetMethod,
// even though those annotations are invalid.
// https://github.com/dotnet/runtime/issues/101211
[ExpectedWarning ("IL2075", ProducedBy = Tool.Analyzer)]
static void TestAnnotationOnNonTypeMethod ()
{
var t = new NonTypeType ();
Expand Down