Nullable tracking in LINQ #4441
Replies: 2 comments 2 replies
-
I think this is definitely something that should be improved. Though it does seem to be fairly narrow, which makes me ask some questions:
|
Beta Was this translation helpful? Give feedback.
-
List<string> func3(List<string?> input)
{
// a similar but slightly different case
return input.Where(s => s != null).ToList();
} That one makes my slightly uncomfortable. I don't have a good answer to this however. I don't have a good feelling for how common this would be, and I don't have any suggestions for avoiding it as an issue! |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
Related to dotnet/roslyn#37468
Related to #3951
Several users have +1'd an issue asking for improved nullable tracking in LINQ (22 at the time of writing). I think it's a sign that we should explore whether to adjust nullable analysis to support more scenarios in this area.
This is more of a "brainstorming" document than a proposal, and I'm posting it in the hope that your feedback will help uncover the problems with it, and help us get a sense of the impact, the risk, and the cost of it.
Note that this document only considers "method-style" LINQ (not using the query syntax). The query syntax works somewhat better because its structure more closely reflects the relationship between successive lambda parameters. It's possible there are scenarios with the query syntax that we'd want to enhance at the same time, but I haven't looked closely at it.
Motivating examples
A framework for analysis
It feels like what we essentially want to do is make it so some linq operators which take predicates or otherwise perform filtering can track the "state" of the collection element across chained operations--think
Where
,Any
,All
,Except
...We could do this by making it so calls to certain well-known methods cause us to potentially introduce a slot for the collection element. For example:
We may also wish to generalize the change in conversion rules so that more kinds of collections can participate.
One potential formulation: If a type parameter
T1
is used as type argument toIEnumerable<T>
in the base clause, and the variable has not-null flow state for its collection element, a conversion from nullable to non-nullable type argument is permitted forT1
. For example:One situation where type would not be subject to the new conversion rule is when the type argument to
IEnumerable<T>
is not a type parameter from the containing type:We may also wish to also allow some usages to introduce "doubt" about the collection element and prevent its usage in some scenarios:
It feels problematic to enumerate every possible way to mutate a collection element. Just going by conventions doesn't feel adequate, especially since things can simply be mutated, particularly indirectly
I think what we will want to do is: do our best to address the greater part of users issues, but limit the analysis of conversions to when the thing is used as an
IEnumerable<T>
.Alternatively, whenever the thing is used as an
IEnumerable<T?>
, we re-introduce doubt that the collection really contains non-nullable elements.Alternatively, we could limit the lifetime of the collection element slot so that it is discarded when we finish visiting a call chain. (is that practical? and is it desirable?)
Detecting operators and their relevant behaviors
At a glance it doesn't seem like it would be useful to introduce special flow analysis attributes for every kind of behavior that can be produced by a LINQ operator. I think you'd end up with very few usages of each attribute. If we did this feature it would probably involve some special recognition of LINQ operators. There is some precedent with this with
IEquatable<T>.Equals(T)
and other well-known methods.Beta Was this translation helpful? Give feedback.
All reactions