Skip to content
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

Fix recurisve issue with covariant interfaces and fix IID being wrong for built-in interfaces used as generics #1297

Merged
merged 1 commit into from
Mar 14, 2023
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
6 changes: 6 additions & 0 deletions src/Tests/UnitTest/GuidTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,12 @@ public void TestGenerics()
AssertGuid<IList<Uri>>("0d82bd8d-fe62-5d67-a7b9-7886dd75bc4e");
AssertGuid<IList<AsyncActionCompletedHandler>>("5dafe591-86dc-59aa-bfda-07f5d59fc708");
AssertGuid<IList<ComposedNonBlittableStruct>>("c8477314-b257-511b-a3a1-9e4eb6385152");
AssertGuid<IList<IDisposable>>("1bfca4f6-2c4e-5174-9869-b39d35848fcc");
AssertGuid<IList<IWwwFormUrlDecoderEntry>>("2f5fb6d3-231f-57a1-9f2a-daa7e43bf075");
AssertGuid<IList<WwwFormUrlDecoderEntry>>("1d9ba3f5-b997-5a7d-82c4-7857ecbf3a42");
AssertGuid<IList<Deferral>>("a3c9b753-57ad-537f-9626-4ae5785473d4");
AssertGuid<IList<DateTimeOffset>>("94390dc5-e442-5870-88b6-007e232f902c");
AssertGuid<IList<Point>>("c0d513a9-ec4a-5a5d-b6d5-b707defdb9f7");
}
}
}
28 changes: 26 additions & 2 deletions src/Tests/UnitTest/TestComponentCSharp_Tests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2276,8 +2276,32 @@ internal class ManagedType { }
public void CCWOfListOfManagedType()
{
using var ccw = ComWrappersSupport.CreateCCWForObject(new List<ManagedType>());
using var qiResult = ccw.As(GuidGenerator.GetIID(typeof(global::System.Collections.Generic.IEnumerable<object>).GetHelperType()));
}
using var qiResult = ccw.As(GuidGenerator.GetIID(typeof(global::System.Collections.Generic.IEnumerable<object>).GetHelperType()));
}

internal class ManagedType2 : List<ManagedType2> { }

internal class ManagedType3 : List<ManagedType3>, IDisposable
{
public void Dispose()
{
}
}

[Fact]
public void CCWOfListOfManagedType2()
{
using var ccw = ComWrappersSupport.CreateCCWForObject(new ManagedType2());
var qiResult = ccw.As(GuidGenerator.GetIID(typeof(global::System.Collections.Generic.IEnumerable<object>).GetHelperType()));
}

[Fact]
public void CCWOfListOfManagedType3()
{
using var ccw = ComWrappersSupport.CreateCCWForObject(new ManagedType3());
var qiResult = ccw.As(GuidGenerator.GetIID(typeof(global::System.Collections.Generic.IEnumerable<object>).GetHelperType()));
var qiResult2 = ccw.As(GuidGenerator.GetIID(typeof(global::System.Collections.Generic.IEnumerable<IDisposable>).GetHelperType()));
}

[Fact]
public void WeakReferenceOfManagedObject()
Expand Down
2 changes: 1 addition & 1 deletion src/WinRT.Runtime/ComWrappersSupport.cs
Original file line number Diff line number Diff line change
Expand Up @@ -222,7 +222,7 @@ internal static List<ComInterfaceEntry> GetInterfaceTableEntries(
}

if (iface.IsConstructedGenericType
&& Projections.TryGetCompatibleWindowsRuntimeTypesForVariantType(iface, out var compatibleIfaces))
&& Projections.TryGetCompatibleWindowsRuntimeTypesForVariantType(iface, null, out var compatibleIfaces))
{
foreach (var compatibleIface in compatibleIfaces)
{
Expand Down
5 changes: 4 additions & 1 deletion src/WinRT.Runtime/GuidGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,10 @@ public static string GetSignature(
}
}

type = type.IsInterface ? (type.GetAuthoringMetadataType() ?? type) : type;
// For authoring interfaces, we use the metadata type to get the guid.
// For built-in system interfaces that are custom type mapped, we use the helper type to get the guid.
// For others, either the type itself or the helper type has the same guid and can be used.
type = type.IsInterface ? (type.GetAuthoringMetadataType() ?? helperType ?? type) : type;

if (type.IsGenericType)
{
Expand Down
23 changes: 19 additions & 4 deletions src/WinRT.Runtime/Projections.cs
Original file line number Diff line number Diff line change
Expand Up @@ -340,7 +340,7 @@ public static bool TryGetCompatibleWindowsRuntimeTypeForVariantType(Type type, o
return true;
}

private static HashSet<Type> GetCompatibleTypes(Type type)
private static HashSet<Type> GetCompatibleTypes(Type type, Stack<Type> typeStack)
{
HashSet<Type> compatibleTypes = new HashSet<Type>();

Expand All @@ -352,7 +352,7 @@ private static HashSet<Type> GetCompatibleTypes(Type type)
}

if (iface.IsConstructedGenericType
&& TryGetCompatibleWindowsRuntimeTypesForVariantType(iface, out var compatibleIfaces))
&& TryGetCompatibleWindowsRuntimeTypesForVariantType(iface, typeStack, out var compatibleIfaces))
{
compatibleTypes.UnionWith(compatibleIfaces);
}
Expand Down Expand Up @@ -411,7 +411,7 @@ void GetAllPossibleTypeCombinationsCore(List<Type> accum, Stack<Type> stack, IEn
}
}

internal static bool TryGetCompatibleWindowsRuntimeTypesForVariantType(Type type, out IEnumerable<Type> compatibleTypes)
internal static bool TryGetCompatibleWindowsRuntimeTypesForVariantType(Type type, Stack<Type> typeStack, out IEnumerable<Type> compatibleTypes)
{
compatibleTypes = null;
if (!type.IsConstructedGenericType)
Expand All @@ -426,6 +426,19 @@ internal static bool TryGetCompatibleWindowsRuntimeTypesForVariantType(Type type
return false;
}

if (typeStack == null)
{
typeStack = new Stack<Type>();
}
else
{
if (typeStack.Contains(type))
{
return false;
}
}
typeStack.Push(type);

var genericConstraints = definition.GetGenericArguments();
var genericArguments = type.GetGenericArguments();
List<List<Type>> compatibleTypesPerGeneric = new List<List<Type>>();
Expand All @@ -441,17 +454,19 @@ internal static bool TryGetCompatibleWindowsRuntimeTypesForVariantType(Type type
}
else if (!argumentCovariantObject)
{
typeStack.Pop();
return false;
}

if (argumentCovariantObject)
{
compatibleTypesForGeneric.AddRange(GetCompatibleTypes(genericArguments[i]));
compatibleTypesForGeneric.AddRange(GetCompatibleTypes(genericArguments[i], typeStack));
}

compatibleTypesPerGeneric.Add(compatibleTypesForGeneric);
}

typeStack.Pop();
compatibleTypes = GetAllPossibleTypeCombinations(compatibleTypesPerGeneric, definition);
return true;
}
Expand Down