Description
Mock.Of<T>() over a generic interface whose type parameter has an unmanaged constraint produces generated code that does not compile. The generator emits where T : struct, unmanaged on the mock classes, but C# forbids combining struct and unmanaged (CS0449). Because the constraint clause is invalid, T is then not recognized as satisfying the interface's unmanaged constraint, which cascades into ~30 CS8377 errors across the generated files.
Minimal reproduction
public interface ISnapshotSource<T> where T : unmanaged
{
void Fill(ref T snapshot);
}
public sealed class ReproTests
{
[Test]
public async Task Mock_OfUnmanagedConstrainedInterface_Compiles()
{
var sourceMock = Mock.Of<ISnapshotSource<int>>();
await Assert.That(sourceMock).IsNotNull();
}
}
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<IsTestProject>true</IsTestProject>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="TUnit" Version="1.61.29" />
<PackageReference Include="TUnit.Mocks" Version="1.61.29" />
</ItemGroup>
</Project>
Actual behavior
dotnet build fails with 33 errors in the generated sources. The generated mock class is declared as:
public sealed class ISnapshotSource_T_Mock<T> : global::TUnit.Mocks.Mock<global::ISnapshotSource<T>>, global::ISnapshotSource<T> where T : struct, unmanaged
Representative errors:
ISnapshotSource_T__Mock.g.cs(5,148): error CS0449: The 'class', 'struct', 'unmanaged', 'notnull', and 'default' constraints cannot be combined or duplicated, and must be specified first in the constraints list.
ISnapshotSource_T__Mock.g.cs(5,21): error CS8377: The type 'T' must be a non-nullable value type, along with all fields at any level of nesting, in order to use it as parameter 'T' in the generic type or method 'ISnapshotSource<T>'
The same pattern (where T : struct, unmanaged, ...) is emitted in ISnapshotSource_T__MockImplFactory.g.cs and fails the same way.
Expected behavior
The generated mock compiles, emitting where T : unmanaged only (the unmanaged constraint already implies a non-nullable value type, so struct must be omitted).
Environment
- TUnit / TUnit.Mocks 1.61.29
- .NET SDK 10.0.302,
net10.0
- macOS (arm64), also reproduced in a larger solution with
where T : unmanaged, ISomeInterface
Description
Mock.Of<T>()over a generic interface whose type parameter has anunmanagedconstraint produces generated code that does not compile. The generator emitswhere T : struct, unmanagedon the mock classes, but C# forbids combiningstructandunmanaged(CS0449). Because the constraint clause is invalid,Tis then not recognized as satisfying the interface'sunmanagedconstraint, which cascades into ~30 CS8377 errors across the generated files.Minimal reproduction
Actual behavior
dotnet buildfails with 33 errors in the generated sources. The generated mock class is declared as:Representative errors:
The same pattern (
where T : struct, unmanaged, ...) is emitted inISnapshotSource_T__MockImplFactory.g.csand fails the same way.Expected behavior
The generated mock compiles, emitting
where T : unmanagedonly (theunmanagedconstraint already implies a non-nullable value type, sostructmust be omitted).Environment
net10.0where T : unmanaged, ISomeInterface