Skip to content

ValidationsGenerator crashes on generic type parameters (ITypeParameterSymbol) #65418

@ANcpLua

Description

@ANcpLua

Summary

The ValidationsGenerator source generator crashes when endpoint handler methods use generic type parameters (e.g., TRequest from a generic MapCommand<TRequest>() extension method). The generator emits typeof(TRequest) which is not valid C# in the generated code.

Root Cause

TryExtractValidatableType in ValidationsGenerator.TypesParser.cs does not handle ITypeParameterSymbol. When a type parameter reaches the DeclaredAccessibility check, it has Accessibility.NotApplicable, which silently falls through. However, if the type parameter has constraints pointing to concrete validatable types, those types' properties may include the type parameter itself (e.g., CRTP pattern RequestBase<TSelf>), causing typeof(TSelf) to be emitted — which is not valid C#.

Two distinct issues:

  1. Type parameters are silently skipped — generic endpoint extensions like MapCommand<TRequest>(...) where TRequest : IValidatable never discover the concrete validatable types reachable through constraints.

  2. Type parameters leak into emitted code — patterns like record CreateOrder<TSelf> or CRTP RequestBase<TSelf> where TSelf : RequestBase<TSelf> cause typeof(TSelf) to appear in the generated ValidatableInfoResolver, producing a compilation error.

Reproduction

// Extension method using generic type parameter with constraint
public static class EndpointExtensions
{
    public static RouteHandlerBuilder MapCommand<TRequest>(
        this IEndpointRouteBuilder endpoints,
        string pattern,
        Func<TRequest, CancellationToken, Task<IResult>> handler)
        where TRequest : IValidatable
    {
        return endpoints.MapPost(pattern, handler);
    }
}

// Model with validation attributes
public class CreateOrderRequest : IValidatable
{
    [Required]
    public string ProductName { get; set; }
}

// Usage - generator should discover CreateOrderRequest through TRequest constraint
app.MapCommand<CreateOrderRequest>("/orders", async (req, ct) => Results.Ok());

Expected Behavior

The generator should:

  1. Recognize ITypeParameterSymbol and walk its constraint types to discover concrete validatable types
  2. Never emit typeof(T) where T is an unresolved type parameter

Actual Behavior

The generator either:

  • Silently skips the type parameter, missing validation metadata for constrained types
  • Crashes with CS0246 / CS0103 when a type parameter leaks into typeof() expressions in generated code

Proposed Fix

Handle ITypeParameterSymbol in TryExtractValidatableType by:

  1. Adding it to visitedTypes before processing (prevents infinite recursion from circular constraints like where T : IEnumerable<T>)
  2. Walking ConstraintTypes to discover concrete validatable types
  3. Adding a ContainsTypeParameter guard to skip properties whose type contains unresolved type parameters anywhere in the type tree (T, List<T>, T[], Nullable<T>)

PR incoming.

Metadata

Metadata

Assignees

No one assigned

    Labels

    area-minimalIncludes minimal APIs, endpoint filters, parameter binding, request delegate generator etc

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions