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

Use of generic type parameters declared in [NonNullTypes(false)] context should not cause any "nullable" diagnostics on use #30214

Closed
AlekseyTs opened this issue Sep 28, 2018 · 8 comments

Comments

@AlekseyTs
Copy link
Contributor


        [Fact]
        public void ObliviousTypeParameter_01()
        {
            var source =
$@"
#pragma warning disable {(int)ErrorCode.WRN_UninitializedNonNullableField}
#pragma warning disable {(int)ErrorCode.WRN_UnreferencedField}
#pragma warning disable {(int)ErrorCode.WRN_UnreferencedFieldAssg}
#pragma warning disable {(int)ErrorCode.WRN_UnreferencedVarAssg}
"
+
@"
using System.Runtime.CompilerServices;

[NonNullTypes(false)]
class A<T1, T2, T3> where T2 : class where T3 : object
{
    T1 F1;
    T2 F2;
    T3 F3;
    B F4;

    [NonNullTypes(true)]
    void M1()
    {
        F1 = default;
        F2 = default;
        F3 = default;
        F4 = default;
    }

    [NonNullTypes(true)]
    void M2()
    {
        T1 x2 = default;
        T2 y2 = default;
        T3 z2 = default;
    }

    [NonNullTypes(true)]
    void M3()
    {
        C.Test<T1>();
        C.Test<T2>();
        C.Test<T3>();
    }

    [NonNullTypes(true)]
    void M4()
    {
        D.Test(F1);
        D.Test(F2);
        D.Test(F3);
        D.Test(F4);
    }
}

class B {}

[NonNullTypes(true)]
class C
{
    public static void Test<T>() where T : object
    {}
}

[NonNullTypes(true)]
class D
{
    public static void Test<T>(T x) where T : object
    {}
}
";
            var comp = CreateCompilation(new[] { source });
            comp.VerifyDiagnostics(
                // (20,14): warning CS8625: Cannot convert null literal to non-nullable reference or unconstrained type parameter.
                //         F1 = default;
                Diagnostic(ErrorCode.WRN_NullAsNonNullable, "default").WithLocation(20, 14),
                // (21,14): warning CS8625: Cannot convert null literal to non-nullable reference or unconstrained type parameter.
                //         F2 = default;
                Diagnostic(ErrorCode.WRN_NullAsNonNullable, "default").WithLocation(21, 14),
                // (22,14): warning CS8625: Cannot convert null literal to non-nullable reference or unconstrained type parameter.
                //         F3 = default;
                Diagnostic(ErrorCode.WRN_NullAsNonNullable, "default").WithLocation(22, 14),
                // (29,17): warning CS8625: Cannot convert null literal to non-nullable reference or unconstrained type parameter.
                //         T1 x2 = default;
                Diagnostic(ErrorCode.WRN_NullAsNonNullable, "default").WithLocation(29, 17),
                // (30,17): warning CS8625: Cannot convert null literal to non-nullable reference or unconstrained type parameter.
                //         T2 y2 = default;
                Diagnostic(ErrorCode.WRN_NullAsNonNullable, "default").WithLocation(30, 17),
                // (31,17): warning CS8625: Cannot convert null literal to non-nullable reference or unconstrained type parameter.
                //         T3 z2 = default;
                Diagnostic(ErrorCode.WRN_NullAsNonNullable, "default").WithLocation(31, 17),
                // (37,9): warning CS8631: The type 'T1' cannot be used as type parameter 'T' in the generic type or method 'C.Test<T>()'. Nullability of type argument 'T1' doesn't match constraint type 'object'.
                //         C.Test<T1>();
                Diagnostic(ErrorCode.WRN_NullabilityMismatchInTypeParameterConstraint, "C.Test<T1>").WithArguments("C.Test<T>()", "object", "T", "T1").WithLocation(37, 9),
                // (38,9): warning CS8631: The type 'T2' cannot be used as type parameter 'T' in the generic type or method 'C.Test<T>()'. Nullability of type argument 'T2' doesn't match constraint type 'object'.
                //         C.Test<T2>();
                Diagnostic(ErrorCode.WRN_NullabilityMismatchInTypeParameterConstraint, "C.Test<T2>").WithArguments("C.Test<T>()", "object", "T", "T2").WithLocation(38, 9),
                // (39,9): warning CS8631: The type 'T3' cannot be used as type parameter 'T' in the generic type or method 'C.Test<T>()'. Nullability of type argument 'T3' doesn't match constraint type 'object'.
                //         C.Test<T3>();
                Diagnostic(ErrorCode.WRN_NullabilityMismatchInTypeParameterConstraint, "C.Test<T3>").WithArguments("C.Test<T>()", "object", "T", "T3").WithLocation(39, 9)
                );
        }

Expected: No diagnostics.
Note that none is reported for references to F4 field.
Also note that none is reported in M4 method which differs from M3 only by the fact that generic type inference is involved vs. the same type arguments are provided explicitly.

@AlekseyTs
Copy link
Contributor Author

See also #29980, could related

@AlekseyTs
Copy link
Contributor Author

Here is another scenario, which I think is the same issue:

        [Fact]
        public void ConstraintsChecks_27()
        {
            var source =
@"
#pragma warning disable CS0168

public interface IA<TA> where TA : object
{
}

public class C
{}

[System.Runtime.CompilerServices.NonNullTypes(false)]
class B<TB1, TB2> where TB1 : C? where TB2 : C
{
    [System.Runtime.CompilerServices.NonNullTypes(true)]
    public void Test1()
    {
        IA<TB2> z1; // 4
    }
}
";
            var comp1 = CreateCompilation(new[] { source, NonNullTypesTrue });
            comp1.GetDiagnostics().Where(d => d.Code != (int)ErrorCode.WRN_MissingNonNullTypesContextForAnnotation).Verify(
                // (17,12): warning CS8631: The type 'TB2' cannot be used as type parameter 'TA' in the generic type or method 'IA<TA>'. Nullability of type argument 'TB2' doesn't match constraint type 'object'.
                //         IA<TB2> z1; // 4
                Diagnostic(ErrorCode.WRN_NullabilityMismatchInTypeParameterConstraint, "TB2").WithArguments("IA<TA>", "object", "TA", "TB2").WithLocation(17, 12)
            );
        }

Expected: No diagnostics

@jaredpar jaredpar added the Bug label Sep 28, 2018
@AlekseyTs
Copy link
Contributor Author

LDM confirmed today that no diagnostics should be reported for scenarios mentioned above.

@Logerfo
Copy link
Contributor

Logerfo commented Dec 5, 2018

Heads-up: this bug has been deployed with VS19preview1.

@jaredpar jaredpar added this to the 16.1.P1 milestone Jan 27, 2019
@jaredpar
Copy link
Member

jaredpar commented Feb 7, 2019

Confirmed this is a duplicate of #29980. Will make sure to not these scenarios should be included for testing when fixed.

@AlekseyTs
Copy link
Contributor Author

After taking a closer look at #29980, it appears that this issue is not a duplicate. At least it is not fixed automatically once #29980 is addressed in #34797.

@AlekseyTs AlekseyTs reopened this Apr 5, 2019
@AlekseyTs AlekseyTs self-assigned this Apr 5, 2019
@AlekseyTs
Copy link
Contributor Author

Assigning to @gafter based on offline conversation.

@gafter
Copy link
Member

gafter commented Apr 8, 2019

I think there are three issues being discussed here. For clarity I am going to split them out into separate issues so they can be treated separately.

The first is the treatment of a reference to a (unconstrainted) type parameter that appeared in a disabled context (without an annotation). Such a reference should designate an oblivious type and should be treated accordingly. That does not appear to be the treatment today. That is the issue in M1. It is being moved to #34842.

The second is the treatment of a reference to a type parameter that was declared in a disabled context but referenced in an enabled context. The compiler treats such as reference as unannotated, but this issue appears to assert that it should be treated as oblivious. That is the issue in M2 and #30214 (comment). We may need LDM confirmation that is the intent. It is being moved to #34843.

The third issue regards type inference in M3 versus M4. Both should infer the same annotation for the type argument, either unannotated, or oblivious. Which it is may depend on the outcome of the second issue, but in any case they should be the same. It is possible that the problem is that we do not check the inferred type argument against the constraints. Either way, they should be treated the same. This issue is being moved to #34844.

I am closing this umbrella issue and the underlying issues will be tracked in #34842 and #34843 and #34844.

@gafter gafter closed this as completed Apr 8, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants