Skip to content

fix(sourcegen): close generic methods of generic classes on every class source - #7152

Merged
thomhurst merged 3 commits into
mainfrom
fix/issue-7117-generic-method-on-generic-class
Oct 20, 2026
Merged

thomhurst merged 3 commits into
mainfrom
fix/issue-7117-generic-method-on-generic-class

Conversation

@thomhurst

Copy link
Copy Markdown
Owner

Fixes #7117

Summary

On a generic class, [GenerateGenericTest] on a generic test method produced generated code that did not compile (CS0246 for the method type parameter, or CS0411). This PR fixes that. Source-gen mode now produces the same tests as reflection mode for these shapes.

Root cause

CollectConcreteInstantiations splits each set of type arguments into class arguments and method arguments by position. Some sources supply type arguments for the method only: the method's [GenerateGenericTest], a method [Arguments] row, a typed data source, [MethodDataSource], or IInfersType<T>. Their types went through the same split, so they became the class type arguments and the method stayed open. The generated invoker then called CastHelper.Cast<TMethod>(...) or instance.Run(...) with no type arguments.

The workaround in the issue does not work either. With a class-level [GenerateGenericTest], a method [Arguments] row still closed the class over the row's type and left the method open.

Fix (generator only; TestMetadataGenerator.CollectConcreteInstantiations)

  • TryAddInstantiation skips a set of type arguments for a generic method of a generic class unless the set covers both the class and the method.
  • For a generic method of a generic class, every class source is paired with every method source, the way reflection mode closes the method on each concrete class:
    • Class-level [GenerateGenericTest] is paired with each method source that infers the method type arguments ([Arguments] row, typed data source, IInfersType<T>, [MethodDataSource]). The cartesian product with method [GenerateGenericTest] is unchanged.
    • Class [Arguments] row is paired with each of those method sources, and with each method [GenerateGenericTest] type.
  • Method data sources are processed before [GenerateGenericTest] types, in reflection mode's order. A type that a source infers runs only that source. Any other [GenerateGenericTest] type, and IInfersType<T>, runs every method data source, as on a non-generic class. For example, class row [Arguments(1)] with [GenerateGenericTest(typeof(long))] [Arguments(2)] gives Run<int>(2) and Run<long>(2) in both modes.

Reflection mode already behaved this way, so TUnit.Engine needs no change.

Tests

  • New tests/TUnit.Core.SourceGenerator.Tests/Bugs/7117/GenerateGenericTestOnMethodOfGenericClassTests.cs compiles the generated output for the issue's shape and related shapes, and asserts there are no compiler errors. Before the fix it failed with 8 CS0246/CS0411 errors.
  • New tests/TUnit.TestProject/Bugs/_7117 classes and tests/TUnit.Engine.Tests/Issue7117Tests.cs check test names and counts in both modes (6 shapes). Both modes produce the same 8 tests and all pass.
  • Run on net10.0, all passing:
    • TUnit.Core.SourceGenerator.Tests, full run: 193 passed, 1 skipped, 0 failed, and no snapshot changes.
    • TUnit.Engine.Tests filters Issue7117Tests, Issue7106Tests, Issue7092Tests, Issue7096Tests, Issue7105Tests, Issue7107Tests, Issue7121Tests, GenericConstraintValidationTests and GenericMethodWithDataSourceTests.
    • TUnit.TestProject namespaces Bugs._4431, Bugs._4440, Bugs._7092 and Bugs._7099, in source-gen and reflection modes. The counts match, and the only failure is the intentional ExpectedResult.Failure test in 4431.

…ach class source of a generic class

For a generic method of a generic class, the generator treated type arguments
from a method-only source ([GenerateGenericTest] on the method, or a method
[Arguments] row) as the class's type arguments and left the method open. The
generated invoker then named the method type parameter (CS0246) or could not
infer it (CS0411).

The generator now pairs each class source with each method source, as
reflection mode does when it closes the method on each concrete class:
class rows with the method's [GenerateGenericTest] types, and a class-level
[GenerateGenericTest] with method rows. Type arguments that cover only the
class or only the method are no longer emitted.

Fixes #7117
…generic class

Inferred method type arguments from typed data sources, [MethodDataSource]
and IInfersType<T> on a generic method of a generic class are now paired with
each class row and class-level [GenerateGenericTest], as reflection mode does.
The previous commit stopped them being emitted as class type arguments; without
this they would no longer be discovered in source-gen mode.
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 19, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-19T21:26:15.195766Z 5e9976d PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@coderabbitai

coderabbitai Bot commented Oct 19, 2026 •

Copy link
Copy Markdown

Warning

Review limit reached

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

Next included review available in 42 minutes.

Check out review usage here.

View limit details

Limit details: You’ve used all 8 included reviews currently available.

Learn how review limits work.

Review configuration:

⚙️ Run configuration
  • Configuration used: Organization UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: ffc5f4e2-5867-4b8f-9b36-843426a3aee7
📥 Commits

Reviewing files that changed from the base of the PR and between 78c9c14 and b1a7aac.

📒 Files selected for processing: 4
  • src/TUnit.Core.SourceGenerator/Generators/TestMetadataGenerator.cs
  • tests/TUnit.Core.SourceGenerator.Tests/Bugs/7117/GenerateGenericTestOnMethodOfGenericClassTests.cs
  • tests/TUnit.Engine.Tests/Issue7117Tests.cs
  • tests/TUnit.TestProject/Bugs/_7117/GenerateGenericTestOnMethodOfGenericClassTests.cs
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 5e9976d275

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/TUnit.Core.SourceGenerator/Generators/TestMetadataGenerator.cs Outdated
@greptile-apps

greptile-apps Bot commented Oct 19, 2026 •

Copy link
Copy Markdown
Contributor

RetriggerView in GreptileConfidence Score: 5/5

[Medium impact] The PR appears safe to merge; both previous findings are addressed.

Summary

Fixes generic test methods on generic classes by pairing class sources with method sources.

  • Generic test methods now close on each concrete class type.

Both previous findings are addressed. No new actionable issues were found.

Diagram

%%{init: {'theme': 'neutral'}}%%
flowchart LR
  C["Class type arguments"] --> P["Pair class and method types"]
  M["Method source types"] --> S["Replace class type parameters"]
  S --> P
  P --> V{"Constraints pass?"}
  V -->|Yes| T["Generate closed test calls"]
  V -->|No| F["Report failures for the matching rows"]
Loading

Reviews (2) · Last reviewed commit: "fix(sourcegen): close inferred method ty..." · Reviewed by Greptile

Comment thread src/TUnit.Core.SourceGenerator/Generators/TestMetadataGenerator.cs
Comment thread src/TUnit.Core.SourceGenerator/Generators/TestMetadataGenerator.cs Outdated
…er-row constraint failures

- Substitute class type parameters in method type arguments inferred from a
  [MethodDataSource] of the open class (IEnumerable<Func<(T, int)>>), so the
  generated call names the closed type instead of T (CS0246).
- A method constraint violation from a [MethodDataSource] paired with a class
  row now fails once per row it yields, and one from IInfersType<T> once per row
  of every method data source, as in reflection mode.
- Drop the typed data source pairing: InferTypesFromDataSourceAttribute never
  infers method types on a generic class, matching reflection mode, so the loop
  was dead code.
- Add TestProject shapes and engine/generator tests for these cases.
@thomhurst
thomhurst deployed to Pull Requests October 19, 2026 22:54 — with GitHub Actions Active
@thomhurst
thomhurst deployed to Pull Requests October 19, 2026 22:54 — with GitHub Actions Active
@thomhurst
thomhurst deployed to Pull Requests October 19, 2026 22:54 — with GitHub Actions Active
@thomhurst

Copy link
Copy Markdown
Owner Author

Review dispositions as of b1a7aac:

  • Greptile P1 "Generated calls keep open types": fixed. Class type parameters in inferred method types are now substituted.
  • Greptile P1 "Constraint failures lose source rows": fixed. Failures are reported once per row, for both [MethodDataSource] and IInfersType.
  • Codex P1 "typed-source inference": no divergence existed, because the generator never inferred typed sources on a generic class. I removed the dead loop and added a parity test.

The CodeRabbit comment was rate-limited and has no findings. The CI failures on 5e9976d were all cancelled runs, not test failures, so the new push re-runs them.

@github-actions

Copy link
Copy Markdown
Contributor

Review of #7152: generic method on generic class (#7117)

I found no blocking problems. I reviewed the diff only and did not build it or run any tests. The /code-review skill failed to run, so this is a manual read. The PR description says the generator tests pass, with no snapshot changes.

What I like

  • The root cause is clearly identified: method-only type-argument sources were split positionally into class arguments.
  • The guard in TryAddInstantiation is a simple invariant: a generic method on a generic class needs class args plus method args.
  • Pairing every class source with every method source matches reflection mode, so TUnit.Engine needs no change.
  • Coverage is good. A compile-the-output generator test catches the CS0246/CS0411 class of bug, which snapshot tests don't. The engine tests run both modes and check names and counts, including the constraint-violation cases.

Suggestions (non-blocking)

  1. The early return in TryAddInstantiation drops entries silently. If a later change adds a new source kind and forgets to build a full-length argument set, the test silently disappears instead of failing to compile. Consider reporting a diagnostic or asserting in debug builds for that branch.
  2. CollectConcreteInstantiations is getting heavy. It already has many flags (isClassRow, methodRow, fromGenerateGenericTest, methodViolationRowSource, methodViolationAllMethodDataSources). Two of them are now passed together. Grouping them into a small InstantiationSource record (origin, row source, violation policy) would make the pairing logic easier to read and extend. It would also make it harder to pass inconsistent combinations.
  3. The typed-data-source behaviour is deliberate but surprising. Typed data sources (DataSourceGeneratorAttribute<T>) don't infer method type args on generic classes. This matches reflection mode, and the tests cover it. A short note in the docs would help users, because Run<long>(42) rather than Run<int> is not obvious.
  4. The engine test relies on exact test-name strings such as Run<bool> twice. This is fine today, but it will break if display-name formatting changes. Asserting on counts plus generic arguments would be more robust.

Overall this is a solid, well-tested fix.

🤖 Generated with Claude Code

@thomhurst

thomhurst commented Oct 19, 2026 •

Copy link
Copy Markdown
Owner Author

Dispositions for the latest claude-review comment (on b1a7aac):

  1. Early return in TryAddInstantiation: no change. The return is not a lossy path for the inputs this PR handles: a method-only or class-only source on a generic method of a generic class is deliberately skipped there and then paired with every class source in the IsGenericType: true, IsGenericMethod: true branch, which builds full-length argument sets through CloseOverClass. A debug assertion would fire on those legitimate partial sources. Unresolvable instantiations being dropped without a diagnostic is the generator's existing behaviour (concreteInstantiations.Count == 0 just returns in GenerateTestMetadata), and Source-gen silently drops a generic test method when its type arguments cannot be inferred from the data source #7163 already tracks adding a diagnostic or a failing placeholder for it.
  2. Group the TryAddInstantiation flags into a record: not in this PR. It is a refactor of a long-standing local function with no behaviour change, and this PR is a targeted fix. Happy to do it separately if the owner wants it.
  3. Typed data sources on generic classes: I opened Typed data sources do not infer method type arguments when the test class is generic #7164 rather than documenting it here. The behaviour predates this PR and matches between modes, but the difference between generic and non-generic classes looks like a gap worth fixing, with docs as the fallback.
  4. Exact test-name assertions in Issue7117Tests: no change. The display name is the only place the engine-test results expose the concrete method type argument and the row values, which are exactly what Source generator: [GenerateGenericTest] on a method of a generic class fails to compile (CS0246) #7117 got wrong (for example Run<int>(2) against Run<long>(2)). Counts alone would not catch a wrong instantiation. Many existing engine tests assert display names the same way.

No code changes, so no new commit.

github-actions Bot pushed a commit to IntelliTect/CodingGuidelines that referenced this pull request Oct 26, 2026
Updated [TUnit.Core](https://github.com/thomhurst/TUnit) from 1.75.0 to
1.76.28.

<details>
<summary>Release notes</summary>

_Sourced from [TUnit.Core's
releases](https://github.com/thomhurst/TUnit/releases)._

## 1.76.28

<!-- Release notes generated using configuration in .github/release.yml
at v1.76.28 -->

## What's Changed
### Other Changes
* Remove legacy JSON output implementation by @​Saad-elnagar in
thomhurst/TUnit#7234
* fix(engine): drop row-scoped data sources from failed test metadata by
@​kenny-ish in thomhurst/TUnit#7079
* Merge the analyzer release tables under one New Rules section (RS2007)
by @​bfs2021 in thomhurst/TUnit#7174
* fix: release finished test instances before session end by @​thomhurst
in thomhurst/TUnit#7262
* fix: never hand out a disposed shared data-source instance by
@​thomhurst in thomhurst/TUnit#7248
### Dependencies
* chore(deps): update all non-major dependencies to 1.76.0 by
@​thomhurst in thomhurst/TUnit#7233
* chore(deps): bump follow-redirects from 1.16.0 to 1.16.1 in /docs by
@​dependabot[bot] in thomhurst/TUnit#7232
* chore(deps): bump launch-editor from 2.14.1 to 2.14.2 in /docs by
@​dependabot[bot] in thomhurst/TUnit#7231
* chore(deps): update all non-major dependencies to 1.20.1 by
@​thomhurst in thomhurst/TUnit#7235
* chore(deps): update dependency awssdk.sqs to 4.0.100.20 by @​thomhurst
in thomhurst/TUnit#7236
* chore(deps): update dependency microsoft.playwright to 1.64.0 by
@​thomhurst in thomhurst/TUnit#7237
* chore(deps): update all non-major dependencies by @​thomhurst in
thomhurst/TUnit#7238
* chore(deps): update dependency path-to-regexp to v9 by @​thomhurst in
thomhurst/TUnit#7241
* chore(deps): update all non-major dependencies by @​thomhurst in
thomhurst/TUnit#7242
* chore(deps): update dependency serialize-javascript to v7.1.3 by
@​thomhurst in thomhurst/TUnit#7243
* chore(deps): update dependency imposter to 1.0.4 by @​thomhurst in
thomhurst/TUnit#7244
* chore(deps): update dependency stackexchange.redis to 3.4.20 by
@​thomhurst in thomhurst/TUnit#7245
* chore(deps): update dependency serialize-javascript to v7.1.4 by
@​thomhurst in thomhurst/TUnit#7246
* chore(deps): update dependency imposter to 1.0.5 by @​thomhurst in
thomhurst/TUnit#7247
* chore(deps): update all non-major dependencies to 13.6.4 by
@​thomhurst in thomhurst/TUnit#7251
* chore(deps): update dependency imposter to 1.0.6 by @​thomhurst in
thomhurst/TUnit#7258
* chore(deps): bump fast-uri from 3.1.8 to 3.1.9 in /docs by
@​dependabot[bot] in thomhurst/TUnit#7253
* chore(deps): bump body-parser from 1.20.6 to 1.20.9 in /docs by
@​dependabot[bot] in thomhurst/TUnit#7252

## New Contributors
* @​Saad-elnagar made their first contribution in
thomhurst/TUnit#7234
* @​kenny-ish made their first contribution in
thomhurst/TUnit#7079
* @​bfs2021 made their first contribution in
thomhurst/TUnit#7174

**Full Changelog**:
thomhurst/TUnit@v1.76.0...v1.76.28

## 1.76.0

<!-- Release notes generated using configuration in .github/release.yml
at v1.76.0 -->

## What's Changed
### Other Changes
* chore: add OSS scanner config, threat model and SECURITY.md by
@​thomhurst in thomhurst/TUnit#7080
* fix(deps): patch MessagePack for Aspire and use per-TFM
Microsoft.Extensions.Http by @​Quattordici in
thomhurst/TUnit#7072
* fix: skip tests marked with an empty skip reason by @​thomhurst in
thomhurst/TUnit#7083
* fix(engine): report the engine mode actually selected in the banner by
@​thomhurst in thomhurst/TUnit#7085
* fix(engine): order keyed NotInParallel tests by priority, not hash
code by @​thomhurst in thomhurst/TUnit#7090
* fix: remove root causes of flaky tests and the broken Apple smoke jobs
by @​thomhurst in thomhurst/TUnit#7095
* fix(engine): run synchronous keyed NotInParallel tests concurrently by
@​thomhurst in thomhurst/TUnit#7087
* fix(sourcegen): run every [Arguments] row that infers the same generic
type by @​thomhurst in thomhurst/TUnit#7100
* fix: same filter path and display name for generic tests in both
engine modes by @​thomhurst in
thomhurst/TUnit#7110
* fix(engine): apply max parallelism cap to keyed NotInParallel tests by
@​thomhurst in thomhurst/TUnit#7084
* fix(ci): install only Chromium for Playwright and wait on dpkg lock by
@​thomhurst in thomhurst/TUnit#6994
* fix(core): keep the engine-selected execution mode when late
assemblies load by @​thomhurst in
thomhurst/TUnit#7091
* fix(engine): end fail-fast runs without crashing the test host by
@​thomhurst in thomhurst/TUnit#7115
* test: stop the AOT [EngineTest=Pass] run hitting its 5 minute budget
by @​thomhurst in thomhurst/TUnit#7125
* fix(engine): align reflection-mode data sources and hooks with
source-gen by @​thomhurst in
thomhurst/TUnit#7094
* fix(pipeline): stop skipping the NuGet package tester modules by
@​thomhurst in thomhurst/TUnit#7127
* ci: take AOT publishes and doc snippets off the Ubuntu critical path
by @​thomhurst in thomhurst/TUnit#7128
* fix(analyzers): TUnit0001 false positive for MethodDataSource on
generic type-parameter parameters by @​thomhurst in
thomhurst/TUnit#7109
* fix: report generic class constraint violations as failed tests in
both modes by @​thomhurst in
thomhurst/TUnit#7112
* ci: cut runner contention and the AOT publish off the critical path by
@​thomhurst in thomhurst/TUnit#7131
* fix(assertions): make cross-type IsEqualTo work for numeric and
nullable arguments on C# 12 by @​thomhurst in
thomhurst/TUnit#7086
* fix(engine): substitute class type arguments and array element types
in build-time constraint checks by @​thomhurst in
thomhurst/TUnit#7102
* ci: test the NuGet packages on Windows in their own job by @​thomhurst
in thomhurst/TUnit#7130
* fix(sourcegen): bind params T[] on generic test methods by @​thomhurst
in thomhurst/TUnit#7101
* fix(engine): run every [Arguments] row on generic test classes in both
modes by @​thomhurst in thomhurst/TUnit#7111
* fix(engine): use last inferred type for repeated generic parameters by
@​theluckystrike in thomhurst/TUnit#7134
* Make the test suite pass in every environment and run fully in CI by
@​Quattordici in thomhurst/TUnit#7129
* fix(assertions): skip using directive for global-namespace assertion
types by @​thomhurst in thomhurst/TUnit#7139
* fix(core): format numeric display-name arguments with the invariant
culture by @​thomhurst in thomhurst/TUnit#7138
* fix(engine): dispose data-source objects of rows that end as failed
tests by @​thomhurst in thomhurst/TUnit#7150
* Fix net472 compile gate failure in assertions source generator tests
by @​thomhurst in thomhurst/TUnit#7170
* fix(sourcegen): close generic methods of generic classes on every
class source by @​thomhurst in
thomhurst/TUnit#7152
* fix(engine): infer object for null rows on generic test methods in
reflection mode by @​thomhurst in
thomhurst/TUnit#7142
* fix(engine): report every test once on fail-fast runs by @​thomhurst
in thomhurst/TUnit#7145
* test(engine): stop whole-process budgets killing healthy scheduling
engine tests by @​thomhurst in
thomhurst/TUnit#7177
* feat(analyzers): report MethodDataSource Arguments that fit two
overloads equally (TUnit0076) by @​thomhurst in
thomhurst/TUnit#7181
* fix(sourcegen): render top-level dynamic as object so typeof compiles
by @​thomhurst in thomhurst/TUnit#7182
* fix(sourcegen): pair each GenerateGenericTest type only with its typed
ClassDataSource<T> by @​thomhurst in
thomhurst/TUnit#7188
* fix(engine): run untyped [Arguments(null)] rows on generic classes
instead of dropping them by @​thomhurst in
thomhurst/TUnit#7203
* fix(engine): report generic test classes by their generic type
definition in TRX by @​thomhurst in
thomhurst/TUnit#7200
* test(sourcegen): parse snapshot fixtures as a real build does by
@​thomhurst in thomhurst/TUnit#7189
* refactor(engine): dedupe reflection generic discovery by @​thomhurst
in thomhurst/TUnit#7183
* test: make TimeoutHelperTests deterministic under thread-pool load by
@​thomhurst in thomhurst/TUnit#7180
* fix(analyzers): accept null MethodDataSource arguments for nullable
parameters by @​thomhurst in
thomhurst/TUnit#7179
* test(assertions): make WaitsFor cancellation tests robust to slow CI
runners by @​thomhurst in thomhurst/TUnit#7176
* fix(assertions): support [AssertionFrom] with unbound generic types by
@​thomhurst in thomhurst/TUnit#7144
 ... (truncated)

Commits viewable in [compare
view](thomhurst/TUnit@v1.75.0...v1.76.28).
</details>

[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=TUnit.Core&package-manager=nuget&previous-version=1.75.0&new-version=1.76.28)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

This branch was successfully deployed

1 active deployment
Pull Requests — b1a7aac0 Deployed Oct 19, 2026 by thomhurst via modularpipeline (macos-latest) #20237
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Source generator: [GenerateGenericTest] on a method of a generic class fails to compile (CS0246)

1 participant