-
Notifications
You must be signed in to change notification settings - Fork 10.6k
Description
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:
-
Type parameters are silently skipped — generic endpoint extensions like
MapCommand<TRequest>(...)whereTRequest : IValidatablenever discover the concrete validatable types reachable through constraints. -
Type parameters leak into emitted code — patterns like
record CreateOrder<TSelf>or CRTPRequestBase<TSelf> where TSelf : RequestBase<TSelf>causetypeof(TSelf)to appear in the generatedValidatableInfoResolver, 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:
- Recognize
ITypeParameterSymboland walk its constraint types to discover concrete validatable types - Never emit
typeof(T)whereTis an unresolved type parameter
Actual Behavior
The generator either:
- Silently skips the type parameter, missing validation metadata for constrained types
- Crashes with
CS0246/CS0103when a type parameter leaks intotypeof()expressions in generated code
Proposed Fix
Handle ITypeParameterSymbol in TryExtractValidatableType by:
- Adding it to
visitedTypesbefore processing (prevents infinite recursion from circular constraints likewhere T : IEnumerable<T>) - Walking
ConstraintTypesto discover concrete validatable types - Adding a
ContainsTypeParameterguard to skip properties whose type contains unresolved type parameters anywhere in the type tree (T,List<T>,T[],Nullable<T>)
PR incoming.