Skip to content

Class-level [Arguments] rows don't infer T through a T[] or List<T> constructor parameter, and the analyzer rejects them with TUnit0001 #7223

Open

Description

@thomhurst

Found while fixing a review finding on #7149.

A generic class whose constructor takes T[] (or another type built from T, such as List<T>) cannot get its type argument from a class-level [Arguments] row with a non-null value.

[Arguments<string[]>(["x"])]   // TUnit0001: Attribute argument types 'string[]' don't match method parameter types 'T[]'
public class C<T>(T[] values)
{
    [Test]
    [Arguments("a")]
    public async Task Test(T arg) { }
}

What happens (checked on the #7149 branch, net10.0):

  1. The analyzer reports TUnit0001 on the class row, although T = string makes the row valid. The same happens for [Arguments<string[]>(null)].
  2. With TUnit0001 suppressed, both modes fail Test(a) with the "no class row supplies the constructor arguments" message, because neither infers T as string from the row:
    • source generation (TestMetadataGenerator.InferTypesFromClassArgumentsAttribute) infers a class type only when the constructor parameter is exactly T;
    • reflection (ReflectionGenericTypeResolver.DetermineGenericTypeArguments) takes the value's runtime type, string[], as T, which gives C<string[]>, whose constructor takes string[][].

#7149 maps the declared type of a null [Arguments<T>(null)] class row through the constructor parameter in both modes (MatchTypeParameter), so [Arguments<string[]>(null)] on C<T>(T[] values) now infers T = string. Non-null rows still don't, so a null row and a non-null row of the same declared type infer different things.

Expected:

  • the analyzer accepts a class row whose types match the constructor after inferring T;
  • both modes infer T from a non-null row by matching the value's type against the constructor parameter type (T[] gives the element type, List<T> gives the type argument), the same way for every row.

Repro: the fixture above in tests/TUnit.TestProject, with #pragma warning disable TUnit0001 around the attribute, run with --treenode-filter "/*/<namespace>/C*/*" with and without --reflection.

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