roslyn: CS8619 False positive on Task instantiated with different nullability
Version Used
Visual Studio 2019 (16.5.0 Preview 1.0)
Steps to Reproduce
using System.Threading.Tasks;
#nullable enable
public class C {
public Task<(bool Result, string? Extras)> M() {
return Task.FromResult((true, ""));
}
}
Expected Behavior
Since string
is a valid string?
, no warning should be presented.
Actual Behavior
Warning CS8619: Nullability of reference types in value of type ‘Task<(bool, string)>’ doesn’t match target type ‘Task<(bool Result, string? Extras)>’.
About this issue
- Original URL
- State: open
- Created 4 years ago
- Reactions: 3
- Comments: 18 (11 by maintainers)
@inf9144
People can engage however they want (within the rules) 😃
If you see this as variance issue it would be a problem to just declare in or out on the generic type parameters like you can do on interfaces, because this would not be what you would like to express. You dont want the class working/castable/assignable for
T<XBase>
orT<XDerived>
. This would also come with the cost that every contravariance or covariance in C# brings - you cannot use the generic type in all situations on the generic class/struct anymore. (Return Values, Method Parameters, …). Can you understand why i dont match this problem to type variance but to nullability? If this is a variance problem, you would need to have the ability to explicitly define the variance in means of nullability. So having an invariant type which is nullable co-/contravariant. Only then you could relax those restrictions that normally come with covariance/contravariance in general, because (yes on runtime level) you can be sure you have the very same types (in case of reference types).@Logerfo You are welcome to take part in this conversation instead of just putting thumbs down emojis on someones post 😉
//EDIT: And it would not be nice to only solve this for Task<T> / ValueTask<T> because this hits also custom structs that have those generics and behave like ValueHolder, Optionals or …
Sorry, variance is very significant. Just because something is assignable doesn’t mean you can replace one with the other. For example, all strings are objects. But that doesn’t make all lists of strings into lists of objects.
Correct, and that will always be the case (and is unrelated to this issue). Those types are identical as far as the runtime is concerned. So they literally cannot both exist at the same time.
Anything new here? Got my self in this situation, not only with
Task<T>
but also withMyType<T>
,Have a method and cant make an overload for this because string is a reference type and those types are identical:
void Xyz<TFrom>(Expression<Func<TFrom, MyType<string>>> param);
void Xyz<TFrom>(Expression<Func<TFrom, MyType<string?>>> param);
My hacky workaround would be something like
This should really be fixed because it affects all generic types and their usage as parameters… string is fullfilling string? so i cant get why this warning appears on the direction of notnull to nullable assignements. It’s a bug in my eye, no matter if we talk about variance here.
https://github.com/dotnet/csharplang/issues/3950
Woudl be great ot have an attribute to allow other types to play here IMO 😃
This is currently by-design, as the type parameter of
Task
is invariant. That said, LDM discussed this today and we’re going to look into adding some special treatment forTask<T>
and possiblyValueTask<T>
to treat them as covariant.Relates to https://github.com/dotnet/roslyn/issues/40759 FYI @cston