Problem Statement
Once the dual-generic emit bug (#5918) is fixed, an [AssertionExtension] class with its own generic parameter and a concrete (covariance-candidate) receiver compiles cleanly. The remaining friction is the call-site: the generated extension's signature is Matches<TActual, T>(this IAssertionSource<TActual> source, Func<T, bool> predicate, ...) where TActual : Exception, which means callers have to specify TActual explicitly when they only care about T:
Assert.That(ex).Matches<Exception, MyPayload>(p => p.IsValid);
Type inference can pick up T from the predicate argument, but it can't pick up TActual from the receiver expression alone, so the redundant Exception has to be written out at every call site.
Proposed Solution
This is a design call rather than a prescription, but the desired ergonomic end-state is: when the receiver type is concrete (the covariance-candidate branch the generator already detects), the call-site only needs to specify the class's own generic parameters. The receiver type isn't repeated.
There are a few plausible shapes for this (omit the covariant TActual and pin the receiver to IAssertionSource<TConcrete> directly; emit an additional inference-friendly overload alongside the covariant one; encode it through a constraint shape the inferencer can resolve from the receiver). Would prefer to wait on your steer about which shape fits the rest of the generator's design before opening a PR for this.
Alternatives Considered
- Live with the explicit type argument. Works, but every call site repeats the receiver type. Verbose for the most common case.
- Drop covariance support for this shape. Restores inference but loses the ability to assert against a subclass of the declared receiver.
- Workaround at the call site: wrap the assertion in a helper that fixes
TActual. Adds boilerplate that the generator could in principle absorb.
Feature Category
Assertions
How important is this feature to you?
Nice to have - would improve my experience
Additional Context
This is downstream of the dual-generic-emit fix (#5918). The emit fix is structural. Without it the generated source doesn't compile at all. This issue is purely about call-site ergonomics once the compile-time bug is gone.
Contribution
Problem Statement
Once the dual-generic emit bug (#5918) is fixed, an
[AssertionExtension]class with its own generic parameter and a concrete (covariance-candidate) receiver compiles cleanly. The remaining friction is the call-site: the generated extension's signature isMatches<TActual, T>(this IAssertionSource<TActual> source, Func<T, bool> predicate, ...) where TActual : Exception, which means callers have to specifyTActualexplicitly when they only care aboutT:Type inference can pick up
Tfrom the predicate argument, but it can't pick upTActualfrom the receiver expression alone, so the redundantExceptionhas to be written out at every call site.Proposed Solution
This is a design call rather than a prescription, but the desired ergonomic end-state is: when the receiver type is concrete (the covariance-candidate branch the generator already detects), the call-site only needs to specify the class's own generic parameters. The receiver type isn't repeated.
There are a few plausible shapes for this (omit the covariant
TActualand pin the receiver toIAssertionSource<TConcrete>directly; emit an additional inference-friendly overload alongside the covariant one; encode it through a constraint shape the inferencer can resolve from the receiver). Would prefer to wait on your steer about which shape fits the rest of the generator's design before opening a PR for this.Alternatives Considered
TActual. Adds boilerplate that the generator could in principle absorb.Feature Category
Assertions
How important is this feature to you?
Nice to have - would improve my experience
Additional Context
This is downstream of the dual-generic-emit fix (#5918). The emit fix is structural. Without it the generated source doesn't compile at all. This issue is purely about call-site ergonomics once the compile-time bug is gone.
Contribution