The source generation strategy used by PolyType today is emphatically monomorphic. In other words, it will use distinct implementations for ITypeShape<List<string>> and ITypeShape<List<object>> even though these are mostly identical, modulo the ITypeShape used for the element type. Here's an example of how ITypShape<List<string>> is generated today:
namespace PolyType.SourceGenerator
{
internal sealed partial class TypeShapeProvider_PolyType_TestCases
{
/// <summary>Gets a generated shape for the specified type.</summary>
#nullable disable annotations // Use nullable-oblivious property type
public global::PolyType.ITypeShape<global::System.Collections.Generic.List<string>> List_String => __List_String ?? __Init_Singleton(ref __List_String, __Create_List_String());
#nullable enable annotations // Use nullable-oblivious property type
private global::PolyType.ITypeShape<global::System.Collections.Generic.List<string>>? __List_String;
private global::PolyType.ITypeShape<global::System.Collections.Generic.List<string>> __Create_List_String()
{
return new global::PolyType.SourceGenModel.SourceGenEnumerableTypeShape<global::System.Collections.Generic.List<string>, string>
{
ElementTypeFactory = () => String,
ConstructionStrategy = global::PolyType.Abstractions.CollectionConstructionStrategy.Mutable,
DefaultConstructor = static (in global::PolyType.Abstractions.CollectionConstructionOptions<string> options) => new global::System.Collections.Generic.List<string>(options.Capacity ?? 0),
SupportedComparer = global::PolyType.Abstractions.CollectionComparerOptions.None,
GetEnumerable = static obj => obj,
Appender = static (ref global::System.Collections.Generic.List<string> obj, string value) => { obj.Add(value); return true; },
Rank = 1,
Provider = this,
};
}
}
}
We should update the source generator strategy such that this method is defined polymorphically -- in other words, the __Create_List_String() method should be replaced by a generic __Create_List<T>(Func<ITypeShape<T>> elementType) method that is reused across generic instantiations. This functorial approach does introduce a few challenges, namely
- It needs to account for generics that nest within the declaring type, e.g.
record Foo<T>(List<T[]> nestedCollection);
which should convert to a Create_Foo<T>(Func<ITypeShape<List<T[]>>) factory that gets invoked accordingly.
- The current strategy implicitly handles recursive type support by directly referencing the property for the corresponding element type. Care must be taken such that the new strategy account for this in a different way.
The source generation strategy used by PolyType today is emphatically monomorphic. In other words, it will use distinct implementations for
ITypeShape<List<string>>andITypeShape<List<object>>even though these are mostly identical, modulo theITypeShapeused for the element type. Here's an example of howITypShape<List<string>>is generated today:We should update the source generator strategy such that this method is defined polymorphically -- in other words, the
__Create_List_String()method should be replaced by a generic__Create_List<T>(Func<ITypeShape<T>> elementType)method that is reused across generic instantiations. This functorial approach does introduce a few challenges, namelyCreate_Foo<T>(Func<ITypeShape<List<T[]>>)factory that gets invoked accordingly.