Fix return type equivalency checking - #977
Closed
JMolenkamp wants to merge 2 commits into
Closed
Conversation
dtchepak
approved these changes
Aug 8, 2026
dtchepak
left a comment
Member
There was a problem hiding this comment.
Thanks @JMolenkamp !
@Romfos this looks ok to me, can you please take a look as well when you get a chance?
Comment on lines
+116
to
+119
| // Exclude the assignable check for generic arguments, generic types generally are not equivalent when a generic argument is not | ||
| // exactly the same, even though the types themselves may be assignable. | ||
| // See https://github.com/nsubstitute/NSubstitute/issues/974. | ||
| && TypesAreAllEquivalent([a.ReturnType], [b.ReturnType], AreAssignableInclusionType.ExcludeGenericArguments) |
Member
There was a problem hiding this comment.
question: do you know if there needs to be any additional handling for generics with co/contravariance?
Comment on lines
+186
to
+200
| [Test] | ||
| public void Returns_works_with_mismatching_generic_return_types() | ||
| { | ||
| ISomethingWithGenerics something = Substitute.For<ISomethingWithGenerics>(); | ||
|
|
||
| something | ||
| .SomeFunction(Arg.Any<ICloneable>()) | ||
| .Returns(Substitute.For<ICollection<ICloneable>>()); | ||
|
|
||
| something | ||
| .SomeFunction(Arg.Any<string>()) | ||
| .Returns(Substitute.For<ICollection<string>>()); | ||
| } | ||
|
|
||
|
|
Member
There was a problem hiding this comment.
suggestion: might be worth adding the specific case from #974 as well:
[Test]
public void Issue974()
{
var sub = Substitute.For<ISender>();
sub.Send(Arg.Any<NonGenericRequest>()).Returns(Substitute.For<IResult>());
sub.Send(Arg.Any<GenericRequest>()).Returns(Substitute.For<IResult<int>>());
sub.Send(new NonGenericRequest());
sub.Send(new GenericRequest());
}
public interface IResult { }
public interface IResult<T> : IResult { }
public interface IRequest<TResponse> { }
public class NonGenericRequest : IRequest<IResult> { }
public class GenericRequest : IRequest<IResult<int>> { }
public interface ISender {
Task<TResponse> Send<TResponse>(IRequest<TResponse> request);
}
Contributor
|
@JMolenkamp Thanks a lot for your contribution! I created another PR inspired by your one which is a bit simpler. We shall publish it somewhere soon 😊 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Do not use
areAssignablewhen comparing generic argument types in an equivalency check for return types.Closes #974