Skip to content

Commit

Permalink
Fix scenario where generic implementation type doesn't have type fact…
Browse files Browse the repository at this point in the history
…ory initialized (#1693)
  • Loading branch information
manodasanW authored Aug 2, 2024
1 parent 8c806d3 commit 15af469
Show file tree
Hide file tree
Showing 5 changed files with 60 additions and 0 deletions.
26 changes: 26 additions & 0 deletions src/Tests/FunctionalTests/Collections/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,32 @@
return 101;
}

// Test sccenarios where the actual implementation type of the result or its RCW factory
// hasn't been initialized and the statically declared type is a derived generic interface.
var enums = instance.GetEnumIterable();
int count = 0;
foreach (var curEnum in enums)
{
count++;
}

if (count != 2)
{
return 101;
}

count = 0;
var disposableClasses = instance.GetClassIterable();
foreach (var curr in disposableClasses)
{
count++;
}

if (count != 2)
{
return 101;
}

return 100;

static bool SequencesEqual<T>(IEnumerable<T> x, params IEnumerable<T>[] list) => list.All((y) => x.SequenceEqual(y));
Expand Down
12 changes: 12 additions & 0 deletions src/Tests/TestComponentCSharp/Class.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1491,6 +1491,18 @@ namespace winrt::TestComponentCSharp::implementation
_charColl = value;
}

IIterable<EnumValue> Class::GetEnumIterable()
{
return winrt::single_threaded_vector(std::vector{ EnumValue::One, EnumValue::Two });
}

IIterable<TestComponentCSharp::CustomDisposableTest> Class::GetClassIterable()
{
TestComponentCSharp::CustomDisposableTest first;
TestComponentCSharp::CustomDisposableTest second;
return winrt::single_threaded_vector(std::vector{ first, second });
}

IBindableIterable Class::BindableIterableProperty()
{
return _bindableIterable;
Expand Down
2 changes: 2 additions & 0 deletions src/Tests/TestComponentCSharp/Class.h
Original file line number Diff line number Diff line change
Expand Up @@ -299,6 +299,8 @@ namespace winrt::TestComponentCSharp::implementation
Windows::Foundation::Collections::IIterable<int32_t> GetIntIterable();
void SetIntIterable(Windows::Foundation::Collections::IIterable<int32_t> const& value);
void SetCharIterable(Windows::Foundation::Collections::IIterable<char16_t> const& value);
Windows::Foundation::Collections::IIterable<TestComponentCSharp::EnumValue> GetEnumIterable();
Windows::Foundation::Collections::IIterable<TestComponentCSharp::CustomDisposableTest> GetClassIterable();

Microsoft::UI::Xaml::Interop::IBindableIterable BindableIterableProperty();
void BindableIterableProperty(Microsoft::UI::Xaml::Interop::IBindableIterable const& value);
Expand Down
2 changes: 2 additions & 0 deletions src/Tests/TestComponentCSharp/TestComponentCSharp.idl
Original file line number Diff line number Diff line change
Expand Up @@ -346,6 +346,8 @@ namespace TestComponentCSharp
Windows.Foundation.Collections.IIterable<Int32> GetIntIterable();
void SetIntIterable(Windows.Foundation.Collections.IIterable<Int32> value);
void SetCharIterable(Windows.Foundation.Collections.IIterable<Char> value);
Windows.Foundation.Collections.IIterable<EnumValue> GetEnumIterable();
Windows.Foundation.Collections.IIterable<CustomDisposableTest> GetClassIterable();

// Bindable
Microsoft.UI.Xaml.Interop.IBindableIterable BindableIterableProperty;
Expand Down
18 changes: 18 additions & 0 deletions src/WinRT.Runtime/ComWrappersSupport.cs
Original file line number Diff line number Diff line change
Expand Up @@ -641,6 +641,24 @@ internal static Type GetRuntimeClassForTypeCreation(IInspectable inspectable, Ty
}
}

#if NET
// On AOT, RCW type factories for generic interfaces are registered by the projection before it asks to create
// an RCW for it. But we can have scenarios where the actual implementation type is different than the statically
// known type and the implementation type's RCW factory hasn't been initialized. i.e. IList<object> and IEnumerable<object>
// where the latter is the statically known type whose RCW factory is added already but IList<object> hasn't been added.
// In this case, since the caller just needs a IEnumerable<object>, we fallback to the statically known type if IList
// isn't already added. On JIT, we can construct it at runtime.
if (!RuntimeFeature.IsDynamicCodeCompiled)
{
if (implementationType.IsInterface &&
implementationType.IsGenericType &&
!TypedObjectFactoryCacheForType.ContainsKey(implementationType))
{
return staticallyDeterminedType;
}
}
#endif

return implementationType;
}

Expand Down

0 comments on commit 15af469

Please sign in to comment.