File: Semantics\RecordStructTests.cs
Web Access
Project: src\src\Compilers\CSharp\Test\Semantic\Microsoft.CodeAnalysis.CSharp.Semantic.UnitTests.csproj (Microsoft.CodeAnalysis.CSharp.Semantic.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.
 
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using System.Threading;
using Microsoft.CodeAnalysis.CSharp.Symbols;
using Microsoft.CodeAnalysis.CSharp.Symbols.Metadata.PE;
using Microsoft.CodeAnalysis.CSharp.Symbols.Retargeting;
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;
 
namespace Microsoft.CodeAnalysis.CSharp.UnitTests.Semantics
{
    [CompilerTrait(CompilerFeature.RecordStructs)]
    public class RecordStructTests : CompilingTestBase
    {
        private static CSharpCompilation CreateCompilation(CSharpTestSource source)
            => CSharpTestBase.CreateCompilation(new[] { source, IsExternalInitTypeDefinition },
                parseOptions: TestOptions.RegularPreview);
 
        private CompilationVerifier CompileAndVerify(
            CSharpTestSource src,
            string? expectedOutput = null,
            IEnumerable<MetadataReference>? references = null)
            => base.CompileAndVerify(
                new[] { src, IsExternalInitTypeDefinition },
                expectedOutput: expectedOutput,
                parseOptions: TestOptions.RegularPreview,
                references: references,
                // init-only is unverifiable
                verify: Verification.Skipped);
 
        [Fact]
        public void StructRecord1()
        {
            var src = @"
record struct Point(int X, int Y);";
 
            var verifier = CompileAndVerify(src).VerifyDiagnostics();
            verifier.VerifyIL("Point.Equals(object)", @"
{
  // Code size       23 (0x17)
  .maxstack  2
  IL_0000:  ldarg.1
  IL_0001:  isinst     ""Point""
  IL_0006:  brfalse.s  IL_0015
  IL_0008:  ldarg.0
  IL_0009:  ldarg.1
  IL_000a:  unbox.any  ""Point""
  IL_000f:  call       ""readonly bool Point.Equals(Point)""
  IL_0014:  ret
  IL_0015:  ldc.i4.0
  IL_0016:  ret
}");
            verifier.VerifyIL("Point.Equals(Point)", @"
{
  // Code size       49 (0x31)
  .maxstack  3
  IL_0000:  call       ""System.Collections.Generic.EqualityComparer<int> System.Collections.Generic.EqualityComparer<int>.Default.get""
  IL_0005:  ldarg.0
  IL_0006:  ldfld      ""int Point.<X>k__BackingField""
  IL_000b:  ldarg.1
  IL_000c:  ldfld      ""int Point.<X>k__BackingField""
  IL_0011:  callvirt   ""bool System.Collections.Generic.EqualityComparer<int>.Equals(int, int)""
  IL_0016:  brfalse.s  IL_002f
  IL_0018:  call       ""System.Collections.Generic.EqualityComparer<int> System.Collections.Generic.EqualityComparer<int>.Default.get""
  IL_001d:  ldarg.0
  IL_001e:  ldfld      ""int Point.<Y>k__BackingField""
  IL_0023:  ldarg.1
  IL_0024:  ldfld      ""int Point.<Y>k__BackingField""
  IL_0029:  callvirt   ""bool System.Collections.Generic.EqualityComparer<int>.Equals(int, int)""
  IL_002e:  ret
  IL_002f:  ldc.i4.0
  IL_0030:  ret
}");
        }
 
        [Fact]
        public void StructRecord2()
        {
            var src = @"
using System;
record struct S(int X, int Y)
{
    public static void Main()
    {
        var s1 = new S(0, 1);
        var s2 = new S(0, 1);
        Console.WriteLine(s1.X);
        Console.WriteLine(s1.Y);
        Console.WriteLine(s1.Equals(s2));
        Console.WriteLine(s1.Equals(new S(1, 0)));
    }
}";
            var verifier = CompileAndVerify(src, expectedOutput: @"0
1
True
False").VerifyDiagnostics();
        }
 
        [Fact]
        public void StructRecord3()
        {
            var src = @"
using System;
record struct S(int X, int Y)
{
    public bool Equals(S s) => false;
    public static void Main()
    {
        var s1 = new S(0, 1);
        Console.WriteLine(s1.Equals(s1));
    }
}";
            var verifier = CompileAndVerify(src, expectedOutput: @"False")
                .VerifyDiagnostics(
                    // (5,17): warning CS8851: 'S' defines 'Equals' but not 'GetHashCode'
                    //     public bool Equals(S s) => false;
                    Diagnostic(ErrorCode.WRN_RecordEqualsWithoutGetHashCode, "Equals").WithArguments("S").WithLocation(5, 17));
 
            verifier.VerifyIL("S.Main", @"
{
  // Code size       23 (0x17)
  .maxstack  3
  .locals init (S V_0) //s1
  IL_0000:  ldloca.s   V_0
  IL_0002:  ldc.i4.0
  IL_0003:  ldc.i4.1
  IL_0004:  call       ""S..ctor(int, int)""
  IL_0009:  ldloca.s   V_0
  IL_000b:  ldloc.0
  IL_000c:  call       ""bool S.Equals(S)""
  IL_0011:  call       ""void System.Console.WriteLine(bool)""
  IL_0016:  ret
}");
        }
 
        [Fact]
        public void StructRecord5()
        {
            var src = @"
using System;
record struct S(int X, int Y)
{
    public bool Equals(S s)
    {
        Console.Write(""s"");
        return true;
    }
    public static void Main()
    {
        var s1 = new S(0, 1);
        s1.Equals((object)s1);
        s1.Equals(s1);
    }
}";
            CompileAndVerify(src, expectedOutput: @"ss")
                .VerifyDiagnostics(
                    // (5,17): warning CS8851: 'S' defines 'Equals' but not 'GetHashCode'
                    //     public bool Equals(S s)
                    Diagnostic(ErrorCode.WRN_RecordEqualsWithoutGetHashCode, "Equals").WithArguments("S").WithLocation(5, 17));
        }
 
        [Fact]
        public void StructRecordDefaultCtor()
        {
            const string src = @"
public record struct S(int X);";
 
            const string src2 = @"
class C
{
    public S M() => new S();
}";
            var comp = CreateCompilation(src + src2);
            comp.VerifyDiagnostics();
 
            comp = CreateCompilation(src);
            var comp2 = CreateCompilation(src2, references: new[] { comp.EmitToImageReference() });
            comp2.VerifyDiagnostics();
        }
 
        [Fact]
        public void Equality_01()
        {
            var source =
@"using static System.Console;
record struct S;
 
class Program
{
    static void Main()
    {
        var x = new S();
        var y = new S();
        WriteLine(x.Equals(y));
        WriteLine(((object)x).Equals(y));
    }
}";
            var comp = CreateCompilation(source, parseOptions: TestOptions.RegularPreview, options: TestOptions.ReleaseExe);
 
            var verifier = CompileAndVerify(comp, expectedOutput: @"True
True").VerifyDiagnostics();
 
            verifier.VerifyIL("S.Equals(S)", @"
{
  // Code size        2 (0x2)
  .maxstack  1
  IL_0000:  ldc.i4.1
  IL_0001:  ret
}");
            verifier.VerifyIL("S.Equals(object)", @"
{
  // Code size       23 (0x17)
  .maxstack  2
  IL_0000:  ldarg.1
  IL_0001:  isinst     ""S""
  IL_0006:  brfalse.s  IL_0015
  IL_0008:  ldarg.0
  IL_0009:  ldarg.1
  IL_000a:  unbox.any  ""S""
  IL_000f:  call       ""readonly bool S.Equals(S)""
  IL_0014:  ret
  IL_0015:  ldc.i4.0
  IL_0016:  ret
}");
        }
 
        [Fact]
        public void RecordStructLanguageVersion()
        {
            var src1 = @"
struct Point(int x, int y);
";
            var src2 = @"
record struct Point { }
";
            var src3 = @"
record struct Point(int x, int y);
";
 
            var comp = CreateCompilation(new[] { src1, IsExternalInitTypeDefinition }, parseOptions: TestOptions.Regular9, options: TestOptions.ReleaseDll);
            comp.VerifyDiagnostics(
                // 0.cs(2,13): error CS8773: Feature 'primary constructors' is not available in C# 9.0. Please use language version 12.0 or greater.
                // struct Point(int x, int y);
                Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion9, "(int x, int y)").WithArguments("primary constructors", "12.0").WithLocation(2, 13),
                // 0.cs(2,18): warning CS9113: Parameter 'x' is unread.
                // struct Point(int x, int y);
                Diagnostic(ErrorCode.WRN_UnreadPrimaryConstructorParameter, "x").WithArguments("x").WithLocation(2, 18),
                // 0.cs(2,25): warning CS9113: Parameter 'y' is unread.
                // struct Point(int x, int y);
                Diagnostic(ErrorCode.WRN_UnreadPrimaryConstructorParameter, "y").WithArguments("y").WithLocation(2, 25)
                );
 
            comp = CreateCompilation(new[] { src2, IsExternalInitTypeDefinition }, parseOptions: TestOptions.Regular9, options: TestOptions.ReleaseDll);
            comp.VerifyDiagnostics(
                // (2,8): error CS8773: Feature 'record structs' is not available in C# 9.0. Please use language version 10.0 or greater.
                // record struct Point { }
                Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion9, "struct").WithArguments("record structs", "10.0").WithLocation(2, 8));
 
            comp = CreateCompilation(new[] { src3, IsExternalInitTypeDefinition }, parseOptions: TestOptions.Regular9, options: TestOptions.ReleaseDll);
            comp.VerifyDiagnostics(
                // (2,8): error CS8773: Feature 'record structs' is not available in C# 9.0. Please use language version 10.0 or greater.
                // record struct Point(int x, int y);
                Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion9, "struct").WithArguments("record structs", "10.0").WithLocation(2, 8));
 
            comp = CreateCompilation(new[] { src1, IsExternalInitTypeDefinition }, parseOptions: TestOptions.Regular10, options: TestOptions.ReleaseDll);
            comp.VerifyDiagnostics(
                // 0.cs(2,13): error CS8936: Feature 'primary constructors' is not available in C# 10.0. Please use language version 12.0 or greater.
                // struct Point(int x, int y);
                Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "(int x, int y)").WithArguments("primary constructors", "12.0").WithLocation(2, 13),
                // 0.cs(2,18): warning CS9113: Parameter 'x' is unread.
                // struct Point(int x, int y);
                Diagnostic(ErrorCode.WRN_UnreadPrimaryConstructorParameter, "x").WithArguments("x").WithLocation(2, 18),
                // 0.cs(2,25): warning CS9113: Parameter 'y' is unread.
                // struct Point(int x, int y);
                Diagnostic(ErrorCode.WRN_UnreadPrimaryConstructorParameter, "y").WithArguments("y").WithLocation(2, 25)
                );
 
            comp = CreateCompilation(new[] { src2, IsExternalInitTypeDefinition }, parseOptions: TestOptions.Regular10, options: TestOptions.ReleaseDll);
            comp.VerifyDiagnostics();
 
            comp = CreateCompilation(new[] { src3, IsExternalInitTypeDefinition }, parseOptions: TestOptions.Regular10, options: TestOptions.ReleaseDll);
            comp.VerifyDiagnostics();
        }
 
        [Fact]
        public void RecordStructLanguageVersion_Nested()
        {
            var src1 = @"
class C
{
    struct Point(int x, int y);
}
";
            var src2 = @"
class D
{
    record struct Point { }
}
";
            var src3 = @"
struct E
{
    record struct Point(int x, int y);
}
";
            var src4 = @"
namespace NS
{
    record struct Point { }
}
";
            var comp = CreateCompilation(src1, parseOptions: TestOptions.Regular9);
            comp.VerifyDiagnostics(
                // (4,17): error CS8773: Feature 'primary constructors' is not available in C# 9.0. Please use language version 12.0 or greater.
                //     struct Point(int x, int y);
                Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion9, "(int x, int y)").WithArguments("primary constructors", "12.0").WithLocation(4, 17),
                // (4,22): warning CS9113: Parameter 'x' is unread.
                //     struct Point(int x, int y);
                Diagnostic(ErrorCode.WRN_UnreadPrimaryConstructorParameter, "x").WithArguments("x").WithLocation(4, 22),
                // (4,29): warning CS9113: Parameter 'y' is unread.
                //     struct Point(int x, int y);
                Diagnostic(ErrorCode.WRN_UnreadPrimaryConstructorParameter, "y").WithArguments("y").WithLocation(4, 29)
                );
 
            comp = CreateCompilation(new[] { src2, IsExternalInitTypeDefinition }, parseOptions: TestOptions.Regular9);
            comp.VerifyDiagnostics(
                // (4,12): error CS8773: Feature 'record structs' is not available in C# 9.0. Please use language version 10.0 or greater.
                //     record struct Point { }
                Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion9, "struct").WithArguments("record structs", "10.0").WithLocation(4, 12));
 
            comp = CreateCompilation(new[] { src3, IsExternalInitTypeDefinition }, parseOptions: TestOptions.Regular9);
            comp.VerifyDiagnostics(
                // (4,12): error CS8773: Feature 'record structs' is not available in C# 9.0. Please use language version 10.0 or greater.
                //     record struct Point { }
                Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion9, "struct").WithArguments("record structs", "10.0").WithLocation(4, 12));
 
            comp = CreateCompilation(src4, parseOptions: TestOptions.Regular9);
            comp.VerifyDiagnostics(
                // (4,12): error CS8773: Feature 'record structs' is not available in C# 9.0. Please use language version 10.0 or greater.
                //     record struct Point { }
                Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion9, "struct").WithArguments("record structs", "10.0").WithLocation(4, 12));
 
            comp = CreateCompilation(src1);
            comp.VerifyDiagnostics(
                // (4,22): warning CS9113: Parameter 'x' is unread.
                //     struct Point(int x, int y);
                Diagnostic(ErrorCode.WRN_UnreadPrimaryConstructorParameter, "x").WithArguments("x").WithLocation(4, 22),
                // (4,29): warning CS9113: Parameter 'y' is unread.
                //     struct Point(int x, int y);
                Diagnostic(ErrorCode.WRN_UnreadPrimaryConstructorParameter, "y").WithArguments("y").WithLocation(4, 29)
                );
 
            comp = CreateCompilation(src2);
            comp.VerifyDiagnostics();
 
            comp = CreateCompilation(src3);
            comp.VerifyDiagnostics();
 
            comp = CreateCompilation(src4);
            comp.VerifyDiagnostics();
        }
 
        [Fact]
        public void TypeDeclaration_IsStruct()
        {
            var src = @"
record struct Point(int x, int y);
";
            var comp = CreateCompilation(src);
            comp.VerifyDiagnostics();
 
            CompileAndVerify(comp, symbolValidator: validateModule, sourceSymbolValidator: validateModule);
            Assert.True(SyntaxFacts.IsTypeDeclaration(SyntaxKind.RecordStructDeclaration));
 
            static void validateModule(ModuleSymbol module)
            {
                var isSourceSymbol = module is SourceModuleSymbol;
 
                var point = module.GlobalNamespace.GetTypeMember("Point");
                Assert.True(point.IsValueType);
                Assert.False(point.IsReferenceType);
                Assert.False(point.IsRecord);
                Assert.Equal(TypeKind.Struct, point.TypeKind);
                Assert.Equal(SpecialType.System_ValueType, point.BaseTypeNoUseSiteDiagnostics.SpecialType);
                Assert.Equal("Point", point.ToTestDisplayString());
 
                if (isSourceSymbol)
                {
                    Assert.True(point is SourceNamedTypeSymbol);
                    Assert.True(point.IsRecordStruct);
                    Assert.True(point.GetPublicSymbol().IsRecord);
                    Assert.Equal("record struct Point", point.ToDisplayString(SymbolDisplayFormat.TestFormat.AddKindOptions(SymbolDisplayKindOptions.IncludeTypeKeyword)));
                }
                else
                {
                    Assert.True(point is PENamedTypeSymbol);
                    Assert.False(point.IsRecordStruct);
                    Assert.False(point.GetPublicSymbol().IsRecord);
                    Assert.Equal("struct Point", point.ToDisplayString(SymbolDisplayFormat.TestFormat.AddKindOptions(SymbolDisplayKindOptions.IncludeTypeKeyword)));
                }
            }
        }
 
        [Fact]
        public void TypeDeclaration_IsStruct_InConstraints()
        {
            var src = @"
record struct Point(int x, int y);
 
class C<T> where T : struct
{
    void M(C<Point> c) { }
}
 
class C2<T> where T : new()
{
    void M(C2<Point> c) { }
}
 
class C3<T> where T : class
{
    void M(C3<Point> c) { } // 1
}
";
            var comp = CreateCompilation(src);
            comp.VerifyDiagnostics(
                // (16,22): error CS0452: The type 'Point' must be a reference type in order to use it as parameter 'T' in the generic type or method 'C3<T>'
                //     void M(C3<Point> c) { } // 1
                Diagnostic(ErrorCode.ERR_RefConstraintNotSatisfied, "c").WithArguments("C3<T>", "T", "Point").WithLocation(16, 22)
                );
        }
 
        [Fact]
        public void TypeDeclaration_IsStruct_Unmanaged()
        {
            var src = @"
record struct Point(int x, int y);
record struct Point2(string x, string y);
 
class C<T> where T : unmanaged
{
    void M(C<Point> c) { }
    void M2(C<Point2> c) { } // 1
}
";
            var comp = CreateCompilation(src);
            comp.VerifyDiagnostics(
                // (8,23): error CS8377: The type 'Point2' must be a non-nullable value type, along with all fields at any level of nesting, in order to use it as parameter 'T' in the generic type or method 'C<T>'
                //     void M2(C<Point2> c) { } // 1
                Diagnostic(ErrorCode.ERR_UnmanagedConstraintNotSatisfied, "c").WithArguments("C<T>", "T", "Point2").WithLocation(8, 23)
                );
        }
 
        [Fact]
        public void IsRecord_Generic()
        {
            var src = @"
record struct Point<T>(T x, T y);
";
            var comp = CreateCompilation(src);
            comp.VerifyDiagnostics();
 
            CompileAndVerify(comp, symbolValidator: validateModule, sourceSymbolValidator: validateModule);
 
            static void validateModule(ModuleSymbol module)
            {
                var isSourceSymbol = module is SourceModuleSymbol;
 
                var point = module.GlobalNamespace.GetTypeMember("Point");
                Assert.True(point.IsValueType);
                Assert.False(point.IsReferenceType);
                Assert.False(point.IsRecord);
                Assert.Equal(TypeKind.Struct, point.TypeKind);
                Assert.Equal(SpecialType.System_ValueType, point.BaseTypeNoUseSiteDiagnostics.SpecialType);
                Assert.True(SyntaxFacts.IsTypeDeclaration(SyntaxKind.RecordStructDeclaration));
 
                if (isSourceSymbol)
                {
                    Assert.True(point is SourceNamedTypeSymbol);
                    Assert.True(point.IsRecordStruct);
                    Assert.True(point.GetPublicSymbol().IsRecord);
                }
                else
                {
                    Assert.True(point is PENamedTypeSymbol);
                    Assert.False(point.IsRecordStruct);
                    Assert.False(point.GetPublicSymbol().IsRecord);
                }
            }
        }
 
        [Fact]
        public void IsRecord_Retargeting()
        {
            var src = @"
public record struct Point(int x, int y);
";
            var comp = CreateCompilation(src, targetFramework: TargetFramework.Mscorlib40);
            var comp2 = CreateCompilation("", targetFramework: TargetFramework.Mscorlib46, references: new[] { comp.ToMetadataReference() });
            var point = comp2.GlobalNamespace.GetTypeMember("Point");
 
            Assert.Equal("Point", point.ToTestDisplayString());
            Assert.IsType<RetargetingNamedTypeSymbol>(point);
            Assert.True(point.IsRecordStruct);
            Assert.True(point.GetPublicSymbol().IsRecord);
        }
 
        [Fact]
        public void IsRecord_AnonymousType()
        {
            var src = @"
class C
{
    void M()
    {
        var x = new { X = 1 };
    }
}
";
            var comp = CreateCompilation(src);
            var tree = comp.SyntaxTrees.First();
            var model = comp.GetSemanticModel(tree, ignoreAccessibility: false);
            var creation = tree.GetRoot().DescendantNodes().OfType<AnonymousObjectCreationExpressionSyntax>().Single();
            var type = model.GetTypeInfo(creation).Type!;
 
            Assert.Equal("<anonymous type: System.Int32 X>", type.ToTestDisplayString());
            Assert.IsType<AnonymousTypeManager.AnonymousTypePublicSymbol>(((Symbols.PublicModel.NonErrorNamedTypeSymbol)type).UnderlyingNamedTypeSymbol);
            Assert.False(type.IsRecord);
        }
 
        [Fact]
        public void IsRecord_ErrorType()
        {
            var src = @"
class C
{
    Error M() => throw null;
}
";
            var comp = CreateCompilation(src);
            var tree = comp.SyntaxTrees.First();
            var model = comp.GetSemanticModel(tree, ignoreAccessibility: false);
            var method = tree.GetRoot().DescendantNodes().OfType<MethodDeclarationSyntax>().Single();
            var type = model.GetDeclaredSymbol(method)!.ReturnType;
 
            Assert.Equal("Error", type.ToTestDisplayString());
            Assert.IsType<ExtendedErrorTypeSymbol>(((Symbols.PublicModel.ErrorTypeSymbol)type).UnderlyingNamedTypeSymbol);
            Assert.False(type.IsRecord);
        }
 
        [Fact]
        public void IsRecord_Pointer()
        {
            var src = @"
class C
{
    int* M() => throw null;
}
";
            var comp = CreateCompilation(src, options: TestOptions.UnsafeReleaseDll);
            var tree = comp.SyntaxTrees.First();
            var model = comp.GetSemanticModel(tree, ignoreAccessibility: false);
            var method = tree.GetRoot().DescendantNodes().OfType<MethodDeclarationSyntax>().Single();
            var type = model.GetDeclaredSymbol(method)!.ReturnType;
 
            Assert.Equal("System.Int32*", type.ToTestDisplayString());
            Assert.IsType<PointerTypeSymbol>(((Symbols.PublicModel.PointerTypeSymbol)type).UnderlyingTypeSymbol);
            Assert.False(type.IsRecord);
        }
 
        [Fact]
        public void IsRecord_Dynamic()
        {
            var src = @"
class C
{
    void M(dynamic d)
    {
    }
}
";
            var comp = CreateCompilation(src);
            var tree = comp.SyntaxTrees.First();
            var model = comp.GetSemanticModel(tree, ignoreAccessibility: false);
            var method = tree.GetRoot().DescendantNodes().OfType<MethodDeclarationSyntax>().Single();
            var type = model.GetDeclaredSymbol(method)!.GetParameterType(0);
 
            Assert.Equal("dynamic", type.ToTestDisplayString());
            Assert.IsType<DynamicTypeSymbol>(((Symbols.PublicModel.DynamicTypeSymbol)type).UnderlyingTypeSymbol);
            Assert.False(type.IsRecord);
        }
 
        [Fact]
        public void TypeDeclaration_MayNotHaveBaseType()
        {
            var src = @"
record struct Point(int x, int y) : object;
record struct Point2(int x, int y) : System.ValueType;
";
 
            var comp = CreateCompilation(src);
            comp.VerifyDiagnostics(
                // (2,37): error CS0527: Type 'object' in interface list is not an interface
                // record struct Point(int x, int y) : object;
                Diagnostic(ErrorCode.ERR_NonInterfaceInInterfaceList, "object").WithArguments("object").WithLocation(2, 37),
                // (3,38): error CS0527: Type 'ValueType' in interface list is not an interface
                // record struct Point2(int x, int y) : System.ValueType;
                Diagnostic(ErrorCode.ERR_NonInterfaceInInterfaceList, "System.ValueType").WithArguments("System.ValueType").WithLocation(3, 38)
                );
        }
 
        [Fact]
        public void TypeDeclaration_MayNotHaveTypeConstraintsWithoutTypeParameters()
        {
            var src = @"
record struct Point(int x, int y) where T : struct;
";
 
            var comp = CreateCompilation(src);
            comp.VerifyDiagnostics(
                // (2,35): error CS0080: Constraints are not allowed on non-generic declarations
                // record struct Point(int x, int y) where T : struct;
                Diagnostic(ErrorCode.ERR_ConstraintOnlyAllowedOnGenericDecl, "where").WithLocation(2, 35)
                );
        }
 
        [Fact]
        public void TypeDeclaration_AllowedModifiers()
        {
            var src = @"
readonly partial record struct S1;
public record struct S2;
internal record struct S3;
 
public class Base
{
    public int S6;
}
public class C : Base
{
    private protected record struct S4;
    protected internal record struct S5;
    new record struct S6;
}
unsafe record struct S7;
";
 
            var comp = CreateCompilation(src, parseOptions: TestOptions.RegularPreview, options: TestOptions.UnsafeDebugDll);
            comp.VerifyDiagnostics();
            Assert.Equal(Accessibility.Internal, comp.GlobalNamespace.GetTypeMember("S1").DeclaredAccessibility);
            Assert.Equal(Accessibility.Public, comp.GlobalNamespace.GetTypeMember("S2").DeclaredAccessibility);
            Assert.Equal(Accessibility.Internal, comp.GlobalNamespace.GetTypeMember("S3").DeclaredAccessibility);
            Assert.Equal(Accessibility.ProtectedAndInternal, comp.GlobalNamespace.GetTypeMember("C").GetTypeMember("S4").DeclaredAccessibility);
            Assert.Equal(Accessibility.ProtectedOrInternal, comp.GlobalNamespace.GetTypeMember("C").GetTypeMember("S5").DeclaredAccessibility);
        }
 
        [Fact]
        public void TypeDeclaration_DisallowedModifiers()
        {
            var src = @"
abstract record struct S1;
volatile record struct S2;
extern record struct S3;
virtual record struct S4;
override record struct S5;
async record struct S6;
ref record struct S7;
unsafe record struct S8;
static record struct S9;
sealed record struct S10;
";
 
            var comp = CreateCompilation(src);
            comp.VerifyDiagnostics(
                // (2,24): error CS0106: The modifier 'abstract' is not valid for this item
                // abstract record struct S1;
                Diagnostic(ErrorCode.ERR_BadMemberFlag, "S1").WithArguments("abstract").WithLocation(2, 24),
                // (3,24): error CS0106: The modifier 'volatile' is not valid for this item
                // volatile record struct S2;
                Diagnostic(ErrorCode.ERR_BadMemberFlag, "S2").WithArguments("volatile").WithLocation(3, 24),
                // (4,22): error CS0106: The modifier 'extern' is not valid for this item
                // extern record struct S3;
                Diagnostic(ErrorCode.ERR_BadMemberFlag, "S3").WithArguments("extern").WithLocation(4, 22),
                // (5,23): error CS0106: The modifier 'virtual' is not valid for this item
                // virtual record struct S4;
                Diagnostic(ErrorCode.ERR_BadMemberFlag, "S4").WithArguments("virtual").WithLocation(5, 23),
                // (6,24): error CS0106: The modifier 'override' is not valid for this item
                // override record struct S5;
                Diagnostic(ErrorCode.ERR_BadMemberFlag, "S5").WithArguments("override").WithLocation(6, 24),
                // (7,21): error CS0106: The modifier 'async' is not valid for this item
                // async record struct S6;
                Diagnostic(ErrorCode.ERR_BadMemberFlag, "S6").WithArguments("async").WithLocation(7, 21),
                // (8,19): error CS0106: The modifier 'ref' is not valid for this item
                // ref record struct S7;
                Diagnostic(ErrorCode.ERR_BadMemberFlag, "S7").WithArguments("ref").WithLocation(8, 19),
                // (9,22): error CS0227: Unsafe code may only appear if compiling with /unsafe
                // unsafe record struct S8;
                Diagnostic(ErrorCode.ERR_IllegalUnsafe, "S8").WithLocation(9, 22),
                // (10,22): error CS0106: The modifier 'static' is not valid for this item
                // static record struct S9;
                Diagnostic(ErrorCode.ERR_BadMemberFlag, "S9").WithArguments("static").WithLocation(10, 22),
                // (11,22): error CS0106: The modifier 'sealed' is not valid for this item
                // sealed record struct S10;
                Diagnostic(ErrorCode.ERR_BadMemberFlag, "S10").WithArguments("sealed").WithLocation(11, 22)
                );
        }
 
        [Fact]
        public void TypeDeclaration_DuplicatesModifiers()
        {
            var src = @"
public public record struct S2;
";
 
            var comp = CreateCompilation(src);
            comp.VerifyDiagnostics(
                // (2,8): error CS1004: Duplicate 'public' modifier
                // public public record struct S2;
                Diagnostic(ErrorCode.ERR_DuplicateModifier, "public").WithArguments("public").WithLocation(2, 8)
                );
        }
 
        [Fact]
        public void TypeDeclaration_BeforeTopLevelStatement()
        {
            var src = @"
record struct S;
System.Console.WriteLine();
";
 
            var comp = CreateCompilation(src);
            comp.VerifyDiagnostics(
                // (3,1): error CS8803: Top-level statements must precede namespace and type declarations.
                // System.Console.WriteLine();
                Diagnostic(ErrorCode.ERR_TopLevelStatementAfterNamespaceOrType, "System.Console.WriteLine();").WithLocation(3, 1)
                );
        }
 
        [Fact]
        public void TypeDeclaration_WithTypeParameters()
        {
            var src = @"
S<string> local = default;
local.ToString();
 
record struct S<T>;
";
 
            var comp = CreateCompilation(src);
            comp.VerifyDiagnostics();
            Assert.Equal(new[] { "T" }, comp.GlobalNamespace.GetTypeMember("S").TypeParameters.ToTestDisplayStrings());
        }
 
        [Fact]
        public void TypeDeclaration_AllowedModifiersForMembers()
        {
            var src = @"
record struct S
{
    protected int Property { get; set; } // 1
    internal protected string field; // 2, 3
    abstract void M(); // 4
    virtual void M2() { } // 5
}";
 
            var comp = CreateCompilation(src);
            comp.VerifyDiagnostics(
                // (4,19): error CS0666: 'S.Property': new protected member declared in struct
                //     protected int Property { get; set; } // 1
                Diagnostic(ErrorCode.ERR_ProtectedInStruct, "Property").WithArguments("S.Property").WithLocation(4, 19),
                // (5,31): error CS0666: 'S.field': new protected member declared in struct
                //     internal protected string field; // 2, 3
                Diagnostic(ErrorCode.ERR_ProtectedInStruct, "field").WithArguments("S.field").WithLocation(5, 31),
                // (5,31): warning CS0649: Field 'S.field' is never assigned to, and will always have its default value null
                //     internal protected string field; // 2, 3
                Diagnostic(ErrorCode.WRN_UnassignedInternalField, "field").WithArguments("S.field", "null").WithLocation(5, 31),
                // (6,19): error CS0621: 'S.M()': virtual or abstract members cannot be private
                //     abstract void M(); // 4
                Diagnostic(ErrorCode.ERR_VirtualPrivate, "M").WithArguments("S.M()").WithLocation(6, 19),
                // (7,18): error CS0621: 'S.M2()': virtual or abstract members cannot be private
                //     virtual void M2() { } // 5
                Diagnostic(ErrorCode.ERR_VirtualPrivate, "M2").WithArguments("S.M2()").WithLocation(7, 18)
                );
        }
 
        [Fact]
        public void TypeDeclaration_ImplementInterface()
        {
            var src = @"
I i = (I)default(S);
System.Console.Write(i.M(""four""));
 
I i2 = (I)default(S2);
System.Console.Write(i2.M(""four""));
 
interface I
{
    int M(string s);
}
public record struct S : I
{
    public int M(string s)
        => s.Length;
}
public record struct S2 : I
{
    int I.M(string s)
        => s.Length + 1;
}
";
 
            var comp = CreateCompilation(src);
            comp.VerifyDiagnostics();
 
            CompileAndVerify(comp, expectedOutput: "45");
 
            AssertEx.Equal(new[] {
                "System.Int32 S.M(System.String s)",
                "readonly System.String S.ToString()",
                "readonly System.Boolean S.PrintMembers(System.Text.StringBuilder builder)",
                "System.Boolean S.op_Inequality(S left, S right)",
                "System.Boolean S.op_Equality(S left, S right)",
                "readonly System.Int32 S.GetHashCode()",
                "readonly System.Boolean S.Equals(System.Object obj)",
                "readonly System.Boolean S.Equals(S other)",
                "S..ctor()" },
                comp.GetMember<NamedTypeSymbol>("S").GetMembers().ToTestDisplayStrings());
        }
 
        [Fact]
        public void TypeDeclaration_SatisfiesStructConstraint()
        {
            var src = @"
S s = default;
System.Console.Write(M(s));
 
static int M<T>(T t) where T : struct, I
    => t.Property;
 
public interface I
{
    int Property { get; }
}
public record struct S : I
{
    public int Property => 42;
}
";
 
            var comp = CreateCompilation(src);
            comp.VerifyDiagnostics();
 
            CompileAndVerify(comp, expectedOutput: "42");
        }
 
        [Fact]
        public void TypeDeclaration_AccessingThis()
        {
            var src = @"
S s = new S();
System.Console.Write(s.M());
 
public record struct S
{
    public int Property => 42;
 
    public int M()
        => this.Property;
}
";
 
            var comp = CreateCompilation(src);
            comp.VerifyDiagnostics();
 
            var verifier = CompileAndVerify(comp, expectedOutput: "42");
            verifier.VerifyIL("S.M", @"
{
  // Code size        7 (0x7)
  .maxstack  1
  IL_0000:  ldarg.0
  IL_0001:  call       ""int S.Property.get""
  IL_0006:  ret
}
");
        }
 
        [Fact]
        public void TypeDeclaration_NoBaseInitializer()
        {
            var src = @"
public record struct S
{
    public S(int i) : base() { }
}
";
            var comp = CreateCompilation(src);
            comp.VerifyDiagnostics(
                // (4,12): error CS0522: 'S': structs cannot call base class constructors
                //     public S(int i) : base() { }
                Diagnostic(ErrorCode.ERR_StructWithBaseConstructorCall, "S").WithArguments("S").WithLocation(4, 12)
                );
        }
 
        [Fact]
        public void TypeDeclaration_ParameterlessConstructor_01()
        {
            var src =
@"record struct S0();
record struct S1;
record struct S2
{
    public S2() { }
}";
 
            var comp = CreateCompilation(src, parseOptions: TestOptions.Regular9);
            comp.VerifyDiagnostics(
                // (1,8): error CS8773: Feature 'record structs' is not available in C# 9.0. Please use language version 10.0 or greater.
                // record struct S0();
                Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion9, "struct").WithArguments("record structs", "10.0").WithLocation(1, 8),
                // (2,8): error CS8773: Feature 'record structs' is not available in C# 9.0. Please use language version 10.0 or greater.
                // record struct S1;
                Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion9, "struct").WithArguments("record structs", "10.0").WithLocation(2, 8),
                // (3,8): error CS8773: Feature 'record structs' is not available in C# 9.0. Please use language version 10.0 or greater.
                // record struct S2
                Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion9, "struct").WithArguments("record structs", "10.0").WithLocation(3, 8),
                // (5,12): error CS8773: Feature 'parameterless struct constructors' is not available in C# 9.0. Please use language version 10.0 or greater.
                //     public S2() { }
                Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion9, "S2").WithArguments("parameterless struct constructors", "10.0").WithLocation(5, 12));
 
            var verifier = CompileAndVerify(src);
            verifier.VerifyIL("S0..ctor()",
@"{
  // Code size        1 (0x1)
  .maxstack  0
  IL_0000:  ret
}");
            verifier.VerifyMissing("S1..ctor()");
            verifier.VerifyIL("S2..ctor()",
@"{
  // Code size        1 (0x1)
  .maxstack  0
  IL_0000:  ret
}");
        }
 
        [Fact]
        public void TypeDeclaration_ParameterlessConstructor_02()
        {
            var src =
@"record struct S1
{
    S1() { }
}
record struct S2
{
    internal S2() { }
}";
 
            var comp = CreateCompilation(src, parseOptions: TestOptions.Regular9);
            comp.VerifyDiagnostics(
                // (1,8): error CS8773: Feature 'record structs' is not available in C# 9.0. Please use language version 10.0 or greater.
                // record struct S1
                Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion9, "struct").WithArguments("record structs", "10.0").WithLocation(1, 8),
                // (3,5): error CS8773: Feature 'parameterless struct constructors' is not available in C# 9.0. Please use language version 10.0 or greater.
                //     S1() { }
                Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion9, "S1").WithArguments("parameterless struct constructors", "10.0").WithLocation(3, 5),
                // (3,5): error CS8958: The parameterless struct constructor must be 'public'.
                //     S1() { }
                Diagnostic(ErrorCode.ERR_NonPublicParameterlessStructConstructor, "S1").WithLocation(3, 5),
                // (5,8): error CS8773: Feature 'record structs' is not available in C# 9.0. Please use language version 10.0 or greater.
                // record struct S2
                Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion9, "struct").WithArguments("record structs", "10.0").WithLocation(5, 8),
                // (7,14): error CS8773: Feature 'parameterless struct constructors' is not available in C# 9.0. Please use language version 10.0 or greater.
                //     internal S2() { }
                Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion9, "S2").WithArguments("parameterless struct constructors", "10.0").WithLocation(7, 14),
                // (7,14): error CS8958: The parameterless struct constructor must be 'public'.
                //     internal S2() { }
                Diagnostic(ErrorCode.ERR_NonPublicParameterlessStructConstructor, "S2").WithLocation(7, 14));
 
            comp = CreateCompilation(src);
            comp.VerifyDiagnostics(
                // (3,5): error CS8918: The parameterless struct constructor must be 'public'.
                //     S1() { }
                Diagnostic(ErrorCode.ERR_NonPublicParameterlessStructConstructor, "S1").WithLocation(3, 5),
                // (7,14): error CS8918: The parameterless struct constructor must be 'public'.
                //     internal S2() { }
                Diagnostic(ErrorCode.ERR_NonPublicParameterlessStructConstructor, "S2").WithLocation(7, 14));
        }
 
        [Fact]
        public void TypeDeclaration_ParameterlessConstructor_OtherConstructors()
        {
            var src = @"
record struct S1
{
    public S1() { }
    S1(object o) { } // ok because no record parameter list
}
record struct S2
{
    S2(object o) { }
}
record struct S3()
{
    S3(object o) { } // 1
}
record struct S4()
{
    S4(object o) : this() { }
}
record struct S5(object o)
{
    public S5() { } // 2
}
record struct S6(object o)
{
    public S6() : this(null) { }
}
";
            var comp = CreateCompilation(src);
            comp.VerifyDiagnostics(
                // (13,5): error CS8862: A constructor declared in a type with parameter list must have 'this' constructor initializer.
                //     S3(object o) { } // 1
                Diagnostic(ErrorCode.ERR_UnexpectedOrMissingConstructorInitializerInRecord, "S3").WithLocation(13, 5),
                // (21,12): error CS8862: A constructor declared in a type with parameter list must have 'this' constructor initializer.
                //     public S5() { } // 2
                Diagnostic(ErrorCode.ERR_UnexpectedOrMissingConstructorInitializerInRecord, "S5").WithLocation(21, 12)
                );
        }
 
        [Fact]
        public void TypeDeclaration_ParameterlessConstructor_Initializers()
        {
            var src = @"
var s1 = new S1();
var s2 = new S2(null);
var s2b = new S2();
var s3 = new S3();
var s4 = new S4(new object());
var s5 = new S5();
var s6 = new S6(""s6.other"");
 
System.Console.Write((s1.field, s2.field, s2b.field is null, s3.field, s4.field, s5.field, s6.field, s6.other));
 
record struct S1
{
    public string field = ""s1"";
    public S1() { }
}
record struct S2
{
    public string field = ""s2"";
    public S2(object o) { }
}
record struct S3()
{
    public string field = ""s3"";
}
record struct S4
{
    public string field = ""s4"";
    public S4(object o) : this() { }
}
record struct S5()
{
    public string field = ""s5"";
    public S5(object o) : this() { }
}
record struct S6(string other)
{
    public string field = ""s6.field"";
    public S6() : this(""ignored"") { }
}
";
            var comp = CreateCompilation(src);
            comp.VerifyDiagnostics();
            CompileAndVerify(comp, expectedOutput: "(s1, s2, True, s3, s4, s5, s6.field, s6.other)");
        }
 
        [Fact]
        public void TypeDeclaration_InstanceInitializers_01()
        {
            var src = @"
public record struct S
{
    public int field = 42;
    public int Property { get; set; } = 43;
}
";
 
            var comp = CreateCompilation(src, parseOptions: TestOptions.Regular9);
            comp.VerifyDiagnostics(
                // (2,15): error CS8773: Feature 'record structs' is not available in C# 9.0. Please use language version 10.0 or greater.
                // public record struct S
                Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion9, "struct").WithArguments("record structs", "10.0").WithLocation(2, 15),
                // (2,22): error CS8983: A 'struct' with field initializers must include an explicitly declared constructor.
                // public record struct S
                Diagnostic(ErrorCode.ERR_StructHasInitializersAndNoDeclaredConstructor, "S").WithLocation(2, 22),
                // (4,16): error CS8773: Feature 'struct field initializers' is not available in C# 9.0. Please use language version 10.0 or greater.
                //     public int field = 42;
                Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion9, "field").WithArguments("struct field initializers", "10.0").WithLocation(4, 16),
                // (5,16): error CS8773: Feature 'struct field initializers' is not available in C# 9.0. Please use language version 10.0 or greater.
                //     public int Property { get; set; } = 43;
                Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion9, "Property").WithArguments("struct field initializers", "10.0").WithLocation(5, 16));
 
            comp = CreateCompilation(src);
            comp.VerifyDiagnostics(
                // (2,22): error CS8983: A 'struct' with field initializers must include an explicitly declared constructor.
                // public record struct S
                Diagnostic(ErrorCode.ERR_StructHasInitializersAndNoDeclaredConstructor, "S").WithLocation(2, 22));
        }
 
        [Fact]
        public void TypeDeclaration_InstanceInitializers_02()
        {
            var src = @"
public record struct S
{
    public S() { }
    public int field = 42;
    public int Property { get; set; } = 43;
}
";
 
            var comp = CreateCompilation(src, parseOptions: TestOptions.Regular9);
            comp.VerifyDiagnostics(
                // (2,15): error CS8773: Feature 'record structs' is not available in C# 9.0. Please use language version 10.0 or greater.
                // public record struct S
                Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion9, "struct").WithArguments("record structs", "10.0").WithLocation(2, 15),
                // (4,12): error CS8773: Feature 'parameterless struct constructors' is not available in C# 9.0. Please use language version 10.0 or greater.
                //     public S() { }
                Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion9, "S").WithArguments("parameterless struct constructors", "10.0").WithLocation(4, 12),
                // (5,16): error CS8773: Feature 'struct field initializers' is not available in C# 9.0. Please use language version 10.0 or greater.
                //     public int field = 42;
                Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion9, "field").WithArguments("struct field initializers", "10.0").WithLocation(5, 16),
                // (6,16): error CS8773: Feature 'struct field initializers' is not available in C# 9.0. Please use language version 10.0 or greater.
                //     public int Property { get; set; } = 43;
                Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion9, "Property").WithArguments("struct field initializers", "10.0").WithLocation(6, 16));
 
            comp = CreateCompilation(src);
            comp.VerifyDiagnostics();
        }
 
        [Fact]
        public void TypeDeclaration_InstanceInitializers_03()
        {
            var src = @"
public record struct S()
{
    public int field = 42;
    public int Property { get; set; } = 43;
}
";
 
            var comp = CreateCompilation(src, parseOptions: TestOptions.Regular9);
            comp.VerifyDiagnostics(
                // (2,15): error CS8773: Feature 'record structs' is not available in C# 9.0. Please use language version 10.0 or greater.
                // public record struct S()
                Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion9, "struct").WithArguments("record structs", "10.0").WithLocation(2, 15));
 
            comp = CreateCompilation(src);
            comp.VerifyDiagnostics();
        }
 
        [Fact]
        public void TypeDeclaration_NoDestructor()
        {
            var src = @"
public record struct S
{
    ~S() { }
}
";
            var comp = CreateCompilation(src);
            comp.VerifyDiagnostics(
                // (4,6): error CS0575: Only class types can contain destructors
                //     ~S() { }
                Diagnostic(ErrorCode.ERR_OnlyClassesCanContainDestructors, "S").WithLocation(4, 6)
                );
        }
 
        [Fact]
        public void TypeDeclaration_DifferentPartials()
        {
            var src = @"
partial record struct S1;
partial struct S1 { }
 
partial struct S2 { }
partial record struct S2;
 
partial record struct S3;
partial record S3 { }
 
partial record struct S4;
partial record class S4 { }
 
partial record struct S5;
partial class S5 { }
 
partial record struct S6;
partial interface S6 { }
 
partial record class C1;
partial struct C1 { }
 
partial record class C2;
partial record struct C2 { }
 
partial record class C3 { }
partial record C3;
 
partial record class C4;
partial class C4 { }
 
partial record class C5;
partial interface C5 { }
";
 
            var comp = CreateCompilation(src);
            comp.VerifyDiagnostics(
                // (3,16): error CS0261: Partial declarations of 'S1' must be all classes, all record classes, all structs, all record structs, or all interfaces
                // partial struct S1 { }
                Diagnostic(ErrorCode.ERR_PartialTypeKindConflict, "S1").WithArguments("S1").WithLocation(3, 16),
                // (6,23): error CS0261: Partial declarations of 'S2' must be all classes, all record classes, all structs, all record structs, or all interfaces
                // partial record struct S2;
                Diagnostic(ErrorCode.ERR_PartialTypeKindConflict, "S2").WithArguments("S2").WithLocation(6, 23),
                // (9,16): error CS0261: Partial declarations of 'S3' must be all classes, all record classes, all structs, all record structs, or all interfaces
                // partial record S3 { }
                Diagnostic(ErrorCode.ERR_PartialTypeKindConflict, "S3").WithArguments("S3").WithLocation(9, 16),
                // (12,22): error CS0261: Partial declarations of 'S4' must be all classes, all record classes, all structs, all record structs, or all interfaces
                // partial record class S4 { }
                Diagnostic(ErrorCode.ERR_PartialTypeKindConflict, "S4").WithArguments("S4").WithLocation(12, 22),
                // (15,15): error CS0261: Partial declarations of 'S5' must be all classes, all record classes, all structs, all record structs, or all interfaces
                // partial class S5 { }
                Diagnostic(ErrorCode.ERR_PartialTypeKindConflict, "S5").WithArguments("S5").WithLocation(15, 15),
                // (18,19): error CS0261: Partial declarations of 'S6' must be all classes, all record classes, all structs, all record structs, or all interfaces
                // partial interface S6 { }
                Diagnostic(ErrorCode.ERR_PartialTypeKindConflict, "S6").WithArguments("S6").WithLocation(18, 19),
                // (21,16): error CS0261: Partial declarations of 'C1' must be all classes, all record classes, all structs, all record structs, or all interfaces
                // partial struct C1 { }
                Diagnostic(ErrorCode.ERR_PartialTypeKindConflict, "C1").WithArguments("C1").WithLocation(21, 16),
                // (24,23): error CS0261: Partial declarations of 'C2' must be all classes, all record classes, all structs, all record structs, or all interfaces
                // partial record struct C2 { }
                Diagnostic(ErrorCode.ERR_PartialTypeKindConflict, "C2").WithArguments("C2").WithLocation(24, 23),
                // (30,15): error CS0261: Partial declarations of 'C4' must be all classes, all record classes, all structs, all record structs, or all interfaces
                // partial class C4 { }
                Diagnostic(ErrorCode.ERR_PartialTypeKindConflict, "C4").WithArguments("C4").WithLocation(30, 15),
                // (33,19): error CS0261: Partial declarations of 'C5' must be all classes, all record classes, all structs, all record structs, or all interfaces
                // partial interface C5 { }
                Diagnostic(ErrorCode.ERR_PartialTypeKindConflict, "C5").WithArguments("C5").WithLocation(33, 19)
                );
        }
 
        [Fact]
        public void PartialRecord_OnlyOnePartialHasParameterList()
        {
            var src = @"
partial record struct S(int i);
partial record struct S(int i);
 
partial record struct S2(int i);
partial record struct S2();
 
partial record struct S3();
partial record struct S3();
";
            var comp = CreateCompilation(src);
            comp.VerifyDiagnostics(
                // (3,24): error CS8863: Only a single partial type declaration may have a parameter list
                // partial record struct S(int i);
                Diagnostic(ErrorCode.ERR_MultipleRecordParameterLists, "(int i)").WithLocation(3, 24),
                // (6,25): error CS8863: Only a single partial type declaration may have a parameter list
                // partial record struct S2();
                Diagnostic(ErrorCode.ERR_MultipleRecordParameterLists, "()").WithLocation(6, 25),
                // (9,25): error CS8863: Only a single partial type declaration may have a parameter list
                // partial record struct S3();
                Diagnostic(ErrorCode.ERR_MultipleRecordParameterLists, "()").WithLocation(9, 25)
                );
        }
 
        [Fact]
        public void PartialRecord_ParametersInScopeOfBothParts()
        {
            var src = @"
var c = new C(2);
System.Console.Write((c.P1, c.P2));
 
public partial record struct C(int X)
{
    public int P1 { get; set; } = X;
}
public partial record struct C
{
    public int P2 { get; set; } = X;
}
";
            var comp = CreateCompilation(src);
            CompileAndVerify(comp, expectedOutput: "(2, 2)", verify: Verification.Skipped /* init-only */)
                .VerifyDiagnostics(
                    // (5,30): warning CS0282: There is no defined ordering between fields in multiple declarations of partial struct 'C'. To specify an ordering, all instance fields must be in the same declaration.
                    // public partial record struct C(int X)
                    Diagnostic(ErrorCode.WRN_SequentialOnPartialClass, "C").WithArguments("C").WithLocation(5, 30)
                    );
        }
 
        [Fact]
        public void PartialRecord_DuplicateMemberNames()
        {
            var src = @"
public partial record struct C(int X)
{
    public void M(int i) { }
}
public partial record struct C
{
    public void M(string s) { }
}
";
            var comp = CreateCompilation(src);
            var expectedMemberNames = new string[]
            {
                ".ctor",
                "<X>k__BackingField",
                "get_X",
                "set_X",
                "X",
                "M",
                "M",
                "ToString",
                "PrintMembers",
                "op_Inequality",
                "op_Equality",
                "GetHashCode",
                "Equals",
                "Equals",
                "Deconstruct",
                ".ctor",
            };
            AssertEx.Equal(expectedMemberNames, comp.GetMember<NamedTypeSymbol>("C").GetPublicSymbol().MemberNames);
        }
 
        [Fact]
        public void RecordInsideGenericType()
        {
            var src = @"
var c = new C<int>.Nested(2);
System.Console.Write(c.T);
 
public class C<T>
{
    public record struct Nested(T T);
}
";
            var comp = CreateCompilation(src);
            comp.VerifyDiagnostics();
            CompileAndVerify(comp, expectedOutput: "2");
        }
 
        [Fact]
        public void PositionalMemberModifiers_RefOrOut()
        {
            var src = @"
record struct R(ref int P1, out int P2);
";
 
            var comp = CreateCompilation(src);
            comp.VerifyEmitDiagnostics(
                // (2,15): error CS0177: The out parameter 'P2' must be assigned to before control leaves the current method
                // record struct R(ref int P1, out int P2);
                Diagnostic(ErrorCode.ERR_ParamUnassigned, "R").WithArguments("P2").WithLocation(2, 15),
                // (2,17): error CS0631: ref and out are not valid in this context
                // record struct R(ref int P1, out int P2);
                Diagnostic(ErrorCode.ERR_IllegalRefParam, "ref").WithLocation(2, 17),
                // (2,29): error CS0631: ref and out are not valid in this context
                // record struct R(ref int P1, out int P2);
                Diagnostic(ErrorCode.ERR_IllegalRefParam, "out").WithLocation(2, 29)
                );
        }
 
        [Fact, WorkItem(45008, "https://github.com/dotnet/roslyn/issues/45008")]
        public void PositionalMemberModifiers_This()
        {
            var src = @"
record struct R(this int i);
";
 
            var comp = CreateCompilation(src);
            comp.VerifyEmitDiagnostics(
                // (2,17): error CS0027: Keyword 'this' is not available in the current context
                // record struct R(this int i);
                Diagnostic(ErrorCode.ERR_ThisInBadContext, "this").WithLocation(2, 17)
                );
        }
 
        [Fact, WorkItem(45591, "https://github.com/dotnet/roslyn/issues/45591")]
        public void Clone_DisallowedInSource()
        {
            var src = @"
record struct C1(string Clone); // 1
record struct C2
{
    string Clone; // 2
}
record struct C3
{
    string Clone { get; set; } // 3
}
record struct C5
{
    void Clone() { } // 4
    void Clone(int i) { } // 5
}
record struct C6
{
    class Clone { } // 6
}
record struct C7
{
    delegate void Clone(); // 7
}
record struct C8
{
    event System.Action Clone;  // 8
}
record struct Clone
{
    Clone(int i) => throw null;
}
record struct C9 : System.ICloneable
{
    object System.ICloneable.Clone() => throw null;
}
";
 
            var comp = CreateCompilation(src);
            comp.VerifyDiagnostics(
                // (2,25): error CS8859: Members named 'Clone' are disallowed in records.
                // record struct C1(string Clone); // 1
                Diagnostic(ErrorCode.ERR_CloneDisallowedInRecord, "Clone").WithLocation(2, 25),
                // (5,12): error CS8859: Members named 'Clone' are disallowed in records.
                //     string Clone; // 2
                Diagnostic(ErrorCode.ERR_CloneDisallowedInRecord, "Clone").WithLocation(5, 12),
                // (5,12): warning CS0169: The field 'C2.Clone' is never used
                //     string Clone; // 2
                Diagnostic(ErrorCode.WRN_UnreferencedField, "Clone").WithArguments("C2.Clone").WithLocation(5, 12),
                // (9,12): error CS8859: Members named 'Clone' are disallowed in records.
                //     string Clone { get; set; } // 3
                Diagnostic(ErrorCode.ERR_CloneDisallowedInRecord, "Clone").WithLocation(9, 12),
                // (13,10): error CS8859: Members named 'Clone' are disallowed in records.
                //     void Clone() { } // 4
                Diagnostic(ErrorCode.ERR_CloneDisallowedInRecord, "Clone").WithLocation(13, 10),
                // (14,10): error CS8859: Members named 'Clone' are disallowed in records.
                //     void Clone(int i) { } // 5
                Diagnostic(ErrorCode.ERR_CloneDisallowedInRecord, "Clone").WithLocation(14, 10),
                // (18,11): error CS8859: Members named 'Clone' are disallowed in records.
                //     class Clone { } // 6
                Diagnostic(ErrorCode.ERR_CloneDisallowedInRecord, "Clone").WithLocation(18, 11),
                // (22,19): error CS8859: Members named 'Clone' are disallowed in records.
                //     delegate void Clone(); // 7
                Diagnostic(ErrorCode.ERR_CloneDisallowedInRecord, "Clone").WithLocation(22, 19),
                // (26,25): error CS8859: Members named 'Clone' are disallowed in records.
                //     event System.Action Clone;  // 8
                Diagnostic(ErrorCode.ERR_CloneDisallowedInRecord, "Clone").WithLocation(26, 25),
                // (26,25): warning CS0067: The event 'C8.Clone' is never used
                //     event System.Action Clone;  // 8
                Diagnostic(ErrorCode.WRN_UnreferencedEvent, "Clone").WithArguments("C8.Clone").WithLocation(26, 25)
                );
        }
 
        [ConditionalFact(typeof(DesktopOnly), Reason = ConditionalSkipReason.RestrictedTypesNeedDesktop)]
        [WorkItem(48115, "https://github.com/dotnet/roslyn/issues/48115")]
        public void RestrictedTypesAndPointerTypes()
        {
            var src = @"
class C<T> { }
static class C2 { }
ref struct RefLike{}
 
unsafe record struct C(
    int* P1, // 1
    int*[] P2,
    C<int*[]> P3,
    delegate*<int, int> P4, // 2
    void P5, // 3
    C2 P6, // 4, 5
    System.ArgIterator P7, // 6
    System.TypedReference P8, // 7
    RefLike P9, // 8
    delegate*<void> P10); // 9
";
 
            var comp = CreateCompilation(new[] { src, IsExternalInitTypeDefinition }, options: TestOptions.UnsafeDebugDll);
            comp.VerifyEmitDiagnostics(
                // 0.cs(7,10): error CS8908: The type 'int*' may not be used for a field of a record.
                //     int* P1, // 1
                Diagnostic(ErrorCode.ERR_BadFieldTypeInRecord, "P1").WithArguments("int*").WithLocation(7, 10),
                // 0.cs(10,25): error CS8908: The type 'delegate*<int, int>' may not be used for a field of a record.
                //     delegate*<int, int> P4, // 2
                Diagnostic(ErrorCode.ERR_BadFieldTypeInRecord, "P4").WithArguments("delegate*<int, int>").WithLocation(10, 25),
                // 0.cs(11,5): error CS1536: Invalid parameter type 'void'
                //     void P5, // 3
                Diagnostic(ErrorCode.ERR_NoVoidParameter, "void").WithLocation(11, 5),
                // 0.cs(12,5): error CS0721: 'C2': static types cannot be used as parameters
                //     C2 P6, // 4, 5
                Diagnostic(ErrorCode.ERR_ParameterIsStaticClass, "C2").WithArguments("C2").WithLocation(12, 5),
                // 0.cs(12,5): error CS0722: 'C2': static types cannot be used as return types
                //     C2 P6, // 4, 5
                Diagnostic(ErrorCode.ERR_ReturnTypeIsStaticClass, "C2").WithArguments("C2").WithLocation(12, 5),
                // 0.cs(13,5): error CS0610: Field or property cannot be of type 'ArgIterator'
                //     System.ArgIterator P7, // 6
                Diagnostic(ErrorCode.ERR_FieldCantBeRefAny, "System.ArgIterator").WithArguments("System.ArgIterator").WithLocation(13, 5),
                // 0.cs(14,5): error CS0610: Field or property cannot be of type 'TypedReference'
                //     System.TypedReference P8, // 7
                Diagnostic(ErrorCode.ERR_FieldCantBeRefAny, "System.TypedReference").WithArguments("System.TypedReference").WithLocation(14, 5),
                // 0.cs(15,5): error CS8345: Field or auto-implemented property cannot be of type 'RefLike' unless it is an instance member of a ref struct.
                //     RefLike P9, // 8
                Diagnostic(ErrorCode.ERR_FieldAutoPropCantBeByRefLike, "RefLike").WithArguments("RefLike").WithLocation(15, 5),
                // 0.cs(16,21): error CS8908: The type 'delegate*<void>' may not be used for a field of a record.
                //     delegate*<void> P10); // 9
                Diagnostic(ErrorCode.ERR_BadFieldTypeInRecord, "P10").WithArguments("delegate*<void>").WithLocation(16, 21)
                );
        }
 
        [ConditionalFact(typeof(DesktopOnly), Reason = ConditionalSkipReason.RestrictedTypesNeedDesktop)]
        [WorkItem(48115, "https://github.com/dotnet/roslyn/issues/48115")]
        public void RestrictedTypesAndPointerTypes_NominalMembers()
        {
            var src = @"
public class C<T> { }
public static class C2 { }
public ref struct RefLike{}
 
public unsafe record struct C
{
    public int* f1; // 1
    public int*[] f2;
    public C<int*[]> f3;
    public delegate*<int, int> f4; // 2
    public void f5; // 3
    public C2 f6; // 4
    public System.ArgIterator f7; // 5
    public System.TypedReference f8; // 6
    public RefLike f9; // 7
    public delegate*<void> f10; // 8
}
";
 
            var comp = CreateCompilation(new[] { src, IsExternalInitTypeDefinition }, options: TestOptions.UnsafeDebugDll);
            comp.VerifyEmitDiagnostics(
                // 0.cs(8,17): error CS8908: The type 'int*' may not be used for a field of a record.
                //     public int* f1; // 1
                Diagnostic(ErrorCode.ERR_BadFieldTypeInRecord, "f1").WithArguments("int*").WithLocation(8, 17),
                // 0.cs(11,32): error CS8908: The type 'delegate*<int, int>' may not be used for a field of a record.
                //     public delegate*<int, int> f4; // 2
                Diagnostic(ErrorCode.ERR_BadFieldTypeInRecord, "f4").WithArguments("delegate*<int, int>").WithLocation(11, 32),
                // 0.cs(12,12): error CS0670: Field cannot have void type
                //     public void f5; // 3
                Diagnostic(ErrorCode.ERR_FieldCantHaveVoidType, "void").WithLocation(12, 12),
                // 0.cs(13,15): error CS0723: Cannot declare a variable of static type 'C2'
                //     public C2 f6; // 4
                Diagnostic(ErrorCode.ERR_VarDeclIsStaticClass, "f6").WithArguments("C2").WithLocation(13, 15),
                // 0.cs(14,12): error CS0610: Field or property cannot be of type 'ArgIterator'
                //     public System.ArgIterator f7; // 5
                Diagnostic(ErrorCode.ERR_FieldCantBeRefAny, "System.ArgIterator").WithArguments("System.ArgIterator").WithLocation(14, 12),
                // 0.cs(15,12): error CS0610: Field or property cannot be of type 'TypedReference'
                //     public System.TypedReference f8; // 6
                Diagnostic(ErrorCode.ERR_FieldCantBeRefAny, "System.TypedReference").WithArguments("System.TypedReference").WithLocation(15, 12),
                // 0.cs(16,12): error CS8345: Field or auto-implemented property cannot be of type 'RefLike' unless it is an instance member of a ref struct.
                //     public RefLike f9; // 7
                Diagnostic(ErrorCode.ERR_FieldAutoPropCantBeByRefLike, "RefLike").WithArguments("RefLike").WithLocation(16, 12),
                // 0.cs(17,28): error CS8908: The type 'delegate*<void>' may not be used for a field of a record.
                //     public delegate*<void> f10; // 8
                Diagnostic(ErrorCode.ERR_BadFieldTypeInRecord, "f10").WithArguments("delegate*<void>").WithLocation(17, 28)
                );
        }
 
        [ConditionalFact(typeof(DesktopOnly), Reason = ConditionalSkipReason.RestrictedTypesNeedDesktop)]
        [WorkItem(48115, "https://github.com/dotnet/roslyn/issues/48115")]
        public void RestrictedTypesAndPointerTypes_NominalMembers_AutoProperties()
        {
            var src = @"
public class C<T> { }
public static class C2 { }
public ref struct RefLike{}
 
public unsafe record struct C
{
    public int* f1 { get; set; } // 1
    public int*[] f2 { get; set; }
    public C<int*[]> f3 { get; set; }
    public delegate*<int, int> f4 { get; set; } // 2
    public void f5 { get; set; } // 3
    public C2 f6 { get; set; } // 4
    public System.ArgIterator f7 { get; set; } // 5
    public System.TypedReference f8 { get; set; } // 6
    public RefLike f9 { get; set; } // 7
    public delegate*<void>[] f10 { get; set; } // 8
}
";
 
            var comp = CreateCompilation(new[] { src, IsExternalInitTypeDefinition }, options: TestOptions.UnsafeDebugDll);
            comp.VerifyEmitDiagnostics(
                // 0.cs(8,17): error CS8908: The type 'int*' may not be used for a field of a record.
                //     public int* f1 { get; set; } // 1
                Diagnostic(ErrorCode.ERR_BadFieldTypeInRecord, "f1").WithArguments("int*").WithLocation(8, 17),
                // 0.cs(11,32): error CS8908: The type 'delegate*<int, int>' may not be used for a field of a record.
                //     public delegate*<int, int> f4 { get; set; } // 2
                Diagnostic(ErrorCode.ERR_BadFieldTypeInRecord, "f4").WithArguments("delegate*<int, int>").WithLocation(11, 32),
                // 0.cs(12,17): error CS0547: 'C.f5': property or indexer cannot have void type
                //     public void f5 { get; set; } // 3
                Diagnostic(ErrorCode.ERR_PropertyCantHaveVoidType, "f5").WithArguments("C.f5").WithLocation(12, 17),
                // 0.cs(13,12): error CS0722: 'C2': static types cannot be used as return types
                //     public C2 f6 { get; set; } // 4
                Diagnostic(ErrorCode.ERR_ReturnTypeIsStaticClass, "C2").WithArguments("C2").WithLocation(13, 12),
                // 0.cs(14,12): error CS0610: Field or property cannot be of type 'ArgIterator'
                //     public System.ArgIterator f7 { get; set; } // 5
                Diagnostic(ErrorCode.ERR_FieldCantBeRefAny, "System.ArgIterator").WithArguments("System.ArgIterator").WithLocation(14, 12),
                // 0.cs(15,12): error CS0610: Field or property cannot be of type 'TypedReference'
                //     public System.TypedReference f8 { get; set; } // 6
                Diagnostic(ErrorCode.ERR_FieldCantBeRefAny, "System.TypedReference").WithArguments("System.TypedReference").WithLocation(15, 12),
                // 0.cs(16,12): error CS8345: Field or auto-implemented property cannot be of type 'RefLike' unless it is an instance member of a ref struct.
                //     public RefLike f9 { get; set; } // 7
                Diagnostic(ErrorCode.ERR_FieldAutoPropCantBeByRefLike, "RefLike").WithArguments("RefLike").WithLocation(16, 12)
                );
        }
 
        [Fact]
        [WorkItem(48115, "https://github.com/dotnet/roslyn/issues/48115")]
        public void RestrictedTypesAndPointerTypes_PointerTypeAllowedForParameterAndProperty()
        {
            var src = @"
class C<T> { }
 
unsafe record struct C(int* P1, int*[] P2, C<int*[]> P3)
{
    int* P1
    {
        get { System.Console.Write(""P1 ""); return null; }
        init { }
    }
    int*[] P2
    {
        get { System.Console.Write(""P2 ""); return null; }
        init { }
    }
    C<int*[]> P3
    {
        get { System.Console.Write(""P3 ""); return null; }
        init { }
    }
 
    public unsafe static void Main()
    {
        var x = new C(null, null, null);
        var (x1, x2, x3) = x;
        System.Console.Write(""RAN"");
    }
}
";
            var comp = CreateCompilation(new[] { src, IsExternalInitTypeDefinition }, parseOptions: TestOptions.RegularPreview, options: TestOptions.UnsafeDebugExe);
            comp.VerifyEmitDiagnostics(
                // (4,29): warning CS8907: Parameter 'P1' is unread. Did you forget to use it to initialize the property with that name?
                // unsafe record struct C(int* P1, int*[] P2, C<int*[]> P3)
                Diagnostic(ErrorCode.WRN_UnreadRecordParameter, "P1").WithArguments("P1").WithLocation(4, 29),
                // (4,40): warning CS8907: Parameter 'P2' is unread. Did you forget to use it to initialize the property with that name?
                // unsafe record struct C(int* P1, int*[] P2, C<int*[]> P3)
                Diagnostic(ErrorCode.WRN_UnreadRecordParameter, "P2").WithArguments("P2").WithLocation(4, 40),
                // (4,54): warning CS8907: Parameter 'P3' is unread. Did you forget to use it to initialize the property with that name?
                // unsafe record struct C(int* P1, int*[] P2, C<int*[]> P3)
                Diagnostic(ErrorCode.WRN_UnreadRecordParameter, "P3").WithArguments("P3").WithLocation(4, 54)
                );
 
            CompileAndVerify(comp, expectedOutput: "P1 P2 P3 RAN", verify: Verification.Skipped /* pointers */);
        }
 
        [ConditionalFact(typeof(DesktopOnly), Reason = ConditionalSkipReason.RestrictedTypesNeedDesktop)]
        [WorkItem(48115, "https://github.com/dotnet/roslyn/issues/48115")]
        public void RestrictedTypesAndPointerTypes_StaticFields()
        {
            var src = @"
public class C<T> { }
public static class C2 { }
public ref struct RefLike{}
 
public unsafe record C
{
    public static int* f1;
    public static int*[] f2;
    public static C<int*[]> f3;
    public static delegate*<int, int> f4;
    public static C2 f6; // 1
    public static System.ArgIterator f7; // 2
    public static System.TypedReference f8; // 3
    public static RefLike f9; // 4
}
";
 
            var comp = CreateCompilation(new[] { src, IsExternalInitTypeDefinition }, options: TestOptions.UnsafeDebugDll);
            comp.VerifyEmitDiagnostics(
                // (12,22): error CS0723: Cannot declare a variable of static type 'C2'
                //     public static C2 f6; // 1
                Diagnostic(ErrorCode.ERR_VarDeclIsStaticClass, "f6").WithArguments("C2").WithLocation(12, 22),
                // (13,19): error CS0610: Field or property cannot be of type 'ArgIterator'
                //     public static System.ArgIterator f7; // 2
                Diagnostic(ErrorCode.ERR_FieldCantBeRefAny, "System.ArgIterator").WithArguments("System.ArgIterator").WithLocation(13, 19),
                // (14,19): error CS0610: Field or property cannot be of type 'TypedReference'
                //     public static System.TypedReference f8; // 3
                Diagnostic(ErrorCode.ERR_FieldCantBeRefAny, "System.TypedReference").WithArguments("System.TypedReference").WithLocation(14, 19),
                // (15,19): error CS8345: Field or auto-implemented property cannot be of type 'RefLike' unless it is an instance member of a ref struct.
                //     public static RefLike f9; // 4
                Diagnostic(ErrorCode.ERR_FieldAutoPropCantBeByRefLike, "RefLike").WithArguments("RefLike").WithLocation(15, 19)
                );
        }
 
        [Fact]
        public void RecordProperties_01()
        {
            var src = @"
using System;
record struct C(int X, int Y)
{
    int Z = 345;
    public static void Main()
    {
        var c = new C(1, 2);
        Console.Write(c.X);
        Console.Write(c.Y);
        Console.Write(c.Z);
    }
}";
            var verifier = CompileAndVerify(src, expectedOutput: @"12345").VerifyDiagnostics();
 
            verifier.VerifyIL("C..ctor(int, int)", @"
{
  // Code size       26 (0x1a)
  .maxstack  2
  IL_0000:  ldarg.0
  IL_0001:  ldarg.1
  IL_0002:  stfld      ""int C.<X>k__BackingField""
  IL_0007:  ldarg.0
  IL_0008:  ldarg.2
  IL_0009:  stfld      ""int C.<Y>k__BackingField""
  IL_000e:  ldarg.0
  IL_000f:  ldc.i4     0x159
  IL_0014:  stfld      ""int C.Z""
  IL_0019:  ret
}
");
 
            var c = verifier.Compilation.GlobalNamespace.GetTypeMember("C");
            Assert.False(c.IsReadOnly);
            var x = (IPropertySymbol)c.GetMember("X");
            Assert.Equal("readonly System.Int32 C.X.get", x.GetMethod.ToTestDisplayString());
            Assert.Equal("void C.X.set", x.SetMethod.ToTestDisplayString());
            Assert.False(x.SetMethod!.IsInitOnly);
 
            var xBackingField = (IFieldSymbol)c.GetMember("<X>k__BackingField");
            Assert.Equal("System.Int32 C.<X>k__BackingField", xBackingField.ToTestDisplayString());
            Assert.False(xBackingField.IsReadOnly);
        }
 
        [Fact]
        public void RecordProperties_01_EmptyParameterList()
        {
            var src = @"
using System;
record struct C()
{
    int Z = 345;
    public static void Main()
    {
        var c = new C();
        Console.Write(c.Z);
    }
}";
            CreateCompilation(src).VerifyEmitDiagnostics();
        }
 
        [Fact]
        public void RecordProperties_01_Readonly()
        {
            var src = @"
using System;
readonly record struct C(int X, int Y)
{
    readonly int Z = 345;
    public static void Main()
    {
        var c = new C(1, 2);
        Console.Write(c.X);
        Console.Write(c.Y);
        Console.Write(c.Z);
    }
}";
            var verifier = CompileAndVerify(src, expectedOutput: @"12345").VerifyDiagnostics();
 
            var c = verifier.Compilation.GlobalNamespace.GetTypeMember("C");
            Assert.True(c.IsReadOnly);
            var x = (IPropertySymbol)c.GetMember("X");
            Assert.Equal("System.Int32 C.X.get", x.GetMethod.ToTestDisplayString());
            Assert.Equal("void modreq(System.Runtime.CompilerServices.IsExternalInit) C.X.init", x.SetMethod.ToTestDisplayString());
            Assert.True(x.SetMethod!.IsInitOnly);
 
            var xBackingField = (IFieldSymbol)c.GetMember("<X>k__BackingField");
            Assert.Equal("System.Int32 C.<X>k__BackingField", xBackingField.ToTestDisplayString());
            Assert.True(xBackingField.IsReadOnly);
        }
 
        [Fact]
        public void RecordProperties_01_ReadonlyMismatch()
        {
            var src = @"
readonly record struct C(int X)
{
    public int X { get; set; } = X; // 1
}
record struct C2(int X)
{
    public int X { get; init; } = X;
}
";
            var comp = CreateCompilation(src);
            comp.VerifyEmitDiagnostics(
                // (4,16): error CS8341: Auto-implemented instance properties in readonly structs must be readonly.
                //     public int X { get; set; } = X; // 1
                Diagnostic(ErrorCode.ERR_AutoPropsInRoStruct, "X").WithLocation(4, 16)
                );
        }
 
        [Fact]
        public void RecordProperties_02()
        {
            var src = @"
using System;
record struct C(int X, int Y)
{
    public C(int a, int b)
    {
    }
 
    public static void Main()
    {
        var c = new C(1, 2);
        Console.WriteLine(c.X);
        Console.WriteLine(c.Y);
    }
 
    private int X1 = X;
}";
            var comp = CreateCompilation(src);
            comp.VerifyDiagnostics(
                // (5,12): error CS0111: Type 'C' already defines a member called 'C' with the same parameter types
                //     public C(int a, int b)
                Diagnostic(ErrorCode.ERR_MemberAlreadyExists, "C").WithArguments("C", "C").WithLocation(5, 12),
                // (5,12): error CS8862: A constructor declared in a type with parameter list must have 'this' constructor initializer.
                //     public C(int a, int b)
                Diagnostic(ErrorCode.ERR_UnexpectedOrMissingConstructorInitializerInRecord, "C").WithLocation(5, 12),
                // (11,21): error CS0121: The call is ambiguous between the following methods or properties: 'C.C(int, int)' and 'C.C(int, int)'
                //         var c = new C(1, 2);
                Diagnostic(ErrorCode.ERR_AmbigCall, "C").WithArguments("C.C(int, int)", "C.C(int, int)").WithLocation(11, 21)
                );
        }
 
        [Fact]
        public void RecordProperties_03()
        {
            var src = @"
using System;
record struct C(int X, int Y)
{
    public int X { get; }
 
    public static void Main()
    {
        var c = new C(1, 2);
        Console.WriteLine(c.X);
        Console.WriteLine(c.Y);
    }
}";
            var comp = CreateCompilation(new[] { src, IsExternalInitTypeDefinition }, parseOptions: TestOptions.Regular10);
            comp.VerifyEmitDiagnostics(
                // (3,15): error CS0843: Auto-implemented property 'C.X' must be fully assigned before control is returned to the caller. Consider updating to language version '11.0' to auto-default the property.
                // record struct C(int X, int Y)
                Diagnostic(ErrorCode.ERR_UnassignedThisAutoPropertyUnsupportedVersion, "C").WithArguments("C.X", "11.0").WithLocation(3, 15),
                // (3,21): warning CS8907: Parameter 'X' is unread. Did you forget to use it to initialize the property with that name?
                // record struct C(int X, int Y)
                Diagnostic(ErrorCode.WRN_UnreadRecordParameter, "X").WithArguments("X").WithLocation(3, 21)
                );
 
            var verifier = CompileAndVerify(src, parseOptions: TestOptions.Regular11);
            verifier.VerifyDiagnostics(
                // (3,21): warning CS8907: Parameter 'X' is unread. Did you forget to use it to initialize the property with that name?
                // record struct C(int X, int Y)
                Diagnostic(ErrorCode.WRN_UnreadRecordParameter, "X").WithArguments("X").WithLocation(3, 21)
                );
            verifier.VerifyIL("C..ctor(int, int)", @"
{
  // Code size       15 (0xf)
  .maxstack  2
  IL_0000:  ldarg.0
  IL_0001:  ldc.i4.0
  IL_0002:  stfld      ""int C.<X>k__BackingField""
  IL_0007:  ldarg.0
  IL_0008:  ldarg.2
  IL_0009:  stfld      ""int C.<Y>k__BackingField""
  IL_000e:  ret
}
");
        }
 
        [Fact]
        public void RecordProperties_03_InitializedWithY()
        {
            var src = @"
using System;
record struct C(int X, int Y)
{
    public int X { get; } = Y;
 
    public static void Main()
    {
        var c = new C(1, 2);
        Console.Write(c.X);
        Console.Write(c.Y);
    }
}";
            CompileAndVerify(src, expectedOutput: "22")
                .VerifyDiagnostics(
                    // (3,21): warning CS8907: Parameter 'X' is unread. Did you forget to use it to initialize the property with that name?
                    // record struct C(int X, int Y)
                    Diagnostic(ErrorCode.WRN_UnreadRecordParameter, "X").WithArguments("X").WithLocation(3, 21)
                    );
        }
 
        [Fact]
        public void RecordProperties_04()
        {
            var src = @"
using System;
record struct C(int X, int Y)
{
    public int X { get; } = 3;
 
    public static void Main()
    {
        var c = new C(1, 2);
        Console.Write(c.X);
        Console.Write(c.Y);
    }
}";
            CompileAndVerify(src, expectedOutput: "32")
                .VerifyDiagnostics(
                    // (3,21): warning CS8907: Parameter 'X' is unread. Did you forget to use it to initialize the property with that name?
                    // record struct C(int X, int Y)
                    Diagnostic(ErrorCode.WRN_UnreadRecordParameter, "X").WithArguments("X").WithLocation(3, 21)
                    );
        }
 
        [Fact]
        public void RecordProperties_05()
        {
            var src = @"
record struct C(int X, int X)
{
}";
            var comp = CreateCompilation(src);
            comp.VerifyDiagnostics(
                // (2,28): error CS0100: The parameter name 'X' is a duplicate
                // record struct C(int X, int X)
                Diagnostic(ErrorCode.ERR_DuplicateParamName, "X").WithArguments("X").WithLocation(2, 28),
                // (2,28): error CS0102: The type 'C' already contains a definition for 'X'
                // record struct C(int X, int X)
                Diagnostic(ErrorCode.ERR_DuplicateNameInClass, "X").WithArguments("C", "X").WithLocation(2, 28)
                );
 
            var expectedMembers = new[]
            {
                "System.Int32 C.X { get; set; }",
                "System.Int32 C.X { get; set; }"
            };
            AssertEx.Equal(expectedMembers,
                comp.GetMember<NamedTypeSymbol>("C").GetMembers().OfType<PropertySymbol>().ToTestDisplayStrings());
 
            var expectedMemberNames = new[] {
                ".ctor",
                "<X>k__BackingField",
                "get_X",
                "set_X",
                "X",
                "<X>k__BackingField",
                "get_X",
                "set_X",
                "X",
                "ToString",
                "PrintMembers",
                "op_Inequality",
                "op_Equality",
                "GetHashCode",
                "Equals",
                "Equals",
                "Deconstruct",
                ".ctor"
            };
            AssertEx.Equal(expectedMemberNames, comp.GetMember<NamedTypeSymbol>("C").GetPublicSymbol().MemberNames);
        }
 
        [Fact]
        public void RecordProperties_06()
        {
            var src = @"
record struct C(int X, int Y)
{
    public void get_X() { }
    public void set_X() { }
    int get_Y(int value) => value;
    int set_Y(int value) => value;
}";
            var comp = CreateCompilation(src);
            comp.VerifyDiagnostics(
                // (2,21): error CS0082: Type 'C' already reserves a member called 'get_X' with the same parameter types
                // record struct C(int X, int Y)
                Diagnostic(ErrorCode.ERR_MemberReserved, "X").WithArguments("get_X", "C").WithLocation(2, 21),
                // (2,28): error CS0082: Type 'C' already reserves a member called 'set_Y' with the same parameter types
                // record struct C(int X, int Y)
                Diagnostic(ErrorCode.ERR_MemberReserved, "Y").WithArguments("set_Y", "C").WithLocation(2, 28)
                );
 
            var actualMembers = comp.GetMember<NamedTypeSymbol>("C").GetMembers().ToTestDisplayStrings();
            var expectedMembers = new[]
            {
                "C..ctor(System.Int32 X, System.Int32 Y)",
                "System.Int32 C.<X>k__BackingField",
                "readonly System.Int32 C.X.get",
                "void C.X.set",
                "System.Int32 C.X { get; set; }",
                "System.Int32 C.<Y>k__BackingField",
                "readonly System.Int32 C.Y.get",
                "void C.Y.set",
                "System.Int32 C.Y { get; set; }",
                "void C.get_X()",
                "void C.set_X()",
                "System.Int32 C.get_Y(System.Int32 value)",
                "System.Int32 C.set_Y(System.Int32 value)",
                "readonly System.String C.ToString()",
                "readonly System.Boolean C.PrintMembers(System.Text.StringBuilder builder)",
                "System.Boolean C.op_Inequality(C left, C right)",
                "System.Boolean C.op_Equality(C left, C right)",
                "readonly System.Int32 C.GetHashCode()",
                "readonly System.Boolean C.Equals(System.Object obj)",
                "readonly System.Boolean C.Equals(C other)",
                "readonly void C.Deconstruct(out System.Int32 X, out System.Int32 Y)",
                "C..ctor()",
            };
            AssertEx.Equal(expectedMembers, actualMembers);
        }
 
        [Fact]
        public void RecordProperties_07()
        {
            var comp = CreateCompilation(@"
record struct C1(object P, object get_P);
record struct C2(object get_P, object P);");
            comp.VerifyDiagnostics(
                // (2,25): error CS0102: The type 'C1' already contains a definition for 'get_P'
                // record struct C1(object P, object get_P);
                Diagnostic(ErrorCode.ERR_DuplicateNameInClass, "P").WithArguments("C1", "get_P").WithLocation(2, 25),
                // (3,39): error CS0102: The type 'C2' already contains a definition for 'get_P'
                // record struct C2(object get_P, object P);
                Diagnostic(ErrorCode.ERR_DuplicateNameInClass, "P").WithArguments("C2", "get_P").WithLocation(3, 39)
                );
        }
 
        [Fact]
        public void RecordProperties_08()
        {
            var comp = CreateCompilation(@"
record struct C1(object O1)
{
    public object O1 { get; } = O1;
    public object O2 { get; } = O1;
}");
            comp.VerifyDiagnostics();
        }
 
        [Fact]
        public void RecordProperties_09()
        {
            var src = @"
record struct C(object P1, object P2, object P3, object P4)
{
    class P1 { }
    object P2 = 2;
    int P3(object o) => 3;
    int P4<T>(T t) => 4;
}";
            var comp = CreateCompilation(src);
            comp.VerifyDiagnostics(
                // (2,24): error CS0102: The type 'C' already contains a definition for 'P1'
                // record struct C(object P1, object P2, object P3, object P4)
                Diagnostic(ErrorCode.ERR_DuplicateNameInClass, "P1").WithArguments("C", "P1").WithLocation(2, 24),
                // (2,35): warning CS8907: Parameter 'P2' is unread. Did you forget to use it to initialize the property with that name?
                // record struct C(object P1, object P2, object P3, object P4)
                Diagnostic(ErrorCode.WRN_UnreadRecordParameter, "P2").WithArguments("P2").WithLocation(2, 35),
                // (6,9): error CS0102: The type 'C' already contains a definition for 'P3'
                //     int P3(object o) => 3;
                Diagnostic(ErrorCode.ERR_DuplicateNameInClass, "P3").WithArguments("C", "P3").WithLocation(6, 9),
                // (7,9): error CS0102: The type 'C' already contains a definition for 'P4'
                //     int P4<T>(T t) => 4;
                Diagnostic(ErrorCode.ERR_DuplicateNameInClass, "P4").WithArguments("C", "P4").WithLocation(7, 9)
                );
        }
 
        [Fact]
        public void RecordProperties_10()
        {
            var src = @"
record struct C(object P)
{
    const int P = 4;
}";
            var comp = CreateCompilation(src);
            comp.VerifyDiagnostics(
                // (2,24): error CS8866: Record member 'C.P' must be a readable instance property or field of type 'object' to match positional parameter 'P'.
                // record struct C(object P)
                Diagnostic(ErrorCode.ERR_BadRecordMemberForPositionalParameter, "P").WithArguments("C.P", "object", "P").WithLocation(2, 24),
                // (2,24): warning CS8907: Parameter 'P' is unread. Did you forget to use it to initialize the property with that name?
                // record struct C(object P)
                Diagnostic(ErrorCode.WRN_UnreadRecordParameter, "P").WithArguments("P").WithLocation(2, 24)
                );
        }
 
        [Fact]
        public void RecordProperties_11_UnreadPositionalParameter()
        {
            var source = @"
record struct C1(object O1, object O2, object O3) // 1, 2
{
    public object O1 { get; init; }
    public object O2 { get; init; } = M(O2);
    public object O3 { get; init; } = M(O3 = null);
    private static object M(object o) => o;
}
";
            var comp = CreateCompilation(new[] { source, IsExternalInitTypeDefinition }, parseOptions: TestOptions.Regular10);
            comp.VerifyDiagnostics(
                    // (2,15): error CS0843: Auto-implemented property 'C1.O1' must be fully assigned before control is returned to the caller. Consider updating to language version '11.0' to auto-default the property.
                    // record struct C1(object O1, object O2, object O3) // 1, 2
                    Diagnostic(ErrorCode.ERR_UnassignedThisAutoPropertyUnsupportedVersion, "C1").WithArguments("C1.O1", "11.0").WithLocation(2, 15),
                    // (2,25): warning CS8907: Parameter 'O1' is unread. Did you forget to use it to initialize the property with that name?
                    // record struct C1(object O1, object O2, object O3) // 1, 2
                    Diagnostic(ErrorCode.WRN_UnreadRecordParameter, "O1").WithArguments("O1").WithLocation(2, 25),
                    // (2,47): warning CS8907: Parameter 'O3' is unread. Did you forget to use it to initialize the property with that name?
                    // record struct C1(object O1, object O2, object O3) // 1, 2
                    Diagnostic(ErrorCode.WRN_UnreadRecordParameter, "O3").WithArguments("O3").WithLocation(2, 47)
                );
 
            var verifier = CompileAndVerify(new[] { source, IsExternalInitTypeDefinition }, parseOptions: TestOptions.Regular11, verify: Verification.Skipped);
            verifier.VerifyDiagnostics(
                // (2,25): warning CS8907: Parameter 'O1' is unread. Did you forget to use it to initialize the property with that name?
                // record struct C1(object O1, object O2, object O3) // 1, 2
                Diagnostic(ErrorCode.WRN_UnreadRecordParameter, "O1").WithArguments("O1").WithLocation(2, 25),
                // (2,47): warning CS8907: Parameter 'O3' is unread. Did you forget to use it to initialize the property with that name?
                // record struct C1(object O1, object O2, object O3) // 1, 2
                Diagnostic(ErrorCode.WRN_UnreadRecordParameter, "O3").WithArguments("O3").WithLocation(2, 47));
            verifier.VerifyIL("C1..ctor(object, object, object)", @"
{
  // Code size       35 (0x23)
  .maxstack  3
  IL_0000:  ldarg.0
  IL_0001:  ldnull
  IL_0002:  stfld      ""object C1.<O1>k__BackingField""
  IL_0007:  ldarg.0
  IL_0008:  ldarg.2
  IL_0009:  call       ""object C1.M(object)""
  IL_000e:  stfld      ""object C1.<O2>k__BackingField""
  IL_0013:  ldarg.0
  IL_0014:  ldnull
  IL_0015:  dup
  IL_0016:  starg.s    V_3
  IL_0018:  call       ""object C1.M(object)""
  IL_001d:  stfld      ""object C1.<O3>k__BackingField""
  IL_0022:  ret
}
");
        }
 
        [Fact]
        public void RecordProperties_11_UnreadPositionalParameter_InRefOut()
        {
            var comp = CreateCompilation(@"
record struct C1(object O1, object O2, object O3) // 1
{
    public object O1 { get; init; } = MIn(in O1);
    public object O2 { get; init; } = MRef(ref O2);
    public object O3 { get; init; } = MOut(out O3);
 
    static object MIn(in object o) => o;
    static object MRef(ref object o) => o;
    static object MOut(out object o) => throw null;
}
");
            comp.VerifyDiagnostics(
                // (2,47): warning CS8907: Parameter 'O3' is unread. Did you forget to use it to initialize the property with that name?
                // record struct C1(object O1, object O2, object O3) // 1
                Diagnostic(ErrorCode.WRN_UnreadRecordParameter, "O3").WithArguments("O3").WithLocation(2, 47)
                );
        }
 
        [Fact]
        public void RecordProperties_SelfContainedStruct()
        {
            var comp = CreateCompilation(@"
record struct C(C c);
");
            comp.VerifyDiagnostics(
                // (2,19): error CS0523: Struct member 'C.c' of type 'C' causes a cycle in the struct layout
                // record struct C(C c);
                Diagnostic(ErrorCode.ERR_StructLayoutCycle, "c").WithArguments("C.c", "C").WithLocation(2, 19)
                );
        }
 
        [Fact]
        public void RecordProperties_PropertyInValueType()
        {
            var corlib_cs = @"
namespace System
{
    public class Object
    {
        public virtual bool Equals(object x) => throw null;
        public virtual int GetHashCode() => throw null;
        public virtual string ToString() => throw null;
    }
    public class Exception { }
    public class ValueType
    {
        public bool X { get; set; }
    }
    public class Attribute { }
    public class AttributeUsageAttribute : Attribute
    {
        public AttributeUsageAttribute(AttributeTargets t) { }
        public bool AllowMultiple { get; set; }
        public bool Inherited { get; set; }
    }
    public struct Enum { }
    public enum AttributeTargets { }
    public class String { }
    public struct Void { }
    public struct Boolean { }
    public struct Char { }
    public struct Int32 { }
    public interface IEquatable<T> { }
}
namespace System.Collections.Generic
{
    public abstract class EqualityComparer<T>
    {
        public static EqualityComparer<T> Default => throw null;
        public abstract int GetHashCode(T t);
    }
}
namespace System.Text
{
    public class StringBuilder
    {
        public StringBuilder Append(string s) => null;
        public StringBuilder Append(char c) => null;
        public StringBuilder Append(object o) => null;
    }
}
";
            var corlibRef = CreateEmptyCompilation(corlib_cs).EmitToImageReference();
 
            {
                var src = @"
record struct C(bool X)
{
    bool M()
    {
        return X;
    }
}
";
                var comp = CreateEmptyCompilation(src, parseOptions: TestOptions.RegularPreview, references: new[] { corlibRef });
                comp.VerifyEmitDiagnostics(
                    // (2,22): warning CS8907: Parameter 'X' is unread. Did you forget to use it to initialize the property with that name?
                    // record struct C(bool X)
                    Diagnostic(ErrorCode.WRN_UnreadRecordParameter, "X").WithArguments("X").WithLocation(2, 22)
                    );
 
                Assert.Null(comp.GlobalNamespace.GetTypeMember("C").GetMember("X"));
                var tree = comp.SyntaxTrees.Single();
                var model = comp.GetSemanticModel(tree, ignoreAccessibility: false);
                var x = tree.GetRoot().DescendantNodes().OfType<ReturnStatementSyntax>().Single().Expression;
                Assert.Equal("System.Boolean System.ValueType.X { get; set; }", model.GetSymbolInfo(x!).Symbol.ToTestDisplayString());
            }
 
            {
                var src = @"
readonly record struct C(bool X)
{
    bool M()
    {
        return X;
    }
}
";
                var comp = CreateEmptyCompilation(src, parseOptions: TestOptions.RegularPreview, references: new[] { corlibRef });
                comp.VerifyEmitDiagnostics(
                    // (2,31): warning CS8907: Parameter 'X' is unread. Did you forget to use it to initialize the property with that name?
                    // readonly record struct C(bool X)
                    Diagnostic(ErrorCode.WRN_UnreadRecordParameter, "X").WithArguments("X").WithLocation(2, 31)
                    );
 
                Assert.Null(comp.GlobalNamespace.GetTypeMember("C").GetMember("X"));
                var tree = comp.SyntaxTrees.Single();
                var model = comp.GetSemanticModel(tree, ignoreAccessibility: false);
                var x = tree.GetRoot().DescendantNodes().OfType<ReturnStatementSyntax>().Single().Expression;
                Assert.Equal("System.Boolean System.ValueType.X { get; set; }", model.GetSymbolInfo(x!).Symbol.ToTestDisplayString());
            }
        }
 
        [Fact]
        public void RecordProperties_PropertyInValueType_Static()
        {
            var corlib_cs = @"
namespace System
{
    public class Object
    {
        public virtual bool Equals(object x) => throw null;
        public virtual int GetHashCode() => throw null;
        public virtual string ToString() => throw null;
    }
    public class Exception { }
    public class ValueType
    {
        public static bool X { get; set; }
    }
    public class Attribute { }
    public class AttributeUsageAttribute : Attribute
    {
        public AttributeUsageAttribute(AttributeTargets t) { }
        public bool AllowMultiple { get; set; }
        public bool Inherited { get; set; }
    }
    public struct Enum { }
    public enum AttributeTargets { }
    public class String { }
    public struct Void { }
    public struct Boolean { }
    public struct Char { }
    public struct Int32 { }
    public interface IEquatable<T> { }
}
namespace System.Collections.Generic
{
    public abstract class EqualityComparer<T>
    {
        public static EqualityComparer<T> Default => throw null;
        public abstract int GetHashCode(T t);
    }
}
namespace System.Text
{
    public class StringBuilder
    {
        public StringBuilder Append(string s) => null;
        public StringBuilder Append(char c) => null;
        public StringBuilder Append(object o) => null;
    }
}
";
            var corlibRef = CreateEmptyCompilation(corlib_cs).EmitToImageReference();
            var src = @"
record struct C(bool X)
{
    bool M()
    {
        return X;
    }
}
";
            var comp = CreateEmptyCompilation(src, parseOptions: TestOptions.RegularPreview, references: new[] { corlibRef });
            comp.VerifyEmitDiagnostics(
                // (2,22): error CS8866: Record member 'System.ValueType.X' must be a readable instance property or field of type 'bool' to match positional parameter 'X'.
                // record struct C(bool X)
                Diagnostic(ErrorCode.ERR_BadRecordMemberForPositionalParameter, "X").WithArguments("System.ValueType.X", "bool", "X").WithLocation(2, 22),
                // (2,22): warning CS8907: Parameter 'X' is unread. Did you forget to use it to initialize the property with that name?
                // record struct C(bool X)
                Diagnostic(ErrorCode.WRN_UnreadRecordParameter, "X").WithArguments("X").WithLocation(2, 22)
                );
        }
 
        [Fact]
        public void StaticCtor()
        {
            var src = @"
record R(int x)
{
    static void Main() { }
 
    static R()
    {
        System.Console.Write(""static ctor"");
    }
}
";
 
            var comp = CreateCompilation(new[] { src, IsExternalInitTypeDefinition }, parseOptions: TestOptions.RegularPreview, options: TestOptions.DebugExe);
            comp.VerifyEmitDiagnostics();
            CompileAndVerify(comp, expectedOutput: "static ctor", verify: Verification.Skipped /* init-only */);
        }
 
        [Fact]
        public void StaticCtor_ParameterlessPrimaryCtor()
        {
            var src = @"
record struct R(int I)
{
    static R() { }
}
";
 
            var comp = CreateCompilation(src);
            comp.VerifyEmitDiagnostics();
        }
 
        [Fact]
        public void StaticCtor_CopyCtor()
        {
            var src = @"
record struct R(int I)
{
    static R(R r) { }
}
";
 
            var comp = CreateCompilation(src);
            comp.VerifyEmitDiagnostics(
                // (4,12): error CS0132: 'R.R(R)': a static constructor must be parameterless
                //     static R(R r) { }
                Diagnostic(ErrorCode.ERR_StaticConstParam, "R").WithArguments("R.R(R)").WithLocation(4, 12)
                );
        }
 
        [Fact]
        public void InterfaceImplementation_NotReadonly()
        {
            var source = @"
I r = new R(42);
r.P2 = 43;
r.P3 = 44;
System.Console.Write((r.P1, r.P2, r.P3));
 
interface I
{
    int P1 { get; set; }
    int P2 { get; set; }
    int P3 { get; set; }
}
record struct R(int P1) : I
{
    public int P2 { get; set; } = 0;
    int I.P3 { get; set; } = 0;
}
";
            var comp = CreateCompilation(source);
            comp.VerifyEmitDiagnostics();
            CompileAndVerify(comp, expectedOutput: "(42, 43, 44)");
        }
 
        [Fact]
        public void InterfaceImplementation_NotReadonly_InitOnlyInterface()
        {
            var source = @"
interface I
{
    int P1 { get; init; }
}
record struct R(int P1) : I;
";
            var comp = CreateCompilation(source);
            comp.VerifyEmitDiagnostics(
                // (6,27): error CS8854: 'R' does not implement interface member 'I.P1.init'. 'R.P1.set' cannot implement 'I.P1.init'.
                // record struct R(int P1) : I;
                Diagnostic(ErrorCode.ERR_CloseUnimplementedInterfaceMemberWrongInitOnly, "I").WithArguments("R", "I.P1.init", "R.P1.set").WithLocation(6, 27)
                );
        }
 
        [Fact]
        public void InterfaceImplementation_Readonly()
        {
            var source = @"
I r = new R(42) { P2 = 43 };
System.Console.Write((r.P1, r.P2));
 
interface I
{
    int P1 { get; init; }
    int P2 { get; init; }
}
readonly record struct R(int P1) : I
{
    public int P2 { get; init; } = 0;
}
";
            var comp = CreateCompilation(source);
            comp.VerifyEmitDiagnostics();
            CompileAndVerify(comp, expectedOutput: "(42, 43)", verify: Verification.Skipped /* init-only */);
        }
 
        [Fact]
        public void InterfaceImplementation_Readonly_SetInterface()
        {
            var source = @"
interface I
{
    int P1 { get; set; }
}
readonly record struct R(int P1) : I;
";
            var comp = CreateCompilation(source);
            comp.VerifyEmitDiagnostics(
                // (6,36): error CS8854: 'R' does not implement interface member 'I.P1.set'. 'R.P1.init' cannot implement 'I.P1.set'.
                // readonly record struct R(int P1) : I;
                Diagnostic(ErrorCode.ERR_CloseUnimplementedInterfaceMemberWrongInitOnly, "I").WithArguments("R", "I.P1.set", "R.P1.init").WithLocation(6, 36)
                );
        }
 
        [Fact]
        public void InterfaceImplementation_Readonly_PrivateImplementation()
        {
            var source = @"
I r = new R(42) { P2 = 43, P3 = 44 };
System.Console.Write((r.P1, r.P2, r.P3));
 
interface I
{
    int P1 { get; init; }
    int P2 { get; init; }
    int P3 { get; init; }
}
readonly record struct R(int P1) : I
{
    public int P2 { get; init; } = 0;
    int I.P3 { get; init; } = 0; // not practically initializable
}
";
            var comp = CreateCompilation(source);
            comp.VerifyEmitDiagnostics(
                // (2,28): error CS0117: 'R' does not contain a definition for 'P3'
                // I r = new R(42) { P2 = 43, P3 = 44 };
                Diagnostic(ErrorCode.ERR_NoSuchMember, "P3").WithArguments("R", "P3").WithLocation(2, 28)
                );
        }
 
        [Fact]
        public void Initializers_01()
        {
            var src = @"
using System;
 
record struct C(int X)
{
    int Z = X + 1;
 
    public static void Main()
    {
        var c = new C(1);
        Console.WriteLine(c.Z);
    }
}";
            var verifier = CompileAndVerify(src, expectedOutput: @"2").VerifyDiagnostics();
 
            var comp = CreateCompilation(src);
 
            var tree = comp.SyntaxTrees.First();
            var model = comp.GetSemanticModel(tree);
 
            var x = tree.GetRoot().DescendantNodes().OfType<IdentifierNameSyntax>().Where(id => id.Identifier.ValueText == "X").First();
            Assert.Equal("= X + 1", x.Parent!.Parent!.ToString());
 
            var symbol = model.GetSymbolInfo(x).Symbol;
            Assert.Equal(SymbolKind.Parameter, symbol!.Kind);
            Assert.Equal("System.Int32 X", symbol.ToTestDisplayString());
            Assert.Equal("C..ctor(System.Int32 X)", symbol.ContainingSymbol.ToTestDisplayString());
            Assert.Equal("System.Int32 C.Z", model.GetEnclosingSymbol(x.SpanStart).ToTestDisplayString());
            Assert.Contains(symbol, model.LookupSymbols(x.SpanStart, name: "X"));
            Assert.Contains("X", model.LookupNames(x.SpanStart));
 
            var recordDeclaration = tree.GetRoot().DescendantNodes().OfType<RecordDeclarationSyntax>().Single();
            Assert.Equal("C", recordDeclaration.Identifier.ValueText);
            Assert.Null(model.GetOperation(recordDeclaration));
        }
 
        [Fact]
        public void Initializers_02()
        {
            var src = @"
record struct C(int X)
{
    static int Z = X + 1;
}";
 
            var comp = CreateCompilation(src);
            comp.VerifyDiagnostics(
                // (4,20): error CS9105: Cannot use primary constructor parameter 'int X' in this context.
                //     static int Z = X + 1;
                Diagnostic(ErrorCode.ERR_InvalidPrimaryConstructorParameterReference, "X").WithArguments("int X").WithLocation(4, 20)
                );
 
            var tree = comp.SyntaxTrees.First();
            var model = comp.GetSemanticModel(tree);
 
            var x = tree.GetRoot().DescendantNodes().OfType<IdentifierNameSyntax>().Where(id => id.Identifier.ValueText == "X").First();
            Assert.Equal("= X + 1", x.Parent!.Parent!.ToString());
 
            var symbol = model.GetSymbolInfo(x).Symbol;
            Assert.Equal(SymbolKind.Parameter, symbol!.Kind);
            Assert.Equal("System.Int32 X", symbol.ToTestDisplayString());
            Assert.Equal("C..ctor(System.Int32 X)", symbol.ContainingSymbol.ToTestDisplayString());
            Assert.Equal("System.Int32 C.Z", model.GetEnclosingSymbol(x.SpanStart).ToTestDisplayString());
            Assert.Contains(symbol, model.LookupSymbols(x.SpanStart, name: "X"));
            Assert.Contains("X", model.LookupNames(x.SpanStart));
        }
 
        [Fact]
        public void Initializers_03()
        {
            var src = @"
record struct C(int X)
{
    const int Z = X + 1;
}";
 
            var comp = CreateCompilation(src);
            comp.VerifyDiagnostics(
                // (4,19): error CS9105: Cannot use primary constructor parameter 'int X' in this context.
                //     const int Z = X + 1;
                Diagnostic(ErrorCode.ERR_InvalidPrimaryConstructorParameterReference, "X").WithArguments("int X").WithLocation(4, 19),
                // (4,19): error CS0133: The expression being assigned to 'C.Z' must be constant
                //     const int Z = X + 1;
                Diagnostic(ErrorCode.ERR_NotConstantExpression, "X + 1").WithArguments("C.Z").WithLocation(4, 19)
                );
 
            var tree = comp.SyntaxTrees.First();
            var model = comp.GetSemanticModel(tree);
 
            var x = tree.GetRoot().DescendantNodes().OfType<IdentifierNameSyntax>().Where(id => id.Identifier.ValueText == "X").First();
            Assert.Equal("= X + 1", x.Parent!.Parent!.ToString());
 
            var symbol = model.GetSymbolInfo(x).Symbol;
            Assert.Equal(SymbolKind.Parameter, symbol!.Kind);
            Assert.Equal("System.Int32 X", symbol.ToTestDisplayString());
            Assert.Equal("C..ctor(System.Int32 X)", symbol.ContainingSymbol.ToTestDisplayString());
            Assert.Equal("System.Int32 C.Z", model.GetEnclosingSymbol(x.SpanStart).ToTestDisplayString());
            Assert.Contains(symbol, model.LookupSymbols(x.SpanStart, name: "X"));
            Assert.Contains("X", model.LookupNames(x.SpanStart));
        }
 
        [Fact]
        public void Initializers_04()
        {
            var src = @"
using System;
 
record struct C(int X)
{
    Func<int> Z = () => X + 1;
 
    public static void Main()
    {
        var c = new C(1);
        Console.WriteLine(c.Z());
    }
}";
            var verifier = CompileAndVerify(src, expectedOutput: @"2").VerifyDiagnostics();
 
            var comp = CreateCompilation(src);
 
            var tree = comp.SyntaxTrees.First();
            var model = comp.GetSemanticModel(tree);
 
            var x = tree.GetRoot().DescendantNodes().OfType<IdentifierNameSyntax>().Where(id => id.Identifier.ValueText == "X").First();
            Assert.Equal("() => X + 1", x.Parent!.Parent!.ToString());
 
            var symbol = model.GetSymbolInfo(x).Symbol;
            Assert.Equal(SymbolKind.Parameter, symbol!.Kind);
            Assert.Equal("System.Int32 X", symbol.ToTestDisplayString());
            Assert.Equal("C..ctor(System.Int32 X)", symbol.ContainingSymbol.ToTestDisplayString());
            Assert.Equal("lambda expression", model.GetEnclosingSymbol(x.SpanStart).ToTestDisplayString());
            Assert.Contains(symbol, model.LookupSymbols(x.SpanStart, name: "X"));
            Assert.Contains("X", model.LookupNames(x.SpanStart));
        }
 
        [Fact]
        public void SynthesizedRecordPointerProperty()
        {
            var src = @"
record struct R(int P1, int* P2, delegate*<int> P3);";
 
            var comp = CreateCompilation(src);
            var p = comp.GlobalNamespace.GetTypeMember("R").GetMember<SourcePropertySymbolBase>("P1");
            Assert.False(p.HasPointerType);
 
            p = comp.GlobalNamespace.GetTypeMember("R").GetMember<SourcePropertySymbolBase>("P2");
            Assert.True(p.HasPointerType);
 
            p = comp.GlobalNamespace.GetTypeMember("R").GetMember<SourcePropertySymbolBase>("P3");
            Assert.True(p.HasPointerType);
        }
 
        [Fact]
        public void PositionalMemberModifiers_In()
        {
            var src = @"
var r = new R(42);
int i = 43;
var r2 = new R(in i);
System.Console.Write((r.P1, r2.P1));
 
record struct R(in int P1);
";
 
            var comp = CreateCompilation(src);
            comp.VerifyDiagnostics();
            var verifier = CompileAndVerify(comp, expectedOutput: "(42, 43)");
 
            var actualMembers = comp.GetMember<NamedTypeSymbol>("R").Constructors.ToTestDisplayStrings();
            var expectedMembers = new[]
            {
                "R..ctor(in System.Int32 P1)",
                "R..ctor()"
            };
            AssertEx.Equal(expectedMembers, actualMembers);
        }
 
        [Fact]
        public void PositionalMemberModifiers_Params()
        {
            var src = @"
var r = new R(42, 43);
var r2 = new R(new[] { 44, 45 });
System.Console.Write((r.Array[0], r.Array[1], r2.Array[0], r2.Array[1]));
 
record struct R(params int[] Array);
";
 
            var comp = CreateCompilation(src);
            comp.VerifyDiagnostics();
            CompileAndVerify(comp, expectedOutput: "(42, 43, 44, 45)");
 
            var actualMembers = comp.GetMember<NamedTypeSymbol>("R").Constructors.ToTestDisplayStrings();
            var expectedMembers = new[]
            {
                "R..ctor(params System.Int32[] Array)",
                "R..ctor()"
            };
            AssertEx.Equal(expectedMembers, actualMembers);
        }
 
        [Fact]
        public void PositionalMemberDefaultValue()
        {
            var src = @"
var r = new R(); // This uses the parameterless constructor
System.Console.Write(r.P);
 
record struct R(int P = 42);
";
 
            var comp = CreateCompilation(src);
            comp.VerifyDiagnostics();
            CompileAndVerify(comp, expectedOutput: "0");
        }
 
        [Fact]
        public void PositionalMemberDefaultValue_PassingOneArgument()
        {
            var src = @"
var r = new R(41);
System.Console.Write(r.O);
System.Console.Write("" "");
System.Console.Write(r.P);
 
record struct R(int O, int P = 42);
";
 
            var comp = CreateCompilation(src);
            comp.VerifyDiagnostics();
            CompileAndVerify(comp, expectedOutput: "41 42");
        }
 
        [Fact]
        public void PositionalMemberDefaultValue_AndPropertyWithInitializer()
        {
            var src = @"
var r = new R(0);
System.Console.Write(r.P);
 
record struct R(int O, int P = 1)
{
    public int P { get; init; } = 42;
}
";
            var comp = CreateCompilation(src);
            comp.VerifyDiagnostics(
                // (5,28): warning CS8907: Parameter 'P' is unread. Did you forget to use it to initialize the property with that name?
                // record struct R(int O, int P = 1)
                Diagnostic(ErrorCode.WRN_UnreadRecordParameter, "P").WithArguments("P").WithLocation(5, 28)
                );
            var verifier = CompileAndVerify(comp, expectedOutput: "42", verify: Verification.Skipped /* init-only */);
 
            verifier.VerifyIL("R..ctor(int, int)", @"
{
  // Code size       16 (0x10)
  .maxstack  2
  IL_0000:  ldarg.0
  IL_0001:  ldarg.1
  IL_0002:  stfld      ""int R.<O>k__BackingField""
  IL_0007:  ldarg.0
  IL_0008:  ldc.i4.s   42
  IL_000a:  stfld      ""int R.<P>k__BackingField""
  IL_000f:  ret
}");
        }
 
        [Fact]
        public void PositionalMemberDefaultValue_AndPropertyWithoutInitializer()
        {
            var src = @"
record struct R(int P = 42)
{
    public int P { get; init; }
 
    public static void Main()
    {
        var r = new R();
        System.Console.Write(r.P);
    }
}
";
            var comp = CreateCompilation(new[] { src, IsExternalInitTypeDefinition }, parseOptions: TestOptions.Regular10);
            comp.VerifyDiagnostics(
                // (2,15): error CS0843: Auto-implemented property 'R.P' must be fully assigned before control is returned to the caller. Consider updating to language version '11.0' to auto-default the property.
                // record struct R(int P = 42)
                Diagnostic(ErrorCode.ERR_UnassignedThisAutoPropertyUnsupportedVersion, "R").WithArguments("R.P", "11.0").WithLocation(2, 15),
                // (2,21): warning CS8907: Parameter 'P' is unread. Did you forget to use it to initialize the property with that name?
                // record struct R(int P = 42)
                Diagnostic(ErrorCode.WRN_UnreadRecordParameter, "P").WithArguments("P").WithLocation(2, 21)
                );
 
            var verifier = CompileAndVerify(new[] { src, IsExternalInitTypeDefinition }, parseOptions: TestOptions.Regular11, verify: Verification.Skipped);
            verifier.VerifyDiagnostics(
                // (2,21): warning CS8907: Parameter 'P' is unread. Did you forget to use it to initialize the property with that name?
                // record struct R(int P = 42)
                Diagnostic(ErrorCode.WRN_UnreadRecordParameter, "P").WithArguments("P").WithLocation(2, 21)
                );
            verifier.VerifyIL("R..ctor(int)", @"
{
  // Code size        8 (0x8)
  .maxstack  2
  IL_0000:  ldarg.0
  IL_0001:  ldc.i4.0
  IL_0002:  stfld      ""int R.<P>k__BackingField""
  IL_0007:  ret
}
");
        }
 
        [Fact]
        public void PositionalMemberDefaultValue_AndPropertyWithInitializer_CopyingParameter()
        {
            var src = @"
var r = new R(0);
System.Console.Write(r.P);
 
record struct R(int O, int P = 42)
{
    public int P { get; init; } = P;
}
";
            var comp = CreateCompilation(src);
            comp.VerifyDiagnostics();
            var verifier = CompileAndVerify(comp, expectedOutput: "42", verify: Verification.Skipped /* init-only */);
 
            verifier.VerifyIL("R..ctor(int, int)", @"
{
  // Code size       15 (0xf)
  .maxstack  2
  IL_0000:  ldarg.0
  IL_0001:  ldarg.1
  IL_0002:  stfld      ""int R.<O>k__BackingField""
  IL_0007:  ldarg.0
  IL_0008:  ldarg.2
  IL_0009:  stfld      ""int R.<P>k__BackingField""
  IL_000e:  ret
}");
        }
 
        [Fact]
        public void RecordWithConstraints_NullableWarning()
        {
            var src = @"
#nullable enable
var r = new R<string?>(""R"");
var r2 = new R2<string?>(""R2"");
System.Console.Write((r.P, r2.P));
 
record struct R<T>(T P) where T : class;
record struct R2<T>(T P) where T : class { }
";
 
            var comp = CreateCompilation(src);
            comp.VerifyDiagnostics(
                // (3,15): warning CS8634: The type 'string?' cannot be used as type parameter 'T' in the generic type or method 'R<T>'. Nullability of type argument 'string?' doesn't match 'class' constraint.
                // var r = new R<string?>("R");
                Diagnostic(ErrorCode.WRN_NullabilityMismatchInTypeParameterReferenceTypeConstraint, "string?").WithArguments("R<T>", "T", "string?").WithLocation(3, 15),
                // (4,17): warning CS8634: The type 'string?' cannot be used as type parameter 'T' in the generic type or method 'R2<T>'. Nullability of type argument 'string?' doesn't match 'class' constraint.
                // var r2 = new R2<string?>("R2");
                Diagnostic(ErrorCode.WRN_NullabilityMismatchInTypeParameterReferenceTypeConstraint, "string?").WithArguments("R2<T>", "T", "string?").WithLocation(4, 17)
                );
            CompileAndVerify(comp, expectedOutput: "(R, R2)");
        }
 
        [Fact]
        public void RecordWithConstraints_ConstraintError()
        {
            var src = @"
record struct R<T>(T P) where T : class;
record struct R2<T>(T P) where T : class { }
 
public class C
{
    public static void Main()
    {
        _ = new R<int>(1);
        _ = new R2<int>(2);
    }
}";
 
            var comp = CreateCompilation(src);
            comp.VerifyDiagnostics(
                // (9,19): error CS0452: The type 'int' must be a reference type in order to use it as parameter 'T' in the generic type or method 'R<T>'
                //         _ = new R<int>(1);
                Diagnostic(ErrorCode.ERR_RefConstraintNotSatisfied, "int").WithArguments("R<T>", "T", "int").WithLocation(9, 19),
                // (10,20): error CS0452: The type 'int' must be a reference type in order to use it as parameter 'T' in the generic type or method 'R2<T>'
                //         _ = new R2<int>(2);
                Diagnostic(ErrorCode.ERR_RefConstraintNotSatisfied, "int").WithArguments("R2<T>", "T", "int").WithLocation(10, 20)
                );
        }
 
        [Fact]
        public void CyclicBases4()
        {
            var text =
@"
record struct A<T> : B<A<T>> { }
record struct B<T> : A<B<T>>
{
    A<T> F() { return null; }
}
";
            var comp = CreateCompilation(text);
            comp.GetDeclarationDiagnostics().Verify(
                // (3,22): error CS0527: Type 'A<B<T>>' in interface list is not an interface
                // record struct B<T> : A<B<T>>
                Diagnostic(ErrorCode.ERR_NonInterfaceInInterfaceList, "A<B<T>>").WithArguments("A<B<T>>").WithLocation(3, 22),
                // (2,22): error CS0527: Type 'B<A<T>>' in interface list is not an interface
                // record struct A<T> : B<A<T>> { }
                Diagnostic(ErrorCode.ERR_NonInterfaceInInterfaceList, "B<A<T>>").WithArguments("B<A<T>>").WithLocation(2, 22)
                );
        }
 
        [Fact]
        public void PartialClassWithDifferentTupleNamesInImplementedInterfaces()
        {
            var source = @"
public interface I<T> { }
public partial record C1 : I<(int a, int b)> { }
public partial record C1 : I<(int notA, int notB)> { }
 
public partial record C2 : I<(int a, int b)> { }
public partial record C2 : I<(int, int)> { }
 
public partial record C3 : I<(int a, int b)> { }
public partial record C3 : I<(int a, int b)> { }
 
public partial record C4 : I<(int a, int b)> { }
public partial record C4 : I<(int b, int a)> { }
";
            var comp = CreateCompilation(source);
            comp.VerifyDiagnostics(
                // (3,23): error CS8140: 'I<(int notA, int notB)>' is already listed in the interface list on type 'C1' with different tuple element names, as 'I<(int a, int b)>'.
                // public partial record C1 : I<(int a, int b)> { }
                Diagnostic(ErrorCode.ERR_DuplicateInterfaceWithTupleNamesInBaseList, "C1").WithArguments("I<(int notA, int notB)>", "I<(int a, int b)>", "C1").WithLocation(3, 23),
                // (6,23): error CS8140: 'I<(int, int)>' is already listed in the interface list on type 'C2' with different tuple element names, as 'I<(int a, int b)>'.
                // public partial record C2 : I<(int a, int b)> { }
                Diagnostic(ErrorCode.ERR_DuplicateInterfaceWithTupleNamesInBaseList, "C2").WithArguments("I<(int, int)>", "I<(int a, int b)>", "C2").WithLocation(6, 23),
                // (12,23): error CS8140: 'I<(int b, int a)>' is already listed in the interface list on type 'C4' with different tuple element names, as 'I<(int a, int b)>'.
                // public partial record C4 : I<(int a, int b)> { }
                Diagnostic(ErrorCode.ERR_DuplicateInterfaceWithTupleNamesInBaseList, "C4").WithArguments("I<(int b, int a)>", "I<(int a, int b)>", "C4").WithLocation(12, 23)
                );
        }
 
        [Fact]
        public void CS0267ERR_PartialMisplaced()
        {
            var test = @"
partial public record struct C  // CS0267
{
}
";
 
            CreateCompilation(test).VerifyDiagnostics(
                // (2,1): error CS0267: The 'partial' modifier can only appear immediately before 'class', 'record', 'struct', 'interface', or a method return type.
                // partial public record struct C  // CS0267
                Diagnostic(ErrorCode.ERR_PartialMisplaced, "partial").WithLocation(2, 1)
                );
        }
 
        [Fact]
        public void SealedStaticRecord()
        {
            var source = @"
sealed static record struct R;
";
            CreateCompilation(source).VerifyDiagnostics(
                // (2,29): error CS0106: The modifier 'sealed' is not valid for this item
                // sealed static record struct R;
                Diagnostic(ErrorCode.ERR_BadMemberFlag, "R").WithArguments("sealed").WithLocation(2, 29),
                // (2,29): error CS0106: The modifier 'static' is not valid for this item
                // sealed static record struct R;
                Diagnostic(ErrorCode.ERR_BadMemberFlag, "R").WithArguments("static").WithLocation(2, 29)
                );
        }
 
        [Fact]
        public void CS0513ERR_AbstractInConcreteClass02()
        {
            var text = @"
record struct C
{
    public abstract event System.Action E;
    public abstract int this[int x] { get; set; }
}
";
            CreateCompilation(text).VerifyDiagnostics(
                // (5,25): error CS0106: The modifier 'abstract' is not valid for this item
                //     public abstract int this[int x] { get; set; }
                Diagnostic(ErrorCode.ERR_BadMemberFlag, "this").WithArguments("abstract").WithLocation(5, 25),
                // (4,41): error CS0106: The modifier 'abstract' is not valid for this item
                //     public abstract event System.Action E;
                Diagnostic(ErrorCode.ERR_BadMemberFlag, "E").WithArguments("abstract").WithLocation(4, 41)
                );
        }
 
        [Fact]
        public void CS0574ERR_BadDestructorName()
        {
            var test = @"
public record struct @iii
{
    ~iiii(){}
}
";
 
            CreateCompilation(test).VerifyDiagnostics(
                // (4,6): error CS0574: Name of destructor must match name of type
                //     ~iiii(){}
                Diagnostic(ErrorCode.ERR_BadDestructorName, "iiii").WithLocation(4, 6),
                // (4,6): error CS0575: Only class types can contain destructors
                //     ~iiii(){}
                Diagnostic(ErrorCode.ERR_OnlyClassesCanContainDestructors, "iiii").WithLocation(4, 6)
                );
        }
 
        [Fact]
        public void StaticRecordWithConstructorAndDestructor()
        {
            var text = @"
static record struct R(int I)
{
    public R() : this(0) { }
    ~R() { }
}
";
            var comp = CreateCompilation(text);
            comp.VerifyDiagnostics(
                // (2,22): error CS0106: The modifier 'static' is not valid for this item
                // static record struct R(int I)
                Diagnostic(ErrorCode.ERR_BadMemberFlag, "R").WithArguments("static").WithLocation(2, 22),
                // (5,6): error CS0575: Only class types can contain destructors
                //     ~R() { }
                Diagnostic(ErrorCode.ERR_OnlyClassesCanContainDestructors, "R").WithLocation(5, 6)
                );
        }
 
        [Fact]
        public void RecordWithPartialMethodExplicitImplementation()
        {
            var source =
@"record struct R
{
    partial void M();
}";
            CreateCompilation(source).VerifyDiagnostics(
                // (3,18): error CS0751: A partial member must be declared within a partial type
                //     partial void M();
                Diagnostic(ErrorCode.ERR_PartialMemberOnlyInPartialClass, "M").WithLocation(3, 18)
                );
        }
 
        [Fact]
        public void RecordWithPartialMethodRequiringBody()
        {
            var source =
@"partial record struct R
{
    public partial int M();
}";
            CreateCompilation(source).VerifyDiagnostics(
                // (3,24): error CS8795: Partial method 'R.M()' must have an implementation part because it has accessibility modifiers.
                //     public partial int M();
                Diagnostic(ErrorCode.ERR_PartialMethodWithAccessibilityModsMustHaveImplementation, "M").WithArguments("R.M()").WithLocation(3, 24)
                );
        }
 
        [Fact]
        public void CanDeclareIteratorInRecord()
        {
            var source = @"
using System.Collections.Generic;
 
foreach(var i in new X(42).GetItems())
{
    System.Console.Write(i);
}
 
public record struct X(int a)
{
    public IEnumerable<int> GetItems() { yield return a; yield return a + 1; }
}";
 
            var comp = CreateCompilation(source).VerifyDiagnostics();
 
            CompileAndVerify(comp, expectedOutput: "4243");
        }
 
        [Fact]
        public void ParameterlessConstructor()
        {
            var src = @"
System.Console.Write(new C().Property);
 
record struct C()
{
    public int Property { get; set; } = 42;
}";
            var comp = CreateCompilation(src);
            comp.VerifyDiagnostics();
            CompileAndVerify(comp, expectedOutput: "42");
        }
 
        [Fact]
        public void XmlDoc()
        {
            var src = @"
/// <summary>Summary</summary>
/// <param name=""I1"">Description for I1</param>
public record struct C(int I1);
 
namespace System.Runtime.CompilerServices
{
    /// <summary>Ignored</summary>
    public static class IsExternalInit
    {
    }
}
";
 
            var comp = CreateCompilation(src, parseOptions: TestOptions.RegularWithDocumentationComments);
            comp.VerifyDiagnostics();
 
            var cMember = comp.GetMember<NamedTypeSymbol>("C");
            Assert.Equal(
@"<member name=""T:C"">
    <summary>Summary</summary>
    <param name=""I1"">Description for I1</param>
</member>
", cMember.GetDocumentationCommentXml());
            var constructor = cMember.GetMembers(".ctor").OfType<SynthesizedPrimaryConstructor>().Single();
            Assert.Equal(
@"<member name=""M:C.#ctor(System.Int32)"">
    <summary>Summary</summary>
    <param name=""I1"">Description for I1</param>
</member>
", constructor.GetDocumentationCommentXml());
 
            Assert.Equal("", constructor.GetParameters()[0].GetDocumentationCommentXml());
 
            var property = cMember.GetMembers("I1").Single();
            AssertEx.Equal(
@"<member name=""P:C.I1"">
    <summary>Description for I1</summary>
</member>
", property.GetDocumentationCommentXml());
        }
 
        [Theory, CombinatorialData, WorkItem("https://devdiv.visualstudio.com/DevDiv/_workitems/edit/1931501")]
        public void XmlDoc_InsideType(
            [CombinatorialValues("x", "p")] string identifier,
            [CombinatorialValues("param", "paramref")] string tag)
        {
            var source = $$"""
                record struct C(int p)
                {
                    /// <{{tag}} name="{{identifier}}"></{{tag}}>
                }
                """;
            var comp = CreateCompilation(source, parseOptions: TestOptions.RegularPreview.WithDocumentationMode(DocumentationMode.Diagnose));
            comp.VerifyDiagnostics(
                // (3,5): warning CS1587: XML comment is not placed on a valid language element
                //     /// <param name="x"></param>
                Diagnostic(ErrorCode.WRN_UnprocessedXMLComment, "/").WithLocation(3, 5));
 
            var tree = comp.SyntaxTrees.Single();
            var doc = tree.GetRoot().DescendantTrivia().Select(trivia => trivia.GetStructure()).OfType<DocumentationCommentTriviaSyntax>().Single();
            var x = doc.DescendantNodes().OfType<IdentifierNameSyntax>().Single();
            Assert.Equal(identifier, x.Identifier.ValueText);
 
            var model = comp.GetSemanticModel(tree);
            var symbolInfo = model.GetSymbolInfo(x);
            Assert.Null(symbolInfo.Symbol);
            Assert.True(symbolInfo.IsEmpty);
            Assert.Equal(CandidateReason.None, symbolInfo.CandidateReason);
            Assert.Empty(symbolInfo.CandidateSymbols);
        }
 
        [Fact]
        public void XmlDoc_Cref()
        {
            var src = @"
/// <summary>Summary</summary>
/// <param name=""I1"">Description for <see cref=""I1""/></param>
public record struct C(int I1)
{
    /// <summary>Summary</summary>
    /// <param name=""x"">Description for <see cref=""x""/></param>
    public void M(int x) { }
}
 
namespace System.Runtime.CompilerServices
{
    /// <summary>Ignored</summary>
    public static class IsExternalInit
    {
    }
}
";
 
            var comp = CreateCompilation(src, parseOptions: TestOptions.RegularWithDocumentationComments);
            comp.VerifyDiagnostics(
                // (7,52): warning CS1574: XML comment has cref attribute 'x' that could not be resolved
                //     /// <param name="x">Description for <see cref="x"/></param>
                Diagnostic(ErrorCode.WRN_BadXMLRef, "x").WithArguments("x").WithLocation(7, 52)
                );
 
            var tree = comp.SyntaxTrees.Single();
            var docComments = tree.GetCompilationUnitRoot().DescendantTrivia().Select(trivia => trivia.GetStructure()).OfType<DocumentationCommentTriviaSyntax>();
            var cref = docComments.First().DescendantNodes().OfType<XmlCrefAttributeSyntax>().First().Cref;
            Assert.Equal("I1", cref.ToString());
 
            var model = comp.GetSemanticModel(tree, ignoreAccessibility: false);
            Assert.Equal(SymbolKind.Property, model.GetSymbolInfo(cref).Symbol!.Kind);
 
            var property = comp.GetMember("C.I1");
            AssertEx.Equal(
@"<member name=""P:C.I1"">
    <summary>Description for <see cref=""P:C.I1""/></summary>
</member>
", property.GetDocumentationCommentXml());
        }
 
        [Fact]
        public void XmlDoc_Cref_OtherMember()
        {
            var src = @"
/// <summary>Summary</summary>
/// <param name=""I1"">Description for <see cref=""I2""/></param>
public record struct C(int I1, int I2)
{
    /// <summary>Summary</summary>
    /// <param name=""x"">Description for <see cref=""x""/></param>
    public void M(int x) { }
}
 
namespace System.Runtime.CompilerServices
{
    /// <summary>Ignored</summary>
    public static class IsExternalInit
    {
    }
}
";
 
            var comp = CreateCompilation(src, parseOptions: TestOptions.RegularWithDocumentationComments);
            comp.VerifyDiagnostics(
                // (4,36): warning CS1573: Parameter 'I2' has no matching param tag in the XML comment for 'C.C(int, int)' (but other parameters do)
                // public record struct C(int I1, int I2)
                Diagnostic(ErrorCode.WRN_MissingParamTag, "I2").WithArguments("I2", "C.C(int, int)").WithLocation(4, 36),
                // (7,52): warning CS1574: XML comment has cref attribute 'x' that could not be resolved
                //     /// <param name="x">Description for <see cref="x"/></param>
                Diagnostic(ErrorCode.WRN_BadXMLRef, "x").WithArguments("x").WithLocation(7, 52)
                );
 
            var tree = comp.SyntaxTrees.Single();
            var docComments = tree.GetCompilationUnitRoot().DescendantTrivia().Select(trivia => trivia.GetStructure()).OfType<DocumentationCommentTriviaSyntax>();
            var cref = docComments.First().DescendantNodes().OfType<XmlCrefAttributeSyntax>().First().Cref;
            Assert.Equal("I2", cref.ToString());
 
            var model = comp.GetSemanticModel(tree, ignoreAccessibility: false);
            Assert.Equal(SymbolKind.Property, model.GetSymbolInfo(cref).Symbol!.Kind);
 
            var property = comp.GetMember("C.I1");
            AssertEx.Equal(
@"<member name=""P:C.I1"">
    <summary>Description for <see cref=""P:C.I2""/></summary>
</member>
", property.GetDocumentationCommentXml());
        }
 
        [Fact]
        public void XmlDoc_SeeAlso_InsideParamTag()
        {
            var src = @"
/// <summary>Summary</summary>
/// <param name=""I1"">Description for <seealso cref=""I2""/>something like I2</seealso></param>
public record struct C(int I1, int I2)
{
    /// <summary>Summary</summary>
    /// <param name=""x"">Description for <see cref=""x""/></param>
    public void M(int x) { }
}
 
namespace System.Runtime.CompilerServices
{
    /// <summary>Ignored</summary>
    public static class IsExternalInit
    {
    }
}
";
 
            var comp = CreateCompilation(src, parseOptions: TestOptions.RegularWithDocumentationComments);
            comp.VerifyDiagnostics(
                // (3,77): warning CS1570: XML comment has badly formed XML -- 'End tag 'seealso' does not match the start tag 'param'.'
                // /// <param name="I1">Description for <seealso cref="I2"/>something like I2</seealso></param>
                Diagnostic(ErrorCode.WRN_XMLParseError, "seealso").WithArguments("seealso", "param").WithLocation(3, 77),
                // (3,85): warning CS1570: XML comment has badly formed XML -- 'End tag was not expected at this location.'
                // /// <param name="I1">Description for <seealso cref="I2"/>something like I2</seealso></param>
                Diagnostic(ErrorCode.WRN_XMLParseError, "<").WithLocation(3, 85),
                // (7,52): warning CS1574: XML comment has cref attribute 'x' that could not be resolved
                //     /// <param name="x">Description for <see cref="x"/></param>
                Diagnostic(ErrorCode.WRN_BadXMLRef, "x").WithArguments("x").WithLocation(7, 52)
                );
 
            var tree = comp.SyntaxTrees.Single();
            var docComments = tree.GetCompilationUnitRoot().DescendantTrivia().Select(trivia => trivia.GetStructure()).OfType<DocumentationCommentTriviaSyntax>();
            var cref = docComments.First().DescendantNodes().OfType<XmlCrefAttributeSyntax>().First().Cref;
            Assert.Equal("I2", cref.ToString());
 
            var model = comp.GetSemanticModel(tree, ignoreAccessibility: false);
            Assert.Equal(SymbolKind.Property, model.GetSymbolInfo(cref).Symbol!.Kind);
 
            var property = comp.GetMember("C.I1");
            AssertEx.Equal(
@"<!-- Badly formed XML comment ignored for member ""P:C.I1"" -->
", property.GetDocumentationCommentXml());
        }
 
        [Fact]
        public void Deconstruct_Simple()
        {
            var source =
@"using System;
 
record struct B(int X, int Y)
{
    public static void Main()
    {
        M(new B(1, 2));
    }
 
    static void M(B b)
    {
        switch (b)
        {
            case B(int x, int y):
                Console.Write(x);
                Console.Write(y);
                break;
        }
    }
}";
            var verifier = CompileAndVerify(source, expectedOutput: "12");
            verifier.VerifyDiagnostics();
 
            verifier.VerifyIL("B.Deconstruct", @"
{
  // Code size       17 (0x11)
  .maxstack  2
  IL_0000:  ldarg.1
  IL_0001:  ldarg.0
  IL_0002:  call       ""readonly int B.X.get""
  IL_0007:  stind.i4
  IL_0008:  ldarg.2
  IL_0009:  ldarg.0
  IL_000a:  call       ""readonly int B.Y.get""
  IL_000f:  stind.i4
  IL_0010:  ret
}");
 
            var deconstruct = ((CSharpCompilation)verifier.Compilation).GetMember<MethodSymbol>("B.Deconstruct");
            Assert.Equal(2, deconstruct.ParameterCount);
 
            Assert.Equal(RefKind.Out, deconstruct.Parameters[0].RefKind);
            Assert.Equal("X", deconstruct.Parameters[0].Name);
 
            Assert.Equal(RefKind.Out, deconstruct.Parameters[1].RefKind);
            Assert.Equal("Y", deconstruct.Parameters[1].Name);
 
            Assert.True(deconstruct.ReturnsVoid);
            Assert.False(deconstruct.IsVirtual);
            Assert.False(deconstruct.IsStatic);
            Assert.Equal(Accessibility.Public, deconstruct.DeclaredAccessibility);
        }
 
        [Fact]
        public void Deconstruct_PositionalAndNominalProperty()
        {
            var source =
@"using System;
 
record struct B(int X)
{
    public int Y { get; init; } = 0;
 
    public static void Main()
    {
        M(new B(1));
    }
 
    static void M(B b)
    {
        switch (b)
        {
            case B(int x):
                Console.Write(x);
                break;
        }
    }
}";
            var verifier = CompileAndVerify(source, expectedOutput: "1");
            verifier.VerifyDiagnostics();
 
            Assert.Equal(
                "readonly void B.Deconstruct(out System.Int32 X)",
                verifier.Compilation.GetMember("B.Deconstruct").ToTestDisplayString(includeNonNullable: false));
        }
 
        [Fact]
        public void Deconstruct_Nested()
        {
            var source =
@"using System;
 
record struct B(int X, int Y);
 
record struct C(B B, int Z)
{
    public static void Main()
    {
        M(new C(new B(1, 2), 3));
    }
 
    static void M(C c)
    {
        switch (c)
        {
            case C(B(int x, int y), int z):
                Console.Write(x);
                Console.Write(y);
                Console.Write(z);
                break;
        }
    }
}
";
 
            var verifier = CompileAndVerify(source, expectedOutput: "123");
            verifier.VerifyDiagnostics();
 
            verifier.VerifyIL("B.Deconstruct", @"
{
  // Code size       17 (0x11)
  .maxstack  2
  IL_0000:  ldarg.1
  IL_0001:  ldarg.0
  IL_0002:  call       ""readonly int B.X.get""
  IL_0007:  stind.i4
  IL_0008:  ldarg.2
  IL_0009:  ldarg.0
  IL_000a:  call       ""readonly int B.Y.get""
  IL_000f:  stind.i4
  IL_0010:  ret
}");
 
            verifier.VerifyIL("C.Deconstruct", @"
{
  // Code size       21 (0x15)
  .maxstack  2
  IL_0000:  ldarg.1
  IL_0001:  ldarg.0
  IL_0002:  call       ""readonly B C.B.get""
  IL_0007:  stobj      ""B""
  IL_000c:  ldarg.2
  IL_000d:  ldarg.0
  IL_000e:  call       ""readonly int C.Z.get""
  IL_0013:  stind.i4
  IL_0014:  ret
}");
        }
 
        [Fact]
        public void Deconstruct_PropertyCollision()
        {
            var source =
@"using System;
 
record struct B(int X, int Y)
{
    public int X => 3;
 
    static void M(B b)
    {
        switch (b)
        {
            case B(int x, int y):
                Console.Write(x);
                Console.Write(y);
                break;
        }
    }
 
    static void Main()
    {
        M(new B(1, 2));
    }
}
";
            var verifier = CompileAndVerify(source, expectedOutput: "32");
            verifier.VerifyDiagnostics(
                // (3,21): warning CS8907: Parameter 'X' is unread. Did you forget to use it to initialize the property with that name?
                // record struct B(int X, int Y)
                Diagnostic(ErrorCode.WRN_UnreadRecordParameter, "X").WithArguments("X").WithLocation(3, 21)
                );
 
            Assert.Equal(
                "void B.Deconstruct(out System.Int32 X, out System.Int32 Y)",
                verifier.Compilation.GetMember("B.Deconstruct").ToTestDisplayString(includeNonNullable: false));
        }
 
        [Fact]
        public void Deconstruct_MethodCollision_01()
        {
            var source = @"
record struct B(int X, int Y)
{
    public int X() => 3;
 
    static void M(B b)
    {
        switch (b)
        {
            case B(int x, int y):
                break;
        }
    }
 
    static void Main()
    {
        M(new B(1, 2));
    }
}
";
            var comp = CreateCompilation(source);
            comp.VerifyDiagnostics(
                // (4,16): error CS0102: The type 'B' already contains a definition for 'X'
                //     public int X() => 3;
                Diagnostic(ErrorCode.ERR_DuplicateNameInClass, "X").WithArguments("B", "X").WithLocation(4, 16)
                );
 
            Assert.Equal(
                "readonly void B.Deconstruct(out System.Int32 X, out System.Int32 Y)",
                comp.GetMember("B.Deconstruct").ToTestDisplayString(includeNonNullable: false));
        }
 
        [Fact]
        public void Deconstruct_FieldCollision()
        {
            var source = @"
using System;
 
record struct C(int X)
{
    int X = 0;
 
    static void M(C c)
    {
        switch (c)
        {
            case C(int x):
                Console.Write(x);
                break;
        }
    }
 
    static void Main()
    {
        M(new C(0));
    }
}
";
            var comp = CreateCompilation(source);
            comp.VerifyDiagnostics(
                // (4,21): warning CS8907: Parameter 'X' is unread. Did you forget to use it to initialize the property with that name?
                // record struct C(int X)
                Diagnostic(ErrorCode.WRN_UnreadRecordParameter, "X").WithArguments("X").WithLocation(4, 21),
                // (6,9): warning CS0414: The field 'C.X' is assigned but its value is never used
                //     int X = 0;
                Diagnostic(ErrorCode.WRN_UnreferencedFieldAssg, "X").WithArguments("C.X").WithLocation(6, 9));
 
            Assert.Equal(
                "readonly void C.Deconstruct(out System.Int32 X)",
                comp.GetMember("C.Deconstruct").ToTestDisplayString(includeNonNullable: false));
        }
 
        [Fact]
        public void Deconstruct_Empty()
        {
            var source = @"
record struct C
{
    static void M(C c)
    {
        switch (c)
        {
            case C():
                break;
        }
    }
 
    static void Main()
    {
        M(new C());
    }
}
";
            var comp = CreateCompilation(source);
            comp.VerifyDiagnostics(
                // (8,19): error CS1061: 'C' does not contain a definition for 'Deconstruct' and no accessible extension method 'Deconstruct' accepting a first argument of type 'C' could be found (are you missing a using directive or an assembly reference?)
                //             case C():
                Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "()").WithArguments("C", "Deconstruct").WithLocation(8, 19),
                // (8,19): error CS8129: No suitable 'Deconstruct' instance or extension method was found for type 'C', with 0 out parameters and a void return type.
                //             case C():
                Diagnostic(ErrorCode.ERR_MissingDeconstruct, "()").WithArguments("C", "0").WithLocation(8, 19));
 
            Assert.Null(comp.GetMember("C.Deconstruct"));
        }
 
        [Fact]
        public void Deconstruct_Conversion_02()
        {
            var source = @"
#nullable enable
using System;
 
record struct C(string? X, string Y)
{
    public string X { get; init; } = null!;
    public string? Y { get; init; } = string.Empty;
 
    static void M(C c)
    {
        switch (c)
        {
            case C(var x, string y):
                Console.Write(x);
                Console.Write(y);
                break;
        }
    }
 
    static void Main()
    {
        M(new C(""a"", ""b""));
    }
}
";
            var comp = CreateCompilation(source);
            comp.VerifyDiagnostics(
                // (5,25): warning CS8907: Parameter 'X' is unread. Did you forget to use it to initialize the property with that name?
                // record struct C(string? X, string Y)
                Diagnostic(ErrorCode.WRN_UnreadRecordParameter, "X").WithArguments("X").WithLocation(5, 25),
                // (5,35): warning CS8907: Parameter 'Y' is unread. Did you forget to use it to initialize the property with that name?
                // record struct C(string? X, string Y)
                Diagnostic(ErrorCode.WRN_UnreadRecordParameter, "Y").WithArguments("Y").WithLocation(5, 35)
                );
 
            Assert.Equal(
                "readonly void C.Deconstruct(out System.String? X, out System.String Y)",
                comp.GetMember("C.Deconstruct").ToTestDisplayString(includeNonNullable: false));
        }
 
        [Fact]
        public void Deconstruct_Empty_WithParameterList()
        {
            var source = @"
record struct C()
{
    static void M(C c)
    {
        switch (c)
        {
            case C():
                break;
        }
    }
 
    static void Main()
    {
        M(new C());
    }
}
";
            var comp = CreateCompilation(source);
            comp.VerifyDiagnostics(
                // (8,19): error CS1061: 'C' does not contain a definition for 'Deconstruct' and no accessible extension method 'Deconstruct' accepting a first argument of type 'C' could be found (are you missing a using directive or an assembly reference?)
                //             case C():
                Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "()").WithArguments("C", "Deconstruct").WithLocation(8, 19),
                // (8,19): error CS8129: No suitable 'Deconstruct' instance or extension method was found for type 'C', with 0 out parameters and a void return type.
                //             case C():
                Diagnostic(ErrorCode.ERR_MissingDeconstruct, "()").WithArguments("C", "0").WithLocation(8, 19));
 
            AssertEx.Equal(new[] {
                "C..ctor()",
                "void C.M(C c)",
                "void C.Main()",
                "readonly System.String C.ToString()",
                "readonly System.Boolean C.PrintMembers(System.Text.StringBuilder builder)",
                "System.Boolean C.op_Inequality(C left, C right)",
                "System.Boolean C.op_Equality(C left, C right)",
                "readonly System.Int32 C.GetHashCode()",
                "readonly System.Boolean C.Equals(System.Object obj)",
                "readonly System.Boolean C.Equals(C other)" },
                comp.GetMember<NamedTypeSymbol>("C").GetMembers().ToTestDisplayStrings());
        }
 
        [Fact]
        public void Deconstruct_Empty_WithParameterList_UserDefined_01()
        {
            var source =
@"using System;
 
record struct C(int I)
{
    public void Deconstruct()
    {
    }
 
    static void M(C c)
    {
        switch (c)
        {
            case C():
                Console.Write(12);
                break;
        }
    }
 
    public static void Main()
    {
        M(new C(42));
    }
}
";
            var verifier = CompileAndVerify(source, expectedOutput: "12");
            verifier.VerifyDiagnostics();
        }
 
        [Fact]
        public void Deconstruct_GeneratedAsReadOnly()
        {
            var src = @"
record struct A(int I, string S);
";
            var comp = CreateCompilation(src);
            comp.VerifyDiagnostics();
            var method = comp.GetMember<SynthesizedRecordDeconstruct>("A.Deconstruct");
            Assert.True(method.IsDeclaredReadOnly);
        }
 
        [Fact]
        public void Deconstruct_WithNonReadOnlyGetter_GeneratedAsNonReadOnly()
        {
            var src = @"
record struct A(int I, string S)
{
    public int I { get => 0; }
}
";
            var comp = CreateCompilation(src);
            comp.VerifyDiagnostics(
                // (2,21): warning CS8907: Parameter 'I' is unread. Did you forget to use it to initialize the property with that name?
                // record struct A(int I, string S)
                Diagnostic(ErrorCode.WRN_UnreadRecordParameter, "I").WithArguments("I").WithLocation(2, 21));
            var method = comp.GetMember<SynthesizedRecordDeconstruct>("A.Deconstruct");
            Assert.False(method.IsDeclaredReadOnly);
        }
 
        [Fact]
        public void Deconstruct_UserDefined()
        {
            var source =
@"using System;
 
record struct B(int X, int Y)
{
    public void Deconstruct(out int X, out int Y)
    {
        X = this.X + 1;
        Y = this.Y + 2;
    }
 
    static void M(B b)
    {
        switch (b)
        {
            case B(int x, int y):
                Console.Write(x);
                Console.Write(y);
                break;
        }
    }
 
    public static void Main()
    {
        M(new B(0, 0));
    }
}
";
            var verifier = CompileAndVerify(source, expectedOutput: "12");
            verifier.VerifyDiagnostics();
        }
 
        [Fact]
        public void Deconstruct_UserDefined_DifferentSignature_02()
        {
            var source =
@"using System;
 
record struct B(int X)
{
    public int Deconstruct(out int a) => throw null;
 
    static void M(B b)
    {
        switch (b)
        {
            case B(int x):
                Console.Write(x);
                break;
        }
    }
 
    public static void Main()
    {
        M(new B(1));
    }
}
";
            var comp = CreateCompilation(source);
            comp.VerifyDiagnostics(
                // (5,16): error CS8874: Record member 'B.Deconstruct(out int)' must return 'void'.
                //     public int Deconstruct(out int a) => throw null;
                Diagnostic(ErrorCode.ERR_SignatureMismatchInRecord, "Deconstruct").WithArguments("B.Deconstruct(out int)", "void").WithLocation(5, 16),
                // (11,19): error CS8129: No suitable 'Deconstruct' instance or extension method was found for type 'B', with 1 out parameters and a void return type.
                //             case B(int x):
                Diagnostic(ErrorCode.ERR_MissingDeconstruct, "(int x)").WithArguments("B", "1").WithLocation(11, 19));
 
            Assert.Equal("System.Int32 B.Deconstruct(out System.Int32 a)", comp.GetMember("B.Deconstruct").ToTestDisplayString(includeNonNullable: false));
        }
 
        [Theory]
        [InlineData("")]
        [InlineData("private")]
        [InlineData("internal")]
        public void Deconstruct_UserDefined_Accessibility_07(string accessibility)
        {
            var source =
$@"
record struct A(int X)
{{
    {accessibility} void Deconstruct(out int a)
        => throw null;
}}
";
            var comp = CreateCompilation(source);
            comp.VerifyEmitDiagnostics(
                // (4,11): error CS8873: Record member 'A.Deconstruct(out int)' must be public.
                //      void Deconstruct(out int a)
                Diagnostic(ErrorCode.ERR_NonPublicAPIInRecord, "Deconstruct").WithArguments("A.Deconstruct(out int)").WithLocation(4, 11 + accessibility.Length)
                );
        }
 
        [Fact]
        public void Deconstruct_UserDefined_Static_08()
        {
            var source =
@"
record struct A(int X)
{
    public static void Deconstruct(out int a)
        => throw null;
}
";
            var comp = CreateCompilation(source);
            comp.VerifyEmitDiagnostics(
                // (4,24): error CS8877: Record member 'A.Deconstruct(out int)' may not be static.
                //     public static void Deconstruct(out int a)
                Diagnostic(ErrorCode.ERR_StaticAPIInRecord, "Deconstruct").WithArguments("A.Deconstruct(out int)").WithLocation(4, 24)
                );
        }
 
        [Fact]
        public void OutVarInPositionalParameterDefaultValue()
        {
            var source =
@"
record struct A(int X = A.M(out int a) + a)
{
    public static int M(out int a)
        => throw null;
}
";
            var comp = CreateCompilation(source);
            comp.VerifyEmitDiagnostics(
                // (2,25): error CS1736: Default parameter value for 'X' must be a compile-time constant
                // record struct A(int X = A.M(out int a) + a)
                Diagnostic(ErrorCode.ERR_DefaultValueMustBeConstant, "A.M(out int a) + a").WithArguments("X").WithLocation(2, 25)
                );
        }
 
        [Fact]
        public void FieldConsideredUnassignedIfInitializationViaProperty()
        {
            var source = @"
record struct Pos(int X)
{
    private int x;
    public int X { get { return x; } set { x = value; } } = X;
}
 
record struct Pos2(int X)
{
    private int x = X; // value isn't validated by setter
    public int X { get { return x; } set { x = value; } }
}
";
            var comp = CreateCompilation(source, parseOptions: TestOptions.Regular10);
            comp.VerifyEmitDiagnostics(
                // (2,15): error CS0171: Field 'Pos.x' must be fully assigned before control is returned to the caller. Consider updating to language version '11.0' to auto-default the field.
                // record struct Pos(int X)
                Diagnostic(ErrorCode.ERR_UnassignedThisUnsupportedVersion, "Pos").WithArguments("Pos.x", "11.0").WithLocation(2, 15),
                // (5,16): error CS8050: Only auto-implemented properties, or properties that use the 'field' keyword, can have initializers.
                //     public int X { get { return x; } set { x = value; } } = X;
                Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "X").WithLocation(5, 16)
                );
 
            comp = CreateCompilation(source, parseOptions: TestOptions.Regular11);
            comp.VerifyEmitDiagnostics(
                // (5,16): error CS8050: Only auto-implemented properties, or properties that use the 'field' keyword, can have initializers.
                //     public int X { get { return x; } set { x = value; } } = X;
                Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "X").WithLocation(5, 16)
                );
        }
 
        [Fact]
        public void IEquatableT_01()
        {
            var source =
@"record struct A<T>;
class Program
{
    static void F<T>(System.IEquatable<T> t)
    {
    }
    static void M<T>()
    {
        F(new A<T>());
    }
}";
            var comp = CreateCompilation(source);
            comp.VerifyDiagnostics(
                );
        }
 
        [Fact]
        public void IEquatableT_02()
        {
            var source =
@"using System;
record struct A;
record struct B<T>;
 
class Program
{
    static bool F<T>(IEquatable<T> t, T t2)
    {
        return t.Equals(t2);
    }
    static void Main()
    {
        Console.Write(F(new A(), new A()));
        Console.Write(F(new B<int>(), new B<int>()));
    }
}";
            var comp = CreateCompilation(new[] { source, IsExternalInitTypeDefinition }, parseOptions: TestOptions.RegularPreview, options: TestOptions.ReleaseExe);
            CompileAndVerify(comp, expectedOutput: "TrueTrue").VerifyDiagnostics();
        }
 
        [Fact]
        public void IEquatableT_02_ImplicitImplementation()
        {
            var source =
@"using System;
record struct A
{
    public bool Equals(A other)
    {
        System.Console.Write(""A.Equals(A) "");
        return false;
    }
}
record struct B<T>
{
    public bool Equals(B<T> other)
    {
        System.Console.Write(""B.Equals(B) "");
        return true;
    }
}
 
class Program
{
    static bool F<T>(IEquatable<T> t, T t2)
    {
        return t.Equals(t2);
    }
    static void Main()
    {
        Console.Write(F(new A(), new A()));
        Console.Write("" "");
        Console.Write(F(new B<int>(), new B<int>()));
    }
}";
            var comp = CreateCompilation(new[] { source, IsExternalInitTypeDefinition }, parseOptions: TestOptions.RegularPreview, options: TestOptions.ReleaseExe);
            CompileAndVerify(comp, expectedOutput: "A.Equals(A) False B.Equals(B) True").VerifyDiagnostics(
                // (4,17): warning CS8851: 'A' defines 'Equals' but not 'GetHashCode'
                //     public bool Equals(A other)
                Diagnostic(ErrorCode.WRN_RecordEqualsWithoutGetHashCode, "Equals").WithArguments("A").WithLocation(4, 17),
                // (12,17): warning CS8851: 'B' defines 'Equals' but not 'GetHashCode'
                //     public bool Equals(B<T> other)
                Diagnostic(ErrorCode.WRN_RecordEqualsWithoutGetHashCode, "Equals").WithArguments("B").WithLocation(12, 17)
                );
        }
 
        [Fact]
        public void IEquatableT_02_ExplicitImplementation()
        {
            var source =
@"using System;
record struct A
{
    bool IEquatable<A>.Equals(A other)
    {
        System.Console.Write(""A.Equals(A) "");
        return false;
    }
}
record struct B<T>
{
    bool IEquatable<B<T>>.Equals(B<T> other)
    {
        System.Console.Write(""B.Equals(B) "");
        return true;
    }
}
 
class Program
{
    static bool F<T>(IEquatable<T> t, T t2)
    {
        return t.Equals(t2);
    }
    static void Main()
    {
        Console.Write(F(new A(), new A()));
        Console.Write("" "");
        Console.Write(F(new B<int>(), new B<int>()));
    }
}";
            var comp = CreateCompilation(new[] { source, IsExternalInitTypeDefinition }, parseOptions: TestOptions.RegularPreview, options: TestOptions.ReleaseExe);
            CompileAndVerify(comp, expectedOutput: "A.Equals(A) False B.Equals(B) True").VerifyDiagnostics();
        }
 
        [Fact]
        public void IEquatableT_03()
        {
            var source = @"
record struct A<T> : System.IEquatable<A<T>>;
";
            var comp = CreateCompilation(source);
            comp.VerifyDiagnostics();
 
            var type = comp.GetMember<NamedTypeSymbol>("A");
            AssertEx.Equal(new[] { "System.IEquatable<A<T>>" }, type.InterfacesNoUseSiteDiagnostics().ToTestDisplayStrings());
            AssertEx.Equal(new[] { "System.IEquatable<A<T>>" }, type.AllInterfacesNoUseSiteDiagnostics.ToTestDisplayStrings());
        }
 
        [Fact]
        public void IEquatableT_MissingIEquatable()
        {
            var source = @"
record struct A<T>;
";
            var comp = CreateCompilation(source);
            comp.MakeTypeMissing(WellKnownType.System_IEquatable_T);
            comp.VerifyEmitDiagnostics(
                    // (2,15): error CS0518: Predefined type 'System.IEquatable`1' is not defined or imported
                    // record struct A<T>;
                    Diagnostic(ErrorCode.ERR_PredefinedTypeNotFound, "A").WithArguments("System.IEquatable`1").WithLocation(2, 15),
                    // (2,15): error CS0518: Predefined type 'System.IEquatable`1' is not defined or imported
                    // record struct A<T>;
                    Diagnostic(ErrorCode.ERR_PredefinedTypeNotFound, "A").WithArguments("System.IEquatable`1").WithLocation(2, 15)
                    );
 
            var type = comp.GetMember<NamedTypeSymbol>("A");
            AssertEx.Equal(new[] { "System.IEquatable<A<T>>[missing]" }, type.InterfacesNoUseSiteDiagnostics().ToTestDisplayStrings());
            AssertEx.Equal(new[] { "System.IEquatable<A<T>>[missing]" }, type.AllInterfacesNoUseSiteDiagnostics.ToTestDisplayStrings());
        }
 
        [Fact]
        public void RecordEquals_01()
        {
            var source = @"
var a1 = new B();
var a2 = new B();
System.Console.WriteLine(a1.Equals(a2));
 
record struct B
{
    public bool Equals(B other)
    {
        System.Console.WriteLine(""B.Equals(B)"");
        return false;
    }
}
";
            var comp = CreateCompilation(source);
            comp.VerifyDiagnostics(
                // (8,17): warning CS8851: 'B' defines 'Equals' but not 'GetHashCode'
                //     public bool Equals(B other)
                Diagnostic(ErrorCode.WRN_RecordEqualsWithoutGetHashCode, "Equals").WithArguments("B").WithLocation(8, 17)
                );
 
            CompileAndVerify(comp, expectedOutput:
@"
B.Equals(B)
False
");
        }
 
        [Fact]
        public void RecordEquals_01_NoInParameters()
        {
            var source = @"
var a1 = new B();
var a2 = new B();
System.Console.WriteLine(a1.Equals(in a2));
 
record struct B;
";
            var comp = CreateCompilation(source);
            comp.VerifyEmitDiagnostics(
                // (4,39): error CS1615: Argument 1 may not be passed with the 'in' keyword
                // System.Console.WriteLine(a1.Equals(in a2));
                Diagnostic(ErrorCode.ERR_BadArgExtraRef, "a2").WithArguments("1", "in").WithLocation(4, 39)
                );
        }
 
        [Theory]
        [InlineData("protected")]
        [InlineData("private protected")]
        [InlineData("internal protected")]
        public void RecordEquals_10(string accessibility)
        {
            var source =
$@"
record struct A
{{
    {accessibility} bool Equals(A x)
        => throw null;
 
    bool System.IEquatable<A>.Equals(A x) => throw null;
}}
";
            var comp = CreateCompilation(source);
            comp.VerifyEmitDiagnostics(
                // (4,29): error CS0666: 'A.Equals(A)': new protected member declared in struct
                //     internal protected bool Equals(A x)
                Diagnostic(ErrorCode.ERR_ProtectedInStruct, "Equals").WithArguments("A.Equals(A)").WithLocation(4, 11 + accessibility.Length),
                // (4,29): error CS8873: Record member 'A.Equals(A)' must be public.
                //     internal protected bool Equals(A x)
                Diagnostic(ErrorCode.ERR_NonPublicAPIInRecord, "Equals").WithArguments("A.Equals(A)").WithLocation(4, 11 + accessibility.Length),
                // (4,29): warning CS8851: 'A' defines 'Equals' but not 'GetHashCode'
                //     internal protected bool Equals(A x)
                Diagnostic(ErrorCode.WRN_RecordEqualsWithoutGetHashCode, "Equals").WithArguments("A").WithLocation(4, 11 + accessibility.Length)
                );
        }
 
        [Theory]
        [InlineData("")]
        [InlineData("private")]
        [InlineData("internal")]
        public void RecordEquals_11(string accessibility)
        {
            var source =
$@"
record struct A
{{
    {accessibility} bool Equals(A x)
        => throw null;
 
    bool System.IEquatable<A>.Equals(A x) => throw null;
}}
";
            var comp = CreateCompilation(source);
            comp.VerifyEmitDiagnostics(
                // (4,...): error CS8873: Record member 'A.Equals(A)' must be public.
                //      { accessibility } bool Equals(A x)
                Diagnostic(ErrorCode.ERR_NonPublicAPIInRecord, "Equals").WithArguments("A.Equals(A)").WithLocation(4, 11 + accessibility.Length),
                // (4,11): warning CS8851: 'A' defines 'Equals' but not 'GetHashCode'
                //      bool Equals(A x)
                Diagnostic(ErrorCode.WRN_RecordEqualsWithoutGetHashCode, "Equals").WithArguments("A").WithLocation(4, 11 + accessibility.Length)
                );
        }
 
        [Fact]
        public void RecordEquals_12()
        {
            var source = @"
A a1 = new A();
A a2 = new A();
 
System.Console.Write(a1.Equals(a2));
System.Console.Write(a1.Equals((object)a2));
 
record struct A
{
    public bool Equals(B other) => throw null;
}
class B
{
}
";
            var comp = CreateCompilation(source);
            comp.VerifyDiagnostics();
            var verifier = CompileAndVerify(comp, expectedOutput: "TrueTrue");
            verifier.VerifyIL("A.Equals(A)", @"
{
  // Code size        2 (0x2)
  .maxstack  1
  IL_0000:  ldc.i4.1
  IL_0001:  ret
}");
 
            verifier.VerifyIL("A.Equals(object)", @"
{
  // Code size       23 (0x17)
  .maxstack  2
  IL_0000:  ldarg.1
  IL_0001:  isinst     ""A""
  IL_0006:  brfalse.s  IL_0015
  IL_0008:  ldarg.0
  IL_0009:  ldarg.1
  IL_000a:  unbox.any  ""A""
  IL_000f:  call       ""readonly bool A.Equals(A)""
  IL_0014:  ret
  IL_0015:  ldc.i4.0
  IL_0016:  ret
}");
 
            verifier.VerifyIL("A.GetHashCode()", @"
{
  // Code size        2 (0x2)
  .maxstack  1
  IL_0000:  ldc.i4.0
  IL_0001:  ret
}");
 
            var recordEquals = comp.GetMembers("A.Equals").OfType<SynthesizedRecordEquals>().Single();
            Assert.Equal("readonly System.Boolean A.Equals(A other)", recordEquals.ToTestDisplayString());
            Assert.Equal(Accessibility.Public, recordEquals.DeclaredAccessibility);
            Assert.False(recordEquals.IsAbstract);
            Assert.False(recordEquals.IsVirtual);
            Assert.False(recordEquals.IsOverride);
            Assert.False(recordEquals.IsSealed);
            Assert.True(recordEquals.IsImplicitlyDeclared);
 
            var objectEquals = comp.GetMembers("A.Equals").OfType<SynthesizedRecordObjEquals>().Single();
            Assert.Equal("readonly System.Boolean A.Equals(System.Object obj)", objectEquals.ToTestDisplayString());
            Assert.Equal(Accessibility.Public, objectEquals.DeclaredAccessibility);
            Assert.False(objectEquals.IsAbstract);
            Assert.False(objectEquals.IsVirtual);
            Assert.True(objectEquals.IsOverride);
            Assert.False(objectEquals.IsSealed);
            Assert.True(objectEquals.IsImplicitlyDeclared);
 
            MethodSymbol gethashCode = comp.GetMembers("A." + WellKnownMemberNames.ObjectGetHashCode).OfType<SynthesizedRecordGetHashCode>().Single();
            Assert.Equal("readonly System.Int32 A.GetHashCode()", gethashCode.ToTestDisplayString());
            Assert.Equal(Accessibility.Public, gethashCode.DeclaredAccessibility);
            Assert.False(gethashCode.IsStatic);
            Assert.False(gethashCode.IsAbstract);
            Assert.False(gethashCode.IsVirtual);
            Assert.True(gethashCode.IsOverride);
            Assert.False(gethashCode.IsSealed);
            Assert.True(gethashCode.IsImplicitlyDeclared);
        }
 
        [Fact]
        public void RecordEquals_13()
        {
            var source = @"
record struct A
{
    public int Equals(A other)
        => throw null;
 
    bool System.IEquatable<A>.Equals(A x) => throw null;
}
";
            var comp = CreateCompilation(source);
            comp.VerifyEmitDiagnostics(
                // (4,16): error CS8874: Record member 'A.Equals(A)' must return 'bool'.
                //     public int Equals(A other)
                Diagnostic(ErrorCode.ERR_SignatureMismatchInRecord, "Equals").WithArguments("A.Equals(A)", "bool").WithLocation(4, 16),
                // (4,16): warning CS8851: 'A' defines 'Equals' but not 'GetHashCode'
                //     public int Equals(A other)
                Diagnostic(ErrorCode.WRN_RecordEqualsWithoutGetHashCode, "Equals").WithArguments("A").WithLocation(4, 16)
                );
        }
 
        [Fact]
        public void RecordEquals_14()
        {
            var source = @"
record struct A
{
    public bool Equals(A other)
        => throw null;
 
    System.Boolean System.IEquatable<A>.Equals(A x) => throw null;
}
";
            var comp = CreateCompilation(source);
            comp.MakeTypeMissing(SpecialType.System_Boolean);
            comp.VerifyEmitDiagnostics(
                // (2,1): error CS0518: Predefined type 'System.Boolean' is not defined or imported
                // record struct A
                Diagnostic(ErrorCode.ERR_PredefinedTypeNotFound, @"record struct A
{
    public bool Equals(A other)
        => throw null;
 
    System.Boolean System.IEquatable<A>.Equals(A x) => throw null;
}").WithArguments("System.Boolean").WithLocation(2, 1),
                // (2,1): error CS0518: Predefined type 'System.Boolean' is not defined or imported
                // record struct A
                Diagnostic(ErrorCode.ERR_PredefinedTypeNotFound, @"record struct A
{
    public bool Equals(A other)
        => throw null;
 
    System.Boolean System.IEquatable<A>.Equals(A x) => throw null;
}").WithArguments("System.Boolean").WithLocation(2, 1),
                // (2,15): error CS0518: Predefined type 'System.Boolean' is not defined or imported
                // record struct A
                Diagnostic(ErrorCode.ERR_PredefinedTypeNotFound, "A").WithArguments("System.Boolean").WithLocation(2, 15),
                // (2,15): error CS0518: Predefined type 'System.Boolean' is not defined or imported
                // record struct A
                Diagnostic(ErrorCode.ERR_PredefinedTypeNotFound, "A").WithArguments("System.Boolean").WithLocation(2, 15),
                // (2,15): error CS0518: Predefined type 'System.Boolean' is not defined or imported
                // record struct A
                Diagnostic(ErrorCode.ERR_PredefinedTypeNotFound, "A").WithArguments("System.Boolean").WithLocation(2, 15),
                // (2,15): error CS0518: Predefined type 'System.Boolean' is not defined or imported
                // record struct A
                Diagnostic(ErrorCode.ERR_PredefinedTypeNotFound, "A").WithArguments("System.Boolean").WithLocation(2, 15),
                // (4,12): error CS0518: Predefined type 'System.Boolean' is not defined or imported
                //     public bool Equals(A other)
                Diagnostic(ErrorCode.ERR_PredefinedTypeNotFound, "bool").WithArguments("System.Boolean").WithLocation(4, 12),
                // (4,17): warning CS8851: 'A' defines 'Equals' but not 'GetHashCode'
                //     public bool Equals(A other)
                Diagnostic(ErrorCode.WRN_RecordEqualsWithoutGetHashCode, "Equals").WithArguments("A").WithLocation(4, 17)
                );
        }
 
        [Fact]
        public void RecordEquals_19()
        {
            var source = @"
record struct A
{
    public static bool Equals(A x) => throw null;
}
";
            var comp = CreateCompilation(source);
            comp.VerifyEmitDiagnostics(
                // (2,15): error CS0736: 'A' does not implement interface member 'IEquatable<A>.Equals(A)'. 'A.Equals(A)' cannot implement an interface member because it is static.
                // record struct A
                Diagnostic(ErrorCode.ERR_CloseUnimplementedInterfaceMemberStatic, "A").WithArguments("A", "System.IEquatable<A>.Equals(A)", "A.Equals(A)").WithLocation(2, 15),
                // (4,24): error CS8877: Record member 'A.Equals(A)' may not be static.
                //     public static bool Equals(A x) => throw null;
                Diagnostic(ErrorCode.ERR_StaticAPIInRecord, "Equals").WithArguments("A.Equals(A)").WithLocation(4, 24),
                // (4,24): warning CS8851: 'A' defines 'Equals' but not 'GetHashCode'
                //     public static bool Equals(A x) => throw null;
                Diagnostic(ErrorCode.WRN_RecordEqualsWithoutGetHashCode, "Equals").WithArguments("A").WithLocation(4, 24)
                );
        }
 
        [Fact]
        public void RecordEquals_RecordEqualsInValueType()
        {
            var src = @"
public record struct A;
 
namespace System
{
    public class Object
    {
        public virtual bool Equals(object x) => throw null;
        public virtual int GetHashCode() => throw null;
        public virtual string ToString() => throw null;
    }
    public class Exception { }
    public class ValueType
    {
        public bool Equals(A x) => throw null;
    }
    public class Attribute { }
    public class String { }
    public struct Void { }
    public struct Boolean { }
    public struct Char { }
    public struct Int32 { }
    public interface IEquatable<T> { }
}
namespace System.Collections.Generic
{
    public abstract class EqualityComparer<T>
    {
        public static EqualityComparer<T> Default => throw null;
        public abstract int GetHashCode(T t);
    }
}
namespace System.Text
{
    public class StringBuilder
    {
        public StringBuilder Append(string s) => null;
        public StringBuilder Append(char c) => null;
        public StringBuilder Append(object o) => null;
    }
}
";
            var comp = CreateEmptyCompilation(src, parseOptions: TestOptions.RegularPreview.WithNoRefSafetyRulesAttribute());
 
            comp.VerifyEmitDiagnostics(
                // warning CS8021: No value for RuntimeMetadataVersion found. No assembly containing System.Object was found nor was a value for RuntimeMetadataVersion specified through options.
                Diagnostic(ErrorCode.WRN_NoRuntimeMetadataVersion).WithLocation(1, 1)
                );
 
            var recordEquals = comp.GetMembers("A.Equals").OfType<SynthesizedRecordEquals>().Single();
            Assert.Equal("readonly System.Boolean A.Equals(A other)", recordEquals.ToTestDisplayString());
        }
 
        [Fact]
        public void RecordEquals_FourFields()
        {
            var source = @"
A a1 = new A(1, ""hello"");
 
System.Console.Write(a1.Equals(a1));
System.Console.Write(a1.Equals((object)a1));
System.Console.Write("" - "");
 
A a2 = new A(1, ""hello"") { fieldI = 100 };
 
System.Console.Write(a1.Equals(a2));
System.Console.Write(a1.Equals((object)a2));
System.Console.Write(a2.Equals(a1));
System.Console.Write(a2.Equals((object)a1));
System.Console.Write("" - "");
 
A a3 = new A(1, ""world"");
 
System.Console.Write(a1.Equals(a3));
System.Console.Write(a1.Equals((object)a3));
System.Console.Write(a3.Equals(a1));
System.Console.Write(a3.Equals((object)a1));
 
record struct A(int I, string S)
{
    public int fieldI = 42;
    public string fieldS = ""hello"";
}
";
            var comp = CreateCompilation(source);
            comp.VerifyDiagnostics();
            var verifier = CompileAndVerify(comp, expectedOutput: "TrueTrue - FalseFalseFalseFalse - FalseFalseFalseFalse");
            verifier.VerifyIL("A.Equals(A)", @"
{
  // Code size       97 (0x61)
  .maxstack  3
  IL_0000:  call       ""System.Collections.Generic.EqualityComparer<int> System.Collections.Generic.EqualityComparer<int>.Default.get""
  IL_0005:  ldarg.0
  IL_0006:  ldfld      ""int A.<I>k__BackingField""
  IL_000b:  ldarg.1
  IL_000c:  ldfld      ""int A.<I>k__BackingField""
  IL_0011:  callvirt   ""bool System.Collections.Generic.EqualityComparer<int>.Equals(int, int)""
  IL_0016:  brfalse.s  IL_005f
  IL_0018:  call       ""System.Collections.Generic.EqualityComparer<string> System.Collections.Generic.EqualityComparer<string>.Default.get""
  IL_001d:  ldarg.0
  IL_001e:  ldfld      ""string A.<S>k__BackingField""
  IL_0023:  ldarg.1
  IL_0024:  ldfld      ""string A.<S>k__BackingField""
  IL_0029:  callvirt   ""bool System.Collections.Generic.EqualityComparer<string>.Equals(string, string)""
  IL_002e:  brfalse.s  IL_005f
  IL_0030:  call       ""System.Collections.Generic.EqualityComparer<int> System.Collections.Generic.EqualityComparer<int>.Default.get""
  IL_0035:  ldarg.0
  IL_0036:  ldfld      ""int A.fieldI""
  IL_003b:  ldarg.1
  IL_003c:  ldfld      ""int A.fieldI""
  IL_0041:  callvirt   ""bool System.Collections.Generic.EqualityComparer<int>.Equals(int, int)""
  IL_0046:  brfalse.s  IL_005f
  IL_0048:  call       ""System.Collections.Generic.EqualityComparer<string> System.Collections.Generic.EqualityComparer<string>.Default.get""
  IL_004d:  ldarg.0
  IL_004e:  ldfld      ""string A.fieldS""
  IL_0053:  ldarg.1
  IL_0054:  ldfld      ""string A.fieldS""
  IL_0059:  callvirt   ""bool System.Collections.Generic.EqualityComparer<string>.Equals(string, string)""
  IL_005e:  ret
  IL_005f:  ldc.i4.0
  IL_0060:  ret
}");
 
            verifier.VerifyIL("A.Equals(object)", @"
{
  // Code size       23 (0x17)
  .maxstack  2
  IL_0000:  ldarg.1
  IL_0001:  isinst     ""A""
  IL_0006:  brfalse.s  IL_0015
  IL_0008:  ldarg.0
  IL_0009:  ldarg.1
  IL_000a:  unbox.any  ""A""
  IL_000f:  call       ""readonly bool A.Equals(A)""
  IL_0014:  ret
  IL_0015:  ldc.i4.0
  IL_0016:  ret
}");
 
            verifier.VerifyIL("A.GetHashCode()", @"
{
  // Code size       86 (0x56)
  .maxstack  3
  IL_0000:  call       ""System.Collections.Generic.EqualityComparer<int> System.Collections.Generic.EqualityComparer<int>.Default.get""
  IL_0005:  ldarg.0
  IL_0006:  ldfld      ""int A.<I>k__BackingField""
  IL_000b:  callvirt   ""int System.Collections.Generic.EqualityComparer<int>.GetHashCode(int)""
  IL_0010:  ldc.i4     0xa5555529
  IL_0015:  mul
  IL_0016:  call       ""System.Collections.Generic.EqualityComparer<string> System.Collections.Generic.EqualityComparer<string>.Default.get""
  IL_001b:  ldarg.0
  IL_001c:  ldfld      ""string A.<S>k__BackingField""
  IL_0021:  callvirt   ""int System.Collections.Generic.EqualityComparer<string>.GetHashCode(string)""
  IL_0026:  add
  IL_0027:  ldc.i4     0xa5555529
  IL_002c:  mul
  IL_002d:  call       ""System.Collections.Generic.EqualityComparer<int> System.Collections.Generic.EqualityComparer<int>.Default.get""
  IL_0032:  ldarg.0
  IL_0033:  ldfld      ""int A.fieldI""
  IL_0038:  callvirt   ""int System.Collections.Generic.EqualityComparer<int>.GetHashCode(int)""
  IL_003d:  add
  IL_003e:  ldc.i4     0xa5555529
  IL_0043:  mul
  IL_0044:  call       ""System.Collections.Generic.EqualityComparer<string> System.Collections.Generic.EqualityComparer<string>.Default.get""
  IL_0049:  ldarg.0
  IL_004a:  ldfld      ""string A.fieldS""
  IL_004f:  callvirt   ""int System.Collections.Generic.EqualityComparer<string>.GetHashCode(string)""
  IL_0054:  add
  IL_0055:  ret
}");
        }
 
        [Fact]
        public void RecordEquals_StaticField()
        {
            var source = @"
record struct A
{
    public static int field = 42;
}
";
            var comp = CreateCompilation(source);
            comp.VerifyDiagnostics();
            var verifier = CompileAndVerify(comp);
            verifier.VerifyIL("A.Equals(A)", @"
{
  // Code size        2 (0x2)
  .maxstack  1
  IL_0000:  ldc.i4.1
  IL_0001:  ret
}");
 
            verifier.VerifyIL("A.GetHashCode()", @"
{
  // Code size        2 (0x2)
  .maxstack  1
  IL_0000:  ldc.i4.0
  IL_0001:  ret
}");
        }
 
        [Fact]
        public void RecordEquals_GeneratedAsReadOnly()
        {
            var src = @"
record struct A(int I, string S);
";
            var comp = CreateCompilation(src);
            comp.VerifyDiagnostics();
            var recordEquals = comp.GetMembers("A.Equals").OfType<SynthesizedRecordEquals>().Single();
            Assert.True(recordEquals.IsDeclaredReadOnly);
        }
 
        [Fact]
        public void ObjectEquals_06()
        {
            var source = @"
record struct A
{
    public static new bool Equals(object obj) => throw null;
}
";
            var comp = CreateCompilation(source);
            comp.VerifyEmitDiagnostics(
                // (4,28): error CS0111: Type 'A' already defines a member called 'Equals' with the same parameter types
                //     public static new bool Equals(object obj) => throw null;
                Diagnostic(ErrorCode.ERR_MemberAlreadyExists, "Equals").WithArguments("Equals", "A").WithLocation(4, 28)
                );
        }
 
        [Fact]
        public void ObjectEquals_UserDefined()
        {
            var source = @"
record struct A
{
    public override bool Equals(object obj) => throw null;
}
";
            var comp = CreateCompilation(source);
            comp.VerifyEmitDiagnostics(
                // (4,26): error CS0111: Type 'A' already defines a member called 'Equals' with the same parameter types
                //     public override bool Equals(object obj) => throw null;
                Diagnostic(ErrorCode.ERR_MemberAlreadyExists, "Equals").WithArguments("Equals", "A").WithLocation(4, 26)
                );
        }
 
        [Fact]
        public void ObjectEquals_GeneratedAsReadOnly()
        {
            var src = @"
record struct A(int I, string S);
";
            var comp = CreateCompilation(src);
            comp.VerifyDiagnostics();
            var objectEquals = comp.GetMembers("A.Equals").OfType<SynthesizedRecordObjEquals>().Single();
            Assert.True(objectEquals.IsDeclaredReadOnly);
        }
 
        [Fact]
        public void GetHashCode_UserDefined()
        {
            var source = @"
System.Console.Write(new A().GetHashCode());
 
record struct A
{
    public override int GetHashCode() => 42;
}
";
            var comp = CreateCompilation(source);
            comp.VerifyEmitDiagnostics();
            CompileAndVerify(comp, expectedOutput: "42");
        }
 
        [Fact]
        public void GetHashCode_GetHashCodeInValueType()
        {
            var src = @"
public record struct A;
 
namespace System
{
    public class Object
    {
        public virtual bool Equals(object x) => throw null;
        public virtual string ToString() => throw null;
    }
    public class Exception { }
    public class ValueType
    {
        public virtual int GetHashCode() => throw null;
    }
    public class Attribute { }
    public class String { }
    public struct Void { }
    public struct Boolean { }
    public struct Char { }
    public struct Int32 { }
    public interface IEquatable<T> { }
}
namespace System.Collections.Generic
{
    public abstract class EqualityComparer<T>
    {
        public static EqualityComparer<T> Default => throw null;
        public abstract int GetHashCode(T t);
    }
}
namespace System.Text
{
    public class StringBuilder
    {
        public StringBuilder Append(string s) => null;
        public StringBuilder Append(char c) => null;
        public StringBuilder Append(object o) => null;
    }
}
";
            var comp = CreateEmptyCompilation(src, parseOptions: TestOptions.RegularPreview.WithNoRefSafetyRulesAttribute());
 
            comp.VerifyEmitDiagnostics(
                // warning CS8021: No value for RuntimeMetadataVersion found. No assembly containing System.Object was found nor was a value for RuntimeMetadataVersion specified through options.
                Diagnostic(ErrorCode.WRN_NoRuntimeMetadataVersion).WithLocation(1, 1),
                // (2,22): error CS8869: 'A.GetHashCode()' does not override expected method from 'object'.
                // public record struct A;
                Diagnostic(ErrorCode.ERR_DoesNotOverrideMethodFromObject, "A").WithArguments("A.GetHashCode()").WithLocation(2, 22)
                );
        }
 
        [Fact]
        public void GetHashCode_MissingEqualityComparer_EmptyRecord()
        {
            var src = @"
public record struct A;
";
            var comp = CreateCompilation(src);
            comp.MakeTypeMissing(WellKnownType.System_Collections_Generic_EqualityComparer_T);
            comp.VerifyEmitDiagnostics();
        }
 
        [Fact]
        public void GetHashCode_MissingEqualityComparer_NonEmptyRecord()
        {
            var src = @"
public record struct A(int I);
";
            var comp = CreateCompilation(src);
            comp.MakeTypeMissing(WellKnownType.System_Collections_Generic_EqualityComparer_T);
 
            comp.VerifyEmitDiagnostics(
                // (2,1): error CS0656: Missing compiler required member 'System.Collections.Generic.EqualityComparer`1.GetHashCode'
                // public record struct A(int I);
                Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "public record struct A(int I);").WithArguments("System.Collections.Generic.EqualityComparer`1", "GetHashCode").WithLocation(2, 1),
                // (2,1): error CS0656: Missing compiler required member 'System.Collections.Generic.EqualityComparer`1.get_Default'
                // public record struct A(int I);
                Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "public record struct A(int I);").WithArguments("System.Collections.Generic.EqualityComparer`1", "get_Default").WithLocation(2, 1)
                );
        }
 
        [Fact]
        public void GetHashCode_GeneratedAsReadOnly()
        {
            var src = @"
record struct A(int I, string S);
";
            var comp = CreateCompilation(src);
            comp.VerifyDiagnostics();
            var method = comp.GetMember<SynthesizedRecordGetHashCode>("A.GetHashCode");
            Assert.True(method.IsDeclaredReadOnly);
        }
 
        [Fact]
        public void GetHashCodeIsDefinedButEqualsIsNot()
        {
            var src = @"
public record struct C
{
    public object Data;
    public override int GetHashCode() { return 0; }
}";
            var comp = CreateCompilation(src);
            comp.VerifyDiagnostics();
        }
 
        [Fact]
        public void EqualsIsDefinedButGetHashCodeIsNot()
        {
            var src = @"
public record struct C
{
    public object Data;
    public bool Equals(C c) { return false; }
}";
            var comp = CreateCompilation(src);
            comp.VerifyDiagnostics(
                // (5,17): warning CS8851: 'C' defines 'Equals' but not 'GetHashCode'
                //     public bool Equals(C c) { return false; }
                Diagnostic(ErrorCode.WRN_RecordEqualsWithoutGetHashCode, "Equals").WithArguments("C").WithLocation(5, 17));
        }
 
        [Fact]
        public void EqualityOperators_01()
        {
            var source = @"
record struct A(int X)
{
    public bool Equals(ref A other)
        => throw null;
 
    static void Main()
    {
        Test(default, default);
        Test(default, new A(0));
        Test(new A(1), new A(1));
        Test(new A(2), new A(3));
        var a = new A(11);
        Test(a, a);
    }
 
    static void Test(A a1, A a2)
    {
        System.Console.WriteLine(""{0} {1} {2} {3}"", a1 == a2, a2 == a1, a1 != a2, a2 != a1);
    }
}
";
            var verifier = CompileAndVerify(source, expectedOutput: @"
True True False False
True True False False
True True False False
False False True True
True True False False
").VerifyDiagnostics();
 
            var comp = (CSharpCompilation)verifier.Compilation;
            MethodSymbol op = comp.GetMembers("A." + WellKnownMemberNames.EqualityOperatorName).OfType<SynthesizedRecordEqualityOperator>().Single();
            Assert.Equal("System.Boolean A.op_Equality(A left, A right)", op.ToTestDisplayString());
            Assert.Equal(Accessibility.Public, op.DeclaredAccessibility);
            Assert.True(op.IsStatic);
            Assert.False(op.IsAbstract);
            Assert.False(op.IsVirtual);
            Assert.False(op.IsOverride);
            Assert.False(op.IsSealed);
            Assert.True(op.IsImplicitlyDeclared);
 
            op = comp.GetMembers("A." + WellKnownMemberNames.InequalityOperatorName).OfType<SynthesizedRecordInequalityOperator>().Single();
            Assert.Equal("System.Boolean A.op_Inequality(A left, A right)", op.ToTestDisplayString());
            Assert.Equal(Accessibility.Public, op.DeclaredAccessibility);
            Assert.True(op.IsStatic);
            Assert.False(op.IsAbstract);
            Assert.False(op.IsVirtual);
            Assert.False(op.IsOverride);
            Assert.False(op.IsSealed);
            Assert.True(op.IsImplicitlyDeclared);
 
            verifier.VerifyIL("bool A.op_Equality(A, A)", @"
{
  // Code size        9 (0x9)
  .maxstack  2
  IL_0000:  ldarga.s   V_0
  IL_0002:  ldarg.1
  IL_0003:  call       ""readonly bool A.Equals(A)""
  IL_0008:  ret
}
");
 
            verifier.VerifyIL("bool A.op_Inequality(A, A)", @"
{
  // Code size       11 (0xb)
  .maxstack  2
  IL_0000:  ldarg.0
  IL_0001:  ldarg.1
  IL_0002:  call       ""bool A.op_Equality(A, A)""
  IL_0007:  ldc.i4.0
  IL_0008:  ceq
  IL_000a:  ret
}
");
        }
 
        [Fact]
        public void EqualityOperators_03()
        {
            var source =
@"
record struct A
{
    public static bool operator==(A r1, A r2)
        => throw null;
    public static bool operator==(A r1, string r2)
        => throw null;
    public static bool operator!=(A r1, string r2)
        => throw null;
}
";
            var comp = CreateCompilation(source);
            comp.VerifyEmitDiagnostics(
                // (4,32): error CS0111: Type 'A' already defines a member called 'op_Equality' with the same parameter types
                //     public static bool operator==(A r1, A r2)
                Diagnostic(ErrorCode.ERR_MemberAlreadyExists, "==").WithArguments("op_Equality", "A").WithLocation(4, 32)
                );
        }
 
        [Fact]
        public void EqualityOperators_04()
        {
            var source = @"
record struct A
{
    public static bool operator!=(A r1, A r2)
        => throw null;
    public static bool operator!=(string r1, A r2)
        => throw null;
    public static bool operator==(string r1, A r2)
        => throw null;
}
";
            var comp = CreateCompilation(source);
            comp.VerifyEmitDiagnostics(
                // (4,32): error CS0111: Type 'A' already defines a member called 'op_Inequality' with the same parameter types
                //     public static bool operator!=(A r1, A r2)
                Diagnostic(ErrorCode.ERR_MemberAlreadyExists, "!=").WithArguments("op_Inequality", "A").WithLocation(4, 32)
                );
        }
 
        [Fact]
        public void EqualityOperators_05()
        {
            var source = @"
record struct A
{
    public static bool op_Equality(A r1, A r2)
        => throw null;
    public static bool op_Equality(string r1, A r2)
        => throw null;
}
";
            var comp = CreateCompilation(source);
            comp.VerifyEmitDiagnostics(
                // (4,24): error CS0111: Type 'A' already defines a member called 'op_Equality' with the same parameter types
                //     public static bool op_Equality(A r1, A r2)
                Diagnostic(ErrorCode.ERR_MemberAlreadyExists, "op_Equality").WithArguments("op_Equality", "A").WithLocation(4, 24)
                );
        }
 
        [Fact]
        public void EqualityOperators_06()
        {
            var source = @"
record struct A
{
    public static bool op_Inequality(A r1, A r2)
        => throw null;
    public static bool op_Inequality(A r1, string r2)
        => throw null;
}
";
            var comp = CreateCompilation(source);
            comp.VerifyEmitDiagnostics(
                // (4,24): error CS0111: Type 'A' already defines a member called 'op_Inequality' with the same parameter types
                //     public static bool op_Inequality(A r1, A r2)
                Diagnostic(ErrorCode.ERR_MemberAlreadyExists, "op_Inequality").WithArguments("op_Inequality", "A").WithLocation(4, 24)
                );
        }
 
        [Fact]
        public void EqualityOperators_07()
        {
            var source = @"
record struct A
{
    public static bool Equals(A other)
        => throw null;
}
";
            var comp = CreateCompilation(source);
            comp.VerifyEmitDiagnostics(
                // (2,15): error CS0736: 'A' does not implement interface member 'IEquatable<A>.Equals(A)'. 'A.Equals(A)' cannot implement an interface member because it is static.
                // record struct A
                Diagnostic(ErrorCode.ERR_CloseUnimplementedInterfaceMemberStatic, "A").WithArguments("A", "System.IEquatable<A>.Equals(A)", "A.Equals(A)").WithLocation(2, 15),
                // (4,24): error CS8877: Record member 'A.Equals(A)' may not be static.
                //     public static bool Equals(A other)
                Diagnostic(ErrorCode.ERR_StaticAPIInRecord, "Equals").WithArguments("A.Equals(A)").WithLocation(4, 24),
                // (4,24): warning CS8851: 'A' defines 'Equals' but not 'GetHashCode'
                //     public static bool Equals(A other)
                Diagnostic(ErrorCode.WRN_RecordEqualsWithoutGetHashCode, "Equals").WithArguments("A").WithLocation(4, 24)
                );
        }
 
        [Theory]
        [CombinatorialData]
        public void EqualityOperators_09(bool useImageReference)
        {
            var source1 = @"
public record struct A(int X);
";
            var comp1 = CreateCompilation(source1);
 
            var source2 =
@"
class Program
{
    static void Main()
    {
        Test(default, default);
        Test(default, new A(0));
        Test(new A(1), new A(1));
        Test(new A(2), new A(3));
    }
 
    static void Test(A a1, A a2)
    {
        System.Console.WriteLine(""{0} {1} {2} {3}"", a1 == a2, a2 == a1, a1 != a2, a2 != a1);
    }
}
";
            CompileAndVerify(source2, references: new[] { useImageReference ? comp1.EmitToImageReference() : comp1.ToMetadataReference() }, expectedOutput: @"
True True False False
True True False False
True True False False
False False True True
").VerifyDiagnostics();
        }
 
        [Fact]
        public void GetSimpleNonTypeMembers_DirectApiCheck()
        {
            var src = @"
public record struct RecordB();
";
            var comp = CreateCompilation(src);
            var b = comp.GlobalNamespace.GetTypeMember("RecordB");
            AssertEx.SetEqual(new[] { "System.Boolean RecordB.op_Equality(RecordB left, RecordB right)" },
                b.GetSimpleNonTypeMembers("op_Equality").ToTestDisplayStrings());
        }
 
        [Fact]
        public void ToString_NestedRecord()
        {
            var src = @"
var c1 = new Outer.C1(42);
System.Console.Write(c1.ToString());
 
public class Outer
{
    public record struct C1(int I1);
}
";
 
            var compDebug = CreateCompilation(new[] { src, IsExternalInitTypeDefinition }, parseOptions: TestOptions.RegularPreview, options: TestOptions.DebugExe);
            var compRelease = CreateCompilation(new[] { src, IsExternalInitTypeDefinition }, parseOptions: TestOptions.RegularPreview, options: TestOptions.ReleaseExe);
            CompileAndVerify(compDebug, expectedOutput: "C1 { I1 = 42 }");
            compDebug.VerifyEmitDiagnostics();
 
            CompileAndVerify(compRelease, expectedOutput: "C1 { I1 = 42 }");
            compRelease.VerifyEmitDiagnostics();
        }
 
        [Fact]
        public void ToString_TopLevelRecord_Empty()
        {
            var src = @"
var c1 = new C1();
System.Console.Write(c1.ToString());
 
record struct C1;
";
 
            var comp = CreateCompilation(src);
            comp.VerifyEmitDiagnostics();
            var v = CompileAndVerify(comp, expectedOutput: "C1 { }");
 
            var print = comp.GetMember<MethodSymbol>("C1." + WellKnownMemberNames.PrintMembersMethodName);
            Assert.Equal(Accessibility.Private, print.DeclaredAccessibility);
            Assert.False(print.IsOverride);
            Assert.False(print.IsVirtual);
            Assert.False(print.IsAbstract);
            Assert.False(print.IsSealed);
            Assert.True(print.IsImplicitlyDeclared);
 
            var toString = comp.GetMember<MethodSymbol>("C1." + WellKnownMemberNames.ObjectToString);
            Assert.Equal(Accessibility.Public, toString.DeclaredAccessibility);
            Assert.True(toString.IsOverride);
            Assert.False(toString.IsVirtual);
            Assert.False(toString.IsAbstract);
            Assert.False(toString.IsSealed);
            Assert.True(toString.IsImplicitlyDeclared);
 
            v.VerifyIL("C1." + WellKnownMemberNames.PrintMembersMethodName, @"
{
  // Code size        2 (0x2)
  .maxstack  1
  IL_0000:  ldc.i4.0
  IL_0001:  ret
}
");
            v.VerifyIL("C1." + WellKnownMemberNames.ObjectToString, @"
{
  // Code size       64 (0x40)
  .maxstack  2
  .locals init (System.Text.StringBuilder V_0)
  IL_0000:  newobj     ""System.Text.StringBuilder..ctor()""
  IL_0005:  stloc.0
  IL_0006:  ldloc.0
  IL_0007:  ldstr      ""C1""
  IL_000c:  callvirt   ""System.Text.StringBuilder System.Text.StringBuilder.Append(string)""
  IL_0011:  pop
  IL_0012:  ldloc.0
  IL_0013:  ldstr      "" { ""
  IL_0018:  callvirt   ""System.Text.StringBuilder System.Text.StringBuilder.Append(string)""
  IL_001d:  pop
  IL_001e:  ldarg.0
  IL_001f:  ldloc.0
  IL_0020:  call       ""readonly bool C1.PrintMembers(System.Text.StringBuilder)""
  IL_0025:  brfalse.s  IL_0030
  IL_0027:  ldloc.0
  IL_0028:  ldc.i4.s   32
  IL_002a:  callvirt   ""System.Text.StringBuilder System.Text.StringBuilder.Append(char)""
  IL_002f:  pop
  IL_0030:  ldloc.0
  IL_0031:  ldc.i4.s   125
  IL_0033:  callvirt   ""System.Text.StringBuilder System.Text.StringBuilder.Append(char)""
  IL_0038:  pop
  IL_0039:  ldloc.0
  IL_003a:  callvirt   ""string object.ToString()""
  IL_003f:  ret
}
");
        }
 
        [Fact]
        public void ToString_TopLevelRecord_MissingStringBuilder()
        {
            var src = @"
record struct C1;
";
 
            var comp = CreateCompilation(src);
            comp.MakeTypeMissing(WellKnownType.System_Text_StringBuilder);
            comp.VerifyEmitDiagnostics(
                // (2,1): error CS0518: Predefined type 'System.Text.StringBuilder' is not defined or imported
                // record struct C1;
                Diagnostic(ErrorCode.ERR_PredefinedTypeNotFound, "record struct C1;").WithArguments("System.Text.StringBuilder").WithLocation(2, 1),
                // (2,1): error CS0656: Missing compiler required member 'System.Text.StringBuilder..ctor'
                // record struct C1;
                Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "record struct C1;").WithArguments("System.Text.StringBuilder", ".ctor").WithLocation(2, 1),
                // (2,15): error CS0518: Predefined type 'System.Text.StringBuilder' is not defined or imported
                // record struct C1;
                Diagnostic(ErrorCode.ERR_PredefinedTypeNotFound, "C1").WithArguments("System.Text.StringBuilder").WithLocation(2, 15)
                );
        }
 
        [Fact]
        public void ToString_TopLevelRecord_MissingStringBuilderCtor()
        {
            var src = @"
record struct C1;
";
 
            var comp = CreateCompilation(src);
            comp.MakeMemberMissing(WellKnownMember.System_Text_StringBuilder__ctor);
            comp.VerifyEmitDiagnostics(
                // (2,1): error CS0656: Missing compiler required member 'System.Text.StringBuilder..ctor'
                // record struct C1;
                Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "record struct C1;").WithArguments("System.Text.StringBuilder", ".ctor").WithLocation(2, 1)
                );
        }
 
        [Fact]
        public void ToString_TopLevelRecord_MissingStringBuilderAppendString()
        {
            var src = @"
record struct C1;
";
 
            var comp = CreateCompilation(src);
            comp.MakeMemberMissing(WellKnownMember.System_Text_StringBuilder__AppendString);
            comp.VerifyEmitDiagnostics(
                // (2,1): error CS0656: Missing compiler required member 'System.Text.StringBuilder.Append'
                // record struct C1;
                Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "record struct C1;").WithArguments("System.Text.StringBuilder", "Append").WithLocation(2, 1)
                );
        }
 
        [Fact]
        public void ToString_TopLevelRecord_OneProperty_MissingStringBuilderAppendString()
        {
            var src = @"
record struct C1(int P);
";
 
            var comp = CreateCompilation(src);
            comp.MakeMemberMissing(WellKnownMember.System_Text_StringBuilder__AppendString);
            comp.VerifyEmitDiagnostics(
                // (2,1): error CS0656: Missing compiler required member 'System.Text.StringBuilder.Append'
                // record struct C1(int P);
                Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "record struct C1(int P);").WithArguments("System.Text.StringBuilder", "Append").WithLocation(2, 1),
                // (2,1): error CS0656: Missing compiler required member 'System.Text.StringBuilder.Append'
                // record struct C1(int P);
                Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "record struct C1(int P);").WithArguments("System.Text.StringBuilder", "Append").WithLocation(2, 1)
                );
        }
 
        [Fact]
        public void ToString_RecordWithIndexer()
        {
            var src = @"
var c1 = new C1(42);
System.Console.Write(c1.ToString());
 
record struct C1(int I1)
{
    private int field = 44;
    public int this[int i] => 0;
    public int PropertyWithoutGetter { set { } }
    public int P2 { get => 43; }
    public event System.Action a = null;
 
    private int field1 = 100;
    internal int field2 = 100;
 
    private int Property1 { get; set; } = 100;
    internal int Property2 { get; set; } = 100;
}
";
 
            var comp = CreateCompilation(src);
            CompileAndVerify(comp, expectedOutput: "C1 { I1 = 42, P2 = 43 }");
            comp.VerifyEmitDiagnostics(
                // (7,17): warning CS0414: The field 'C1.field' is assigned but its value is never used
                //     private int field = 44;
                Diagnostic(ErrorCode.WRN_UnreferencedFieldAssg, "field").WithArguments("C1.field").WithLocation(7, 17),
                // (11,32): warning CS0414: The field 'C1.a' is assigned but its value is never used
                //     public event System.Action a = null;
                Diagnostic(ErrorCode.WRN_UnreferencedFieldAssg, "a").WithArguments("C1.a").WithLocation(11, 32),
                // (13,17): warning CS0414: The field 'C1.field1' is assigned but its value is never used
                //     private int field1 = 100;
                Diagnostic(ErrorCode.WRN_UnreferencedFieldAssg, "field1").WithArguments("C1.field1").WithLocation(13, 17)
                );
        }
 
        [Fact]
        public void ToString_PrivateGetter()
        {
            var src = @"
var c1 = new C1();
System.Console.Write(c1.ToString());
 
record struct C1
{
    public int P1 { private get => 43; set => throw null; }
}
";
 
            var comp = CreateCompilation(src);
            CompileAndVerify(comp, expectedOutput: "C1 { P1 = 43 }");
            comp.VerifyEmitDiagnostics();
        }
 
        [Fact]
        public void ToString_TopLevelRecord_OneField_ValueType()
        {
            var src = @"
var c1 = new C1() { field = 42 };
System.Console.Write(c1.ToString());
 
record struct C1
{
    public int field;
}
";
 
            var comp = CreateCompilation(src);
            comp.VerifyEmitDiagnostics();
            var v = CompileAndVerify(comp, expectedOutput: "C1 { field = 42 }");
 
            var print = comp.GetMember<MethodSymbol>("C1." + WellKnownMemberNames.PrintMembersMethodName);
            Assert.Equal(Accessibility.Private, print.DeclaredAccessibility);
            Assert.False(print.IsOverride);
            Assert.False(print.IsVirtual);
            Assert.False(print.IsAbstract);
            Assert.False(print.IsSealed);
            Assert.True(print.IsImplicitlyDeclared);
 
            var toString = comp.GetMember<MethodSymbol>("C1." + WellKnownMemberNames.ObjectToString);
            Assert.Equal(Accessibility.Public, toString.DeclaredAccessibility);
            Assert.True(toString.IsOverride);
            Assert.False(toString.IsVirtual);
            Assert.False(toString.IsAbstract);
            Assert.False(toString.IsSealed);
            Assert.True(toString.IsImplicitlyDeclared);
 
            v.VerifyIL("C1." + WellKnownMemberNames.PrintMembersMethodName, @"
{
  // Code size       41 (0x29)
  .maxstack  2
  .locals init (int V_0)
  IL_0000:  ldarg.1
  IL_0001:  ldstr      ""field = ""
  IL_0006:  callvirt   ""System.Text.StringBuilder System.Text.StringBuilder.Append(string)""
  IL_000b:  pop
  IL_000c:  ldarg.1
  IL_000d:  ldarg.0
  IL_000e:  ldfld      ""int C1.field""
  IL_0013:  stloc.0
  IL_0014:  ldloca.s   V_0
  IL_0016:  constrained. ""int""
  IL_001c:  callvirt   ""string object.ToString()""
  IL_0021:  callvirt   ""System.Text.StringBuilder System.Text.StringBuilder.Append(string)""
  IL_0026:  pop
  IL_0027:  ldc.i4.1
  IL_0028:  ret
}
");
        }
 
        [Fact]
        public void ToString_TopLevelRecord_OneField_ConstrainedValueType()
        {
            var src = @"
var c1 = new C1<int>() { field = 42 };
System.Console.Write(c1.ToString());
 
record struct C1<T> where T : struct
{
    public T field;
}
";
 
            var comp = CreateCompilation(src);
            comp.VerifyEmitDiagnostics();
            var v = CompileAndVerify(comp, expectedOutput: "C1 { field = 42 }");
 
            v.VerifyIL("C1<T>." + WellKnownMemberNames.PrintMembersMethodName, @"
{
  // Code size       41 (0x29)
  .maxstack  2
  .locals init (T V_0)
  IL_0000:  ldarg.1
  IL_0001:  ldstr      ""field = ""
  IL_0006:  callvirt   ""System.Text.StringBuilder System.Text.StringBuilder.Append(string)""
  IL_000b:  pop
  IL_000c:  ldarg.1
  IL_000d:  ldarg.0
  IL_000e:  ldfld      ""T C1<T>.field""
  IL_0013:  stloc.0
  IL_0014:  ldloca.s   V_0
  IL_0016:  constrained. ""T""
  IL_001c:  callvirt   ""string object.ToString()""
  IL_0021:  callvirt   ""System.Text.StringBuilder System.Text.StringBuilder.Append(string)""
  IL_0026:  pop
  IL_0027:  ldc.i4.1
  IL_0028:  ret
}
");
        }
 
        [Fact]
        public void ToString_TopLevelRecord_OneField_ReferenceType()
        {
            var src = @"
var c1 = new C1() { field = ""hello"" };
System.Console.Write(c1.ToString());
 
record struct C1
{
    public string field;
}
";
 
            var comp = CreateCompilation(src);
            comp.VerifyEmitDiagnostics();
            var v = CompileAndVerify(comp, expectedOutput: "C1 { field = hello }");
 
            v.VerifyIL("C1." + WellKnownMemberNames.PrintMembersMethodName, @"
{
  // Code size       27 (0x1b)
  .maxstack  2
  IL_0000:  ldarg.1
  IL_0001:  ldstr      ""field = ""
  IL_0006:  callvirt   ""System.Text.StringBuilder System.Text.StringBuilder.Append(string)""
  IL_000b:  pop
  IL_000c:  ldarg.1
  IL_000d:  ldarg.0
  IL_000e:  ldfld      ""string C1.field""
  IL_0013:  callvirt   ""System.Text.StringBuilder System.Text.StringBuilder.Append(object)""
  IL_0018:  pop
  IL_0019:  ldc.i4.1
  IL_001a:  ret
}
");
        }
 
        [Fact]
        public void ToString_TopLevelRecord_TwoFields_ReferenceType()
        {
            var src = @"
var c1 = new C1(42) { field1 = ""hi"", field2 = null };
System.Console.Write(c1.ToString());
 
record struct C1(int I)
{
    public string field1 = null;
    public string field2 = null;
 
    private string field3 = null;
    internal string field4 = null;
}
";
 
            var comp = CreateCompilation(src);
            comp.VerifyEmitDiagnostics(
                // (10,20): warning CS0414: The field 'C1.field3' is assigned but its value is never used
                //     private string field3 = null;
                Diagnostic(ErrorCode.WRN_UnreferencedFieldAssg, "field3").WithArguments("C1.field3").WithLocation(10, 20)
                );
            var v = CompileAndVerify(comp, expectedOutput: "C1 { I = 42, field1 = hi, field2 =  }");
 
            v.VerifyIL("C1." + WellKnownMemberNames.PrintMembersMethodName, @"
{
  // Code size       91 (0x5b)
  .maxstack  2
  .locals init (int V_0)
  IL_0000:  ldarg.1
  IL_0001:  ldstr      ""I = ""
  IL_0006:  callvirt   ""System.Text.StringBuilder System.Text.StringBuilder.Append(string)""
  IL_000b:  pop
  IL_000c:  ldarg.1
  IL_000d:  ldarg.0
  IL_000e:  call       ""readonly int C1.I.get""
  IL_0013:  stloc.0
  IL_0014:  ldloca.s   V_0
  IL_0016:  constrained. ""int""
  IL_001c:  callvirt   ""string object.ToString()""
  IL_0021:  callvirt   ""System.Text.StringBuilder System.Text.StringBuilder.Append(string)""
  IL_0026:  pop
  IL_0027:  ldarg.1
  IL_0028:  ldstr      "", field1 = ""
  IL_002d:  callvirt   ""System.Text.StringBuilder System.Text.StringBuilder.Append(string)""
  IL_0032:  pop
  IL_0033:  ldarg.1
  IL_0034:  ldarg.0
  IL_0035:  ldfld      ""string C1.field1""
  IL_003a:  callvirt   ""System.Text.StringBuilder System.Text.StringBuilder.Append(object)""
  IL_003f:  pop
  IL_0040:  ldarg.1
  IL_0041:  ldstr      "", field2 = ""
  IL_0046:  callvirt   ""System.Text.StringBuilder System.Text.StringBuilder.Append(string)""
  IL_004b:  pop
  IL_004c:  ldarg.1
  IL_004d:  ldarg.0
  IL_004e:  ldfld      ""string C1.field2""
  IL_0053:  callvirt   ""System.Text.StringBuilder System.Text.StringBuilder.Append(object)""
  IL_0058:  pop
  IL_0059:  ldc.i4.1
  IL_005a:  ret
}
");
        }
 
        [Fact]
        public void ToString_TopLevelRecord_Readonly()
        {
            var src = @"
var c1 = new C1(42);
System.Console.Write(c1.ToString());
 
readonly record struct C1(int I);
";
 
            var comp = CreateCompilation(src);
            comp.VerifyDiagnostics();
            var v = CompileAndVerify(comp, expectedOutput: "C1 { I = 42 }", verify: Verification.Skipped /* init-only */);
 
            v.VerifyIL("C1." + WellKnownMemberNames.PrintMembersMethodName, @"
{
  // Code size       41 (0x29)
  .maxstack  2
  .locals init (int V_0)
  IL_0000:  ldarg.1
  IL_0001:  ldstr      ""I = ""
  IL_0006:  callvirt   ""System.Text.StringBuilder System.Text.StringBuilder.Append(string)""
  IL_000b:  pop
  IL_000c:  ldarg.1
  IL_000d:  ldarg.0
  IL_000e:  call       ""int C1.I.get""
  IL_0013:  stloc.0
  IL_0014:  ldloca.s   V_0
  IL_0016:  constrained. ""int""
  IL_001c:  callvirt   ""string object.ToString()""
  IL_0021:  callvirt   ""System.Text.StringBuilder System.Text.StringBuilder.Append(string)""
  IL_0026:  pop
  IL_0027:  ldc.i4.1
  IL_0028:  ret
}
");
            v.VerifyIL("C1." + WellKnownMemberNames.ObjectToString, @"
{
  // Code size       64 (0x40)
  .maxstack  2
  .locals init (System.Text.StringBuilder V_0)
  IL_0000:  newobj     ""System.Text.StringBuilder..ctor()""
  IL_0005:  stloc.0
  IL_0006:  ldloc.0
  IL_0007:  ldstr      ""C1""
  IL_000c:  callvirt   ""System.Text.StringBuilder System.Text.StringBuilder.Append(string)""
  IL_0011:  pop
  IL_0012:  ldloc.0
  IL_0013:  ldstr      "" { ""
  IL_0018:  callvirt   ""System.Text.StringBuilder System.Text.StringBuilder.Append(string)""
  IL_001d:  pop
  IL_001e:  ldarg.0
  IL_001f:  ldloc.0
  IL_0020:  call       ""bool C1.PrintMembers(System.Text.StringBuilder)""
  IL_0025:  brfalse.s  IL_0030
  IL_0027:  ldloc.0
  IL_0028:  ldc.i4.s   32
  IL_002a:  callvirt   ""System.Text.StringBuilder System.Text.StringBuilder.Append(char)""
  IL_002f:  pop
  IL_0030:  ldloc.0
  IL_0031:  ldc.i4.s   125
  IL_0033:  callvirt   ""System.Text.StringBuilder System.Text.StringBuilder.Append(char)""
  IL_0038:  pop
  IL_0039:  ldloc.0
  IL_003a:  callvirt   ""string object.ToString()""
  IL_003f:  ret
}
");
        }
 
        [Fact]
        public void ToString_TopLevelRecord_UserDefinedToString()
        {
            var src = @"
var c1 = new C1();
System.Console.Write(c1.ToString());
 
record struct C1
{
    public override string ToString() => ""RAN"";
}
";
 
            var comp = CreateCompilation(src);
            comp.VerifyEmitDiagnostics();
            CompileAndVerify(comp, expectedOutput: "RAN");
 
            var print = comp.GetMember<MethodSymbol>("C1." + WellKnownMemberNames.PrintMembersMethodName);
            Assert.Equal("readonly System.Boolean C1." + WellKnownMemberNames.PrintMembersMethodName + "(System.Text.StringBuilder builder)", print.ToTestDisplayString());
        }
 
        [Fact]
        public void ToString_TopLevelRecord_UserDefinedToString_New()
        {
            var src = @"
record struct C1
{
    public new string ToString() => throw null;
}
";
 
            var comp = CreateCompilation(src);
            comp.VerifyEmitDiagnostics(
                // (4,23): error CS8869: 'C1.ToString()' does not override expected method from 'object'.
                //     public new string ToString() => throw null;
                Diagnostic(ErrorCode.ERR_DoesNotOverrideMethodFromObject, "ToString").WithArguments("C1.ToString()").WithLocation(4, 23)
                );
        }
 
        [Fact]
        public void ToString_TopLevelRecord_UserDefinedToString_Sealed()
        {
            var src = @"
record struct C1
{
    public sealed override string ToString() => throw null;
}
";
 
            var comp = CreateCompilation(src);
            comp.VerifyEmitDiagnostics(
                // (4,35): error CS0106: The modifier 'sealed' is not valid for this item
                //     public sealed override string ToString() => throw null;
                Diagnostic(ErrorCode.ERR_BadMemberFlag, "ToString").WithArguments("sealed").WithLocation(4, 35)
                );
        }
 
        [Fact]
        public void ToString_UserDefinedPrintMembers_WithNullableStringBuilder()
        {
            var src = @"
#nullable enable
record struct C1
{
    private bool PrintMembers(System.Text.StringBuilder? builder) => throw null!;
}
";
            var comp = CreateCompilation(src);
            comp.VerifyEmitDiagnostics();
        }
 
        [Fact]
        public void ToString_UserDefinedPrintMembers_ErrorReturnType()
        {
            var src = @"
record struct C1
{
    private Error PrintMembers(System.Text.StringBuilder builder) => throw null;
}
";
            var comp = CreateCompilation(src);
            comp.VerifyEmitDiagnostics(
                // (4,13): error CS0246: The type or namespace name 'Error' could not be found (are you missing a using directive or an assembly reference?)
                //     private Error PrintMembers(System.Text.StringBuilder builder) => throw null;
                Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "Error").WithArguments("Error").WithLocation(4, 13)
                );
        }
 
        [Fact]
        public void ToString_UserDefinedPrintMembers_WrongReturnType()
        {
            var src = @"
record struct C1
{
    private int PrintMembers(System.Text.StringBuilder builder) => throw null;
}
";
            var comp = CreateCompilation(src);
            comp.VerifyEmitDiagnostics(
                // (4,17): error CS8874: Record member 'C1.PrintMembers(StringBuilder)' must return 'bool'.
                //     private int PrintMembers(System.Text.StringBuilder builder) => throw null;
                Diagnostic(ErrorCode.ERR_SignatureMismatchInRecord, "PrintMembers").WithArguments("C1.PrintMembers(System.Text.StringBuilder)", "bool").WithLocation(4, 17)
                );
        }
 
        [Fact]
        public void ToString_UserDefinedPrintMembers()
        {
            var src = @"
var c1 = new C1();
System.Console.Write(c1.ToString());
System.Console.Write("" - "");
c1.M();
 
record struct C1
{
    private bool PrintMembers(System.Text.StringBuilder builder)
    {
        builder.Append(""RAN"");
        return true;
    }
 
    public void M()
    {
        var builder = new System.Text.StringBuilder();
        if (PrintMembers(builder))
        {
            System.Console.Write(builder.ToString());
        }
    }
}
";
 
            var comp = CreateCompilation(src);
            comp.VerifyEmitDiagnostics();
            CompileAndVerify(comp, expectedOutput: "C1 { RAN } - RAN");
        }
 
        [Fact]
        public void ToString_CallingSynthesizedPrintMembers()
        {
            var src = @"
var c1 = new C1(1, 2, 3);
System.Console.Write(c1.ToString());
System.Console.Write("" - "");
c1.M();
 
record struct C1(int I, int I2, int I3)
{
    public void M()
    {
        var builder = new System.Text.StringBuilder();
        if (PrintMembers(builder))
        {
            System.Console.Write(builder.ToString());
        }
    }
}
";
 
            var comp = CreateCompilation(src);
            comp.VerifyEmitDiagnostics();
            CompileAndVerify(comp, expectedOutput: "C1 { I = 1, I2 = 2, I3 = 3 } - I = 1, I2 = 2, I3 = 3");
        }
 
        [Fact]
        public void ToString_UserDefinedPrintMembers_WrongAccessibility()
        {
            var src = @"
var c = new C1();
System.Console.Write(c.ToString());
 
record struct C1
{
    internal bool PrintMembers(System.Text.StringBuilder builder) => throw null;
}
";
 
            var comp = CreateCompilation(src);
            comp.VerifyEmitDiagnostics(
                // (7,19): error CS8879: Record member 'C1.PrintMembers(StringBuilder)' must be private.
                //     internal bool PrintMembers(System.Text.StringBuilder builder) => throw null;
                Diagnostic(ErrorCode.ERR_NonPrivateAPIInRecord, "PrintMembers").WithArguments("C1.PrintMembers(System.Text.StringBuilder)").WithLocation(7, 19)
                );
        }
 
        [Fact]
        public void ToString_UserDefinedPrintMembers_Static()
        {
            var src = @"
record struct C1
{
    static private bool PrintMembers(System.Text.StringBuilder builder) => throw null;
}
";
 
            var comp = CreateCompilation(src);
            comp.VerifyEmitDiagnostics(
                // (4,25): error CS8877: Record member 'C1.PrintMembers(StringBuilder)' may not be static.
                //     static private bool PrintMembers(System.Text.StringBuilder builder) => throw null;
                Diagnostic(ErrorCode.ERR_StaticAPIInRecord, "PrintMembers").WithArguments("C1.PrintMembers(System.Text.StringBuilder)").WithLocation(4, 25)
                );
        }
 
        [Fact]
        public void ToString_GeneratedAsReadOnly()
        {
            var src = @"
record struct A(int I, string S);
";
            var comp = CreateCompilation(src);
            comp.VerifyDiagnostics();
            var method = comp.GetMember<SynthesizedRecordToString>("A.ToString");
            Assert.True(method.IsDeclaredReadOnly);
        }
 
        [Fact]
        public void ToString_WihtNonReadOnlyGetter_GeneratedAsNonReadOnly()
        {
            var src = @"
record struct A(int I, string S)
{
    public double T => 0.1;
}
";
            var comp = CreateCompilation(src);
            comp.VerifyDiagnostics();
            var method = comp.GetMember<SynthesizedRecordToString>("A.ToString");
            Assert.False(method.IsDeclaredReadOnly);
        }
 
        [Fact]
        public void AmbigCtor_WithPropertyInitializer()
        {
            // Scenario causes ambiguous ctor for record class, but not record struct
            var src = @"
record struct R(R X)
{
    public R X { get; init; } = X;
}
";
            var comp = CreateCompilation(src);
            comp.VerifyEmitDiagnostics(
                // (4,14): error CS0523: Struct member 'R.X' of type 'R' causes a cycle in the struct layout
                //     public R X { get; init; } = X;
                Diagnostic(ErrorCode.ERR_StructLayoutCycle, "X").WithArguments("R.X", "R").WithLocation(4, 14)
                );
 
            var tree = comp.SyntaxTrees[0];
            var model = comp.GetSemanticModel(tree, ignoreAccessibility: false);
            var parameterSyntax = tree.GetRoot().DescendantNodes().OfType<ParameterSyntax>().Single();
            var parameter = model.GetDeclaredSymbol(parameterSyntax)!;
            Assert.Equal("R X", parameter.ToTestDisplayString());
            Assert.Equal(SymbolKind.Parameter, parameter.Kind);
            Assert.Equal("R..ctor(R X)", parameter.ContainingSymbol.ToTestDisplayString());
 
            var initializerSyntax = tree.GetRoot().DescendantNodes().OfType<EqualsValueClauseSyntax>().Single();
            var initializer = model.GetSymbolInfo(initializerSyntax.Value).Symbol!;
            Assert.Equal("R X", initializer.ToTestDisplayString());
            Assert.Equal(SymbolKind.Parameter, initializer.Kind);
            Assert.Equal("R..ctor(R X)", initializer.ContainingSymbol.ToTestDisplayString());
 
            var src2 = @"
record struct R(R X);
";
            var comp2 = CreateCompilation(src2);
            comp2.VerifyEmitDiagnostics(
                // (2,19): error CS0523: Struct member 'R.X' of type 'R' causes a cycle in the struct layout
                // record struct R(R X);
                Diagnostic(ErrorCode.ERR_StructLayoutCycle, "X").WithArguments("R.X", "R").WithLocation(2, 19)
                );
        }
 
        [Fact]
        public void GetDeclaredSymbolOnAnOutLocalInPropertyInitializer()
        {
            var src = @"
record struct R(int I)
{
    public int I { get; init; } = M(out int i);
    static int M(out int i) => throw null;
}
";
            var comp = CreateCompilation(src);
            comp.VerifyEmitDiagnostics(
                // (2,21): warning CS8907: Parameter 'I' is unread. Did you forget to use it to initialize the property with that name?
                // record struct R(int I)
                Diagnostic(ErrorCode.WRN_UnreadRecordParameter, "I").WithArguments("I").WithLocation(2, 21)
                );
 
            var tree = comp.SyntaxTrees[0];
            var model = comp.GetSemanticModel(tree, ignoreAccessibility: false);
            var outVarSyntax = tree.GetRoot().DescendantNodes().OfType<SingleVariableDesignationSyntax>().Single();
            var outVar = model.GetDeclaredSymbol(outVarSyntax)!;
            Assert.Equal("System.Int32 i", outVar.ToTestDisplayString());
            Assert.Equal(SymbolKind.Local, outVar.Kind);
            Assert.Equal("System.Int32 R.<I>k__BackingField", outVar.ContainingSymbol.ToTestDisplayString());
        }
 
        [Fact]
        public void AnalyzerActions_01()
        {
            // Test RegisterSyntaxNodeAction
            var text1 = @"
record struct A([Attr1]int X = 0) : I1
{
    private int M() => 3;
    A(string S) : this(4) => throw null;
}
 
interface I1 {}
 
class Attr1 : System.Attribute {}
";
            var analyzer = new AnalyzerActions_01_Analyzer();
            var comp = CreateCompilation(text1);
            comp.GetAnalyzerDiagnostics(new[] { analyzer }, null).Verify();
 
            Assert.Equal(1, analyzer.FireCount0);
            Assert.Equal(1, analyzer.FireCountRecordStructDeclarationA);
            Assert.Equal(1, analyzer.FireCount3);
            Assert.Equal(1, analyzer.FireCountSimpleBaseTypeI1onA);
            Assert.Equal(1, analyzer.FireCount5);
            Assert.Equal(1, analyzer.FireCountParameterListAPrimaryCtor);
            Assert.Equal(1, analyzer.FireCount7);
            Assert.Equal(1, analyzer.FireCountConstructorDeclaration);
            Assert.Equal(1, analyzer.FireCountStringParameterList);
            Assert.Equal(1, analyzer.FireCountThisConstructorInitializer);
            Assert.Equal(1, analyzer.FireCount11);
            Assert.Equal(1, analyzer.FireCount12);
        }
 
        private class AnalyzerActions_01_Analyzer : DiagnosticAnalyzer
        {
            public int FireCount0;
            public int FireCountRecordStructDeclarationA;
            public int FireCount3;
            public int FireCountSimpleBaseTypeI1onA;
            public int FireCount5;
            public int FireCountParameterListAPrimaryCtor;
            public int FireCount7;
            public int FireCountConstructorDeclaration;
            public int FireCountStringParameterList;
            public int FireCountThisConstructorInitializer;
            public int FireCount11;
            public int FireCount12;
 
            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(Handle1, SyntaxKind.NumericLiteralExpression);
                context.RegisterSyntaxNodeAction(Handle2, SyntaxKind.EqualsValueClause);
                context.RegisterSyntaxNodeAction(Fail, SyntaxKind.BaseConstructorInitializer);
                context.RegisterSyntaxNodeAction(Handle3, SyntaxKind.ThisConstructorInitializer);
                context.RegisterSyntaxNodeAction(Handle4, SyntaxKind.ConstructorDeclaration);
                context.RegisterSyntaxNodeAction(Fail, SyntaxKind.PrimaryConstructorBaseType);
                context.RegisterSyntaxNodeAction(Handle6, SyntaxKind.RecordStructDeclaration);
                context.RegisterSyntaxNodeAction(Handle7, SyntaxKind.IdentifierName);
                context.RegisterSyntaxNodeAction(Handle8, SyntaxKind.SimpleBaseType);
                context.RegisterSyntaxNodeAction(Handle9, SyntaxKind.ParameterList);
                context.RegisterSyntaxNodeAction(Handle10, SyntaxKind.ArgumentList);
            }
 
            protected void Handle1(SyntaxNodeAnalysisContext context)
            {
                var literal = (LiteralExpressionSyntax)context.Node;
 
                switch (literal.ToString())
                {
                    case "0":
                        Interlocked.Increment(ref FireCount0);
                        Assert.Equal("A..ctor([System.Int32 X = 0])", context.ContainingSymbol.ToTestDisplayString());
                        break;
                    case "3":
                        Interlocked.Increment(ref FireCount7);
                        Assert.Equal("System.Int32 A.M()", context.ContainingSymbol.ToTestDisplayString());
                        break;
                    case "4":
                        Interlocked.Increment(ref FireCount12);
                        Assert.Equal("A..ctor(System.String S)", context.ContainingSymbol.ToTestDisplayString());
                        break;
                    default:
                        Assert.True(false);
                        break;
                }
 
                Assert.Same(literal.SyntaxTree, context.ContainingSymbol!.DeclaringSyntaxReferences.Single().SyntaxTree);
            }
 
            protected void Handle2(SyntaxNodeAnalysisContext context)
            {
                var equalsValue = (EqualsValueClauseSyntax)context.Node;
 
                switch (equalsValue.ToString())
                {
                    case "= 0":
                        Interlocked.Increment(ref FireCount3);
                        Assert.Equal("A..ctor([System.Int32 X = 0])", context.ContainingSymbol.ToTestDisplayString());
                        break;
                    default:
                        Assert.True(false);
                        break;
                }
 
                Assert.Same(equalsValue.SyntaxTree, context.ContainingSymbol!.DeclaringSyntaxReferences.Single().SyntaxTree);
            }
 
            protected void Handle3(SyntaxNodeAnalysisContext context)
            {
                var initializer = (ConstructorInitializerSyntax)context.Node;
 
                switch (initializer.ToString())
                {
                    case ": this(4)":
                        Interlocked.Increment(ref FireCountThisConstructorInitializer);
                        Assert.Equal("A..ctor(System.String S)", context.ContainingSymbol.ToTestDisplayString());
                        break;
                    default:
                        Assert.True(false);
                        break;
                }
 
                Assert.Same(initializer.SyntaxTree, context.ContainingSymbol!.DeclaringSyntaxReferences.Single().SyntaxTree);
            }
 
            protected void Handle4(SyntaxNodeAnalysisContext context)
            {
                Interlocked.Increment(ref FireCountConstructorDeclaration);
                Assert.Equal("A..ctor(System.String S)", context.ContainingSymbol.ToTestDisplayString());
            }
 
            protected void Fail(SyntaxNodeAnalysisContext context)
            {
                Assert.True(false);
            }
 
            protected void Handle6(SyntaxNodeAnalysisContext context)
            {
                var record = (RecordDeclarationSyntax)context.Node;
                Assert.Equal(SyntaxKind.RecordStructDeclaration, record.Kind());
 
                switch (context.ContainingSymbol.ToTestDisplayString())
                {
                    case "A":
                        Interlocked.Increment(ref FireCountRecordStructDeclarationA);
                        break;
                    default:
                        Assert.True(false);
                        break;
                }
 
                Assert.Same(record.SyntaxTree, context.ContainingSymbol!.DeclaringSyntaxReferences.Single().SyntaxTree);
            }
 
            protected void Handle7(SyntaxNodeAnalysisContext context)
            {
                var identifier = (IdentifierNameSyntax)context.Node;
 
                switch (identifier.Identifier.ValueText)
                {
                    case "Attr1":
                        Interlocked.Increment(ref FireCount5);
                        Assert.Equal("A..ctor([System.Int32 X = 0])", context.ContainingSymbol.ToTestDisplayString());
                        break;
                }
            }
 
            protected void Handle8(SyntaxNodeAnalysisContext context)
            {
                var baseType = (SimpleBaseTypeSyntax)context.Node;
 
                switch (baseType.ToString())
                {
                    case "I1":
                        switch (context.ContainingSymbol.ToTestDisplayString())
                        {
                            case "A":
                                Interlocked.Increment(ref FireCountSimpleBaseTypeI1onA);
                                break;
                            default:
                                Assert.True(false);
                                break;
                        }
                        break;
 
                    case "System.Attribute":
                        break;
 
                    default:
                        Assert.True(false);
                        break;
                }
            }
 
            protected void Handle9(SyntaxNodeAnalysisContext context)
            {
                var parameterList = (ParameterListSyntax)context.Node;
 
                switch (parameterList.ToString())
                {
                    case "([Attr1]int X = 0)":
                        Interlocked.Increment(ref FireCountParameterListAPrimaryCtor);
                        Assert.Equal("A..ctor([System.Int32 X = 0])", context.ContainingSymbol.ToTestDisplayString());
                        break;
                    case "(string S)":
                        Interlocked.Increment(ref FireCountStringParameterList);
                        Assert.Equal("A..ctor(System.String S)", context.ContainingSymbol.ToTestDisplayString());
                        break;
                    case "()":
                        break;
                    default:
                        Assert.True(false);
                        break;
                }
            }
 
            protected void Handle10(SyntaxNodeAnalysisContext context)
            {
                var argumentList = (ArgumentListSyntax)context.Node;
 
                switch (argumentList.ToString())
                {
                    case "(4)":
                        Interlocked.Increment(ref FireCount11);
                        Assert.Equal("A..ctor(System.String S)", context.ContainingSymbol.ToTestDisplayString());
                        break;
                    default:
                        Assert.True(false);
                        break;
                }
            }
        }
 
        [Fact]
        public void AnalyzerActions_02()
        {
            // Test RegisterSymbolAction
            var text1 = @"
record struct A(int X = 0)
{}
 
record struct C
{
    C(int Z = 4)
    {}
}
";
 
            var analyzer = new AnalyzerActions_02_Analyzer();
            var comp = CreateCompilation(text1);
            comp.GetAnalyzerDiagnostics(new[] { analyzer }, null).Verify();
 
            Assert.Equal(1, analyzer.FireCount1);
            Assert.Equal(1, analyzer.FireCount2);
            Assert.Equal(1, analyzer.FireCount3);
            Assert.Equal(1, analyzer.FireCount4);
            Assert.Equal(1, analyzer.FireCount5);
            Assert.Equal(1, analyzer.FireCount6);
            Assert.Equal(1, analyzer.FireCount7);
        }
 
        private class AnalyzerActions_02_Analyzer : DiagnosticAnalyzer
        {
            public int FireCount1;
            public int FireCount2;
            public int FireCount3;
            public int FireCount4;
            public int FireCount5;
            public int FireCount6;
            public int FireCount7;
 
            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.RegisterSymbolAction(Handle, SymbolKind.Method);
                context.RegisterSymbolAction(Handle, SymbolKind.Property);
                context.RegisterSymbolAction(Handle, SymbolKind.Parameter);
                context.RegisterSymbolAction(Handle, SymbolKind.NamedType);
            }
 
            private void Handle(SymbolAnalysisContext context)
            {
                switch (context.Symbol.ToTestDisplayString())
                {
                    case "A..ctor([System.Int32 X = 0])":
                        Interlocked.Increment(ref FireCount1);
                        break;
                    case "System.Int32 A.X { get; set; }":
                        Interlocked.Increment(ref FireCount2);
                        break;
                    case "[System.Int32 X = 0]":
                        Interlocked.Increment(ref FireCount3);
                        break;
                    case "C..ctor([System.Int32 Z = 4])":
                        Interlocked.Increment(ref FireCount4);
                        break;
                    case "[System.Int32 Z = 4]":
                        Interlocked.Increment(ref FireCount5);
                        break;
                    case "A":
                        Interlocked.Increment(ref FireCount6);
                        break;
                    case "C":
                        Interlocked.Increment(ref FireCount7);
                        break;
                    case "System.Runtime.CompilerServices.IsExternalInit":
                        break;
                    default:
                        Assert.True(false);
                        break;
                }
            }
        }
 
        [Fact]
        public void AnalyzerActions_03()
        {
            // Test RegisterSymbolStartAction
            var text1 = @"
readonly record struct A(int X = 0)
{}
 
readonly record struct C
{
    C(int Z = 4)
    {}
}
";
 
            var analyzer = new AnalyzerActions_03_Analyzer();
            var comp = CreateCompilation(text1);
            comp.GetAnalyzerDiagnostics(new[] { analyzer }, null).Verify();
 
            Assert.Equal(1, analyzer.FireCount1);
            Assert.Equal(1, analyzer.FireCount2);
            Assert.Equal(0, analyzer.FireCount3);
            Assert.Equal(1, analyzer.FireCount4);
            Assert.Equal(0, analyzer.FireCount5);
            Assert.Equal(1, analyzer.FireCount6);
            Assert.Equal(1, analyzer.FireCount7);
            Assert.Equal(1, analyzer.FireCount8);
            Assert.Equal(1, analyzer.FireCount9);
            Assert.Equal(1, analyzer.FireCount10);
            Assert.Equal(1, analyzer.FireCount11);
            Assert.Equal(1, analyzer.FireCount12);
        }
 
        private class AnalyzerActions_03_Analyzer : DiagnosticAnalyzer
        {
            public int FireCount1;
            public int FireCount2;
            public int FireCount3;
            public int FireCount4;
            public int FireCount5;
            public int FireCount6;
            public int FireCount7;
            public int FireCount8;
            public int FireCount9;
            public int FireCount10;
            public int FireCount11;
            public int FireCount12;
 
            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.RegisterSymbolStartAction(Handle1, SymbolKind.Method);
                context.RegisterSymbolStartAction(Handle1, SymbolKind.Property);
                context.RegisterSymbolStartAction(Handle1, SymbolKind.Parameter);
                context.RegisterSymbolStartAction(Handle1, SymbolKind.NamedType);
            }
 
            private void Handle1(SymbolStartAnalysisContext context)
            {
                switch (context.Symbol.ToTestDisplayString())
                {
                    case "A..ctor([System.Int32 X = 0])":
                        Interlocked.Increment(ref FireCount1);
                        context.RegisterSymbolEndAction(Handle2);
                        break;
                    case "System.Int32 A.X { get; init; }":
                        Interlocked.Increment(ref FireCount2);
                        context.RegisterSymbolEndAction(Handle3);
                        break;
                    case "[System.Int32 X = 0]":
                        Interlocked.Increment(ref FireCount3);
                        break;
                    case "C..ctor([System.Int32 Z = 4])":
                        Interlocked.Increment(ref FireCount4);
                        context.RegisterSymbolEndAction(Handle4);
                        break;
                    case "[System.Int32 Z = 4]":
                        Interlocked.Increment(ref FireCount5);
                        break;
                    case "A":
                        Interlocked.Increment(ref FireCount9);
 
                        Assert.Equal(0, FireCount1);
                        Assert.Equal(0, FireCount2);
                        Assert.Equal(0, FireCount6);
                        Assert.Equal(0, FireCount7);
 
                        context.RegisterSymbolEndAction(Handle5);
                        break;
                    case "C":
                        Interlocked.Increment(ref FireCount10);
 
                        Assert.Equal(0, FireCount4);
                        Assert.Equal(0, FireCount8);
 
                        context.RegisterSymbolEndAction(Handle6);
                        break;
                    case "System.Runtime.CompilerServices.IsExternalInit":
                        break;
                    default:
                        Assert.True(false);
                        break;
                }
            }
 
            private void Handle2(SymbolAnalysisContext context)
            {
                Assert.Equal("A..ctor([System.Int32 X = 0])", context.Symbol.ToTestDisplayString());
                Interlocked.Increment(ref FireCount6);
            }
 
            private void Handle3(SymbolAnalysisContext context)
            {
                Assert.Equal("System.Int32 A.X { get; init; }", context.Symbol.ToTestDisplayString());
                Interlocked.Increment(ref FireCount7);
            }
 
            private void Handle4(SymbolAnalysisContext context)
            {
                Assert.Equal("C..ctor([System.Int32 Z = 4])", context.Symbol.ToTestDisplayString());
                Interlocked.Increment(ref FireCount8);
            }
 
            private void Handle5(SymbolAnalysisContext context)
            {
                Assert.Equal("A", context.Symbol.ToTestDisplayString());
                Interlocked.Increment(ref FireCount11);
 
                Assert.Equal(1, FireCount1);
                Assert.Equal(1, FireCount2);
                Assert.Equal(1, FireCount6);
                Assert.Equal(1, FireCount7);
            }
 
            private void Handle6(SymbolAnalysisContext context)
            {
                Assert.Equal("C", context.Symbol.ToTestDisplayString());
                Interlocked.Increment(ref FireCount12);
 
                Assert.Equal(1, FireCount4);
                Assert.Equal(1, FireCount8);
            }
        }
 
        [Fact]
        public void AnalyzerActions_04()
        {
            // Test RegisterOperationAction
            var text1 = @"
record struct A([Attr1(100)]int X = 0) : I1
{}
 
interface I1 {}
";
 
            var analyzer = new AnalyzerActions_04_Analyzer();
            var comp = CreateCompilation(text1);
            comp.GetAnalyzerDiagnostics(new[] { analyzer }, null).Verify();
 
            Assert.Equal(0, analyzer.FireCount1);
            Assert.Equal(1, analyzer.FireCount6);
            Assert.Equal(1, analyzer.FireCount7);
            Assert.Equal(1, analyzer.FireCount14);
        }
 
        private class AnalyzerActions_04_Analyzer : DiagnosticAnalyzer
        {
            public int FireCount1;
            public int FireCount6;
            public int FireCount7;
            public int FireCount14;
 
            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.RegisterOperationAction(HandleConstructorBody, OperationKind.ConstructorBody);
                context.RegisterOperationAction(HandleInvocation, OperationKind.Invocation);
                context.RegisterOperationAction(HandleLiteral, OperationKind.Literal);
                context.RegisterOperationAction(HandleParameterInitializer, OperationKind.ParameterInitializer);
                context.RegisterOperationAction(Fail, OperationKind.PropertyInitializer);
                context.RegisterOperationAction(Fail, OperationKind.FieldInitializer);
            }
 
            protected void HandleConstructorBody(OperationAnalysisContext context)
            {
                switch (context.ContainingSymbol.ToTestDisplayString())
                {
                    case "A..ctor([System.Int32 X = 0])":
                        Interlocked.Increment(ref FireCount1);
                        Assert.Equal(SyntaxKind.RecordDeclaration, context.Operation.Syntax.Kind());
                        VerifyOperationTree((CSharpCompilation)context.Compilation, context.Operation, @"");
 
                        break;
                    default:
                        Assert.True(false);
                        break;
                }
            }
 
            protected void HandleInvocation(OperationAnalysisContext context)
            {
                Assert.True(false);
            }
 
            protected void HandleLiteral(OperationAnalysisContext context)
            {
                switch (context.Operation.Syntax.ToString())
                {
                    case "100":
                        Assert.Equal("A..ctor([System.Int32 X = 0])", context.ContainingSymbol.ToTestDisplayString());
                        Interlocked.Increment(ref FireCount6);
                        break;
                    case "0":
                        Assert.Equal("A..ctor([System.Int32 X = 0])", context.ContainingSymbol.ToTestDisplayString());
                        Interlocked.Increment(ref FireCount7);
                        break;
                    default:
                        Assert.True(false);
                        break;
                }
            }
 
            protected void HandleParameterInitializer(OperationAnalysisContext context)
            {
                switch (context.Operation.Syntax.ToString())
                {
                    case "= 0":
                        Assert.Equal("A..ctor([System.Int32 X = 0])", context.ContainingSymbol.ToTestDisplayString());
                        Interlocked.Increment(ref FireCount14);
                        break;
                    default:
                        Assert.True(false);
                        break;
                }
            }
 
            protected void Fail(OperationAnalysisContext context)
            {
                Assert.True(false);
            }
        }
 
        [Fact]
        public void AnalyzerActions_05()
        {
            // Test RegisterOperationBlockAction
            var text1 = @"
record struct A([Attr1(100)]int X = 0) : I1
{}
 
interface I1 {}
";
 
            var analyzer = new AnalyzerActions_05_Analyzer();
            var comp = CreateCompilation(text1);
            comp.GetAnalyzerDiagnostics(new[] { analyzer }, null).Verify();
 
            Assert.Equal(1, analyzer.FireCount1);
        }
 
        private class AnalyzerActions_05_Analyzer : DiagnosticAnalyzer
        {
            public int FireCount1;
 
            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.RegisterOperationBlockAction(Handle);
            }
 
            private void Handle(OperationBlockAnalysisContext context)
            {
                switch (context.OwningSymbol.ToTestDisplayString())
                {
                    case "A..ctor([System.Int32 X = 0])":
                        Interlocked.Increment(ref FireCount1);
                        Assert.Equal(2, context.OperationBlocks.Length);
 
                        Assert.Equal(OperationKind.ParameterInitializer, context.OperationBlocks[0].Kind);
                        Assert.Equal("= 0", context.OperationBlocks[0].Syntax.ToString());
 
                        Assert.Equal(OperationKind.Attribute, context.OperationBlocks[1].Kind);
                        Assert.Equal("Attr1(100)", context.OperationBlocks[1].Syntax.ToString());
 
                        break;
                    default:
                        Assert.True(false);
                        break;
                }
            }
        }
 
        [Fact]
        public void AnalyzerActions_07()
        {
            // Test RegisterCodeBlockAction
            var text1 = @"
record struct A([Attr1(100)]int X = 0) : I1
{
    int M() => 3;
}
 
interface I1 {}
";
            var analyzer = new AnalyzerActions_07_Analyzer();
            var comp = CreateCompilation(text1);
            comp.GetAnalyzerDiagnostics(new[] { analyzer }, null).Verify();
 
            Assert.Equal(1, analyzer.FireCount1);
            Assert.Equal(1, analyzer.FireCount4);
        }
 
        private class AnalyzerActions_07_Analyzer : DiagnosticAnalyzer
        {
            public int FireCount1;
            public int FireCount4;
 
            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.RegisterCodeBlockAction(Handle);
            }
 
            private void Handle(CodeBlockAnalysisContext context)
            {
                switch (context.OwningSymbol.ToTestDisplayString())
                {
                    case "A..ctor([System.Int32 X = 0])":
 
                        switch (context.CodeBlock)
                        {
                            case RecordDeclarationSyntax { Identifier: { ValueText: "A" } }:
                                Interlocked.Increment(ref FireCount1);
                                break;
                            default:
                                Assert.True(false);
                                break;
                        }
                        break;
                    case "System.Int32 A.M()":
                        switch (context.CodeBlock)
                        {
                            case MethodDeclarationSyntax { Identifier: { ValueText: "M" } }:
                                Interlocked.Increment(ref FireCount4);
                                break;
                            default:
                                Assert.True(false);
                                break;
                        }
                        break;
                    default:
                        Assert.True(false);
                        break;
                }
            }
        }
 
        [Fact]
        public void AnalyzerActions_08()
        {
            // Test RegisterCodeBlockStartAction
            var text1 = @"
record struct A([Attr1]int X = 0) : I1
{
    private int M() => 3;
    A(string S) : this(4) => throw null;
}
 
interface I1 {}
";
 
            var analyzer = new AnalyzerActions_08_Analyzer();
            var comp = CreateCompilation(text1);
            comp.GetAnalyzerDiagnostics(new[] { analyzer }, null).Verify();
 
            Assert.Equal(1, analyzer.FireCount100);
            Assert.Equal(1, analyzer.FireCount400);
            Assert.Equal(1, analyzer.FireCount500);
 
            Assert.Equal(1, analyzer.FireCount0);
            Assert.Equal(0, analyzer.FireCountRecordStructDeclarationA);
            Assert.Equal(1, analyzer.FireCount3);
            Assert.Equal(0, analyzer.FireCountSimpleBaseTypeI1onA);
            Assert.Equal(1, analyzer.FireCount5);
            Assert.Equal(0, analyzer.FireCountParameterListAPrimaryCtor);
            Assert.Equal(1, analyzer.FireCount7);
            Assert.Equal(0, analyzer.FireCountConstructorDeclaration);
            Assert.Equal(0, analyzer.FireCountStringParameterList);
            Assert.Equal(1, analyzer.FireCountThisConstructorInitializer);
            Assert.Equal(1, analyzer.FireCount11);
            Assert.Equal(1, analyzer.FireCount12);
            Assert.Equal(1, analyzer.FireCount1000);
            Assert.Equal(1, analyzer.FireCount4000);
            Assert.Equal(1, analyzer.FireCount5000);
        }
 
        private class AnalyzerActions_08_Analyzer : AnalyzerActions_01_Analyzer
        {
            public int FireCount100;
            public int FireCount400;
            public int FireCount500;
            public int FireCount1000;
            public int FireCount4000;
            public int FireCount5000;
 
            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.RegisterCodeBlockStartAction<SyntaxKind>(Handle);
            }
 
            private void Handle(CodeBlockStartAnalysisContext<SyntaxKind> context)
            {
                switch (context.OwningSymbol.ToTestDisplayString())
                {
                    case "A..ctor([System.Int32 X = 0])":
                        switch (context.CodeBlock)
                        {
                            case RecordDeclarationSyntax { Identifier: { ValueText: "A" } }:
                                Interlocked.Increment(ref FireCount100);
                                break;
                            default:
                                Assert.True(false);
                                break;
                        }
                        break;
                    case "System.Int32 A.M()":
                        switch (context.CodeBlock)
                        {
                            case MethodDeclarationSyntax { Identifier: { ValueText: "M" } }:
                                Interlocked.Increment(ref FireCount400);
                                break;
                            default:
                                Assert.True(false);
                                break;
                        }
                        break;
                    case "A..ctor(System.String S)":
                        switch (context.CodeBlock)
                        {
                            case ConstructorDeclarationSyntax { Identifier: { ValueText: "A" } }:
                                Interlocked.Increment(ref FireCount500);
                                break;
                            default:
                                Assert.True(false);
                                break;
                        }
                        break;
                    default:
                        Assert.True(false);
                        break;
                }
 
                context.RegisterSyntaxNodeAction(Handle1, SyntaxKind.NumericLiteralExpression);
                context.RegisterSyntaxNodeAction(Handle2, SyntaxKind.EqualsValueClause);
                context.RegisterSyntaxNodeAction(Fail, SyntaxKind.BaseConstructorInitializer);
                context.RegisterSyntaxNodeAction(Handle3, SyntaxKind.ThisConstructorInitializer);
                context.RegisterSyntaxNodeAction(Handle4, SyntaxKind.ConstructorDeclaration);
                context.RegisterSyntaxNodeAction(Fail, SyntaxKind.PrimaryConstructorBaseType);
                context.RegisterSyntaxNodeAction(Handle6, SyntaxKind.RecordStructDeclaration);
                context.RegisterSyntaxNodeAction(Handle7, SyntaxKind.IdentifierName);
                context.RegisterSyntaxNodeAction(Handle8, SyntaxKind.SimpleBaseType);
                context.RegisterSyntaxNodeAction(Handle9, SyntaxKind.ParameterList);
                context.RegisterSyntaxNodeAction(Handle10, SyntaxKind.ArgumentList);
 
                context.RegisterCodeBlockEndAction(Handle11);
            }
 
            private void Handle11(CodeBlockAnalysisContext context)
            {
                switch (context.OwningSymbol.ToTestDisplayString())
                {
                    case "A..ctor([System.Int32 X = 0])":
 
                        switch (context.CodeBlock)
                        {
                            case RecordDeclarationSyntax { Identifier: { ValueText: "A" } }:
                                Interlocked.Increment(ref FireCount1000);
                                break;
                            default:
                                Assert.True(false);
                                break;
                        }
                        break;
                    case "System.Int32 A.M()":
                        switch (context.CodeBlock)
                        {
                            case MethodDeclarationSyntax { Identifier: { ValueText: "M" } }:
                                Interlocked.Increment(ref FireCount4000);
                                break;
                            default:
                                Assert.True(false);
                                break;
                        }
                        break;
                    case "A..ctor(System.String S)":
                        switch (context.CodeBlock)
                        {
                            case ConstructorDeclarationSyntax { Identifier: { ValueText: "A" } }:
                                Interlocked.Increment(ref FireCount5000);
                                break;
                            default:
                                Assert.True(false);
                                break;
                        }
                        break;
                    default:
                        Assert.True(false);
                        break;
                }
            }
        }
 
        [Fact]
        public void AnalyzerActions_09()
        {
            var text1 = @"
record A([Attr1(100)]int X = 0) : I1
{}
 
record B([Attr2(200)]int Y = 1) : A(2), I1
{
    int M() => 3;
}
 
record C : A, I1
{
    C([Attr3(300)]int Z = 4) : base(5)
    {}
}
 
interface I1 {}
";
 
            var analyzer = new AnalyzerActions_09_Analyzer();
            var comp = CreateCompilation(text1);
            comp.GetAnalyzerDiagnostics(new[] { analyzer }, null).Verify();
 
            Assert.Equal(1, analyzer.FireCount1);
            Assert.Equal(1, analyzer.FireCount2);
            Assert.Equal(1, analyzer.FireCount3);
            Assert.Equal(1, analyzer.FireCount4);
            Assert.Equal(1, analyzer.FireCount5);
            Assert.Equal(1, analyzer.FireCount6);
            Assert.Equal(1, analyzer.FireCount7);
            Assert.Equal(1, analyzer.FireCount8);
            Assert.Equal(1, analyzer.FireCount9);
        }
 
        private class AnalyzerActions_09_Analyzer : DiagnosticAnalyzer
        {
            public int FireCount1;
            public int FireCount2;
            public int FireCount3;
            public int FireCount4;
            public int FireCount5;
            public int FireCount6;
            public int FireCount7;
            public int FireCount8;
            public int FireCount9;
 
            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.RegisterSymbolAction(Handle1, SymbolKind.Method);
                context.RegisterSymbolAction(Handle2, SymbolKind.Property);
                context.RegisterSymbolAction(Handle3, SymbolKind.Parameter);
            }
 
            private void Handle1(SymbolAnalysisContext context)
            {
                switch (context.Symbol.ToTestDisplayString())
                {
                    case "A..ctor([System.Int32 X = 0])":
                        Interlocked.Increment(ref FireCount1);
                        break;
                    case "B..ctor([System.Int32 Y = 1])":
                        Interlocked.Increment(ref FireCount2);
                        break;
                    case "C..ctor([System.Int32 Z = 4])":
                        Interlocked.Increment(ref FireCount3);
                        break;
                    case "System.Int32 B.M()":
                        Interlocked.Increment(ref FireCount4);
                        break;
                    default:
                        Assert.True(false);
                        break;
                }
            }
 
            private void Handle2(SymbolAnalysisContext context)
            {
                switch (context.Symbol.ToTestDisplayString())
                {
                    case "System.Int32 A.X { get; init; }":
                        Interlocked.Increment(ref FireCount5);
                        break;
                    case "System.Int32 B.Y { get; init; }":
                        Interlocked.Increment(ref FireCount6);
                        break;
                    default:
                        Assert.True(false);
                        break;
                }
            }
 
            private void Handle3(SymbolAnalysisContext context)
            {
                switch (context.Symbol.ToTestDisplayString())
                {
                    case "[System.Int32 X = 0]":
                        Interlocked.Increment(ref FireCount7);
                        break;
                    case "[System.Int32 Y = 1]":
                        Interlocked.Increment(ref FireCount8);
                        break;
                    case "[System.Int32 Z = 4]":
                        Interlocked.Increment(ref FireCount9);
                        break;
                    default:
                        Assert.True(false);
                        break;
                }
            }
        }
 
        [Fact]
        public void WithExprOnStruct_LangVersion()
        {
            var src = @"
var b = new B() { X = 1 };
var b2 = b.M();
System.Console.Write(b2.X);
System.Console.Write("" "");
System.Console.Write(b.X);
 
public struct B
{
    public int X { get; set; }
    public B M()
    /*<bind>*/{
        return this with { X = 42 };
    }/*</bind>*/
}";
            var comp = CreateCompilation(src, parseOptions: TestOptions.Regular9);
            comp.VerifyEmitDiagnostics(
                // (13,16): error CS8773: Feature 'with on structs' is not available in C# 9.0. Please use language version 10.0 or greater.
                //         return this with { X = 42 };
                Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion9, "this with { X = 42 }").WithArguments("with on structs", "10.0").WithLocation(13, 16)
                );
 
            comp = CreateCompilation(src);
            comp.VerifyDiagnostics();
            var verifier = CompileAndVerify(comp, expectedOutput: "42 1");
            verifier.VerifyIL("B.M", @"
{
  // Code size       18 (0x12)
  .maxstack  2
  .locals init (B V_0)
  IL_0000:  ldarg.0
  IL_0001:  ldobj      ""B""
  IL_0006:  stloc.0
  IL_0007:  ldloca.s   V_0
  IL_0009:  ldc.i4.s   42
  IL_000b:  call       ""void B.X.set""
  IL_0010:  ldloc.0
  IL_0011:  ret
}");
 
            var tree = comp.SyntaxTrees.First();
            var model = comp.GetSemanticModel(tree, ignoreAccessibility: false);
            var with = tree.GetRoot().DescendantNodes().OfType<WithExpressionSyntax>().Single();
            var type = model.GetTypeInfo(with);
            Assert.Equal("B", type.Type.ToTestDisplayString());
 
            var operation = model.GetOperation(with);
 
            VerifyOperationTree(comp, operation, @"
IWithOperation (OperationKind.With, Type: B) (Syntax: 'this with { X = 42 }')
  Operand:
    IInstanceReferenceOperation (ReferenceKind: ContainingTypeInstance) (OperationKind.InstanceReference, Type: B) (Syntax: 'this')
  CloneMethod: null
  Initializer:
    IObjectOrCollectionInitializerOperation (OperationKind.ObjectOrCollectionInitializer, Type: B) (Syntax: '{ X = 42 }')
      Initializers(1):
          ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: System.Int32) (Syntax: 'X = 42')
            Left:
              IPropertyReferenceOperation: System.Int32 B.X { get; set; } (OperationKind.PropertyReference, Type: System.Int32) (Syntax: 'X')
                Instance Receiver:
                  IInstanceReferenceOperation (ReferenceKind: ImplicitReceiver) (OperationKind.InstanceReference, Type: B, IsImplicit) (Syntax: 'X')
            Right:
              ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 42) (Syntax: '42')
");
 
            var expectedFlowGraph = @"
Block[B0] - Entry
    Statements (0)
    Next (Regular) Block[B1]
        Entering: {R1}
.locals {R1}
{
    CaptureIds: [0]
    Block[B1] - Block
        Predecessors: [B0]
        Statements (2)
            IFlowCaptureOperation: 0 (OperationKind.FlowCapture, Type: null, IsImplicit) (Syntax: 'this')
              Value:
                IInstanceReferenceOperation (ReferenceKind: ContainingTypeInstance) (OperationKind.InstanceReference, Type: B) (Syntax: 'this')
            ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: System.Int32) (Syntax: 'X = 42')
              Left:
                IPropertyReferenceOperation: System.Int32 B.X { get; set; } (OperationKind.PropertyReference, Type: System.Int32) (Syntax: 'X')
                  Instance Receiver:
                    IFlowCaptureReferenceOperation: 0 (OperationKind.FlowCaptureReference, Type: B, IsImplicit) (Syntax: 'this')
              Right:
                ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 42) (Syntax: '42')
        Next (Return) Block[B2]
            IFlowCaptureReferenceOperation: 0 (OperationKind.FlowCaptureReference, Type: B, IsImplicit) (Syntax: 'this')
            Leaving: {R1}
}
Block[B2] - Exit
    Predecessors: [B1]
    Statements (0)
";
            var expectedDiagnostics = DiagnosticDescription.None;
 
            VerifyFlowGraphAndDiagnosticsForTest<BlockSyntax>(src, expectedFlowGraph, expectedDiagnostics, parseOptions: TestOptions.RegularPreview);
        }
 
        [Fact]
        public void WithExprOnStruct_ControlFlow_DuplicateInitialization()
        {
            var src = @"
public struct B
{
    public int X { get; set; }
 
    public B M()
    /*<bind>*/{
        return this with { X = 42, X = 43 };
    }/*</bind>*/
}";
            var expectedDiagnostics = new[]
            {
                // (8,36): error CS1912: Duplicate initialization of member 'X'
                //         return this with { X = 42, X = 43 };
                Diagnostic(ErrorCode.ERR_MemberAlreadyInitialized, "X").WithArguments("X").WithLocation(8, 36)
            };
            var comp = CreateCompilation(src);
            comp.VerifyEmitDiagnostics(expectedDiagnostics);
 
            var expectedFlowGraph = @"
Block[B0] - Entry
    Statements (0)
    Next (Regular) Block[B1]
        Entering: {R1}
.locals {R1}
{
    CaptureIds: [0]
    Block[B1] - Block
        Predecessors: [B0]
        Statements (3)
            IFlowCaptureOperation: 0 (OperationKind.FlowCapture, Type: null, IsImplicit) (Syntax: 'this')
              Value:
                IInstanceReferenceOperation (ReferenceKind: ContainingTypeInstance) (OperationKind.InstanceReference, Type: B) (Syntax: 'this')
            ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: System.Int32) (Syntax: 'X = 42')
              Left:
                IPropertyReferenceOperation: System.Int32 B.X { get; set; } (OperationKind.PropertyReference, Type: System.Int32) (Syntax: 'X')
                  Instance Receiver:
                    IFlowCaptureReferenceOperation: 0 (OperationKind.FlowCaptureReference, Type: B, IsImplicit) (Syntax: 'this')
              Right:
                ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 42) (Syntax: '42')
            ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: System.Int32, IsInvalid) (Syntax: 'X = 43')
              Left:
                IPropertyReferenceOperation: System.Int32 B.X { get; set; } (OperationKind.PropertyReference, Type: System.Int32, IsInvalid) (Syntax: 'X')
                  Instance Receiver:
                    IFlowCaptureReferenceOperation: 0 (OperationKind.FlowCaptureReference, Type: B, IsImplicit) (Syntax: 'this')
              Right:
                ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 43) (Syntax: '43')
        Next (Return) Block[B2]
            IFlowCaptureReferenceOperation: 0 (OperationKind.FlowCaptureReference, Type: B, IsImplicit) (Syntax: 'this')
            Leaving: {R1}
}
Block[B2] - Exit
    Predecessors: [B1]
    Statements (0)
";
            VerifyFlowGraphAndDiagnosticsForTest<BlockSyntax>(src, expectedFlowGraph, expectedDiagnostics, parseOptions: TestOptions.RegularPreview);
        }
 
        [Fact]
        public void WithExprOnStruct_ControlFlow_NestedInitializer()
        {
            var src = @"
public struct C
{
    public int Y { get; set; }
}
public struct B
{
    public C X { get; set; }
 
    public B M()
    /*<bind>*/{
        return this with { X = { Y = 1 } };
    }/*</bind>*/
}";
 
            var expectedDiagnostics = new[]
            {
                // (12,32): error CS1525: Invalid expression term '{'
                //         return this with { X = { Y = 1 } };
                Diagnostic(ErrorCode.ERR_InvalidExprTerm, "{").WithArguments("{").WithLocation(12, 32),
                // (12,32): error CS1513: } expected
                //         return this with { X = { Y = 1 } };
                Diagnostic(ErrorCode.ERR_RbraceExpected, "{").WithLocation(12, 32),
                // (12,32): error CS1002: ; expected
                //         return this with { X = { Y = 1 } };
                Diagnostic(ErrorCode.ERR_SemicolonExpected, "{").WithLocation(12, 32),
                // (12,34): error CS0103: The name 'Y' does not exist in the current context
                //         return this with { X = { Y = 1 } };
                Diagnostic(ErrorCode.ERR_NameNotInContext, "Y").WithArguments("Y").WithLocation(12, 34),
                // (12,34): warning CS0162: Unreachable code detected
                //         return this with { X = { Y = 1 } };
                Diagnostic(ErrorCode.WRN_UnreachableCode, "Y").WithLocation(12, 34),
                // (12,40): error CS1002: ; expected
                //         return this with { X = { Y = 1 } };
                Diagnostic(ErrorCode.ERR_SemicolonExpected, "}").WithLocation(12, 40),
                // (12,43): error CS1597: Semicolon after method or accessor block is not valid
                //         return this with { X = { Y = 1 } };
                Diagnostic(ErrorCode.ERR_UnexpectedSemicolon, ";").WithLocation(12, 43),
                // (14,1): error CS1022: Type or namespace definition, or end-of-file expected
                // }
                Diagnostic(ErrorCode.ERR_EOFExpected, "}").WithLocation(14, 1)
            };
            var comp = CreateCompilation(src);
            comp.VerifyEmitDiagnostics(expectedDiagnostics);
 
            var expectedFlowGraph = @"
Block[B0] - Entry
    Statements (0)
    Next (Regular) Block[B1]
        Entering: {R1}
.locals {R1}
{
    CaptureIds: [0]
    Block[B1] - Block
        Predecessors: [B0]
        Statements (2)
            IFlowCaptureOperation: 0 (OperationKind.FlowCapture, Type: null, IsImplicit) (Syntax: 'this')
              Value:
                IInstanceReferenceOperation (ReferenceKind: ContainingTypeInstance) (OperationKind.InstanceReference, Type: B) (Syntax: 'this')
            ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: C, IsInvalid) (Syntax: 'X = ')
              Left:
                IPropertyReferenceOperation: C B.X { get; set; } (OperationKind.PropertyReference, Type: C) (Syntax: 'X')
                  Instance Receiver:
                    IFlowCaptureReferenceOperation: 0 (OperationKind.FlowCaptureReference, Type: B, IsImplicit) (Syntax: 'this')
              Right:
                IInvalidOperation (OperationKind.Invalid, Type: null, IsInvalid) (Syntax: '')
                  Children(0)
        Next (Return) Block[B3]
            IFlowCaptureReferenceOperation: 0 (OperationKind.FlowCaptureReference, Type: B, IsImplicit) (Syntax: 'this')
            Leaving: {R1}
}
Block[B2] - Block [UnReachable]
    Predecessors (0)
    Statements (1)
        IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null, IsInvalid) (Syntax: 'Y = 1 ')
          Expression:
            ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: ?, IsInvalid) (Syntax: 'Y = 1')
              Left:
                IInvalidOperation (OperationKind.Invalid, Type: ?, IsInvalid) (Syntax: 'Y')
                  Children(0)
              Right:
                ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 1) (Syntax: '1')
    Next (Regular) Block[B3]
Block[B3] - Exit
    Predecessors: [B1] [B2]
    Statements (0)
";
            VerifyFlowGraphAndDiagnosticsForTest<BlockSyntax>(src, expectedFlowGraph, expectedDiagnostics, parseOptions: TestOptions.RegularPreview);
        }
 
        [Fact]
        public void WithExprOnStruct_ControlFlow_NonAssignmentExpression()
        {
            var src = @"
public struct B
{
    public int X { get; set; }
 
    public B M(int i, int j)
    /*<bind>*/{
        return this with { i, j++, M2(), X = 2};
    }/*</bind>*/
 
    static int M2() => 0;
}";
            var expectedDiagnostics = new[]
            {
                // (8,28): error CS0747: Invalid initializer member declarator
                //         return this with { i, j++, M2(), X = 2};
                Diagnostic(ErrorCode.ERR_InvalidInitializerElementInitializer, "i").WithLocation(8, 28),
                // (8,28): error CS0117: 'B' does not contain a definition for 'i'
                //         return this with { i, j++, M2(), X = 2};
                Diagnostic(ErrorCode.ERR_NoSuchMember, "i").WithArguments("B", "i").WithLocation(8, 28),
                // (8,31): error CS0747: Invalid initializer member declarator
                //         return this with { i, j++, M2(), X = 2};
                Diagnostic(ErrorCode.ERR_InvalidInitializerElementInitializer, "j++").WithLocation(8, 31),
                // (8,36): error CS0747: Invalid initializer member declarator
                //         return this with { i, j++, M2(), X = 2};
                Diagnostic(ErrorCode.ERR_InvalidInitializerElementInitializer, "M2()").WithLocation(8, 36)
            };
            var comp = CreateCompilation(src);
            comp.VerifyEmitDiagnostics(expectedDiagnostics);
 
            var expectedFlowGraph = @"
Block[B0] - Entry
    Statements (0)
    Next (Regular) Block[B1]
        Entering: {R1}
.locals {R1}
{
    CaptureIds: [0]
    Block[B1] - Block
        Predecessors: [B0]
        Statements (5)
            IFlowCaptureOperation: 0 (OperationKind.FlowCapture, Type: null, IsImplicit) (Syntax: 'this')
              Value:
                IInstanceReferenceOperation (ReferenceKind: ContainingTypeInstance) (OperationKind.InstanceReference, Type: B) (Syntax: 'this')
            ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: ?, IsInvalid, IsImplicit) (Syntax: 'i')
              Left:
                IInvalidOperation (OperationKind.Invalid, Type: ?, IsInvalid, IsImplicit) (Syntax: 'i')
                  Children(1):
                      IOperation:  (OperationKind.None, Type: null, IsInvalid) (Syntax: 'i')
                        Children(1):
                            IFlowCaptureReferenceOperation: 0 (OperationKind.FlowCaptureReference, Type: B, IsImplicit) (Syntax: 'this')
              Right:
                IInvalidOperation (OperationKind.Invalid, Type: null, IsInvalid, IsImplicit) (Syntax: 'i')
                  Children(0)
            IInvalidOperation (OperationKind.Invalid, Type: System.Int32, IsInvalid, IsImplicit) (Syntax: 'j++')
              Children(1):
                  IIncrementOrDecrementOperation (Postfix) (OperationKind.Increment, Type: System.Int32, IsInvalid) (Syntax: 'j++')
                    Target:
                      IParameterReferenceOperation: j (OperationKind.ParameterReference, Type: System.Int32, IsInvalid) (Syntax: 'j')
            IInvalidOperation (OperationKind.Invalid, Type: System.Int32, IsInvalid, IsImplicit) (Syntax: 'M2()')
              Children(1):
                  IInvocationOperation (System.Int32 B.M2()) (OperationKind.Invocation, Type: System.Int32, IsInvalid) (Syntax: 'M2()')
                    Instance Receiver:
                      null
                    Arguments(0)
            ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: System.Int32) (Syntax: 'X = 2')
              Left:
                IPropertyReferenceOperation: System.Int32 B.X { get; set; } (OperationKind.PropertyReference, Type: System.Int32) (Syntax: 'X')
                  Instance Receiver:
                    IFlowCaptureReferenceOperation: 0 (OperationKind.FlowCaptureReference, Type: B, IsImplicit) (Syntax: 'this')
              Right:
                ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 2) (Syntax: '2')
        Next (Return) Block[B2]
            IFlowCaptureReferenceOperation: 0 (OperationKind.FlowCaptureReference, Type: B, IsImplicit) (Syntax: 'this')
            Leaving: {R1}
}
Block[B2] - Exit
    Predecessors: [B1]
    Statements (0)
";
            VerifyFlowGraphAndDiagnosticsForTest<BlockSyntax>(src, expectedFlowGraph, expectedDiagnostics, parseOptions: TestOptions.RegularPreview);
        }
 
        [Fact]
        public void ObjectCreationInitializer_ControlFlow_WithCoalescingExpressionForValue()
        {
            var src = @"
public struct B
{
    public string X;
 
    public void M(string hello)
    /*<bind>*/{
        var x = new B() { X = Identity((string)null) ?? Identity(hello) };
    }/*</bind>*/
 
    T Identity<T>(T t) => t;
}";
 
            var comp = CreateCompilation(src);
            comp.VerifyDiagnostics();
            var expectedFlowGraph = @"
Block[B0] - Entry
    Statements (0)
    Next (Regular) Block[B1]
        Entering: {R1}
.locals {R1}
{
    Locals: [B x]
    CaptureIds: [0]
    Block[B1] - Block
        Predecessors: [B0]
        Statements (1)
            IFlowCaptureOperation: 0 (OperationKind.FlowCapture, Type: null, IsImplicit) (Syntax: 'new B() { X ... ty(hello) }')
              Value:
                IObjectCreationOperation (Constructor: B..ctor()) (OperationKind.ObjectCreation, Type: B) (Syntax: 'new B() { X ... ty(hello) }')
                  Arguments(0)
                  Initializer:
                    null
        Next (Regular) Block[B2]
            Entering: {R2} {R3}
    .locals {R2}
    {
        CaptureIds: [2]
        .locals {R3}
        {
            CaptureIds: [1]
            Block[B2] - Block
                Predecessors: [B1]
                Statements (1)
                    IFlowCaptureOperation: 1 (OperationKind.FlowCapture, Type: null, IsImplicit) (Syntax: 'Identity((string)null)')
                      Value:
                        IInvocationOperation ( System.String B.Identity<System.String>(System.String t)) (OperationKind.Invocation, Type: System.String) (Syntax: 'Identity((string)null)')
                          Instance Receiver:
                            IInstanceReferenceOperation (ReferenceKind: ContainingTypeInstance) (OperationKind.InstanceReference, Type: B, IsImplicit) (Syntax: 'Identity')
                          Arguments(1):
                              IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: t) (OperationKind.Argument, Type: null) (Syntax: '(string)null')
                                IConversionOperation (TryCast: False, Unchecked) (OperationKind.Conversion, Type: System.String, Constant: null) (Syntax: '(string)null')
                                  Conversion: CommonConversion (Exists: True, IsIdentity: False, IsNumeric: False, IsReference: True, IsUserDefined: False) (MethodSymbol: null)
                                    (ImplicitReference)
                                  Operand:
                                    ILiteralOperation (OperationKind.Literal, Type: null, Constant: null) (Syntax: 'null')
                                InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null)
                                OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null)
                Jump if True (Regular) to Block[B4]
                    IIsNullOperation (OperationKind.IsNull, Type: System.Boolean, IsImplicit) (Syntax: 'Identity((string)null)')
                      Operand:
                        IFlowCaptureReferenceOperation: 1 (OperationKind.FlowCaptureReference, Type: System.String, IsImplicit) (Syntax: 'Identity((string)null)')
                    Leaving: {R3}
                Next (Regular) Block[B3]
            Block[B3] - Block
                Predecessors: [B2]
                Statements (1)
                    IFlowCaptureOperation: 2 (OperationKind.FlowCapture, Type: null, IsImplicit) (Syntax: 'Identity((string)null)')
                      Value:
                        IFlowCaptureReferenceOperation: 1 (OperationKind.FlowCaptureReference, Type: System.String, IsImplicit) (Syntax: 'Identity((string)null)')
                Next (Regular) Block[B5]
                    Leaving: {R3}
        }
        Block[B4] - Block
            Predecessors: [B2]
            Statements (1)
                IFlowCaptureOperation: 2 (OperationKind.FlowCapture, Type: null, IsImplicit) (Syntax: 'Identity(hello)')
                  Value:
                    IInvocationOperation ( System.String B.Identity<System.String>(System.String t)) (OperationKind.Invocation, Type: System.String) (Syntax: 'Identity(hello)')
                      Instance Receiver:
                        IInstanceReferenceOperation (ReferenceKind: ContainingTypeInstance) (OperationKind.InstanceReference, Type: B, IsImplicit) (Syntax: 'Identity')
                      Arguments(1):
                          IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: t) (OperationKind.Argument, Type: null) (Syntax: 'hello')
                            IParameterReferenceOperation: hello (OperationKind.ParameterReference, Type: System.String) (Syntax: 'hello')
                            InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null)
                            OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null)
            Next (Regular) Block[B5]
        Block[B5] - Block
            Predecessors: [B3] [B4]
            Statements (1)
                ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: System.String) (Syntax: 'X = Identit ... tity(hello)')
                  Left:
                    IFieldReferenceOperation: System.String B.X (OperationKind.FieldReference, Type: System.String) (Syntax: 'X')
                      Instance Receiver:
                        IFlowCaptureReferenceOperation: 0 (OperationKind.FlowCaptureReference, Type: B, IsImplicit) (Syntax: 'new B() { X ... ty(hello) }')
                  Right:
                    IFlowCaptureReferenceOperation: 2 (OperationKind.FlowCaptureReference, Type: System.String, IsImplicit) (Syntax: 'Identity((s ... tity(hello)')
            Next (Regular) Block[B6]
                Leaving: {R2}
    }
    Block[B6] - Block
        Predecessors: [B5]
        Statements (1)
            ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: B, IsImplicit) (Syntax: 'x = new B() ... ty(hello) }')
              Left:
                ILocalReferenceOperation: x (IsDeclaration: True) (OperationKind.LocalReference, Type: B, IsImplicit) (Syntax: 'x = new B() ... ty(hello) }')
              Right:
                IFlowCaptureReferenceOperation: 0 (OperationKind.FlowCaptureReference, Type: B, IsImplicit) (Syntax: 'new B() { X ... ty(hello) }')
        Next (Regular) Block[B7]
            Leaving: {R1}
}
Block[B7] - Exit
    Predecessors: [B6]
    Statements (0)
";
            var expectedDiagnostics = DiagnosticDescription.None;
 
            VerifyFlowGraphAndDiagnosticsForTest<BlockSyntax>(src, expectedFlowGraph, expectedDiagnostics);
        }
 
        [Fact]
        public void WithExprOnStruct_ControlFlow_WithCoalescingExpressionForValue()
        {
            var src = @"
var b = new B() { X = string.Empty };
var b2 = b.M(""hello"");
System.Console.Write(b2.X);
 
public struct B
{
    public string X;
 
    public B M(string hello)
    /*<bind>*/{
        return Identity(this) with { X = Identity((string)null) ?? Identity(hello) };
    }/*</bind>*/
 
    T Identity<T>(T t) => t;
}";
 
            var comp = CreateCompilation(src);
            comp.VerifyDiagnostics();
            CompileAndVerify(comp, expectedOutput: "hello");
            var expectedFlowGraph = @"
Block[B0] - Entry
    Statements (0)
    Next (Regular) Block[B1]
        Entering: {R1}
 
.locals {R1}
{
    CaptureIds: [0]
    Block[B1] - Block
        Predecessors: [B0]
        Statements (1)
            IFlowCaptureOperation: 0 (OperationKind.FlowCapture, Type: null, IsImplicit) (Syntax: 'Identity(this)')
              Value:
                IInvocationOperation ( B B.Identity<B>(B t)) (OperationKind.Invocation, Type: B) (Syntax: 'Identity(this)')
                  Instance Receiver:
                    IInstanceReferenceOperation (ReferenceKind: ContainingTypeInstance) (OperationKind.InstanceReference, Type: B, IsImplicit) (Syntax: 'Identity')
                  Arguments(1):
                      IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: t) (OperationKind.Argument, Type: null) (Syntax: 'this')
                        IInstanceReferenceOperation (ReferenceKind: ContainingTypeInstance) (OperationKind.InstanceReference, Type: B) (Syntax: 'this')
                        InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null)
                        OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null)
 
        Next (Regular) Block[B2]
            Entering: {R2} {R3}
 
    .locals {R2}
    {
        CaptureIds: [2]
        .locals {R3}
        {
            CaptureIds: [1]
            Block[B2] - Block
                Predecessors: [B1]
                Statements (1)
                    IFlowCaptureOperation: 1 (OperationKind.FlowCapture, Type: null, IsImplicit) (Syntax: 'Identity((string)null)')
                      Value:
                        IInvocationOperation ( System.String B.Identity<System.String>(System.String t)) (OperationKind.Invocation, Type: System.String) (Syntax: 'Identity((string)null)')
                          Instance Receiver:
                            IInstanceReferenceOperation (ReferenceKind: ContainingTypeInstance) (OperationKind.InstanceReference, Type: B, IsImplicit) (Syntax: 'Identity')
                          Arguments(1):
                              IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: t) (OperationKind.Argument, Type: null) (Syntax: '(string)null')
                                IConversionOperation (TryCast: False, Unchecked) (OperationKind.Conversion, Type: System.String, Constant: null) (Syntax: '(string)null')
                                  Conversion: CommonConversion (Exists: True, IsIdentity: False, IsNumeric: False, IsReference: True, IsUserDefined: False) (MethodSymbol: null)
                                    (ImplicitReference)
                                  Operand:
                                    ILiteralOperation (OperationKind.Literal, Type: null, Constant: null) (Syntax: 'null')
                                InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null)
                                OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null)
 
                Jump if True (Regular) to Block[B4]
                    IIsNullOperation (OperationKind.IsNull, Type: System.Boolean, IsImplicit) (Syntax: 'Identity((string)null)')
                      Operand:
                        IFlowCaptureReferenceOperation: 1 (OperationKind.FlowCaptureReference, Type: System.String, IsImplicit) (Syntax: 'Identity((string)null)')
                    Leaving: {R3}
 
                Next (Regular) Block[B3]
            Block[B3] - Block
                Predecessors: [B2]
                Statements (1)
                    IFlowCaptureOperation: 2 (OperationKind.FlowCapture, Type: null, IsImplicit) (Syntax: 'Identity((string)null)')
                      Value:
                        IFlowCaptureReferenceOperation: 1 (OperationKind.FlowCaptureReference, Type: System.String, IsImplicit) (Syntax: 'Identity((string)null)')
 
                Next (Regular) Block[B5]
                    Leaving: {R3}
        }
 
        Block[B4] - Block
            Predecessors: [B2]
            Statements (1)
                IFlowCaptureOperation: 2 (OperationKind.FlowCapture, Type: null, IsImplicit) (Syntax: 'Identity(hello)')
                  Value:
                    IInvocationOperation ( System.String B.Identity<System.String>(System.String t)) (OperationKind.Invocation, Type: System.String) (Syntax: 'Identity(hello)')
                      Instance Receiver:
                        IInstanceReferenceOperation (ReferenceKind: ContainingTypeInstance) (OperationKind.InstanceReference, Type: B, IsImplicit) (Syntax: 'Identity')
                      Arguments(1):
                          IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: t) (OperationKind.Argument, Type: null) (Syntax: 'hello')
                            IParameterReferenceOperation: hello (OperationKind.ParameterReference, Type: System.String) (Syntax: 'hello')
                            InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null)
                            OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null)
 
            Next (Regular) Block[B5]
        Block[B5] - Block
            Predecessors: [B3] [B4]
            Statements (1)
                ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: System.String) (Syntax: 'X = Identit ... tity(hello)')
                  Left:
                    IFieldReferenceOperation: System.String B.X (OperationKind.FieldReference, Type: System.String) (Syntax: 'X')
                      Instance Receiver:
                        IFlowCaptureReferenceOperation: 0 (OperationKind.FlowCaptureReference, Type: B, IsImplicit) (Syntax: 'Identity(this)')
                  Right:
                    IFlowCaptureReferenceOperation: 2 (OperationKind.FlowCaptureReference, Type: System.String, IsImplicit) (Syntax: 'Identity((s ... tity(hello)')
 
            Next (Regular) Block[B6]
                Leaving: {R2}
    }
 
    Block[B6] - Block
        Predecessors: [B5]
        Statements (0)
        Next (Return) Block[B7]
            IFlowCaptureReferenceOperation: 0 (OperationKind.FlowCaptureReference, Type: B, IsImplicit) (Syntax: 'Identity(this)')
            Leaving: {R1}
}
 
Block[B7] - Exit
    Predecessors: [B6]
    Statements (0)
";
            var expectedDiagnostics = DiagnosticDescription.None;
 
            VerifyFlowGraphAndDiagnosticsForTest<BlockSyntax>(src, expectedFlowGraph, expectedDiagnostics, parseOptions: TestOptions.RegularPreview);
        }
 
        [Fact]
        public void WithExprOnStruct_OnParameter()
        {
            var src = @"
var b = new B() { X = 1 };
var b2 = B.M(b);
System.Console.Write(b2.X);
 
public struct B
{
    public int X { get; set; }
    public static B M(B b)
    {
        return b with { X = 42 };
    }
}";
 
            var comp = CreateCompilation(src);
            comp.VerifyDiagnostics();
            var verifier = CompileAndVerify(comp, expectedOutput: "42");
            verifier.VerifyIL("B.M", @"
{
  // Code size       13 (0xd)
  .maxstack  2
  .locals init (B V_0)
  IL_0000:  ldarg.0
  IL_0001:  stloc.0
  IL_0002:  ldloca.s   V_0
  IL_0004:  ldc.i4.s   42
  IL_0006:  call       ""void B.X.set""
  IL_000b:  ldloc.0
  IL_000c:  ret
}");
        }
 
        [Fact]
        public void WithExprOnStruct_OnThis()
        {
            var src = @"
record struct C
{
    public int X { get; set; }
 
    C(string ignored)
    {
        _ = this with { X = 42 }; // 1
        this = default;
    }
}
";
 
            var comp = CreateCompilation(src, parseOptions: TestOptions.Regular10);
            comp.VerifyDiagnostics(
                // (8,13): error CS0188: The 'this' object cannot be used before all of its fields have been assigned. Consider updating to language version '11.0' to auto-default the unassigned fields.
                //         _ = this with { X = 42 }; // 1
                Diagnostic(ErrorCode.ERR_UseDefViolationThisUnsupportedVersion, "this").WithArguments("11.0").WithLocation(8, 13)
                );
 
            var verifier = CompileAndVerify(src, parseOptions: TestOptions.Regular11);
            verifier.VerifyDiagnostics();
            verifier.VerifyIL("C..ctor(string)", @"
{
  // Code size       31 (0x1f)
  .maxstack  2
  .locals init (C V_0)
  IL_0000:  ldarg.0
  IL_0001:  ldc.i4.0
  IL_0002:  stfld      ""int C.<X>k__BackingField""
  IL_0007:  ldarg.0
  IL_0008:  ldobj      ""C""
  IL_000d:  stloc.0
  IL_000e:  ldloca.s   V_0
  IL_0010:  ldc.i4.s   42
  IL_0012:  call       ""void C.X.set""
  IL_0017:  ldarg.0
  IL_0018:  initobj    ""C""
  IL_001e:  ret
}
");
        }
 
        [Fact]
        public void WithExprOnStruct_OnTStructParameter()
        {
            var src = @"
var b = new B() { X = 1 };
var b2 = B.M(b);
System.Console.Write(b2.X);
 
public interface I
{
    int X { get; set; }
}
 
public struct B : I
{
    public int X { get; set; }
    public static T M<T>(T b) where T : struct, I
    {
        return b with { X = 42 };
    }
}";
 
            var comp = CreateCompilation(src);
            comp.VerifyDiagnostics();
            var verifier = CompileAndVerify(comp, expectedOutput: "42");
            verifier.VerifyIL("B.M<T>(T)", @"
{
  // Code size       19 (0x13)
  .maxstack  2
  .locals init (T V_0)
  IL_0000:  ldarg.0
  IL_0001:  stloc.0
  IL_0002:  ldloca.s   V_0
  IL_0004:  ldc.i4.s   42
  IL_0006:  constrained. ""T""
  IL_000c:  callvirt   ""void I.X.set""
  IL_0011:  ldloc.0
  IL_0012:  ret
}");
 
            var tree = comp.SyntaxTrees.First();
            var model = comp.GetSemanticModel(tree, ignoreAccessibility: false);
            var with = tree.GetRoot().DescendantNodes().OfType<WithExpressionSyntax>().Single();
            var type = model.GetTypeInfo(with);
            Assert.Equal("T", type.Type.ToTestDisplayString());
        }
 
        [Fact]
        public void WithExprOnStruct_OnRecordStructParameter()
        {
            var src = @"
var b = new B(1);
var b2 = B.M(b);
System.Console.Write(b2.X);
 
public record struct B(int X)
{
    public static B M(B b)
    {
        return b with { X = 42 };
    }
}";
 
            var comp = CreateCompilation(src);
            comp.VerifyDiagnostics();
            var verifier = CompileAndVerify(comp, expectedOutput: "42");
            verifier.VerifyIL("B.M", @"
{
  // Code size       13 (0xd)
  .maxstack  2
  .locals init (B V_0)
  IL_0000:  ldarg.0
  IL_0001:  stloc.0
  IL_0002:  ldloca.s   V_0
  IL_0004:  ldc.i4.s   42
  IL_0006:  call       ""void B.X.set""
  IL_000b:  ldloc.0
  IL_000c:  ret
}");
        }
 
        [Fact]
        public void WithExprOnStruct_OnRecordStructParameter_Readonly()
        {
            var src = @"
var b = new B(1, 2);
var b2 = B.M(b);
System.Console.Write(b2.X);
System.Console.Write(b2.Y);
 
public readonly record struct B(int X, int Y)
{
    public static B M(B b)
    {
        return b with { X = 42, Y = 43 };
    }
}";
 
            var comp = CreateCompilation(src);
            comp.VerifyDiagnostics();
            var verifier = CompileAndVerify(comp, expectedOutput: "4243", verify: Verification.Skipped /* init-only */);
            verifier.VerifyIL("B.M", @"
{
  // Code size       22 (0x16)
  .maxstack  2
  .locals init (B V_0)
  IL_0000:  ldarg.0
  IL_0001:  stloc.0
  IL_0002:  ldloca.s   V_0
  IL_0004:  ldc.i4.s   42
  IL_0006:  call       ""void B.X.init""
  IL_000b:  ldloca.s   V_0
  IL_000d:  ldc.i4.s   43
  IL_000f:  call       ""void B.Y.init""
  IL_0014:  ldloc.0
  IL_0015:  ret
}");
        }
 
        [Fact]
        public void WithExprOnStruct_OnTuple()
        {
            var src = @"
class C
{
    static void Main()
    {
        var b = (1, 2);
        var b2 = M(b);
        System.Console.Write(b2.Item1);
        System.Console.Write(b2.Item2);
    }
 
    static (int, int) M((int, int) b)
    {
        return b with { Item1 = 42, Item2 = 43 };
    }
}";
            var comp = CreateCompilation(src, parseOptions: TestOptions.RegularPreview, options: TestOptions.ReleaseExe);
            comp.VerifyDiagnostics();
            var verifier = CompileAndVerify(comp, expectedOutput: "4243");
            verifier.VerifyIL("C.M", @"
{
  // Code size       22 (0x16)
  .maxstack  2
  .locals init (System.ValueTuple<int, int> V_0)
  IL_0000:  ldarg.0
  IL_0001:  stloc.0
  IL_0002:  ldloca.s   V_0
  IL_0004:  ldc.i4.s   42
  IL_0006:  stfld      ""int System.ValueTuple<int, int>.Item1""
  IL_000b:  ldloca.s   V_0
  IL_000d:  ldc.i4.s   43
  IL_000f:  stfld      ""int System.ValueTuple<int, int>.Item2""
  IL_0014:  ldloc.0
  IL_0015:  ret
}");
        }
 
        [Fact]
        public void WithExprOnStruct_OnTuple_WithNames()
        {
            var src = @"
var b = (1, 2);
var b2 = M(b);
System.Console.Write(b2.Item1);
System.Console.Write(b2.Item2);
 
static (int, int) M((int X, int Y) b)
{
    return b with { X = 42, Y = 43 };
}";
            var comp = CreateCompilation(src);
            comp.VerifyDiagnostics();
            var verifier = CompileAndVerify(comp, expectedOutput: "4243");
            verifier.VerifyIL("Program.<<Main>$>g__M|0_0(System.ValueTuple<int, int>)", @"
{
  // Code size       22 (0x16)
  .maxstack  2
  .locals init (System.ValueTuple<int, int> V_0)
  IL_0000:  ldarg.0
  IL_0001:  stloc.0
  IL_0002:  ldloca.s   V_0
  IL_0004:  ldc.i4.s   42
  IL_0006:  stfld      ""int System.ValueTuple<int, int>.Item1""
  IL_000b:  ldloca.s   V_0
  IL_000d:  ldc.i4.s   43
  IL_000f:  stfld      ""int System.ValueTuple<int, int>.Item2""
  IL_0014:  ldloc.0
  IL_0015:  ret
}");
        }
 
        [Fact]
        public void WithExprOnStruct_OnTuple_LongTuple()
        {
            var src = @"
var b = (1, 2, 3, 4, 5, 6, 7, 8);
var b2 = M(b);
System.Console.Write(b2.Item7);
System.Console.Write(b2.Item8);
 
static (int, int, int, int, int, int, int, int) M((int, int, int, int, int, int, int, int) b)
{
    return b with { Item7 = 42, Item8 = 43 };
}";
            var comp = CreateCompilation(src);
            comp.VerifyDiagnostics();
            var verifier = CompileAndVerify(comp, expectedOutput: "4243");
            verifier.VerifyIL("Program.<<Main>$>g__M|0_0(System.ValueTuple<int, int, int, int, int, int, int, System.ValueTuple<int>>)", @"
{
  // Code size       27 (0x1b)
  .maxstack  2
  .locals init (System.ValueTuple<int, int, int, int, int, int, int, System.ValueTuple<int>> V_0)
  IL_0000:  ldarg.0
  IL_0001:  stloc.0
  IL_0002:  ldloca.s   V_0
  IL_0004:  ldc.i4.s   42
  IL_0006:  stfld      ""int System.ValueTuple<int, int, int, int, int, int, int, System.ValueTuple<int>>.Item7""
  IL_000b:  ldloca.s   V_0
  IL_000d:  ldflda     ""System.ValueTuple<int> System.ValueTuple<int, int, int, int, int, int, int, System.ValueTuple<int>>.Rest""
  IL_0012:  ldc.i4.s   43
  IL_0014:  stfld      ""int System.ValueTuple<int>.Item1""
  IL_0019:  ldloc.0
  IL_001a:  ret
}");
        }
 
        [Fact]
        public void WithExprOnStruct_OnReadonlyField()
        {
            var src = @"
var b = new B { X = 1 }; // 1
 
public struct B
{
    public readonly int X;
    public B M()
    {
        return this with { X = 42 }; // 2
    }
    public static B M2(B b)
    {
        return b with { X = 42 }; // 3
    }
    public B(int i)
    {
        this = default;
        _ = this with { X = 42 }; // 4
    }
}";
            var comp = CreateCompilation(src);
            comp.VerifyEmitDiagnostics(
                // (2,17): error CS0191: A readonly field cannot be assigned to (except in a constructor or init-only setter of the type in which the field is defined or a variable initializer)
                // var b = new B { X = 1 }; // 1
                Diagnostic(ErrorCode.ERR_AssgReadonly, "X").WithLocation(2, 17),
                // (9,28): error CS0191: A readonly field cannot be assigned to (except in a constructor or init-only setter of the type in which the field is defined or a variable initializer)
                //         return this with { X = 42 }; // 2
                Diagnostic(ErrorCode.ERR_AssgReadonly, "X").WithLocation(9, 28),
                // (13,25): error CS0191: A readonly field cannot be assigned to (except in a constructor or init-only setter of the type in which the field is defined or a variable initializer)
                //         return b with { X = 42 }; // 3
                Diagnostic(ErrorCode.ERR_AssgReadonly, "X").WithLocation(13, 25),
                // (18,25): error CS0191: A readonly field cannot be assigned to (except in a constructor or init-only setter of the type in which the field is defined or a variable initializer)
                //         _ = this with { X = 42 }; // 4
                Diagnostic(ErrorCode.ERR_AssgReadonly, "X").WithLocation(18, 25)
                );
        }
 
        [Fact]
        public void WithExprOnStruct_OnEnum()
        {
            var src = @"
public enum E { }
class C
{
    static E M(E e)
    {
        return e with { };
    }
}";
            var comp = CreateCompilation(src);
            comp.VerifyEmitDiagnostics();
        }
 
        [Fact]
        public void WithExprOnStruct_OnPointer()
        {
            var src = @"
unsafe class C
{
    static int* M(int* i)
    {
        return i with { };
    }
}";
            var comp = CreateCompilation(src, options: TestOptions.UnsafeReleaseDll, parseOptions: TestOptions.RegularPreview);
            comp.VerifyEmitDiagnostics(
                // (6,16): error CS8858: The receiver type 'int*' is not a valid record type and is not a struct type.
                //         return i with { };
                Diagnostic(ErrorCode.ERR_CannotClone, "i").WithArguments("int*").WithLocation(6, 16)
                );
        }
 
        [Fact]
        public void WithExprOnStruct_OnInterface()
        {
            var src = @"
public interface I
{
    int X { get; set; }
}
class C
{
    static I M(I i)
    {
        return i with { X = 42 };
    }
}";
            var comp = CreateCompilation(src);
            comp.VerifyEmitDiagnostics(
                // (10,16): error CS8858: The receiver type 'I' is not a valid record type and is not a value type.
                //         return i with { X = 42 };
                Diagnostic(ErrorCode.ERR_CannotClone, "i").WithArguments("I").WithLocation(10, 16)
                );
        }
 
        [Fact]
        public void WithExprOnStruct_OnRefStruct()
        {
            // Similar to test RefLikeObjInitializers but with `with` expressions
            var text = @"
using System;
 
class Program
{
    static S2 Test1()
    {
        S1 outer = default;
        S1 inner = stackalloc int[1];
 
        // error
        return new S2() with { Field1 = outer, Field2 = inner };
    }
 
    static S2 Test2()
    {
        S1 outer = default;
        S1 inner = stackalloc int[1];
 
        S2 result;
 
        // error
        result = new S2() with { Field1 = inner, Field2 = outer };
 
        return result;
    }
 
    static S2 Test3()
    {
        S1 outer = default;
        S1 inner = stackalloc int[1];
 
        return new S2() with { Field1 = outer, Field2 = outer };
    }
 
    public ref struct S1
    {
        public static implicit operator S1(Span<int> o) => default;
    }
 
    public ref struct S2
    {
        public S1 Field1;
        public S1 Field2;
    }
}
";
            CreateCompilationWithMscorlibAndSpan(text, parseOptions: TestOptions.RegularPreview).VerifyDiagnostics(
                // (12,30): error CS8352: Cannot use variable 'Field2 = inner' in this context because it may expose referenced variables outside of their declaration scope
                //         return new S2() with { Field1 = outer, Field2 = inner };
                Diagnostic(ErrorCode.ERR_EscapeVariable, "{ Field1 = outer, Field2 = inner }").WithArguments("Field2 = inner").WithLocation(12, 30),
                // (23,32): error CS8352: Cannot use variable 'Field1 = inner' in this context because it may expose referenced variables outside of their declaration scope
                //         result = new S2() with { Field1 = inner, Field2 = outer };
                Diagnostic(ErrorCode.ERR_EscapeVariable, "{ Field1 = inner, Field2 = outer }").WithArguments("Field1 = inner").WithLocation(23, 32)
                );
        }
 
        [Theory]
        [InlineData(LanguageVersion.CSharp10)]
        [InlineData(LanguageVersion.CSharp11)]
        public void WithExprOnStruct_OnRefStruct_ReceiverMayWrap(LanguageVersion languageVersion)
        {
            // Similar to test LocalWithNoInitializerEscape but wrapping method is used as receiver for `with` expression
            var text = @"using System;
 
class Program
{
    static void Main()
    {
        S1 sp;
        Span<int> local = stackalloc int[1];
        sp = MayWrap(ref local) with { }; // 1, 2
    }
 
    static S1 MayWrap(ref Span<int> arg)
    {
        return default;
    }
 
    ref struct S1
    {
        public ref int this[int i] => throw null;
    }
}
";
            var comp = CreateCompilationWithMscorlibAndSpan(new[] { text, UnscopedRefAttributeDefinition }, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion));
            comp.VerifyDiagnostics(
                // (9,26): error CS8352: Cannot use variable 'local' in this context because it may expose referenced variables outside of their declaration scope
                //         sp = MayWrap(ref local) with { }; // 1, 2
                Diagnostic(ErrorCode.ERR_EscapeVariable, "local").WithArguments("local").WithLocation(9, 26),
                // (9,14): error CS8347: Cannot use a result of 'Program.MayWrap(ref Span<int>)' in this context because it may expose variables referenced by parameter 'arg' outside of their declaration scope
                //         sp = MayWrap(ref local) with { }; // 1, 2
                Diagnostic(ErrorCode.ERR_EscapeCall, "MayWrap(ref local)").WithArguments("Program.MayWrap(ref System.Span<int>)", "arg").WithLocation(9, 14));
        }
 
        [Fact]
        public void WithExprOnStruct_OnRefStruct_ReceiverMayWrap_02()
        {
            var text = @"
using System;
class Program
{
    static void Main()
    {
        Span<int> local = stackalloc int[1];
        S1 sp = MayWrap(ref local) with { };
    }
 
    static S1 MayWrap(ref Span<int> arg)
    {
        return default;
    }
 
    ref struct S1
    {
        public ref int this[int i] => throw null;
    }
}
";
            CreateCompilationWithMscorlibAndSpan(text, parseOptions: TestOptions.RegularPreview).VerifyDiagnostics();
        }
 
        [Fact]
        public void WithExpr_NullableAnalysis_01()
        {
            var src = @"
#nullable enable
record struct B(int X)
{
    static void M(B b)
    {
        string? s = null;
        _ = b with { X = M(out s) };
        s.ToString();
    }
 
    static int M(out string s) { s = ""a""; return 42; }
}";
            var comp = CreateCompilation(src);
            comp.VerifyDiagnostics();
        }
 
        [Fact]
        public void WithExpr_NullableAnalysis_02()
        {
            var src = @"
#nullable enable
record struct B(string X)
{
    static void M(B b, string? s)
    {
        b.X.ToString();
        _ = b with { X = s }; // 1
        b.X.ToString(); // 2
    }
}";
            var comp = CreateCompilation(src);
            comp.VerifyDiagnostics(
                // (8,26): warning CS8601: Possible null reference assignment.
                //         _ = b with { X = s }; // 1
                Diagnostic(ErrorCode.WRN_NullReferenceAssignment, "s").WithLocation(8, 26));
        }
 
        [Fact]
        public void WithExpr_NullableAnalysis_03()
        {
            var src = @"
#nullable enable
record struct B(string? X)
{
    static void M1(B b, string s, bool flag)
    {
        if (flag) { b.X.ToString(); } // 1
        _ = b with { X = s };
        if (flag) { b.X.ToString(); } // 2
    }
 
    static void M2(B b, string s, bool flag)
    {
        if (flag) { b.X.ToString(); } // 3
        b = b with { X = s };
        if (flag) { b.X.ToString(); }
    }
}";
            var comp = CreateCompilation(src);
            comp.VerifyDiagnostics(
                // (7,21): warning CS8602: Dereference of a possibly null reference.
                //         if (flag) { b.X.ToString(); } // 1
                Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "b.X").WithLocation(7, 21),
                // (9,21): warning CS8602: Dereference of a possibly null reference.
                //         if (flag) { b.X.ToString(); } // 2
                Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "b.X").WithLocation(9, 21),
                // (14,21): warning CS8602: Dereference of a possibly null reference.
                //         if (flag) { b.X.ToString(); } // 3
                Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "b.X").WithLocation(14, 21));
        }
 
        [Fact, WorkItem(44763, "https://github.com/dotnet/roslyn/issues/44763")]
        public void WithExpr_NullableAnalysis_05()
        {
            var src = @"
#nullable enable
record struct B(string? X, string? Y)
{
    static void M1(bool flag)
    {
        B b = new B(""hello"", null);
        if (flag)
        {
            b.X.ToString(); // shouldn't warn
            b.Y.ToString(); // 1
        }
 
        b = b with { Y = ""world"" };
        b.X.ToString(); // shouldn't warn
        b.Y.ToString();
    }
}";
            // records should propagate the nullability of the
            // constructor arguments to the corresponding properties.
            // https://github.com/dotnet/roslyn/issues/44763
            var comp = CreateCompilation(src);
            comp.VerifyDiagnostics(
                // (10,13): warning CS8602: Dereference of a possibly null reference.
                //             b.X.ToString(); // shouldn't warn
                Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "b.X").WithLocation(10, 13),
                // (11,13): warning CS8602: Dereference of a possibly null reference.
                //             b.Y.ToString(); // 1
                Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "b.Y").WithLocation(11, 13),
                // (15,9): warning CS8602: Dereference of a possibly null reference.
                //         b.X.ToString(); // shouldn't warn
                Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "b.X").WithLocation(15, 9));
        }
 
        [Fact]
        public void WithExpr_NullableAnalysis_06()
        {
            var src = @"
#nullable enable
struct B
{
    public string? X { get; init; }
    public string? Y { get; init; }
 
    static void M1(bool flag)
    {
        B b = new B { X = ""hello"", Y = null };
        if (flag)
        {
            b.X.ToString();
            b.Y.ToString(); // 1
        }
 
        b = b with { Y = ""world"" };
 
        b.X.ToString();
        b.Y.ToString();
    }
}";
            var comp = CreateCompilation(src);
            comp.VerifyDiagnostics(
                // (14,13): warning CS8602: Dereference of a possibly null reference.
                //             b.Y.ToString(); // 1
                Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "b.Y").WithLocation(14, 13)
            );
        }
 
        [Fact]
        public void WithExprAssignToRef1()
        {
            var src = @"
using System;
record struct C(int Y)
{
    private readonly int[] _a = new[] { 0 };
    public ref int X => ref _a[0];
 
    public static void Main()
    {
        var c = new C(0) { X = 5 };
        Console.WriteLine(c.X);
        c = c with { X = 1 };
        Console.WriteLine(c.X);
    }
}";
            var verifier = CompileAndVerify(src, expectedOutput: @"
5
1").VerifyDiagnostics();
 
            verifier.VerifyIL("C.Main", @"
{
  // Code size       59 (0x3b)
  .maxstack  2
  .locals init (C V_0, //c
                C V_1)
  IL_0000:  ldloca.s   V_1
  IL_0002:  ldc.i4.0
  IL_0003:  call       ""C..ctor(int)""
  IL_0008:  ldloca.s   V_1
  IL_000a:  call       ""ref int C.X.get""
  IL_000f:  ldc.i4.5
  IL_0010:  stind.i4
  IL_0011:  ldloc.1
  IL_0012:  stloc.0
  IL_0013:  ldloca.s   V_0
  IL_0015:  call       ""ref int C.X.get""
  IL_001a:  ldind.i4
  IL_001b:  call       ""void System.Console.WriteLine(int)""
  IL_0020:  ldloc.0
  IL_0021:  stloc.1
  IL_0022:  ldloca.s   V_1
  IL_0024:  call       ""ref int C.X.get""
  IL_0029:  ldc.i4.1
  IL_002a:  stind.i4
  IL_002b:  ldloc.1
  IL_002c:  stloc.0
  IL_002d:  ldloca.s   V_0
  IL_002f:  call       ""ref int C.X.get""
  IL_0034:  ldind.i4
  IL_0035:  call       ""void System.Console.WriteLine(int)""
  IL_003a:  ret
}");
        }
 
        [Fact]
        public void WithExpressionSameLHS()
        {
            var comp = CreateCompilation(@"
record struct C(int X)
{
    public static void Main()
    {
        var c = new C(0);
        c = c with { X = 1, X = 2};
    }
}");
            comp.VerifyDiagnostics(
                // (7,29): error CS1912: Duplicate initialization of member 'X'
                //         c = c with { X = 1, X = 2};
                Diagnostic(ErrorCode.ERR_MemberAlreadyInitialized, "X").WithArguments("X").WithLocation(7, 29)
            );
        }
 
        [Fact]
        public void WithExpr_AnonymousType_ChangeAllProperties()
        {
            var src = @"
C.M();
 
public class C
{
    public static void M()
    /*<bind>*/{
        var a = new { A = 10, B = 20 };
        var b = Identity(a) with { A = Identity(30), B = Identity(40) };
        System.Console.Write(b);
    }/*</bind>*/
 
    static T Identity<T>(T t)
    {
        System.Console.Write($""Identity({t}) "");
        return t;
    }
}";
            var comp = CreateCompilation(src, parseOptions: TestOptions.Regular9);
            comp.VerifyEmitDiagnostics(
                // (9,17): error CS8773: Feature 'with on anonymous types' is not available in C# 9.0. Please use language version 10.0 or greater.
                //         var b = Identity(a) with { A = Identity(30), B = Identity(40) };
                Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion9, "Identity(a) with { A = Identity(30), B = Identity(40) }").WithArguments("with on anonymous types", "10.0").WithLocation(9, 17)
                );
 
            comp = CreateCompilation(src, parseOptions: TestOptions.Regular10);
            comp.VerifyEmitDiagnostics();
            var verifier = CompileAndVerify(comp, expectedOutput: "Identity({ A = 10, B = 20 }) Identity(30) Identity(40) { A = 30, B = 40 }");
            verifier.VerifyIL("C.M", @"
{
  // Code size       42 (0x2a)
  .maxstack  2
  .locals init (int V_0)
  IL_0000:  ldc.i4.s   10
  IL_0002:  ldc.i4.s   20
  IL_0004:  newobj     ""<>f__AnonymousType0<int, int>..ctor(int, int)""
  IL_0009:  call       ""<anonymous type: int A, int B> C.Identity<<anonymous type: int A, int B>>(<anonymous type: int A, int B>)""
  IL_000e:  pop
  IL_000f:  ldc.i4.s   30
  IL_0011:  call       ""int C.Identity<int>(int)""
  IL_0016:  ldc.i4.s   40
  IL_0018:  call       ""int C.Identity<int>(int)""
  IL_001d:  stloc.0
  IL_001e:  ldloc.0
  IL_001f:  newobj     ""<>f__AnonymousType0<int, int>..ctor(int, int)""
  IL_0024:  call       ""void System.Console.Write(object)""
  IL_0029:  ret
}
");
            var expectedFlowGraph = @"
Block[B0] - Entry
    Statements (0)
    Next (Regular) Block[B1]
        Entering: {R1} {R2}
.locals {R1}
{
    Locals: [<anonymous type: System.Int32 A, System.Int32 B> a] [<anonymous type: System.Int32 A, System.Int32 B> b]
    .locals {R2}
    {
        CaptureIds: [0] [1]
        Block[B1] - Block
            Predecessors: [B0]
            Statements (3)
                IFlowCaptureOperation: 0 (OperationKind.FlowCapture, Type: null, IsImplicit) (Syntax: '10')
                  Value:
                    ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 10) (Syntax: '10')
                IFlowCaptureOperation: 1 (OperationKind.FlowCapture, Type: null, IsImplicit) (Syntax: '20')
                  Value:
                    ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 20) (Syntax: '20')
                ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: <anonymous type: System.Int32 A, System.Int32 B>, IsImplicit) (Syntax: 'a = new { A ... 0, B = 20 }')
                  Left:
                    ILocalReferenceOperation: a (IsDeclaration: True) (OperationKind.LocalReference, Type: <anonymous type: System.Int32 A, System.Int32 B>, IsImplicit) (Syntax: 'a = new { A ... 0, B = 20 }')
                  Right:
                    IAnonymousObjectCreationOperation (OperationKind.AnonymousObjectCreation, Type: <anonymous type: System.Int32 A, System.Int32 B>) (Syntax: 'new { A = 10, B = 20 }')
                      Initializers(2):
                          ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: System.Int32, Constant: 10) (Syntax: 'A = 10')
                            Left:
                              IPropertyReferenceOperation: System.Int32 <anonymous type: System.Int32 A, System.Int32 B>.A { get; } (OperationKind.PropertyReference, Type: System.Int32) (Syntax: 'A')
                                Instance Receiver:
                                  IInstanceReferenceOperation (ReferenceKind: ImplicitReceiver) (OperationKind.InstanceReference, Type: <anonymous type: System.Int32 A, System.Int32 B>, IsImplicit) (Syntax: 'new { A = 10, B = 20 }')
                            Right:
                              IFlowCaptureReferenceOperation: 0 (OperationKind.FlowCaptureReference, Type: System.Int32, Constant: 10, IsImplicit) (Syntax: '10')
                          ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: System.Int32, Constant: 20) (Syntax: 'B = 20')
                            Left:
                              IPropertyReferenceOperation: System.Int32 <anonymous type: System.Int32 A, System.Int32 B>.B { get; } (OperationKind.PropertyReference, Type: System.Int32) (Syntax: 'B')
                                Instance Receiver:
                                  IInstanceReferenceOperation (ReferenceKind: ImplicitReceiver) (OperationKind.InstanceReference, Type: <anonymous type: System.Int32 A, System.Int32 B>, IsImplicit) (Syntax: 'new { A = 10, B = 20 }')
                            Right:
                              IFlowCaptureReferenceOperation: 1 (OperationKind.FlowCaptureReference, Type: System.Int32, Constant: 20, IsImplicit) (Syntax: '20')
            Next (Regular) Block[B2]
                Leaving: {R2}
                Entering: {R3}
    }
    .locals {R3}
    {
        CaptureIds: [2] [3]
        Block[B2] - Block
            Predecessors: [B1]
            Statements (4)
                IInvocationOperation (<anonymous type: System.Int32 A, System.Int32 B> C.Identity<<anonymous type: System.Int32 A, System.Int32 B>>(<anonymous type: System.Int32 A, System.Int32 B> t)) (OperationKind.Invocation, Type: <anonymous type: System.Int32 A, System.Int32 B>) (Syntax: 'Identity(a)')
                  Instance Receiver:
                    null
                  Arguments(1):
                      IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: t) (OperationKind.Argument, Type: null) (Syntax: 'a')
                        ILocalReferenceOperation: a (OperationKind.LocalReference, Type: <anonymous type: System.Int32 A, System.Int32 B>) (Syntax: 'a')
                        InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null)
                        OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null)
                IFlowCaptureOperation: 2 (OperationKind.FlowCapture, Type: null, IsImplicit) (Syntax: 'Identity(30)')
                  Value:
                    IInvocationOperation (System.Int32 C.Identity<System.Int32>(System.Int32 t)) (OperationKind.Invocation, Type: System.Int32) (Syntax: 'Identity(30)')
                      Instance Receiver:
                        null
                      Arguments(1):
                          IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: t) (OperationKind.Argument, Type: null) (Syntax: '30')
                            ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 30) (Syntax: '30')
                            InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null)
                            OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null)
                IFlowCaptureOperation: 3 (OperationKind.FlowCapture, Type: null, IsImplicit) (Syntax: 'Identity(40)')
                  Value:
                    IInvocationOperation (System.Int32 C.Identity<System.Int32>(System.Int32 t)) (OperationKind.Invocation, Type: System.Int32) (Syntax: 'Identity(40)')
                      Instance Receiver:
                        null
                      Arguments(1):
                          IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: t) (OperationKind.Argument, Type: null) (Syntax: '40')
                            ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 40) (Syntax: '40')
                            InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null)
                            OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null)
                ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: <anonymous type: System.Int32 A, System.Int32 B>, IsImplicit) (Syntax: 'b = Identit ... ntity(40) }')
                  Left:
                    ILocalReferenceOperation: b (IsDeclaration: True) (OperationKind.LocalReference, Type: <anonymous type: System.Int32 A, System.Int32 B>, IsImplicit) (Syntax: 'b = Identit ... ntity(40) }')
                  Right:
                    IAnonymousObjectCreationOperation (OperationKind.AnonymousObjectCreation, Type: <anonymous type: System.Int32 A, System.Int32 B>) (Syntax: 'Identity(a) ... ntity(40) }')
                      Initializers(2):
                          ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: System.Int32, IsImplicit) (Syntax: 'Identity(a) ... ntity(40) }')
                            Left:
                              IPropertyReferenceOperation: System.Int32 <anonymous type: System.Int32 A, System.Int32 B>.A { get; } (OperationKind.PropertyReference, Type: System.Int32, IsImplicit) (Syntax: 'Identity(a) ... ntity(40) }')
                                Instance Receiver:
                                  IInstanceReferenceOperation (ReferenceKind: ImplicitReceiver) (OperationKind.InstanceReference, Type: <anonymous type: System.Int32 A, System.Int32 B>, IsImplicit) (Syntax: 'Identity(a) ... ntity(40) }')
                            Right:
                              IFlowCaptureReferenceOperation: 2 (OperationKind.FlowCaptureReference, Type: <anonymous type: System.Int32 A, System.Int32 B>, IsImplicit) (Syntax: 'Identity(a)')
                          ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: System.Int32, IsImplicit) (Syntax: 'Identity(a) ... ntity(40) }')
                            Left:
                              IPropertyReferenceOperation: System.Int32 <anonymous type: System.Int32 A, System.Int32 B>.B { get; } (OperationKind.PropertyReference, Type: System.Int32, IsImplicit) (Syntax: 'Identity(a) ... ntity(40) }')
                                Instance Receiver:
                                  IInstanceReferenceOperation (ReferenceKind: ImplicitReceiver) (OperationKind.InstanceReference, Type: <anonymous type: System.Int32 A, System.Int32 B>, IsImplicit) (Syntax: 'Identity(a) ... ntity(40) }')
                            Right:
                              IFlowCaptureReferenceOperation: 3 (OperationKind.FlowCaptureReference, Type: <anonymous type: System.Int32 A, System.Int32 B>, IsImplicit) (Syntax: 'Identity(a)')
            Next (Regular) Block[B3]
                Leaving: {R3}
    }
    Block[B3] - Block
        Predecessors: [B2]
        Statements (1)
            IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'System.Console.Write(b);')
              Expression:
                IInvocationOperation (void System.Console.Write(System.Object value)) (OperationKind.Invocation, Type: System.Void) (Syntax: 'System.Console.Write(b)')
                  Instance Receiver:
                    null
                  Arguments(1):
                      IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: value) (OperationKind.Argument, Type: null) (Syntax: 'b')
                        IConversionOperation (TryCast: False, Unchecked) (OperationKind.Conversion, Type: System.Object, IsImplicit) (Syntax: 'b')
                          Conversion: CommonConversion (Exists: True, IsIdentity: False, IsNumeric: False, IsReference: True, IsUserDefined: False) (MethodSymbol: null)
                            (ImplicitReference)
                          Operand:
                            ILocalReferenceOperation: b (OperationKind.LocalReference, Type: <anonymous type: System.Int32 A, System.Int32 B>) (Syntax: 'b')
                        InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null)
                        OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null)
        Next (Regular) Block[B4]
            Leaving: {R1}
}
Block[B4] - Exit
    Predecessors: [B3]
    Statements (0)
";
            var expectedDiagnostics = DiagnosticDescription.None;
 
            VerifyFlowGraphAndDiagnosticsForTest<BlockSyntax>(src, expectedFlowGraph, expectedDiagnostics, parseOptions: TestOptions.RegularPreview);
        }
 
        [Fact]
        public void WithExpr_AnonymousType_ChangeAllProperties_ReverseOrder()
        {
            var src = @"
C.M();
 
public class C
{
    public static void M()
    /*<bind>*/{
        var a = new { A = 10, B = 20 };
        var b = Identity(a) with { B = Identity(40), A = Identity(30) };
        System.Console.Write(b);
    }/*</bind>*/
 
    static T Identity<T>(T t)
    {
        System.Console.Write($""Identity({t}) "");
        return t;
    }
}";
 
            var comp = CreateCompilation(src, parseOptions: TestOptions.RegularPreview);
            comp.VerifyEmitDiagnostics();
            var verifier = CompileAndVerify(comp, expectedOutput: "Identity({ A = 10, B = 20 }) Identity(40) Identity(30) { A = 30, B = 40 }");
            verifier.VerifyIL("C.M", @"
{
  // Code size       42 (0x2a)
  .maxstack  2
  .locals init (int V_0)
  IL_0000:  ldc.i4.s   10
  IL_0002:  ldc.i4.s   20
  IL_0004:  newobj     ""<>f__AnonymousType0<int, int>..ctor(int, int)""
  IL_0009:  call       ""<anonymous type: int A, int B> C.Identity<<anonymous type: int A, int B>>(<anonymous type: int A, int B>)""
  IL_000e:  pop
  IL_000f:  ldc.i4.s   40
  IL_0011:  call       ""int C.Identity<int>(int)""
  IL_0016:  stloc.0
  IL_0017:  ldc.i4.s   30
  IL_0019:  call       ""int C.Identity<int>(int)""
  IL_001e:  ldloc.0
  IL_001f:  newobj     ""<>f__AnonymousType0<int, int>..ctor(int, int)""
  IL_0024:  call       ""void System.Console.Write(object)""
  IL_0029:  ret
}
");
            var expectedFlowGraph = @"
Block[B0] - Entry
    Statements (0)
    Next (Regular) Block[B1]
        Entering: {R1} {R2}
.locals {R1}
{
    Locals: [<anonymous type: System.Int32 A, System.Int32 B> a] [<anonymous type: System.Int32 A, System.Int32 B> b]
    .locals {R2}
    {
        CaptureIds: [0] [1]
        Block[B1] - Block
            Predecessors: [B0]
            Statements (3)
                IFlowCaptureOperation: 0 (OperationKind.FlowCapture, Type: null, IsImplicit) (Syntax: '10')
                  Value:
                    ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 10) (Syntax: '10')
                IFlowCaptureOperation: 1 (OperationKind.FlowCapture, Type: null, IsImplicit) (Syntax: '20')
                  Value:
                    ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 20) (Syntax: '20')
                ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: <anonymous type: System.Int32 A, System.Int32 B>, IsImplicit) (Syntax: 'a = new { A ... 0, B = 20 }')
                  Left:
                    ILocalReferenceOperation: a (IsDeclaration: True) (OperationKind.LocalReference, Type: <anonymous type: System.Int32 A, System.Int32 B>, IsImplicit) (Syntax: 'a = new { A ... 0, B = 20 }')
                  Right:
                    IAnonymousObjectCreationOperation (OperationKind.AnonymousObjectCreation, Type: <anonymous type: System.Int32 A, System.Int32 B>) (Syntax: 'new { A = 10, B = 20 }')
                      Initializers(2):
                          ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: System.Int32, Constant: 10) (Syntax: 'A = 10')
                            Left:
                              IPropertyReferenceOperation: System.Int32 <anonymous type: System.Int32 A, System.Int32 B>.A { get; } (OperationKind.PropertyReference, Type: System.Int32) (Syntax: 'A')
                                Instance Receiver:
                                  IInstanceReferenceOperation (ReferenceKind: ImplicitReceiver) (OperationKind.InstanceReference, Type: <anonymous type: System.Int32 A, System.Int32 B>, IsImplicit) (Syntax: 'new { A = 10, B = 20 }')
                            Right:
                              IFlowCaptureReferenceOperation: 0 (OperationKind.FlowCaptureReference, Type: System.Int32, Constant: 10, IsImplicit) (Syntax: '10')
                          ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: System.Int32, Constant: 20) (Syntax: 'B = 20')
                            Left:
                              IPropertyReferenceOperation: System.Int32 <anonymous type: System.Int32 A, System.Int32 B>.B { get; } (OperationKind.PropertyReference, Type: System.Int32) (Syntax: 'B')
                                Instance Receiver:
                                  IInstanceReferenceOperation (ReferenceKind: ImplicitReceiver) (OperationKind.InstanceReference, Type: <anonymous type: System.Int32 A, System.Int32 B>, IsImplicit) (Syntax: 'new { A = 10, B = 20 }')
                            Right:
                              IFlowCaptureReferenceOperation: 1 (OperationKind.FlowCaptureReference, Type: System.Int32, Constant: 20, IsImplicit) (Syntax: '20')
            Next (Regular) Block[B2]
                Leaving: {R2}
                Entering: {R3}
    }
    .locals {R3}
    {
        CaptureIds: [2] [3]
        Block[B2] - Block
            Predecessors: [B1]
            Statements (4)
                IInvocationOperation (<anonymous type: System.Int32 A, System.Int32 B> C.Identity<<anonymous type: System.Int32 A, System.Int32 B>>(<anonymous type: System.Int32 A, System.Int32 B> t)) (OperationKind.Invocation, Type: <anonymous type: System.Int32 A, System.Int32 B>) (Syntax: 'Identity(a)')
                  Instance Receiver:
                    null
                  Arguments(1):
                      IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: t) (OperationKind.Argument, Type: null) (Syntax: 'a')
                        ILocalReferenceOperation: a (OperationKind.LocalReference, Type: <anonymous type: System.Int32 A, System.Int32 B>) (Syntax: 'a')
                        InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null)
                        OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null)
                IFlowCaptureOperation: 2 (OperationKind.FlowCapture, Type: null, IsImplicit) (Syntax: 'Identity(40)')
                  Value:
                    IInvocationOperation (System.Int32 C.Identity<System.Int32>(System.Int32 t)) (OperationKind.Invocation, Type: System.Int32) (Syntax: 'Identity(40)')
                      Instance Receiver:
                        null
                      Arguments(1):
                          IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: t) (OperationKind.Argument, Type: null) (Syntax: '40')
                            ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 40) (Syntax: '40')
                            InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null)
                            OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null)
                IFlowCaptureOperation: 3 (OperationKind.FlowCapture, Type: null, IsImplicit) (Syntax: 'Identity(30)')
                  Value:
                    IInvocationOperation (System.Int32 C.Identity<System.Int32>(System.Int32 t)) (OperationKind.Invocation, Type: System.Int32) (Syntax: 'Identity(30)')
                      Instance Receiver:
                        null
                      Arguments(1):
                          IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: t) (OperationKind.Argument, Type: null) (Syntax: '30')
                            ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 30) (Syntax: '30')
                            InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null)
                            OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null)
                ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: <anonymous type: System.Int32 A, System.Int32 B>, IsImplicit) (Syntax: 'b = Identit ... ntity(30) }')
                  Left:
                    ILocalReferenceOperation: b (IsDeclaration: True) (OperationKind.LocalReference, Type: <anonymous type: System.Int32 A, System.Int32 B>, IsImplicit) (Syntax: 'b = Identit ... ntity(30) }')
                  Right:
                    IAnonymousObjectCreationOperation (OperationKind.AnonymousObjectCreation, Type: <anonymous type: System.Int32 A, System.Int32 B>) (Syntax: 'Identity(a) ... ntity(30) }')
                      Initializers(2):
                          ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: System.Int32, IsImplicit) (Syntax: 'Identity(a) ... ntity(30) }')
                            Left:
                              IPropertyReferenceOperation: System.Int32 <anonymous type: System.Int32 A, System.Int32 B>.A { get; } (OperationKind.PropertyReference, Type: System.Int32, IsImplicit) (Syntax: 'Identity(a) ... ntity(30) }')
                                Instance Receiver:
                                  IInstanceReferenceOperation (ReferenceKind: ImplicitReceiver) (OperationKind.InstanceReference, Type: <anonymous type: System.Int32 A, System.Int32 B>, IsImplicit) (Syntax: 'Identity(a) ... ntity(30) }')
                            Right:
                              IFlowCaptureReferenceOperation: 3 (OperationKind.FlowCaptureReference, Type: <anonymous type: System.Int32 A, System.Int32 B>, IsImplicit) (Syntax: 'Identity(a)')
                          ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: System.Int32, IsImplicit) (Syntax: 'Identity(a) ... ntity(30) }')
                            Left:
                              IPropertyReferenceOperation: System.Int32 <anonymous type: System.Int32 A, System.Int32 B>.B { get; } (OperationKind.PropertyReference, Type: System.Int32, IsImplicit) (Syntax: 'Identity(a) ... ntity(30) }')
                                Instance Receiver:
                                  IInstanceReferenceOperation (ReferenceKind: ImplicitReceiver) (OperationKind.InstanceReference, Type: <anonymous type: System.Int32 A, System.Int32 B>, IsImplicit) (Syntax: 'Identity(a) ... ntity(30) }')
                            Right:
                              IFlowCaptureReferenceOperation: 2 (OperationKind.FlowCaptureReference, Type: <anonymous type: System.Int32 A, System.Int32 B>, IsImplicit) (Syntax: 'Identity(a)')
            Next (Regular) Block[B3]
                Leaving: {R3}
    }
    Block[B3] - Block
        Predecessors: [B2]
        Statements (1)
            IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'System.Console.Write(b);')
              Expression:
                IInvocationOperation (void System.Console.Write(System.Object value)) (OperationKind.Invocation, Type: System.Void) (Syntax: 'System.Console.Write(b)')
                  Instance Receiver:
                    null
                  Arguments(1):
                      IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: value) (OperationKind.Argument, Type: null) (Syntax: 'b')
                        IConversionOperation (TryCast: False, Unchecked) (OperationKind.Conversion, Type: System.Object, IsImplicit) (Syntax: 'b')
                          Conversion: CommonConversion (Exists: True, IsIdentity: False, IsNumeric: False, IsReference: True, IsUserDefined: False) (MethodSymbol: null)
                            (ImplicitReference)
                          Operand:
                            ILocalReferenceOperation: b (OperationKind.LocalReference, Type: <anonymous type: System.Int32 A, System.Int32 B>) (Syntax: 'b')
                        InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null)
                        OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null)
        Next (Regular) Block[B4]
            Leaving: {R1}
}
Block[B4] - Exit
    Predecessors: [B3]
    Statements (0)
";
            var expectedDiagnostics = DiagnosticDescription.None;
 
            VerifyFlowGraphAndDiagnosticsForTest<BlockSyntax>(src, expectedFlowGraph, expectedDiagnostics, parseOptions: TestOptions.RegularPreview);
        }
 
        [Fact]
        public void WithExpr_AnonymousType_ChangeNoProperty()
        {
            var src = @"
C.M();
 
public class C
{
    public static void M()
    /*<bind>*/{
        var a = new { A = 10, B = 20 };
        var b = M2(a) with { };
        System.Console.Write(b);
    }/*</bind>*/
 
    static T M2<T>(T t)
    {
        System.Console.Write(""M2 "");
        return t;
    }
}";
            var comp = CreateCompilation(src, parseOptions: TestOptions.RegularPreview);
            comp.VerifyEmitDiagnostics();
            var verifier = CompileAndVerify(comp, expectedOutput: "M2 { A = 10, B = 20 }");
            verifier.VerifyIL("C.M", @"
{
  // Code size       38 (0x26)
  .maxstack  2
  .locals init (<>f__AnonymousType0<int, int> V_0)
  IL_0000:  ldc.i4.s   10
  IL_0002:  ldc.i4.s   20
  IL_0004:  newobj     ""<>f__AnonymousType0<int, int>..ctor(int, int)""
  IL_0009:  call       ""<anonymous type: int A, int B> C.M2<<anonymous type: int A, int B>>(<anonymous type: int A, int B>)""
  IL_000e:  stloc.0
  IL_000f:  ldloc.0
  IL_0010:  callvirt   ""int <>f__AnonymousType0<int, int>.A.get""
  IL_0015:  ldloc.0
  IL_0016:  callvirt   ""int <>f__AnonymousType0<int, int>.B.get""
  IL_001b:  newobj     ""<>f__AnonymousType0<int, int>..ctor(int, int)""
  IL_0020:  call       ""void System.Console.Write(object)""
  IL_0025:  ret
}
");
 
            var expectedFlowGraph = @"
Block[B0] - Entry
    Statements (0)
    Next (Regular) Block[B1]
        Entering: {R1} {R2}
.locals {R1}
{
    Locals: [<anonymous type: System.Int32 A, System.Int32 B> a] [<anonymous type: System.Int32 A, System.Int32 B> b]
    .locals {R2}
    {
        CaptureIds: [0] [1]
        Block[B1] - Block
            Predecessors: [B0]
            Statements (3)
                IFlowCaptureOperation: 0 (OperationKind.FlowCapture, Type: null, IsImplicit) (Syntax: '10')
                  Value:
                    ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 10) (Syntax: '10')
                IFlowCaptureOperation: 1 (OperationKind.FlowCapture, Type: null, IsImplicit) (Syntax: '20')
                  Value:
                    ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 20) (Syntax: '20')
                ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: <anonymous type: System.Int32 A, System.Int32 B>, IsImplicit) (Syntax: 'a = new { A ... 0, B = 20 }')
                  Left:
                    ILocalReferenceOperation: a (IsDeclaration: True) (OperationKind.LocalReference, Type: <anonymous type: System.Int32 A, System.Int32 B>, IsImplicit) (Syntax: 'a = new { A ... 0, B = 20 }')
                  Right:
                    IAnonymousObjectCreationOperation (OperationKind.AnonymousObjectCreation, Type: <anonymous type: System.Int32 A, System.Int32 B>) (Syntax: 'new { A = 10, B = 20 }')
                      Initializers(2):
                          ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: System.Int32, Constant: 10) (Syntax: 'A = 10')
                            Left:
                              IPropertyReferenceOperation: System.Int32 <anonymous type: System.Int32 A, System.Int32 B>.A { get; } (OperationKind.PropertyReference, Type: System.Int32) (Syntax: 'A')
                                Instance Receiver:
                                  IInstanceReferenceOperation (ReferenceKind: ImplicitReceiver) (OperationKind.InstanceReference, Type: <anonymous type: System.Int32 A, System.Int32 B>, IsImplicit) (Syntax: 'new { A = 10, B = 20 }')
                            Right:
                              IFlowCaptureReferenceOperation: 0 (OperationKind.FlowCaptureReference, Type: System.Int32, Constant: 10, IsImplicit) (Syntax: '10')
                          ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: System.Int32, Constant: 20) (Syntax: 'B = 20')
                            Left:
                              IPropertyReferenceOperation: System.Int32 <anonymous type: System.Int32 A, System.Int32 B>.B { get; } (OperationKind.PropertyReference, Type: System.Int32) (Syntax: 'B')
                                Instance Receiver:
                                  IInstanceReferenceOperation (ReferenceKind: ImplicitReceiver) (OperationKind.InstanceReference, Type: <anonymous type: System.Int32 A, System.Int32 B>, IsImplicit) (Syntax: 'new { A = 10, B = 20 }')
                            Right:
                              IFlowCaptureReferenceOperation: 1 (OperationKind.FlowCaptureReference, Type: System.Int32, Constant: 20, IsImplicit) (Syntax: '20')
            Next (Regular) Block[B2]
                Leaving: {R2}
                Entering: {R3} {R4}
    }
    .locals {R3}
    {
        CaptureIds: [3] [4]
        .locals {R4}
        {
            CaptureIds: [2]
            Block[B2] - Block
                Predecessors: [B1]
                Statements (3)
                    IFlowCaptureOperation: 2 (OperationKind.FlowCapture, Type: null, IsImplicit) (Syntax: 'M2(a)')
                      Value:
                        IInvocationOperation (<anonymous type: System.Int32 A, System.Int32 B> C.M2<<anonymous type: System.Int32 A, System.Int32 B>>(<anonymous type: System.Int32 A, System.Int32 B> t)) (OperationKind.Invocation, Type: <anonymous type: System.Int32 A, System.Int32 B>) (Syntax: 'M2(a)')
                          Instance Receiver:
                            null
                          Arguments(1):
                              IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: t) (OperationKind.Argument, Type: null) (Syntax: 'a')
                                ILocalReferenceOperation: a (OperationKind.LocalReference, Type: <anonymous type: System.Int32 A, System.Int32 B>) (Syntax: 'a')
                                InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null)
                                OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null)
                    IFlowCaptureOperation: 3 (OperationKind.FlowCapture, Type: null, IsImplicit) (Syntax: 'M2(a) with { }')
                      Value:
                        IPropertyReferenceOperation: System.Int32 <anonymous type: System.Int32 A, System.Int32 B>.A { get; } (OperationKind.PropertyReference, Type: System.Int32, IsImplicit) (Syntax: 'M2(a) with { }')
                          Instance Receiver:
                            IFlowCaptureReferenceOperation: 2 (OperationKind.FlowCaptureReference, Type: <anonymous type: System.Int32 A, System.Int32 B>, IsImplicit) (Syntax: 'M2(a)')
                    IFlowCaptureOperation: 4 (OperationKind.FlowCapture, Type: null, IsImplicit) (Syntax: 'M2(a) with { }')
                      Value:
                        IPropertyReferenceOperation: System.Int32 <anonymous type: System.Int32 A, System.Int32 B>.B { get; } (OperationKind.PropertyReference, Type: System.Int32, IsImplicit) (Syntax: 'M2(a) with { }')
                          Instance Receiver:
                            IFlowCaptureReferenceOperation: 2 (OperationKind.FlowCaptureReference, Type: <anonymous type: System.Int32 A, System.Int32 B>, IsImplicit) (Syntax: 'M2(a)')
                Next (Regular) Block[B3]
                    Leaving: {R4}
        }
        Block[B3] - Block
            Predecessors: [B2]
            Statements (1)
                ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: <anonymous type: System.Int32 A, System.Int32 B>, IsImplicit) (Syntax: 'b = M2(a) with { }')
                  Left:
                    ILocalReferenceOperation: b (IsDeclaration: True) (OperationKind.LocalReference, Type: <anonymous type: System.Int32 A, System.Int32 B>, IsImplicit) (Syntax: 'b = M2(a) with { }')
                  Right:
                    IAnonymousObjectCreationOperation (OperationKind.AnonymousObjectCreation, Type: <anonymous type: System.Int32 A, System.Int32 B>) (Syntax: 'M2(a) with { }')
                      Initializers(2):
                          ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: System.Int32, IsImplicit) (Syntax: 'M2(a) with { }')
                            Left:
                              IPropertyReferenceOperation: System.Int32 <anonymous type: System.Int32 A, System.Int32 B>.A { get; } (OperationKind.PropertyReference, Type: System.Int32, IsImplicit) (Syntax: 'M2(a) with { }')
                                Instance Receiver:
                                  IInstanceReferenceOperation (ReferenceKind: ImplicitReceiver) (OperationKind.InstanceReference, Type: <anonymous type: System.Int32 A, System.Int32 B>, IsImplicit) (Syntax: 'M2(a) with { }')
                            Right:
                              IFlowCaptureReferenceOperation: 3 (OperationKind.FlowCaptureReference, Type: <anonymous type: System.Int32 A, System.Int32 B>, IsImplicit) (Syntax: 'M2(a)')
                          ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: System.Int32, IsImplicit) (Syntax: 'M2(a) with { }')
                            Left:
                              IPropertyReferenceOperation: System.Int32 <anonymous type: System.Int32 A, System.Int32 B>.B { get; } (OperationKind.PropertyReference, Type: System.Int32, IsImplicit) (Syntax: 'M2(a) with { }')
                                Instance Receiver:
                                  IInstanceReferenceOperation (ReferenceKind: ImplicitReceiver) (OperationKind.InstanceReference, Type: <anonymous type: System.Int32 A, System.Int32 B>, IsImplicit) (Syntax: 'M2(a) with { }')
                            Right:
                              IFlowCaptureReferenceOperation: 4 (OperationKind.FlowCaptureReference, Type: <anonymous type: System.Int32 A, System.Int32 B>, IsImplicit) (Syntax: 'M2(a)')
            Next (Regular) Block[B4]
                Leaving: {R3}
    }
    Block[B4] - Block
        Predecessors: [B3]
        Statements (1)
            IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'System.Console.Write(b);')
              Expression:
                IInvocationOperation (void System.Console.Write(System.Object value)) (OperationKind.Invocation, Type: System.Void) (Syntax: 'System.Console.Write(b)')
                  Instance Receiver:
                    null
                  Arguments(1):
                      IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: value) (OperationKind.Argument, Type: null) (Syntax: 'b')
                        IConversionOperation (TryCast: False, Unchecked) (OperationKind.Conversion, Type: System.Object, IsImplicit) (Syntax: 'b')
                          Conversion: CommonConversion (Exists: True, IsIdentity: False, IsNumeric: False, IsReference: True, IsUserDefined: False) (MethodSymbol: null)
                            (ImplicitReference)
                          Operand:
                            ILocalReferenceOperation: b (OperationKind.LocalReference, Type: <anonymous type: System.Int32 A, System.Int32 B>) (Syntax: 'b')
                        InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null)
                        OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null)
        Next (Regular) Block[B5]
            Leaving: {R1}
}
Block[B5] - Exit
    Predecessors: [B4]
    Statements (0)
";
            var expectedDiagnostics = DiagnosticDescription.None;
 
            VerifyFlowGraphAndDiagnosticsForTest<BlockSyntax>(src, expectedFlowGraph, expectedDiagnostics, parseOptions: TestOptions.RegularPreview);
        }
 
        [Fact]
        public void WithExpr_AnonymousType_ChangeOneProperty()
        {
            var src = @"
C.M();
 
public class C
{
    public static void M()
    /*<bind>*/{
        var a = new { A = 10, B = 20 };
        var b = a with { B = Identity(30) };
        System.Console.Write(b);
    }/*</bind>*/
 
    static T Identity<T>(T t) => t;
}";
            var comp = CreateCompilation(src, parseOptions: TestOptions.RegularPreview);
            comp.VerifyEmitDiagnostics();
            var verifier = CompileAndVerify(comp, expectedOutput: "{ A = 10, B = 30 }");
            verifier.VerifyIL("C.M", @"
{
  // Code size       34 (0x22)
  .maxstack  2
  .locals init (int V_0)
  IL_0000:  ldc.i4.s   10
  IL_0002:  ldc.i4.s   20
  IL_0004:  newobj     ""<>f__AnonymousType0<int, int>..ctor(int, int)""
  IL_0009:  ldc.i4.s   30
  IL_000b:  call       ""int C.Identity<int>(int)""
  IL_0010:  stloc.0
  IL_0011:  callvirt   ""int <>f__AnonymousType0<int, int>.A.get""
  IL_0016:  ldloc.0
  IL_0017:  newobj     ""<>f__AnonymousType0<int, int>..ctor(int, int)""
  IL_001c:  call       ""void System.Console.Write(object)""
  IL_0021:  ret
}
");
 
            var tree = comp.SyntaxTrees.Single();
            var model = comp.GetSemanticModel(tree, ignoreAccessibility: false);
            var withExpr = tree.GetRoot().DescendantNodes().OfType<WithExpressionSyntax>().Single();
            var operation = model.GetOperation(withExpr);
 
            VerifyOperationTree(comp, operation, @"
IWithOperation (OperationKind.With, Type: <anonymous type: System.Int32 A, System.Int32 B>) (Syntax: 'a with { B  ... ntity(30) }')
  Operand:
    ILocalReferenceOperation: a (OperationKind.LocalReference, Type: <anonymous type: System.Int32 A, System.Int32 B>) (Syntax: 'a')
  CloneMethod: null
  Initializer:
    IObjectOrCollectionInitializerOperation (OperationKind.ObjectOrCollectionInitializer, Type: <anonymous type: System.Int32 A, System.Int32 B>) (Syntax: '{ B = Identity(30) }')
      Initializers(1):
          ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: System.Int32) (Syntax: 'B = Identity(30)')
            Left:
              IPropertyReferenceOperation: System.Int32 <anonymous type: System.Int32 A, System.Int32 B>.B { get; } (OperationKind.PropertyReference, Type: System.Int32) (Syntax: 'B')
                Instance Receiver:
                  IInstanceReferenceOperation (ReferenceKind: ImplicitReceiver) (OperationKind.InstanceReference, Type: <anonymous type: System.Int32 A, System.Int32 B>, IsImplicit) (Syntax: 'B')
            Right:
              IInvocationOperation (System.Int32 C.Identity<System.Int32>(System.Int32 t)) (OperationKind.Invocation, Type: System.Int32) (Syntax: 'Identity(30)')
                Instance Receiver:
                  null
                Arguments(1):
                    IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: t) (OperationKind.Argument, Type: null) (Syntax: '30')
                      ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 30) (Syntax: '30')
                      InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null)
                      OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null)
");
 
            var expectedFlowGraph = @"
Block[B0] - Entry
    Statements (0)
    Next (Regular) Block[B1]
        Entering: {R1} {R2}
.locals {R1}
{
    Locals: [<anonymous type: System.Int32 A, System.Int32 B> a] [<anonymous type: System.Int32 A, System.Int32 B> b]
    .locals {R2}
    {
        CaptureIds: [0] [1]
        Block[B1] - Block
            Predecessors: [B0]
            Statements (3)
                IFlowCaptureOperation: 0 (OperationKind.FlowCapture, Type: null, IsImplicit) (Syntax: '10')
                  Value:
                    ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 10) (Syntax: '10')
                IFlowCaptureOperation: 1 (OperationKind.FlowCapture, Type: null, IsImplicit) (Syntax: '20')
                  Value:
                    ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 20) (Syntax: '20')
                ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: <anonymous type: System.Int32 A, System.Int32 B>, IsImplicit) (Syntax: 'a = new { A ... 0, B = 20 }')
                  Left:
                    ILocalReferenceOperation: a (IsDeclaration: True) (OperationKind.LocalReference, Type: <anonymous type: System.Int32 A, System.Int32 B>, IsImplicit) (Syntax: 'a = new { A ... 0, B = 20 }')
                  Right:
                    IAnonymousObjectCreationOperation (OperationKind.AnonymousObjectCreation, Type: <anonymous type: System.Int32 A, System.Int32 B>) (Syntax: 'new { A = 10, B = 20 }')
                      Initializers(2):
                          ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: System.Int32, Constant: 10) (Syntax: 'A = 10')
                            Left:
                              IPropertyReferenceOperation: System.Int32 <anonymous type: System.Int32 A, System.Int32 B>.A { get; } (OperationKind.PropertyReference, Type: System.Int32) (Syntax: 'A')
                                Instance Receiver:
                                  IInstanceReferenceOperation (ReferenceKind: ImplicitReceiver) (OperationKind.InstanceReference, Type: <anonymous type: System.Int32 A, System.Int32 B>, IsImplicit) (Syntax: 'new { A = 10, B = 20 }')
                            Right:
                              IFlowCaptureReferenceOperation: 0 (OperationKind.FlowCaptureReference, Type: System.Int32, Constant: 10, IsImplicit) (Syntax: '10')
                          ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: System.Int32, Constant: 20) (Syntax: 'B = 20')
                            Left:
                              IPropertyReferenceOperation: System.Int32 <anonymous type: System.Int32 A, System.Int32 B>.B { get; } (OperationKind.PropertyReference, Type: System.Int32) (Syntax: 'B')
                                Instance Receiver:
                                  IInstanceReferenceOperation (ReferenceKind: ImplicitReceiver) (OperationKind.InstanceReference, Type: <anonymous type: System.Int32 A, System.Int32 B>, IsImplicit) (Syntax: 'new { A = 10, B = 20 }')
                            Right:
                              IFlowCaptureReferenceOperation: 1 (OperationKind.FlowCaptureReference, Type: System.Int32, Constant: 20, IsImplicit) (Syntax: '20')
            Next (Regular) Block[B2]
                Leaving: {R2}
                Entering: {R3} {R4}
    }
    .locals {R3}
    {
        CaptureIds: [3] [4]
        .locals {R4}
        {
            CaptureIds: [2]
            Block[B2] - Block
                Predecessors: [B1]
                Statements (3)
                    IFlowCaptureOperation: 2 (OperationKind.FlowCapture, Type: null, IsImplicit) (Syntax: 'a')
                      Value:
                        ILocalReferenceOperation: a (OperationKind.LocalReference, Type: <anonymous type: System.Int32 A, System.Int32 B>) (Syntax: 'a')
                    IFlowCaptureOperation: 3 (OperationKind.FlowCapture, Type: null, IsImplicit) (Syntax: 'Identity(30)')
                      Value:
                        IInvocationOperation (System.Int32 C.Identity<System.Int32>(System.Int32 t)) (OperationKind.Invocation, Type: System.Int32) (Syntax: 'Identity(30)')
                          Instance Receiver:
                            null
                          Arguments(1):
                              IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: t) (OperationKind.Argument, Type: null) (Syntax: '30')
                                ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 30) (Syntax: '30')
                                InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null)
                                OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null)
                    IFlowCaptureOperation: 4 (OperationKind.FlowCapture, Type: null, IsImplicit) (Syntax: 'a with { B  ... ntity(30) }')
                      Value:
                        IPropertyReferenceOperation: System.Int32 <anonymous type: System.Int32 A, System.Int32 B>.A { get; } (OperationKind.PropertyReference, Type: System.Int32, IsImplicit) (Syntax: 'a with { B  ... ntity(30) }')
                          Instance Receiver:
                            IFlowCaptureReferenceOperation: 2 (OperationKind.FlowCaptureReference, Type: <anonymous type: System.Int32 A, System.Int32 B>, IsImplicit) (Syntax: 'a')
                Next (Regular) Block[B3]
                    Leaving: {R4}
        }
        Block[B3] - Block
            Predecessors: [B2]
            Statements (1)
                ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: <anonymous type: System.Int32 A, System.Int32 B>, IsImplicit) (Syntax: 'b = a with  ... ntity(30) }')
                  Left:
                    ILocalReferenceOperation: b (IsDeclaration: True) (OperationKind.LocalReference, Type: <anonymous type: System.Int32 A, System.Int32 B>, IsImplicit) (Syntax: 'b = a with  ... ntity(30) }')
                  Right:
                    IAnonymousObjectCreationOperation (OperationKind.AnonymousObjectCreation, Type: <anonymous type: System.Int32 A, System.Int32 B>) (Syntax: 'a with { B  ... ntity(30) }')
                      Initializers(2):
                          ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: System.Int32, IsImplicit) (Syntax: 'a with { B  ... ntity(30) }')
                            Left:
                              IPropertyReferenceOperation: System.Int32 <anonymous type: System.Int32 A, System.Int32 B>.A { get; } (OperationKind.PropertyReference, Type: System.Int32, IsImplicit) (Syntax: 'a with { B  ... ntity(30) }')
                                Instance Receiver:
                                  IInstanceReferenceOperation (ReferenceKind: ImplicitReceiver) (OperationKind.InstanceReference, Type: <anonymous type: System.Int32 A, System.Int32 B>, IsImplicit) (Syntax: 'a with { B  ... ntity(30) }')
                            Right:
                              IFlowCaptureReferenceOperation: 4 (OperationKind.FlowCaptureReference, Type: <anonymous type: System.Int32 A, System.Int32 B>, IsImplicit) (Syntax: 'a')
                          ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: System.Int32, IsImplicit) (Syntax: 'a with { B  ... ntity(30) }')
                            Left:
                              IPropertyReferenceOperation: System.Int32 <anonymous type: System.Int32 A, System.Int32 B>.B { get; } (OperationKind.PropertyReference, Type: System.Int32, IsImplicit) (Syntax: 'a with { B  ... ntity(30) }')
                                Instance Receiver:
                                  IInstanceReferenceOperation (ReferenceKind: ImplicitReceiver) (OperationKind.InstanceReference, Type: <anonymous type: System.Int32 A, System.Int32 B>, IsImplicit) (Syntax: 'a with { B  ... ntity(30) }')
                            Right:
                              IFlowCaptureReferenceOperation: 3 (OperationKind.FlowCaptureReference, Type: <anonymous type: System.Int32 A, System.Int32 B>, IsImplicit) (Syntax: 'a')
            Next (Regular) Block[B4]
                Leaving: {R3}
    }
    Block[B4] - Block
        Predecessors: [B3]
        Statements (1)
            IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'System.Console.Write(b);')
              Expression:
                IInvocationOperation (void System.Console.Write(System.Object value)) (OperationKind.Invocation, Type: System.Void) (Syntax: 'System.Console.Write(b)')
                  Instance Receiver:
                    null
                  Arguments(1):
                      IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: value) (OperationKind.Argument, Type: null) (Syntax: 'b')
                        IConversionOperation (TryCast: False, Unchecked) (OperationKind.Conversion, Type: System.Object, IsImplicit) (Syntax: 'b')
                          Conversion: CommonConversion (Exists: True, IsIdentity: False, IsNumeric: False, IsReference: True, IsUserDefined: False) (MethodSymbol: null)
                            (ImplicitReference)
                          Operand:
                            ILocalReferenceOperation: b (OperationKind.LocalReference, Type: <anonymous type: System.Int32 A, System.Int32 B>) (Syntax: 'b')
                        InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null)
                        OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null)
        Next (Regular) Block[B5]
            Leaving: {R1}
}
Block[B5] - Exit
    Predecessors: [B4]
    Statements (0)
";
            var expectedDiagnostics = DiagnosticDescription.None;
 
            VerifyFlowGraphAndDiagnosticsForTest<BlockSyntax>(src, expectedFlowGraph, expectedDiagnostics, parseOptions: TestOptions.RegularPreview);
        }
 
        [Fact]
        public void WithExpr_AnonymousType_ChangeOneProperty_WithMethodCallForTarget()
        {
            var src = @"
C.M();
 
public class C
{
    public static void M()
    /*<bind>*/{
        var a = new { A = 10, B = 20 };
        var b = Identity(a) with { B = 30 };
        System.Console.Write(b);
    }/*</bind>*/
 
    static T Identity<T>(T t) => t;
}";
            var comp = CreateCompilation(src, parseOptions: TestOptions.RegularPreview);
            comp.VerifyEmitDiagnostics();
            var verifier = CompileAndVerify(comp, expectedOutput: "{ A = 10, B = 30 }");
            verifier.VerifyIL("C.M", @"
{
  // Code size       34 (0x22)
  .maxstack  2
  .locals init (int V_0)
  IL_0000:  ldc.i4.s   10
  IL_0002:  ldc.i4.s   20
  IL_0004:  newobj     ""<>f__AnonymousType0<int, int>..ctor(int, int)""
  IL_0009:  call       ""<anonymous type: int A, int B> C.Identity<<anonymous type: int A, int B>>(<anonymous type: int A, int B>)""
  IL_000e:  ldc.i4.s   30
  IL_0010:  stloc.0
  IL_0011:  callvirt   ""int <>f__AnonymousType0<int, int>.A.get""
  IL_0016:  ldloc.0
  IL_0017:  newobj     ""<>f__AnonymousType0<int, int>..ctor(int, int)""
  IL_001c:  call       ""void System.Console.Write(object)""
  IL_0021:  ret
}
");
 
            var expectedFlowGraph = @"
Block[B0] - Entry
    Statements (0)
    Next (Regular) Block[B1]
        Entering: {R1} {R2}
.locals {R1}
{
    Locals: [<anonymous type: System.Int32 A, System.Int32 B> a] [<anonymous type: System.Int32 A, System.Int32 B> b]
    .locals {R2}
    {
        CaptureIds: [0] [1]
        Block[B1] - Block
            Predecessors: [B0]
            Statements (3)
                IFlowCaptureOperation: 0 (OperationKind.FlowCapture, Type: null, IsImplicit) (Syntax: '10')
                  Value:
                    ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 10) (Syntax: '10')
                IFlowCaptureOperation: 1 (OperationKind.FlowCapture, Type: null, IsImplicit) (Syntax: '20')
                  Value:
                    ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 20) (Syntax: '20')
                ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: <anonymous type: System.Int32 A, System.Int32 B>, IsImplicit) (Syntax: 'a = new { A ... 0, B = 20 }')
                  Left:
                    ILocalReferenceOperation: a (IsDeclaration: True) (OperationKind.LocalReference, Type: <anonymous type: System.Int32 A, System.Int32 B>, IsImplicit) (Syntax: 'a = new { A ... 0, B = 20 }')
                  Right:
                    IAnonymousObjectCreationOperation (OperationKind.AnonymousObjectCreation, Type: <anonymous type: System.Int32 A, System.Int32 B>) (Syntax: 'new { A = 10, B = 20 }')
                      Initializers(2):
                          ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: System.Int32, Constant: 10) (Syntax: 'A = 10')
                            Left:
                              IPropertyReferenceOperation: System.Int32 <anonymous type: System.Int32 A, System.Int32 B>.A { get; } (OperationKind.PropertyReference, Type: System.Int32) (Syntax: 'A')
                                Instance Receiver:
                                  IInstanceReferenceOperation (ReferenceKind: ImplicitReceiver) (OperationKind.InstanceReference, Type: <anonymous type: System.Int32 A, System.Int32 B>, IsImplicit) (Syntax: 'new { A = 10, B = 20 }')
                            Right:
                              IFlowCaptureReferenceOperation: 0 (OperationKind.FlowCaptureReference, Type: System.Int32, Constant: 10, IsImplicit) (Syntax: '10')
                          ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: System.Int32, Constant: 20) (Syntax: 'B = 20')
                            Left:
                              IPropertyReferenceOperation: System.Int32 <anonymous type: System.Int32 A, System.Int32 B>.B { get; } (OperationKind.PropertyReference, Type: System.Int32) (Syntax: 'B')
                                Instance Receiver:
                                  IInstanceReferenceOperation (ReferenceKind: ImplicitReceiver) (OperationKind.InstanceReference, Type: <anonymous type: System.Int32 A, System.Int32 B>, IsImplicit) (Syntax: 'new { A = 10, B = 20 }')
                            Right:
                              IFlowCaptureReferenceOperation: 1 (OperationKind.FlowCaptureReference, Type: System.Int32, Constant: 20, IsImplicit) (Syntax: '20')
            Next (Regular) Block[B2]
                Leaving: {R2}
                Entering: {R3} {R4}
    }
    .locals {R3}
    {
        CaptureIds: [3] [4]
        .locals {R4}
        {
            CaptureIds: [2]
            Block[B2] - Block
                Predecessors: [B1]
                Statements (3)
                    IFlowCaptureOperation: 2 (OperationKind.FlowCapture, Type: null, IsImplicit) (Syntax: 'Identity(a)')
                      Value:
                        IInvocationOperation (<anonymous type: System.Int32 A, System.Int32 B> C.Identity<<anonymous type: System.Int32 A, System.Int32 B>>(<anonymous type: System.Int32 A, System.Int32 B> t)) (OperationKind.Invocation, Type: <anonymous type: System.Int32 A, System.Int32 B>) (Syntax: 'Identity(a)')
                          Instance Receiver:
                            null
                          Arguments(1):
                              IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: t) (OperationKind.Argument, Type: null) (Syntax: 'a')
                                ILocalReferenceOperation: a (OperationKind.LocalReference, Type: <anonymous type: System.Int32 A, System.Int32 B>) (Syntax: 'a')
                                InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null)
                                OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null)
                    IFlowCaptureOperation: 3 (OperationKind.FlowCapture, Type: null, IsImplicit) (Syntax: '30')
                      Value:
                        ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 30) (Syntax: '30')
                    IFlowCaptureOperation: 4 (OperationKind.FlowCapture, Type: null, IsImplicit) (Syntax: 'Identity(a) ...  { B = 30 }')
                      Value:
                        IPropertyReferenceOperation: System.Int32 <anonymous type: System.Int32 A, System.Int32 B>.A { get; } (OperationKind.PropertyReference, Type: System.Int32, IsImplicit) (Syntax: 'Identity(a) ...  { B = 30 }')
                          Instance Receiver:
                            IFlowCaptureReferenceOperation: 2 (OperationKind.FlowCaptureReference, Type: <anonymous type: System.Int32 A, System.Int32 B>, IsImplicit) (Syntax: 'Identity(a)')
                Next (Regular) Block[B3]
                    Leaving: {R4}
        }
        Block[B3] - Block
            Predecessors: [B2]
            Statements (1)
                ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: <anonymous type: System.Int32 A, System.Int32 B>, IsImplicit) (Syntax: 'b = Identit ...  { B = 30 }')
                  Left:
                    ILocalReferenceOperation: b (IsDeclaration: True) (OperationKind.LocalReference, Type: <anonymous type: System.Int32 A, System.Int32 B>, IsImplicit) (Syntax: 'b = Identit ...  { B = 30 }')
                  Right:
                    IAnonymousObjectCreationOperation (OperationKind.AnonymousObjectCreation, Type: <anonymous type: System.Int32 A, System.Int32 B>) (Syntax: 'Identity(a) ...  { B = 30 }')
                      Initializers(2):
                          ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: System.Int32, IsImplicit) (Syntax: 'Identity(a) ...  { B = 30 }')
                            Left:
                              IPropertyReferenceOperation: System.Int32 <anonymous type: System.Int32 A, System.Int32 B>.A { get; } (OperationKind.PropertyReference, Type: System.Int32, IsImplicit) (Syntax: 'Identity(a) ...  { B = 30 }')
                                Instance Receiver:
                                  IInstanceReferenceOperation (ReferenceKind: ImplicitReceiver) (OperationKind.InstanceReference, Type: <anonymous type: System.Int32 A, System.Int32 B>, IsImplicit) (Syntax: 'Identity(a) ...  { B = 30 }')
                            Right:
                              IFlowCaptureReferenceOperation: 4 (OperationKind.FlowCaptureReference, Type: <anonymous type: System.Int32 A, System.Int32 B>, IsImplicit) (Syntax: 'Identity(a)')
                          ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: System.Int32, IsImplicit) (Syntax: 'Identity(a) ...  { B = 30 }')
                            Left:
                              IPropertyReferenceOperation: System.Int32 <anonymous type: System.Int32 A, System.Int32 B>.B { get; } (OperationKind.PropertyReference, Type: System.Int32, IsImplicit) (Syntax: 'Identity(a) ...  { B = 30 }')
                                Instance Receiver:
                                  IInstanceReferenceOperation (ReferenceKind: ImplicitReceiver) (OperationKind.InstanceReference, Type: <anonymous type: System.Int32 A, System.Int32 B>, IsImplicit) (Syntax: 'Identity(a) ...  { B = 30 }')
                            Right:
                              IFlowCaptureReferenceOperation: 3 (OperationKind.FlowCaptureReference, Type: <anonymous type: System.Int32 A, System.Int32 B>, IsImplicit) (Syntax: 'Identity(a)')
            Next (Regular) Block[B4]
                Leaving: {R3}
    }
    Block[B4] - Block
        Predecessors: [B3]
        Statements (1)
            IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'System.Console.Write(b);')
              Expression:
                IInvocationOperation (void System.Console.Write(System.Object value)) (OperationKind.Invocation, Type: System.Void) (Syntax: 'System.Console.Write(b)')
                  Instance Receiver:
                    null
                  Arguments(1):
                      IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: value) (OperationKind.Argument, Type: null) (Syntax: 'b')
                        IConversionOperation (TryCast: False, Unchecked) (OperationKind.Conversion, Type: System.Object, IsImplicit) (Syntax: 'b')
                          Conversion: CommonConversion (Exists: True, IsIdentity: False, IsNumeric: False, IsReference: True, IsUserDefined: False) (MethodSymbol: null)
                            (ImplicitReference)
                          Operand:
                            ILocalReferenceOperation: b (OperationKind.LocalReference, Type: <anonymous type: System.Int32 A, System.Int32 B>) (Syntax: 'b')
                        InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null)
                        OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null)
        Next (Regular) Block[B5]
            Leaving: {R1}
}
Block[B5] - Exit
    Predecessors: [B4]
    Statements (0)
";
            var expectedDiagnostics = DiagnosticDescription.None;
 
            VerifyFlowGraphAndDiagnosticsForTest<BlockSyntax>(src, expectedFlowGraph, expectedDiagnostics, parseOptions: TestOptions.RegularPreview);
        }
 
        [Fact]
        public void WithExpr_AnonymousType_ChangeOneProperty_WithCoalescingExpressionForTarget()
        {
            var src = @"
C.M();
 
public class C
{
    public static void M()
    /*<bind>*/{
        var a = new { A = 10, B = 20 };
        var b = (Identity(a) ?? Identity2(a)) with { B = 30 };
        System.Console.Write(b);
    }/*</bind>*/
 
    static T Identity<T>(T t) => t;
    static T Identity2<T>(T t) => t;
}";
            var comp = CreateCompilation(src, parseOptions: TestOptions.RegularPreview);
            comp.VerifyEmitDiagnostics();
            CompileAndVerify(comp, expectedOutput: "{ A = 10, B = 30 }");
 
            var expectedFlowGraph = @"
Block[B0] - Entry
    Statements (0)
    Next (Regular) Block[B1]
        Entering: {R1} {R2}
.locals {R1}
{
    Locals: [<anonymous type: System.Int32 A, System.Int32 B> a] [<anonymous type: System.Int32 A, System.Int32 B> b]
    .locals {R2}
    {
        CaptureIds: [0] [1]
        Block[B1] - Block
            Predecessors: [B0]
            Statements (3)
                IFlowCaptureOperation: 0 (OperationKind.FlowCapture, Type: null, IsImplicit) (Syntax: '10')
                  Value:
                    ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 10) (Syntax: '10')
                IFlowCaptureOperation: 1 (OperationKind.FlowCapture, Type: null, IsImplicit) (Syntax: '20')
                  Value:
                    ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 20) (Syntax: '20')
                ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: <anonymous type: System.Int32 A, System.Int32 B>, IsImplicit) (Syntax: 'a = new { A ... 0, B = 20 }')
                  Left:
                    ILocalReferenceOperation: a (IsDeclaration: True) (OperationKind.LocalReference, Type: <anonymous type: System.Int32 A, System.Int32 B>, IsImplicit) (Syntax: 'a = new { A ... 0, B = 20 }')
                  Right:
                    IAnonymousObjectCreationOperation (OperationKind.AnonymousObjectCreation, Type: <anonymous type: System.Int32 A, System.Int32 B>) (Syntax: 'new { A = 10, B = 20 }')
                      Initializers(2):
                          ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: System.Int32, Constant: 10) (Syntax: 'A = 10')
                            Left:
                              IPropertyReferenceOperation: System.Int32 <anonymous type: System.Int32 A, System.Int32 B>.A { get; } (OperationKind.PropertyReference, Type: System.Int32) (Syntax: 'A')
                                Instance Receiver:
                                  IInstanceReferenceOperation (ReferenceKind: ImplicitReceiver) (OperationKind.InstanceReference, Type: <anonymous type: System.Int32 A, System.Int32 B>, IsImplicit) (Syntax: 'new { A = 10, B = 20 }')
                            Right:
                              IFlowCaptureReferenceOperation: 0 (OperationKind.FlowCaptureReference, Type: System.Int32, Constant: 10, IsImplicit) (Syntax: '10')
                          ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: System.Int32, Constant: 20) (Syntax: 'B = 20')
                            Left:
                              IPropertyReferenceOperation: System.Int32 <anonymous type: System.Int32 A, System.Int32 B>.B { get; } (OperationKind.PropertyReference, Type: System.Int32) (Syntax: 'B')
                                Instance Receiver:
                                  IInstanceReferenceOperation (ReferenceKind: ImplicitReceiver) (OperationKind.InstanceReference, Type: <anonymous type: System.Int32 A, System.Int32 B>, IsImplicit) (Syntax: 'new { A = 10, B = 20 }')
                            Right:
                              IFlowCaptureReferenceOperation: 1 (OperationKind.FlowCaptureReference, Type: System.Int32, Constant: 20, IsImplicit) (Syntax: '20')
            Next (Regular) Block[B2]
                Leaving: {R2}
                Entering: {R3} {R4} {R5}
    }
    .locals {R3}
    {
        CaptureIds: [4] [5]
        .locals {R4}
        {
            CaptureIds: [2]
            .locals {R5}
            {
                CaptureIds: [3]
                Block[B2] - Block
                    Predecessors: [B1]
                    Statements (1)
                        IFlowCaptureOperation: 3 (OperationKind.FlowCapture, Type: null, IsImplicit) (Syntax: 'Identity(a)')
                          Value:
                            IInvocationOperation (<anonymous type: System.Int32 A, System.Int32 B> C.Identity<<anonymous type: System.Int32 A, System.Int32 B>>(<anonymous type: System.Int32 A, System.Int32 B> t)) (OperationKind.Invocation, Type: <anonymous type: System.Int32 A, System.Int32 B>) (Syntax: 'Identity(a)')
                              Instance Receiver:
                                null
                              Arguments(1):
                                  IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: t) (OperationKind.Argument, Type: null) (Syntax: 'a')
                                    ILocalReferenceOperation: a (OperationKind.LocalReference, Type: <anonymous type: System.Int32 A, System.Int32 B>) (Syntax: 'a')
                                    InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null)
                                    OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null)
                    Jump if True (Regular) to Block[B4]
                        IIsNullOperation (OperationKind.IsNull, Type: System.Boolean, IsImplicit) (Syntax: 'Identity(a)')
                          Operand:
                            IFlowCaptureReferenceOperation: 3 (OperationKind.FlowCaptureReference, Type: <anonymous type: System.Int32 A, System.Int32 B>, IsImplicit) (Syntax: 'Identity(a)')
                        Leaving: {R5}
                    Next (Regular) Block[B3]
                Block[B3] - Block
                    Predecessors: [B2]
                    Statements (1)
                        IFlowCaptureOperation: 2 (OperationKind.FlowCapture, Type: null, IsImplicit) (Syntax: 'Identity(a)')
                          Value:
                            IFlowCaptureReferenceOperation: 3 (OperationKind.FlowCaptureReference, Type: <anonymous type: System.Int32 A, System.Int32 B>, IsImplicit) (Syntax: 'Identity(a)')
                    Next (Regular) Block[B5]
                        Leaving: {R5}
            }
            Block[B4] - Block
                Predecessors: [B2]
                Statements (1)
                    IFlowCaptureOperation: 2 (OperationKind.FlowCapture, Type: null, IsImplicit) (Syntax: 'Identity2(a)')
                      Value:
                        IInvocationOperation (<anonymous type: System.Int32 A, System.Int32 B> C.Identity2<<anonymous type: System.Int32 A, System.Int32 B>>(<anonymous type: System.Int32 A, System.Int32 B> t)) (OperationKind.Invocation, Type: <anonymous type: System.Int32 A, System.Int32 B>) (Syntax: 'Identity2(a)')
                          Instance Receiver:
                            null
                          Arguments(1):
                              IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: t) (OperationKind.Argument, Type: null) (Syntax: 'a')
                                ILocalReferenceOperation: a (OperationKind.LocalReference, Type: <anonymous type: System.Int32 A, System.Int32 B>) (Syntax: 'a')
                                InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null)
                                OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null)
                Next (Regular) Block[B5]
            Block[B5] - Block
                Predecessors: [B3] [B4]
                Statements (2)
                    IFlowCaptureOperation: 4 (OperationKind.FlowCapture, Type: null, IsImplicit) (Syntax: '30')
                      Value:
                        ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 30) (Syntax: '30')
                    IFlowCaptureOperation: 5 (OperationKind.FlowCapture, Type: null, IsImplicit) (Syntax: '(Identity(a ...  { B = 30 }')
                      Value:
                        IPropertyReferenceOperation: System.Int32 <anonymous type: System.Int32 A, System.Int32 B>.A { get; } (OperationKind.PropertyReference, Type: System.Int32, IsImplicit) (Syntax: '(Identity(a ...  { B = 30 }')
                          Instance Receiver:
                            IFlowCaptureReferenceOperation: 2 (OperationKind.FlowCaptureReference, Type: <anonymous type: System.Int32 A, System.Int32 B>, IsImplicit) (Syntax: 'Identity(a) ... dentity2(a)')
                Next (Regular) Block[B6]
                    Leaving: {R4}
        }
        Block[B6] - Block
                Predecessors: [B5]
                Statements (1)
                    ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: <anonymous type: System.Int32 A, System.Int32 B>, IsImplicit) (Syntax: 'b = (Identi ...  { B = 30 }')
                      Left:
                        ILocalReferenceOperation: b (IsDeclaration: True) (OperationKind.LocalReference, Type: <anonymous type: System.Int32 A, System.Int32 B>, IsImplicit) (Syntax: 'b = (Identi ...  { B = 30 }')
                      Right:
                        IAnonymousObjectCreationOperation (OperationKind.AnonymousObjectCreation, Type: <anonymous type: System.Int32 A, System.Int32 B>) (Syntax: '(Identity(a ...  { B = 30 }')
                          Initializers(2):
                              ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: System.Int32, IsImplicit) (Syntax: '(Identity(a ...  { B = 30 }')
                                Left:
                                  IPropertyReferenceOperation: System.Int32 <anonymous type: System.Int32 A, System.Int32 B>.A { get; } (OperationKind.PropertyReference, Type: System.Int32, IsImplicit) (Syntax: '(Identity(a ...  { B = 30 }')
                                    Instance Receiver:
                                      IInstanceReferenceOperation (ReferenceKind: ImplicitReceiver) (OperationKind.InstanceReference, Type: <anonymous type: System.Int32 A, System.Int32 B>, IsImplicit) (Syntax: '(Identity(a ...  { B = 30 }')
                                Right:
                                  IFlowCaptureReferenceOperation: 5 (OperationKind.FlowCaptureReference, Type: <anonymous type: System.Int32 A, System.Int32 B>, IsImplicit) (Syntax: 'Identity(a) ... dentity2(a)')
                              ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: System.Int32, IsImplicit) (Syntax: '(Identity(a ...  { B = 30 }')
                                Left:
                                  IPropertyReferenceOperation: System.Int32 <anonymous type: System.Int32 A, System.Int32 B>.B { get; } (OperationKind.PropertyReference, Type: System.Int32, IsImplicit) (Syntax: '(Identity(a ...  { B = 30 }')
                                    Instance Receiver:
                                      IInstanceReferenceOperation (ReferenceKind: ImplicitReceiver) (OperationKind.InstanceReference, Type: <anonymous type: System.Int32 A, System.Int32 B>, IsImplicit) (Syntax: '(Identity(a ...  { B = 30 }')
                                Right:
                                  IFlowCaptureReferenceOperation: 4 (OperationKind.FlowCaptureReference, Type: <anonymous type: System.Int32 A, System.Int32 B>, IsImplicit) (Syntax: 'Identity(a) ... dentity2(a)')
                Next (Regular) Block[B7]
                    Leaving: {R3}
        }
        Block[B7] - Block
            Predecessors: [B6]
            Statements (1)
                IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'System.Console.Write(b);')
                  Expression:
                    IInvocationOperation (void System.Console.Write(System.Object value)) (OperationKind.Invocation, Type: System.Void) (Syntax: 'System.Console.Write(b)')
                      Instance Receiver:
                        null
                      Arguments(1):
                          IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: value) (OperationKind.Argument, Type: null) (Syntax: 'b')
                            IConversionOperation (TryCast: False, Unchecked) (OperationKind.Conversion, Type: System.Object, IsImplicit) (Syntax: 'b')
                              Conversion: CommonConversion (Exists: True, IsIdentity: False, IsNumeric: False, IsReference: True, IsUserDefined: False) (MethodSymbol: null)
                                (ImplicitReference)
                              Operand:
                                ILocalReferenceOperation: b (OperationKind.LocalReference, Type: <anonymous type: System.Int32 A, System.Int32 B>) (Syntax: 'b')
                            InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null)
                            OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null)
            Next (Regular) Block[B8]
                Leaving: {R1}
    }
    Block[B8] - Exit
        Predecessors: [B7]
        Statements (0)
";
            var expectedDiagnostics = DiagnosticDescription.None;
 
            VerifyFlowGraphAndDiagnosticsForTest<BlockSyntax>(src, expectedFlowGraph, expectedDiagnostics, parseOptions: TestOptions.RegularPreview);
        }
 
        [Fact]
        public void WithExpr_AnonymousType_ChangeOneProperty_WithCoalescingExpressionForValue()
        {
            var src = @"
C.M(""hello"", ""world"");
 
public class C
{
    public static void M(string hello, string world)
    /*<bind>*/{
        var x = new { A = hello, B = string.Empty };
        var y = x with { B =  Identity(null) ?? Identity2(world) };
        System.Console.Write(y);
    }/*</bind>*/
 
    static string Identity(string t) => t;
    static string Identity2(string t) => t;
}";
            var comp = CreateCompilation(src, parseOptions: TestOptions.RegularPreview);
            comp.VerifyEmitDiagnostics();
            CompileAndVerify(comp, expectedOutput: "{ A = hello, B = world }");
 
            var expectedFlowGraph = @"
Block[B0] - Entry
    Statements (0)
    Next (Regular) Block[B1]
        Entering: {R1} {R2}
.locals {R1}
{
    Locals: [<anonymous type: System.String A, System.String B> x] [<anonymous type: System.String A, System.String B> y]
    .locals {R2}
    {
        CaptureIds: [0] [1]
        Block[B1] - Block
            Predecessors: [B0]
            Statements (3)
                IFlowCaptureOperation: 0 (OperationKind.FlowCapture, Type: null, IsImplicit) (Syntax: 'hello')
                  Value:
                    IParameterReferenceOperation: hello (OperationKind.ParameterReference, Type: System.String) (Syntax: 'hello')
                IFlowCaptureOperation: 1 (OperationKind.FlowCapture, Type: null, IsImplicit) (Syntax: 'string.Empty')
                  Value:
                    IFieldReferenceOperation: System.String System.String.Empty (Static) (OperationKind.FieldReference, Type: System.String) (Syntax: 'string.Empty')
                      Instance Receiver:
                        null
                ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: <anonymous type: System.String A, System.String B>, IsImplicit) (Syntax: 'x = new { A ... ing.Empty }')
                  Left:
                    ILocalReferenceOperation: x (IsDeclaration: True) (OperationKind.LocalReference, Type: <anonymous type: System.String A, System.String B>, IsImplicit) (Syntax: 'x = new { A ... ing.Empty }')
                  Right:
                    IAnonymousObjectCreationOperation (OperationKind.AnonymousObjectCreation, Type: <anonymous type: System.String A, System.String B>) (Syntax: 'new { A = h ... ing.Empty }')
                      Initializers(2):
                          ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: System.String) (Syntax: 'A = hello')
                            Left:
                              IPropertyReferenceOperation: System.String <anonymous type: System.String A, System.String B>.A { get; } (OperationKind.PropertyReference, Type: System.String) (Syntax: 'A')
                                Instance Receiver:
                                  IInstanceReferenceOperation (ReferenceKind: ImplicitReceiver) (OperationKind.InstanceReference, Type: <anonymous type: System.String A, System.String B>, IsImplicit) (Syntax: 'new { A = h ... ing.Empty }')
                            Right:
                              IFlowCaptureReferenceOperation: 0 (OperationKind.FlowCaptureReference, Type: System.String, IsImplicit) (Syntax: 'hello')
                          ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: System.String) (Syntax: 'B = string.Empty')
                            Left:
                              IPropertyReferenceOperation: System.String <anonymous type: System.String A, System.String B>.B { get; } (OperationKind.PropertyReference, Type: System.String) (Syntax: 'B')
                                Instance Receiver:
                                  IInstanceReferenceOperation (ReferenceKind: ImplicitReceiver) (OperationKind.InstanceReference, Type: <anonymous type: System.String A, System.String B>, IsImplicit) (Syntax: 'new { A = h ... ing.Empty }')
                            Right:
                              IFlowCaptureReferenceOperation: 1 (OperationKind.FlowCaptureReference, Type: System.String, IsImplicit) (Syntax: 'string.Empty')
            Next (Regular) Block[B2]
                Leaving: {R2}
                Entering: {R3} {R4}
    }
    .locals {R3}
    {
        CaptureIds: [3] [5]
        .locals {R4}
        {
            CaptureIds: [2]
            Block[B2] - Block
                Predecessors: [B1]
                Statements (1)
                    IFlowCaptureOperation: 2 (OperationKind.FlowCapture, Type: null, IsImplicit) (Syntax: 'x')
                      Value:
                        ILocalReferenceOperation: x (OperationKind.LocalReference, Type: <anonymous type: System.String A, System.String B>) (Syntax: 'x')
                Next (Regular) Block[B3]
                    Entering: {R5}
            .locals {R5}
            {
                CaptureIds: [4]
                Block[B3] - Block
                    Predecessors: [B2]
                    Statements (1)
                        IFlowCaptureOperation: 4 (OperationKind.FlowCapture, Type: null, IsImplicit) (Syntax: 'Identity(null)')
                          Value:
                            IInvocationOperation (System.String C.Identity(System.String t)) (OperationKind.Invocation, Type: System.String) (Syntax: 'Identity(null)')
                              Instance Receiver:
                                null
                              Arguments(1):
                                  IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: t) (OperationKind.Argument, Type: null) (Syntax: 'null')
                                    IConversionOperation (TryCast: False, Unchecked) (OperationKind.Conversion, Type: System.String, Constant: null, IsImplicit) (Syntax: 'null')
                                      Conversion: CommonConversion (Exists: True, IsIdentity: False, IsNumeric: False, IsReference: True, IsUserDefined: False) (MethodSymbol: null)
                                        (ImplicitReference)
                                      Operand:
                                        ILiteralOperation (OperationKind.Literal, Type: null, Constant: null) (Syntax: 'null')
                                    InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null)
                                    OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null)
                    Jump if True (Regular) to Block[B5]
                        IIsNullOperation (OperationKind.IsNull, Type: System.Boolean, IsImplicit) (Syntax: 'Identity(null)')
                          Operand:
                            IFlowCaptureReferenceOperation: 4 (OperationKind.FlowCaptureReference, Type: System.String, IsImplicit) (Syntax: 'Identity(null)')
                        Leaving: {R5}
                    Next (Regular) Block[B4]
                Block[B4] - Block
                    Predecessors: [B3]
                    Statements (1)
                        IFlowCaptureOperation: 3 (OperationKind.FlowCapture, Type: null, IsImplicit) (Syntax: 'Identity(null)')
                          Value:
                            IFlowCaptureReferenceOperation: 4 (OperationKind.FlowCaptureReference, Type: System.String, IsImplicit) (Syntax: 'Identity(null)')
                    Next (Regular) Block[B6]
                        Leaving: {R5}
            }
            Block[B5] - Block
                Predecessors: [B3]
                Statements (1)
                    IFlowCaptureOperation: 3 (OperationKind.FlowCapture, Type: null, IsImplicit) (Syntax: 'Identity2(world)')
                      Value:
                        IInvocationOperation (System.String C.Identity2(System.String t)) (OperationKind.Invocation, Type: System.String) (Syntax: 'Identity2(world)')
                          Instance Receiver:
                            null
                          Arguments(1):
                              IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: t) (OperationKind.Argument, Type: null) (Syntax: 'world')
                                IParameterReferenceOperation: world (OperationKind.ParameterReference, Type: System.String) (Syntax: 'world')
                                InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null)
                                OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null)
                Next (Regular) Block[B6]
            Block[B6] - Block
                Predecessors: [B4] [B5]
                Statements (1)
                    IFlowCaptureOperation: 5 (OperationKind.FlowCapture, Type: null, IsImplicit) (Syntax: 'x with { B  ... y2(world) }')
                      Value:
                        IPropertyReferenceOperation: System.String <anonymous type: System.String A, System.String B>.A { get; } (OperationKind.PropertyReference, Type: System.String, IsImplicit) (Syntax: 'x with { B  ... y2(world) }')
                          Instance Receiver:
                            IFlowCaptureReferenceOperation: 2 (OperationKind.FlowCaptureReference, Type: <anonymous type: System.String A, System.String B>, IsImplicit) (Syntax: 'x')
                Next (Regular) Block[B7]
                    Leaving: {R4}
        }
        Block[B7] - Block
            Predecessors: [B6]
            Statements (1)
                ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: <anonymous type: System.String A, System.String B>, IsImplicit) (Syntax: 'y = x with  ... y2(world) }')
                  Left:
                    ILocalReferenceOperation: y (IsDeclaration: True) (OperationKind.LocalReference, Type: <anonymous type: System.String A, System.String B>, IsImplicit) (Syntax: 'y = x with  ... y2(world) }')
                  Right:
                    IAnonymousObjectCreationOperation (OperationKind.AnonymousObjectCreation, Type: <anonymous type: System.String A, System.String B>) (Syntax: 'x with { B  ... y2(world) }')
                      Initializers(2):
                          ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: System.String, IsImplicit) (Syntax: 'x with { B  ... y2(world) }')
                            Left:
                              IPropertyReferenceOperation: System.String <anonymous type: System.String A, System.String B>.A { get; } (OperationKind.PropertyReference, Type: System.String, IsImplicit) (Syntax: 'x with { B  ... y2(world) }')
                                Instance Receiver:
                                  IInstanceReferenceOperation (ReferenceKind: ImplicitReceiver) (OperationKind.InstanceReference, Type: <anonymous type: System.String A, System.String B>, IsImplicit) (Syntax: 'x with { B  ... y2(world) }')
                            Right:
                              IFlowCaptureReferenceOperation: 5 (OperationKind.FlowCaptureReference, Type: <anonymous type: System.String A, System.String B>, IsImplicit) (Syntax: 'x')
                          ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: System.String, IsImplicit) (Syntax: 'x with { B  ... y2(world) }')
                            Left:
                              IPropertyReferenceOperation: System.String <anonymous type: System.String A, System.String B>.B { get; } (OperationKind.PropertyReference, Type: System.String, IsImplicit) (Syntax: 'x with { B  ... y2(world) }')
                                Instance Receiver:
                                  IInstanceReferenceOperation (ReferenceKind: ImplicitReceiver) (OperationKind.InstanceReference, Type: <anonymous type: System.String A, System.String B>, IsImplicit) (Syntax: 'x with { B  ... y2(world) }')
                            Right:
                              IFlowCaptureReferenceOperation: 3 (OperationKind.FlowCaptureReference, Type: <anonymous type: System.String A, System.String B>, IsImplicit) (Syntax: 'x')
            Next (Regular) Block[B8]
                Leaving: {R3}
    }
    Block[B8] - Block
        Predecessors: [B7]
        Statements (1)
            IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'System.Console.Write(y);')
              Expression:
                IInvocationOperation (void System.Console.Write(System.Object value)) (OperationKind.Invocation, Type: System.Void) (Syntax: 'System.Console.Write(y)')
                  Instance Receiver:
                    null
                  Arguments(1):
                      IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: value) (OperationKind.Argument, Type: null) (Syntax: 'y')
                        IConversionOperation (TryCast: False, Unchecked) (OperationKind.Conversion, Type: System.Object, IsImplicit) (Syntax: 'y')
                          Conversion: CommonConversion (Exists: True, IsIdentity: False, IsNumeric: False, IsReference: True, IsUserDefined: False) (MethodSymbol: null)
                            (ImplicitReference)
                          Operand:
                            ILocalReferenceOperation: y (OperationKind.LocalReference, Type: <anonymous type: System.String A, System.String B>) (Syntax: 'y')
                        InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null)
                        OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null)
        Next (Regular) Block[B9]
            Leaving: {R1}
}
Block[B9] - Exit
    Predecessors: [B8]
    Statements (0)
";
            var expectedDiagnostics = DiagnosticDescription.None;
 
            VerifyFlowGraphAndDiagnosticsForTest<BlockSyntax>(src, expectedFlowGraph, expectedDiagnostics, parseOptions: TestOptions.RegularPreview);
        }
 
        [Fact]
        public void WithExpr_AnonymousType_ErrorMember()
        {
            var src = @"
public class C
{
    public static void M()
    /*<bind>*/{
        var a = new { A = 10 };
        var b = a with { Error = Identity(20) };
    }/*</bind>*/
 
    static T Identity<T>(T t) => t;
}";
 
            var comp = CreateCompilation(src, parseOptions: TestOptions.RegularPreview);
            var expectedDiagnostics = new[]
            {
                // (7,26): error CS0117: '<anonymous type: int A>' does not contain a definition for 'Error'
                //         var b = a with { Error = Identity(20) };
                Diagnostic(ErrorCode.ERR_NoSuchMember, "Error").WithArguments("<anonymous type: int A>", "Error").WithLocation(7, 26)
            };
            comp.VerifyEmitDiagnostics(expectedDiagnostics);
 
            var expectedFlowGraph = @"
Block[B0] - Entry
    Statements (0)
    Next (Regular) Block[B1]
        Entering: {R1} {R2}
.locals {R1}
{
    Locals: [<anonymous type: System.Int32 A> a] [<anonymous type: System.Int32 A> b]
    .locals {R2}
    {
        CaptureIds: [0]
        Block[B1] - Block
            Predecessors: [B0]
            Statements (2)
                IFlowCaptureOperation: 0 (OperationKind.FlowCapture, Type: null, IsImplicit) (Syntax: '10')
                  Value:
                    ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 10) (Syntax: '10')
                ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: <anonymous type: System.Int32 A>, IsImplicit) (Syntax: 'a = new { A = 10 }')
                  Left:
                    ILocalReferenceOperation: a (IsDeclaration: True) (OperationKind.LocalReference, Type: <anonymous type: System.Int32 A>, IsImplicit) (Syntax: 'a = new { A = 10 }')
                  Right:
                    IAnonymousObjectCreationOperation (OperationKind.AnonymousObjectCreation, Type: <anonymous type: System.Int32 A>) (Syntax: 'new { A = 10 }')
                      Initializers(1):
                          ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: System.Int32, Constant: 10) (Syntax: 'A = 10')
                            Left:
                              IPropertyReferenceOperation: System.Int32 <anonymous type: System.Int32 A>.A { get; } (OperationKind.PropertyReference, Type: System.Int32) (Syntax: 'A')
                                Instance Receiver:
                                  IInstanceReferenceOperation (ReferenceKind: ImplicitReceiver) (OperationKind.InstanceReference, Type: <anonymous type: System.Int32 A>, IsImplicit) (Syntax: 'new { A = 10 }')
                            Right:
                              IFlowCaptureReferenceOperation: 0 (OperationKind.FlowCaptureReference, Type: System.Int32, Constant: 10, IsImplicit) (Syntax: '10')
            Next (Regular) Block[B2]
                Leaving: {R2}
                Entering: {R3} {R4}
    }
    .locals {R3}
    {
        CaptureIds: [2]
        .locals {R4}
        {
            CaptureIds: [1]
            Block[B2] - Block
                Predecessors: [B1]
                Statements (3)
                    IFlowCaptureOperation: 1 (OperationKind.FlowCapture, Type: null, IsImplicit) (Syntax: 'a')
                      Value:
                        ILocalReferenceOperation: a (OperationKind.LocalReference, Type: <anonymous type: System.Int32 A>) (Syntax: 'a')
                    IInvocationOperation (System.Int32 C.Identity<System.Int32>(System.Int32 t)) (OperationKind.Invocation, Type: System.Int32) (Syntax: 'Identity(20)')
                      Instance Receiver:
                        null
                      Arguments(1):
                          IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: t) (OperationKind.Argument, Type: null) (Syntax: '20')
                            ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 20) (Syntax: '20')
                            InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null)
                            OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null)
                    IFlowCaptureOperation: 2 (OperationKind.FlowCapture, Type: null, IsInvalid, IsImplicit) (Syntax: 'a with { Er ... ntity(20) }')
                      Value:
                        IPropertyReferenceOperation: System.Int32 <anonymous type: System.Int32 A>.A { get; } (OperationKind.PropertyReference, Type: System.Int32, IsInvalid, IsImplicit) (Syntax: 'a with { Er ... ntity(20) }')
                          Instance Receiver:
                            IFlowCaptureReferenceOperation: 1 (OperationKind.FlowCaptureReference, Type: <anonymous type: System.Int32 A>, IsImplicit) (Syntax: 'a')
                Next (Regular) Block[B3]
                    Leaving: {R4}
        }
        Block[B3] - Block
            Predecessors: [B2]
            Statements (1)
                ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: <anonymous type: System.Int32 A>, IsInvalid, IsImplicit) (Syntax: 'b = a with  ... ntity(20) }')
                  Left:
                    ILocalReferenceOperation: b (IsDeclaration: True) (OperationKind.LocalReference, Type: <anonymous type: System.Int32 A>, IsInvalid, IsImplicit) (Syntax: 'b = a with  ... ntity(20) }')
                  Right:
                    IAnonymousObjectCreationOperation (OperationKind.AnonymousObjectCreation, Type: <anonymous type: System.Int32 A>, IsInvalid) (Syntax: 'a with { Er ... ntity(20) }')
                      Initializers(1):
                          ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: System.Int32, IsInvalid, IsImplicit) (Syntax: 'a with { Er ... ntity(20) }')
                            Left:
                              IPropertyReferenceOperation: System.Int32 <anonymous type: System.Int32 A>.A { get; } (OperationKind.PropertyReference, Type: System.Int32, IsInvalid, IsImplicit) (Syntax: 'a with { Er ... ntity(20) }')
                                Instance Receiver:
                                  IInstanceReferenceOperation (ReferenceKind: ImplicitReceiver) (OperationKind.InstanceReference, Type: <anonymous type: System.Int32 A>, IsInvalid, IsImplicit) (Syntax: 'a with { Er ... ntity(20) }')
                            Right:
                              IFlowCaptureReferenceOperation: 2 (OperationKind.FlowCaptureReference, Type: <anonymous type: System.Int32 A>, IsImplicit) (Syntax: 'a')
            Next (Regular) Block[B4]
                Leaving: {R3} {R1}
    }
}
Block[B4] - Exit
    Predecessors: [B3]
    Statements (0)
";
            VerifyFlowGraphAndDiagnosticsForTest<BlockSyntax>(src, expectedFlowGraph, expectedDiagnostics, parseOptions: TestOptions.RegularPreview);
        }
 
        [Fact]
        public void WithExpr_AnonymousType_ToString()
        {
            var src = @"
public class C
{
    public static void M()
    /*<bind>*/{
        var a = new { A = 10 };
        var b = a with { ToString = Identity(20) };
    }/*</bind>*/
 
    static T Identity<T>(T t) => t;
}";
 
            var comp = CreateCompilation(src, parseOptions: TestOptions.RegularPreview);
            var expectedDiagnostics = new[]
            {
                // (7,26): error CS1913: Member 'ToString' cannot be initialized. It is not a field or property.
                //         var b = a with { ToString = Identity(20) };
                Diagnostic(ErrorCode.ERR_MemberCannotBeInitialized, "ToString").WithArguments("ToString").WithLocation(7, 26)
            };
            comp.VerifyEmitDiagnostics(expectedDiagnostics);
 
            var expectedFlowGraph = @"
Block[B0] - Entry
    Statements (0)
    Next (Regular) Block[B1]
        Entering: {R1} {R2}
.locals {R1}
{
    Locals: [<anonymous type: System.Int32 A> a] [<anonymous type: System.Int32 A> b]
    .locals {R2}
    {
        CaptureIds: [0]
        Block[B1] - Block
            Predecessors: [B0]
            Statements (2)
                IFlowCaptureOperation: 0 (OperationKind.FlowCapture, Type: null, IsImplicit) (Syntax: '10')
                  Value:
                    ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 10) (Syntax: '10')
                ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: <anonymous type: System.Int32 A>, IsImplicit) (Syntax: 'a = new { A = 10 }')
                  Left:
                    ILocalReferenceOperation: a (IsDeclaration: True) (OperationKind.LocalReference, Type: <anonymous type: System.Int32 A>, IsImplicit) (Syntax: 'a = new { A = 10 }')
                  Right:
                    IAnonymousObjectCreationOperation (OperationKind.AnonymousObjectCreation, Type: <anonymous type: System.Int32 A>) (Syntax: 'new { A = 10 }')
                      Initializers(1):
                          ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: System.Int32, Constant: 10) (Syntax: 'A = 10')
                            Left:
                              IPropertyReferenceOperation: System.Int32 <anonymous type: System.Int32 A>.A { get; } (OperationKind.PropertyReference, Type: System.Int32) (Syntax: 'A')
                                Instance Receiver:
                                  IInstanceReferenceOperation (ReferenceKind: ImplicitReceiver) (OperationKind.InstanceReference, Type: <anonymous type: System.Int32 A>, IsImplicit) (Syntax: 'new { A = 10 }')
                            Right:
                              IFlowCaptureReferenceOperation: 0 (OperationKind.FlowCaptureReference, Type: System.Int32, Constant: 10, IsImplicit) (Syntax: '10')
            Next (Regular) Block[B2]
                Leaving: {R2}
                Entering: {R3} {R4}
    }
    .locals {R3}
    {
        CaptureIds: [2]
        .locals {R4}
        {
            CaptureIds: [1]
            Block[B2] - Block
                Predecessors: [B1]
                Statements (3)
                    IFlowCaptureOperation: 1 (OperationKind.FlowCapture, Type: null, IsImplicit) (Syntax: 'a')
                      Value:
                        ILocalReferenceOperation: a (OperationKind.LocalReference, Type: <anonymous type: System.Int32 A>) (Syntax: 'a')
                    IInvocationOperation (System.Int32 C.Identity<System.Int32>(System.Int32 t)) (OperationKind.Invocation, Type: System.Int32) (Syntax: 'Identity(20)')
                      Instance Receiver:
                        null
                      Arguments(1):
                          IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: t) (OperationKind.Argument, Type: null) (Syntax: '20')
                            ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 20) (Syntax: '20')
                            InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null)
                            OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null)
                    IFlowCaptureOperation: 2 (OperationKind.FlowCapture, Type: null, IsInvalid, IsImplicit) (Syntax: 'a with { To ... ntity(20) }')
                      Value:
                        IPropertyReferenceOperation: System.Int32 <anonymous type: System.Int32 A>.A { get; } (OperationKind.PropertyReference, Type: System.Int32, IsInvalid, IsImplicit) (Syntax: 'a with { To ... ntity(20) }')
                          Instance Receiver:
                            IFlowCaptureReferenceOperation: 1 (OperationKind.FlowCaptureReference, Type: <anonymous type: System.Int32 A>, IsImplicit) (Syntax: 'a')
                Next (Regular) Block[B3]
                    Leaving: {R4}
        }
        Block[B3] - Block
            Predecessors: [B2]
            Statements (1)
                ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: <anonymous type: System.Int32 A>, IsInvalid, IsImplicit) (Syntax: 'b = a with  ... ntity(20) }')
                  Left:
                    ILocalReferenceOperation: b (IsDeclaration: True) (OperationKind.LocalReference, Type: <anonymous type: System.Int32 A>, IsInvalid, IsImplicit) (Syntax: 'b = a with  ... ntity(20) }')
                  Right:
                    IAnonymousObjectCreationOperation (OperationKind.AnonymousObjectCreation, Type: <anonymous type: System.Int32 A>, IsInvalid) (Syntax: 'a with { To ... ntity(20) }')
                      Initializers(1):
                          ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: System.Int32, IsInvalid, IsImplicit) (Syntax: 'a with { To ... ntity(20) }')
                            Left:
                              IPropertyReferenceOperation: System.Int32 <anonymous type: System.Int32 A>.A { get; } (OperationKind.PropertyReference, Type: System.Int32, IsInvalid, IsImplicit) (Syntax: 'a with { To ... ntity(20) }')
                                Instance Receiver:
                                  IInstanceReferenceOperation (ReferenceKind: ImplicitReceiver) (OperationKind.InstanceReference, Type: <anonymous type: System.Int32 A>, IsInvalid, IsImplicit) (Syntax: 'a with { To ... ntity(20) }')
                            Right:
                              IFlowCaptureReferenceOperation: 2 (OperationKind.FlowCaptureReference, Type: <anonymous type: System.Int32 A>, IsImplicit) (Syntax: 'a')
            Next (Regular) Block[B4]
                Leaving: {R3} {R1}
    }
}
Block[B4] - Exit
    Predecessors: [B3]
    Statements (0)
";
            VerifyFlowGraphAndDiagnosticsForTest<BlockSyntax>(src, expectedFlowGraph, expectedDiagnostics, parseOptions: TestOptions.RegularPreview);
        }
 
        [Fact]
        public void WithExpr_AnonymousType_NestedInitializer()
        {
            var src = @"
C.M();
 
public class C
{
    public static void M()
    /*<bind>*/{
        var nested = new { A = 10 };
        var a = new { Nested = nested };
        var b = a with { Nested = { A = 20 } };
        System.Console.Write(b);
    }/*</bind>*/
}";
            var expectedDiagnostics = new[]
            {
                // (10,35): error CS1525: Invalid expression term '{'
                //         var b = a with { Nested = { A = 20 } };
                Diagnostic(ErrorCode.ERR_InvalidExprTerm, "{").WithArguments("{").WithLocation(10, 35),
                // (10,35): error CS1513: } expected
                //         var b = a with { Nested = { A = 20 } };
                Diagnostic(ErrorCode.ERR_RbraceExpected, "{").WithLocation(10, 35),
                // (10,35): error CS1002: ; expected
                //         var b = a with { Nested = { A = 20 } };
                Diagnostic(ErrorCode.ERR_SemicolonExpected, "{").WithLocation(10, 35),
                // (10,37): error CS0103: The name 'A' does not exist in the current context
                //         var b = a with { Nested = { A = 20 } };
                Diagnostic(ErrorCode.ERR_NameNotInContext, "A").WithArguments("A").WithLocation(10, 37),
                // (10,44): error CS1002: ; expected
                //         var b = a with { Nested = { A = 20 } };
                Diagnostic(ErrorCode.ERR_SemicolonExpected, "}").WithLocation(10, 44),
                // (10,47): error CS1597: Semicolon after method or accessor block is not valid
                //         var b = a with { Nested = { A = 20 } };
                Diagnostic(ErrorCode.ERR_UnexpectedSemicolon, ";").WithLocation(10, 47),
                // (11,29): error CS1519: Invalid token '(' in class, record, struct, or interface member declaration
                //         System.Console.Write(b);
                Diagnostic(ErrorCode.ERR_InvalidMemberDecl, "(").WithArguments("(").WithLocation(11, 29),
                // (11,31): error CS8124: Tuple must contain at least two elements.
                //         System.Console.Write(b);
                Diagnostic(ErrorCode.ERR_TupleTooFewElements, ")").WithLocation(11, 31),
                // (11,32): error CS1519: Invalid token ';' in class, record, struct, or interface member declaration
                //         System.Console.Write(b);
                Diagnostic(ErrorCode.ERR_InvalidMemberDecl, ";").WithArguments(";").WithLocation(11, 32),
                // (13,1): error CS1022: Type or namespace definition, or end-of-file expected
                // }
                Diagnostic(ErrorCode.ERR_EOFExpected, "}").WithLocation(13, 1)
            };
            var comp = CreateCompilation(src, parseOptions: TestOptions.RegularPreview);
            comp.VerifyEmitDiagnostics(expectedDiagnostics);
 
            var expectedFlowGraph = @"
Block[B0] - Entry
    Statements (0)
    Next (Regular) Block[B1]
        Entering: {R1} {R2}
.locals {R1}
{
    Locals: [<anonymous type: System.Int32 A> nested] [<anonymous type: <anonymous type: System.Int32 A> Nested> a] [<anonymous type: <anonymous type: System.Int32 A> Nested> b]
    .locals {R2}
    {
        CaptureIds: [0]
        Block[B1] - Block
            Predecessors: [B0]
            Statements (2)
                IFlowCaptureOperation: 0 (OperationKind.FlowCapture, Type: null, IsImplicit) (Syntax: '10')
                  Value:
                    ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 10) (Syntax: '10')
                ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: <anonymous type: System.Int32 A>, IsImplicit) (Syntax: 'nested = new { A = 10 }')
                  Left:
                    ILocalReferenceOperation: nested (IsDeclaration: True) (OperationKind.LocalReference, Type: <anonymous type: System.Int32 A>, IsImplicit) (Syntax: 'nested = new { A = 10 }')
                  Right:
                    IAnonymousObjectCreationOperation (OperationKind.AnonymousObjectCreation, Type: <anonymous type: System.Int32 A>) (Syntax: 'new { A = 10 }')
                      Initializers(1):
                          ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: System.Int32, Constant: 10) (Syntax: 'A = 10')
                            Left:
                              IPropertyReferenceOperation: System.Int32 <anonymous type: System.Int32 A>.A { get; } (OperationKind.PropertyReference, Type: System.Int32) (Syntax: 'A')
                                Instance Receiver:
                                  IInstanceReferenceOperation (ReferenceKind: ImplicitReceiver) (OperationKind.InstanceReference, Type: <anonymous type: System.Int32 A>, IsImplicit) (Syntax: 'new { A = 10 }')
                            Right:
                              IFlowCaptureReferenceOperation: 0 (OperationKind.FlowCaptureReference, Type: System.Int32, Constant: 10, IsImplicit) (Syntax: '10')
            Next (Regular) Block[B2]
                Leaving: {R2}
                Entering: {R3}
    }
    .locals {R3}
    {
        CaptureIds: [1]
        Block[B2] - Block
            Predecessors: [B1]
            Statements (2)
                IFlowCaptureOperation: 1 (OperationKind.FlowCapture, Type: null, IsImplicit) (Syntax: 'nested')
                  Value:
                    ILocalReferenceOperation: nested (OperationKind.LocalReference, Type: <anonymous type: System.Int32 A>) (Syntax: 'nested')
                ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: <anonymous type: <anonymous type: System.Int32 A> Nested>, IsImplicit) (Syntax: 'a = new { N ...  = nested }')
                  Left:
                    ILocalReferenceOperation: a (IsDeclaration: True) (OperationKind.LocalReference, Type: <anonymous type: <anonymous type: System.Int32 A> Nested>, IsImplicit) (Syntax: 'a = new { N ...  = nested }')
                  Right:
                    IAnonymousObjectCreationOperation (OperationKind.AnonymousObjectCreation, Type: <anonymous type: <anonymous type: System.Int32 A> Nested>) (Syntax: 'new { Nested = nested }')
                      Initializers(1):
                          ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: <anonymous type: System.Int32 A>) (Syntax: 'Nested = nested')
                            Left:
                              IPropertyReferenceOperation: <anonymous type: System.Int32 A> <anonymous type: <anonymous type: System.Int32 A> Nested>.Nested { get; } (OperationKind.PropertyReference, Type: <anonymous type: System.Int32 A>) (Syntax: 'Nested')
                                Instance Receiver:
                                  IInstanceReferenceOperation (ReferenceKind: ImplicitReceiver) (OperationKind.InstanceReference, Type: <anonymous type: <anonymous type: System.Int32 A> Nested>, IsImplicit) (Syntax: 'new { Nested = nested }')
                            Right:
                              IFlowCaptureReferenceOperation: 1 (OperationKind.FlowCaptureReference, Type: <anonymous type: System.Int32 A>, IsImplicit) (Syntax: 'nested')
            Next (Regular) Block[B3]
                Leaving: {R3}
                Entering: {R4}
    }
    .locals {R4}
    {
        CaptureIds: [2]
        Block[B3] - Block
            Predecessors: [B2]
            Statements (3)
                ILocalReferenceOperation: a (OperationKind.LocalReference, Type: <anonymous type: <anonymous type: System.Int32 A> Nested>) (Syntax: 'a')
                IFlowCaptureOperation: 2 (OperationKind.FlowCapture, Type: null, IsInvalid, IsImplicit) (Syntax: '')
                  Value:
                    IInvalidOperation (OperationKind.Invalid, Type: null, IsInvalid) (Syntax: '')
                      Children(0)
                ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: <anonymous type: <anonymous type: System.Int32 A> Nested>, IsInvalid, IsImplicit) (Syntax: 'b = a with { Nested = ')
                  Left:
                    ILocalReferenceOperation: b (IsDeclaration: True) (OperationKind.LocalReference, Type: <anonymous type: <anonymous type: System.Int32 A> Nested>, IsInvalid, IsImplicit) (Syntax: 'b = a with { Nested = ')
                  Right:
                    IAnonymousObjectCreationOperation (OperationKind.AnonymousObjectCreation, Type: <anonymous type: <anonymous type: System.Int32 A> Nested>, IsInvalid) (Syntax: 'a with { Nested = ')
                      Initializers(1):
                          ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: <anonymous type: System.Int32 A>, IsInvalid, IsImplicit) (Syntax: 'a with { Nested = ')
                            Left:
                              IPropertyReferenceOperation: <anonymous type: System.Int32 A> <anonymous type: <anonymous type: System.Int32 A> Nested>.Nested { get; } (OperationKind.PropertyReference, Type: <anonymous type: System.Int32 A>, IsInvalid, IsImplicit) (Syntax: 'a with { Nested = ')
                                Instance Receiver:
                                  IInstanceReferenceOperation (ReferenceKind: ImplicitReceiver) (OperationKind.InstanceReference, Type: <anonymous type: <anonymous type: System.Int32 A> Nested>, IsInvalid, IsImplicit) (Syntax: 'a with { Nested = ')
                            Right:
                              IFlowCaptureReferenceOperation: 2 (OperationKind.FlowCaptureReference, Type: <anonymous type: <anonymous type: System.Int32 A> Nested>, IsImplicit) (Syntax: 'a')
            Next (Regular) Block[B4]
                Leaving: {R4}
    }
    Block[B4] - Block
        Predecessors: [B3]
        Statements (1)
            IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null, IsInvalid) (Syntax: 'A = 20 ')
              Expression:
                ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: ?, IsInvalid) (Syntax: 'A = 20')
                  Left:
                    IInvalidOperation (OperationKind.Invalid, Type: ?, IsInvalid) (Syntax: 'A')
                      Children(0)
                  Right:
                    ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 20) (Syntax: '20')
        Next (Regular) Block[B5]
            Leaving: {R1}
}
Block[B5] - Exit
    Predecessors: [B4]
    Statements (0)
";
            VerifyFlowGraphAndDiagnosticsForTest<BlockSyntax>(src, expectedFlowGraph, expectedDiagnostics, parseOptions: TestOptions.RegularPreview);
        }
 
        [Fact]
        public void WithExpr_AnonymousType_NonAssignmentExpression()
        {
            var src = @"
public class C
{
    public static void M(int i, int j)
    /*<bind>*/{
        var a = new { A = 10 };
        var b = a with { i, j++, M2(), A = 20 };
    }/*</bind>*/
 
    static int M2() => 0;
}";
 
            var comp = CreateCompilation(src, parseOptions: TestOptions.RegularPreview);
            var expectedDiagnostics = new[]
            {
                // (7,26): error CS0747: Invalid initializer member declarator
                //         var b = a with { i, j++, M2(), A = 20 };
                Diagnostic(ErrorCode.ERR_InvalidInitializerElementInitializer, "i").WithLocation(7, 26),
                // (7,26): error CS0117: '<anonymous type: int A>' does not contain a definition for 'i'
                //         var b = a with { i, j++, M2(), A = 20 };
                Diagnostic(ErrorCode.ERR_NoSuchMember, "i").WithArguments("<anonymous type: int A>", "i").WithLocation(7, 26),
                // (7,29): error CS0747: Invalid initializer member declarator
                //         var b = a with { i, j++, M2(), A = 20 };
                Diagnostic(ErrorCode.ERR_InvalidInitializerElementInitializer, "j++").WithLocation(7, 29),
                // (7,34): error CS0747: Invalid initializer member declarator
                //         var b = a with { i, j++, M2(), A = 20 };
                Diagnostic(ErrorCode.ERR_InvalidInitializerElementInitializer, "M2()").WithLocation(7, 34)
            };
            comp.VerifyEmitDiagnostics(expectedDiagnostics);
 
            var expectedFlowGraph = @"
Block[B0] - Entry
    Statements (0)
    Next (Regular) Block[B1]
        Entering: {R1} {R2}
.locals {R1}
{
    Locals: [<anonymous type: System.Int32 A> a] [<anonymous type: System.Int32 A> b]
    .locals {R2}
    {
        CaptureIds: [0]
        Block[B1] - Block
            Predecessors: [B0]
            Statements (2)
                IFlowCaptureOperation: 0 (OperationKind.FlowCapture, Type: null, IsImplicit) (Syntax: '10')
                  Value:
                    ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 10) (Syntax: '10')
                ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: <anonymous type: System.Int32 A>, IsImplicit) (Syntax: 'a = new { A = 10 }')
                  Left:
                    ILocalReferenceOperation: a (IsDeclaration: True) (OperationKind.LocalReference, Type: <anonymous type: System.Int32 A>, IsImplicit) (Syntax: 'a = new { A = 10 }')
                  Right:
                    IAnonymousObjectCreationOperation (OperationKind.AnonymousObjectCreation, Type: <anonymous type: System.Int32 A>) (Syntax: 'new { A = 10 }')
                      Initializers(1):
                          ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: System.Int32, Constant: 10) (Syntax: 'A = 10')
                            Left:
                              IPropertyReferenceOperation: System.Int32 <anonymous type: System.Int32 A>.A { get; } (OperationKind.PropertyReference, Type: System.Int32) (Syntax: 'A')
                                Instance Receiver:
                                  IInstanceReferenceOperation (ReferenceKind: ImplicitReceiver) (OperationKind.InstanceReference, Type: <anonymous type: System.Int32 A>, IsImplicit) (Syntax: 'new { A = 10 }')
                            Right:
                              IFlowCaptureReferenceOperation: 0 (OperationKind.FlowCaptureReference, Type: System.Int32, Constant: 10, IsImplicit) (Syntax: '10')
            Next (Regular) Block[B2]
                Leaving: {R2}
                Entering: {R3}
    }
    .locals {R3}
    {
        CaptureIds: [1]
        Block[B2] - Block
            Predecessors: [B1]
            Statements (6)
                ILocalReferenceOperation: a (OperationKind.LocalReference, Type: <anonymous type: System.Int32 A>) (Syntax: 'a')
                IInvalidOperation (OperationKind.Invalid, Type: null, IsInvalid, IsImplicit) (Syntax: 'i')
                  Children(0)
                IInvalidOperation (OperationKind.Invalid, Type: System.Int32, IsInvalid, IsImplicit) (Syntax: 'j++')
                  Children(1):
                      IIncrementOrDecrementOperation (Postfix) (OperationKind.Increment, Type: System.Int32, IsInvalid) (Syntax: 'j++')
                        Target:
                          IParameterReferenceOperation: j (OperationKind.ParameterReference, Type: System.Int32, IsInvalid) (Syntax: 'j')
                IInvalidOperation (OperationKind.Invalid, Type: System.Int32, IsInvalid, IsImplicit) (Syntax: 'M2()')
                  Children(1):
                      IInvocationOperation (System.Int32 C.M2()) (OperationKind.Invocation, Type: System.Int32, IsInvalid) (Syntax: 'M2()')
                        Instance Receiver:
                          null
                        Arguments(0)
                IFlowCaptureOperation: 1 (OperationKind.FlowCapture, Type: null, IsImplicit) (Syntax: '20')
                  Value:
                    ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 20) (Syntax: '20')
                ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: <anonymous type: System.Int32 A>, IsInvalid, IsImplicit) (Syntax: 'b = a with  ... ), A = 20 }')
                  Left:
                    ILocalReferenceOperation: b (IsDeclaration: True) (OperationKind.LocalReference, Type: <anonymous type: System.Int32 A>, IsInvalid, IsImplicit) (Syntax: 'b = a with  ... ), A = 20 }')
                  Right:
                    IAnonymousObjectCreationOperation (OperationKind.AnonymousObjectCreation, Type: <anonymous type: System.Int32 A>, IsInvalid) (Syntax: 'a with { i, ... ), A = 20 }')
                      Initializers(1):
                          ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: System.Int32, IsInvalid, IsImplicit) (Syntax: 'a with { i, ... ), A = 20 }')
                            Left:
                              IPropertyReferenceOperation: System.Int32 <anonymous type: System.Int32 A>.A { get; } (OperationKind.PropertyReference, Type: System.Int32, IsInvalid, IsImplicit) (Syntax: 'a with { i, ... ), A = 20 }')
                                Instance Receiver:
                                  IInstanceReferenceOperation (ReferenceKind: ImplicitReceiver) (OperationKind.InstanceReference, Type: <anonymous type: System.Int32 A>, IsInvalid, IsImplicit) (Syntax: 'a with { i, ... ), A = 20 }')
                            Right:
                              IFlowCaptureReferenceOperation: 1 (OperationKind.FlowCaptureReference, Type: <anonymous type: System.Int32 A>, IsImplicit) (Syntax: 'a')
            Next (Regular) Block[B3]
                Leaving: {R3} {R1}
    }
}
Block[B3] - Exit
    Predecessors: [B2]
    Statements (0)
";
            VerifyFlowGraphAndDiagnosticsForTest<BlockSyntax>(src, expectedFlowGraph, expectedDiagnostics, parseOptions: TestOptions.RegularPreview);
        }
 
        [Fact]
        public void WithExpr_AnonymousType_IndexerAccess()
        {
            var src = @"
public class C
{
    public static void M()
    /*<bind>*/{
        var a = new { A = 10 };
        var b = a with { [0] = 20 };
    }/*</bind>*/
}";
 
            var expectedDiagnostics = new[]
            {
                // (7,26): error CS0131: The left-hand side of an assignment must be a variable, property or indexer
                //         var b = a with { [0] = 20 };
                Diagnostic(ErrorCode.ERR_AssgLvalueExpected, "[0]").WithLocation(7, 26),
                // (7,26): error CS0747: Invalid initializer member declarator
                //         var b = a with { [0] = 20 };
                Diagnostic(ErrorCode.ERR_InvalidInitializerElementInitializer, "[0] = 20").WithLocation(7, 26)
            };
            var comp = CreateCompilation(src, parseOptions: TestOptions.RegularPreview);
            comp.VerifyEmitDiagnostics(expectedDiagnostics);
 
            var expectedFlowGraph = @"
Block[B0] - Entry
    Statements (0)
    Next (Regular) Block[B1]
        Entering: {R1} {R2}
 
.locals {R1}
{
    Locals: [<anonymous type: System.Int32 A> a] [<anonymous type: System.Int32 A> b]
    .locals {R2}
    {
        CaptureIds: [0]
        Block[B1] - Block
            Predecessors: [B0]
            Statements (2)
                IFlowCaptureOperation: 0 (OperationKind.FlowCapture, Type: null, IsImplicit) (Syntax: '10')
                  Value:
                    ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 10) (Syntax: '10')
 
                ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: <anonymous type: System.Int32 A>, IsImplicit) (Syntax: 'a = new { A = 10 }')
                  Left:
                    ILocalReferenceOperation: a (IsDeclaration: True) (OperationKind.LocalReference, Type: <anonymous type: System.Int32 A>, IsImplicit) (Syntax: 'a = new { A = 10 }')
                  Right:
                    IAnonymousObjectCreationOperation (OperationKind.AnonymousObjectCreation, Type: <anonymous type: System.Int32 A>) (Syntax: 'new { A = 10 }')
                      Initializers(1):
                          ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: System.Int32, Constant: 10) (Syntax: 'A = 10')
                            Left:
                              IPropertyReferenceOperation: System.Int32 <anonymous type: System.Int32 A>.A { get; } (OperationKind.PropertyReference, Type: System.Int32) (Syntax: 'A')
                                Instance Receiver:
                                  IInstanceReferenceOperation (ReferenceKind: ImplicitReceiver) (OperationKind.InstanceReference, Type: <anonymous type: System.Int32 A>, IsImplicit) (Syntax: 'new { A = 10 }')
                            Right:
                              IFlowCaptureReferenceOperation: 0 (OperationKind.FlowCaptureReference, Type: System.Int32, Constant: 10, IsImplicit) (Syntax: '10')
 
            Next (Regular) Block[B2]
                Leaving: {R2}
                Entering: {R3} {R4}
    }
    .locals {R3}
    {
        CaptureIds: [2]
        .locals {R4}
        {
            CaptureIds: [1]
            Block[B2] - Block
                Predecessors: [B1]
                Statements (3)
                    IFlowCaptureOperation: 1 (OperationKind.FlowCapture, Type: null, IsImplicit) (Syntax: 'a')
                      Value:
                        ILocalReferenceOperation: a (OperationKind.LocalReference, Type: <anonymous type: System.Int32 A>) (Syntax: 'a')
 
                    ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 20, IsInvalid) (Syntax: '20')
 
                    IFlowCaptureOperation: 2 (OperationKind.FlowCapture, Type: null, IsInvalid, IsImplicit) (Syntax: 'a with { [0] = 20 }')
                      Value:
                        IPropertyReferenceOperation: System.Int32 <anonymous type: System.Int32 A>.A { get; } (OperationKind.PropertyReference, Type: System.Int32, IsInvalid, IsImplicit) (Syntax: 'a with { [0] = 20 }')
                          Instance Receiver:
                            IFlowCaptureReferenceOperation: 1 (OperationKind.FlowCaptureReference, Type: <anonymous type: System.Int32 A>, IsImplicit) (Syntax: 'a')
 
                Next (Regular) Block[B3]
                    Leaving: {R4}
        }
 
        Block[B3] - Block
            Predecessors: [B2]
            Statements (1)
                ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: <anonymous type: System.Int32 A>, IsInvalid, IsImplicit) (Syntax: 'b = a with { [0] = 20 }')
                  Left:
                    ILocalReferenceOperation: b (IsDeclaration: True) (OperationKind.LocalReference, Type: <anonymous type: System.Int32 A>, IsInvalid, IsImplicit) (Syntax: 'b = a with { [0] = 20 }')
                  Right:
                    IAnonymousObjectCreationOperation (OperationKind.AnonymousObjectCreation, Type: <anonymous type: System.Int32 A>, IsInvalid) (Syntax: 'a with { [0] = 20 }')
                      Initializers(1):
                          ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: System.Int32, IsInvalid, IsImplicit) (Syntax: 'a with { [0] = 20 }')
                            Left:
                              IPropertyReferenceOperation: System.Int32 <anonymous type: System.Int32 A>.A { get; } (OperationKind.PropertyReference, Type: System.Int32, IsInvalid, IsImplicit) (Syntax: 'a with { [0] = 20 }')
                                Instance Receiver:
                                  IInstanceReferenceOperation (ReferenceKind: ImplicitReceiver) (OperationKind.InstanceReference, Type: <anonymous type: System.Int32 A>, IsInvalid, IsImplicit) (Syntax: 'a with { [0] = 20 }')
                            Right:
                              IFlowCaptureReferenceOperation: 2 (OperationKind.FlowCaptureReference, Type: <anonymous type: System.Int32 A>, IsImplicit) (Syntax: 'a')
 
            Next (Regular) Block[B4]
                Leaving: {R3} {R1}
    }
}
 
Block[B4] - Exit
    Predecessors: [B3]
    Statements (0)
";
            VerifyFlowGraphAndDiagnosticsForTest<BlockSyntax>(src, expectedFlowGraph, expectedDiagnostics, parseOptions: TestOptions.RegularPreview);
        }
 
        [Fact]
        public void WithExpr_AnonymousType_CannotSet()
        {
            var src = @"
public class C
{
    public static void M()
    {
        var a = new { A = 10 };
        a.A = 20;
 
        var b = new { B = a };
        b.B.A = 30;
    }
}";
            var comp = CreateCompilation(src, parseOptions: TestOptions.Regular9);
            comp.VerifyEmitDiagnostics(
                // (7,9): error CS0200: Property or indexer '<anonymous type: int A>.A' cannot be assigned to -- it is read only
                //         a.A = 20;
                Diagnostic(ErrorCode.ERR_AssgReadonlyProp, "a.A").WithArguments("<anonymous type: int A>.A").WithLocation(7, 9),
                // (10,9): error CS0200: Property or indexer '<anonymous type: int A>.A' cannot be assigned to -- it is read only
                //         b.B.A = 30;
                Diagnostic(ErrorCode.ERR_AssgReadonlyProp, "b.B.A").WithArguments("<anonymous type: int A>.A").WithLocation(10, 9)
                );
        }
 
        [Fact]
        public void WithExpr_AnonymousType_DuplicateMemberInDeclaration()
        {
            var src = @"
public class C
{
    public static void M()
    /*<bind>*/{
        var a = new { A = 10, A = 20 };
        var b = Identity(a) with { A = Identity(30) };
        System.Console.Write(b);
    }/*</bind>*/
 
    static T Identity<T>(T t) => t;
}";
            var expectedDiagnostics = new[]
            {
                // (6,31): error CS0833: An anonymous type cannot have multiple properties with the same name
                //         var a = new { A = 10, A = 20 };
                Diagnostic(ErrorCode.ERR_AnonymousTypeDuplicatePropertyName, "A = 20").WithLocation(6, 31)
            };
 
            var comp = CreateCompilation(src, parseOptions: TestOptions.RegularPreview);
            comp.VerifyEmitDiagnostics(expectedDiagnostics);
 
            var expectedFlowGraph = @"
Block[B0] - Entry
    Statements (0)
    Next (Regular) Block[B1]
        Entering: {R1} {R2}
.locals {R1}
{
    Locals: [<anonymous type: System.Int32 A, System.Int32 $1> a] [<anonymous type: System.Int32 A, System.Int32 $1> b]
    .locals {R2}
    {
        CaptureIds: [0] [1]
        Block[B1] - Block
            Predecessors: [B0]
            Statements (3)
                IFlowCaptureOperation: 0 (OperationKind.FlowCapture, Type: null, IsImplicit) (Syntax: '10')
                  Value:
                    ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 10) (Syntax: '10')
                IFlowCaptureOperation: 1 (OperationKind.FlowCapture, Type: null, IsInvalid, IsImplicit) (Syntax: '20')
                  Value:
                    ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 20, IsInvalid) (Syntax: '20')
                ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: <anonymous type: System.Int32 A, System.Int32 $1>, IsInvalid, IsImplicit) (Syntax: 'a = new { A ... 0, A = 20 }')
                  Left:
                    ILocalReferenceOperation: a (IsDeclaration: True) (OperationKind.LocalReference, Type: <anonymous type: System.Int32 A, System.Int32 $1>, IsInvalid, IsImplicit) (Syntax: 'a = new { A ... 0, A = 20 }')
                  Right:
                    IAnonymousObjectCreationOperation (OperationKind.AnonymousObjectCreation, Type: <anonymous type: System.Int32 A, System.Int32 $1>, IsInvalid) (Syntax: 'new { A = 10, A = 20 }')
                      Initializers(2):
                          ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: System.Int32, Constant: 10) (Syntax: 'A = 10')
                            Left:
                              IPropertyReferenceOperation: System.Int32 <anonymous type: System.Int32 A, System.Int32 $1>.A { get; } (OperationKind.PropertyReference, Type: System.Int32) (Syntax: 'A')
                                Instance Receiver:
                                  IInstanceReferenceOperation (ReferenceKind: ImplicitReceiver) (OperationKind.InstanceReference, Type: <anonymous type: System.Int32 A, System.Int32 $1>, IsInvalid, IsImplicit) (Syntax: 'new { A = 10, A = 20 }')
                            Right:
                              IFlowCaptureReferenceOperation: 0 (OperationKind.FlowCaptureReference, Type: System.Int32, Constant: 10, IsImplicit) (Syntax: '10')
                          ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: System.Int32, Constant: 20, IsInvalid) (Syntax: 'A = 20')
                            Left:
                              IPropertyReferenceOperation: System.Int32 <anonymous type: System.Int32 A, System.Int32 $1>.$1 { get; } (OperationKind.PropertyReference, Type: System.Int32, IsInvalid) (Syntax: 'A')
                                Instance Receiver:
                                  IInstanceReferenceOperation (ReferenceKind: ImplicitReceiver) (OperationKind.InstanceReference, Type: <anonymous type: System.Int32 A, System.Int32 $1>, IsInvalid, IsImplicit) (Syntax: 'new { A = 10, A = 20 }')
                            Right:
                              IFlowCaptureReferenceOperation: 1 (OperationKind.FlowCaptureReference, Type: System.Int32, Constant: 20, IsInvalid, IsImplicit) (Syntax: '20')
            Next (Regular) Block[B2]
                Leaving: {R2}
                Entering: {R3} {R4}
    }
    .locals {R3}
    {
        CaptureIds: [3] [4]
        .locals {R4}
        {
            CaptureIds: [2]
            Block[B2] - Block
                Predecessors: [B1]
                Statements (3)
                    IFlowCaptureOperation: 2 (OperationKind.FlowCapture, Type: null, IsImplicit) (Syntax: 'Identity(a)')
                      Value:
                        IInvocationOperation (<anonymous type: System.Int32 A, System.Int32 $1> C.Identity<<anonymous type: System.Int32 A, System.Int32 $1>>(<anonymous type: System.Int32 A, System.Int32 $1> t)) (OperationKind.Invocation, Type: <anonymous type: System.Int32 A, System.Int32 $1>) (Syntax: 'Identity(a)')
                          Instance Receiver:
                            null
                          Arguments(1):
                              IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: t) (OperationKind.Argument, Type: null) (Syntax: 'a')
                                ILocalReferenceOperation: a (OperationKind.LocalReference, Type: <anonymous type: System.Int32 A, System.Int32 $1>) (Syntax: 'a')
                                InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null)
                                OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null)
                    IFlowCaptureOperation: 3 (OperationKind.FlowCapture, Type: null, IsImplicit) (Syntax: 'Identity(30)')
                      Value:
                        IInvocationOperation (System.Int32 C.Identity<System.Int32>(System.Int32 t)) (OperationKind.Invocation, Type: System.Int32) (Syntax: 'Identity(30)')
                          Instance Receiver:
                            null
                          Arguments(1):
                              IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: t) (OperationKind.Argument, Type: null) (Syntax: '30')
                                ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 30) (Syntax: '30')
                                InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null)
                                OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null)
                    IFlowCaptureOperation: 4 (OperationKind.FlowCapture, Type: null, IsImplicit) (Syntax: 'Identity(a) ... ntity(30) }')
                      Value:
                        IPropertyReferenceOperation: System.Int32 <anonymous type: System.Int32 A, System.Int32 $1>.$1 { get; } (OperationKind.PropertyReference, Type: System.Int32, IsImplicit) (Syntax: 'Identity(a) ... ntity(30) }')
                          Instance Receiver:
                            IFlowCaptureReferenceOperation: 2 (OperationKind.FlowCaptureReference, Type: <anonymous type: System.Int32 A, System.Int32 $1>, IsImplicit) (Syntax: 'Identity(a)')
                Next (Regular) Block[B3]
                    Leaving: {R4}
        }
        Block[B3] - Block
            Predecessors: [B2]
            Statements (1)
                ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: <anonymous type: System.Int32 A, System.Int32 $1>, IsImplicit) (Syntax: 'b = Identit ... ntity(30) }')
                  Left:
                    ILocalReferenceOperation: b (IsDeclaration: True) (OperationKind.LocalReference, Type: <anonymous type: System.Int32 A, System.Int32 $1>, IsImplicit) (Syntax: 'b = Identit ... ntity(30) }')
                  Right:
                    IAnonymousObjectCreationOperation (OperationKind.AnonymousObjectCreation, Type: <anonymous type: System.Int32 A, System.Int32 $1>) (Syntax: 'Identity(a) ... ntity(30) }')
                      Initializers(2):
                          ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: System.Int32, IsImplicit) (Syntax: 'Identity(a) ... ntity(30) }')
                            Left:
                              IPropertyReferenceOperation: System.Int32 <anonymous type: System.Int32 A, System.Int32 $1>.A { get; } (OperationKind.PropertyReference, Type: System.Int32, IsImplicit) (Syntax: 'Identity(a) ... ntity(30) }')
                                Instance Receiver:
                                  IInstanceReferenceOperation (ReferenceKind: ImplicitReceiver) (OperationKind.InstanceReference, Type: <anonymous type: System.Int32 A, System.Int32 $1>, IsImplicit) (Syntax: 'Identity(a) ... ntity(30) }')
                            Right:
                              IFlowCaptureReferenceOperation: 3 (OperationKind.FlowCaptureReference, Type: <anonymous type: System.Int32 A, System.Int32 $1>, IsImplicit) (Syntax: 'Identity(a)')
                          ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: System.Int32, IsImplicit) (Syntax: 'Identity(a) ... ntity(30) }')
                            Left:
                              IPropertyReferenceOperation: System.Int32 <anonymous type: System.Int32 A, System.Int32 $1>.$1 { get; } (OperationKind.PropertyReference, Type: System.Int32, IsImplicit) (Syntax: 'Identity(a) ... ntity(30) }')
                                Instance Receiver:
                                  IInstanceReferenceOperation (ReferenceKind: ImplicitReceiver) (OperationKind.InstanceReference, Type: <anonymous type: System.Int32 A, System.Int32 $1>, IsImplicit) (Syntax: 'Identity(a) ... ntity(30) }')
                            Right:
                              IFlowCaptureReferenceOperation: 4 (OperationKind.FlowCaptureReference, Type: <anonymous type: System.Int32 A, System.Int32 $1>, IsImplicit) (Syntax: 'Identity(a)')
            Next (Regular) Block[B4]
                Leaving: {R3}
    }
    Block[B4] - Block
        Predecessors: [B3]
        Statements (1)
            IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'System.Console.Write(b);')
              Expression:
                IInvocationOperation (void System.Console.Write(System.Object value)) (OperationKind.Invocation, Type: System.Void) (Syntax: 'System.Console.Write(b)')
                  Instance Receiver:
                    null
                  Arguments(1):
                      IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: value) (OperationKind.Argument, Type: null) (Syntax: 'b')
                        IConversionOperation (TryCast: False, Unchecked) (OperationKind.Conversion, Type: System.Object, IsImplicit) (Syntax: 'b')
                          Conversion: CommonConversion (Exists: True, IsIdentity: False, IsNumeric: False, IsReference: True, IsUserDefined: False) (MethodSymbol: null)
                            (ImplicitReference)
                          Operand:
                            ILocalReferenceOperation: b (OperationKind.LocalReference, Type: <anonymous type: System.Int32 A, System.Int32 $1>) (Syntax: 'b')
                        InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null)
                        OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null)
        Next (Regular) Block[B5]
            Leaving: {R1}
}
Block[B5] - Exit
    Predecessors: [B4]
    Statements (0)
";
 
            VerifyFlowGraphAndDiagnosticsForTest<BlockSyntax>(src, expectedFlowGraph, expectedDiagnostics, parseOptions: TestOptions.RegularPreview);
        }
 
        [Fact]
        public void WithExpr_AnonymousType_DuplicateInitialization()
        {
            var src = @"
public class C
{
    public static void M()
    /*<bind>*/{
        var a = new { A = 10 };
        var b = Identity(a) with { A = Identity(30), A = Identity(40) };
    }/*</bind>*/
 
    static T Identity<T>(T t) => t;
}";
            var expectedDiagnostics = new[]
            {
                // (7,54): error CS1912: Duplicate initialization of member 'A'
                //         var b = Identity(a) with { A = Identity(30), A = Identity(40) };
                Diagnostic(ErrorCode.ERR_MemberAlreadyInitialized, "A").WithArguments("A").WithLocation(7, 54)
            };
 
            var comp = CreateCompilation(src, parseOptions: TestOptions.RegularPreview);
            comp.VerifyEmitDiagnostics(expectedDiagnostics);
 
            var expectedFlowGraph = @"
Block[B0] - Entry
    Statements (0)
    Next (Regular) Block[B1]
        Entering: {R1} {R2}
.locals {R1}
{
    Locals: [<anonymous type: System.Int32 A> a] [<anonymous type: System.Int32 A> b]
    .locals {R2}
    {
        CaptureIds: [0]
        Block[B1] - Block
            Predecessors: [B0]
            Statements (2)
                IFlowCaptureOperation: 0 (OperationKind.FlowCapture, Type: null, IsImplicit) (Syntax: '10')
                  Value:
                    ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 10) (Syntax: '10')
                ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: <anonymous type: System.Int32 A>, IsImplicit) (Syntax: 'a = new { A = 10 }')
                  Left:
                    ILocalReferenceOperation: a (IsDeclaration: True) (OperationKind.LocalReference, Type: <anonymous type: System.Int32 A>, IsImplicit) (Syntax: 'a = new { A = 10 }')
                  Right:
                    IAnonymousObjectCreationOperation (OperationKind.AnonymousObjectCreation, Type: <anonymous type: System.Int32 A>) (Syntax: 'new { A = 10 }')
                      Initializers(1):
                          ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: System.Int32, Constant: 10) (Syntax: 'A = 10')
                            Left:
                              IPropertyReferenceOperation: System.Int32 <anonymous type: System.Int32 A>.A { get; } (OperationKind.PropertyReference, Type: System.Int32) (Syntax: 'A')
                                Instance Receiver:
                                  IInstanceReferenceOperation (ReferenceKind: ImplicitReceiver) (OperationKind.InstanceReference, Type: <anonymous type: System.Int32 A>, IsImplicit) (Syntax: 'new { A = 10 }')
                            Right:
                              IFlowCaptureReferenceOperation: 0 (OperationKind.FlowCaptureReference, Type: System.Int32, Constant: 10, IsImplicit) (Syntax: '10')
            Next (Regular) Block[B2]
                Leaving: {R2}
                Entering: {R3}
    }
    .locals {R3}
    {
        CaptureIds: [1]
        Block[B2] - Block
            Predecessors: [B1]
            Statements (4)
                IInvocationOperation (<anonymous type: System.Int32 A> C.Identity<<anonymous type: System.Int32 A>>(<anonymous type: System.Int32 A> t)) (OperationKind.Invocation, Type: <anonymous type: System.Int32 A>) (Syntax: 'Identity(a)')
                  Instance Receiver:
                    null
                  Arguments(1):
                      IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: t) (OperationKind.Argument, Type: null) (Syntax: 'a')
                        ILocalReferenceOperation: a (OperationKind.LocalReference, Type: <anonymous type: System.Int32 A>) (Syntax: 'a')
                        InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null)
                        OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null)
                IFlowCaptureOperation: 1 (OperationKind.FlowCapture, Type: null, IsImplicit) (Syntax: 'Identity(30)')
                  Value:
                    IInvocationOperation (System.Int32 C.Identity<System.Int32>(System.Int32 t)) (OperationKind.Invocation, Type: System.Int32) (Syntax: 'Identity(30)')
                      Instance Receiver:
                        null
                      Arguments(1):
                          IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: t) (OperationKind.Argument, Type: null) (Syntax: '30')
                            ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 30) (Syntax: '30')
                            InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null)
                            OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null)
                IInvocationOperation (System.Int32 C.Identity<System.Int32>(System.Int32 t)) (OperationKind.Invocation, Type: System.Int32) (Syntax: 'Identity(40)')
                  Instance Receiver:
                    null
                  Arguments(1):
                      IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: t) (OperationKind.Argument, Type: null) (Syntax: '40')
                        ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 40) (Syntax: '40')
                        InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null)
                        OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null)
                ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: <anonymous type: System.Int32 A>, IsInvalid, IsImplicit) (Syntax: 'b = Identit ... ntity(40) }')
                  Left:
                    ILocalReferenceOperation: b (IsDeclaration: True) (OperationKind.LocalReference, Type: <anonymous type: System.Int32 A>, IsInvalid, IsImplicit) (Syntax: 'b = Identit ... ntity(40) }')
                  Right:
                    IAnonymousObjectCreationOperation (OperationKind.AnonymousObjectCreation, Type: <anonymous type: System.Int32 A>, IsInvalid) (Syntax: 'Identity(a) ... ntity(40) }')
                      Initializers(1):
                          ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: System.Int32, IsInvalid, IsImplicit) (Syntax: 'Identity(a) ... ntity(40) }')
                            Left:
                              IPropertyReferenceOperation: System.Int32 <anonymous type: System.Int32 A>.A { get; } (OperationKind.PropertyReference, Type: System.Int32, IsInvalid, IsImplicit) (Syntax: 'Identity(a) ... ntity(40) }')
                                Instance Receiver:
                                  IInstanceReferenceOperation (ReferenceKind: ImplicitReceiver) (OperationKind.InstanceReference, Type: <anonymous type: System.Int32 A>, IsInvalid, IsImplicit) (Syntax: 'Identity(a) ... ntity(40) }')
                            Right:
                              IFlowCaptureReferenceOperation: 1 (OperationKind.FlowCaptureReference, Type: <anonymous type: System.Int32 A>, IsImplicit) (Syntax: 'Identity(a)')
            Next (Regular) Block[B3]
                Leaving: {R3} {R1}
    }
}
Block[B3] - Exit
    Predecessors: [B2]
    Statements (0)
";
 
            VerifyFlowGraphAndDiagnosticsForTest<BlockSyntax>(src, expectedFlowGraph, expectedDiagnostics, parseOptions: TestOptions.RegularPreview);
        }
 
        [Fact, WorkItem(53849, "https://github.com/dotnet/roslyn/issues/53849")]
        public void WithExpr_AnonymousType_ValueIsLoweredToo()
        {
            var src = @"
var x = new { Property = 42 };
var adjusted = x with { Property = x.Property + 2 };
 
System.Console.WriteLine(adjusted);
";
            var comp = CreateCompilation(src, parseOptions: TestOptions.RegularPreview);
            var verifier = CompileAndVerify(comp, expectedOutput: "{ Property = 44 }");
            verifier.VerifyDiagnostics();
        }
 
        [Fact, WorkItem(53849, "https://github.com/dotnet/roslyn/issues/53849")]
        public void WithExpr_AnonymousType_ValueIsLoweredToo_NestedWith()
        {
            var src = @"
var x = new { Property = 42 };
var container = new { Item = x };
var adjusted = container with { Item = x with { Property = x.Property + 2 } };
 
System.Console.WriteLine(adjusted);
";
            var comp = CreateCompilation(src, parseOptions: TestOptions.RegularPreview);
            var verifier = CompileAndVerify(comp, expectedOutput: "{ Item = { Property = 44 } }");
            verifier.VerifyDiagnostics();
        }
 
        [Fact]
        public void AttributesOnPrimaryConstructorParameters_01()
        {
            string source = @"
[System.AttributeUsage(System.AttributeTargets.Field, AllowMultiple = true) ]
public class A : System.Attribute
{
}
[System.AttributeUsage(System.AttributeTargets.Property, AllowMultiple = true) ]
public class B : System.Attribute
{
}
 
[System.AttributeUsage(System.AttributeTargets.Parameter, AllowMultiple = true) ]
public class C : System.Attribute
{
}
 
[System.AttributeUsage(System.AttributeTargets.Parameter, AllowMultiple = true) ]
public class D : System.Attribute
{
}
 
public readonly record struct Test(
    [field: A]
    [property: B]
    [param: C]
    [D]
    int P1)
{
}
";
            Action<ModuleSymbol> symbolValidator = moduleSymbol =>
            {
                var @class = moduleSymbol.GlobalNamespace.GetMember<NamedTypeSymbol>("Test");
 
                var prop1 = @class.GetMember<PropertySymbol>("P1");
                AssertEx.SetEqual(new[] { "B" }, getAttributeStrings(prop1));
 
                var field1 = @class.GetMember<FieldSymbol>("<P1>k__BackingField");
                AssertEx.SetEqual(new[] { "A" }, getAttributeStrings(field1));
 
                var param1 = @class.GetMembers(".ctor").OfType<MethodSymbol>().Where(m => m.Parameters.AsSingleton()?.Name == "P1").Single().Parameters[0];
                AssertEx.SetEqual(new[] { "C", "D" }, getAttributeStrings(param1));
            };
 
            var comp = CompileAndVerify(new[] { source, IsExternalInitTypeDefinition }, sourceSymbolValidator: symbolValidator, symbolValidator: symbolValidator,
                parseOptions: TestOptions.RegularPreview,
                // init-only is unverifiable
                verify: Verification.Skipped,
                options: TestOptions.DebugDll.WithMetadataImportOptions(MetadataImportOptions.All));
 
            comp.VerifyDiagnostics();
 
            IEnumerable<string> getAttributeStrings(Symbol symbol)
            {
                return GetAttributeStrings(symbol.GetAttributes().Where(a => a.AttributeClass!.Name is "A" or "B" or "C" or "D"));
            }
        }
 
        [Fact]
        public void FieldAsPositionalMember()
        {
            var source = @"
var a = new A(42);
System.Console.Write(a.X);
System.Console.Write("" - "");
a.Deconstruct(out int x);
System.Console.Write(x);
 
record struct A(int X)
{
    public int X = X;
}
";
            var comp = CreateCompilation(source, parseOptions: TestOptions.Regular9);
            comp.VerifyEmitDiagnostics(
                // (8,8): error CS8773: Feature 'record structs' is not available in C# 9.0. Please use language version 10.0 or greater.
                // record struct A(int X)
                Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion9, "struct").WithArguments("record structs", "10.0").WithLocation(8, 8),
                // (8,17): error CS8773: Feature 'positional fields in records' is not available in C# 9.0. Please use language version 10.0 or greater.
                // record struct A(int X)
                Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion9, "int X").WithArguments("positional fields in records", "10.0").WithLocation(8, 17));
 
            comp = CreateCompilation(source, parseOptions: TestOptions.Regular10);
            comp.VerifyDiagnostics();
            var verifier = CompileAndVerify(comp, expectedOutput: "42 - 42");
            verifier.VerifyIL("A.Deconstruct", @"
{
  // Code size        9 (0x9)
  .maxstack  2
  IL_0000:  ldarg.1
  IL_0001:  ldarg.0
  IL_0002:  ldfld      ""int A.X""
  IL_0007:  stind.i4
  IL_0008:  ret
}
");
        }
 
        [Fact]
        public void FieldAsPositionalMember_Readonly()
        {
            var source = @"
readonly record struct A(int X)
{
    public int X = X; // 1
}
readonly record struct B(int X)
{
    public readonly int X = X;
}
";
 
            var comp = CreateCompilation(source);
            comp.VerifyDiagnostics(
                // (4,16): error CS8340: Instance fields of readonly structs must be readonly.
                //     public int X = X; // 1
                Diagnostic(ErrorCode.ERR_FieldsInRoStruct, "X").WithLocation(4, 16)
                );
        }
 
        [Fact]
        public void FieldAsPositionalMember_Fixed()
        {
            var src = @"
unsafe record struct C(int[] P)
{
    public fixed int P[2];
    public int[] X = P;
}";
            var comp = CreateCompilation(src, options: TestOptions.UnsafeReleaseDll, parseOptions: TestOptions.RegularPreview);
            comp.VerifyEmitDiagnostics(
                // (2,30): error CS8866: Record member 'C.P' must be a readable instance property or field of type 'int[]' to match positional parameter 'P'.
                // unsafe record struct C(int[] P)
                Diagnostic(ErrorCode.ERR_BadRecordMemberForPositionalParameter, "P").WithArguments("C.P", "int[]", "P").WithLocation(2, 30),
                // (4,22): error CS8908: The type 'int*' may not be used for a field of a record.
                //     public fixed int P[2];
                Diagnostic(ErrorCode.ERR_BadFieldTypeInRecord, "P").WithArguments("int*").WithLocation(4, 22)
                );
        }
 
        [Fact]
        public void FieldAsPositionalMember_WrongType()
        {
            var source = @"
record struct A(int X)
{
    public string X = null;
    public int Y = X;
}
";
 
            var comp = CreateCompilation(source);
            comp.VerifyDiagnostics(
                // (2,21): error CS8866: Record member 'A.X' must be a readable instance property or field of type 'int' to match positional parameter 'X'.
                // record struct A(int X)
                Diagnostic(ErrorCode.ERR_BadRecordMemberForPositionalParameter, "X").WithArguments("A.X", "int", "X").WithLocation(2, 21)
                );
        }
 
        [Fact]
        public void FieldAsPositionalMember_DuplicateFields()
        {
            var source = @"
record struct A(int X)
{
    public int X = 0;
    public int X = 0;
    public int Y = X;
}
";
 
            var comp = CreateCompilation(source);
            comp.VerifyDiagnostics(
                // (5,16): error CS0102: The type 'A' already contains a definition for 'X'
                //     public int X = 0;
                Diagnostic(ErrorCode.ERR_DuplicateNameInClass, "X").WithArguments("A", "X").WithLocation(5, 16)
                );
        }
 
        [Fact]
        public void SyntaxFactory_TypeDeclaration()
        {
            var expected = @"record struct Point
{
}";
            AssertEx.AssertEqualToleratingWhitespaceDifferences(expected, SyntaxFactory.TypeDeclaration(SyntaxKind.RecordStructDeclaration, "Point").NormalizeWhitespace().ToString());
        }
 
        [Fact]
        public void InterfaceWithParameters()
        {
            var src = @"
public interface I
{
}
 
record struct R(int X) : I()
{
}
 
record struct R2(int X) : I(X)
{
}
";
            var comp = CreateCompilation(src);
            comp.VerifyEmitDiagnostics(
                // (6,27): error CS8861: Unexpected argument list.
                // record struct R(int X) : I()
                Diagnostic(ErrorCode.ERR_UnexpectedArgumentList, "()").WithLocation(6, 27),
                // (10,28): error CS8861: Unexpected argument list.
                // record struct R2(int X) : I(X)
                Diagnostic(ErrorCode.ERR_UnexpectedArgumentList, "(X)").WithLocation(10, 28)
                );
        }
 
        [Fact]
        public void InterfaceWithParameters_NoPrimaryConstructor()
        {
            var src = @"
public interface I
{
}
 
record struct R : I()
{
}
 
record struct R2 : I(0)
{
}
";
            var comp = CreateCompilation(src);
            comp.VerifyEmitDiagnostics(
                // (6,20): error CS8861: Unexpected argument list.
                // record struct R : I()
                Diagnostic(ErrorCode.ERR_UnexpectedArgumentList, "()").WithLocation(6, 20),
                // (10,21): error CS8861: Unexpected argument list.
                // record struct R2 : I(0)
                Diagnostic(ErrorCode.ERR_UnexpectedArgumentList, "(0)").WithLocation(10, 21)
                );
        }
 
        [Fact]
        public void InterfaceWithParameters_Struct()
        {
            var src = @"
public interface I
{
}
 
struct C : I()
{
}
 
struct C2 : I(0)
{
}
";
            var comp = CreateCompilation(src);
            comp.VerifyEmitDiagnostics(
                // (6,13): error CS8861: Unexpected argument list.
                // struct C : I()
                Diagnostic(ErrorCode.ERR_UnexpectedArgumentList, "()").WithLocation(6, 13),
                // (10,14): error CS8861: Unexpected argument list.
                // struct C2 : I(0)
                Diagnostic(ErrorCode.ERR_UnexpectedArgumentList, "(0)").WithLocation(10, 14)
                );
        }
 
        [Fact]
        public void BaseArguments_Speculation()
        {
            var src = @"
record struct R1(int X) : Error1(0, 1)
{
}
record struct R2(int X) : Error2()
{
}
record struct R3(int X) : Error3
{
}
";
            var comp = CreateCompilation(src);
            comp.VerifyDiagnostics(
                // (2,27): error CS0246: The type or namespace name 'Error1' could not be found (are you missing a using directive or an assembly reference?)
                // record struct R1(int X) : Error1(0, 1)
                Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "Error1").WithArguments("Error1").WithLocation(2, 27),
                // (2,33): error CS8861: Unexpected argument list.
                // record struct R1(int X) : Error1(0, 1)
                Diagnostic(ErrorCode.ERR_UnexpectedArgumentList, "(0, 1)").WithLocation(2, 33),
                // (5,27): error CS0246: The type or namespace name 'Error2' could not be found (are you missing a using directive or an assembly reference?)
                // record struct R2(int X) : Error2()
                Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "Error2").WithArguments("Error2").WithLocation(5, 27),
                // (5,33): error CS8861: Unexpected argument list.
                // record struct R2(int X) : Error2()
                Diagnostic(ErrorCode.ERR_UnexpectedArgumentList, "()").WithLocation(5, 33),
                // (8,27): error CS0246: The type or namespace name 'Error3' could not be found (are you missing a using directive or an assembly reference?)
                // record struct R3(int X) : Error3
                Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "Error3").WithArguments("Error3").WithLocation(8, 27)
                );
 
            var tree = comp.SyntaxTrees.First();
            var model = comp.GetSemanticModel(tree);
 
            var baseWithargs =
                tree.GetRoot().DescendantNodes().OfType<PrimaryConstructorBaseTypeSyntax>().First();
            Assert.Equal("Error1(0, 1)", baseWithargs.ToString());
 
            var speculativeBase =
                baseWithargs.WithArgumentList(baseWithargs.ArgumentList.WithArguments(baseWithargs.ArgumentList.Arguments.RemoveAt(1)));
            Assert.Equal("Error1(0)", speculativeBase.ToString());
 
            Assert.False(model.TryGetSpeculativeSemanticModel(baseWithargs.ArgumentList.OpenParenToken.SpanStart, speculativeBase, out _));
 
            var baseWithoutargs =
                tree.GetRoot().DescendantNodes().OfType<PrimaryConstructorBaseTypeSyntax>().Skip(1).First();
            Assert.Equal("Error2()", baseWithoutargs.ToString());
 
            Assert.False(model.TryGetSpeculativeSemanticModel(baseWithoutargs.ArgumentList.OpenParenToken.SpanStart, speculativeBase, out _));
 
            var baseWithoutParens = tree.GetRoot().DescendantNodes().OfType<SimpleBaseTypeSyntax>().Single();
            Assert.Equal("Error3", baseWithoutParens.ToString());
 
            Assert.False(model.TryGetSpeculativeSemanticModel(baseWithoutParens.SpanStart + 2, speculativeBase, out _));
        }
 
        [Fact, WorkItem(54413, "https://github.com/dotnet/roslyn/issues/54413")]
        public void ValueTypeCopyConstructorLike_NoThisInitializer()
        {
            var src = @"
record struct Value(string Text)
{
    private Value(int X) { } // 1
    private Value(Value original) { } // 2
}
 
record class Boxed(string Text)
{
    private Boxed(int X) { } // 3
    private Boxed(Boxed original) { } // 4
}
";
            var comp = CreateCompilation(src);
            comp.VerifyEmitDiagnostics(
                // (4,13): error CS8862: A constructor declared in a type with parameter list must have 'this' constructor initializer.
                //     private Value(int X) { } // 1
                Diagnostic(ErrorCode.ERR_UnexpectedOrMissingConstructorInitializerInRecord, "Value").WithLocation(4, 13),
                // (5,13): error CS8862: A constructor declared in a type with parameter list must have 'this' constructor initializer.
                //     private Value(Value original) { } // 2
                Diagnostic(ErrorCode.ERR_UnexpectedOrMissingConstructorInitializerInRecord, "Value").WithLocation(5, 13),
                // (10,13): error CS8862: A constructor declared in a type with parameter list must have 'this' constructor initializer.
                //     private Boxed(int X) { } // 3
                Diagnostic(ErrorCode.ERR_UnexpectedOrMissingConstructorInitializerInRecord, "Boxed").WithLocation(10, 13),
                // (11,13): error CS8878: A copy constructor 'Boxed.Boxed(Boxed)' must be public or protected because the record is not sealed.
                //     private Boxed(Boxed original) { } // 4
                Diagnostic(ErrorCode.ERR_CopyConstructorWrongAccessibility, "Boxed").WithArguments("Boxed.Boxed(Boxed)").WithLocation(11, 13)
                );
        }
 
        [Fact]
        public void ValueTypeCopyConstructorLike()
        {
            var src = @"
System.Console.Write(new Value(new Value(0)));
 
record struct Value(int I)
{
    public Value(Value original) : this(42) { }
}
";
            var comp = CreateCompilation(src);
            CompileAndVerify(comp, expectedOutput: "Value { I = 42 }");
        }
 
        [Fact]
        public void ExplicitConstructors_01()
        {
            var source =
@"using static System.Console;
record struct S1
{
}
record struct S2
{
    public S2() { }
}
record struct S3
{
    public S3(object o) { }
}
class Program
{
    static void Main()
    {
        WriteLine(new S1());
        WriteLine(new S2());
        WriteLine(new S3());
        WriteLine(new S3(null));
    }
}";
            var verifier = CompileAndVerify(source, expectedOutput:
@"S1 { }
S2 { }
S3 { }
S3 { }
");
            verifier.VerifyMissing("S1..ctor()");
            verifier.VerifyIL("S2..ctor()",
@"{
  // Code size        1 (0x1)
  .maxstack  0
  IL_0000:  ret
}");
            verifier.VerifyMissing("S3..ctor()");
            verifier.VerifyIL("S3..ctor(object)",
@"{
  // Code size        1 (0x1)
  .maxstack  0
  IL_0000:  ret
}");
        }
 
        [Fact]
        public void ExplicitConstructors_02()
        {
            var source =
@"record struct S1
{
    public S1(object o) { }
}
record struct S2()
{
    public S2(object o) { }
}
record struct S3(char A)
{
    public S3(object o) { }
}
record struct S4(char A, char B)
{
    public S4(object o) { }
}";
            var comp = CreateCompilation(source);
            comp.VerifyDiagnostics(
                // (7,12): error CS8862: A constructor declared in a type with parameter list must have 'this' constructor initializer.
                //     public S2(object o) { }
                Diagnostic(ErrorCode.ERR_UnexpectedOrMissingConstructorInitializerInRecord, "S2").WithLocation(7, 12),
                // (11,12): error CS8862: A constructor declared in a type with parameter list must have 'this' constructor initializer.
                //     public S3(object o) { }
                Diagnostic(ErrorCode.ERR_UnexpectedOrMissingConstructorInitializerInRecord, "S3").WithLocation(11, 12),
                // (15,12): error CS8862: A constructor declared in a type with parameter list must have 'this' constructor initializer.
                //     public S4(object o) { }
                Diagnostic(ErrorCode.ERR_UnexpectedOrMissingConstructorInitializerInRecord, "S4").WithLocation(15, 12));
        }
 
        [Fact]
        public void ExplicitConstructors_03()
        {
            var source =
@"using static System.Console;
record struct S1
{
    public S1(object o) : this() { }
}
record struct S2()
{
    public S2(object o) : this() { }
}
class Program
{
    static void Main()
    {
        WriteLine(new S1());
        WriteLine(new S2());
    }
}";
            CompileAndVerify(source, expectedOutput:
@"S1 { }
S2 { }
");
        }
 
        [Fact]
        public void ExplicitConstructors_04()
        {
            var source =
@"using static System.Console;
record struct S0
{
    internal object F = 0;
    public S0() { }
}
record struct S1
{
    internal object F = 1;
    public S1(object o) : this() { F = o; }
}
record struct S2()
{
    internal object F = 2;
    public S2(object o) : this() { F = o; }
}
class Program
{
    static void Main()
    {
        WriteLine(new S0().F);
        WriteLine(new S1().F);
        WriteLine(new S1(-1).F);
        WriteLine(new S2().F);
        WriteLine(new S2(-2).F);
    }
}";
            CompileAndVerify(source, expectedOutput:
@"0
 
-1
2
-2
");
        }
 
        [Fact]
        [WorkItem(58328, "https://github.com/dotnet/roslyn/issues/58328")]
        public void ExplicitConstructors_05()
        {
            var source =
@"record struct S3(char A)
{
    public S3(object o) : this() { }
}
record struct S4(char A, char B)
{
    public S4(object o) : this() { }
}";
            var comp = CreateCompilation(source);
            comp.VerifyDiagnostics(
                // (3,27): error CS8982: A constructor declared in a 'struct' with parameter list must have a 'this' initializer that calls the primary constructor or an explicitly declared constructor.
                //     public S3(object o) : this() { }
                Diagnostic(ErrorCode.ERR_RecordStructConstructorCallsDefaultConstructor, "this").WithLocation(3, 27),
                // (7,27): error CS8982: A constructor declared in a 'struct' with parameter list must have a 'this' initializer that calls the primary constructor or an explicitly declared constructor.
                //     public S4(object o) : this() { }
                Diagnostic(ErrorCode.ERR_RecordStructConstructorCallsDefaultConstructor, "this").WithLocation(7, 27));
        }
 
        [Fact]
        [WorkItem(58328, "https://github.com/dotnet/roslyn/issues/58328")]
        public void ExplicitConstructors_06()
        {
            var source =
@"record struct S3(char A)
{
    internal object F = 3;
    public S3(object o) : this() { F = o; }
}
record struct S4(char A, char B)
{
    internal object F = 4;
    public S4(object o) : this() { F = o; }
}";
            var comp = CreateCompilation(source);
            comp.VerifyDiagnostics(
                // (4,27): error CS8982: A constructor declared in a 'struct' with parameter list must have a 'this' initializer that calls the primary constructor or an explicitly declared constructor.
                //     public S3(object o) : this() { F = o; }
                Diagnostic(ErrorCode.ERR_RecordStructConstructorCallsDefaultConstructor, "this").WithLocation(4, 27),
                // (9,27): error CS8982: A constructor declared in a 'struct' with parameter list must have a 'this' initializer that calls the primary constructor or an explicitly declared constructor.
                //     public S4(object o) : this() { F = o; }
                Diagnostic(ErrorCode.ERR_RecordStructConstructorCallsDefaultConstructor, "this").WithLocation(9, 27));
        }
 
        [Fact]
        public void ExplicitConstructors_07()
        {
            var source =
@"using static System.Console;
record struct S1
{
    public S1(object o) : this() { }
    public S1() { }
}
record struct S3(char A)
{
    public S3(object o) : this() { }
    public S3() : this('a') { }
}
record struct S4(char A, char B)
{
    public S4(object o) : this() { }
    public S4() : this('a', 'b') { }
}
class Program
{
    static void Main()
    {
        WriteLine(new S1());
        WriteLine(new S1(1));
        WriteLine(new S3());
        WriteLine(new S3(3));
        WriteLine(new S4());
        WriteLine(new S4(4));
    }
}";
            var verifier = CompileAndVerify(source, expectedOutput:
@"S1 { }
S1 { }
S3 { A = a }
S3 { A = a }
S4 { A = a, B = b }
S4 { A = a, B = b }
");
            verifier.VerifyIL("S1..ctor()",
@"{
  // Code size        1 (0x1)
  .maxstack  0
  IL_0000:  ret
}");
            verifier.VerifyIL("S1..ctor(object)",
@"{
  // Code size        7 (0x7)
  .maxstack  1
  IL_0000:  ldarg.0
  IL_0001:  call       ""S1..ctor()""
  IL_0006:  ret
}");
            verifier.VerifyIL("S3..ctor()",
@"{
  // Code size        9 (0x9)
  .maxstack  2
  IL_0000:  ldarg.0
  IL_0001:  ldc.i4.s   97
  IL_0003:  call       ""S3..ctor(char)""
  IL_0008:  ret
}");
            verifier.VerifyIL("S3..ctor(object)",
@"{
  // Code size        7 (0x7)
  .maxstack  1
  IL_0000:  ldarg.0
  IL_0001:  call       ""S3..ctor()""
  IL_0006:  ret
}");
            verifier.VerifyIL("S4..ctor()",
@"{
  // Code size       11 (0xb)
  .maxstack  3
  IL_0000:  ldarg.0
  IL_0001:  ldc.i4.s   97
  IL_0003:  ldc.i4.s   98
  IL_0005:  call       ""S4..ctor(char, char)""
  IL_000a:  ret
}");
            verifier.VerifyIL("S4..ctor(object)",
@"{
  // Code size        7 (0x7)
  .maxstack  1
  IL_0000:  ldarg.0
  IL_0001:  call       ""S4..ctor()""
  IL_0006:  ret
}");
        }
 
        [Fact]
        public void ExplicitConstructors_08()
        {
            var source =
@"record struct S2()
{
    public S2(object o) : this() { }
    public S2() { }
}";
            var comp = CreateCompilation(source);
            comp.VerifyDiagnostics(
                // (3,27): error CS2121: The call is ambiguous between the following methods or properties: 'S2.S2()' and 'S2.S2()'
                //     public S2(object o) : this() { }
                Diagnostic(ErrorCode.ERR_AmbigCall, "this").WithArguments("S2.S2()", "S2.S2()").WithLocation(3, 27),
                // (4,12): error CS2111: Type 'S2' already defines a member called 'S2' with the same parameter types
                //     public S2() { }
                Diagnostic(ErrorCode.ERR_MemberAlreadyExists, "S2").WithArguments("S2", "S2").WithLocation(4, 12),
                // (4,12): error CS8862: A constructor declared in a type with parameter list must have 'this' constructor initializer.
                //     public S2() { }
                Diagnostic(ErrorCode.ERR_UnexpectedOrMissingConstructorInitializerInRecord, "S2").WithLocation(4, 12));
        }
 
        [Fact]
        public void ExplicitConstructors_09()
        {
            var source =
@"record struct S1
{
    public S1(object o) : base() { }
}
record struct S2()
{
    public S2(object o) : base() { }
}
record struct S3(char A)
{
    public S3(object o) : base() { }
}";
            var comp = CreateCompilation(source);
            comp.VerifyDiagnostics(
                // (3,12): error CS0522: 'S1': structs cannot call base class constructors
                //     public S1(object o) : base() { }
                Diagnostic(ErrorCode.ERR_StructWithBaseConstructorCall, "S1").WithArguments("S1").WithLocation(3, 12),
                // (7,12): error CS0522: 'S2': structs cannot call base class constructors
                //     public S2(object o) : base() { }
                Diagnostic(ErrorCode.ERR_StructWithBaseConstructorCall, "S2").WithArguments("S2").WithLocation(7, 12),
                // (7,27): error CS8862: A constructor declared in a type with parameter list must have 'this' constructor initializer.
                //     public S2(object o) : base() { }
                Diagnostic(ErrorCode.ERR_UnexpectedOrMissingConstructorInitializerInRecord, "base").WithLocation(7, 27),
                // (11,12): error CS0522: 'S3': structs cannot call base class constructors
                //     public S3(object o) : base() { }
                Diagnostic(ErrorCode.ERR_StructWithBaseConstructorCall, "S3").WithArguments("S3").WithLocation(11, 12),
                // (11,27): error CS8862: A constructor declared in a type with parameter list must have 'this' constructor initializer.
                //     public S3(object o) : base() { }
                Diagnostic(ErrorCode.ERR_UnexpectedOrMissingConstructorInitializerInRecord, "base").WithLocation(11, 27));
        }
 
        [Fact]
        [WorkItem(58328, "https://github.com/dotnet/roslyn/issues/58328")]
        public void ExplicitConstructors_10()
        {
            var source =
@"record struct S(object F)
{
    public object F;
    public S(int i) : this() { F = i; }
}";
            var comp = CreateCompilation(source, parseOptions: TestOptions.Regular10);
            comp.VerifyDiagnostics(
                // (1,15): error CS0171: Field 'S.F' must be fully assigned before control is returned to the caller. Consider updating to language version '11.0' to auto-default the field.
                // record struct S(object F)
                Diagnostic(ErrorCode.ERR_UnassignedThisUnsupportedVersion, "S").WithArguments("S.F", "11.0").WithLocation(1, 15),
                // (1,24): warning CS8907: Parameter 'F' is unread. Did you forget to use it to initialize the property with that name?
                // record struct S(object F)
                Diagnostic(ErrorCode.WRN_UnreadRecordParameter, "F").WithArguments("F").WithLocation(1, 24),
                // (4,23): error CS8982: A constructor declared in a 'struct' with parameter list must have a 'this' initializer that calls the primary constructor or an explicitly declared constructor.
                //     public S(int i) : this() { F = i; }
                Diagnostic(ErrorCode.ERR_RecordStructConstructorCallsDefaultConstructor, "this").WithLocation(4, 23));
 
            comp = CreateCompilation(source, parseOptions: TestOptions.Regular11);
            comp.VerifyDiagnostics(
                // (1,24): warning CS8907: Parameter 'F' is unread. Did you forget to use it to initialize the property with that name?
                // record struct S(object F)
                Diagnostic(ErrorCode.WRN_UnreadRecordParameter, "F").WithArguments("F").WithLocation(1, 24),
                // (4,23): error CS8982: A constructor declared in a 'struct' with parameter list must have a 'this' initializer that calls the primary constructor or an explicitly declared constructor.
                //     public S(int i) : this() { F = i; }
                Diagnostic(ErrorCode.ERR_RecordStructConstructorCallsDefaultConstructor, "this").WithLocation(4, 23));
        }
 
        [Fact]
        public void ExplicitConstructors_11()
        {
            var source =
@"record struct S(int X)
{
    static internal int F = 1;
    static S() : this() { }
}";
            var comp = CreateCompilation(source);
            comp.VerifyDiagnostics(
                // (4,18): error CS0514: 'S': static constructor cannot have an explicit 'this' or 'base' constructor call
                //     static S() : this() { }
                Diagnostic(ErrorCode.ERR_StaticConstructorWithExplicitConstructorCall, "this").WithArguments("S").WithLocation(4, 18));
        }
 
        [Fact]
        public void StructNamedRecord()
        {
            var source = "struct record { } ";
            var comp = CreateCompilation(source, parseOptions: TestOptions.Regular8);
            comp.VerifyDiagnostics(
                // (1,8): warning CS8981: The type name 'record' only contains lower-cased ascii characters. Such names may become reserved for the language.
                // struct record { }
                Diagnostic(ErrorCode.WRN_LowerCaseTypeName, "record").WithArguments("record").WithLocation(1, 8)
                );
 
            comp = CreateCompilation(source, parseOptions: TestOptions.Regular9);
            comp.VerifyDiagnostics(
                // (1,8): warning CS8860: Types and aliases should not be named 'record'.
                // struct record { }
                Diagnostic(ErrorCode.WRN_RecordNamedDisallowed, "record").WithLocation(1, 8)
                );
 
            comp = CreateCompilation(source, parseOptions: TestOptions.Regular10);
            comp.VerifyDiagnostics(
                // (1,8): warning CS8860: Types and aliases should not be named 'record'.
                // struct record { }
                Diagnostic(ErrorCode.WRN_RecordNamedDisallowed, "record").WithLocation(1, 8)
                );
        }
 
        [Fact]
        public void ClassNamedRecord()
        {
            var source = "class record { } ";
            var comp = CreateCompilation(source, parseOptions: TestOptions.Regular8);
            comp.VerifyDiagnostics(
                // (1,7): warning CS8981: The type name 'record' only contains lower-cased ascii characters. Such names may become reserved for the language.
                // class record { }
                Diagnostic(ErrorCode.WRN_LowerCaseTypeName, "record").WithArguments("record").WithLocation(1, 7)
                );
 
            comp = CreateCompilation(source, parseOptions: TestOptions.Regular9);
            comp.VerifyDiagnostics(
                // (1,7): warning CS8860: Types and aliases should not be named 'record'.
                // class record { }
                Diagnostic(ErrorCode.WRN_RecordNamedDisallowed, "record").WithLocation(1, 7)
                );
 
            comp = CreateCompilation(source, parseOptions: TestOptions.Regular10);
            comp.VerifyDiagnostics(
                // (1,7): warning CS8860: Types and aliases should not be named 'record'.
                // class record { }
                Diagnostic(ErrorCode.WRN_RecordNamedDisallowed, "record").WithLocation(1, 7)
                );
        }
 
        [Fact]
        public void StructNamedRecord_WithTypeParameters()
        {
            var source = "struct record<T> { } ";
            var comp = CreateCompilation(source, parseOptions: TestOptions.Regular8);
            comp.VerifyDiagnostics(
                // (1,8): warning CS8981: The type name 'record' only contains lower-cased ascii characters. Such names may become reserved for the language.
                // struct record { }
                Diagnostic(ErrorCode.WRN_LowerCaseTypeName, "record").WithArguments("record").WithLocation(1, 8)
                );
 
            comp = CreateCompilation(source, parseOptions: TestOptions.Regular9);
            comp.VerifyDiagnostics(
                // (1,8): warning CS8860: Types and aliases should not be named 'record'.
                // struct record { }
                Diagnostic(ErrorCode.WRN_RecordNamedDisallowed, "record").WithLocation(1, 8)
                );
 
            comp = CreateCompilation(source, parseOptions: TestOptions.Regular10);
            comp.VerifyDiagnostics(
                // (1,8): warning CS8860: Types and aliases should not be named 'record'.
                // struct record<T> { }
                Diagnostic(ErrorCode.WRN_RecordNamedDisallowed, "record").WithLocation(1, 8)
                );
        }
 
        [Fact]
        public void ClassNamedRecord_WithTypeParameters()
        {
            var source = "class record<T> { } ";
            var comp = CreateCompilation(source, parseOptions: TestOptions.Regular8);
            comp.VerifyDiagnostics(
                // (1,7): warning CS8981: The type name 'record' only contains lower-cased ascii characters. Such names may become reserved for the language.
                // class record<T> { }
                Diagnostic(ErrorCode.WRN_LowerCaseTypeName, "record").WithArguments("record").WithLocation(1, 7)
                );
 
            comp = CreateCompilation(source, parseOptions: TestOptions.Regular9);
            comp.VerifyDiagnostics(
                // (1,7): warning CS8860: Types and aliases should not be named 'record'.
                // class record<T> { }
                Diagnostic(ErrorCode.WRN_RecordNamedDisallowed, "record").WithLocation(1, 7)
                );
 
            comp = CreateCompilation(source, parseOptions: TestOptions.Regular10);
            comp.VerifyDiagnostics(
                // (1,7): warning CS8860: Types and aliases should not be named 'record'.
                // class record<T> { }
                Diagnostic(ErrorCode.WRN_RecordNamedDisallowed, "record").WithLocation(1, 7)
                );
        }
 
        [Fact]
        public void StructNamedRecord_WithBaseList()
        {
            var source = @"
interface I { }
struct record : I { }
";
            var comp = CreateCompilation(source, parseOptions: TestOptions.Regular8);
            comp.VerifyDiagnostics(
                // (3,8): warning CS8981: The type name 'record' only contains lower-cased ascii characters. Such names may become reserved for the language.
                // struct record : I { }
                Diagnostic(ErrorCode.WRN_LowerCaseTypeName, "record").WithArguments("record").WithLocation(3, 8)
                );
 
            comp = CreateCompilation(source, parseOptions: TestOptions.Regular9);
            comp.VerifyDiagnostics(
                // (3,8): warning CS8860: Types and aliases should not be named 'record'.
                // struct record : I { }
                Diagnostic(ErrorCode.WRN_RecordNamedDisallowed, "record").WithLocation(3, 8)
                );
 
            comp = CreateCompilation(source, parseOptions: TestOptions.Regular10);
            comp.VerifyDiagnostics(
                // (3,8): warning CS8860: Types and aliases should not be named 'record'.
                // struct record : I { }
                Diagnostic(ErrorCode.WRN_RecordNamedDisallowed, "record").WithLocation(3, 8)
                );
        }
 
        [Fact]
        public void StructNamedRecord_WithBaseList_Generic()
        {
            var source = @"
interface I { }
struct record<T> : I { }
";
            var comp = CreateCompilation(source, parseOptions: TestOptions.Regular8);
            comp.VerifyDiagnostics(
                // (3,8): warning CS8981: The type name 'record' only contains lower-cased ascii characters. Such names may become reserved for the language.
                // struct record<T> : I { }
                Diagnostic(ErrorCode.WRN_LowerCaseTypeName, "record").WithArguments("record").WithLocation(3, 8)
                );
 
            comp = CreateCompilation(source, parseOptions: TestOptions.Regular9);
            comp.VerifyDiagnostics(
                // (3,8): warning CS8860: Types and aliases should not be named 'record'.
                // struct record<T> : I { }
                Diagnostic(ErrorCode.WRN_RecordNamedDisallowed, "record").WithLocation(3, 8)
                );
 
            comp = CreateCompilation(source, parseOptions: TestOptions.Regular10);
            comp.VerifyDiagnostics(
                // (3,8): warning CS8860: Types and aliases should not be named 'record'.
                // struct record<T> : I { }
                Diagnostic(ErrorCode.WRN_RecordNamedDisallowed, "record").WithLocation(3, 8)
                );
        }
 
        [Fact]
        public void ClassNamedRecord_WithBaseList_Generic()
        {
            var source = @"
interface I { }
class record<T> : I { }
";
            var comp = CreateCompilation(source, parseOptions: TestOptions.Regular8);
            comp.VerifyDiagnostics(
                // (3,7): warning CS8981: The type name 'record' only contains lower-cased ascii characters. Such names may become reserved for the language.
                // class record<T> : I { }
                Diagnostic(ErrorCode.WRN_LowerCaseTypeName, "record").WithArguments("record").WithLocation(3, 7)
                );
 
            comp = CreateCompilation(source, parseOptions: TestOptions.Regular9);
            comp.VerifyDiagnostics(
                // (3,7): warning CS8860: Types and aliases should not be named 'record'.
                // class record<T> : I { }
                Diagnostic(ErrorCode.WRN_RecordNamedDisallowed, "record").WithLocation(3, 7)
                );
 
            comp = CreateCompilation(source, parseOptions: TestOptions.Regular10);
            comp.VerifyDiagnostics(
                // (3,7): warning CS8860: Types and aliases should not be named 'record'.
                // class record<T> : I { }
                Diagnostic(ErrorCode.WRN_RecordNamedDisallowed, "record").WithLocation(3, 7)
                );
        }
 
        [Fact]
        [WorkItem(64238, "https://github.com/dotnet/roslyn/issues/64238")]
        public void NoMethodBodiesInComImportType()
        {
            var source1 =
@"
[System.Runtime.InteropServices.ComImport]
[System.Runtime.InteropServices.Guid(""00112233-4455-6677-8899-aabbccddeeff"")]
record struct R1(int x);
";
            var compilation1 = CreateCompilation(source1, options: TestOptions.DebugDll, targetFramework: TargetFramework.Net60);
 
            compilation1.VerifyDiagnostics(
                // (2,2): error CS0592: Attribute 'System.Runtime.InteropServices.ComImport' is not valid on this declaration type. It is only valid on 'class, interface' declarations.
                // [System.Runtime.InteropServices.ComImport]
                Diagnostic(ErrorCode.ERR_AttributeOnBadSymbolType, "System.Runtime.InteropServices.ComImport").WithArguments("System.Runtime.InteropServices.ComImport", "class, interface").WithLocation(2, 2)
                );
        }
    }
}