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
51 changes: 51 additions & 0 deletions TUnit.AOT.Tests/GenericTypeDefinitionTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
using System;
using System.Collections.Generic;

namespace TUnit.AOT.Tests
{
/// <summary>
/// Tests to verify that non-generic types like System.Type are not treated as generic type definitions
/// </summary>
public class GenericTypeDefinitionTests
{
[Test]
public void TestMakeGenericType_WithNonGenericType_ShouldCompile()
{
// This test verifies that the AotTypeResolver doesn't generate invalid code
// when MakeGenericType is used with System.Type as an argument (not as the generic definition)

Type listGenericDefinition = typeof(List<>);
Type typeOfType = typeof(Type);

// This call should not cause the generator to treat System.Type as a generic type definition
Type listOfType = listGenericDefinition.MakeGenericType(typeOfType);

Console.WriteLine($"Successfully created: {listOfType}");

// Verify the constructed type is correct
if (listOfType != typeof(List<Type>))
{
throw new InvalidOperationException("Type construction failed");
}
}

[Test]
public void TestNonGenericType_ShouldNotBeUsedAsGenericDefinition()
{
// Verify that System.Type itself is not a generic type
Type typeOfType = typeof(Type);

if (typeOfType.IsGenericType)
{
throw new InvalidOperationException("System.Type should not be considered a generic type");
}

if (typeOfType.IsGenericTypeDefinition)
{
throw new InvalidOperationException("System.Type should not be considered a generic type definition");
}

Console.WriteLine("System.Type correctly identified as non-generic");
}
}
}
30 changes: 26 additions & 4 deletions TUnit.Core.SourceGenerator/Generators/AotTypeResolverGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -489,6 +489,12 @@ private static bool ContainsUnresolvedGenericParameters(ITypeSymbol type)

private static void GenerateGenericTypeCombination(CodeWriter writer, GenericTypeCombination combination)
{
// Ensure the generic definition is actually a generic type definition
if (!IsGenericTypeDefinition(combination.GenericDefinition))
{
return;
}

var conditions = new List<string>();

// Only generate combinations for concrete types, not generic type parameters
Expand Down Expand Up @@ -549,11 +555,15 @@ private static List<GenericTypeCombination> ExtractGenericTypeCombinations(
var genericDef = typeRef.ReferencedTypes[0];
var typeArgs = typeRef.ReferencedTypes.Skip(1).ToImmutableArray();

combinations.Add(new GenericTypeCombination
// Only create combinations for actual generic type definitions
if (IsGenericTypeDefinition(genericDef))
{
GenericDefinition = genericDef,
TypeArguments = typeArgs
});
combinations.Add(new GenericTypeCombination
{
GenericDefinition = genericDef,
TypeArguments = typeArgs
});
}
}
}

Expand Down Expand Up @@ -620,6 +630,18 @@ private static bool IsConcreteType(ITypeSymbol type)
return true;
}

private static bool IsGenericTypeDefinition(ITypeSymbol type)
{
// Check if this is a generic type with unbound type parameters (a generic type definition)
if (type is INamedTypeSymbol { IsGenericType: true } namedType)
{
// A generic type definition has type parameters (not type arguments)
return namedType.TypeParameters.Length > 0 && namedType.IsUnboundGenericType;
}

return false;
}

private sealed class TypeReferenceInfo
{
public required ImmutableArray<ITypeSymbol> ReferencedTypes { get; init; }
Expand Down
Loading