Skip to content

Source generator: params T[] on a generic test method fails to compile (CS0246, CS1503) #7099

Closed

Description

@thomhurst

Summary

A generic test method whose last parameter is params T[] (or a plain trailing T[]) does not compile in source-generation mode once the method is closed through [GenerateGenericTest], or through type inference from another argument. The generated code reports CS0246 and CS1503, so the whole test project fails to build. This came up while working on #7094.

Repro

public class ParamsGenericTests
{
    [Test]
    [GenerateGenericTest(typeof(int))]
    [Arguments(1, 2, 3)]
    public void Explicit_Many<T>(params T[] values) { }
}

The same happens for these shapes:

  • zero arguments ([Arguments]), one argument, and many arguments
  • reference types ([GenerateGenericTest(typeof(string))], [Arguments("a", "b", "c")])
  • a leading non-generic parameter (Test<T>(string label, params T[] values))
  • an array passed as the only argument ([Arguments(new[] { 4, 5 })])
  • a plain trailing array (Test<T>(T[] values))
  • a class type parameter ([GenerateGenericTest(typeof(int))] class Foo<T> { [Test, Arguments(1, 2)] void Test(params T[] values) })
  • inference from a leading argument ([Arguments(1, 2, 3)] Test<T>(T first, params T[] rest))

Errors

MyTests_ParamsGenericTests_Explicit_Many__T__.g.cs(24,121): error CS0246: The type or namespace name 'T' could not be found (are you missing a using directive or an assembly reference?)
MyTests_ParamsGenericTests_Explicit_Many__T__.g.cs(34,84): error CS0246: The type or namespace name 'T' could not be found (are you missing a using directive or an assembly reference?)
MyTests_ParamsGenericTests_Explicit_Many__T__.g.cs(34,41): error CS1503: Argument 1: cannot convert from 'T[]' to 'int'

The generated code that triggers them:

// parameter metadata (line 24)
global::TUnit.Core.ParameterMetadataFactory.Create(typeof(object), "values", new global::TUnit.Core.ConcreteType(typeof(T[])), false)

// invoker for the closed Explicit_Many<int> (line 34)
instance.Explicit_Many<int>(global::TUnit.Core.Helpers.CastHelper.Cast<T[]>(args[0]));

Root cause

There are three gaps in TUnit.Core.SourceGenerator:

  1. CodeGenerationHelpers.GenerateTypeInfo handles type parameters (T) and constructed generics (List<T>), but not arrays of a type parameter. T[] falls through to ConcreteType(typeof(T[])), and T is not in scope in the generated class.
  2. SubstituteTypeParameters, which the concrete-instantiation invoker uses, does not recurse into IArrayTypeSymbol. T[] stays T[] instead of becoming int[].
  3. EmitConcreteInvokeBody (the invoker for [GenerateGenericTest] and inferred instantiations) casts each argument to its declared parameter type by position. It never applies the trailing-array binding that non-generic methods get through TupleArgumentHelper.GenerateArgumentAccessWithParams (packing the remaining row values, Array.Empty<T>() for zero, and ToTrailingArray for a single value). So even with (2) fixed, [Arguments(1, 2, 3)] would pass only args[0].

Reflection mode

On current main, with EnableTUnitSourceGeneration=false and --reflection:

  • Every [GenerateGenericTest] shape above passes, including the class-type-parameter case.
  • Inferred instantiations fail at test build time: [Arguments(1, 2, 3)] Test<T>(T first, params T[] rest) reports GenericTypeResolutionException: Type mismatch: Cannot use argument of type 'Int32' for parameter of type 'T[]'. TestGenericTypeResolver.ResolveMethodGenericArguments maps each row value positionally against the declared parameter types, so the trailing values meet T[].
  • [Arguments(1, 2, 3)] Test<T>(params T[] values), with no other parameter to infer from, fails the same way in reflection mode. In source-gen mode it generates no test at all, with no diagnostic, because InferTypesFromArgumentsAttribute only infers from parameters whose type is a bare type parameter.

The two inference gaps are separate from this compile error and are left for a follow-up.

Activity

  1. thomhurst commented on Oct 17, 2026

    @thomhurst
    OwnerAuthor

    PR #7101 (fe482c9) also fixes inference from a leading argument in reflection mode, so Test<T>(T first, params T[] rest) now works in both modes. Both modes also infer T from a lone array value. Still open: inferring T only from loose params values, as in [Arguments(1, 2, 3)] Test<T>(params T[] values). Reflection mode needs a change to the invoker in ReflectionTestDataCollector.cs, which defaults an unmapped T to object. Source-gen still emits no test for this case.

  2. added 7 commits that reference this issue on Oct 18, 2026
    d58bcbf
    6285f9b
    a4ca664
    2862c46
    6c9c5d1
    a2f33f5
    ae74298
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions