File: Symbols\Source\NullablePublicAPITests.cs
Web Access
Project: src\src\Compilers\CSharp\Test\Symbol\Microsoft.CodeAnalysis.CSharp.Symbol.UnitTests.csproj (Microsoft.CodeAnalysis.CSharp.Symbol.UnitTests)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
 
#pragma warning disable RSEXPERIMENTAL001 // Internal usage of experimental API
#nullable disable
 
using System;
using System.Collections.Immutable;
using System.Linq;
using System.Threading;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.CSharp.Test.Utilities;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.Test.Utilities;
using Roslyn.Test.Utilities;
using Roslyn.Utilities;
using Xunit;
using PublicNullableAnnotation = Microsoft.CodeAnalysis.NullableAnnotation;
using PublicNullableFlowState = Microsoft.CodeAnalysis.NullableFlowState;
 
namespace Microsoft.CodeAnalysis.CSharp.UnitTests
{
    [CompilerTrait(CompilerFeature.NullableReferenceTypes)]
    public class NullablePublicAPITests : CSharpTestBase
    {
        [Fact]
        public void TestArrayNullability()
        {
            var source = @"
class C
{
    void M(C?[] arr1)
    {
        C[] arr2 = (C[])arr1;
        arr1[0].ToString();
        arr2[0].ToString();
    }
}
";
 
            var comp = CreateCompilation(source, options: WithNullableEnable());
            comp.VerifyDiagnostics(
                // (6,20): warning CS8619: Nullability of reference types in value of type 'C?[]' doesn't match target type 'C[]'.
                //         C[] arr2 = (C[])arr1;
                Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "(C[])arr1").WithArguments("C?[]", "C[]").WithLocation(6, 20),
                // (7,9): warning CS8602: Possible dereference of a null reference.
                //         arr1[0].ToString();
                Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "arr1[0]").WithLocation(7, 9));
 
            var syntaxTree = comp.SyntaxTrees[0];
            var root = syntaxTree.GetRoot();
            var model = comp.GetSemanticModel(syntaxTree);
 
            var arrayAccesses = root.DescendantNodes().OfType<ElementAccessExpressionSyntax>().ToList();
            var arrayTypes = arrayAccesses.Select(arr => model.GetTypeInfoAndVerifyIOperation(arr.Expression).Type).Cast<IArrayTypeSymbol>().ToList();
 
            Assert.Equal(PublicNullableAnnotation.Annotated, arrayTypes[0].ElementNullableAnnotation);
            Assert.Equal(PublicNullableAnnotation.Annotated, arrayTypes[0].ElementType.NullableAnnotation);
            Assert.Equal(PublicNullableAnnotation.NotAnnotated, arrayTypes[1].ElementNullableAnnotation);
            Assert.Equal(PublicNullableAnnotation.NotAnnotated, arrayTypes[1].ElementType.NullableAnnotation);
        }
 
        [Fact]
        public void TestTypeArgumentNullability()
        {
            var source = @"
class B<T> {}
class C
{
    B<T> M<T>(T t) where T : C? { return default!; }
 
    void M1(C? c)
    {
        M(new C());
        M(c);
        if (c == null) return;
        M(c);
    }
}";
 
            var comp = CreateCompilation(source, options: WithNullableEnable());
            comp.VerifyDiagnostics();
 
            var syntaxTree = comp.SyntaxTrees[0];
            var root = syntaxTree.GetRoot();
            var model = comp.GetSemanticModel(syntaxTree);
 
            var invocations = root.DescendantNodes().OfType<InvocationExpressionSyntax>().ToList();
            var expressionTypes = invocations.Select(inv => model.GetTypeInfoAndVerifyIOperation(inv).Type).Cast<INamedTypeSymbol>().ToList();
 
            Assert.Equal(PublicNullableAnnotation.NotAnnotated, expressionTypes[0].TypeArgumentNullableAnnotations.Single());
            Assert.Equal(PublicNullableAnnotation.NotAnnotated, expressionTypes[0].TypeArgumentNullableAnnotations().Single());
            Assert.Equal(PublicNullableAnnotation.Annotated, expressionTypes[1].TypeArgumentNullableAnnotations.Single());
            Assert.Equal(PublicNullableAnnotation.Annotated, expressionTypes[1].TypeArgumentNullableAnnotations().Single());
            Assert.Equal(PublicNullableAnnotation.NotAnnotated, expressionTypes[2].TypeArgumentNullableAnnotations.Single());
            Assert.Equal(PublicNullableAnnotation.NotAnnotated, expressionTypes[2].TypeArgumentNullableAnnotations().Single());
        }
 
        [Fact]
        [WorkItem(34412, "https://github.com/dotnet/roslyn/issues/34412")]
        public void FieldDeclarations()
        {
            var source = @"
public struct S {}
public class C
{
#nullable enable
    public C c1 = new C();
    public C? c2 = null;
    public S s1 = default;
    public S? s2 = null;
 
#nullable disable
    public C c3 = null;
    public C? c4 = null;
    public S s3 = default;
    public S? s4 = null;
}
";
            VerifyAcrossCompilations(
                source,
                new[]
                {
                    // (13,13): warning CS8632: The annotation for nullable reference types should only be used in code within a '#nullable' context.
                    //     public C? c4 = null;
                    Diagnostic(ErrorCode.WRN_MissingNonNullTypesContextForAnnotation, "?").WithLocation(13, 13)
                },
                new DiagnosticDescription[]
                {
                    // (5,2): error CS8652: The feature 'nullable reference types' is not available in C# 7.3. Please use language version 8.0 or greater.
                    // #nullable enable
                    Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7_3, "nullable").WithArguments("nullable reference types", "8.0").WithLocation(5, 2),
                    // (7,13): error CS8652: The feature 'nullable reference types' is not available in C# 7.3. Please use language version 8.0 or greater.
                    //     public C? c2 = null;
                    Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7_3, "?").WithArguments("nullable reference types", "8.0").WithLocation(7, 13),
                    // (11,2): error CS8652: The feature 'nullable reference types' is not available in C# 7.3. Please use language version 8.0 or greater.
                    // #nullable disable
                    Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7_3, "nullable").WithArguments("nullable reference types", "8.0").WithLocation(11, 2),
                    // (13,13): error CS8652: The feature 'nullable reference types' is not available in C# 7.3. Please use language version 8.0 or greater.
                    //     public C? c4 = null;
                    Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7_3, "?").WithArguments("nullable reference types", "8.0").WithLocation(13, 13)
                },
                comp =>
                {
                    var c = ((Compilation)comp).GetTypeByMetadataName("C");
                    return c.GetMembers().OfType<IFieldSymbol>().ToArray();
                },
                member =>
                {
                    var result = member.Type.NullableAnnotation;
                    Assert.Equal(result, member.NullableAnnotation);
                    return member.Type.NullableAnnotation;
                },
                testMetadata: true,
                PublicNullableAnnotation.NotAnnotated,
                PublicNullableAnnotation.Annotated,
                PublicNullableAnnotation.NotAnnotated,
                PublicNullableAnnotation.Annotated,
                PublicNullableAnnotation.None,
                PublicNullableAnnotation.Annotated,
                PublicNullableAnnotation.NotAnnotated,
                PublicNullableAnnotation.Annotated);
        }
 
        [Fact]
        [WorkItem(34412, "https://github.com/dotnet/roslyn/issues/34412")]
        public void PropertyDeclarations()
        {
            var source = @"
public struct S {}
public class C
{
#nullable enable
    public C C1 { get; set; } = new C();
    public C? C2 { get; set; }
    public S S1 { get; set; }
    public S? S2 { get; set; }
 
#nullable disable
    public C C3 { get; set; }
    public C? C4 { get; set; }
    public S S3 { get; set; }
    public S? S4 { get; set; }
}
";
 
            VerifyAcrossCompilations(
                source,
                new[]
                {
                    // (13,13): warning CS8632: The annotation for nullable reference types should only be used in code within a '#nullable' context.
                    //     public C? C4 { get; set; }
                    Diagnostic(ErrorCode.WRN_MissingNonNullTypesContextForAnnotation, "?").WithLocation(13, 13)
                },
                new[]
                {
                    // (5,2): error CS8652: The feature 'nullable reference types' is not available in C# 7.3. Please use language version 8.0 or greater.
                    // #nullable enable
                    Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7_3, "nullable").WithArguments("nullable reference types", "8.0").WithLocation(5, 2),
                    // (7,13): error CS8652: The feature 'nullable reference types' is not available in C# 7.3. Please use language version 8.0 or greater.
                    //     public C? C2 { get; set; }
                    Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7_3, "?").WithArguments("nullable reference types", "8.0").WithLocation(7, 13),
                    // (11,2): error CS8652: The feature 'nullable reference types' is not available in C# 7.3. Please use language version 8.0 or greater.
                    // #nullable disable
                    Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7_3, "nullable").WithArguments("nullable reference types", "8.0").WithLocation(11, 2),
                    // (13,13): error CS8652: The feature 'nullable reference types' is not available in C# 7.3. Please use language version 8.0 or greater.
                    //     public C? C4 { get; set; }
                    Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7_3, "?").WithArguments("nullable reference types", "8.0").WithLocation(13, 13)
                },
                comp =>
                {
                    var c = ((Compilation)comp).GetTypeByMetadataName("C");
                    return c.GetMembers().OfType<IPropertySymbol>().ToArray();
                },
                member =>
                {
                    var result = member.Type.NullableAnnotation;
                    Assert.Equal(result, member.NullableAnnotation);
                    return result;
                },
                testMetadata: true,
                PublicNullableAnnotation.NotAnnotated,
                PublicNullableAnnotation.Annotated,
                PublicNullableAnnotation.NotAnnotated,
                PublicNullableAnnotation.Annotated,
                PublicNullableAnnotation.None,
                PublicNullableAnnotation.Annotated,
                PublicNullableAnnotation.NotAnnotated,
                PublicNullableAnnotation.Annotated);
        }
 
        [Fact]
        [WorkItem(34412, "https://github.com/dotnet/roslyn/issues/34412")]
        public void MethodReturnDeclarations()
        {
            var source = @"
public struct S {}
public class C
{
#nullable enable
    public string M0() => string.Empty;
    public string? M1() => null;
#nullable disable
    public string M2() => null;
    public string? M3() => null; // 1
 
#nullable enable
    public S M4() => default;
    public S? M5() => null;
#nullable disable
    public S M6() => default;
    public S? M7() => default;
}";
 
            VerifyAcrossCompilations(
                source,
                new[]
                {
                    // (10,18): warning CS8632: The annotation for nullable reference types should only be used in code within a '#nullable' context.
                    //     public string? M3() => null; // 1
                    Diagnostic(ErrorCode.WRN_MissingNonNullTypesContextForAnnotation, "?").WithLocation(10, 18)
                },
                new[]
                {
                    // (5,2): error CS8652: The feature 'nullable reference types' is not available in C# 7.3. Please use language version 8.0 or greater.
                    // #nullable enable
                    Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7_3, "nullable").WithArguments("nullable reference types", "8.0").WithLocation(5, 2),
                    // (7,18): error CS8652: The feature 'nullable reference types' is not available in C# 7.3. Please use language version 8.0 or greater.
                    //     public string? M1() => null;
                    Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7_3, "?").WithArguments("nullable reference types", "8.0").WithLocation(7, 18),
                    // (8,2): error CS8652: The feature 'nullable reference types' is not available in C# 7.3. Please use language version 8.0 or greater.
                    // #nullable disable
                    Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7_3, "nullable").WithArguments("nullable reference types", "8.0").WithLocation(8, 2),
                    // (10,18): error CS8652: The feature 'nullable reference types' is not available in C# 7.3. Please use language version 8.0 or greater.
                    //     public string? M3() => null; // 1
                    Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7_3, "?").WithArguments("nullable reference types", "8.0").WithLocation(10, 18),
                    // (12,2): error CS8652: The feature 'nullable reference types' is not available in C# 7.3. Please use language version 8.0 or greater.
                    // #nullable enable
                    Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7_3, "nullable").WithArguments("nullable reference types", "8.0").WithLocation(12, 2),
                    // (15,2): error CS8652: The feature 'nullable reference types' is not available in C# 7.3. Please use language version 8.0 or greater.
                    // #nullable disable
                    Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7_3, "nullable").WithArguments("nullable reference types", "8.0").WithLocation(15, 2)
                },
                compilation =>
                {
                    var c = ((Compilation)compilation).GetTypeByMetadataName("C");
                    return c.GetMembers().OfType<IMethodSymbol>().Where(m => m.Name.StartsWith("M")).ToArray();
                },
                member =>
                {
                    var result = member.ReturnType.NullableAnnotation;
                    Assert.Equal(result, member.ReturnNullableAnnotation);
                    return result;
                },
                testMetadata: true,
                PublicNullableAnnotation.NotAnnotated,
                PublicNullableAnnotation.Annotated,
                PublicNullableAnnotation.None,
                PublicNullableAnnotation.Annotated,
                PublicNullableAnnotation.NotAnnotated,
                PublicNullableAnnotation.Annotated,
                PublicNullableAnnotation.NotAnnotated,
                PublicNullableAnnotation.Annotated);
        }
 
        [Fact]
        [WorkItem(34412, "https://github.com/dotnet/roslyn/issues/34412")]
        public void ParameterDeclarations()
        {
            var source = @"
public struct S {}
public class C
{
    public void M1(
#nullable enable
        C c1,
#nullable disable
        C c2,
#nullable enable
        C? c3,
#nullable disable
        C? c4,
#nullable enable
        S s1,
#nullable disable
        S s2,
#nullable enable
        S? s3,
#nullable disable
        S? s4) {}
}
";
            VerifyAcrossCompilations(
                source,
                new[]
                {
                    // (13,10): warning CS8632: The annotation for nullable reference types should only be used in code within a '#nullable' context.
                    //         C? c4,
                    Diagnostic(ErrorCode.WRN_MissingNonNullTypesContextForAnnotation, "?").WithLocation(13, 10)
                },
                new[] {
                    // (6,2): error CS8652: The feature 'nullable reference types' is not available in C# 7.3. Please use language version 8.0 or greater.
                    // #nullable enable
                    Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7_3, "nullable").WithArguments("nullable reference types", "8.0").WithLocation(6, 2),
                    // (8,2): error CS8652: The feature 'nullable reference types' is not available in C# 7.3. Please use language version 8.0 or greater.
                    // #nullable disable
                    Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7_3, "nullable").WithArguments("nullable reference types", "8.0").WithLocation(8, 2),
                    // (10,2): error CS8652: The feature 'nullable reference types' is not available in C# 7.3. Please use language version 8.0 or greater.
                    // #nullable enable
                    Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7_3, "nullable").WithArguments("nullable reference types", "8.0").WithLocation(10, 2),
                    // (11,10): error CS8652: The feature 'nullable reference types' is not available in C# 7.3. Please use language version 8.0 or greater.
                    //         C? c3,
                    Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7_3, "?").WithArguments("nullable reference types", "8.0").WithLocation(11, 10),
                    // (12,2): error CS8652: The feature 'nullable reference types' is not available in C# 7.3. Please use language version 8.0 or greater.
                    // #nullable disable
                    Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7_3, "nullable").WithArguments("nullable reference types", "8.0").WithLocation(12, 2),
                    // (13,10): error CS8652: The feature 'nullable reference types' is not available in C# 7.3. Please use language version 8.0 or greater.
                    //         C? c4,
                    Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7_3, "?").WithArguments("nullable reference types", "8.0").WithLocation(13, 10),
                    // (14,2): error CS8652: The feature 'nullable reference types' is not available in C# 7.3. Please use language version 8.0 or greater.
                    // #nullable enable
                    Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7_3, "nullable").WithArguments("nullable reference types", "8.0").WithLocation(14, 2),
                    // (16,2): error CS8652: The feature 'nullable reference types' is not available in C# 7.3. Please use language version 8.0 or greater.
                    // #nullable disable
                    Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7_3, "nullable").WithArguments("nullable reference types", "8.0").WithLocation(16, 2),
                    // (18,2): error CS8652: The feature 'nullable reference types' is not available in C# 7.3. Please use language version 8.0 or greater.
                    // #nullable enable
                    Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7_3, "nullable").WithArguments("nullable reference types", "8.0").WithLocation(18, 2),
                    // (20,2): error CS8652: The feature 'nullable reference types' is not available in C# 7.3. Please use language version 8.0 or greater.
                    // #nullable disable
                    Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7_3, "nullable").WithArguments("nullable reference types", "8.0").WithLocation(20, 2)
                },
                compilation =>
                {
                    var c = ((Compilation)compilation).GetTypeByMetadataName("C");
                    return c.GetMembers("M1").OfType<IMethodSymbol>().Single().Parameters.ToArray();
                },
                member =>
                {
                    var result = member.Type.NullableAnnotation;
                    Assert.Equal(result, member.NullableAnnotation);
                    return result;
                },
                testMetadata: true,
                PublicNullableAnnotation.NotAnnotated,
                PublicNullableAnnotation.None,
                PublicNullableAnnotation.Annotated,
                PublicNullableAnnotation.Annotated,
                PublicNullableAnnotation.NotAnnotated,
                PublicNullableAnnotation.NotAnnotated,
                PublicNullableAnnotation.Annotated,
                PublicNullableAnnotation.Annotated);
        }
 
        [Fact]
        [WorkItem(35034, "https://github.com/dotnet/roslyn/issues/35034")]
        public void MethodDeclarationReceiver()
        {
            var source = @"
public class C
{
#nullable enable
    public static void M1() {}
    public void M2() {}
 
#nullable disable
    public static void M3() {}
    public void M4() {}
}
public static class Ext
{
#nullable enable
    public static void M5(this C c) {}
    public static void M6(this C? c) {}
    public static void M7(this int i) {}
    public static void M8(this int? i) {}
 
#nullable disable
    public static void M9(this C c) {}
    public static void M10(this C? c) {}
    public static void M11(this int i) {}
    public static void M12(this int? i) {}
}
";
 
            var comp1 = CreateCompilation(source, options: WithNullableEnable());
            comp1.VerifyDiagnostics(
                // (22,34): warning CS8632: The annotation for nullable reference types should only be used in code within a '#nullable' annotations context.
                //     public static void M10(this C? c) {}
                Diagnostic(ErrorCode.WRN_MissingNonNullTypesContextForAnnotation, "?").WithLocation(22, 34));
            verifyCompilation(comp1);
 
            var comp2 = CreateCompilation(source, options: WithNullableDisable());
            comp2.VerifyDiagnostics(
                // (22,34): warning CS8632: The annotation for nullable reference types should only be used in code within a '#nullable' annotations context.
                //     public static void M10(this C? c) {}
                Diagnostic(ErrorCode.WRN_MissingNonNullTypesContextForAnnotation, "?").WithLocation(22, 34));
            verifyCompilation(comp2);
 
            var comp3 = CreateCompilation(source, parseOptions: TestOptions.Regular7_3, skipUsesIsNullable: true);
            comp3.VerifyDiagnostics(
                // (4,2): error CS8370: Feature 'nullable reference types' is not available in C# 7.3. Please use language version 8.0 or greater.
                // #nullable enable
                Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7_3, "nullable").WithArguments("nullable reference types", "8.0").WithLocation(4, 2),
                // (8,2): error CS8370: Feature 'nullable reference types' is not available in C# 7.3. Please use language version 8.0 or greater.
                // #nullable disable
                Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7_3, "nullable").WithArguments("nullable reference types", "8.0").WithLocation(8, 2),
                // (14,2): error CS8370: Feature 'nullable reference types' is not available in C# 7.3. Please use language version 8.0 or greater.
                // #nullable enable
                Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7_3, "nullable").WithArguments("nullable reference types", "8.0").WithLocation(14, 2),
                // (16,33): error CS8370: Feature 'nullable reference types' is not available in C# 7.3. Please use language version 8.0 or greater.
                //     public static void M6(this C? c) {}
                Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7_3, "?").WithArguments("nullable reference types", "8.0").WithLocation(16, 33),
                // (20,2): error CS8370: Feature 'nullable reference types' is not available in C# 7.3. Please use language version 8.0 or greater.
                // #nullable disable
                Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7_3, "nullable").WithArguments("nullable reference types", "8.0").WithLocation(20, 2),
                // (22,34): error CS8370: Feature 'nullable reference types' is not available in C# 7.3. Please use language version 8.0 or greater.
                //     public static void M10(this C? c) {}
                Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7_3, "?").WithArguments("nullable reference types", "8.0").WithLocation(22, 34));
            verifyCompilation(comp3);
 
            var comp1Emit = comp1.EmitToImageReference();
            var comp4 = CreateCompilation("", references: new[] { comp1Emit }, options: WithNullableEnable());
            comp4.VerifyDiagnostics();
            verifyCompilation(comp4);
 
            var comp2Emit = comp2.EmitToImageReference();
            var comp5 = CreateCompilation("", references: new[] { comp2Emit }, options: WithNullableDisable());
            comp5.VerifyDiagnostics();
            verifyCompilation(comp5);
 
            var comp6 = CreateCompilation("", references: new[] { comp1Emit }, parseOptions: TestOptions.Regular7_3);
            comp6.VerifyDiagnostics();
            verifyCompilation(comp6);
 
            void verifyCompilation(CSharpCompilation compilation)
            {
                var c = ((Compilation)compilation).GetTypeByMetadataName("C");
                var members = c.GetMembers().OfType<IMethodSymbol>().Where(m => m.Name.StartsWith("M")).ToArray();
                assertNullability(members,
                    PublicNullableAnnotation.None,
                    PublicNullableAnnotation.NotAnnotated,
                    PublicNullableAnnotation.None,
                    PublicNullableAnnotation.NotAnnotated);
 
                var e = ((Compilation)compilation).GetTypeByMetadataName("Ext");
                members = e.GetMembers().OfType<IMethodSymbol>().Where(m => m.Name.StartsWith("M")).Select(m => m.ReduceExtensionMethod(m.Parameters[0].Type)).ToArray();
                assertNullability(members,
                    PublicNullableAnnotation.NotAnnotated,
                    PublicNullableAnnotation.Annotated,
                    PublicNullableAnnotation.NotAnnotated,
                    PublicNullableAnnotation.Annotated,
                    PublicNullableAnnotation.None,
                    PublicNullableAnnotation.Annotated,
                    PublicNullableAnnotation.NotAnnotated,
                    PublicNullableAnnotation.Annotated);
 
                static void assertNullability(IMethodSymbol[] methods, params PublicNullableAnnotation[] expectedAnnotations)
                {
                    var actualAnnotations = methods.Select(m =>
                    {
                        var result = m.ReceiverType.NullableAnnotation;
                        Assert.Equal(result, m.ReceiverNullableAnnotation);
                        return result;
                    });
                    AssertEx.Equal(expectedAnnotations, actualAnnotations);
                }
            }
        }
 
        [Fact]
        public void LocalFunctions()
        {
            var source = @"
#pragma warning disable CS8321 // Unused local function
public struct S {}
public class C
{
    void M1()
    {
#nullable enable
        C LM1(C c) => new C();
        C? LM2(C? c) => null;
        S LM3(S s) => default;
        S? LM4(S? s) => null;
#nullable disable
        C LM5(C c) => new C();
        C? LM6(C? c) => null;
        S LM7(S s) => default;
        S? LM8(S? s) => null;
    }
}
";
 
            VerifyAcrossCompilations(
                source,
                new[] {
                    // (15,10): warning CS8632: The annotation for nullable reference types should only be used in code within a '#nullable' context.
                    //         C? LM6(C? c) => null;
                    Diagnostic(ErrorCode.WRN_MissingNonNullTypesContextForAnnotation, "?").WithLocation(15, 10),
                    // (15,17): warning CS8632: The annotation for nullable reference types should only be used in code within a '#nullable' context.
                    //         C? LM6(C? c) => null;
                    Diagnostic(ErrorCode.WRN_MissingNonNullTypesContextForAnnotation, "?").WithLocation(15, 17)
                },
                new[] {
                    // (8,2): error CS8652: The feature 'nullable reference types' is not available in C# 7.3. Please use language version 8.0 or greater.
                    // #nullable enable
                    Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7_3, "nullable").WithArguments("nullable reference types", "8.0").WithLocation(8, 2),
                    // (10,10): error CS8652: The feature 'nullable reference types' is not available in C# 7.3. Please use language version 8.0 or greater.
                    //         C? LM2(C? c) => null;
                    Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7_3, "?").WithArguments("nullable reference types", "8.0").WithLocation(10, 10),
                    // (10,17): error CS8652: The feature 'nullable reference types' is not available in C# 7.3. Please use language version 8.0 or greater.
                    //         C? LM2(C? c) => null;
                    Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7_3, "?").WithArguments("nullable reference types", "8.0").WithLocation(10, 17),
                    // (13,2): error CS8652: The feature 'nullable reference types' is not available in C# 7.3. Please use language version 8.0 or greater.
                    // #nullable disable
                    Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7_3, "nullable").WithArguments("nullable reference types", "8.0").WithLocation(13, 2),
                    // (15,10): error CS8652: The feature 'nullable reference types' is not available in C# 7.3. Please use language version 8.0 or greater.
                    //         C? LM6(C? c) => null;
                    Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7_3, "?").WithArguments("nullable reference types", "8.0").WithLocation(15, 10),
                    // (15,17): error CS8652: The feature 'nullable reference types' is not available in C# 7.3. Please use language version 8.0 or greater.
                    //         C? LM6(C? c) => null;
                    Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7_3, "?").WithArguments("nullable reference types", "8.0").WithLocation(15, 17)
                },
                comp =>
                {
                    var syntaxTree = comp.SyntaxTrees[0];
                    var semanticModel = comp.GetSemanticModel(syntaxTree);
                    return syntaxTree.GetRoot().DescendantNodes().OfType<CSharp.Syntax.LocalFunctionStatementSyntax>().Select(func => semanticModel.GetDeclaredSymbol(func)).Cast<IMethodSymbol>().ToArray();
                },
                method =>
                {
                    Assert.Equal(method.ReturnNullableAnnotation, method.Parameters[0].NullableAnnotation);
                    Assert.Equal(method.ReturnNullableAnnotation, method.Parameters[0].Type.NullableAnnotation);
                    Assert.Equal(PublicNullableAnnotation.None, method.ReceiverNullableAnnotation);
                    Assert.Equal(PublicNullableAnnotation.None, method.ReceiverType.NullableAnnotation);
                    var result = method.ReturnType.NullableAnnotation;
                    Assert.Equal(result, method.ReturnNullableAnnotation);
                    return result;
                },
                testMetadata: false,
                PublicNullableAnnotation.NotAnnotated,
                PublicNullableAnnotation.Annotated,
                PublicNullableAnnotation.NotAnnotated,
                PublicNullableAnnotation.Annotated,
                PublicNullableAnnotation.None,
                PublicNullableAnnotation.Annotated,
                PublicNullableAnnotation.NotAnnotated,
                PublicNullableAnnotation.Annotated);
        }
 
        [Fact]
        public void EventDeclarations()
        {
            var source = @"
#pragma warning disable CS0067 // Unused event
public class C
{
    public delegate void D();
 
#nullable enable
    public event D D1;
    public event D? D2;
 
#nullable disable
    public event D D3;
    public event D? D4;
}";
            VerifyAcrossCompilations(
                source,
                new[] { 
                    // (8,20): warning CS8618: Non-nullable event 'D1' is uninitialized. Consider declaring the event as nullable.
                    //     public event D D1;
                    Diagnostic(ErrorCode.WRN_UninitializedNonNullableField, "D1").WithArguments("event", "D1").WithLocation(8, 20),
                    // (13,19): warning CS8632: The annotation for nullable reference types should only be used in code within a '#nullable' annotations context.
                    //     public event D? D4;
                    Diagnostic(ErrorCode.WRN_MissingNonNullTypesContextForAnnotation, "?").WithLocation(13, 19)
                },
                new[] { 
                    // (7,2): error CS8652: The feature 'nullable reference types' is not available in C# 7.3. Please use language version 8.0 or greater.
                    // #nullable enable
                    Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7_3, "nullable").WithArguments("nullable reference types", "8.0").WithLocation(7, 2),
                    // (9,19): error CS8652: The feature 'nullable reference types' is not available in C# 7.3. Please use language version 8.0 or greater.
                    //     public event D? D2;
                    Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7_3, "?").WithArguments("nullable reference types", "8.0").WithLocation(9, 19),
                    // (11,2): error CS8652: The feature 'nullable reference types' is not available in C# 7.3. Please use language version 8.0 or greater.
                    // #nullable disable
                    Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7_3, "nullable").WithArguments("nullable reference types", "8.0").WithLocation(11, 2),
                    // (13,19): error CS8652: The feature 'nullable reference types' is not available in C# 7.3. Please use language version 8.0 or greater.
                    //     public event D? D4;
                    Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7_3, "?").WithArguments("nullable reference types", "8.0").WithLocation(13, 19)
                },
                compilation =>
                {
                    var c = ((Compilation)compilation).GetTypeByMetadataName("C");
                    return c.GetMembers().OfType<IEventSymbol>().ToArray();
                },
                member =>
                {
                    var result = member.Type.NullableAnnotation;
                    Assert.Equal(result, member.NullableAnnotation);
                    return result;
                },
                testMetadata: true,
                PublicNullableAnnotation.NotAnnotated,
                PublicNullableAnnotation.Annotated,
                PublicNullableAnnotation.None,
                PublicNullableAnnotation.Annotated);
        }
 
        [Fact]
        [WorkItem(34412, "https://github.com/dotnet/roslyn/issues/34412")]
        public void ArrayElements()
        {
            var source =
@"public interface I
{
#nullable enable
    object[] F1();
    object?[] F2();
    int[] F3();
    int?[] F4();
#nullable disable
    object[] F5();
    object?[] F6();
    int[] F7();
    int?[] F8();
}";
            VerifyAcrossCompilations(
                source,
                new[]
                {
                    // (10,11): warning CS8632: The annotation for nullable reference types should only be used in code within a '#nullable' annotations context.
                    //     object?[] F6();
                    Diagnostic(ErrorCode.WRN_MissingNonNullTypesContextForAnnotation, "?").WithLocation(10, 11)
                },
                new[]
                {
                    // (3,2): error CS8370: Feature 'nullable reference types' is not available in C# 7.3. Please use language version 8.0 or greater.
                    // #nullable enable
                    Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7_3, "nullable").WithArguments("nullable reference types", "8.0").WithLocation(3, 2),
                    // (5,11): error CS8370: Feature 'nullable reference types' is not available in C# 7.3. Please use language version 8.0 or greater.
                    //     object?[] F2();
                    Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7_3, "?").WithArguments("nullable reference types", "8.0").WithLocation(5, 11),
                    // (8,2): error CS8370: Feature 'nullable reference types' is not available in C# 7.3. Please use language version 8.0 or greater.
                    // #nullable disable
                    Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7_3, "nullable").WithArguments("nullable reference types", "8.0").WithLocation(8, 2),
                    // (10,11): error CS8370: Feature 'nullable reference types' is not available in C# 7.3. Please use language version 8.0 or greater.
                    //     object?[] F6();
                    Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7_3, "?").WithArguments("nullable reference types", "8.0").WithLocation(10, 11)
                },
                comp => ((INamedTypeSymbol)((Compilation)comp).GetMember("I")).GetMembers().OfType<IMethodSymbol>().Where(m => m.Name.StartsWith("F")).ToArray(),
                method =>
                {
                    var array = (IArrayTypeSymbol)method.ReturnType;
                    var result = array.ElementType.NullableAnnotation;
                    Assert.Equal(result, array.ElementNullableAnnotation);
                    return result;
                },
                testMetadata: true,
                PublicNullableAnnotation.NotAnnotated,
                PublicNullableAnnotation.Annotated,
                PublicNullableAnnotation.NotAnnotated,
                PublicNullableAnnotation.Annotated,
                PublicNullableAnnotation.None,
                PublicNullableAnnotation.Annotated,
                PublicNullableAnnotation.NotAnnotated,
                PublicNullableAnnotation.Annotated);
        }
 
        [Fact]
        [WorkItem(34412, "https://github.com/dotnet/roslyn/issues/34412")]
        public void TypeParameters()
        {
            var source =
@"#nullable enable
public interface I<T, U, V>
    where U : class
    where V : struct
{
    T F1();
    U F2();
    U? F3();
    V F4();
    V? F5();
#nullable disable
    T F6();
    U F7();
    U? F8();
    V F9();
    V? F10();
}";
            VerifyAcrossCompilations(
                source,
                new[]
                {
                    // (14,6): warning CS8632: The annotation for nullable reference types should only be used in code within a '#nullable' annotations context.
                    //     U? F8();
                    Diagnostic(ErrorCode.WRN_MissingNonNullTypesContextForAnnotation, "?").WithLocation(14, 6)
                },
                new[]
                {
                    // (1,2): error CS8370: Feature 'nullable reference types' is not available in C# 7.3. Please use language version 8.0 or greater.
                    // #nullable enable
                    Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7_3, "nullable").WithArguments("nullable reference types", "8.0").WithLocation(1, 2),
                    // (8,6): error CS8370: Feature 'nullable reference types' is not available in C# 7.3. Please use language version 8.0 or greater.
                    //     U? F3();
                    Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7_3, "?").WithArguments("nullable reference types", "8.0").WithLocation(8, 6),
                    // (11,2): error CS8370: Feature 'nullable reference types' is not available in C# 7.3. Please use language version 8.0 or greater.
                    // #nullable disable
                    Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7_3, "nullable").WithArguments("nullable reference types", "8.0").WithLocation(11, 2),
                    // (14,6): error CS8370: Feature 'nullable reference types' is not available in C# 7.3. Please use language version 8.0 or greater.
                    //     U? F8();
                    Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7_3, "?").WithArguments("nullable reference types", "8.0").WithLocation(14, 6)
                },
                comp => ((INamedTypeSymbol)((Compilation)comp).GetMember("I")).GetMembers().OfType<IMethodSymbol>().Where(m => m.Name.StartsWith("F")).ToArray(),
                method =>
                {
                    var result = method.ReturnType.NullableAnnotation;
                    Assert.Equal(result, method.ReturnNullableAnnotation);
                    return result;
                },
                testMetadata: true,
                PublicNullableAnnotation.NotAnnotated,
                PublicNullableAnnotation.NotAnnotated,
                PublicNullableAnnotation.Annotated,
                PublicNullableAnnotation.NotAnnotated,
                PublicNullableAnnotation.Annotated,
                PublicNullableAnnotation.None,
                PublicNullableAnnotation.None,
                PublicNullableAnnotation.Annotated,
                PublicNullableAnnotation.NotAnnotated,
                PublicNullableAnnotation.Annotated);
        }
 
        [Fact]
        [WorkItem(34412, "https://github.com/dotnet/roslyn/issues/34412")]
        public void Constraints()
        {
            var source =
@"public class A<T>
{
    public class B<U> where U : T { }
}
public interface I
{
#nullable enable
    A<string> F1();
    A<string?> F2();
    A<int> F3();
    A<int?> F4();
#nullable disable
    A<string> F5();
    A<string?> F6();
    A<int> F7();
    A<int?> F8();
}";
            VerifyAcrossCompilations(
                source,
                new[]
                {
                    // (14,13): warning CS8632: The annotation for nullable reference types should only be used in code within a '#nullable' annotations context.
                    //     A<object?> F6();
                    Diagnostic(ErrorCode.WRN_MissingNonNullTypesContextForAnnotation, "?").WithLocation(14, 13)
                },
                new[]
                {
                    // (7,2): error CS8370: Feature 'nullable reference types' is not available in C# 7.3. Please use language version 8.0 or greater.
                    // #nullable enable
                    Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7_3, "nullable").WithArguments("nullable reference types", "8.0").WithLocation(7, 2),
                    // (9,13): error CS8370: Feature 'nullable reference types' is not available in C# 7.3. Please use language version 8.0 or greater.
                    //     A<string?> F2();
                    Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7_3, "?").WithArguments("nullable reference types", "8.0").WithLocation(9, 13),
                    // (12,2): error CS8370: Feature 'nullable reference types' is not available in C# 7.3. Please use language version 8.0 or greater.
                    // #nullable disable
                    Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7_3, "nullable").WithArguments("nullable reference types", "8.0").WithLocation(12, 2),
                    // (14,13): error CS8370: Feature 'nullable reference types' is not available in C# 7.3. Please use language version 8.0 or greater.
                    //     A<string?> F6();
                    Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7_3, "?").WithArguments("nullable reference types", "8.0").WithLocation(14, 13)
                },
                comp => ((INamedTypeSymbol)((Compilation)comp).GetMember("I")).GetMembers().OfType<IMethodSymbol>().Where(m => m.Name.StartsWith("F")).ToArray(),
                method =>
                {
                    ITypeParameterSymbol typeParameterSymbol = ((INamedTypeSymbol)((INamedTypeSymbol)method.ReturnType).GetMembers("B").Single()).TypeParameters.Single();
                    var result = typeParameterSymbol.ConstraintTypes.Single().NullableAnnotation;
                    Assert.Equal(result, typeParameterSymbol.ConstraintNullableAnnotations.Single());
                    return result;
                },
                testMetadata: true,
                PublicNullableAnnotation.NotAnnotated,
                PublicNullableAnnotation.Annotated,
                PublicNullableAnnotation.NotAnnotated,
                PublicNullableAnnotation.Annotated,
                PublicNullableAnnotation.None,
                PublicNullableAnnotation.Annotated,
                PublicNullableAnnotation.NotAnnotated,
                PublicNullableAnnotation.Annotated);
        }
 
        [Fact]
        [WorkItem(34412, "https://github.com/dotnet/roslyn/issues/34412")]
        public void TypeArguments_01()
        {
            var source =
@"public interface IA<T>
{
}
#nullable enable
public interface IB<T, U, V>
    where U : class
    where V : struct
{
    IA<T> F1();
    IA<U> F2();
    IA<U?> F3();
    IA<V> F4();
    IA<V?> F5();
#nullable disable
    IA<T> F6();
    IA<U> F7();
    IA<U?> F8();
    IA<V> F9();
    IA<V?> F10();
}";
            VerifyAcrossCompilations(
                source,
                new[]
                {
                    // (17,9): warning CS8632: The annotation for nullable reference types should only be used in code within a '#nullable' annotations context.
                    //     IA<U?> F8();
                    Diagnostic(ErrorCode.WRN_MissingNonNullTypesContextForAnnotation, "?").WithLocation(17, 9)
                },
                new[]
                {
                    // (4,2): error CS8370: Feature 'nullable reference types' is not available in C# 7.3. Please use language version 8.0 or greater.
                    // #nullable enable
                    Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7_3, "nullable").WithArguments("nullable reference types", "8.0").WithLocation(4, 2),
                    // (11,9): error CS8370: Feature 'nullable reference types' is not available in C# 7.3. Please use language version 8.0 or greater.
                    //     IA<U?> F3();
                    Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7_3, "?").WithArguments("nullable reference types", "8.0").WithLocation(11, 9),
                    // (14,2): error CS8370: Feature 'nullable reference types' is not available in C# 7.3. Please use language version 8.0 or greater.
                    // #nullable disable
                    Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7_3, "nullable").WithArguments("nullable reference types", "8.0").WithLocation(14, 2),
                    // (17,9): error CS8370: Feature 'nullable reference types' is not available in C# 7.3. Please use language version 8.0 or greater.
                    //     IA<U?> F8();
                    Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7_3, "?").WithArguments("nullable reference types", "8.0").WithLocation(17, 9)
                },
                comp => ((INamedTypeSymbol)((Compilation)comp).GetMember("IB")).GetMembers().OfType<IMethodSymbol>().Where(m => m.Name.StartsWith("F")).ToArray(),
                method =>
                {
                    var result = ((INamedTypeSymbol)method.ReturnType).TypeArguments.Single().NullableAnnotation;
                    Assert.Equal(result, ((INamedTypeSymbol)method.ReturnType).TypeArgumentNullableAnnotations.Single());
                    Assert.Equal(result, ((INamedTypeSymbol)method.ReturnType).TypeArgumentNullableAnnotations().Single());
                    return result;
                },
                testMetadata: true,
                PublicNullableAnnotation.NotAnnotated,
                PublicNullableAnnotation.NotAnnotated,
                PublicNullableAnnotation.Annotated,
                PublicNullableAnnotation.NotAnnotated,
                PublicNullableAnnotation.Annotated,
                PublicNullableAnnotation.None,
                PublicNullableAnnotation.None,
                PublicNullableAnnotation.Annotated,
                PublicNullableAnnotation.NotAnnotated,
                PublicNullableAnnotation.Annotated);
        }
 
        [Fact]
        [WorkItem(34412, "https://github.com/dotnet/roslyn/issues/34412")]
        public void TypeArguments_02()
        {
            var source =
@"class C
{
    static void F<T>()
    {
    }
#nullable enable
    static void M<T, U, V>()
        where U : class
        where V : struct
    {
        F<T>();
        F<U>();
        F<U?>();
        F<V>();
        F<V?>();
#nullable disable
        F<T>();
        F<U>();
        F<U?>();
        F<V>();
        F<V?>();
    }
}";
            var comp = CreateCompilation(source);
            comp.VerifyDiagnostics(
                // (19,12): warning CS8632: The annotation for nullable reference types should only be used in code within a '#nullable' annotations context.
                //         F<U?>();
                Diagnostic(ErrorCode.WRN_MissingNonNullTypesContextForAnnotation, "?").WithLocation(19, 12));
            var syntaxTree = comp.SyntaxTrees[0];
            var model = comp.GetSemanticModel(syntaxTree);
            var invocations = syntaxTree.GetRoot().DescendantNodes().OfType<InvocationExpressionSyntax>();
            var actualAnnotations = invocations.Select(inv =>
            {
                var method = (IMethodSymbol)model.GetSymbolInfo(inv).Symbol;
                var result = method.TypeArguments.Single().NullableAnnotation;
                Assert.Equal(result, method.TypeArgumentNullableAnnotations.Single());
                return result;
            }).ToArray();
            var expectedAnnotations = new[]
            {
                PublicNullableAnnotation.NotAnnotated,
                PublicNullableAnnotation.NotAnnotated,
                PublicNullableAnnotation.Annotated,
                PublicNullableAnnotation.NotAnnotated,
                PublicNullableAnnotation.Annotated,
                PublicNullableAnnotation.None,
                PublicNullableAnnotation.None,
                PublicNullableAnnotation.Annotated,
                PublicNullableAnnotation.NotAnnotated,
                PublicNullableAnnotation.Annotated
            };
            AssertEx.Equal(expectedAnnotations, actualAnnotations);
        }
 
        [Fact]
        [WorkItem(34412, "https://github.com/dotnet/roslyn/issues/34412")]
        public void Locals()
        {
            var source =
@"#pragma warning disable 168
class C
{
#nullable enable
    static void M<T, U, V>()
        where U : class
        where V : struct
    {
        T x1;
        U x2;
        U? x3;
        V x4;
        V? x5;
#nullable disable
        T x6;
        U x7;
        U? x8;
        V x9;
        V? x10;
    }
}";
            var comp = CreateCompilation(source);
            comp.VerifyDiagnostics(
                // (17,10): warning CS8632: The annotation for nullable reference types should only be used in code within a '#nullable' annotations context.
                //         U? x8;
                Diagnostic(ErrorCode.WRN_MissingNonNullTypesContextForAnnotation, "?").WithLocation(17, 10));
            var syntaxTree = comp.SyntaxTrees[0];
            var model = comp.GetSemanticModel(syntaxTree);
            var variables = syntaxTree.GetRoot().DescendantNodes().OfType<VariableDeclaratorSyntax>();
            var actualAnnotations = variables.Select(v =>
            {
                var localSymbol = (ILocalSymbol)model.GetDeclaredSymbol(v);
                var result = localSymbol.Type.NullableAnnotation;
                Assert.Equal(result, localSymbol.NullableAnnotation);
                return result;
            }).ToArray();
 
            var expectedAnnotations = new[]
            {
                PublicNullableAnnotation.NotAnnotated,
                PublicNullableAnnotation.NotAnnotated,
                PublicNullableAnnotation.Annotated,
                PublicNullableAnnotation.NotAnnotated,
                PublicNullableAnnotation.Annotated,
                PublicNullableAnnotation.None,
                PublicNullableAnnotation.None,
                PublicNullableAnnotation.Annotated,
                PublicNullableAnnotation.NotAnnotated,
                PublicNullableAnnotation.Annotated
            };
            AssertEx.Equal(expectedAnnotations, actualAnnotations);
        }
 
        private static void VerifyAcrossCompilations<T>(string source,
                                                 DiagnosticDescription[] nullableEnabledErrors,
                                                 DiagnosticDescription[] nullableDisabledErrors,
                                                 Func<CSharpCompilation, T[]> memberFunc,
                                                 Func<T, PublicNullableAnnotation> nullabilityFunc,
                                                 bool testMetadata,
                                                 params PublicNullableAnnotation[] expectedNullabilities)
        {
            var comp1 = CreateCompilation(source, options: WithNullableEnable());
            comp1.VerifyDiagnostics(nullableEnabledErrors);
            verifyCompilation(comp1);
 
            var comp2 = CreateCompilation(source, options: WithNullableDisable());
            comp2.VerifyDiagnostics(nullableEnabledErrors);
            verifyCompilation(comp2);
 
            var comp3 = CreateCompilation(source, parseOptions: TestOptions.Regular7_3, skipUsesIsNullable: true);
            comp3.VerifyDiagnostics(nullableDisabledErrors);
            verifyCompilation(comp3);
 
            if (!testMetadata) return;
 
            var comp1Emit = comp1.EmitToImageReference();
            var comp4 = CreateCompilation("", references: new[] { comp1Emit }, options: WithNullableEnable());
            comp4.VerifyDiagnostics();
            verifyCompilation(comp4);
 
            var comp2Emit = comp2.EmitToImageReference();
            var comp5 = CreateCompilation("", references: new[] { comp2Emit }, options: WithNullableDisable());
            comp5.VerifyDiagnostics();
            verifyCompilation(comp5);
 
            var comp6 = CreateCompilation("", references: new[] { comp1Emit }, parseOptions: TestOptions.Regular7_3);
            comp6.VerifyDiagnostics();
            verifyCompilation(comp6);
 
            void verifyCompilation(CSharpCompilation compilation)
            {
                var members = memberFunc(compilation);
                AssertEx.Equal(expectedNullabilities, members.Select(nullabilityFunc));
            }
        }
 
        [Fact]
        public void LambdaBody_01()
        {
            var source = @"
using System;
class C
{
    void M(Action a)
    {
        M(() =>
            {
                object? o = null;
                if (o == null) return;
                o.ToString();
            });
    }
}
";
 
            var comp = CreateCompilation(source, options: WithNullableEnable());
            comp.VerifyDiagnostics();
 
            var syntaxTree = comp.SyntaxTrees[0];
            var root = syntaxTree.GetRoot();
            var model = comp.GetSemanticModel(syntaxTree);
 
            var invocation = root.DescendantNodes().OfType<InvocationExpressionSyntax>().Last();
            var typeInfo = model.GetTypeInfoAndVerifyIOperation(((MemberAccessExpressionSyntax)invocation.Expression).Expression);
            Assert.Equal(PublicNullableFlowState.NotNull, typeInfo.Nullability.FlowState);
            // https://github.com/dotnet/roslyn/issues/34993: This is incorrect. o should be Annotated, as you can assign
            // null without a warning.
            Assert.Equal(PublicNullableAnnotation.NotAnnotated, typeInfo.Nullability.Annotation);
        }
 
        [Fact, WorkItem(34919, "https://github.com/dotnet/roslyn/issues/34919")]
        public void EnumInitializer()
        {
            var source = @"
enum E1 : byte
{
    A1
}
enum E2
{
    A2 = E1.A1
}";
 
            var comp = CreateCompilation(source, options: WithNullableEnable());
 
            var syntaxTree = comp.SyntaxTrees[0];
            var root = syntaxTree.GetRoot();
            var model = comp.GetSemanticModel(syntaxTree);
 
            _ = model.GetTypeInfoAndVerifyIOperation(root.DescendantNodes().OfType<EqualsValueClauseSyntax>().Single().Value);
        }
 
        [Fact]
        public void AnalyzerTest()
        {
            var source = @"
class C
{
    void M()
    {
        object? o = null;
        var o1 = o;
        if (o == null) return;
        var o2 = o;
    }
}";
 
            var comp = CreateCompilation(source, options: WithNullableEnable());
 
            comp.VerifyDiagnostics();
            comp.VerifyAnalyzerDiagnostics(new[] { new NullabilityPrinter() }, null, null,
                Diagnostic("CA9998_NullabilityPrinter", "o = null").WithArguments("o", "Annotated").WithLocation(6, 17),
                Diagnostic("CA9998_NullabilityPrinter", "o1 = o").WithArguments("o1", "Annotated").WithLocation(7, 13),
                Diagnostic("CA9999_NullabilityPrinter", "o").WithArguments("o", "MaybeNull", "Annotated", "MaybeNull").WithLocation(7, 18),
                Diagnostic("CA9999_NullabilityPrinter", "o").WithArguments("o", "MaybeNull", "Annotated", "MaybeNull").WithLocation(8, 13),
                Diagnostic("CA9998_NullabilityPrinter", "o2 = o").WithArguments("o2", "Annotated").WithLocation(9, 13),
                Diagnostic("CA9999_NullabilityPrinter", "o").WithArguments("o", "NotNull", "NotAnnotated", "NotNull").WithLocation(9, 18));
        }
 
        private class NullabilityPrinter : DiagnosticAnalyzer
        {
            public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics => ImmutableArray.Create(s_descriptor1, s_descriptor2);
 
            private static readonly DiagnosticDescriptor s_descriptor1 = new DiagnosticDescriptor(id: "CA9999_NullabilityPrinter", title: "CA9999_NullabilityPrinter", messageFormat: "Nullability of '{0}' is '{1}':'{2}'. Speculative flow state is '{3}'", category: "Test", defaultSeverity: DiagnosticSeverity.Warning, isEnabledByDefault: true);
            private static readonly DiagnosticDescriptor s_descriptor2 = new DiagnosticDescriptor(id: "CA9998_NullabilityPrinter", title: "CA9998_NullabilityPrinter", messageFormat: "Declared nullability of '{0}' is '{1}'", category: "Test", defaultSeverity: DiagnosticSeverity.Warning, isEnabledByDefault: true);
 
            public override void Initialize(AnalysisContext context)
            {
                var newSource = (ExpressionStatementSyntax)SyntaxFactory.ParseStatement("_ = o;");
                var oReference = ((AssignmentExpressionSyntax)newSource.Expression).Right;
 
                context.RegisterSyntaxNodeAction(syntaxContext =>
                {
                    if (syntaxContext.Node.ToString() != "o") return;
                    var info = syntaxContext.SemanticModel.GetTypeInfoAndVerifyIOperation(syntaxContext.Node);
                    Assert.True(syntaxContext.SemanticModel.TryGetSpeculativeSemanticModel(syntaxContext.Node.SpanStart, newSource, out var specModel));
                    var specInfo = specModel.GetTypeInfoAndVerifyIOperation(oReference);
                    syntaxContext.ReportDiagnostic(CodeAnalysis.Diagnostic.Create(s_descriptor1, syntaxContext.Node.GetLocation(), syntaxContext.Node, info.Nullability.FlowState, info.Nullability.Annotation, specInfo.Nullability.FlowState));
                }, SyntaxKind.IdentifierName);
 
                context.RegisterSyntaxNodeAction(context =>
                {
                    var declarator = (VariableDeclaratorSyntax)context.Node;
                    var declaredSymbol = (ILocalSymbol)context.SemanticModel.GetDeclaredSymbol(declarator);
                    Assert.Equal(declaredSymbol.Type.NullableAnnotation, declaredSymbol.NullableAnnotation);
                    context.ReportDiagnostic(CodeAnalysis.Diagnostic.Create(s_descriptor2, declarator.GetLocation(), declaredSymbol.Name, declaredSymbol.NullableAnnotation));
 
                }, SyntaxKind.VariableDeclarator);
            }
        }
 
        [Fact]
        public void MultipleConversions()
        {
            var source = @"
class A { public static explicit operator C(A a) => new D(); }
class B : A { }
class C { }
class D : C { }
class E
{
    void M()
    {
        var d = (D)(C?)new B();
    }
}";
 
            var comp = (Compilation)CreateCompilation(source, options: WithNullableEnable());
            comp.VerifyDiagnostics(
                // (10,17): warning CS8600: Converting null literal or possible null value to non-nullable type.
                //         var d = (D)(C?)new B();
                Diagnostic(ErrorCode.WRN_ConvertingNullableToNonNullable, "(D)(C?)new B()").WithLocation(10, 17));
 
            var syntaxTree = comp.SyntaxTrees.First();
            var root = syntaxTree.GetRoot();
            var model = comp.GetSemanticModel(syntaxTree);
 
            var aType = comp.GetTypeByMetadataName("A");
            var bType = comp.GetTypeByMetadataName("B");
            var cType = comp.GetTypeByMetadataName("C");
            var dType = comp.GetTypeByMetadataName("D");
 
            var nullable = new NullabilityInfo(PublicNullableAnnotation.Annotated, PublicNullableFlowState.MaybeNull);
            var notNullable = new NullabilityInfo(PublicNullableAnnotation.NotAnnotated, PublicNullableFlowState.NotNull);
 
            var dCast = (CastExpressionSyntax)root.DescendantNodes().OfType<EqualsValueClauseSyntax>().Single().Value;
            var dInfo = model.GetTypeInfoAndVerifyIOperation(dCast);
            Assert.Equal(dType, dInfo.Type);
            Assert.Equal(dType, dInfo.ConvertedType);
            Assert.Equal(nullable, dInfo.Nullability);
            Assert.Equal(nullable, dInfo.ConvertedNullability);
 
            var cCast = (CastExpressionSyntax)dCast.Expression;
            var cInfo = model.GetTypeInfoAndVerifyIOperation(cCast);
            Assert.Equal(cType, cInfo.Type);
            Assert.Equal(cType, cInfo.ConvertedType);
            Assert.Equal(nullable, cInfo.Nullability);
            Assert.Equal(nullable, cInfo.ConvertedNullability);
 
            var objectCreation = cCast.Expression;
            var creationInfo = model.GetTypeInfoAndVerifyIOperation(objectCreation);
            Assert.Equal(bType, creationInfo.Type);
            Assert.Equal(aType, creationInfo.ConvertedType);
            Assert.Equal(notNullable, creationInfo.Nullability);
            Assert.Equal(nullable, creationInfo.ConvertedNullability);
        }
 
        [Fact]
        public void ConditionalOperator_InvalidType()
        {
            var source = @"
class C
{
    void M()
    {
        var x = new Undefined() ? new object() : null;
    }
}";
 
            var comp = CreateCompilation(source, options: WithNullableEnable());
            comp.VerifyDiagnostics(
                // (6,21): error CS0246: The type or namespace name 'Undefined' could not be found (are you missing a using directive or an assembly reference?)
                //         var x = new Undefined() ? new object() : null;
                Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "Undefined").WithArguments("Undefined").WithLocation(6, 21));
 
            var syntaxTree = comp.SyntaxTrees[0];
            var root = syntaxTree.GetRoot();
            var model = comp.GetSemanticModel(syntaxTree);
 
            var conditional = root.DescendantNodes().OfType<ConditionalExpressionSyntax>().Single();
 
            var notNull = new NullabilityInfo(PublicNullableAnnotation.NotAnnotated, PublicNullableFlowState.NotNull);
            var @null = new NullabilityInfo(PublicNullableAnnotation.Annotated, PublicNullableFlowState.MaybeNull);
 
            var leftInfo = model.GetTypeInfoAndVerifyIOperation(conditional.WhenTrue);
            var rightInfo = model.GetTypeInfoAndVerifyIOperation(conditional.WhenFalse);
 
            Assert.Equal(notNull, leftInfo.Nullability);
            Assert.Equal(notNull, leftInfo.ConvertedNullability);
            Assert.Equal(@null, rightInfo.Nullability);
            Assert.Equal(@null, rightInfo.ConvertedNullability);
        }
 
        [Fact]
        public void InferredDeclarationType()
        {
            var source =
@"
using System.Collections.Generic;
#nullable enable
class C : System.IDisposable
{
    void M(C? x, C x2)
    {
        var /*T:C?*/ y = x;
        var /*T:C?*/ y2 = x2;
        
        using var /*T:C?*/ y3 = x;
        using var /*T:C?*/ y4 = x2;
        
        using (var /*T:C?*/ y5 = x) { }
        using (var /*T:C?*/ y6 = x2) { }
        
        ref var/*T:C?*/ y7 = ref x;
        ref var/*T:C?*/ y8 = ref x2;
        
        if (x == null) 
            return;
        var /*T:C?*/ y9 = x;
        using var /*T:C?*/ y10 = x;
        ref var /*T:C?*/ y11 = ref x;
        
        x = null;
        var /*T:C?*/ y12 = x;
        using var /*T:C?*/ y13 = x;
        ref var /*T:C?*/ y14 = ref x;
        
        x2 = null; // 1
        var /*T:C?*/ y15 = x2;
        using var /*T:C?*/ y16 = x2;
        ref var /*T:C?*/ y17 = ref x2;
    }
    
    void M2(List<C?> l1, List<C> l2)
    {
        foreach (var /*T:C?*/ x in l1) { }
        foreach (var /*T:C?*/ x in l2) { }
    }
 
    public void Dispose() { }
}";
            var comp = CreateCompilation(source);
            comp.VerifyDiagnostics(
                // (31,14): warning CS8600: Converting null literal or possible null value to non-nullable type.
                //         x2 = null; // 1
                Diagnostic(ErrorCode.WRN_ConvertingNullableToNonNullable, "null").WithLocation(31, 14)
                );
            comp.VerifyTypes();
        }
 
        [Fact]
        public void SpeculativeSemanticModel_BasicTest()
        {
            var source = @"
class C
{
    void M(string? s1)
    {
        if (s1 != null)
        {
            s1.ToString();
        }
 
        s1?.ToString();
 
        s1 = """";
        var s2 = s1 == null ? """" : s1;
    }
}";
 
            var comp = CreateCompilation(source, options: WithNullableEnable());
            comp.VerifyDiagnostics();
 
            var syntaxTree = comp.SyntaxTrees[0];
            var root = syntaxTree.GetRoot();
            var model = comp.GetSemanticModel(syntaxTree);
 
            var ifStatement = root.DescendantNodes().OfType<IfStatementSyntax>().Single();
            var conditionalAccessExpression = root.DescendantNodes().OfType<ConditionalAccessExpressionSyntax>().Single();
            var ternary = root.DescendantNodes().OfType<ConditionalExpressionSyntax>().Single();
 
            var newSource = (BlockSyntax)SyntaxFactory.ParseStatement(@"{ string? s3 = null; _ = s1 == """" ? s1 : s1; }");
            var newExprStatement = (ExpressionStatementSyntax)newSource.Statements[1];
            var newTernary = (ConditionalExpressionSyntax)((AssignmentExpressionSyntax)newExprStatement.Expression).Right;
            var inCondition = ((BinaryExpressionSyntax)newTernary.Condition).Left;
            var whenTrue = newTernary.WhenTrue;
            var whenFalse = newTernary.WhenFalse;
 
            var newReference = (IdentifierNameSyntax)SyntaxFactory.ParseExpression(@"s1");
            var newCoalesce = (AssignmentExpressionSyntax)SyntaxFactory.ParseExpression(@"s3 ??= s1", options: TestOptions.Regular8);
 
            // Before the if statement
            verifySpeculativeModel(ifStatement.SpanStart, PublicNullableFlowState.MaybeNull);
 
            // In if statement consequence
            verifySpeculativeModel(ifStatement.Statement.SpanStart, PublicNullableFlowState.NotNull);
 
            // Before the conditional access
            verifySpeculativeModel(conditionalAccessExpression.SpanStart, PublicNullableFlowState.MaybeNull);
 
            // After the conditional access
            verifySpeculativeModel(conditionalAccessExpression.WhenNotNull.SpanStart, PublicNullableFlowState.NotNull);
 
            // In the conditional whenTrue
            verifySpeculativeModel(ternary.WhenTrue.SpanStart, PublicNullableFlowState.MaybeNull);
 
            // In the conditional whenFalse
            verifySpeculativeModel(ternary.WhenFalse.SpanStart, PublicNullableFlowState.NotNull);
 
            void verifySpeculativeModel(int spanStart, PublicNullableFlowState conditionFlowState)
            {
                Assert.True(model.TryGetSpeculativeSemanticModel(spanStart, newSource, out var speculativeModel));
 
                var speculativeTypeInfo = speculativeModel.GetTypeInfoAndVerifyIOperation(inCondition);
                Assert.Equal(conditionFlowState, speculativeTypeInfo.Nullability.FlowState);
 
                speculativeTypeInfo = speculativeModel.GetTypeInfoAndVerifyIOperation(whenTrue);
                Assert.Equal(PublicNullableFlowState.NotNull, speculativeTypeInfo.Nullability.FlowState);
 
                var referenceTypeInfo = speculativeModel.GetSpeculativeTypeInfo(whenTrue.SpanStart, newReference, SpeculativeBindingOption.BindAsExpression);
                Assert.Equal(PublicNullableFlowState.NotNull, referenceTypeInfo.Nullability.FlowState);
                var coalesceTypeInfo = speculativeModel.GetSpeculativeTypeInfo(whenTrue.SpanStart, newCoalesce, SpeculativeBindingOption.BindAsExpression);
                Assert.Equal(PublicNullableFlowState.NotNull, coalesceTypeInfo.Nullability.FlowState);
 
                speculativeTypeInfo = speculativeModel.GetTypeInfoAndVerifyIOperation(whenFalse);
                Assert.Equal(conditionFlowState, speculativeTypeInfo.Nullability.FlowState);
                referenceTypeInfo = speculativeModel.GetSpeculativeTypeInfo(whenFalse.SpanStart, newReference, SpeculativeBindingOption.BindAsExpression);
                Assert.Equal(conditionFlowState, referenceTypeInfo.Nullability.FlowState);
 
                coalesceTypeInfo = speculativeModel.GetSpeculativeTypeInfo(whenFalse.SpanStart, newCoalesce, SpeculativeBindingOption.BindAsExpression);
                Assert.Equal(conditionFlowState, coalesceTypeInfo.Nullability.FlowState);
            }
        }
 
        [Fact]
        public void SpeculativeModel_Properties()
        {
            var source = @"
class C
{
    object? Foo
    {
        get
        {
            object? x = null;
            return x;
        }
    }
}";
 
            var comp = CreateCompilation(source, options: WithNullableEnable());
            comp.VerifyDiagnostics();
 
            var syntaxTree = comp.SyntaxTrees[0];
            var root = syntaxTree.GetRoot();
            var model = comp.GetSemanticModel(syntaxTree);
 
            var returnStatement = root.DescendantNodes().OfType<ReturnStatementSyntax>().Single();
            var newSource = (BlockSyntax)SyntaxFactory.ParseStatement("{ var y = x ?? new object(); y.ToString(); }");
            var yReference = ((MemberAccessExpressionSyntax)newSource.DescendantNodes().OfType<InvocationExpressionSyntax>().Single().Expression).Expression;
            Assert.True(model.TryGetSpeculativeSemanticModel(returnStatement.SpanStart, newSource, out var specModel));
            var speculativeTypeInfo = specModel.GetTypeInfoAndVerifyIOperation(yReference);
            Assert.Equal(PublicNullableFlowState.NotNull, speculativeTypeInfo.Nullability.FlowState);
        }
 
        [Fact]
        public void TupleAssignment()
        {
            var source =
@"
#pragma warning disable CS0219
#nullable enable
class C
{
    void M(C? x, C x2)
    {
        (C? a, C b) t = (x, x2) /*T:(C? x, C! x2)*/ /*CT:(C? a, C! b)*/;
        (object a, int b) t2 = (x, (short)0)/*T:(C? x, short)*/ /*CT:(object! a, int b)*/; // 1
        (object a, int b) t3 = (default, default) /*T:<null>!*/ /*CT:(object! a, int b)*/; // 2
        (object a, int b) t4 = (default(object), default(int)) /*T:(object?, int)*/ /*CT:(object! a, int b)*/; // 3
    }
}";
            var comp = CreateCompilation(source);
            comp.VerifyTypes();
            comp.VerifyDiagnostics(
                // (9,32): warning CS8619: Nullability of reference types in value of type '(object? x, int)' doesn't match target type '(object a, int b)'.
                //         (object a, int b) t2 = (x, (short)0)/*T:(C? x, short)*/ /*CT:(object! a, int b)*/; // 1
                Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "(x, (short)0)").WithArguments("(object? x, int)", "(object a, int b)").WithLocation(9, 32),
                // (10,32): warning CS8619: Nullability of reference types in value of type '(object?, int)' doesn't match target type '(object a, int b)'.
                //         (object a, int b) t3 = (default, default) /*T:<null>!*/ /*CT:(object! a, int b)*/; //2
                Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "(default, default)").WithArguments("(object?, int)", "(object a, int b)").WithLocation(10, 32),
                // (11,32): warning CS8619: Nullability of reference types in value of type '(object?, int)' doesn't match target type '(object a, int b)'.
                //         (object a, int b) t4 = (default(object), default(int)) /*T:(object?, int)*/ /*CT:(object! a, int b)*/; // 3
                Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "(default(object), default(int))").WithArguments("(object?, int)", "(object a, int b)").WithLocation(11, 32)
                );
        }
 
        [Fact]
        public void SpeculativeGetTypeInfo_Basic()
        {
            var source = @"
class C
{
    static object? staticField = null;
    object field = staticField is null ? new object() : staticField;
 
    string M(string? s1)
    {
        if (s1 != null)
        {
            s1.ToString();
        }
 
        s1?.ToString();
 
        s1 = """";
        var s2 = s1 == null ? """" : s1;
 
        return null!;
    }
}";
 
            var comp = CreateCompilation(source, options: WithNullableEnable());
            comp.VerifyDiagnostics();
 
            var syntaxTree = comp.SyntaxTrees[0];
            var root = syntaxTree.GetRoot();
            var model = comp.GetSemanticModel(syntaxTree);
 
            var ifStatement = root.DescendantNodes().OfType<IfStatementSyntax>().Single();
            var conditionalAccessExpression = root.DescendantNodes().OfType<ConditionalAccessExpressionSyntax>().Single();
            var ternary = root.DescendantNodes().OfType<ConditionalExpressionSyntax>().ElementAt(1);
 
            var newReference = (IdentifierNameSyntax)SyntaxFactory.ParseExpression(@"s1");
            var newCoalesce = (AssignmentExpressionSyntax)SyntaxFactory.ParseExpression(@"s1 ??= """"");
 
            verifySpeculativeTypeInfo(ifStatement.SpanStart, PublicNullableFlowState.MaybeNull);
            verifySpeculativeTypeInfo(ifStatement.Statement.SpanStart, PublicNullableFlowState.NotNull);
 
            verifySpeculativeTypeInfo(conditionalAccessExpression.SpanStart, PublicNullableFlowState.MaybeNull);
            verifySpeculativeTypeInfo(conditionalAccessExpression.WhenNotNull.SpanStart, PublicNullableFlowState.NotNull);
 
            verifySpeculativeTypeInfo(ternary.WhenTrue.SpanStart, PublicNullableFlowState.MaybeNull);
            verifySpeculativeTypeInfo(ternary.WhenFalse.SpanStart, PublicNullableFlowState.NotNull);
 
            void verifySpeculativeTypeInfo(int position, PublicNullableFlowState expectedFlowState)
            {
                var specTypeInfo = model.GetSpeculativeTypeInfo(position, newReference, SpeculativeBindingOption.BindAsExpression);
                Assert.Equal(expectedFlowState, specTypeInfo.Nullability.FlowState);
                specTypeInfo = model.GetSpeculativeTypeInfo(position, newCoalesce, SpeculativeBindingOption.BindAsExpression);
                Assert.Equal(PublicNullableFlowState.NotNull, specTypeInfo.Nullability.FlowState);
            }
        }
 
        [Fact, WorkItem(48574, "https://github.com/dotnet/roslyn/issues/48574")]
        public void SpeculativeGetTypeInfo_Constructor()
        {
            var source = @"
class C
{
    public string Prop { get; set; }
    public C()
    {
        if (Prop != null)
        {
            Prop.ToString();
        }
 
        Prop?.ToString();
 
        Prop = """";
        var s2 = Prop == null ? """" : Prop;
    }
}";
 
            var comp = CreateCompilation(source, options: WithNullableEnable());
            comp.VerifyDiagnostics(
                // (5,12): warning CS8618: Non-nullable property 'Prop' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the property as nullable.
                //     public C()
                Diagnostic(ErrorCode.WRN_UninitializedNonNullableField, "C").WithArguments("property", "Prop").WithLocation(5, 12));
 
            var syntaxTree = comp.SyntaxTrees[0];
            var root = syntaxTree.GetRoot();
            var model = comp.GetSemanticModel(syntaxTree);
 
            var ifStatement = root.DescendantNodes().OfType<IfStatementSyntax>().Single();
            var conditionalAccessExpression = root.DescendantNodes().OfType<ConditionalAccessExpressionSyntax>().Single();
            var ternary = root.DescendantNodes().OfType<ConditionalExpressionSyntax>().Single();
 
            var newReference = (IdentifierNameSyntax)SyntaxFactory.ParseExpression(@"Prop");
            var newCoalesce = (AssignmentExpressionSyntax)SyntaxFactory.ParseExpression(@"Prop ??= """"");
 
            verifySpeculativeTypeInfo(ifStatement.SpanStart, PublicNullableFlowState.MaybeNull);
            verifySpeculativeTypeInfo(ifStatement.Statement.SpanStart, PublicNullableFlowState.NotNull);
 
            verifySpeculativeTypeInfo(conditionalAccessExpression.SpanStart, PublicNullableFlowState.MaybeNull);
            verifySpeculativeTypeInfo(conditionalAccessExpression.WhenNotNull.SpanStart, PublicNullableFlowState.NotNull);
 
            verifySpeculativeTypeInfo(ternary.WhenTrue.SpanStart, PublicNullableFlowState.MaybeNull);
            verifySpeculativeTypeInfo(ternary.WhenFalse.SpanStart, PublicNullableFlowState.NotNull);
 
            void verifySpeculativeTypeInfo(int position, PublicNullableFlowState expectedFlowState)
            {
                var specTypeInfo = model.GetSpeculativeTypeInfo(position, newReference, SpeculativeBindingOption.BindAsExpression);
                Assert.Equal(expectedFlowState, specTypeInfo.Nullability.FlowState);
                specTypeInfo = model.GetSpeculativeTypeInfo(position, newCoalesce, SpeculativeBindingOption.BindAsExpression);
                Assert.Equal(PublicNullableFlowState.NotNull, specTypeInfo.Nullability.FlowState);
            }
        }
 
        [Fact, WorkItem(45398, "https://github.com/dotnet/roslyn/issues/45398")]
        public void VarInLambda_GetTypeInfo()
        {
            var source = @"
#nullable enable
using System;
class C
{
    private static string s_data;
    static void Main()
    {
        Action a = () => {
            var v = s_data;
            v = GetNullableString();
        };
    }
    static string? GetNullableString() => null;
}";
 
            var comp = CreateCompilation(source, options: WithNullableEnable());
            comp.VerifyDiagnostics(
                // (6,27): warning CS8618: Non-nullable field 's_data' is uninitialized. Consider declaring the field as nullable.
                //     private static string s_data;
                Diagnostic(ErrorCode.WRN_UninitializedNonNullableField, "s_data").WithArguments("field", "s_data").WithLocation(6, 27),
                // (6,27): warning CS0649: Field 'C.s_data' is never assigned to, and will always have its default value null
                //     private static string s_data;
                Diagnostic(ErrorCode.WRN_UnassignedInternalField, "s_data").WithArguments("C.s_data", "null").WithLocation(6, 27));
 
            var syntaxTree = comp.SyntaxTrees[0];
            var root = syntaxTree.GetRoot();
            var model = comp.GetSemanticModel(syntaxTree);
 
            var lambda = root.DescendantNodes().OfType<LambdaExpressionSyntax>().Single();
            var varDecl = lambda.DescendantNodes().OfType<VariableDeclarationSyntax>().Single();
 
            var type = model.GetTypeInfo(varDecl.Type);
            Assert.Equal(PublicNullableFlowState.MaybeNull, type.Nullability.FlowState);
            Assert.Equal(PublicNullableAnnotation.Annotated, type.Nullability.Annotation);
        }
 
        [Fact, WorkItem(45398, "https://github.com/dotnet/roslyn/issues/45398")]
        public void VarInLambda_ParameterMismatch_GetTypeInfo()
        {
            var source = @"
#nullable enable
using System;
class C
{
    private static string s_data;
    static void Main()
    {
        Action<string> a = () => {
            var v = s_data;
            v = GetNullableString();
        };
    }
    static string? GetNullableString() => null;
}";
 
            var comp = CreateCompilation(source, options: WithNullableEnable());
            comp.VerifyDiagnostics(
                // (6,27): warning CS8618: Non-nullable field 's_data' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the field as nullable.
                //     private static string s_data;
                Diagnostic(ErrorCode.WRN_UninitializedNonNullableField, "s_data").WithArguments("field", "s_data").WithLocation(6, 27),
                // (6,27): warning CS0649: Field 'C.s_data' is never assigned to, and will always have its default value null
                //     private static string s_data;
                Diagnostic(ErrorCode.WRN_UnassignedInternalField, "s_data").WithArguments("C.s_data", "null").WithLocation(6, 27),
                // (9,31): error CS1593: Delegate 'Action<string>' does not take 0 arguments
                //         Action<string> a = () => {
                Diagnostic(ErrorCode.ERR_BadDelArgCount, "=>").WithArguments("System.Action<string>", "0").WithLocation(9, 31));
 
            var syntaxTree = comp.SyntaxTrees[0];
            var root = syntaxTree.GetRoot();
            var model = comp.GetSemanticModel(syntaxTree);
 
            var lambda = root.DescendantNodes().OfType<LambdaExpressionSyntax>().Single();
            var varDecl = lambda.DescendantNodes().OfType<VariableDeclarationSyntax>().Single();
 
            var type = model.GetTypeInfo(varDecl.Type);
            Assert.Equal(PublicNullableFlowState.None, type.Nullability.FlowState);
            Assert.Equal(PublicNullableAnnotation.None, type.Nullability.Annotation);
        }
 
        [Fact, WorkItem(45398, "https://github.com/dotnet/roslyn/issues/45398")]
        public void VarInLambda_ErrorDelegateType_GetTypeInfo()
        {
            var source = @"
#nullable enable
 
class C
{
    private static string s_data;
    static void Main()
    {
        NonexistentDelegateType a = () => {
            var v = s_data;
            v = GetNullableString();
        };
    }
    static string? GetNullableString() => null;
}";
 
            var comp = CreateCompilation(source, options: WithNullableEnable());
            comp.VerifyDiagnostics(
                // (6,27): warning CS8618: Non-nullable field 's_data' is uninitialized. Consider declaring the field as nullable.
                //     private static string s_data;
                Diagnostic(ErrorCode.WRN_UninitializedNonNullableField, "s_data").WithArguments("field", "s_data").WithLocation(6, 27),
                // (6,27): warning CS0649: Field 'C.s_data' is never assigned to, and will always have its default value null
                //     private static string s_data;
                Diagnostic(ErrorCode.WRN_UnassignedInternalField, "s_data").WithArguments("C.s_data", "null").WithLocation(6, 27),
                // (9,9): error CS0246: The type or namespace name 'NonexistentDelegateType' could not be found (are you missing a using directive or an assembly reference?)
                //         NonexistentDelegateType a = () => {
                Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "NonexistentDelegateType").WithArguments("NonexistentDelegateType").WithLocation(9, 9));
 
            var syntaxTree = comp.SyntaxTrees[0];
            var root = syntaxTree.GetRoot();
            var model = comp.GetSemanticModel(syntaxTree);
 
            var lambda = root.DescendantNodes().OfType<LambdaExpressionSyntax>().Single();
            var varDecl = lambda.DescendantNodes().OfType<VariableDeclarationSyntax>().Single();
 
            var type = model.GetTypeInfo(varDecl.Type);
            Assert.Equal(PublicNullableFlowState.None, type.Nullability.FlowState);
            Assert.Equal(PublicNullableAnnotation.None, type.Nullability.Annotation);
        }
 
        [Fact]
        public void FeatureFlagTurnsOffNullableAnalysis()
        {
            var source =
@"
#nullable enable
class C
{
    object field = null;
 
    void M()
    {
        object o = null;
    }
}
";
 
            var featureFlagOff = TestOptions.Regular8.WithFeature("run-nullable-analysis", "never");
 
            var comp = CreateCompilation(source, options: WithNullableEnable(), parseOptions: featureFlagOff);
            comp.VerifyDiagnostics(
                // (5,12): warning CS0414: The field 'C.field' is assigned but its value is never used
                //     object field = null;
                Diagnostic(ErrorCode.WRN_UnreferencedFieldAssg, "field").WithArguments("C.field").WithLocation(5, 12),
                // (9,16): warning CS0219: The variable 'o' is assigned but its value is never used
                //         object o = null;
                Diagnostic(ErrorCode.WRN_UnreferencedVarAssg, "o").WithArguments("o").WithLocation(9, 16));
 
            Assert.False(isNullableAnalysisEnabled(comp));
 
            comp = CreateCompilation(source, options: WithNullableEnable());
            comp.VerifyDiagnostics(
                // (5,12): warning CS0414: The field 'C.field' is assigned but its value is never used
                //     object field = null;
                Diagnostic(ErrorCode.WRN_UnreferencedFieldAssg, "field").WithArguments("C.field").WithLocation(5, 12),
                // (5,20): warning CS8625: Cannot convert null literal to non-nullable reference type.
                //     object field = null;
                Diagnostic(ErrorCode.WRN_NullAsNonNullable, "null").WithLocation(5, 20),
                // (9,16): warning CS0219: The variable 'o' is assigned but its value is never used
                //         object o = null;
                Diagnostic(ErrorCode.WRN_UnreferencedVarAssg, "o").WithArguments("o").WithLocation(9, 16),
                // (9,20): warning CS8600: Converting null literal or possible null value to non-nullable type.
                //         object o = null;
                Diagnostic(ErrorCode.WRN_ConvertingNullableToNonNullable, "null").WithLocation(9, 20));
 
            Assert.True(isNullableAnalysisEnabled(comp));
 
            static bool isNullableAnalysisEnabled(CSharpCompilation comp)
            {
                var tree = (CSharpSyntaxTree)comp.SyntaxTrees.Single();
                return comp.IsNullableAnalysisEnabledIn(tree, new Text.TextSpan(0, tree.Length));
            }
        }
 
        private class CSharp73ProvidesNullableSemanticInfo_Analyzer : DiagnosticAnalyzer
        {
            public int HitCount;
 
            private static readonly DiagnosticDescriptor Descriptor =
               new DiagnosticDescriptor("XY0000", "Test", "Test", "Test", DiagnosticSeverity.Warning, true, "Test", "Test");
 
            public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics
            => ImmutableArray.Create(Descriptor);
 
            public override void Initialize(AnalysisContext context)
            {
                context.RegisterSyntaxNodeAction(AnalyzeMemberAccess, SyntaxKind.SimpleMemberAccessExpression);
            }
 
            private void AnalyzeMemberAccess(SyntaxNodeAnalysisContext context)
            {
                var node = (MemberAccessExpressionSyntax)context.Node;
                var model = context.SemanticModel;
                var info = model.GetTypeInfo(node.Expression);
 
                Assert.Equal(PublicNullableAnnotation.Annotated, info.Nullability.Annotation);
                Assert.Equal(PublicNullableFlowState.MaybeNull, info.Nullability.FlowState);
 
                Interlocked.Increment(ref HitCount);
            }
        }
 
        [Fact]
        public void CSharp73ProvidesNullableSemanticInfo()
        {
            var source = @"
class C
{
    void M(string s)
    {
        if (s == null)
        {
            s.ToString();
        }
    }
}
";
            var comp = CreateCompilation(source, options: WithNullableEnable(), parseOptions: TestOptions.Regular7_3, skipUsesIsNullable: true);
            comp.VerifyDiagnostics(
                // error CS8630: Invalid 'NullableContextOptions' value: 'Enable' for C# 7.3. Please use language version '8.0' or greater.
                Diagnostic(ErrorCode.ERR_NullableOptionNotAvailable).WithArguments("NullableContextOptions", "Enable", "7.3", "8.0").WithLocation(1, 1)
                );
 
            var analyzer = new CSharp73ProvidesNullableSemanticInfo_Analyzer();
            comp.GetAnalyzerDiagnostics(new[] { analyzer }).Verify();
            Assert.Equal(1, analyzer.HitCount);
        }
 
        [Fact]
        public void SymbolInfo_Invocation_InferredArguments()
        {
            var source = @"
class C
{
    T Identity<T>(T t) => t;
 
    void M(string? s)
    {
        _ = Identity(s);
        if (s is null) return;
        _ = Identity(s);
    }
}";
 
            var comp = CreateCompilation(source, options: WithNullableEnable());
            comp.VerifyDiagnostics();
 
            var syntaxTree = comp.SyntaxTrees[0];
            var root = syntaxTree.GetRoot();
            var model = comp.GetSemanticModel(syntaxTree);
 
            var invocations = root.DescendantNodes().OfType<InvocationExpressionSyntax>().ToArray();
 
            var symbolInfo = model.GetSymbolInfo(invocations[0]);
            verifySymbolInfo((IMethodSymbol)symbolInfo.Symbol, PublicNullableAnnotation.Annotated);
            symbolInfo = model.GetSymbolInfo(invocations[1]);
            verifySymbolInfo((IMethodSymbol)symbolInfo.Symbol, PublicNullableAnnotation.NotAnnotated);
 
            static void verifySymbolInfo(IMethodSymbol methodSymbol, PublicNullableAnnotation expectedAnnotation)
            {
                Assert.Equal(expectedAnnotation, methodSymbol.TypeArgumentNullableAnnotations.Single());
                Assert.Equal(expectedAnnotation, methodSymbol.TypeArguments.Single().NullableAnnotation);
                Assert.Equal(expectedAnnotation, methodSymbol.Parameters.Single().NullableAnnotation);
                Assert.Equal(expectedAnnotation, methodSymbol.Parameters.Single().Type.NullableAnnotation);
                Assert.Equal(expectedAnnotation, methodSymbol.ReturnNullableAnnotation);
                Assert.Equal(expectedAnnotation, methodSymbol.ReturnType.NullableAnnotation);
            }
        }
 
        [Fact]
        public void SymbolInfo_Invocation_LocalFunction()
        {
            var source = @"
using System.Collections.Generic;
class C
{
 
    void M(string? s)
    {
        _ = CreateList(s);
        if (s is null) return;
        _ = CreateList(s);
 
        List<T> CreateList<T>(T t) => null!;
    }
}";
 
            var comp = CreateCompilation(source, options: WithNullableEnable());
            comp.VerifyDiagnostics();
 
            var syntaxTree = comp.SyntaxTrees[0];
            var root = syntaxTree.GetRoot();
            var model = comp.GetSemanticModel(syntaxTree);
 
            var invocations = root.DescendantNodes().OfType<InvocationExpressionSyntax>().ToArray();
 
            var symbolInfo = model.GetSymbolInfo(invocations[0]);
            verifySymbolInfo((IMethodSymbol)symbolInfo.Symbol, PublicNullableAnnotation.Annotated);
            symbolInfo = model.GetSymbolInfo(invocations[1]);
            verifySymbolInfo((IMethodSymbol)symbolInfo.Symbol, PublicNullableAnnotation.NotAnnotated);
 
            static void verifySymbolInfo(IMethodSymbol methodSymbol, PublicNullableAnnotation expectedAnnotation)
            {
                Assert.Equal(expectedAnnotation, methodSymbol.TypeArgumentNullableAnnotations.Single());
                Assert.Equal(expectedAnnotation, methodSymbol.TypeArguments.Single().NullableAnnotation);
                Assert.Equal(expectedAnnotation, methodSymbol.Parameters.Single().NullableAnnotation);
                Assert.Equal(expectedAnnotation, methodSymbol.Parameters.Single().Type.NullableAnnotation);
                Assert.Equal(expectedAnnotation, ((INamedTypeSymbol)methodSymbol.ReturnType).TypeArgumentNullableAnnotations.Single());
                Assert.Equal(expectedAnnotation, ((INamedTypeSymbol)methodSymbol.ReturnType).TypeArgumentNullableAnnotations().Single());
            }
        }
 
        [Fact]
        public void GetDeclaredSymbol_Locals_Inference()
        {
            var source = @"
class C
{
    void M(string? s1, string s2)
    {
        var o1 = s1;
        var o2 = s2;
        if (s1 == null) return;
        var o3 = s1;
        s2 = null;
        var o4 = s2;        
    }
}";
 
            var comp = CreateCompilation(source, options: WithNullableEnable());
            comp.VerifyDiagnostics(
                // (10,14): warning CS8600: Converting null literal or possible null value to non-nullable type.
                //         s2 = null;
                Diagnostic(ErrorCode.WRN_ConvertingNullableToNonNullable, "null").WithLocation(10, 14));
 
            var syntaxTree = comp.SyntaxTrees[0];
            var root = syntaxTree.GetRoot();
            var model = comp.GetSemanticModel(syntaxTree);
 
            var declarations = root.DescendantNodes().OfType<VariableDeclaratorSyntax>().ToList();
 
            assertAnnotation(declarations[0]);
            assertAnnotation(declarations[1]);
            assertAnnotation(declarations[2]);
            assertAnnotation(declarations[3]);
 
            void assertAnnotation(VariableDeclaratorSyntax variable)
            {
                var symbol = (ILocalSymbol)model.GetDeclaredSymbol(variable);
                Assert.Equal(PublicNullableAnnotation.Annotated, symbol.NullableAnnotation);
                Assert.Equal(PublicNullableAnnotation.Annotated, symbol.Type.NullableAnnotation);
 
                var typeInfo = model.GetTypeInfoAndVerifyIOperation(((VariableDeclarationSyntax)variable.Parent).Type);
                Assert.Equal(PublicNullableFlowState.MaybeNull, typeInfo.Nullability.FlowState);
                Assert.Equal(PublicNullableFlowState.MaybeNull, typeInfo.ConvertedNullability.FlowState);
                Assert.Equal(CodeAnalysis.NullableAnnotation.Annotated, typeInfo.Nullability.Annotation);
                Assert.Equal(CodeAnalysis.NullableAnnotation.Annotated, typeInfo.ConvertedNullability.Annotation);
            }
        }
 
        [Fact]
        public void GetDeclaredSymbol_Locals_NoInference()
        {
            // All declarations are the opposite of inference
            var source = @"
#pragma warning disable CS8600
class C
{
    void M(string? s1, string s2)
    {
        string o1 = s1;
        string? o2 = s2;
        if (s1 == null) return;
        string? o3 = s1;
        s2 = null;
        string o4 = s2;        
    }
}";
 
            var comp = CreateCompilation(source, options: WithNullableEnable());
            comp.VerifyDiagnostics();
 
            var syntaxTree = comp.SyntaxTrees[0];
            var root = syntaxTree.GetRoot();
            var model = comp.GetSemanticModel(syntaxTree);
 
            var declarations = root.DescendantNodes().OfType<VariableDeclaratorSyntax>().ToList();
 
            assertAnnotation(declarations[0], PublicNullableAnnotation.NotAnnotated);
            assertAnnotation(declarations[1], PublicNullableAnnotation.Annotated);
            assertAnnotation(declarations[2], PublicNullableAnnotation.Annotated);
            assertAnnotation(declarations[3], PublicNullableAnnotation.NotAnnotated);
 
            void assertAnnotation(VariableDeclaratorSyntax variable, PublicNullableAnnotation expectedAnnotation)
            {
                var symbol = (ILocalSymbol)model.GetDeclaredSymbol(variable);
                Assert.Equal(expectedAnnotation, symbol.NullableAnnotation);
                Assert.Equal(expectedAnnotation, symbol.Type.NullableAnnotation);
            }
        }
 
        [Fact]
        public void GetDeclaredSymbol_SingleVariableDeclaration_Inference()
        {
            var source1 = @"
#pragma warning disable CS8600
class C
{
    void M(string? s1, string s2)
    {
        var (o1, o2) = (s1, s2);
        var (o3, o4) = (s2, s1);
        if (s1 == null) return;
        var (o5, o6) = (s1, s2);
        s2 = null;
        var (o7, o8) = (s1, s2);
    }
}";
 
            verifyCompilation(source1);
 
            var source2 = @"
#pragma warning disable CS8600
class C
{
    void M(string? s1, string s2)
    {
        (var o1, var o2) = (s1, s2);
        (var o3, var o4) = (s2, s1);
        if (s1 == null) return;
        (var o5, var o6) = (s1, s2);
        s2 = null;
        (var o7, var o8) = (s1, s2);
    }
}";
 
            verifyCompilation(source2);
 
            void verifyCompilation(string source)
            {
                var comp = CreateCompilation(source, options: WithNullableEnable());
                comp.VerifyDiagnostics();
 
                var syntaxTree = comp.SyntaxTrees[0];
                var root = syntaxTree.GetRoot();
                var model = comp.GetSemanticModel(syntaxTree);
 
                var declarations = root.DescendantNodes().OfType<AssignmentExpressionSyntax>().ToList();
 
                assertAnnotation(declarations[0], PublicNullableAnnotation.Annotated, PublicNullableAnnotation.Annotated);
                assertAnnotation(declarations[1], PublicNullableAnnotation.Annotated, PublicNullableAnnotation.Annotated);
                assertAnnotation(declarations[2], PublicNullableAnnotation.Annotated, PublicNullableAnnotation.Annotated);
                assertAnnotation(declarations[4], PublicNullableAnnotation.Annotated, PublicNullableAnnotation.Annotated);
 
                void assertAnnotation(AssignmentExpressionSyntax variable, PublicNullableAnnotation expectedAnnotation1, PublicNullableAnnotation expectedAnnotation2)
                {
                    var symbols = variable.DescendantNodes().OfType<SingleVariableDesignationSyntax>().Select(s => model.GetDeclaredSymbol(s)).Cast<ILocalSymbol>().ToList();
                    Assert.Equal(expectedAnnotation1, symbols[0].NullableAnnotation);
                    Assert.Equal(expectedAnnotation1, symbols[0].Type.NullableAnnotation);
                    Assert.Equal(expectedAnnotation2, symbols[1].NullableAnnotation);
                    Assert.Equal(expectedAnnotation2, symbols[1].Type.NullableAnnotation);
                }
            }
        }
 
        [Fact]
        public void GetDeclaredSymbol_SingleVariableDeclaration_MixedInference()
        {
            var source = @"
#pragma warning disable CS8600
class C
{
    void M(string? s1, string s2)
    {
        (string o1, var o2) = (s1, s2);
        (string? o3, var o4) = (s2, s1);
        if (s1 == null) return;
        (var o5, string? o6) = (s1, s2);
        s2 = null;
        (var o7, string o8) = (s1, s2);
    }
}";
 
            var comp = CreateCompilation(source, options: WithNullableEnable());
            comp.VerifyDiagnostics();
 
            var syntaxTree = comp.SyntaxTrees[0];
            var root = syntaxTree.GetRoot();
            var model = comp.GetSemanticModel(syntaxTree);
 
            var declarations = root.DescendantNodes().OfType<AssignmentExpressionSyntax>().ToList();
 
            assertAnnotation(declarations[0], PublicNullableAnnotation.NotAnnotated, PublicNullableAnnotation.Annotated);
            assertAnnotation(declarations[1], PublicNullableAnnotation.Annotated, PublicNullableAnnotation.Annotated);
            assertAnnotation(declarations[2], PublicNullableAnnotation.Annotated, PublicNullableAnnotation.Annotated);
            assertAnnotation(declarations[4], PublicNullableAnnotation.Annotated, PublicNullableAnnotation.NotAnnotated);
 
            void assertAnnotation(AssignmentExpressionSyntax variable, PublicNullableAnnotation expectedAnnotation1, PublicNullableAnnotation expectedAnnotation2)
            {
                var symbols = variable.DescendantNodes().OfType<SingleVariableDesignationSyntax>().Select(s => model.GetDeclaredSymbol(s)).Cast<ILocalSymbol>().ToList();
                Assert.Equal(expectedAnnotation1, symbols[0].NullableAnnotation);
                Assert.Equal(expectedAnnotation1, symbols[0].Type.NullableAnnotation);
                Assert.Equal(expectedAnnotation2, symbols[1].NullableAnnotation);
                Assert.Equal(expectedAnnotation2, symbols[1].Type.NullableAnnotation);
            }
        }
 
        [Fact]
        public void GetDeclaredSymbol_SpeculativeModel()
        {
            // All declarations are the opposite of inference
            var source = @"
#pragma warning disable CS8600
class C
{
    void M(string? s1, string s2)
    {
        string o1 = s1;
        string? o2 = s2;
        if (s1 == null) return;
        string? o3 = s1;
        s2 = null;
        string o4 = s2;        
    }
}";
 
            var comp = CreateCompilation(source, options: WithNullableEnable());
            comp.VerifyDiagnostics();
 
            var syntaxTree = comp.SyntaxTrees[0];
            var root = syntaxTree.GetRoot();
            var model = comp.GetSemanticModel(syntaxTree);
 
            var s2Assignment = root.DescendantNodes().OfType<AssignmentExpressionSyntax>().Single();
            var lastDeclaration = root.DescendantNodes().OfType<VariableDeclaratorSyntax>().ElementAt(3);
            var newDeclaration = SyntaxFactory.ParseStatement("var o5 = s2;");
            var newDeclarator = newDeclaration.DescendantNodes().OfType<VariableDeclaratorSyntax>().Single();
 
            Assert.True(model.TryGetSpeculativeSemanticModel(s2Assignment.SpanStart, newDeclaration, out var specModel));
            Assert.Equal(PublicNullableAnnotation.Annotated, ((ILocalSymbol)specModel.GetDeclaredSymbol(newDeclarator)).NullableAnnotation);
            Assert.Equal(PublicNullableAnnotation.Annotated, ((ILocalSymbol)specModel.GetDeclaredSymbol(newDeclarator)).Type.NullableAnnotation);
 
            Assert.True(model.TryGetSpeculativeSemanticModel(lastDeclaration.SpanStart, newDeclaration, out specModel));
            Assert.Equal(PublicNullableAnnotation.Annotated, ((ILocalSymbol)specModel.GetDeclaredSymbol(newDeclarator)).NullableAnnotation);
            Assert.Equal(PublicNullableAnnotation.Annotated, ((ILocalSymbol)specModel.GetDeclaredSymbol(newDeclarator)).Type.NullableAnnotation);
        }
 
        [Fact]
        public void GetDeclaredSymbol_Using()
        {
            var source = @"
using System;
using System.Threading.Tasks;
class C : IDisposable, IAsyncDisposable
{
    public void Dispose() => throw null!;
    public ValueTask DisposeAsync() => throw null!;
    async void M(C? c1)
    {
        using var c2 = c1;
        using var c3 = c1 ?? new C();
        using (var c4 = c1) {}
        using (var c5 = c1 ?? new C()) {}
        await using (var c6 = c1) {}
        await using (var c6 = c1 ?? new C()) {}
    }
}
";
 
            var comp = CreateCompilationWithTasksExtensions(new[] { source, s_IAsyncEnumerable }, options: WithNullableEnable());
            comp.VerifyDiagnostics();
 
            var syntaxTree = comp.SyntaxTrees[0];
            var root = syntaxTree.GetRoot();
            var model = comp.GetSemanticModel(syntaxTree);
 
            var declarations = root.DescendantNodes().OfType<VariableDeclaratorSyntax>().ToList();
 
            assertAnnotation(declarations[0], PublicNullableAnnotation.Annotated);
            assertAnnotation(declarations[1], PublicNullableAnnotation.Annotated);
            assertAnnotation(declarations[2], PublicNullableAnnotation.Annotated);
            assertAnnotation(declarations[3], PublicNullableAnnotation.Annotated);
            assertAnnotation(declarations[4], PublicNullableAnnotation.Annotated);
            assertAnnotation(declarations[5], PublicNullableAnnotation.Annotated);
 
            void assertAnnotation(VariableDeclaratorSyntax variable, PublicNullableAnnotation expectedAnnotation)
            {
                var symbol = (ILocalSymbol)model.GetDeclaredSymbol(variable);
                Assert.Equal(expectedAnnotation, symbol.NullableAnnotation);
                Assert.Equal(expectedAnnotation, symbol.Type.NullableAnnotation);
            }
        }
 
        [Fact]
        public void GetDeclaredSymbol_Fixed()
        {
            var source = @"
class C
{
    unsafe void M(object? o)
    {
        fixed (var o1 = o ?? new object())
        {
        }
    }
}
";
 
            var comp = CreateCompilation(source, options: WithNullableEnable().WithAllowUnsafe(true));
            comp.VerifyDiagnostics(
                // (6,20): error CS0821: Implicitly-typed local variables cannot be fixed
                //         fixed (var o1 = o ?? new object())
                Diagnostic(ErrorCode.ERR_ImplicitlyTypedLocalCannotBeFixed, "o1 = o ?? new object()").WithLocation(6, 20));
 
            var syntaxTree = comp.SyntaxTrees[0];
            var root = syntaxTree.GetRoot();
            var model = comp.GetSemanticModel(syntaxTree);
 
            var declaration = root.DescendantNodes().OfType<VariableDeclaratorSyntax>().Single();
            var symbol = (ILocalSymbol)model.GetDeclaredSymbol(declaration);
            Assert.Equal(PublicNullableAnnotation.Annotated, symbol.NullableAnnotation);
            Assert.Equal(PublicNullableAnnotation.Annotated, symbol.Type.NullableAnnotation);
        }
 
        [Fact]
        public void GetDeclaredSymbol_ForLoop()
        {
            var source = @"
class C
{
    void M(object? o1, object o2)
    {
        for (var o3 = o1; false; ) {}
        for (var o4 = o1 ?? o2; false; ) {}
        for (var o5 = o1, o6 = o2; false; ) {}
    }
}
";
            var comp = CreateCompilation(source, options: WithNullableEnable());
            comp.VerifyDiagnostics(
                // (8,14): error CS0819: Implicitly-typed variables cannot have multiple declarators
                //         for (var o5 = o1, o6 = o2; false; ) {}
                Diagnostic(ErrorCode.ERR_ImplicitlyTypedVariableMultipleDeclarator, "var o5 = o1, o6 = o2").WithLocation(8, 14));
 
            var syntaxTree = comp.SyntaxTrees[0];
            var root = syntaxTree.GetRoot();
            var model = comp.GetSemanticModel(syntaxTree);
 
            var declarations = root.DescendantNodes().OfType<VariableDeclaratorSyntax>().ToList();
 
            assertAnnotation(declarations[0], PublicNullableAnnotation.Annotated);
            assertAnnotation(declarations[1], PublicNullableAnnotation.Annotated);
            assertAnnotation(declarations[2], PublicNullableAnnotation.Annotated);
            assertAnnotation(declarations[3], PublicNullableAnnotation.Annotated);
 
            void assertAnnotation(VariableDeclaratorSyntax variable, PublicNullableAnnotation expectedAnnotation)
            {
                var symbol = (ILocalSymbol)model.GetDeclaredSymbol(variable);
                Assert.Equal(expectedAnnotation, symbol.NullableAnnotation);
                Assert.Equal(expectedAnnotation, symbol.Type.NullableAnnotation);
            }
        }
 
        [Fact]
        public void GetDeclaredSymbol_OutVariable()
        {
            var source = @"
class C
{
    void Out(out object? o1, out object o2) => throw null!;
    void M()
    {
        Out(out var o1, out var o2);
    }
}";
 
            var comp = CreateCompilation(source, options: WithNullableEnable());
            comp.VerifyDiagnostics();
 
            var syntaxTree = comp.SyntaxTrees[0];
            var root = syntaxTree.GetRoot();
            var model = comp.GetSemanticModel(syntaxTree);
 
            var declarations = root.DescendantNodes().OfType<SingleVariableDesignationSyntax>().ToList();
            assertAnnotation(declarations[0], PublicNullableAnnotation.Annotated);
            assertAnnotation(declarations[1], PublicNullableAnnotation.Annotated);
 
            void assertAnnotation(SingleVariableDesignationSyntax variable, PublicNullableAnnotation expectedAnnotation)
            {
                var symbol = (ILocalSymbol)model.GetDeclaredSymbol(variable);
                Assert.Equal(expectedAnnotation, symbol.NullableAnnotation);
                Assert.Equal(expectedAnnotation, symbol.Type.NullableAnnotation);
 
                var typeInfo = model.GetTypeInfoAndVerifyIOperation(((DeclarationExpressionSyntax)variable.Parent).Type);
                Assert.Equal("System.Object?", typeInfo.Type.ToTestDisplayString());
                Assert.Equal("System.Object?", typeInfo.ConvertedType.ToTestDisplayString());
                Assert.Equal(PublicNullableAnnotation.Annotated, typeInfo.Nullability.Annotation);
                Assert.Equal(PublicNullableFlowState.MaybeNull, typeInfo.Nullability.FlowState);
            }
        }
 
        [Fact]
        public void GetDeclaredSymbol_OutVariable_WithTypeInference()
        {
            var source = @"
#pragma warning disable CS8600
class C
{
    void Out<T>(T o1, out T o2) => throw null!;
    void M(object o1, object? o2)
    {
        Out(o1, out var o3);
        Out(o2, out var o4);
        o1 = null;
        Out(o1, out var o5);
        _ = o2 ?? throw null!;
        Out(o2, out var o6);
    }
}";
 
            var comp = CreateCompilation(source, options: WithNullableEnable());
            comp.VerifyDiagnostics();
 
            var syntaxTree = comp.SyntaxTrees[0];
            var root = syntaxTree.GetRoot();
            var model = comp.GetSemanticModel(syntaxTree);
 
            var declarations = root.DescendantNodes().OfType<SingleVariableDesignationSyntax>().ToList();
            assertAnnotation(declarations[0], PublicNullableAnnotation.Annotated);
            assertAnnotation(declarations[1], PublicNullableAnnotation.Annotated);
            assertAnnotation(declarations[2], PublicNullableAnnotation.Annotated);
            assertAnnotation(declarations[3], PublicNullableAnnotation.Annotated);
 
            void assertAnnotation(SingleVariableDesignationSyntax variable, PublicNullableAnnotation expectedAnnotation)
            {
                var symbol = (ILocalSymbol)model.GetDeclaredSymbol(variable);
                Assert.Equal(expectedAnnotation, symbol.NullableAnnotation);
                Assert.Equal(expectedAnnotation, symbol.Type.NullableAnnotation);
            }
        }
 
        [Fact]
        public void GetDeclaredSymbol_Switch()
        {
            var source = @"
class C
{
    void M(object? o)
    {
        switch (o)
        {
            case object o1:
                break;
            case var o2:
                break;
        }
 
        _ = o switch { {} o1 => o1, var o2 => o2 };
    }
}";
 
            var comp = CreateCompilation(source, options: WithNullableEnable());
            comp.VerifyDiagnostics();
 
            var syntaxTree = comp.SyntaxTrees[0];
            var root = syntaxTree.GetRoot();
            var model = comp.GetSemanticModel(syntaxTree);
 
            var declarations = root.DescendantNodes().OfType<SingleVariableDesignationSyntax>().ToList();
 
            assertAnnotation(declarations[0], PublicNullableAnnotation.NotAnnotated);
            assertAnnotation(declarations[1], PublicNullableAnnotation.Annotated);
            assertAnnotation(declarations[2], PublicNullableAnnotation.Annotated);
            assertAnnotation(declarations[3], PublicNullableAnnotation.Annotated);
 
            void assertAnnotation(SingleVariableDesignationSyntax variable, PublicNullableAnnotation expectedAnnotation)
            {
                var symbol = (ILocalSymbol)model.GetDeclaredSymbol(variable);
                Assert.Equal(expectedAnnotation, symbol.NullableAnnotation);
                Assert.Equal(expectedAnnotation, symbol.Type.NullableAnnotation);
            }
        }
 
        [Fact]
        public void GetDeclaredSymbol_InLambda()
        {
            var source = @"
using System;
class C
{
    void M(object? o)
    {
        Action a1 = () =>
        {
            var o1 = o;
        };
 
        if (o == null) return;
 
        Action a2 = () =>
        {
            var o1 = o;
        };
    }
}";
 
            var comp = CreateCompilation(source, options: WithNullableEnable());
            comp.VerifyDiagnostics();
 
            var syntaxTree = comp.SyntaxTrees[0];
            var root = syntaxTree.GetRoot();
            var model = comp.GetSemanticModel(syntaxTree);
 
            var declarations = root.DescendantNodes().OfType<VariableDeclaratorSyntax>().ToList();
 
            assertAnnotation(declarations[1], PublicNullableAnnotation.Annotated);
            assertAnnotation(declarations[3], PublicNullableAnnotation.Annotated);
 
            void assertAnnotation(VariableDeclaratorSyntax variable, PublicNullableAnnotation expectedAnnotation)
            {
                var symbol = (ILocalSymbol)model.GetDeclaredSymbol(variable);
                Assert.Equal(expectedAnnotation, symbol.NullableAnnotation);
                Assert.Equal(expectedAnnotation, symbol.Type.NullableAnnotation);
            }
        }
 
        [Fact]
        public void GetDeclaredSymbol_Foreach_Inferred()
        {
            var source = @"
#pragma warning disable CS8600
using System.Collections.Generic;
class C
{
    List<T> GetList<T>(T t) => throw null!;
    void M(object o1, object? o2)
    {
        foreach (var o in GetList(o1)) {}
        foreach (var o in GetList(o2)) {}
        o1 = null;
        foreach (var o in GetList(o1)) {}
        _  = o2 ?? throw null!;
        foreach (var o in GetList(o2)) {}
    }
}";
 
            var comp = CreateCompilation(source, options: WithNullableEnable());
            comp.VerifyDiagnostics();
 
            var syntaxTree = comp.SyntaxTrees[0];
            var root = syntaxTree.GetRoot();
            var model = comp.GetSemanticModel(syntaxTree);
 
            var declarations = root.DescendantNodes().OfType<ForEachStatementSyntax>().ToList();
 
            assertAnnotation(declarations[0]);
            assertAnnotation(declarations[1]);
            assertAnnotation(declarations[2]);
            assertAnnotation(declarations[3]);
 
            void assertAnnotation(ForEachStatementSyntax foreachStatement)
            {
                var symbol = model.GetDeclaredSymbol(foreachStatement);
                Assert.Equal(PublicNullableAnnotation.Annotated, symbol.NullableAnnotation);
                Assert.Equal(PublicNullableAnnotation.Annotated, symbol.Type.NullableAnnotation);
 
                var typeInfo = model.GetTypeInfoAndVerifyIOperation(foreachStatement.Type);
                Assert.Equal(PublicNullableAnnotation.Annotated, typeInfo.Nullability.Annotation);
                Assert.Equal(PublicNullableAnnotation.Annotated, typeInfo.ConvertedNullability.Annotation);
                Assert.Equal(PublicNullableAnnotation.Annotated, typeInfo.Type.NullableAnnotation);
                Assert.Equal(PublicNullableAnnotation.Annotated, typeInfo.ConvertedType.NullableAnnotation);
            }
        }
 
        [Fact]
        public void GetDeclaredSymbol_Foreach_NoInference()
        {
            var source = @"
#pragma warning disable CS8600
using System.Collections.Generic;
class C
{
    List<T> GetList<T>(T t) => throw null!;
    void M(object o1, object? o2)
    {
        foreach (object? o in GetList(o1)) {}
        foreach (object o in GetList(o2)) {}
        o1 = null;
        foreach (object o in GetList(o1)) {}
        _  = o2 ?? throw null!;
        foreach (object? o in GetList(o2)) {}
    }
}";
 
            var comp = CreateCompilation(source, options: WithNullableEnable());
            comp.VerifyDiagnostics();
 
            var syntaxTree = comp.SyntaxTrees[0];
            var root = syntaxTree.GetRoot();
            var model = comp.GetSemanticModel(syntaxTree);
 
            var declarations = root.DescendantNodes().OfType<ForEachStatementSyntax>().ToList();
 
            assertAnnotation(declarations[0], PublicNullableAnnotation.Annotated);
            assertAnnotation(declarations[1], PublicNullableAnnotation.NotAnnotated);
            assertAnnotation(declarations[2], PublicNullableAnnotation.NotAnnotated);
            assertAnnotation(declarations[3], PublicNullableAnnotation.Annotated);
 
            void assertAnnotation(ForEachStatementSyntax variable, PublicNullableAnnotation expectedAnnotation)
            {
                var symbol = model.GetDeclaredSymbol(variable);
                Assert.Equal(expectedAnnotation, symbol.NullableAnnotation);
                Assert.Equal(expectedAnnotation, symbol.Type.NullableAnnotation);
            }
        }
 
        [Fact]
        public void GetDeclaredSymbol_Foreach_Tuples_MixedInference()
        {
            var source = @"
#pragma warning disable CS8600
using System.Collections.Generic;
class C
{
    List<(T, T)> GetList<T>(T t) => throw null!;
    void M(object o1, object? o2)
    {
        foreach ((var o3, object? o4) in GetList(o1)) {}
        foreach ((var o3, object o4) in GetList(o2)) { o3.ToString(); } // 1
        o1 = null;
        foreach ((var o3, object o4) in GetList(o1)) {}
        _  = o2 ?? throw null!;
        foreach ((var o3, object? o4) in GetList(o2)) {}
    }
}";
 
            var comp = CreateCompilation(source, options: WithNullableEnable());
            comp.VerifyDiagnostics(
                // (10,56): warning CS8602: Dereference of a possibly null reference.
                //         foreach ((var o3, object o4) in GetList(o2)) { o3.ToString(); } // 1
                Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "o3").WithLocation(10, 56));
 
            var syntaxTree = comp.SyntaxTrees[0];
            var root = syntaxTree.GetRoot();
            var model = comp.GetSemanticModel(syntaxTree);
 
            var declarations = root.DescendantNodes().OfType<SingleVariableDesignationSyntax>().ToList();
 
            assertAnnotation(declarations[0], PublicNullableAnnotation.Annotated);
            assertAnnotation(declarations[1], PublicNullableAnnotation.Annotated);
            assertAnnotation(declarations[2], PublicNullableAnnotation.Annotated);
            assertAnnotation(declarations[3], PublicNullableAnnotation.NotAnnotated);
            assertAnnotation(declarations[4], PublicNullableAnnotation.Annotated);
            assertAnnotation(declarations[5], PublicNullableAnnotation.NotAnnotated);
            assertAnnotation(declarations[6], PublicNullableAnnotation.Annotated);
            assertAnnotation(declarations[7], PublicNullableAnnotation.Annotated);
 
            void assertAnnotation(SingleVariableDesignationSyntax variable, PublicNullableAnnotation expectedAnnotation)
            {
                var symbol = (ILocalSymbol)model.GetDeclaredSymbol(variable);
                Assert.Equal(expectedAnnotation, symbol.NullableAnnotation);
                Assert.Equal(expectedAnnotation, symbol.Type.NullableAnnotation);
 
                var type = ((DeclarationExpressionSyntax)variable.Parent).Type;
                if (type.IsVar)
                {
                    var typeInfo = model.GetTypeInfoAndVerifyIOperation(type);
                    Assert.Equal(PublicNullableFlowState.MaybeNull, typeInfo.Nullability.FlowState);
                    Assert.Equal(PublicNullableFlowState.MaybeNull, typeInfo.ConvertedNullability.FlowState);
                    Assert.Equal(CodeAnalysis.NullableAnnotation.Annotated, typeInfo.Nullability.Annotation);
                    Assert.Equal(CodeAnalysis.NullableAnnotation.Annotated, typeInfo.ConvertedNullability.Annotation);
                }
            }
        }
 
        [Fact]
        public void GetForeachInfo()
        {
            var source = @"
class C
{
    void M(string?[] nullableStrings, string[] strings)
    {
        foreach (var o in nullableStrings) {}
        foreach (var o in strings) {}
    }
}";
 
            var comp = CreateCompilation(source, options: WithNullableEnable());
            comp.VerifyDiagnostics();
 
            var syntaxTree = comp.SyntaxTrees[0];
            var root = syntaxTree.GetRoot();
            var model = comp.GetSemanticModel(syntaxTree);
 
            var declarations = root.DescendantNodes().OfType<ForEachStatementSyntax>().ToList();
 
            assertAnnotation(declarations[0], PublicNullableAnnotation.Annotated);
            assertAnnotation(declarations[1], PublicNullableAnnotation.NotAnnotated);
 
            void assertAnnotation(ForEachStatementSyntax foreachStatement, PublicNullableAnnotation expectedElementTypeAnnotation)
            {
                var foreachInfo = model.GetForEachStatementInfo(foreachStatement);
                Assert.Equal(expectedElementTypeAnnotation, foreachInfo.ElementType.NullableAnnotation);
            }
        }
 
        [InlineData("always")]
        [InlineData("never")]
        [Theory, WorkItem(37659, "https://github.com/dotnet/roslyn/issues/37659")]
        public void InvalidCodeVar_GetsCorrectSymbol(string flagState)
        {
            var source = @"
public class C
{
    public void M(string s)
    {
        s. // no completion
        var o = new object;
    }
}
";
 
            var comp = CreateCompilation(source, parseOptions: TestOptions.Regular8.WithFeature("run-nullable-analysis", flagState));
 
            var syntaxTree = comp.SyntaxTrees[0];
            var root = syntaxTree.GetRoot();
            var model = comp.GetSemanticModel(syntaxTree);
 
            var sRef = root.DescendantNodes().OfType<IdentifierNameSyntax>().Where(n => n.Identifier.ValueText == "s").Single();
 
            var info = model.GetSpeculativeSymbolInfo(sRef.Position, sRef, SpeculativeBindingOption.BindAsExpression);
 
            IParameterSymbol symbol = (IParameterSymbol)info.Symbol;
            Assert.True(info.CandidateSymbols.IsEmpty);
            Assert.NotNull(symbol);
            Assert.Equal("s", symbol.Name);
            Assert.Equal(SpecialType.System_String, symbol.Type.SpecialType);
        }
 
        [Fact, WorkItem(37879, "https://github.com/dotnet/roslyn/issues/37879")]
        public void MissingSymbols_ReinferredParent()
        {
            var source = @"
class C
{
    public void A<T>(T t) where T:class
    {
        var c = new F<T>[] { }.Select(v => new { Value = v.Item }).ToArray();
    }
    private class F<T>
    {
        public F(T oldItem) => Item = oldItem;
        public T Item { get; }
    }
}";
 
            var comp = CreateCompilation(source, options: WithNullableEnable());
 
            var syntaxTree = comp.SyntaxTrees[0];
            var root = syntaxTree.GetRoot();
            var model = comp.GetSemanticModel(syntaxTree);
 
            var select = root.DescendantNodes().OfType<IdentifierNameSyntax>().Where(i => i.Identifier.ValueText == "Select").Single();
            var symbolInfo = model.GetSymbolInfo(select);
 
            Assert.Null(symbolInfo.Symbol);
            Assert.Empty(symbolInfo.CandidateSymbols);
        }
 
        [Fact, WorkItem(37879, "https://github.com/dotnet/roslyn/issues/37879")]
        public void MultipleSymbols_ReinferredParent()
        {
            var source = @"
using System;
class C
{
    public void A<T>(T t) where T : class
    {
        var c = new F<T>[] { }.Select(v => new { Value = v.Item }).ToArray();
    }
    private class F<T>
    {
        public F(T oldItem) => Item = oldItem;
        public T Item { get; }
    }
}
static class ArrayExtensions
{
    public static U Select<T, U>(this T[] arr, Func<T, object, U> mapper, object arg) => throw null!;
    public static U Select<T, U, V>(this T[] arr, Func<T, V, U> mapper, V arg) => throw null!;
    public static U Select<T, U>(this T[] arr, C mapper) => throw null!;
    public static U Select<T, U>(this T[] arr, string mapper) => throw null!;
}";
 
            var comp = CreateCompilation(source, options: WithNullableEnable());
 
            var syntaxTree = comp.SyntaxTrees[0];
            var root = syntaxTree.GetRoot();
            var model = comp.GetSemanticModel(syntaxTree);
 
            var select = root.DescendantNodes().OfType<IdentifierNameSyntax>().Where(i => i.Identifier.ValueText == "Select").Single();
            var symbolInfo = model.GetSymbolInfo(select);
 
            Assert.Null(symbolInfo.Symbol);
            Assert.Equal(4, symbolInfo.CandidateSymbols.Length);
        }
 
        [Fact]
        public void GetSymbolInfo_PropertySymbols()
        {
            var source = @"
class C<T>
{
    public T GetT { get; }
 
    static C<U> Create<U>(U u) => new C<U>();
 
    static void M(object? o)
    {
        var c1 = Create(o);
        _ = c1.GetT;
        if (o is null) return;
        var c2 = Create(o);
        _ = c2.GetT;
    }
}";
            var comp = CreateCompilation(source, options: WithNullableEnable());
            comp.VerifyDiagnostics(
                    // (4,14): warning CS8618: Non-nullable property 'GetT' is uninitialized. Consider declaring the property as nullable.
                    //     public T GetT { get; }
                    Diagnostic(ErrorCode.WRN_UninitializedNonNullableField, "GetT").WithArguments("property", "GetT").WithLocation(4, 14));
 
            var syntaxTree = comp.SyntaxTrees[0];
            var root = syntaxTree.GetRoot();
            var model = comp.GetSemanticModel(syntaxTree);
 
            var memberAccess = root.DescendantNodes().OfType<MemberAccessExpressionSyntax>().ToList();
 
            var symInfo = model.GetSymbolInfo(memberAccess[0]);
            Assert.Equal(PublicNullableAnnotation.Annotated, ((IPropertySymbol)symInfo.Symbol).NullableAnnotation);
            Assert.Equal(PublicNullableAnnotation.Annotated, ((IPropertySymbol)symInfo.Symbol).Type.NullableAnnotation);
            Assert.Equal(PublicNullableAnnotation.Annotated, symInfo.Symbol.ContainingType.TypeArgumentNullableAnnotations[0]);
            Assert.Equal(PublicNullableAnnotation.Annotated, symInfo.Symbol.ContainingType.TypeArgumentNullableAnnotations().First());
            symInfo = model.GetSymbolInfo(memberAccess[1]);
            Assert.Equal(PublicNullableAnnotation.NotAnnotated, ((IPropertySymbol)symInfo.Symbol).NullableAnnotation);
            Assert.Equal(PublicNullableAnnotation.NotAnnotated, ((IPropertySymbol)symInfo.Symbol).Type.NullableAnnotation);
            Assert.Equal(PublicNullableAnnotation.NotAnnotated, symInfo.Symbol.ContainingType.TypeArgumentNullableAnnotations[0]);
            Assert.Equal(PublicNullableAnnotation.NotAnnotated, symInfo.Symbol.ContainingType.TypeArgumentNullableAnnotations().First());
        }
 
        [Fact]
        public void GetSymbolInfo_FieldSymbols()
        {
            var source = @"
class C<T>
{
    public T GetT;
 
    static C<U> Create<U>(U u) => new C<U>();
 
    static void M(object? o)
    {
        var c1 = Create(o);
        _ = c1.GetT;
        if (o is null) return;
        var c2 = Create(o);
        _ = c2.GetT;
    }
}";
            var comp = CreateCompilation(source, options: WithNullableEnable());
            comp.VerifyDiagnostics(
                    // (4,14): warning CS8618: Non-nullable field 'GetT' is uninitialized. Consider declaring the field as nullable.
                    //     public T GetT;
                    Diagnostic(ErrorCode.WRN_UninitializedNonNullableField, "GetT").WithArguments("field", "GetT").WithLocation(4, 14),
                    // (4,14): warning CS0649: Field 'C<T>.GetT' is never assigned to, and will always have its default value 
                    //     public T GetT;
                    Diagnostic(ErrorCode.WRN_UnassignedInternalField, "GetT").WithArguments("C<T>.GetT", "").WithLocation(4, 14));
 
            var syntaxTree = comp.SyntaxTrees[0];
            var root = syntaxTree.GetRoot();
            var model = comp.GetSemanticModel(syntaxTree);
 
            var memberAccess = root.DescendantNodes().OfType<MemberAccessExpressionSyntax>().ToList();
 
            var symInfo = model.GetSymbolInfo(memberAccess[0]);
            Assert.Equal(PublicNullableAnnotation.Annotated, ((IFieldSymbol)symInfo.Symbol).NullableAnnotation);
            Assert.Equal(PublicNullableAnnotation.Annotated, ((IFieldSymbol)symInfo.Symbol).Type.NullableAnnotation);
            Assert.Equal(PublicNullableAnnotation.Annotated, symInfo.Symbol.ContainingType.TypeArgumentNullableAnnotations[0]);
            Assert.Equal(PublicNullableAnnotation.Annotated, symInfo.Symbol.ContainingType.TypeArgumentNullableAnnotations().First());
            symInfo = model.GetSymbolInfo(memberAccess[1]);
            Assert.Equal(PublicNullableAnnotation.NotAnnotated, ((IFieldSymbol)symInfo.Symbol).NullableAnnotation);
            Assert.Equal(PublicNullableAnnotation.NotAnnotated, ((IFieldSymbol)symInfo.Symbol).Type.NullableAnnotation);
            Assert.Equal(PublicNullableAnnotation.NotAnnotated, symInfo.Symbol.ContainingType.TypeArgumentNullableAnnotations[0]);
            Assert.Equal(PublicNullableAnnotation.NotAnnotated, symInfo.Symbol.ContainingType.TypeArgumentNullableAnnotations().First());
        }
 
        [Fact]
        public void GetSymbolInfo_EventAdditionSymbols()
        {
            var source = @"
#pragma warning disable CS0067
using System;
class C<T>
{
    public event EventHandler? Event;
 
    static C<U> Create<U>(U u) => new C<U>();
 
    static void M(object? o)
    {
        var c1 = Create(o);
        c1.Event += (obj, sender) => {};
        if (o is null) return;
        var c2 = Create(o);
        c2.Event += (obj, sender) => {};
        c2.Event += c1.Event;
    }
}";
            var comp = CreateCompilation(source, options: WithNullableEnable());
            comp.VerifyDiagnostics();
 
            var syntaxTree = comp.SyntaxTrees[0];
            var root = syntaxTree.GetRoot();
            var model = comp.GetSemanticModel(syntaxTree);
 
            var memberAccess = root.DescendantNodes().OfType<MemberAccessExpressionSyntax>().ToList();
 
            var symInfo = model.GetSymbolInfo(memberAccess[0]);
            Assert.Equal(PublicNullableAnnotation.Annotated, ((IEventSymbol)symInfo.Symbol).NullableAnnotation);
            Assert.Equal(PublicNullableAnnotation.Annotated, ((IEventSymbol)symInfo.Symbol).Type.NullableAnnotation);
            Assert.Equal(PublicNullableAnnotation.Annotated, symInfo.Symbol.ContainingType.TypeArgumentNullableAnnotations[0]);
            Assert.Equal(PublicNullableAnnotation.Annotated, symInfo.Symbol.ContainingType.TypeArgumentNullableAnnotations().First());
            symInfo = model.GetSymbolInfo(memberAccess[1]);
            Assert.Equal(PublicNullableAnnotation.Annotated, ((IEventSymbol)symInfo.Symbol).NullableAnnotation);
            Assert.Equal(PublicNullableAnnotation.Annotated, ((IEventSymbol)symInfo.Symbol).Type.NullableAnnotation);
            Assert.Equal(PublicNullableAnnotation.NotAnnotated, symInfo.Symbol.ContainingType.TypeArgumentNullableAnnotations[0]);
            Assert.Equal(PublicNullableAnnotation.NotAnnotated, symInfo.Symbol.ContainingType.TypeArgumentNullableAnnotations().First());
 
            var event1 = model.GetSymbolInfo(memberAccess[2]).Symbol;
            var event2 = model.GetSymbolInfo(memberAccess[3]).Symbol;
            Assert.NotNull(event1);
            Assert.NotNull(event2);
            Assert.True(event1.Equals(event2, SymbolEqualityComparer.Default));
            Assert.False(event1.Equals(event2, SymbolEqualityComparer.IncludeNullability));
        }
 
        [Fact]
        public void GetSymbolInfo_EventAssignmentSymbols()
        {
            var source = @"
#pragma warning disable CS0067
using System;
class C<T>
{
    public event EventHandler? Event;
 
    static C<U> Create<U>(U u) => new C<U>();
 
    static void M(object? o)
    {
        var c1 = Create(o);
        c1.Event = (obj, sender) => {};
        if (o is null) return;
        var c2 = Create(o);
        c2.Event = (obj, sender) => {};
    }
}";
            var comp = CreateCompilation(source, options: WithNullableEnable());
            comp.VerifyDiagnostics();
 
            var syntaxTree = comp.SyntaxTrees[0];
            var root = syntaxTree.GetRoot();
            var model = comp.GetSemanticModel(syntaxTree);
 
            var memberAccess = root.DescendantNodes().OfType<MemberAccessExpressionSyntax>().ToList();
 
            var symInfo = model.GetSymbolInfo(memberAccess[0]);
            Assert.Equal(PublicNullableAnnotation.Annotated, ((IEventSymbol)symInfo.Symbol).NullableAnnotation);
            Assert.Equal(PublicNullableAnnotation.Annotated, ((IEventSymbol)symInfo.Symbol).Type.NullableAnnotation);
            Assert.Equal(PublicNullableAnnotation.Annotated, symInfo.Symbol.ContainingType.TypeArgumentNullableAnnotations[0]);
            Assert.Equal(PublicNullableAnnotation.Annotated, symInfo.Symbol.ContainingType.TypeArgumentNullableAnnotations().First());
            symInfo = model.GetSymbolInfo(memberAccess[1]);
            Assert.Equal(PublicNullableAnnotation.Annotated, ((IEventSymbol)symInfo.Symbol).NullableAnnotation);
            Assert.Equal(PublicNullableAnnotation.Annotated, ((IEventSymbol)symInfo.Symbol).Type.NullableAnnotation);
            Assert.Equal(PublicNullableAnnotation.NotAnnotated, symInfo.Symbol.ContainingType.TypeArgumentNullableAnnotations[0]);
            Assert.Equal(PublicNullableAnnotation.NotAnnotated, symInfo.Symbol.ContainingType.TypeArgumentNullableAnnotations().First());
        }
 
        [Fact]
        public void GetSymbolInfo_EventAssignmentFlowState()
        {
            var source = @"
using System;
class C
{
    event Action? Event;
 
    void M(bool b)
    {
        if (b) Event.Invoke(); // 1
        Event += () => { };
        Event.Invoke();
    }
}";
            var comp = CreateCompilation(source, options: WithNullableEnable());
            comp.VerifyDiagnostics(
                // (9,16): warning CS8602: Dereference of a possibly null reference.
                //         if (b) Event.Invoke(); // 1
                Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "Event").WithLocation(9, 16)
                );
 
            var syntaxTree = comp.SyntaxTrees[0];
            var root = syntaxTree.GetRoot();
            var model = comp.GetSemanticModel(syntaxTree);
 
            var memberAccess = root.DescendantNodes().OfType<MemberAccessExpressionSyntax>().ToList();
            Assert.Equal(2, memberAccess.Count);
 
            var typeInfo = model.GetTypeInfo(memberAccess[0].Expression);
            Assert.Equal(PublicNullableAnnotation.Annotated, typeInfo.Type.NullableAnnotation);
            Assert.Equal(PublicNullableFlowState.MaybeNull, typeInfo.Nullability.FlowState);
 
            typeInfo = model.GetTypeInfo(memberAccess[1].Expression);
            Assert.Equal(PublicNullableAnnotation.NotAnnotated, typeInfo.Type.NullableAnnotation);
            Assert.Equal(PublicNullableFlowState.NotNull, typeInfo.Nullability.FlowState);
 
            var lhs = root.DescendantNodes().OfType<AssignmentExpressionSyntax>().Single().Left;
            typeInfo = model.GetTypeInfo(lhs);
            Assert.Equal(PublicNullableAnnotation.None, typeInfo.Type.NullableAnnotation);
            Assert.Equal(PublicNullableFlowState.None, typeInfo.Nullability.FlowState);
        }
 
        [Fact]
        public void GetSymbolInfo_ReinferredCollectionInitializerAdd_InstanceMethods()
        {
            var source = @"
using System.Collections;
class C : IEnumerable
{
    public void Add<T>(T t) => throw null!;
    public IEnumerator GetEnumerator() => throw null!;
    public static T Identity<T>(T t) => t;
 
    static void M(object? o1, string o2)
    {
        _ = new C() { o1, Identity(o1 ??= new object()), o1, o2 };
    }
}
";
            var comp = CreateCompilation(source, options: WithNullableEnable());
            comp.VerifyDiagnostics();
 
            var syntaxTree = comp.SyntaxTrees[0];
            var root = syntaxTree.GetRoot();
            var model = comp.GetSemanticModel(syntaxTree);
 
            var collectionInitializer = root.DescendantNodes().OfType<InitializerExpressionSyntax>().Single();
 
            verifyAnnotation(collectionInitializer.Expressions[0], PublicNullableAnnotation.Annotated);
            verifyAnnotation(collectionInitializer.Expressions[1], PublicNullableAnnotation.NotAnnotated);
            verifyAnnotation(collectionInitializer.Expressions[2], PublicNullableAnnotation.NotAnnotated);
            verifyAnnotation(collectionInitializer.Expressions[3], PublicNullableAnnotation.NotAnnotated);
 
            void verifyAnnotation(ExpressionSyntax expr, PublicNullableAnnotation expectedAnnotation)
            {
                var symbolInfo = model.GetCollectionInitializerSymbolInfo(expr);
                Assert.Equal(expectedAnnotation, ((IMethodSymbol)symbolInfo.Symbol).TypeArgumentNullableAnnotations[0]);
                Assert.Equal(expectedAnnotation, ((IMethodSymbol)symbolInfo.Symbol).TypeArguments[0].NullableAnnotation);
            }
        }
 
        [Fact]
        public void GetSymbolInfo_ReinferredCollectionInitializerAdd_ExtensionMethod01()
        {
            var source = @"
using System.Collections;
class C : IEnumerable
{
    public IEnumerator GetEnumerator() => throw null!;
    public static T Identity<T>(T t) => t;
 
    static void M(object? o1, string o2)
    {
        _ = new C() { o1, Identity(o1 ??= new object()), o1, o2 };
    }
}
static class CExt
{
    public static void Add<T>(this C c, T t) => throw null!;
}
";
            var comp = CreateCompilation(source, options: WithNullableEnable());
            comp.VerifyDiagnostics();
 
            var syntaxTree = comp.SyntaxTrees[0];
            var root = syntaxTree.GetRoot();
            var model = comp.GetSemanticModel(syntaxTree);
 
            var collectionInitializer = root.DescendantNodes().OfType<InitializerExpressionSyntax>().Single();
 
            verifyAnnotation(collectionInitializer.Expressions[0], PublicNullableAnnotation.Annotated);
            verifyAnnotation(collectionInitializer.Expressions[1], PublicNullableAnnotation.NotAnnotated);
            verifyAnnotation(collectionInitializer.Expressions[2], PublicNullableAnnotation.NotAnnotated);
            verifyAnnotation(collectionInitializer.Expressions[3], PublicNullableAnnotation.NotAnnotated);
 
            void verifyAnnotation(ExpressionSyntax expr, PublicNullableAnnotation expectedAnnotation)
            {
                var symbolInfo = model.GetCollectionInitializerSymbolInfo(expr);
                Assert.Equal(expectedAnnotation, ((IMethodSymbol)symbolInfo.Symbol).TypeArgumentNullableAnnotations[0]);
                Assert.Equal(expectedAnnotation, ((IMethodSymbol)symbolInfo.Symbol).TypeArguments[0].NullableAnnotation);
            }
        }
 
        [Fact]
        public void GetSymbolInfo_ReinferredCollectionInitializerAdd_ExtensionMethod02()
        {
            var source = @"
using System.Collections;
class C : IEnumerable
{
    public IEnumerator GetEnumerator() => throw null!;
    public static T Identity<T>(T t) => t;
 
    static void M(object? o1, string o2)
    {
        _ = new C() { o1, Identity(o1 ??= new object()), o1, o2 };
    }
}
static class CExt
{
    public static void Add<T, U>(this T t, U u) => throw null!;
}
";
            var comp = CreateCompilation(source, options: WithNullableEnable());
            comp.VerifyDiagnostics();
 
            var syntaxTree = comp.SyntaxTrees[0];
            var root = syntaxTree.GetRoot();
            var model = comp.GetSemanticModel(syntaxTree);
 
            var collectionInitializer = root.DescendantNodes().OfType<InitializerExpressionSyntax>().Single();
 
            verifyAnnotation(collectionInitializer.Expressions[0], PublicNullableAnnotation.Annotated);
            verifyAnnotation(collectionInitializer.Expressions[1], PublicNullableAnnotation.NotAnnotated);
            verifyAnnotation(collectionInitializer.Expressions[2], PublicNullableAnnotation.NotAnnotated);
            verifyAnnotation(collectionInitializer.Expressions[3], PublicNullableAnnotation.NotAnnotated);
 
            void verifyAnnotation(ExpressionSyntax expr, PublicNullableAnnotation expectedAnnotation)
            {
                var symbolInfo = model.GetCollectionInitializerSymbolInfo(expr);
                Assert.Equal(PublicNullableAnnotation.NotAnnotated, ((IMethodSymbol)symbolInfo.Symbol).TypeArgumentNullableAnnotations[0]);
                Assert.Equal(PublicNullableAnnotation.NotAnnotated, ((IMethodSymbol)symbolInfo.Symbol).TypeArguments[0].NullableAnnotation);
                Assert.Equal(expectedAnnotation, ((IMethodSymbol)symbolInfo.Symbol).TypeArgumentNullableAnnotations[1]);
                Assert.Equal(expectedAnnotation, ((IMethodSymbol)symbolInfo.Symbol).TypeArguments[1].NullableAnnotation);
            }
        }
 
        [Fact]
        public void GetSymbolInfo_ReinferredCollectionInitializerAdd_MultipleOverloads()
        {
            var source = @"
using System.Collections;
class C : IEnumerable
{
    public IEnumerator GetEnumerator() => throw null!;
    public static T Identity<T>(T t) => t;
 
    static void M(object? o1, string o2)
    {
        _ = new C() { o1, Identity(o1 ??= new object()), o1, o2 };
    }
}
static class CExt1
{
    public static void Add<T>(this C c, T t) => throw null!;
}
static class CExt2
{
    public static void Add<T>(this C c, T t) => throw null!;
}
";
            var comp = CreateCompilation(source, options: WithNullableEnable());
            comp.VerifyDiagnostics(
                // (10,23): error CS0121: The call is ambiguous between the following methods or properties: 'CExt1.Add<T>(C, T)' and 'CExt2.Add<T>(C, T)'
                //         _ = new C() { o1, Identity(o1 ??= new object()), o1, o2 };
                Diagnostic(ErrorCode.ERR_AmbigCall, "o1").WithArguments("CExt1.Add<T>(C, T)", "CExt2.Add<T>(C, T)").WithLocation(10, 23),
                // (10,27): error CS0121: The call is ambiguous between the following methods or properties: 'CExt1.Add<T>(C, T)' and 'CExt2.Add<T>(C, T)'
                //         _ = new C() { o1, Identity(o1 ??= new object()), o1, o2 };
                Diagnostic(ErrorCode.ERR_AmbigCall, "Identity(o1 ??= new object())").WithArguments("CExt1.Add<T>(C, T)", "CExt2.Add<T>(C, T)").WithLocation(10, 27),
                // (10,58): error CS0121: The call is ambiguous between the following methods or properties: 'CExt1.Add<T>(C, T)' and 'CExt2.Add<T>(C, T)'
                //         _ = new C() { o1, Identity(o1 ??= new object()), o1, o2 };
                Diagnostic(ErrorCode.ERR_AmbigCall, "o1").WithArguments("CExt1.Add<T>(C, T)", "CExt2.Add<T>(C, T)").WithLocation(10, 58),
                // (10,62): error CS0121: The call is ambiguous between the following methods or properties: 'CExt1.Add<T>(C, T)' and 'CExt2.Add<T>(C, T)'
                //         _ = new C() { o1, Identity(o1 ??= new object()), o1, o2 };
                Diagnostic(ErrorCode.ERR_AmbigCall, "o2").WithArguments("CExt1.Add<T>(C, T)", "CExt2.Add<T>(C, T)").WithLocation(10, 62));
 
            var syntaxTree = comp.SyntaxTrees[0];
            var root = syntaxTree.GetRoot();
            var model = comp.GetSemanticModel(syntaxTree);
 
            var collectionInitializer = root.DescendantNodes().OfType<InitializerExpressionSyntax>().Single();
 
            verifyAnnotation(collectionInitializer.Expressions[0]);
            verifyAnnotation(collectionInitializer.Expressions[1]);
            verifyAnnotation(collectionInitializer.Expressions[2]);
            verifyAnnotation(collectionInitializer.Expressions[3]);
 
            void verifyAnnotation(ExpressionSyntax expr)
            {
                var symbolInfo = model.GetCollectionInitializerSymbolInfo(expr);
                Assert.Null(symbolInfo.Symbol);
                foreach (var symbol in symbolInfo.CandidateSymbols)
                {
                    Assert.Equal(PublicNullableAnnotation.None, ((IMethodSymbol)symbol).TypeArgumentNullableAnnotations[0]);
                    Assert.Equal(PublicNullableAnnotation.None, ((IMethodSymbol)symbol).TypeArguments[0].NullableAnnotation);
                }
            }
        }
 
        [Fact]
        public void GetSymbolInfo_ReinferredCollectionInitializerAdd_MultiElementAdds()
        {
            var source = @"
using System.Collections;
class C : IEnumerable
{
    public IEnumerator GetEnumerator() => throw null!;
    public static T Identity<T>(T t) => t;
 
    static void M(object? o1, string o2)
    {
        _ = new C() { { o1, o2 }, { o2, o1 }, { Identity(o1 ??= new object()), o2 } };
    }
}
static class CExt
{
    public static void Add<T, U>(this C c, T t, U u) => throw null!;
}
";
 
            var comp = CreateCompilation(source, options: WithNullableEnable());
            comp.VerifyDiagnostics();
 
            var syntaxTree = comp.SyntaxTrees[0];
            var root = syntaxTree.GetRoot();
            var model = comp.GetSemanticModel(syntaxTree);
 
            var collectionInitializer = root.DescendantNodes().OfType<InitializerExpressionSyntax>().First();
 
            verifyAnnotation(collectionInitializer.Expressions[0], PublicNullableAnnotation.Annotated, PublicNullableAnnotation.NotAnnotated);
            verifyAnnotation(collectionInitializer.Expressions[1], PublicNullableAnnotation.NotAnnotated, PublicNullableAnnotation.Annotated);
            verifyAnnotation(collectionInitializer.Expressions[2], PublicNullableAnnotation.NotAnnotated, PublicNullableAnnotation.NotAnnotated);
 
            void verifyAnnotation(ExpressionSyntax expr, PublicNullableAnnotation annotation1, PublicNullableAnnotation annotation2)
            {
                var symbolInfo = model.GetCollectionInitializerSymbolInfo(expr);
                var methodSymbol = ((IMethodSymbol)symbolInfo.Symbol);
                Assert.Equal(annotation1, methodSymbol.TypeArgumentNullableAnnotations[0]);
                Assert.Equal(annotation1, methodSymbol.TypeArguments[0].NullableAnnotation);
                Assert.Equal(annotation2, methodSymbol.TypeArgumentNullableAnnotations[1]);
                Assert.Equal(annotation2, methodSymbol.TypeArguments[1].NullableAnnotation);
            }
        }
 
        [Fact]
        public void GetSymbolInfo_ReinferredCollectionInitializerAdd_MultiElementAdds_LinkedTypes()
        {
            var source = @"
using System.Collections;
class C : IEnumerable
{
    public IEnumerator GetEnumerator() => throw null!;
    public static T Identity<T>(T t) => t;
 
    static void M(object? o1, string o2)
    {
        _ = new C() { { o1, o2 }, { o2, o1 }, { Identity(o1 ??= new object()), o2 } };
    }
}
static class CExt
{
    public static void Add<T>(this C c, T t1, T t2) => throw null!;
}
";
 
            var comp = CreateCompilation(source, options: WithNullableEnable());
            comp.VerifyDiagnostics();
 
            var syntaxTree = comp.SyntaxTrees[0];
            var root = syntaxTree.GetRoot();
            var model = comp.GetSemanticModel(syntaxTree);
 
            var collectionInitializer = root.DescendantNodes().OfType<InitializerExpressionSyntax>().First();
 
            verifyAnnotation(collectionInitializer.Expressions[0], PublicNullableAnnotation.Annotated);
            verifyAnnotation(collectionInitializer.Expressions[1], PublicNullableAnnotation.Annotated);
            verifyAnnotation(collectionInitializer.Expressions[2], PublicNullableAnnotation.NotAnnotated);
 
            void verifyAnnotation(ExpressionSyntax expr, PublicNullableAnnotation annotation)
            {
                var symbolInfo = model.GetCollectionInitializerSymbolInfo(expr);
                var methodSymbol = ((IMethodSymbol)symbolInfo.Symbol);
                Assert.Equal(annotation, methodSymbol.TypeArgumentNullableAnnotations[0]);
                Assert.Equal(annotation, methodSymbol.TypeArguments[0].NullableAnnotation);
            }
        }
 
        [Fact]
        public void GetSymbolInfo_ReinferredIndexer()
        {
            var source = @"
class C<T, U>
{
    public T this[U u] { get => throw null!; set => throw null!; }
    
    public static void M(bool b, object? o1, object o2)
    {
        var c1 = CExt.Create(o1, o2);
        if (b) c1[o1] = o2;
        if (b) _ = c1[o1];
        
        var c2 = CExt.Create(o2, o1);
        if (b) c2[o2] = o1;
        if (b) _ = c2[o2];
        
        var c3 = CExt.Create(o1 ?? o2, o2);
        if (b) c3[o1] = o2;
        if (b) _ = c3[o1];
    }
}
static class CExt
{
    public static C<T, U> Create<T, U>(T t, U u) => throw null!;
}";
 
            var comp = CreateCompilation(source, options: WithNullableEnable());
            comp.VerifyDiagnostics(
                // (9,19): warning CS8604: Possible null reference argument for parameter 'u' in 'object? C<object?, object>.this[object u]'.
                //         if (b) c1[o1] = o2;
                Diagnostic(ErrorCode.WRN_NullReferenceArgument, "o1").WithArguments("u", "object? C<object?, object>.this[object u]").WithLocation(9, 19),
                // (10,23): warning CS8604: Possible null reference argument for parameter 'u' in 'object? C<object?, object>.this[object u]'.
                //         if (b) _ = c1[o1];
                Diagnostic(ErrorCode.WRN_NullReferenceArgument, "o1").WithArguments("u", "object? C<object?, object>.this[object u]").WithLocation(10, 23),
                // (13,25): warning CS8601: Possible null reference assignment.
                //         if (b) c2[o2] = o1;
                Diagnostic(ErrorCode.WRN_NullReferenceAssignment, "o1").WithLocation(13, 25),
                // (17,19): warning CS8604: Possible null reference argument for parameter 'u' in 'object C<object, object>.this[object u]'.
                //         if (b) c3[o1] = o2;
                Diagnostic(ErrorCode.WRN_NullReferenceArgument, "o1").WithArguments("u", "object C<object, object>.this[object u]").WithLocation(17, 19),
                // (18,23): warning CS8604: Possible null reference argument for parameter 'u' in 'object C<object, object>.this[object u]'.
                //         if (b) _ = c3[o1];
                Diagnostic(ErrorCode.WRN_NullReferenceArgument, "o1").WithArguments("u", "object C<object, object>.this[object u]").WithLocation(18, 23));
 
            var syntaxTree = comp.SyntaxTrees[0];
            var root = syntaxTree.GetRoot();
            var model = comp.GetSemanticModel(syntaxTree);
 
            var indexers = root.DescendantNodes().OfType<ElementAccessExpressionSyntax>().ToArray().AsSpan();
            verifyAnnotation(indexers.Slice(0, 2), PublicNullableAnnotation.Annotated, PublicNullableAnnotation.NotAnnotated);
            verifyAnnotation(indexers.Slice(2, 2), PublicNullableAnnotation.NotAnnotated, PublicNullableAnnotation.Annotated);
            verifyAnnotation(indexers.Slice(4, 2), PublicNullableAnnotation.NotAnnotated, PublicNullableAnnotation.NotAnnotated);
 
            void verifyAnnotation(Span<ElementAccessExpressionSyntax> indexers, PublicNullableAnnotation firstAnnotation, PublicNullableAnnotation secondAnnotation)
            {
                var propertySymbol = (IPropertySymbol)model.GetSymbolInfo(indexers[0]).Symbol;
                verifyIndexer(propertySymbol);
                propertySymbol = (IPropertySymbol)model.GetSymbolInfo(indexers[1]).Symbol;
                verifyIndexer(propertySymbol);
 
                void verifyIndexer(IPropertySymbol propertySymbol)
                {
                    Assert.True(propertySymbol.IsIndexer);
                    Assert.Equal(firstAnnotation, propertySymbol.NullableAnnotation);
                    Assert.Equal(firstAnnotation, propertySymbol.Type.NullableAnnotation);
                    Assert.Equal(secondAnnotation, propertySymbol.Parameters[0].NullableAnnotation);
                    Assert.Equal(secondAnnotation, propertySymbol.Parameters[0].Type.NullableAnnotation);
                }
            }
        }
 
        [Fact]
        public void GetSymbolInfo_IndexReinferred()
        {
            var source = @"
class C<T>
{
    public int Length { get; }
    public T this[int i] { get => throw null!; set => throw null!; }
    public static C<TT> Create<TT>(TT t) => throw null!;
 
    public static void M(object? o)
    {
        var c1 = Create(o);
        c1[^1] = new object();
        _ = c1[^1];
 
        var c2 = Create(o ?? new object());
        c2[^1] = new object();
        _ = c2[^1];
    }
}";
 
            var comp = CreateCompilationWithIndexAndRangeAndSpan(source, options: WithNullableEnable());
            comp.VerifyDiagnostics();
 
            var syntaxTree = comp.SyntaxTrees[0];
            var root = syntaxTree.GetRoot();
            var model = comp.GetSemanticModel(syntaxTree);
 
            var elementAccesses = root.DescendantNodes().OfType<ElementAccessExpressionSyntax>().ToArray().AsSpan();
            verifyAnnotation(elementAccesses.Slice(0, 2), PublicNullableAnnotation.Annotated);
            verifyAnnotation(elementAccesses.Slice(2, 2), PublicNullableAnnotation.NotAnnotated);
 
            void verifyAnnotation(Span<ElementAccessExpressionSyntax> indexers, PublicNullableAnnotation annotation)
            {
                var propertySymbol = (IPropertySymbol)model.GetSymbolInfo(indexers[0]).Symbol;
                verifyIndexer(propertySymbol);
                propertySymbol = (IPropertySymbol)model.GetSymbolInfo(indexers[1]).Symbol;
                verifyIndexer(propertySymbol);
 
                void verifyIndexer(IPropertySymbol propertySymbol)
                {
                    Assert.True(propertySymbol.IsIndexer);
                    Assert.Equal(annotation, propertySymbol.NullableAnnotation);
                    Assert.Equal(annotation, propertySymbol.Type.NullableAnnotation);
                }
            }
        }
 
        [Fact]
        public void GetSymbolInfo_RangeReinferred()
        {
            var source = @"
using System;
 
class C<T>
{
    public int Length { get; }
    public Span<T> Slice(int start, int length) => throw null!;
    public static C<TT> Create<TT>(TT t) => throw null!;
 
    public static void M(object? o)
    {
        var c1 = Create(o);
        _ = c1[..^1];
 
        var c2 = Create(o ?? new object());
        _ = c2[..^1];
    }
}";
 
            var comp = CreateCompilationWithIndexAndRangeAndSpan(source, options: WithNullableEnable());
            comp.VerifyDiagnostics();
 
            var syntaxTree = comp.SyntaxTrees[0];
            var root = syntaxTree.GetRoot();
            var model = comp.GetSemanticModel(syntaxTree);
 
            var elementAccesses = root.DescendantNodes().OfType<ElementAccessExpressionSyntax>().ToArray();
            verifyAnnotation(elementAccesses[0], PublicNullableAnnotation.Annotated);
            verifyAnnotation(elementAccesses[1], PublicNullableAnnotation.NotAnnotated);
 
            void verifyAnnotation(ElementAccessExpressionSyntax indexer, PublicNullableAnnotation annotation)
            {
                var propertySymbol = (IMethodSymbol)model.GetSymbolInfo(indexer).Symbol;
                Assert.NotNull(propertySymbol);
                var spanType = (INamedTypeSymbol)propertySymbol.ReturnType;
                Assert.Equal(annotation, spanType.TypeArgumentNullableAnnotations[0]);
                Assert.Equal(annotation, spanType.TypeArgumentNullableAnnotations().First());
            }
        }
 
        [Fact]
        public void GetSymbolInfo_UnaryOperator()
        {
            var source =
@"#nullable enable
struct S<T>
{
    public static S<T> operator~(S<T> s) => s;
}
class Program
{
    static S<T> Create1<T>(T t) => new S<T>();
    static S<T>? Create2<T>(T t) => null;
    static void F<T>() where T : class, new()
    {
        T x = null;
        var sx = Create1(x);
        _ = ~sx;
        T? y = new T();
        var sy = Create2(y);
        _ = ~sy;
    }
}";
            var comp = CreateCompilation(source);
            comp.VerifyDiagnostics(
                // (12,15): warning CS8600: Converting null literal or possible null value to non-nullable type.
                //         T x = null;
                Diagnostic(ErrorCode.WRN_ConvertingNullableToNonNullable, "null").WithLocation(12, 15));
 
            var syntaxTree = comp.SyntaxTrees[0];
            var root = syntaxTree.GetRoot();
            var model = comp.GetSemanticModel(syntaxTree);
            var operators = root.DescendantNodes().OfType<PrefixUnaryExpressionSyntax>().ToList();
            verifyAnnotations(operators[0], PublicNullableAnnotation.Annotated, "S<T?> S<T?>.operator ~(S<T?> s)");
            verifyAnnotations(operators[1], PublicNullableAnnotation.NotAnnotated, "S<T!> S<T!>.operator ~(S<T!> s)");
 
            void verifyAnnotations(PrefixUnaryExpressionSyntax syntax, PublicNullableAnnotation annotation, string expected)
            {
                var method = (IMethodSymbol)model.GetSymbolInfo(syntax).Symbol;
                Assert.Equal(expected, method.ToTestDisplayString(includeNonNullable: true));
                Assert.Equal(annotation, method.ContainingType.TypeArgumentNullableAnnotations[0]);
                Assert.Equal(annotation, method.ContainingType.TypeArgumentNullableAnnotations().First());
            }
        }
 
        [Fact]
        public void GetSymbolInfo_BinaryOperator()
        {
            var source =
@"#nullable enable
struct S<T>
{
    public static S<T> operator+(S<T> x, S<T> y) => x;
}
class Program
{
    static S<T> Create1<T>(T t) => new S<T>();
    static S<T>? Create2<T>(T t) => null;
    static void F<T>() where T : class, new()
    {
        T x = null;
        var sx = Create1(x);
        _ = sx + sx;
        T? y = new T();
        var sy = Create2(y);
        _ = sy + sy;
    }
}";
            var comp = CreateCompilation(source);
            comp.VerifyDiagnostics(
                // (12,15): warning CS8600: Converting null literal or possible null value to non-nullable type.
                //         T x = null;
                Diagnostic(ErrorCode.WRN_ConvertingNullableToNonNullable, "null").WithLocation(12, 15));
 
            var syntaxTree = comp.SyntaxTrees[0];
            var root = syntaxTree.GetRoot();
            var model = comp.GetSemanticModel(syntaxTree);
            var operators = root.DescendantNodes().OfType<BinaryExpressionSyntax>().ToList();
            verifyAnnotations(operators[0], PublicNullableAnnotation.Annotated, "S<T?> S<T?>.operator +(S<T?> x, S<T?> y)");
            verifyAnnotations(operators[1], PublicNullableAnnotation.NotAnnotated, "S<T!> S<T!>.operator +(S<T!> x, S<T!> y)");
 
            void verifyAnnotations(BinaryExpressionSyntax syntax, PublicNullableAnnotation annotation, string expected)
            {
                var method = (IMethodSymbol)model.GetSymbolInfo(syntax).Symbol;
                Assert.Equal(expected, method.ToTestDisplayString(includeNonNullable: true));
                Assert.Equal(annotation, method.ContainingType.TypeArgumentNullableAnnotations[0]);
                Assert.Equal(annotation, method.ContainingType.TypeArgumentNullableAnnotations().First());
            }
        }
 
        [Fact]
        public void GetSymbolInfo_SimpleLambdaReinference()
        {
            var source = @"
using System;
class C
{
    public static Action<T> Create<T>(T t, Action<T> a) => throw null!;
 
    public static void M(object? o)
    {
        var a = Create(o, o1 => { _ = o1.ToString(); });
    }
}";
 
            var comp = CreateCompilation(source, options: WithNullableEnable());
            comp.VerifyDiagnostics(
                    // (9,39): warning CS8602: Dereference of a possibly null reference.
                    //         var a = Create(o, o1 => { _ = o1.ToString(); });
                    Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "o1").WithLocation(9, 39));
 
            var syntaxTree = comp.SyntaxTrees[0];
            var root = syntaxTree.GetRoot();
            var model = comp.GetSemanticModel(syntaxTree);
 
            var lambda = root.DescendantNodes().OfType<LambdaExpressionSyntax>().Single();
            var lambdaSymbol = (IMethodSymbol)model.GetSymbolInfo(lambda).Symbol;
            Assert.NotNull(lambdaSymbol);
            Assert.Equal(MethodKind.LambdaMethod, lambdaSymbol.MethodKind);
            Assert.Equal(PublicNullableAnnotation.Annotated, lambdaSymbol.Parameters[0].NullableAnnotation);
            Assert.Equal(PublicNullableAnnotation.Annotated, lambdaSymbol.Parameters[0].Type.NullableAnnotation);
 
            var o1Ref = lambda.DescendantNodes()
                .OfType<AssignmentExpressionSyntax>()
                .Single()
                .DescendantNodes()
                .OfType<IdentifierNameSyntax>()
                .First(i => i.Identifier.ValueText == "o1");
 
            var parameterSymbol = (IParameterSymbol)model.GetSymbolInfo(o1Ref).Symbol;
            Assert.NotNull(parameterSymbol);
            Assert.Equal(PublicNullableAnnotation.Annotated, parameterSymbol.NullableAnnotation);
            Assert.Equal(PublicNullableAnnotation.Annotated, parameterSymbol.Type.NullableAnnotation);
 
            var mDeclaration = root.DescendantNodes().OfType<MethodDeclarationSyntax>().First(m => m.Identifier.ValueText == "M");
            var mSymbol = model.GetDeclaredSymbol(mDeclaration);
            Assert.Equal(mSymbol, lambdaSymbol.ContainingSymbol, SymbolEqualityComparer.IncludeNullability);
        }
 
        [Fact]
        public void NestedLambdaReinference_NestedReinferred()
        {
            var source = @"
using System;
class C
{
    public static Action<T> Create<T>(T t, Action<T> a) => throw null!;
 
    public static void M(object? o)
    {
        var a = Create(o, o1 => {
            if (o1 == null) return;
            Create(o1, o2 => { _ = o2; _ = o1; });
        });
    }
}";
 
            var comp = CreateCompilation(source, options: WithNullableEnable());
            comp.VerifyDiagnostics();
 
            var syntaxTree = comp.SyntaxTrees[0];
            var root = syntaxTree.GetRoot();
            var model = comp.GetSemanticModel(syntaxTree);
 
            var lambda = root.DescendantNodes().OfType<LambdaExpressionSyntax>().First();
            var lambdaSymbol = model.GetSymbolInfo(lambda).Symbol;
 
            var innerLambda = root.DescendantNodes().OfType<LambdaExpressionSyntax>().ElementAt(1);
 
            var innerLambdaSymbol = (IMethodSymbol)model.GetSymbolInfo(innerLambda).Symbol;
            Assert.NotNull(innerLambdaSymbol);
            Assert.Equal(MethodKind.LambdaMethod, innerLambdaSymbol.MethodKind);
            Assert.Equal(PublicNullableAnnotation.NotAnnotated, innerLambdaSymbol.Parameters[0].NullableAnnotation);
            Assert.Equal(PublicNullableAnnotation.NotAnnotated, innerLambdaSymbol.Parameters[0].Type.NullableAnnotation);
            Assert.Equal(lambdaSymbol, innerLambdaSymbol.ContainingSymbol, SymbolEqualityComparer.IncludeNullability);
 
            var o1Ref = innerLambda.DescendantNodes()
                .OfType<AssignmentExpressionSyntax>()
                .ElementAt(1)
                .DescendantNodes()
                .OfType<IdentifierNameSyntax>()
                .First(i => i.Identifier.ValueText == "o1");
 
            var o1Symbol = (IParameterSymbol)model.GetSymbolInfo(o1Ref).Symbol;
            Assert.Equal(PublicNullableAnnotation.Annotated, o1Symbol.NullableAnnotation);
            Assert.Equal(PublicNullableAnnotation.Annotated, o1Symbol.Type.NullableAnnotation);
 
            var o2Ref = innerLambda.DescendantNodes()
                .OfType<AssignmentExpressionSyntax>()
                .First()
                .DescendantNodes()
                .OfType<IdentifierNameSyntax>()
                .First(i => i.Identifier.ValueText == "o2");
 
            var o2Symbol = (IParameterSymbol)model.GetSymbolInfo(o2Ref).Symbol;
            Assert.Equal(PublicNullableAnnotation.NotAnnotated, o2Symbol.NullableAnnotation);
            Assert.Equal(PublicNullableAnnotation.NotAnnotated, o2Symbol.Type.NullableAnnotation);
            Assert.Equal(innerLambdaSymbol, o2Symbol.ContainingSymbol, SymbolEqualityComparer.IncludeNullability);
        }
 
        [Fact]
        public void NestedLambdaReinference_NestedNotReinferred()
        {
            var source = @"
using System;
class C
{
    public static Action<T> Create<T>(T t, Action<T> a) => throw null!;
 
    public static void M(object? o)
    {
        var a = Create(o, o1 => {
            if (o1 == null) return;
            Action<string> a = o2 => { _ = o2; _ = o1; };
        });
    }
}";
 
            var comp = CreateCompilation(source, options: WithNullableEnable());
            comp.VerifyDiagnostics();
 
            var syntaxTree = comp.SyntaxTrees[0];
            var root = syntaxTree.GetRoot();
            var model = comp.GetSemanticModel(syntaxTree);
 
            var lambda = root.DescendantNodes().OfType<LambdaExpressionSyntax>().First();
            var lambdaSymbol = model.GetSymbolInfo(lambda).Symbol;
 
            var innerLambda = root.DescendantNodes().OfType<LambdaExpressionSyntax>().ElementAt(1);
 
            var innerLambdaSymbol = (IMethodSymbol)model.GetSymbolInfo(innerLambda).Symbol;
            Assert.NotNull(innerLambdaSymbol);
            Assert.Equal(MethodKind.LambdaMethod, innerLambdaSymbol.MethodKind);
            Assert.Equal(PublicNullableAnnotation.NotAnnotated, innerLambdaSymbol.Parameters[0].NullableAnnotation);
            Assert.Equal(PublicNullableAnnotation.NotAnnotated, innerLambdaSymbol.Parameters[0].Type.NullableAnnotation);
            Assert.Equal(lambdaSymbol, innerLambdaSymbol.ContainingSymbol, SymbolEqualityComparer.IncludeNullability);
 
            var o1Ref = innerLambda.DescendantNodes()
                .OfType<AssignmentExpressionSyntax>()
                .ElementAt(1)
                .DescendantNodes()
                .OfType<IdentifierNameSyntax>()
                .First(i => i.Identifier.ValueText == "o1");
 
            var o1Symbol = (IParameterSymbol)model.GetSymbolInfo(o1Ref).Symbol;
            Assert.Equal(PublicNullableAnnotation.Annotated, o1Symbol.NullableAnnotation);
            Assert.Equal(PublicNullableAnnotation.Annotated, o1Symbol.Type.NullableAnnotation);
 
            var o2Ref = innerLambda.DescendantNodes()
                .OfType<AssignmentExpressionSyntax>()
                .First()
                .DescendantNodes()
                .OfType<IdentifierNameSyntax>()
                .First(i => i.Identifier.ValueText == "o2");
 
            var o2Symbol = (IParameterSymbol)model.GetSymbolInfo(o2Ref).Symbol;
            Assert.Equal(PublicNullableAnnotation.NotAnnotated, o2Symbol.NullableAnnotation);
            Assert.Equal(PublicNullableAnnotation.NotAnnotated, o2Symbol.Type.NullableAnnotation);
            Assert.Equal(innerLambdaSymbol, o2Symbol.ContainingSymbol, SymbolEqualityComparer.IncludeNullability);
        }
 
        [Fact(Skip = "https://github.com/dotnet/roslyn/issues/38922")]
        public void NestedLambdaReinference_LocalFunctionInLambda()
        {
            var source = @"
using System;
class C
{
    public static Action<T> Create<T>(T t, Action<T> a) => throw null!;
 
    public static void M(object? o)
    {
        var a = Create(o, o1 => {
            LocalFunction(o1);
            void LocalFunction(object? o2) 
            {
                _ = o2;
            }
        });
    }
}";
            var comp = CreateCompilation(source, options: WithNullableEnable());
            comp.VerifyDiagnostics();
 
            var syntaxTree = comp.SyntaxTrees[0];
            var root = syntaxTree.GetRoot();
            var model = comp.GetSemanticModel(syntaxTree);
 
            var lambda = root.DescendantNodes().OfType<LambdaExpressionSyntax>().Single();
            var lambdaSymbol = (IMethodSymbol)model.GetSymbolInfo(lambda).Symbol;
 
            var localFunction = lambda.DescendantNodes().OfType<LocalFunctionStatementSyntax>().Single();
            var localFunctionSymbol = (IMethodSymbol)model.GetDeclaredSymbol(localFunction);
 
            var o2Reference = localFunction.DescendantNodes().OfType<IdentifierNameSyntax>().Single(id => id.Identifier.ValueText == "o2");
            var o2Symbol = model.GetSymbolInfo(o2Reference).Symbol;
 
            Assert.Equal(lambdaSymbol, localFunctionSymbol.ContainingSymbol, SymbolEqualityComparer.IncludeNullability);
            Assert.Equal(localFunctionSymbol, o2Symbol.ContainingSymbol, SymbolEqualityComparer.IncludeNullability);
        }
 
        [Fact, WorkItem(45825, "https://github.com/dotnet/roslyn/issues/45825")]
        public void LocalFunctionReturnSpeculation()
        {
            var comp = CreateCompilation(@"
#nullable enable
class C
{
    public static implicit operator C(string s) => null!;
    C M()
    {
        string s = """";
        local();
        return null!;
        string local()
        {
            s.ToString();
            return s;
        }
    }
}");
            comp.VerifyDiagnostics();
            var tree = comp.SyntaxTrees[0];
            var model = comp.GetSemanticModel(tree);
            var localFunctionBody = tree.GetRoot().DescendantNodes().OfType<LocalFunctionStatementSyntax>().Single();
            var typeInfo = model.GetTypeInfo(localFunctionBody.DescendantNodes().OfType<ReturnStatementSyntax>().Single().Expression!);
            Assert.Equal("System.String!", typeInfo.ConvertedType.ToTestDisplayString(includeNonNullable: true));
            var @return = (ReturnStatementSyntax)SyntaxFactory.ParseStatement("return s;");
            Assert.True(model.TryGetSpeculativeSemanticModel(localFunctionBody.Body!.OpenBraceToken.SpanStart + 1, @return, out var specModel));
            typeInfo = specModel!.GetTypeInfo(@return.Expression!);
 
            // This behavior is broken. The return type here should be 'System.String!' because we are speculating within the local function.
            // https://github.com/dotnet/roslyn/issues/45825
            Assert.Equal("C!", typeInfo.ConvertedType.ToTestDisplayString(includeNonNullable: true));
        }
 
        [Fact, WorkItem(45825, "https://github.com/dotnet/roslyn/issues/45825")]
        public void LambdaReturnSpeculation()
        {
            var comp = CreateCompilation(@"
#nullable enable
class C
{
    public static implicit operator C(string s) => null!;
    C M()
    {
        string s = """";
        System.Func<string> local = () =>
        {
            s.ToString();
            return s;
        };
        local();
        return null!;
    }
}");
            comp.VerifyDiagnostics();
            var tree = comp.SyntaxTrees[0];
            var model = comp.GetSemanticModel(tree);
            var localFunctionBody = tree.GetRoot().DescendantNodes().OfType<LambdaExpressionSyntax>().Single();
            var typeInfo = model.GetTypeInfo(localFunctionBody.DescendantNodes().OfType<ReturnStatementSyntax>().Single().Expression!);
            Assert.Equal("System.String!", typeInfo.ConvertedType.ToTestDisplayString(includeNonNullable: true));
            var @return = (ReturnStatementSyntax)SyntaxFactory.ParseStatement("return s;");
            Assert.True(model.TryGetSpeculativeSemanticModel(localFunctionBody.Block!.OpenBraceToken.SpanStart + 1, @return, out var specModel));
            typeInfo = specModel!.GetTypeInfo(@return.Expression!);
 
            // This behavior is broken. The return type here should be 'System.String!' because we are speculating within the local function.
            // https://github.com/dotnet/roslyn/issues/45825
            Assert.Equal("C!", typeInfo.ConvertedType.ToTestDisplayString(includeNonNullable: true));
        }
 
        [Fact]
        public void NestedLambdaReinference_SpeculativeParamReference()
        {
            var source = @"
using System;
class C
{
    public static Action<T> Create<T>(T t, Action<T> a) => throw null!;
 
    public static void M(object? o)
    {
        var a = Create(o, o1 => { _ = o1.ToString(); });
    }
}";
 
            var comp = CreateCompilation(source, options: WithNullableEnable());
            comp.VerifyDiagnostics(
                    // (9,39): warning CS8602: Dereference of a possibly null reference.
                    //         var a = Create(o, o1 => { _ = o1.ToString(); });
                    Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "o1").WithLocation(9, 39));
 
            var syntaxTree = comp.SyntaxTrees[0];
            var root = syntaxTree.GetRoot();
            var model = comp.GetSemanticModel(syntaxTree);
 
            var lambda = root.DescendantNodes().OfType<LambdaExpressionSyntax>().Single();
            var o1Ref = lambda.DescendantNodes()
                .OfType<AssignmentExpressionSyntax>()
                .Single()
                .DescendantNodes()
                .OfType<IdentifierNameSyntax>()
                .First(i => i.Identifier.ValueText == "o1");
            var parameterSymbol = (IParameterSymbol)model.GetSymbolInfo(o1Ref).Symbol;
 
            var newStatement = (ExpressionStatementSyntax)SyntaxFactory.ParseStatement("_ = o1;");
            var newReference = ((AssignmentExpressionSyntax)newStatement.Expression).Right;
 
            Assert.True(model.TryGetSpeculativeSemanticModel(lambda.Body.SpanStart, newStatement, out var speculativeModel));
            var info = speculativeModel.GetSymbolInfo(newReference);
 
            Assert.Equal(parameterSymbol, info.Symbol, SymbolEqualityComparer.IncludeNullability);
        }
 
        [Fact]
        public void NestedLambdaReinference_GetDeclaredSymbolParameter()
        {
            var source = @"
using System;
class C
{
    public static Action<T> Create<T>(T t, Action<T> a) => throw null!;
 
    public static void M(object? o)
    {
        var a = Create(o, o1 => { });
    }
}";
 
            var comp = CreateCompilation(source, options: WithNullableEnable());
            comp.VerifyDiagnostics();
            var syntaxTree = comp.SyntaxTrees[0];
            var root = syntaxTree.GetRoot();
            var model = comp.GetSemanticModel(syntaxTree);
 
            var lambda = root.DescendantNodes().OfType<LambdaExpressionSyntax>().Single();
            var lambdaSymbol = (IMethodSymbol)model.GetSymbolInfo(lambda).Symbol;
            var parameter = lambda.DescendantNodes().OfType<ParameterSyntax>().Single();
            var paramSymbol = model.GetDeclaredSymbol(parameter);
            Assert.Equal(lambdaSymbol, paramSymbol.ContainingSymbol, SymbolEqualityComparer.IncludeNullability);
        }
 
        [Fact]
        public void NestedLambdaReinference_NestedLocalDeclaration()
        {
            var source = @"
using System;
class C
{
    public static Action<T> Create<T>(T t, Action<T> a) => throw null!;
 
    public static void M(object? o)
    {
        var a = Create(o, o1 => 
        {
            var o2 = o1 ?? new object();
            Action nested = () => { _ = o2; };
 
            foreach (var o3 in new int[] {}) {}
            foreach (var (o4, o5) in new (object, object)[]{}) {}
            (var o6, var o7) = (new object(), new object());
 
            void localFunc(out object? o)
            {
                o = null;
                var o8 = new object();
            }
        });
    }
}";
 
            var comp = CreateCompilation(source, options: WithNullableEnable());
            comp.VerifyDiagnostics(
                    // (18,18): warning CS8321: The local function 'localFunc' is declared but never used
                    //             void localFunc(out object? o)
                    Diagnostic(ErrorCode.WRN_UnreferencedLocalFunction, "localFunc").WithArguments("localFunc").WithLocation(18, 18));
 
            var syntaxTree = comp.SyntaxTrees[0];
            var root = syntaxTree.GetRoot();
            var model = comp.GetSemanticModel(syntaxTree);
 
            var lambda = root.DescendantNodes().OfType<LambdaExpressionSyntax>().First();
            var lambdaSymbol = model.GetSymbolInfo(lambda).Symbol;
            var o2Declaration = lambda.DescendantNodes().OfType<VariableDeclaratorSyntax>().First();
            var o2Symbol = model.GetDeclaredSymbol(o2Declaration);
 
            Assert.NotNull(lambdaSymbol);
            assertParent(o2Declaration);
 
            var innerLambda = root.DescendantNodes().OfType<LambdaExpressionSyntax>().ElementAt(1);
            var innerO2Reference = innerLambda.DescendantNodes().OfType<IdentifierNameSyntax>().Single(id => id.Identifier.ValueText == "o2");
            var o2Ref = model.GetSymbolInfo(innerO2Reference);
 
            Assert.Equal(o2Symbol, o2Ref.Symbol, SymbolEqualityComparer.IncludeNullability);
 
            var @foreach = lambda.DescendantNodes().OfType<ForEachStatementSyntax>().Single();
            assertParent(@foreach);
 
            foreach (var singleVarDesignation in lambda.DescendantNodes().OfType<SingleVariableDesignationSyntax>())
            {
                assertParent(singleVarDesignation);
            }
 
            var localFunction = lambda.DescendantNodes().OfType<LocalFunctionStatementSyntax>().Single();
            var localFunctionSymbol = model.GetDeclaredSymbol(localFunction);
 
            var o8Declaration = localFunction.DescendantNodes().OfType<VariableDeclaratorSyntax>().Single();
            Assert.Equal(localFunctionSymbol, model.GetDeclaredSymbol(o8Declaration).ContainingSymbol, SymbolEqualityComparer.IncludeNullability);
 
            void assertParent(SyntaxNode node)
            {
                Assert.Equal(lambdaSymbol, model.GetDeclaredSymbol(node).ContainingSymbol, SymbolEqualityComparer.IncludeNullability);
            }
        }
 
        [Fact]
        public void NestedLambdaReinference_InInitializers()
        {
            var source = @"
using System;
class C
{
    public static Action<T> Create<T>(T t, Action<T> a) => throw null!;
    public static object? s_o = null;
 
    public Action<object> f = Create(s_o ?? new object(), o1 => { 
        var o2 = o1;
    });
 
    public Action<object> Prop { get; } = Create(s_o ?? new object(), o3 => { var o4 = o3; });
}
";
 
            var comp = CreateCompilation(source, options: WithNullableEnable());
            comp.VerifyDiagnostics();
 
            var syntaxTree = comp.SyntaxTrees[0];
            var root = syntaxTree.GetRoot();
            var model = comp.GetSemanticModel(syntaxTree);
 
            var fieldLambda = root.DescendantNodes().OfType<LambdaExpressionSyntax>().First();
            var fieldLambdaSymbol = model.GetSymbolInfo(fieldLambda).Symbol;
            var o1Reference = fieldLambda.DescendantNodes().OfType<IdentifierNameSyntax>().Single(id => id.Identifier.ValueText == "o1");
            var o1Symbol = (IParameterSymbol)model.GetSymbolInfo(o1Reference).Symbol;
            var o2Decl = fieldLambda.DescendantNodes().OfType<VariableDeclaratorSyntax>().Single();
            var o2Symbol = (ILocalSymbol)model.GetDeclaredSymbol(o2Decl);
 
            Assert.Equal(PublicNullableAnnotation.NotAnnotated, o1Symbol.NullableAnnotation);
            Assert.Equal(PublicNullableAnnotation.NotAnnotated, o1Symbol.Type.NullableAnnotation);
            Assert.Equal(PublicNullableAnnotation.Annotated, o2Symbol.NullableAnnotation);
            Assert.Equal(PublicNullableAnnotation.Annotated, o2Symbol.Type.NullableAnnotation);
            Assert.Equal(fieldLambdaSymbol, o1Symbol.ContainingSymbol, SymbolEqualityComparer.IncludeNullability);
            Assert.Equal(fieldLambdaSymbol, o2Symbol.ContainingSymbol, SymbolEqualityComparer.IncludeNullability);
 
            var propertyLambda = root.DescendantNodes().OfType<LambdaExpressionSyntax>().ElementAt(1);
            var propertyLambdaSymbol = model.GetSymbolInfo(propertyLambda).Symbol;
            var o3Reference = propertyLambda.DescendantNodes().OfType<IdentifierNameSyntax>().Single(id => id.Identifier.ValueText == "o3");
            var o3Symbol = (IParameterSymbol)model.GetSymbolInfo(o3Reference).Symbol;
            var o4Decl = propertyLambda.DescendantNodes().OfType<VariableDeclaratorSyntax>().Single();
            var o4Symbol = (ILocalSymbol)model.GetDeclaredSymbol(o4Decl);
 
            Assert.Equal(PublicNullableAnnotation.NotAnnotated, o3Symbol.NullableAnnotation);
            Assert.Equal(PublicNullableAnnotation.NotAnnotated, o3Symbol.Type.NullableAnnotation);
            Assert.Equal(PublicNullableAnnotation.Annotated, o4Symbol.NullableAnnotation);
            Assert.Equal(PublicNullableAnnotation.Annotated, o4Symbol.Type.NullableAnnotation);
            Assert.Equal(propertyLambdaSymbol, o3Symbol.ContainingSymbol, SymbolEqualityComparer.IncludeNullability);
            Assert.Equal(propertyLambdaSymbol, o4Symbol.ContainingSymbol, SymbolEqualityComparer.IncludeNullability);
        }
 
        [Fact]
        public void NestedLambdaReinference_PartialExplicitTypes()
        {
            var source = @"
using System;
class C
{
    public static Action<T> Create<T>(T t, Action<T> a) => throw null!;
    public static Action<T> Create<T>(T t, Action<T, T, T> a) => throw null!;
 
    public static void M(object? o)
    {
        var a = Create(o, o1 => {
            if (o1 == null) return;
            Create(o1, (o2, object o3, object? o4) => { });
            Create(o1, (object o2, object? o3, o4) => { });
        });
    }
}";
 
            var comp = CreateCompilation(source, options: WithNullableEnable());
            comp.VerifyDiagnostics(
                    // (12,29): error CS0748: Inconsistent lambda parameter usage; parameter types must be all explicit or all implicit
                    //             Create(o1, (o2, object o3, object? o4) => { });
                    Diagnostic(ErrorCode.ERR_InconsistentLambdaParameterUsage, "object").WithLocation(12, 29),
                    // (12,40): error CS0748: Inconsistent lambda parameter usage; parameter types must be all explicit or all implicit
                    //             Create(o1, (o2, object o3, object? o4) => { });
                    Diagnostic(ErrorCode.ERR_InconsistentLambdaParameterUsage, "object?").WithLocation(12, 40),
                    // (13,48): error CS0748: Inconsistent lambda parameter usage; parameter types must be all explicit or all implicit
                    //             Create(o1, (object o2, object? o3, o4) => { });
                    Diagnostic(ErrorCode.ERR_InconsistentLambdaParameterUsage, "o4").WithLocation(13, 48));
 
            var syntaxTree = comp.SyntaxTrees[0];
            var root = syntaxTree.GetRoot();
            var model = comp.GetSemanticModel(syntaxTree);
 
            var lambda = root.DescendantNodes().OfType<LambdaExpressionSyntax>().First();
            var lambdaSymbol = model.GetSymbolInfo(lambda).Symbol;
 
            var innerLambda1 = root.DescendantNodes().OfType<LambdaExpressionSyntax>().ElementAt(1);
            var innerLambdaSymbol1 = (IMethodSymbol)model.GetSymbolInfo(innerLambda1).Symbol;
            Assert.Equal(lambdaSymbol, innerLambdaSymbol1.ContainingSymbol, SymbolEqualityComparer.IncludeNullability);
            Assert.Equal(PublicNullableAnnotation.NotAnnotated, innerLambdaSymbol1.Parameters[0].NullableAnnotation);
            Assert.Equal(PublicNullableAnnotation.NotAnnotated, innerLambdaSymbol1.Parameters[0].Type.NullableAnnotation);
            Assert.Equal(PublicNullableAnnotation.NotAnnotated, innerLambdaSymbol1.Parameters[1].NullableAnnotation);
            Assert.Equal(PublicNullableAnnotation.NotAnnotated, innerLambdaSymbol1.Parameters[1].Type.NullableAnnotation);
            Assert.Equal(PublicNullableAnnotation.NotAnnotated, innerLambdaSymbol1.Parameters[2].NullableAnnotation);
            Assert.Equal(PublicNullableAnnotation.NotAnnotated, innerLambdaSymbol1.Parameters[2].Type.NullableAnnotation);
 
            var innerLambda2 = root.DescendantNodes().OfType<LambdaExpressionSyntax>().ElementAt(1);
            var innerLambdaSymbol2 = (IMethodSymbol)model.GetSymbolInfo(innerLambda2).Symbol;
            Assert.Equal(lambdaSymbol, innerLambdaSymbol1.ContainingSymbol, SymbolEqualityComparer.IncludeNullability);
            Assert.Equal(PublicNullableAnnotation.NotAnnotated, innerLambdaSymbol2.Parameters[0].NullableAnnotation);
            Assert.Equal(PublicNullableAnnotation.NotAnnotated, innerLambdaSymbol2.Parameters[0].Type.NullableAnnotation);
            Assert.Equal(PublicNullableAnnotation.NotAnnotated, innerLambdaSymbol2.Parameters[1].NullableAnnotation);
            Assert.Equal(PublicNullableAnnotation.NotAnnotated, innerLambdaSymbol2.Parameters[1].Type.NullableAnnotation);
            Assert.Equal(PublicNullableAnnotation.NotAnnotated, innerLambdaSymbol2.Parameters[2].NullableAnnotation);
            Assert.Equal(PublicNullableAnnotation.NotAnnotated, innerLambdaSymbol2.Parameters[2].Type.NullableAnnotation);
        }
 
        [Fact]
        public void NestedLambdaReinference_AttributeAndInitializers()
        {
            var source = @"
using System;
[AttributeUsage(AttributeTargets.All)]
class A : Attribute
{
    public A(object a) {}
}
class C
{
    public static Action<T> Create<T>(T t, Action<T> a) => throw null!;
 
    public static void M(object? o)
    {
        var a = Create(o, o1 => 
        {
            var o2 = o1 ?? new object();
 
            void localFunc([A(o1)] object o3 = o2)
            {
                o = null;
                var o8 = new object();
            }
        });
    }
}";
 
            var comp = CreateCompilation(source, options: WithNullableEnable(), parseOptions: TestOptions.Regular9);
            comp.VerifyDiagnostics(
                    // (18,18): warning CS8321: The local function 'localFunc' is declared but never used
                    //             void localFunc([A(o1)] object o3 = o2)
                    Diagnostic(ErrorCode.WRN_UnreferencedLocalFunction, "localFunc").WithArguments("localFunc").WithLocation(18, 18),
                    // (18,31): error CS0182: An attribute argument must be a constant expression, typeof expression or array creation expression of an attribute parameter type
                    //             void localFunc([A(o1)] object o3 = o2)
                    Diagnostic(ErrorCode.ERR_BadAttributeArgument, "o1").WithLocation(18, 31),
                    // (18,48): error CS1736: Default parameter value for 'o3' must be a compile-time constant
                    //             void localFunc([A(o1)] object o3 = o2)
                    Diagnostic(ErrorCode.ERR_DefaultValueMustBeConstant, "o2").WithArguments("o3").WithLocation(18, 48));
 
            var syntaxTree = comp.SyntaxTrees[0];
            var root = syntaxTree.GetRoot();
            var model = comp.GetSemanticModel(syntaxTree);
 
            var lambda = root.DescendantNodes().OfType<SimpleLambdaExpressionSyntax>().First();
            var o1Decl = lambda.Parameter;
            var o1Symbol = model.GetDeclaredSymbol(o1Decl);
            var o2Decl = root.DescendantNodes().OfType<VariableDeclaratorSyntax>().ElementAt(1);
            var o2Symbol = model.GetDeclaredSymbol(o2Decl);
 
            var o1Ref = root.DescendantNodes().OfType<AttributeArgumentSyntax>().Last().Expression;
            var o1RefSymbol = model.GetSymbolInfo(o1Ref).Symbol;
 
            var o2Ref = root.DescendantNodes().OfType<ParameterSyntax>().Last().Default.Value;
            var o2RefSymbol = model.GetSymbolInfo(o2Ref).Symbol;
 
            Assert.Equal(o1Symbol, o1RefSymbol, SymbolEqualityComparer.IncludeNullability);
            Assert.Equal(o2Symbol, o2RefSymbol, SymbolEqualityComparer.IncludeNullability);
 
            var localFunction = root.DescendantNodes().OfType<LocalFunctionStatementSyntax>().Single();
 
            var speculativeAttribute = SyntaxFactory.Attribute(SyntaxFactory.ParseName("A"), SyntaxFactory.ParseAttributeArgumentList("(o2)"));
            var speculativeO2Ref = speculativeAttribute.DescendantNodes().OfType<AttributeArgumentSyntax>().Single().Expression;
            Assert.True(model.TryGetSpeculativeSemanticModel(localFunction.SpanStart, speculativeAttribute, out var speculativeModel));
            Assert.Equal(o2Symbol, speculativeModel.GetSymbolInfo(speculativeO2Ref).Symbol, SymbolEqualityComparer.IncludeNullability);
 
            var speculativeInitializer = SyntaxFactory.EqualsValueClause(SyntaxFactory.ParseExpression("o1"));
            var speculativeO1Ref = speculativeInitializer.Value;
            Assert.True(model.TryGetSpeculativeSemanticModel(localFunction.ParameterList.Parameters[0].Default.SpanStart, speculativeInitializer, out speculativeModel));
            Assert.Equal(o1Symbol, speculativeModel.GetSymbolInfo(speculativeO1Ref).Symbol, SymbolEqualityComparer.IncludeNullability);
        }
 
        [Fact]
        public void LookupSymbols_ReinferredSymbols()
        {
            var source = @"
using System;
class C
{
    public static Action<T> Create<T>(T t, Action<T> a) => throw null!;
 
    public static void M(object? o)
    {
        var a = Create(o, o1 => 
        {
            var o2 = o1 ?? new object();
            Action nested = () => { _ = o2; };
 
            foreach (var o3 in new int[] {}) {}
            foreach (var (o4, o5) in new (object, object)[]{}) {}
            (var o6, var o7) = (new object(), new object());
 
            void localFunc(out object? o)
            {
                o = null;
                var o8 = new object();
            }
        });
    }
}";
 
            var comp = CreateCompilation(source, options: WithNullableEnable());
            comp.VerifyDiagnostics(
                    // (18,18): warning CS8321: The local function 'localFunc' is declared but never used
                    //             void localFunc(out object? o)
                    Diagnostic(ErrorCode.WRN_UnreferencedLocalFunction, "localFunc").WithArguments("localFunc").WithLocation(18, 18));
 
            var syntaxTree = comp.SyntaxTrees[0];
            var root = syntaxTree.GetRoot();
            var model = comp.GetSemanticModel(syntaxTree);
 
            var lambda = root.DescendantNodes().OfType<LambdaExpressionSyntax>().First();
            var lambdaSymbol = model.GetSymbolInfo(lambda).Symbol;
            var innerLambda = root.DescendantNodes().OfType<LambdaExpressionSyntax>().ElementAt(1);
            var localFunction = lambda.DescendantNodes().OfType<LocalFunctionStatementSyntax>().Single();
            var localFunctionSymbol = model.GetDeclaredSymbol(localFunction);
 
            var position = localFunction.DescendantNodes().OfType<VariableDeclarationSyntax>().Single().Span.End;
 
            var lookupResults = model.LookupSymbols(position);
 
            var o2Result = lookupResults.OfType<ILocalSymbol>().First(l => l.Name == "o2");
            var o8Result = lookupResults.OfType<ILocalSymbol>().First(l => l.Name == "o8");
            Assert.Equal(lambdaSymbol, o2Result.ContainingSymbol, SymbolEqualityComparer.IncludeNullability);
            Assert.Equal(localFunctionSymbol, o8Result.ContainingSymbol, SymbolEqualityComparer.IncludeNullability);
 
            var o1Result = lookupResults.OfType<IParameterSymbol>().First(p => p.Name == "o1");
            var oResult = lookupResults.OfType<IParameterSymbol>().First(p => p.Name == "o");
            Assert.Equal(lambdaSymbol, o1Result.ContainingSymbol, SymbolEqualityComparer.IncludeNullability);
            Assert.Equal(localFunctionSymbol, oResult.ContainingSymbol, SymbolEqualityComparer.IncludeNullability);
 
            var localFunctionResult = lookupResults.OfType<IMethodSymbol>().First(m => m.MethodKind == MethodKind.LocalFunction);
            Assert.Equal(localFunctionSymbol, localFunctionResult, SymbolEqualityComparer.IncludeNullability);
        }
 
        [Fact(Skip = "https://github.com/dotnet/roslyn/issues/38922")]
        public void LocalFunction_GenericTypeParameters()
        {
            var source = @"
using System;
class C
{
    public static Action<T> Create<T>(T t, Action<T> a) => throw null!;
	public static T[] Create<T>(T t) => throw null!;
 
    public static void M(object? o)
    {
        var a = Create(o, o1 => {
            LocalFunction(o1);
            T LocalFunction<T>(T t) 
            {
                _ = Create(t); // Type argument for Create needs to be reparented
				var d = new D<T>(); // Type argument in D's substituted type needs to be reparented
				d.DoSomething(t); // Argument of the function needs to be reparented
                var f = SecondFunction(); // Return type of nested function needs to be reparented
				return d.Prop; // Return type needs to be reparented
                T SecondFunction() { return t; }
            }
        });
    }
}
class D<T>
{
	public void DoSomething(T t) => throw null!;
	public T Prop { get; } = default!;
}";
 
            var comp = CreateCompilation(source, options: WithNullableEnable());
            comp.VerifyDiagnostics();
 
            var syntaxTree = comp.SyntaxTrees[0];
            var root = syntaxTree.GetRoot();
            var model = comp.GetSemanticModel(syntaxTree);
 
            var lambda = root.DescendantNodes().OfType<LambdaExpressionSyntax>().First();
            var lambdaSymbol = model.GetSymbolInfo(lambda).Symbol;
            var localFunction = lambda.DescendantNodes().OfType<LocalFunctionStatementSyntax>().First();
            var localFunctionSymbol = (IMethodSymbol)model.GetDeclaredSymbol(localFunction);
            var nestedLocalFunction = (IMethodSymbol)model.GetDeclaredSymbol(lambda.DescendantNodes().OfType<LocalFunctionStatementSyntax>().ElementAt(1));
 
            var typeParameters = localFunctionSymbol.TypeParameters[0];
            Assert.Same(localFunctionSymbol, typeParameters.ContainingSymbol);
        }
 
        [Fact]
        public void SpeculativeModel_InAttribute01()
        {
            var source = @"
using System;
[AttributeUsage(AttributeTargets.ReturnValue)]
class Attr : Attribute
{
    public Attr(string Test) {}
}
class Test
{
    const string Constant = ""Test"";
    [return: Attr(""Test"")]
    void M() {}
}
";
 
            var comp = CreateCompilation(source, options: WithNullableEnable());
 
            var syntaxTree = comp.SyntaxTrees[0];
            var root = syntaxTree.GetRoot();
            var model = comp.GetSemanticModel(syntaxTree);
 
            var attributeUsage = root.DescendantNodes().OfType<AttributeSyntax>().ElementAt(1);
            var newAttributeUsage = SyntaxFactory.Attribute(SyntaxFactory.ParseName("Attr"), SyntaxFactory.ParseAttributeArgumentList("(Constant)"));
 
            Assert.True(model.TryGetSpeculativeSemanticModel(attributeUsage.SpanStart, newAttributeUsage, out var specModel));
            Assert.NotNull(specModel);
 
            var symbolInfo = specModel.GetSymbolInfo(newAttributeUsage.ArgumentList.Arguments[0].Expression);
            Assert.Equal(SpecialType.System_String, ((IFieldSymbol)symbolInfo.Symbol).Type.SpecialType);
        }
 
        [Fact]
        public void SpeculativeModel_InAttribute02()
        {
            var source =
@"class A : System.Attribute
{
    internal A(object obj) { }
}
class Program
{
#nullable disable
    [A(
#nullable enable
        typeof(object)]
    static void Main()
    {
    }
}";
            var comp = CreateCompilation(source);
            var syntaxTree = comp.SyntaxTrees[0];
            var model = comp.GetSemanticModel(syntaxTree);
            var typeOf = syntaxTree.GetRoot().DescendantNodes().OfType<TypeOfExpressionSyntax>().Single();
            var type = SyntaxFactory.ParseTypeName("string");
            model.TryGetSpeculativeSemanticModel(typeOf.Type.SpanStart, type, out model, SpeculativeBindingOption.BindAsTypeOrNamespace);
            Assert.NotNull(model);
 
            var symbolInfo = model.GetTypeInfo(type);
            Assert.Equal(SpecialType.System_String, symbolInfo.Type.SpecialType);
        }
 
        [Fact]
        public void ParameterDefaultValue()
        {
            var source = @"
class Test
{
    void M0(object obj = default) { } // 1
    void M1(int i = default) { }
}
";
 
            var comp = CreateCompilation(source, options: WithNullableEnable());
            comp.VerifyDiagnostics(
                // (4,26): warning CS8625: Cannot convert null literal to non-nullable reference type.
                //     void M0(object obj = default) { } // 1
                Diagnostic(ErrorCode.WRN_NullAsNonNullable, "default").WithLocation(4, 26));
 
            var syntaxTree = comp.SyntaxTrees[0];
            var root = syntaxTree.GetRoot();
            var model = comp.GetSemanticModel(syntaxTree);
 
            var default0 = root.DescendantNodes().OfType<EqualsValueClauseSyntax>().ElementAt(0).Value;
            Assert.Equal(PublicNullableFlowState.MaybeNull, model.GetTypeInfo(default0).Nullability.FlowState);
 
            var default1 = root.DescendantNodes().OfType<EqualsValueClauseSyntax>().ElementAt(1).Value;
            Assert.Equal(PublicNullableFlowState.NotNull, model.GetTypeInfo(default1).Nullability.FlowState);
        }
 
        [Fact]
        public void AttributeDefaultValue()
        {
            var source = @"
using System;
 
class Attr : Attribute
{
    public Attr(object obj, int i) { }
}
 
[Attr(default, default)] // 1
class Test
{
}
";
 
            var comp = CreateCompilation(source, options: WithNullableEnable());
            comp.VerifyDiagnostics(
                // (9,7): warning CS8625: Cannot convert null literal to non-nullable reference type.
                // [Attr(default, default)] // 1
                Diagnostic(ErrorCode.WRN_NullAsNonNullable, "default").WithLocation(9, 7));
 
            var syntaxTree = comp.SyntaxTrees[0];
            var root = syntaxTree.GetRoot();
            var model = comp.GetSemanticModel(syntaxTree);
 
            var default0 = root.DescendantNodes().OfType<AttributeArgumentSyntax>().ElementAt(0).Expression;
            Assert.Equal(PublicNullableFlowState.MaybeNull, model.GetTypeInfo(default0).Nullability.FlowState);
 
            var default1 = root.DescendantNodes().OfType<AttributeArgumentSyntax>().ElementAt(1).Expression;
            Assert.Equal(PublicNullableFlowState.NotNull, model.GetTypeInfo(default1).Nullability.FlowState);
        }
 
        [Fact]
        [WorkItem(38638, "https://github.com/dotnet/roslyn/issues/38638")]
        public void TypeParameter_Default()
        {
            var source =
@"#nullable enable
abstract class A<T>
{
    internal abstract void F<U>() where U : T;
}
class B1<T> : A<T>
{
    internal override void F<U>() { _ = default(U); }
}
class B2 : A<int?>
{
    internal override void F<U>() { _ = default(U); }
}";
            var comp = CreateCompilation(source);
            comp.VerifyDiagnostics();
            var tree = comp.SyntaxTrees[0];
            var model = comp.GetSemanticModel(tree);
            var exprs = tree.GetRoot().DescendantNodes().OfType<DefaultExpressionSyntax>().ToArray();
            verify(exprs[0], PublicNullableAnnotation.Annotated, PublicNullableFlowState.MaybeNull);
            verify(exprs[1], PublicNullableAnnotation.Annotated, PublicNullableFlowState.MaybeNull);
 
            void verify(DefaultExpressionSyntax expr, PublicNullableAnnotation expectedAnnotation, PublicNullableFlowState expectedState)
            {
                var info = model.GetTypeInfoAndVerifyIOperation(expr).Nullability;
                Assert.Equal(expectedAnnotation, info.Annotation);
                Assert.Equal(expectedState, info.FlowState);
            }
        }
 
        [Fact]
        [WorkItem(40750, "https://github.com/dotnet/roslyn/issues/40750")]
        public void SpeculativeSymbolInfo_OutVariableInDifferentContext_01()
        {
            var source =
@"#nullable enable
class C
{
    void M(out C c2)
    {
        M(out global::C c);
        c2 = c;
    }
}";
            var comp = CreateCompilation(source);
            comp.VerifyDiagnostics();
            var tree = comp.SyntaxTrees[0];
            var model = comp.GetSemanticModel(tree);
            var type = tree.GetRoot().DescendantNodes().OfType<DeclarationExpressionSyntax>().Single().Type;
 
            var statement = SyntaxFactory.ParseStatement(@"M(out C c);");
            Assert.True(model.TryGetSpeculativeSemanticModel(type.SpanStart, statement, out var speculativeModel));
 
            var type2 = statement.DescendantNodes().OfType<DeclarationExpressionSyntax>().Single().Type;
            var symbol2 = speculativeModel.GetSymbolInfo(type2);
            Assert.Equal(PublicNullableAnnotation.NotAnnotated, ((ITypeSymbol)symbol2.Symbol).NullableAnnotation);
        }
 
        [Fact]
        [WorkItem(40750, "https://github.com/dotnet/roslyn/issues/40750")]
        public void SpeculativeSymbolInfo_OutVariableInDifferentContext_02()
        {
            var source =
@"#nullable disable
class C
{
    void M(out C c2)
    {
        M(out global::C c);
        c2 = c;
    }
}";
            var comp = CreateCompilation(source, options: WithNullableEnable());
            comp.VerifyDiagnostics();
            var tree = comp.SyntaxTrees[0];
            var model = comp.GetSemanticModel(tree);
            var type = tree.GetRoot().DescendantNodes().OfType<DeclarationExpressionSyntax>().Single().Type;
 
            var statement = SyntaxFactory.ParseStatement(@"M(out C c);");
            Assert.True(model.TryGetSpeculativeSemanticModel(type.SpanStart, statement, out var speculativeModel));
 
            var type2 = statement.DescendantNodes().OfType<DeclarationExpressionSyntax>().Single().Type;
            var symbol2 = speculativeModel.GetSymbolInfo(type2);
            Assert.Equal(PublicNullableAnnotation.None, ((ITypeSymbol)symbol2.Symbol).NullableAnnotation);
        }
 
        [Fact]
        [WorkItem(40750, "https://github.com/dotnet/roslyn/issues/40750")]
        public void SpeculativeSymbolInfo_OutVariableInDifferentContext_03()
        {
            var source =
@"#nullable enable
class C
{
    void M(out C c2)
    {
        M(out global::C c);
        c2 = c;
    }
}";
            var comp = CreateCompilation(source);
            comp.VerifyDiagnostics();
            var tree = comp.SyntaxTrees[0];
            var model = comp.GetSemanticModel(tree);
            var type = tree.GetRoot().DescendantNodes().OfType<DeclarationExpressionSyntax>().Single().Type;
 
            var statement = SyntaxFactory.ParseStatement(@"
#nullable disable
M(out C c);");
            Assert.True(model.TryGetSpeculativeSemanticModel(type.SpanStart, statement, out var speculativeModel));
 
            var type2 = statement.DescendantNodes().OfType<DeclarationExpressionSyntax>().Single().Type;
            var symbol2 = speculativeModel.GetSymbolInfo(type2);
            Assert.Equal(PublicNullableAnnotation.None, ((ITypeSymbol)symbol2.Symbol).NullableAnnotation);
        }
 
        [Fact]
        [WorkItem(40750, "https://github.com/dotnet/roslyn/issues/40750")]
        public void SpeculativeSymbolInfo_OutVariableInDifferentContext_04()
        {
            var source =
@"#nullable disable
class C
{
    void M(out C c2)
    {
        M(out global::C c);
        c2 = c;
    }
}";
            var comp = CreateCompilation(source, options: WithNullableEnable());
            comp.VerifyDiagnostics();
            var tree = comp.SyntaxTrees[0];
            var model = comp.GetSemanticModel(tree);
            var type = tree.GetRoot().DescendantNodes().OfType<DeclarationExpressionSyntax>().Single().Type;
 
            var statement = SyntaxFactory.ParseStatement(@"
#nullable restore
M(out C c);");
            Assert.True(model.TryGetSpeculativeSemanticModel(type.SpanStart, statement, out var speculativeModel));
 
            var type2 = statement.DescendantNodes().OfType<DeclarationExpressionSyntax>().Single().Type;
            var symbol2 = speculativeModel.GetSymbolInfo(type2);
            Assert.Equal(PublicNullableAnnotation.NotAnnotated, ((ITypeSymbol)symbol2.Symbol).NullableAnnotation);
        }
 
        [Fact]
        [WorkItem(40750, "https://github.com/dotnet/roslyn/issues/40750")]
        public void SpeculativeSymbolInfo_OutVariableInDifferentContext_05()
        {
            var source =
@"#nullable disable annotations
class C
{
    void M(out C c2)
    {
        M(out global::C c);
        c2 = c;
    }
}";
            var comp = CreateCompilation(source, options: WithNullableEnable());
            comp.VerifyDiagnostics();
            var tree = comp.SyntaxTrees[0];
            var model = comp.GetSemanticModel(tree);
            var type = tree.GetRoot().DescendantNodes().OfType<DeclarationExpressionSyntax>().Single().Type;
 
            var statement = SyntaxFactory.ParseStatement(@"
#nullable restore annotations
M(out C c);");
            Assert.True(model.TryGetSpeculativeSemanticModel(type.SpanStart, statement, out var speculativeModel));
 
            var type2 = statement.DescendantNodes().OfType<DeclarationExpressionSyntax>().Single().Type;
            var symbol2 = speculativeModel.GetSymbolInfo(type2);
            Assert.Equal(PublicNullableAnnotation.NotAnnotated, ((ITypeSymbol)symbol2.Symbol).NullableAnnotation);
        }
 
        [Fact]
        [WorkItem(40750, "https://github.com/dotnet/roslyn/issues/40750")]
        public void SpeculativeSymbolInfo_WholeBody_01()
        {
            var source =
@"#nullable enable
class C
{
    void M(out C c2)
    {
        M(out global::C c);
        c2 = c;
    }
}";
            var comp = CreateCompilation(source, options: WithNullableDisable());
            comp.VerifyDiagnostics();
            var tree = comp.SyntaxTrees[0];
            var model = comp.GetSemanticModel(tree);
            var type = tree.GetRoot().DescendantNodes().OfType<DeclarationExpressionSyntax>().Single().Type;
 
            var methodDeclaration = (MethodDeclarationSyntax)SyntaxFactory.ParseMemberDeclaration(@"
void M2(out C c2)
{
    M(out C c);
}");
            Assert.True(model.TryGetSpeculativeSemanticModelForMethodBody(type.SpanStart, methodDeclaration, out var speculativeModel));
 
            var type2 = methodDeclaration.DescendantNodes().OfType<DeclarationExpressionSyntax>().Single().Type;
            var symbol2 = speculativeModel.GetSymbolInfo(type2);
            Assert.Equal(PublicNullableAnnotation.NotAnnotated, ((ITypeSymbol)symbol2.Symbol).NullableAnnotation);
        }
 
        [Fact]
        [WorkItem(40750, "https://github.com/dotnet/roslyn/issues/40750")]
        public void SpeculativeSymbolInfo_WholeBody_02()
        {
            var source =
@"#nullable enable
class C
{
    void M(out C c2)
    {
        M(out global::C c);
        c2 = c;
    }
}";
            var comp = CreateCompilation(source, options: WithNullableDisable());
            comp.VerifyDiagnostics();
            var tree = comp.SyntaxTrees[0];
            var model = comp.GetSemanticModel(tree);
            var type = tree.GetRoot().DescendantNodes().OfType<DeclarationExpressionSyntax>().Single().Type;
 
            var methodDeclaration = (MethodDeclarationSyntax)SyntaxFactory.ParseMemberDeclaration(@"
void M2(out C c2)
{
#nullable disable
    M(out C c);
}");
            Assert.True(model.TryGetSpeculativeSemanticModelForMethodBody(type.SpanStart, methodDeclaration, out var speculativeModel));
 
            var type2 = methodDeclaration.DescendantNodes().OfType<DeclarationExpressionSyntax>().Single().Type;
            var symbol2 = speculativeModel.GetSymbolInfo(type2);
            Assert.Equal(PublicNullableAnnotation.None, ((ITypeSymbol)symbol2.Symbol).NullableAnnotation);
        }
 
        [Fact]
        [WorkItem(40750, "https://github.com/dotnet/roslyn/issues/40750")]
        public void SpeculativeSymbolInfo_ArrowExpression_01()
        {
            var source =
@"#nullable enable
class C
{
    void M(out C c2)
    {
        M(out global::C c);
        c2 = c;
    }
}";
            var comp = CreateCompilation(source, options: WithNullableDisable());
            comp.VerifyDiagnostics();
            var tree = comp.SyntaxTrees[0];
            var model = comp.GetSemanticModel(tree);
            var type = tree.GetRoot().DescendantNodes().OfType<DeclarationExpressionSyntax>().Single().Type;
 
            var arrow = SyntaxFactory.ArrowExpressionClause(SyntaxFactory.ParseExpression(" M(out C c)"));
            Assert.True(model.TryGetSpeculativeSemanticModel(type.SpanStart, arrow, out var speculativeModel));
 
            var type2 = arrow.DescendantNodes().OfType<DeclarationExpressionSyntax>().Single().Type;
            var symbol2 = speculativeModel.GetSymbolInfo(type2);
            Assert.Equal(PublicNullableAnnotation.NotAnnotated, ((ITypeSymbol)symbol2.Symbol).NullableAnnotation);
        }
 
        [Fact]
        [WorkItem(40750, "https://github.com/dotnet/roslyn/issues/40750")]
        public void SpeculativeSymbolInfo_ArrowExpression_02()
        {
            var source =
@"#nullable enable
class C
{
    void M(out C c2)
    {
        M(out global::C c);
        c2 = c;
    }
}";
            var comp = CreateCompilation(source, options: WithNullableDisable());
            comp.VerifyDiagnostics();
            var tree = comp.SyntaxTrees[0];
            var model = comp.GetSemanticModel(tree);
            var type = tree.GetRoot().DescendantNodes().OfType<DeclarationExpressionSyntax>().Single().Type;
 
            var arrow = SyntaxFactory.ArrowExpressionClause(SyntaxFactory.ParseExpression(@"
#nullable disable
M(out C c)"));
            Assert.True(model.TryGetSpeculativeSemanticModel(type.SpanStart, arrow, out var speculativeModel));
 
            var type2 = arrow.DescendantNodes().OfType<DeclarationExpressionSyntax>().Single().Type;
            var symbol2 = speculativeModel.GetSymbolInfo(type2);
            Assert.Equal(PublicNullableAnnotation.None, ((ITypeSymbol)symbol2.Symbol).NullableAnnotation);
        }
 
        [Fact]
        [WorkItem(40750, "https://github.com/dotnet/roslyn/issues/40750")]
        public void SpeculativeSymbolInfo_ConstructorInitializer_01()
        {
            var source =
@"#nullable enable
class C
{
    C() : this("""") {}
    C(string s) {}
    string M(out C c2)
    {
        M(out global::C c);
        c2 = c;
        return """";
    }
}";
            var comp = CreateCompilation(source, options: WithNullableDisable());
            comp.VerifyDiagnostics();
            var tree = comp.SyntaxTrees[0];
            var model = comp.GetSemanticModel(tree);
            var initializer = tree.GetRoot().DescendantNodes().OfType<ConstructorInitializerSyntax>().Single();
 
            var newInitializer = SyntaxFactory.ConstructorInitializer(SyntaxKind.ThisConstructorInitializer, SyntaxFactory.ParseArgumentList(@"(M(out C c))"));
            Assert.True(model.TryGetSpeculativeSemanticModel(initializer.SpanStart, newInitializer, out var speculativeModel));
 
            var type2 = newInitializer.DescendantNodes().OfType<DeclarationExpressionSyntax>().Single().Type;
            var symbol2 = speculativeModel.GetSymbolInfo(type2);
            Assert.Equal(PublicNullableAnnotation.NotAnnotated, ((ITypeSymbol)symbol2.Symbol).NullableAnnotation);
        }
 
        [Fact]
        [WorkItem(40750, "https://github.com/dotnet/roslyn/issues/40750")]
        public void SpeculativeSymbolInfo_ConstructorInitializer_02()
        {
            var source =
@"#nullable enable
class C
{
    C() : this("""") {}
    C(string s) {}
    string M(out C c2)
    {
        M(out global::C c);
        c2 = c;
        return """";
    }
}";
            var comp = CreateCompilation(source, options: WithNullableDisable());
            comp.VerifyDiagnostics();
            var tree = comp.SyntaxTrees[0];
            var model = comp.GetSemanticModel(tree);
            var initializer = tree.GetRoot().DescendantNodes().OfType<ConstructorInitializerSyntax>().Single();
 
            var newInitializer = SyntaxFactory.ConstructorInitializer(SyntaxKind.ThisConstructorInitializer, SyntaxFactory.ParseArgumentList(@"(
#nullable disable
M(out C c))"));
            Assert.True(model.TryGetSpeculativeSemanticModel(initializer.SpanStart, newInitializer, out var speculativeModel));
 
            var type2 = newInitializer.DescendantNodes().OfType<DeclarationExpressionSyntax>().Single().Type;
            var symbol2 = speculativeModel.GetSymbolInfo(type2);
            Assert.Equal(PublicNullableAnnotation.None, ((ITypeSymbol)symbol2.Symbol).NullableAnnotation);
        }
 
        [Fact]
        [WorkItem(40750, "https://github.com/dotnet/roslyn/issues/40750"),
         WorkItem(39993, "https://github.com/dotnet/roslyn/issues/39993")]
        public void SpeculativeSymbolInfo_Expression()
        {
            var source =
@"#nullable enable
class C
{
    void M(out C c2)
    {
        M(out global::C c);
        c2 = c;
    }
}";
            var comp = CreateCompilation(source, options: WithNullableDisable());
            comp.VerifyDiagnostics();
            var tree = comp.SyntaxTrees[0];
            var model = comp.GetSemanticModel(tree);
            var initializer = tree.GetRoot().DescendantNodes().OfType<DeclarationExpressionSyntax>().Single();
 
            var expression = SyntaxFactory.ParseExpression(@"M(out C c)");
            var symbol2 = (IMethodSymbol)model.GetSpeculativeSymbolInfo(initializer.Position, expression, SpeculativeBindingOption.BindAsExpression).Symbol;
            Assert.Equal(PublicNullableAnnotation.NotAnnotated, symbol2.Parameters.Single().Type.NullableAnnotation);
        }
 
        [Fact]
        public void GetOperationOnNullableSuppression()
        {
            var source = @"
#pragma warning disable CS0219 // Unused local
#nullable enable
class C
{
    void M(string p)
    {
        string l1 = default!;
        M(null!);
        C c = new C();
        string l2 = c.M2()!;
    }
 
    string? M2() => null;
}";
 
            var comp = CreateCompilation(source);
            comp.VerifyDiagnostics();
            var tree = comp.SyntaxTrees[0];
            var model = comp.GetSemanticModel(tree);
 
            var suppressions = tree.GetRoot().DescendantNodes().OfType<PostfixUnaryExpressionSyntax>().Where(p => p.IsKind(SyntaxKind.SuppressNullableWarningExpression)).ToList();
            Assert.Equal(3, suppressions.Count);
 
            foreach (var s in suppressions)
            {
                Assert.Null(model.GetOperation(s));
            }
        }
 
        [Fact]
        public void UnconstrainedTypeParameter()
        {
            var source =
@"#nullable enable
class Program
{
    static T F<T>(T t) => t;
    static T F1<T>(T? x1)
    {
        T y1 = F(x1); // 1
        if (x1 == null) throw null!;
        T z1 = F(x1);
        return z1;
    }
    static T F2<T>(T x2)
    {
        T y2 = F(x2);
        x2 = default; // 2
        T z2 = F(x2); // 3
        return z2; // 4
    }
}";
 
            var comp = CreateCompilation(source, parseOptions: TestOptions.Regular9);
            comp.VerifyDiagnostics(
                // (7,16): warning CS8600: Converting null literal or possible null value to non-nullable type.
                //         T y1 = F(x1); // 1
                Diagnostic(ErrorCode.WRN_ConvertingNullableToNonNullable, "F(x1)").WithLocation(7, 16),
                // (15,14): warning CS8600: Converting null literal or possible null value to non-nullable type.
                //         x2 = default; // 2
                Diagnostic(ErrorCode.WRN_ConvertingNullableToNonNullable, "default").WithLocation(15, 14),
                // (16,16): warning CS8600: Converting null literal or possible null value to non-nullable type.
                //         T z2 = F(x2); // 3
                Diagnostic(ErrorCode.WRN_ConvertingNullableToNonNullable, "F(x2)").WithLocation(16, 16),
                // (17,16): warning CS8603: Possible null reference return.
                //         return z2; // 4
                Diagnostic(ErrorCode.WRN_NullReferenceReturn, "z2").WithLocation(17, 16));
 
            var syntaxTree = comp.SyntaxTrees[0];
            var model = comp.GetSemanticModel(syntaxTree);
            var invocations = syntaxTree.GetRoot().DescendantNodes().OfType<InvocationExpressionSyntax>();
            var actualAnnotations = invocations.Select(inv => (((IMethodSymbol)model.GetSymbolInfo(inv).Symbol)).TypeArguments[0].NullableAnnotation).ToArray();
            var expectedAnnotations = new[]
            {
                PublicNullableAnnotation.Annotated,
                PublicNullableAnnotation.NotAnnotated,
                PublicNullableAnnotation.NotAnnotated,
                PublicNullableAnnotation.Annotated,
            };
            AssertEx.Equal(expectedAnnotations, actualAnnotations);
        }
 
        [Fact]
        public void AutoPropInitializer_01()
        {
            var source = @"
class C
{
    public string Prop { get; set; } = ""a"";
    public C()
    {
        Prop.ToString();
    }
 
    public C(string s) : this()
    {
        Prop.ToString();
    }
}
";
            var comp = CreateCompilation(source, options: WithNullableEnable());
            comp.VerifyDiagnostics();
 
            var tree = comp.SyntaxTrees.Single();
            var model = comp.GetSemanticModel(tree);
 
            var memberAccesses = tree.GetRoot().DescendantNodes().OfType<MemberAccessExpressionSyntax>().ToArray();
            Assert.Equal(2, memberAccesses.Length);
 
            var receiver = memberAccesses[0].Expression;
            var info = model.GetTypeInfo(receiver);
            Assert.Equal(PublicNullableAnnotation.NotAnnotated, info.Type.NullableAnnotation);
            Assert.Equal(PublicNullableFlowState.NotNull, info.Nullability.FlowState);
 
            receiver = memberAccesses[1].Expression;
            info = model.GetTypeInfo(receiver);
            Assert.Equal(PublicNullableAnnotation.NotAnnotated, info.Type.NullableAnnotation);
            Assert.Equal(PublicNullableFlowState.NotNull, info.Nullability.FlowState);
        }
 
        private class AutoPropInitializer_02_Analyzer : DiagnosticAnalyzer
        {
            public int HitCount;
 
            private static readonly DiagnosticDescriptor Descriptor =
               new DiagnosticDescriptor("XY0000", "Test", "Test", "Test", DiagnosticSeverity.Warning, true, "Test", "Test");
 
            public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics
            => ImmutableArray.Create(Descriptor);
 
            public override void Initialize(AnalysisContext context)
            {
                context.RegisterSyntaxNodeAction(AnalyzeMemberAccess, SyntaxKind.SimpleMemberAccessExpression);
            }
 
            private void AnalyzeMemberAccess(SyntaxNodeAnalysisContext context)
            {
                var node = (MemberAccessExpressionSyntax)context.Node;
                var model = context.SemanticModel;
                var info = model.GetTypeInfo(node.Expression);
 
                Assert.Equal(PublicNullableAnnotation.NotAnnotated, info.Nullability.Annotation);
                Assert.Equal(PublicNullableFlowState.NotNull, info.Nullability.FlowState);
 
                Interlocked.Increment(ref HitCount);
            }
        }
 
        [Fact]
        public void AutoPropInitializer_02()
        {
            var source = @"
class C
{
    public string Prop { get; set; } = ""a"";
    public C()
    {
        Prop.ToString();
    }
 
    public C(string s) : this()
    {
        Prop.ToString();
    }
}
";
            var comp = CreateCompilation(source, options: WithNullableEnable());
            comp.VerifyDiagnostics();
 
            var analyzer = new AutoPropInitializer_02_Analyzer();
            comp.GetAnalyzerDiagnostics(new[] { analyzer }).Verify();
            Assert.Equal(2, analyzer.HitCount);
        }
 
        [Fact]
        public void AutoPropInitializer_Speculation()
        {
            var source = @"
class C
{
    public string Prop { get; set; } = ""a"";
    public C()
    {
    }
}
";
            var comp = CreateCompilation(source, options: WithNullableEnable());
            comp.VerifyDiagnostics();
 
            var tree = comp.SyntaxTrees.Single();
            var model = comp.GetSemanticModel(tree);
 
            var ctorDecl = tree.GetRoot()
                .DescendantNodes()
                .OfType<ConstructorDeclarationSyntax>()
                .Single();
            var spanStart = ctorDecl
                .Body
                .OpenBraceToken
                .SpanStart;
 
            var newBody = SyntaxFactory.ParseStatement("Prop.ToString();");
            Assert.True(model.TryGetSpeculativeSemanticModel(spanStart, newBody, out var speculativeModel));
 
            var newAccess = newBody.DescendantNodes().OfType<MemberAccessExpressionSyntax>().Single();
            var typeInfo = speculativeModel.GetTypeInfo(newAccess.Expression);
            Assert.Equal(PublicNullableAnnotation.NotAnnotated, typeInfo.Type.NullableAnnotation);
            Assert.Equal(PublicNullableFlowState.NotNull, typeInfo.Nullability.FlowState);
        }
 
        [Theory, WorkItem(47467, "https://github.com/dotnet/roslyn/issues/47467")]
        [InlineData("void M() {}")]
        [InlineData(@"void M() {}
M();")]
        [InlineData(@"
// Comment
void M() {}
M();")]
        public void GetDeclaredSymbolTopLevelStatementsWithLocalFunctionFirst(string code)
        {
            var comp = CreateCompilation(code, options: TestOptions.ReleaseExe.WithNullableContextOptions(NullableContextOptions.Enable));
 
            var tree = comp.SyntaxTrees[0];
            var localFunction = tree.GetRoot().DescendantNodes().OfType<LocalFunctionStatementSyntax>().Single();
            var model = comp.GetSemanticModel(tree);
 
            AssertEx.Equal("void M()", model.GetDeclaredSymbol(localFunction).ToTestDisplayString());
        }
 
        [Fact]
        public void TupleNames_DifferentTernaryBranches_PrivateTupleField()
        {
            var source = @"
#nullable enable
class C
{
    static void M(int a, int b, bool c)
    {
        var (x, y) = c ? ((object)1, a) : (b, 2);
    }
}
namespace System
{
    struct ValueTuple<T1, T2>
    {
        public T1 Item1;
        private T2 Item2;
        public ValueTuple(T1 item1, T2 item2) => throw null;
    }
}
";
 
            var comp = CreateCompilation(source, targetFramework: TargetFramework.Minimal);
 
            var tree = comp.SyntaxTrees[0];
            var model = comp.GetSemanticModel(tree);
            var ternary = tree.GetRoot().DescendantNodes().OfType<ConditionalExpressionSyntax>().Single();
            var operation = model.GetOperation(ternary);
            AssertEx.Equal("(System.Object, System.Int32 a)", operation.Type.ToTestDisplayString());
        }
 
        [Fact]
        public void TupleNames_BadSignatures()
        {
            string source = @"
class C
{
    static void M()
    {
        var x = (a: ""Alice"", b: ""Bob"");
        System.Console.WriteLine($""{x.a}"");
    }
}
 
namespace System
{
    public struct ValueTuple<T1, T2>
    {
        public int Item2;
 
        public ValueTuple(T1 item1, T2 item2)
        {
            this.Item2 = 2;
        }
    }
}
";
            var comp = CreateCompilation(source, assemblyName: "comp", options: WithNullableEnable());
            comp.VerifyDiagnostics(
                // (7,39): error CS8128: Member 'Item1' was not found on type '(T1, T2)' from assembly 'comp, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'.
                //         System.Console.WriteLine($"{x.a}");
                Diagnostic(ErrorCode.ERR_PredefinedTypeMemberNotFoundInAssembly, "a").WithArguments("Item1", "(T1, T2)", "comp, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null").WithLocation(7, 39),
                // (19,18): error CS0229: Ambiguity between '(T1, T2).Item2' and '(T1, T2).Item2'
                //             this.Item2 = 2;
                Diagnostic(ErrorCode.ERR_AmbigMember, "Item2").WithArguments("(T1, T2).Item2", "(T1, T2).Item2").WithLocation(19, 18)
                );
 
            var tree = comp.SyntaxTrees[0];
            var model = comp.GetSemanticModel(tree);
 
            var tupleLiteral = tree.GetRoot().DescendantNodes().OfType<TupleExpressionSyntax>().Single();
            AssertEx.Equal("(System.String a, System.String b)", model.GetTypeInfo(tupleLiteral).Type.ToTestDisplayString(includeNonNullable: false));
        }
 
        [Fact, WorkItem(51461, "https://github.com/dotnet/roslyn/issues/51461")]
        public void LambdaInBadExpression()
        {
            var comp = CreateCompilation(@"
public class C
{
    public C(int i) {}
 
    static void M1()
    {
        string s = null;
        C c = new C(() =>
        { 
            M2();
            _ = s;
            s = """";
            _ = s;
        });
    }
 
    static void M2() {}
}
", options: WithNullableEnable());
 
            comp.VerifyDiagnostics(
                // (8,20): warning CS8600: Converting null literal or possible null value to non-nullable type.
                //         string s = null;
                Diagnostic(ErrorCode.WRN_ConvertingNullableToNonNullable, "null").WithLocation(8, 20),
                // (9,24): error CS1660: Cannot convert lambda expression to type 'int' because it is not a delegate type
                //         C c = new C(() =>
                Diagnostic(ErrorCode.ERR_AnonMethToNonDel, "=>").WithArguments("lambda expression", "int").WithLocation(9, 24));
 
            var tree = comp.SyntaxTrees[0];
            var model = comp.GetSemanticModel(tree);
 
            var constructor = tree.GetRoot().DescendantNodes().OfType<ObjectCreationExpressionSyntax>().Single();
            AssertEx.Equal("C..ctor(System.Int32 i)", model.GetSymbolInfo(constructor).CandidateSymbols[0].ToTestDisplayString());
 
            var assignmentsInLambda = constructor.DescendantNodes().OfType<AssignmentExpressionSyntax>().ToArray();
            AssertEx.Equal("_ = s", assignmentsInLambda[0].ToString());
            AssertEx.Equal("_ = s", assignmentsInLambda[2].ToString());
            AssertEx.Equal("System.String?", model.GetTypeInfo(assignmentsInLambda[0].Right).Type.ToTestDisplayString(includeNonNullable: true));
            AssertEx.Equal("System.String!", model.GetTypeInfo(assignmentsInLambda[2].Right).Type.ToTestDisplayString(includeNonNullable: true));
        }
 
        [Fact]
        public void FreshSemanticModelDoesNotCacheSwitchExpressionInput()
        {
            var comp = CreateCompilation(@"string s = """" switch { _ => string.Empty };", options: WithNullableEnable(TestOptions.ReleaseExe));
 
            SyntaxTree tree = comp.SyntaxTrees[0];
            var switchExpressionInput = tree.GetRoot().DescendantNodes().OfType<SwitchExpressionSyntax>().Single().GoverningExpression;
 
            var model = comp.GetSemanticModel(tree);
            AssertEx.Equal("System.String!", model.GetTypeInfo(switchExpressionInput).Type.ToTestDisplayString(includeNonNullable: true));
 
            // New model should be able to get info, including nullability, without issue
            model = comp.GetSemanticModel(tree);
            AssertEx.Equal("System.String!", model.GetTypeInfo(switchExpressionInput).Type.ToTestDisplayString(includeNonNullable: true));
        }
 
        [Fact]
        public void CondAccessLeft_NonConstantRight_FlowState_01()
        {
            var source = @"
#nullable enable
 
class C
{
    public object? M(object? obj) => false;
 
    public static void M1(C? c, object? x)
    {
        if (c?.M(x = ""a"") == x)
        {
            x.ToString(); // 1
        }
    }
}
";
            var comp = CreateCompilation(source);
            comp.VerifyDiagnostics(
                // (12,13): warning CS8602: Dereference of a possibly null reference.
                //             x.ToString(); // 1
                Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "x").WithLocation(12, 13));
 
            var tree = comp.SyntaxTrees.Single();
            var model = comp.GetSemanticModel(tree);
            var binaryRight = tree.GetRoot().DescendantNodes().OfType<BinaryExpressionSyntax>().Single().Right;
            Assert.Equal("System.Object?", model.GetTypeInfo(binaryRight).Type.ToTestDisplayString(includeNonNullable: true));
        }
 
        [Fact]
        public void CondAccessLeft_NonConstantRight_FlowState_02()
        {
            var source = @"
#nullable enable
 
class C
{
    public object? M(object? obj) => false;
 
    public static void M1(C? c)
    {
        object? x = ""a"";
        if (c?.M(x = null) == x)
        {
            x.ToString(); // 1
        }
    }
}
";
            var comp = CreateCompilation(source);
            comp.VerifyDiagnostics(
                // (13,13): warning CS8602: Dereference of a possibly null reference.
                //             x.ToString(); // 1
                Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "x").WithLocation(13, 13));
 
            var tree = comp.SyntaxTrees.Single();
            var model = comp.GetSemanticModel(tree);
            var binaryRight = tree.GetRoot().DescendantNodes().OfType<BinaryExpressionSyntax>().Single().Right;
            Assert.Equal("System.Object?", model.GetTypeInfo(binaryRight).Type.ToTestDisplayString(includeNonNullable: true));
        }
 
        [Fact]
        public void CondAccessLeft_NonConstantRight_FlowState_03()
        {
            var source = @"
#nullable enable
 
class C
{
    public bool M(object? obj) => false;
 
    public static void M1(C? c, object? x)
    {
        if (c?.M(x = ""a"") == c!.M(x))
        {
            x.ToString();
        }
    }
}
";
            var comp = CreateCompilation(source);
            comp.VerifyDiagnostics();
 
            var tree = comp.SyntaxTrees.Single();
            var model = comp.GetSemanticModel(tree);
            var binaryRightArgument = tree.GetRoot().DescendantNodes().OfType<BinaryExpressionSyntax>().Single().Right.DescendantNodes().OfType<ArgumentSyntax>().Single().Expression;
            Assert.Equal("System.Object?", model.GetTypeInfo(binaryRightArgument).Type.ToTestDisplayString(includeNonNullable: true));
        }
 
        [Theory]
        [CombinatorialData]
        public void NullableDisableSemanticModel_01(bool runNullableAnalysisAlways)
        {
            var source = """
                #nullable enable
                class C
                {
                    void M(string x)
                    {
                        if (x == null)
                        {
                            x.ToString();
                        }
                    }
                }
                """;
 
            var comp = CreateCompilation(source, parseOptions: runNullableAnalysisAlways ? TestOptions.RegularPreview.WithFeature("run-nullable-analysis", "always") : TestOptions.RegularPreview);
            comp.VerifyDiagnostics(
                // (8,13): warning CS8602: Dereference of a possibly null reference.
                //             x.ToString();
                Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "x").WithLocation(8, 13));
 
            test(SemanticModelOptions.None, expectedAnnotation: PublicNullableAnnotation.Annotated);
            test(SemanticModelOptions.DisableNullableAnalysis, expectedAnnotation: PublicNullableAnnotation.None);
 
            void test(SemanticModelOptions options, PublicNullableAnnotation expectedAnnotation)
            {
                var tree = comp.SyntaxTrees.Single();
                var model = comp.GetSemanticModel(tree, options);
                var xUsage = tree.GetRoot().DescendantNodes().OfType<MemberAccessExpressionSyntax>().Single().Expression;
                var typeInfo = model.GetTypeInfo(xUsage);
                Assert.NotNull(typeInfo.Type);
                Assert.Equal(SpecialType.System_String, typeInfo.Type.SpecialType);
                Assert.Equal(expectedAnnotation, typeInfo.Type.NullableAnnotation);
            }
        }
 
        [Fact]
        public void NullableDisableSemanticModel_02()
        {
            var source = """
                #nullable enable
                class C
                {
                    void M(string x)
                    {
                        if (x == null)
                        {
                            x.ToString();
                        }
                    }
                }
                """;
 
            var comp = CreateCompilation(source, parseOptions: TestOptions.RegularPreview.WithFeature("run-nullable-analysis", "never"));
            comp.VerifyDiagnostics();
 
            test(SemanticModelOptions.None);
            test(SemanticModelOptions.DisableNullableAnalysis);
 
            void test(SemanticModelOptions options)
            {
                var tree = comp.SyntaxTrees.Single();
                var model = comp.GetSemanticModel(tree, options);
                var xUsage = tree.GetRoot().DescendantNodes().OfType<MemberAccessExpressionSyntax>().Single().Expression;
                var typeInfo = model.GetTypeInfo(xUsage);
                Assert.NotNull(typeInfo.Type);
                Assert.Equal(SpecialType.System_String, typeInfo.Type.SpecialType);
                Assert.Equal(PublicNullableAnnotation.None, typeInfo.Type.NullableAnnotation);
            }
        }
 
        [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/71522")]
        public void CollectionExpression_NestedNullability_01()
        {
            var source = """
                #nullable enable
 
                var b = false;
                var arr = b ? ["1"] : new[] { "2" };
                """;
 
            var comp = CreateCompilation(source);
            var tree = comp.SyntaxTrees[0];
            var model = comp.GetSemanticModel(tree);
 
            var root = tree.GetRoot();
            var collectionExpr = root.DescendantNodes().OfType<CollectionExpressionSyntax>().Single();
            var typeInfo = model.GetTypeInfo(collectionExpr);
            var type = (IArrayTypeSymbol)typeInfo.ConvertedType;
            Assert.Equal("System.String[]", type.ToTestDisplayString());
            Assert.Equal(PublicNullableAnnotation.NotAnnotated, type.NullableAnnotation);
            Assert.Equal(PublicNullableAnnotation.NotAnnotated, type.ElementNullableAnnotation);
        }
 
        [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/71522")]
        public void CollectionExpression_NestedNullability_01_RhsTargetTyped()
        {
            var source = """
                #nullable enable
 
                var b = false;
                var arr = b ? new[] { "1" } : ["2"];
                """;
 
            var comp = CreateCompilation(source);
            var tree = comp.SyntaxTrees[0];
            var model = comp.GetSemanticModel(tree);
 
            var root = tree.GetRoot();
            var collectionExpr = root.DescendantNodes().OfType<CollectionExpressionSyntax>().Single();
            var typeInfo = model.GetTypeInfo(collectionExpr);
            var type = (IArrayTypeSymbol)typeInfo.ConvertedType;
            Assert.Equal("System.String[]", type.ToTestDisplayString());
            Assert.Equal(PublicNullableAnnotation.NotAnnotated, type.NullableAnnotation);
            Assert.Equal(PublicNullableAnnotation.NotAnnotated, type.ElementNullableAnnotation);
        }
 
        [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/71522")]
        public void CollectionExpression_NestedNullability_02()
        {
            var source = """
                #nullable enable
 
                using System;
                using System.Collections.Generic;
                using System.Linq.Expressions;
 
                class C
                {
                    void M()
                    {
                        string[] x = ["1"];
                    }
                }
                """;
 
            var comp = CreateCompilation(source);
            var tree = comp.SyntaxTrees[0];
            var model = comp.GetSemanticModel(tree);
 
            var root = tree.GetRoot();
            var collectionExpr = root.DescendantNodes().OfType<CollectionExpressionSyntax>().Single();
            var typeInfo = model.GetTypeInfo(collectionExpr);
            var type = (IArrayTypeSymbol)typeInfo.ConvertedType;
            Assert.Equal("System.String[]", type.ToTestDisplayString());
            Assert.Equal(PublicNullableAnnotation.NotAnnotated, type.NullableAnnotation);
            Assert.Equal(PublicNullableAnnotation.NotAnnotated, type.ElementNullableAnnotation);
        }
 
        [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/71522")]
        public void CollectionExpression_NestedNullability_03()
        {
            var source = """
                #nullable enable
 
                var b = false;
                var arr = b switch { true => ["1"], false => new[] { "2" } };
                """;
 
            var comp = CreateCompilation(source);
            var tree = comp.SyntaxTrees[0];
            var model = comp.GetSemanticModel(tree);
 
            var root = tree.GetRoot();
            var collectionExpr = root.DescendantNodes().OfType<CollectionExpressionSyntax>().Single();
            var typeInfo = model.GetTypeInfo(collectionExpr);
            var type = (IArrayTypeSymbol)typeInfo.ConvertedType;
            Assert.Equal("System.String[]", type.ToTestDisplayString());
            Assert.Equal(PublicNullableAnnotation.NotAnnotated, type.NullableAnnotation);
            Assert.Equal(PublicNullableAnnotation.NotAnnotated, type.ElementNullableAnnotation);
        }
 
        [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/71522")]
        public void CollectionExpression_NestedNullability_04()
        {
            var source = """
                #nullable enable
 
                var arr = new[] { ["1"], new[] { "2" } };
                """;
 
            var comp = CreateCompilation(source);
            var tree = comp.SyntaxTrees[0];
            var model = comp.GetSemanticModel(tree);
 
            var root = tree.GetRoot();
            var collectionExpr = root.DescendantNodes().OfType<CollectionExpressionSyntax>().Single();
            var typeInfo = model.GetTypeInfo(collectionExpr);
            var type = (IArrayTypeSymbol)typeInfo.ConvertedType;
            Assert.Equal("System.String[]", type.ToTestDisplayString());
            Assert.Equal(PublicNullableAnnotation.NotAnnotated, type.NullableAnnotation);
            Assert.Equal(PublicNullableAnnotation.NotAnnotated, type.ElementNullableAnnotation);
        }
 
        [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/71522")]
        public void CollectionExpression_NestedNullability_05()
        {
            var source = """
                #nullable enable
                public class C
                {
                    public string[] M1(bool b)
                    {
                        var arr = b ? ["1"] : new[] { "2" };
                        arr[0] = null; // 1
                        return arr;
                    }
 
                    public string[] M2(bool b)
                    {
                        var arr = new[] { "2" };
                        arr = b ? ["1"] : arr;
                        arr[0] = null; // 2
                        return arr;
                    }
                }
                """;
 
            var comp = CreateCompilation(source);
            comp.VerifyEmitDiagnostics(
                // (7,18): warning CS8625: Cannot convert null literal to non-nullable reference type.
                //         arr[0] = null; // 1
                Diagnostic(ErrorCode.WRN_NullAsNonNullable, "null").WithLocation(7, 18),
                // (15,18): warning CS8625: Cannot convert null literal to non-nullable reference type.
                //         arr[0] = null; // 2
                Diagnostic(ErrorCode.WRN_NullAsNonNullable, "null").WithLocation(15, 18));
 
            var tree = comp.SyntaxTrees[0];
            var model = comp.GetSemanticModel(tree);
 
            var root = tree.GetRoot();
            var collectionExprs = root.DescendantNodes().OfType<CollectionExpressionSyntax>().ToArray();
            Assert.Equal(2, collectionExprs.Length);
            foreach (var collectionExpr in collectionExprs)
            {
                var typeInfo = model.GetTypeInfo(collectionExpr);
                var type = (IArrayTypeSymbol)typeInfo.ConvertedType;
                Assert.Equal("System.String[]", type.ToTestDisplayString());
                Assert.Equal(PublicNullableAnnotation.NotAnnotated, type.NullableAnnotation);
                Assert.Equal(PublicNullableAnnotation.NotAnnotated, type.ElementNullableAnnotation);
            }
        }
 
        [Fact]
        [WorkItem("https://github.com/dotnet/roslyn/issues/71522")]
        [WorkItem("https://github.com/dotnet/roslyn/issues/74609")]
        public void CollectionExpression_NestedNullability_06()
        {
            var source = """
                #nullable enable
 
                public class C
                {
                    public string[] M1(bool b)
                    {
                        var lam = () =>
                        {
                            if (b)
                                return ["1"];
 
                            return new[] { "2" };
                        };
 
                        var arr = lam();
                        arr[0] = null; // 1
                        return arr;
                    }
 
                    public string[] M2(bool b)
                    {
                        var lam = () => new[] { "2" };
                        var arr = lam();
                        arr = b ? ["1"] : arr;
                        arr[0] = null; // 2
                        return arr;
                    }
                }
                """;
 
            var comp = CreateCompilation(source);
            // The expected nullable warnings are not reported here.
            // https://github.com/dotnet/roslyn/issues/74609
            comp.VerifyEmitDiagnostics();
 
            var tree = comp.SyntaxTrees[0];
            var model = comp.GetSemanticModel(tree);
 
            var root = tree.GetRoot();
            var collectionExprs = root.DescendantNodes().OfType<CollectionExpressionSyntax>().ToArray();
            Assert.Equal(2, collectionExprs.Length);
            foreach (var collectionExpr in collectionExprs)
            {
                var typeInfo = model.GetTypeInfo(collectionExpr);
                var type = (IArrayTypeSymbol)typeInfo.ConvertedType;
                Assert.Equal("System.String[]", type.ToTestDisplayString());
                Assert.Equal(PublicNullableAnnotation.NotAnnotated, type.NullableAnnotation);
 
                // The arrays have unexpected oblivious element nullability.
                // https://github.com/dotnet/roslyn/issues/74609
                Assert.Equal(PublicNullableAnnotation.None, type.ElementNullableAnnotation);
            }
        }
 
        [Fact]
        [WorkItem("https://github.com/dotnet/roslyn/issues/71522")]
        [WorkItem("https://github.com/dotnet/roslyn/issues/74693")]
        public void TargetTypedExpressions_NestedNullability()
        {
            // Warning (2) is missing because default literals are contributing
            // their initial bound type to best-type in nullable analysis.
            // https://github.com/dotnet/roslyn/issues/74693
            var source = """
                #nullable enable
                using System.Collections.Generic;
 
                public class C
                {
                    public void M(bool b)
                    {
                        var x = b ? null! : new[] {"1"};
                        x[0] = null; // 1
                    }
 
                    public void M2(bool b)
                    {
                        var x = b ? default! : new[] {"1"};
                        x[0] = null; // 2 (missing)
                    }
 
                    public void M3(bool b)
                    {
                        var x = b ? (b ? null! : null!) : new[] {"1"};
                        x[0] = null; // 3
                    }
 
                    public void M4(bool b)
                    {
                        var x = b ? (b switch { _ => null! }) : new[] {"1"};
                        x[0] = null; // 4
                    }
 
                    List<T> MakeList<T>(T value) => new List<T> { value };
 
                    public void M5(bool b)
                    {
                        var x = b ? new() : MakeList("1");
                        x[0] = null; // 5
                    }
 
                    public void M6(bool b)
                    {
                        var x = b ? default! : MakeList("1");
                        x[0] = null; // 6
                    }
                }
                """;
 
            var comp = CreateCompilation(source);
            comp.VerifyEmitDiagnostics(
                // (9,16): warning CS8625: Cannot convert null literal to non-nullable reference type.
                //         x[0] = null; // 1
                Diagnostic(ErrorCode.WRN_NullAsNonNullable, "null").WithLocation(9, 16),
                // (21,16): warning CS8625: Cannot convert null literal to non-nullable reference type.
                //         x[0] = null; // 3
                Diagnostic(ErrorCode.WRN_NullAsNonNullable, "null").WithLocation(21, 16),
                // (27,16): warning CS8625: Cannot convert null literal to non-nullable reference type.
                //         x[0] = null; // 4
                Diagnostic(ErrorCode.WRN_NullAsNonNullable, "null").WithLocation(27, 16),
                // (35,16): warning CS8625: Cannot convert null literal to non-nullable reference type.
                //         x[0] = null; // 5
                Diagnostic(ErrorCode.WRN_NullAsNonNullable, "null").WithLocation(35, 16),
                // (41,16): warning CS8625: Cannot convert null literal to non-nullable reference type.
                //         x[0] = null; // 6
                Diagnostic(ErrorCode.WRN_NullAsNonNullable, "null").WithLocation(41, 16));
        }
    }
}