Skip to content

Assertions source-gen: tighten OwnGenericsAreInferable heuristic to avoid emitting dead pinned-receiver overloads #6223

Description

@thomhurst

Background

Because C# forbids partial type-argument specification, AssertionExtensionGenerator emits two extension overloads for assertion classes that have their own generic parameters on a covariant receiver (see the block comment at TUnit.Assertions.SourceGenerator/Generators/AssertionExtensionGenerator.cs:167-198, issue #5922):

  1. a covariant overload <TActual, T...> for polymorphic receivers, and
  2. a pinned-receiver overload <T...> for inference-friendly call sites.

Whether the pinned overload is needed is decided by the OwnGenericsAreInferable() heuristic in TUnit.Assertions.SourceGenerator/Generators/CovarianceHelper.cs (~lines 97-180). The heuristic is deliberately conservative — e.g. any type parameter appearing only inside a delegate/lambda or Expression<> parameter is treated as non-inferable — so it sometimes emits a pinned overload that no call site can ever prefer.

Each dead overload bloats the public API surface, IntelliSense completion lists, and overload-resolution candidate sets (longer error messages on misuse).

Task

  1. Add test coverage that characterizes which (covariant, pinned) pairs the generator currently emits across the real assertion classes.
  2. Refine the inferability analysis: model C# type-inference rules more precisely for the common shapes (value parameters, delegate parameters whose type args appear elsewhere, params arrays, nested generics).
  3. Drop the pinned overload where the covariant overload is provably always inferable.
  4. Re-verify snapshots and the public API approval tests; confirm no call site in TUnit.TestProject / assertions test suites regresses to requiring explicit type arguments.

Notes

  • Bias must remain toward correctness: a wrongly-dropped pinned overload is a user-facing compile break, a wrongly-kept one is only noise. Only drop where provable.

Part of a generics-DX review of the assertions library.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions