You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
TUnit0001 rejects a whole reference tuple for an explicitly closed generic parameter #7622
TUnit0001 rejects a reference-tuple data source passed to a single generic parameter even when GenerateGenericTest explicitly closes that parameter over the same tuple type. Both execution modes can bind the whole row, so the diagnostic prevents a supported test from compiling.
Expected no diagnostic: the closed parameter is Tuple<int, string>. Actual: TUnit0001 reports argument types 'int, string' do not match parameter 'T'. The analyzer spreads the row before accounting for the explicit generic type. Suppressing only that diagnostic lets the fixture compile and exercise runtime binding.
Environment
.NET SDK 10.0.403, macOS arm64. Found on PR #7620 at 939ae32; the same analyzer is on origin/main at 1a40c80. Related #7374 fixed reference-tuple spreading but this single generic parameter case remains.
Please account for the explicitly closed tuple parameter before spreading the row.
Acceptance criteria
Accept the reproduction without TUnit0001 by accounting for [GenerateGenericTest] before deciding whether to bind the reference-tuple row whole or spread it.
Add analyzer regression coverage for the matching explicit tuple type and incompatible explicit types, preserving diagnostics for unsupported bindings.
Preserve existing concrete tuple-parameter binding and multi-parameter tuple spreading; run the relevant analyzer tests.
Triage evidence
Still applicable on origin/main at e7bc52ea6f: TestDataAnalyzer.UnwrapTypes decides whole-tuple binding against the open parameter type before spreading the row. PR #7620 changes source-generator inference and does not modify the analyzer; #7374 is closed, and its tuple-spreading fix does not cover this explicit generic parameter case. This analyzer fix can proceed independently.
Additional reproduction found while validating #7620: TUnit0001 also rejects a reference-tuple row for Test<T>(Tuple<T, string> row, int extra = 5) without explicit generic types. The diagnostic spreads IEnumerable<Tuple<int, string>> into int, string instead of recognizing the whole first parameter. The same diagnostic occurs with a trailing params int[] or plain int[]. The new WholeTupleWithTrailingParametersTests fixture in #7620 narrowly suppresses TUnit0001 so runtime binding can be exercised. Please include these whole-row shapes when correcting the analyzer's binding decision.
Additional reproduction while validating #7620: IEnumerable<((int, string), int)> Rows() => [((1, "tuple"), 7)] feeding Run<T>((T, string) row, params int[] extra) triggers TUnit0001: argument types '(int, string), int' do not match '(T, string), int[]'. The source-generated invocation accepts the tuple column and packs 7. An explicit int[] second column compiles. The expanded form is separately rejected by reflection generic inference (#7624), so analyzer and runtime fixes need distinct coverage. Observed with SDK 10.0.403 on macOS arm64, PR head 475245e plus the nested-tuple regression fix.
While implementing #7629 on db8efa1, the same whole-row analyzer decision also rejects a reference tuple converted to a sole open value-tuple parameter:
dotnet test --project tests/TUnit.TestProject --framework net10.0 --treenode-filter '/*/TUnit.TestProject.Bugs._7629/*/*' reports TUnit0001: argument types int, string do not match (T, string). A narrowly scoped diagnostic suppression permits the regression to pass in both execution modes. Please include cross-family sole tuple parameters when fixing the whole-row analyzer decision. The new runtime regression keeps this diagnostic suppressed until the analyzer work lands.
The singleton form also reproduces the cross-family whole-row false positive in #7631: IEnumerable<Tuple<int>> Rows() => [Tuple.Create(7)] feeding Test<T>(ValueTuple<T> row), and IEnumerable<ValueTuple<int>> feeding Test<T>(Tuple<T> row), both report TUnit0001 (int does not match the tuple parameter). Observed on acd19d8 with the new singleton regression fixture, SDK 10.0.403, macOS arm64. After suppressing this diagnostic, both forms pass generated and reflection execution with the singleton fixes. Please cover singleton tuples alongside the existing cross-family reproduction.
Additional reproduction verified while addressing #7631: IEnumerable<(int, long)> Rows() => [(1, 2L)]; used by [Test, GenerateGenericTest(typeof(long)), MethodDataSource(nameof(Rows))] public void Run<T>(T first, T? extra) where T : struct { } reports TUnit0001 (argument types int, long versus T, T?). Both generated and reflection execution correctly infer only long after the reflection parity fix. Nullable structural inference should also be applied by the analyzer. The regression has a narrow TUnit0001 suppression under this issue.
Activity
thomhurst commentedon Nov 5, 2026
Additional reproduction found while validating #7620: TUnit0001 also rejects a reference-tuple row for
Test<T>(Tuple<T, string> row, int extra = 5)without explicit generic types. The diagnostic spreadsIEnumerable<Tuple<int, string>>intoint, stringinstead of recognizing the whole first parameter. The same diagnostic occurs with a trailingparams int[]or plainint[]. The newWholeTupleWithTrailingParametersTestsfixture in #7620 narrowly suppresses TUnit0001 so runtime binding can be exercised. Please include these whole-row shapes when correcting the analyzer's binding decision.thomhurst commentedon Nov 5, 2026
Additional reproduction while validating #7620:
IEnumerable<((int, string), int)> Rows() => [((1, "tuple"), 7)]feedingRun<T>((T, string) row, params int[] extra)triggers TUnit0001: argument types '(int, string), int' do not match '(T, string), int[]'. The source-generated invocation accepts the tuple column and packs 7. An explicit int[] second column compiles. The expanded form is separately rejected by reflection generic inference (#7624), so analyzer and runtime fixes need distinct coverage. Observed with SDK 10.0.403 on macOS arm64, PR head 475245e plus the nested-tuple regression fix.thomhurst commentedon Nov 5, 2026
While implementing #7629 on db8efa1, the same whole-row analyzer decision also rejects a reference tuple converted to a sole open value-tuple parameter:
dotnet test --project tests/TUnit.TestProject --framework net10.0 --treenode-filter '/*/TUnit.TestProject.Bugs._7629/*/*'reports TUnit0001: argument typesint, stringdo not match(T, string). A narrowly scoped diagnostic suppression permits the regression to pass in both execution modes. Please include cross-family sole tuple parameters when fixing the whole-row analyzer decision. The new runtime regression keeps this diagnostic suppressed until the analyzer work lands.thomhurst commentedon Nov 5, 2026
The singleton form also reproduces the cross-family whole-row false positive in #7631:
IEnumerable<Tuple<int>> Rows() => [Tuple.Create(7)]feedingTest<T>(ValueTuple<T> row), andIEnumerable<ValueTuple<int>>feedingTest<T>(Tuple<T> row), both report TUnit0001 (intdoes not match the tuple parameter). Observed on acd19d8 with the new singleton regression fixture, SDK 10.0.403, macOS arm64. After suppressing this diagnostic, both forms pass generated and reflection execution with the singleton fixes. Please cover singleton tuples alongside the existing cross-family reproduction.thomhurst commentedon Nov 5, 2026
Additional reproduction verified while addressing #7631:
IEnumerable<(int, long)> Rows() => [(1, 2L)];used by[Test, GenerateGenericTest(typeof(long)), MethodDataSource(nameof(Rows))] public void Run<T>(T first, T? extra) where T : struct { }reports TUnit0001 (argument typesint, longversusT, T?). Both generated and reflection execution correctly infer only long after the reflection parity fix. Nullable structural inference should also be applied by the analyzer. The regression has a narrow TUnit0001 suppression under this issue.