Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -437,10 +437,14 @@ public sealed override IEnumerable<CombinedDependencyListEntry> GetConditionalSt
// Add conditional dependencies for interface methods the type implements. For example, if the type T implements
// interface IFoo which has a method M1, add a dependency on T.M1 dependent on IFoo.M1 being called, since it's
// possible for any IFoo object to actually be an instance of T.
DefType defTypeDefinition = (DefType)defType.GetTypeDefinition();
DefType[] defTypeRuntimeInterfaces = defType.RuntimeInterfaces;
DefType[] defTypeDefinitionRuntimeInterfaces = defTypeDefinition.RuntimeInterfaces;
Debug.Assert(defTypeDefinitionRuntimeInterfaces.Length == defTypeRuntimeInterfaces.Length);
for (int interfaceIndex = 0; interfaceIndex < defTypeRuntimeInterfaces.Length; interfaceIndex++)
{
DefType interfaceType = defTypeRuntimeInterfaces[interfaceIndex];
DefType interfaceDefinitionType = defTypeDefinitionRuntimeInterfaces[interfaceIndex];

Debug.Assert(interfaceType.IsInterface);

Expand All @@ -457,11 +461,22 @@ public sealed override IEnumerable<CombinedDependencyListEntry> GetConditionalSt
if (!isStaticInterfaceMethod && !needsDependenciesForInstanceInterfaceMethodImpls)
continue;

MethodDesc interfaceMethodDefinition = interfaceMethod;
if (interfaceType != interfaceDefinitionType)
interfaceMethodDefinition = factory.TypeSystemContext.GetMethodForInstantiatedType(interfaceMethodDefinition.GetTypicalMethodDefinition(), (InstantiatedType)interfaceDefinitionType);

MethodDesc implMethod = isStaticInterfaceMethod ?
defType.ResolveInterfaceMethodToStaticVirtualMethodOnType(interfaceMethod) :
defType.ResolveInterfaceMethodToVirtualMethodOnType(interfaceMethod);
defTypeDefinition.ResolveInterfaceMethodToStaticVirtualMethodOnType(interfaceMethodDefinition) :
defTypeDefinition.ResolveInterfaceMethodToVirtualMethodOnType(interfaceMethodDefinition);
if (implMethod != null)
{
TypeDesc implType = defType;
while (!implType.HasSameTypeDefinition(implMethod.OwningType))
implType = implType.BaseType;

if (!implType.IsTypeDefinition)
implMethod = factory.TypeSystemContext.GetMethodForInstantiatedType(implMethod.GetTypicalMethodDefinition(), (InstantiatedType)implType);

if (isStaticInterfaceMethod)
{
Debug.Assert(!implMethod.IsVirtual);
Expand Down Expand Up @@ -500,12 +515,7 @@ public sealed override IEnumerable<CombinedDependencyListEntry> GetConditionalSt
// Is the implementation provided by a default interface method?
// If so, add a dependency on the entrypoint directly since nobody else is going to do that
// (interface types have an empty vtable, modulo their generic dictionary).
TypeDesc interfaceOnDefinition = defType.GetTypeDefinition().RuntimeInterfaces[interfaceIndex];
MethodDesc interfaceMethodDefinition = interfaceMethod;
if (!interfaceType.IsTypeDefinition)
interfaceMethodDefinition = factory.TypeSystemContext.GetMethodForInstantiatedType(interfaceMethod.GetTypicalMethodDefinition(), (InstantiatedType)interfaceOnDefinition);

var resolution = defType.GetTypeDefinition().ResolveInterfaceMethodToDefaultImplementationOnType(interfaceMethodDefinition, out implMethod);
var resolution = defTypeDefinition.ResolveInterfaceMethodToDefaultImplementationOnType(interfaceMethodDefinition, out implMethod);
if (resolution == DefaultInterfaceMethodResolution.DefaultImplementation)
{
DefType providingInterfaceDefinitionType = (DefType)implMethod.OwningType;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@

<!-- Crossgen2 currently doesn't support this negative check - that should be fine as runtime behavior is undefined in the presence of invalid IL. -->
<CrossGenTest>false</CrossGenTest>

<!-- Testing TypeLoad/MissingMethod exceptions in situations that are expensive to detect -->
<NativeAotIncompatible>true</NativeAotIncompatible>
</PropertyGroup>
<PropertyGroup>
<DebugType>Full</DebugType>
Expand Down
49 changes: 49 additions & 0 deletions src/tests/nativeaot/SmokeTests/UnitTests/Interfaces.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ public static int Run()
TestDefaultInterfaceVariance.Run();
TestVariantInterfaceOptimizations.Run();
TestSharedInterfaceMethods.Run();
TestGenericAnalysis.Run();
TestCovariantReturns.Run();
TestDynamicInterfaceCastable.Run();
TestStaticInterfaceMethodsAnalysis.Run();
Expand Down Expand Up @@ -653,6 +654,54 @@ public static void Run()
}
}

class TestGenericAnalysis
{
interface IInterface
{
string Method(object p);
}

interface IInterface<T>
{
string Method(T p);
}

class C1<T> : IInterface, IInterface<T>
{
public string Method(object p) => "Method(object)";
public string Method(T p) => "Method(T)";
}

class C2<T> : IInterface, IInterface<T>
{
public string Method(object p) => "Method(object)";
public string Method(T p) => "Method(T)";
}

class C3<T> : IInterface, IInterface<T>
{
public string Method(object p) => "Method(object)";
public string Method(T p) => "Method(T)";
}

static IInterface s_c1 = new C1<object>();
static IInterface<object> s_c2 = new C2<object>();
static IInterface<object> s_c3a = new C3<object>();
static IInterface s_c3b = new C3<object>();

public static void Run()
{
if (s_c1.Method(null) != "Method(object)")
throw new Exception();
if (s_c2.Method(null) != "Method(T)")
throw new Exception();
if (s_c3a.Method(null) != "Method(T)")
throw new Exception();
if (s_c3b.Method(null) != "Method(object)")
throw new Exception();
}
}

class TestCovariantReturns
{
interface IFoo
Expand Down