Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Proposal: Improve analysis of [MaybeNull]T values #2946

Open
cston opened this issue Nov 8, 2019 · 3 comments
Open

Proposal: Improve analysis of [MaybeNull]T values #2946

cston opened this issue Nov 8, 2019 · 3 comments
Assignees
Labels
Implemented Needs ECMA Spec This feature has been implemented in C#, but still needs to be merged into the ECMA specification Proposal champion Proposal
Milestone

Comments

@cston
Copy link
Member

cston commented Nov 8, 2019

Improve analysis of [MaybeNull]T values by adding a third possible flow state.

Additional flow state

A third flow state is added that represents maybe null even when substituted with a non-nullable reference type. The additional state applies only to values of type parameters that are not constrained not nullable. Flow analysis will use two bits for each tracked value.

internal enum NullableFlowState : byte
{
    /// <summary>
    /// Not null.
    /// </summary>
    NotNull = 0b00,

    /// <summary>
    /// Maybe null (type is nullable).
    /// </summary>
    MaybeNull = 0b01,

    /// <summary>
    /// Maybe null (type may be not nullable).
    /// </summary>
    MaybeDefault = 0b11,
}

The merging rules are unchanged: Join() uses bitwise | and Meet() uses bitwise &.

Member signatures affect method analysis

Attributes on members, including attributes on the containing method signature, are considered when analyzing the method body.

static T F1<T>(IEnumerable<T> e)
{
    return e.FirstOrDefault(); // warning: returning [MaybeNull]T
}

[return: MaybeNull] static T F2<T>(IEnumerable<T> e)
{
    return e.FirstOrDefault(); // ok
}

No W warnings

Locals cannot use [MaybeNull] and neither can explicit casts. Because of that limitation, W warnings are not reported for unconstrained types.

static T Default<T>()
{
    T t = default(T); // ok: T t
    return t;         // warning: returning [MaybeNull]T
}

static U Cast<T, U>([AllowNull]T t) where U : T
{
    var u = (U)t; // ok: U u
    return u;     // warning: returning [MaybeNull]U
}

Warnings are produced for compound types though:

T[] array = new[] { default(T) }; // warning: default(T) nullability does not match T

List<T> list = MakeList(default(T)); // warning: default(T) nullability does not match T arg

No warning for null expressions

Expressions (of a type parameter type not constrained to not nullable) that may produce null values are treated as MaybeDefault. Warnings are not reported for the expressions directly.

static T Default<T>()
{
    T t = default(T); // ok
    return t;         // warning: returning [MaybeNull]T
}

static U As<T, U>(T t) where U : class?
{
    U u = t as U; // ok
    return u;     // warning: returning [MaybeNull]U
}

static T ConditionalAccess<T>(IEnumerable<T>? e) where T : class?
{
    T t = e?.First(); // ok
    return t;         // warning: returning [MaybeNull]T
}

Type inference

[MaybeNull] is ignored in method type inference.

T t = Identity(default(T)); // warning: default(T) nullability does not match T arg

Best type algorithm relies on the merging of states to choose [MaybeNull]T over T.

static T Choose<T, U>(bool b, T t, [MaybeNull]U u) where U : T
{
    return b ? t : u; // warning: returning [MaybeNull]T
}

LDM Notes

@huoyaoyuan
Copy link
Member

There should be a clearified state of "if reference type then nullable", in both source and analysis, aka <[MaybeNull]T>.

@orthoxerox
Copy link

New notes:

https://github.com/dotnet/csharplang/blob/master/meetings/2019/LDM-2019-11-25.md

@qrli
Copy link

qrli commented Dec 2, 2019

The above design note contains important info on nullability of unconstrained generic T, which is IMO important for the community to read, as many have opinions on this matter. However, the issue title is a bit subtle, which reads like an internal issue for the roslyn team.

Maybe it is better to create a separate issue for the design note and link back?

@jcouv jcouv self-assigned this Mar 23, 2020
@jcouv jcouv added this to the 8.0 milestone Mar 23, 2020
@333fred 333fred added the Implemented Needs ECMA Spec This feature has been implemented in C#, but still needs to be merged into the ECMA specification label Oct 16, 2020
@dotnet dotnet locked and limited conversation to collaborators Nov 19, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Implemented Needs ECMA Spec This feature has been implemented in C#, but still needs to be merged into the ECMA specification Proposal champion Proposal
Projects
None yet
Development

No branches or pull requests

6 participants