diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/RecordTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/RecordTests.cs index acc856ef2f1adaf3518fa1fc9ff8dc3eddad79c0..842a083cee9235d5f860d6b53396db5209b4d734 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/RecordTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/RecordTests.cs @@ -3689,1426 +3689,1426 @@ .maxstack 3 }"); } - [Theory, WorkItem(44902, "https://github.com/dotnet/roslyn/issues/44902")] - [InlineData(false)] - [InlineData(true)] - public void CopyCtor(bool useCompilationReference) + [Fact] + public void Inheritance_22() { - var sourceA = -@"public record B(object N1, object N2) + var source = +@"record A { -}"; - var compA = CreateCompilation(sourceA); - var verifierA = CompileAndVerify(compA, verify: ExecutionConditionUtil.IsCoreClr ? Verification.Skipped : Verification.Fails); - - verifierA.VerifyIL("B..ctor(B)", @" + public ref object P1 => throw null; + public object P2 => throw null; +} +record B : A { - // Code size 31 (0x1f) - .maxstack 2 - IL_0000: ldarg.0 - IL_0001: call ""object..ctor()"" - IL_0006: ldarg.0 - IL_0007: ldarg.1 - IL_0008: ldfld ""object B.k__BackingField"" - IL_000d: stfld ""object B.k__BackingField"" - IL_0012: ldarg.0 - IL_0013: ldarg.1 - IL_0014: ldfld ""object B.k__BackingField"" - IL_0019: stfld ""object B.k__BackingField"" - IL_001e: ret -}"); - - var refA = useCompilationReference ? compA.ToMetadataReference() : compA.EmitToImageReference(); - - var sourceB = -@"record C(object P1, object P2) : B(3, 4) + public new object P1 => throw null; + public new ref object P2 => throw null; +} +record C(object P1, object P2) : B { - static void Main() - { - var c1 = new C(1, 2); - System.Console.Write((c1.P1, c1.P2, c1.N1, c1.N2)); - System.Console.Write("" ""); - - var c2 = new C(c1); - System.Console.Write((c2.P1, c2.P2, c2.N1, c2.N2)); - System.Console.Write("" ""); - - var c3 = c1 with { P1 = 10, N1 = 30 }; - System.Console.Write((c3.P1, c3.P2, c3.N1, c3.N2)); - } }"; - var compB = CreateCompilation(sourceB, references: new[] { refA }, parseOptions: TestOptions.RegularPreview, options: TestOptions.ReleaseExe); - compB.VerifyDiagnostics(); - - var verifierB = CompileAndVerify(compB, expectedOutput: "(1, 2, 3, 4) (1, 2, 3, 4) (10, 2, 30, 4)", verify: ExecutionConditionUtil.IsCoreClr ? Verification.Skipped : Verification.Fails); - // call base copy constructor B..ctor(B) - verifierB.VerifyIL("C..ctor(C)", @" -{ - // Code size 32 (0x20) - .maxstack 2 - IL_0000: ldarg.0 - IL_0001: ldarg.1 - IL_0002: call ""B..ctor(B)"" - IL_0007: ldarg.0 - IL_0008: ldarg.1 - IL_0009: ldfld ""object C.k__BackingField"" - IL_000e: stfld ""object C.k__BackingField"" - IL_0013: ldarg.0 - IL_0014: ldarg.1 - IL_0015: ldfld ""object C.k__BackingField"" - IL_001a: stfld ""object C.k__BackingField"" - IL_001f: ret -}"); + var comp = CreateCompilation(source); + comp.VerifyDiagnostics(); + var actualMembers = GetProperties(comp, "C").ToTestDisplayStrings(); + AssertEx.Equal(new[] { "System.Type C.EqualityContract { get; }" }, actualMembers); } - [Fact, WorkItem(44902, "https://github.com/dotnet/roslyn/issues/44902")] - public void CopyCtor_WithOtherOverload() + [Fact] + public void Inheritance_23() { var source = -@"public record B(object N1, object N2) +@"record A { - public B(C c) : this(30, 40) => throw null; + public static object P1 { get; } + public object P2 { get; } } -public record C(object P1, object P2) : B(3, 4) +record B : A { - static void Main() - { - var c1 = new C(1, 2); - System.Console.Write((c1.P1, c1.P2, c1.N1, c1.N2)); - System.Console.Write("" ""); - - var c2 = c1 with { P1 = 10, P2 = 20, N1 = 30, N2 = 40 }; - System.Console.Write((c2.P1, c2.P2, c2.N1, c2.N2)); - } -}"; - var comp = CreateCompilation(new[] { source, IsExternalInitTypeDefinition }, parseOptions: TestOptions.RegularPreview, options: TestOptions.ReleaseExe); - comp.VerifyDiagnostics(); - - var verifier = CompileAndVerify(comp, expectedOutput: "(1, 2, 3, 4) (10, 20, 30, 40)", verify: ExecutionConditionUtil.IsCoreClr ? Verification.Skipped : Verification.Fails); - // call base copy constructor B..ctor(B) - verifier.VerifyIL("C..ctor(C)", @" + public new object P1 { get; } + public new static object P2 { get; } +} +record C(object P1, object P2) : B { - // Code size 32 (0x20) - .maxstack 2 - IL_0000: ldarg.0 - IL_0001: ldarg.1 - IL_0002: call ""B..ctor(B)"" - IL_0007: ldarg.0 - IL_0008: ldarg.1 - IL_0009: ldfld ""object C.k__BackingField"" - IL_000e: stfld ""object C.k__BackingField"" - IL_0013: ldarg.0 - IL_0014: ldarg.1 - IL_0015: ldfld ""object C.k__BackingField"" - IL_001a: stfld ""object C.k__BackingField"" - IL_001f: ret -}"); +}"; + var comp = CreateCompilation(source); + comp.VerifyDiagnostics( + // (11,28): error CS8866: Record member 'B.P2' must be a readable instance property of type 'object' to match positional parameter 'P2'. + // record C(object P1, object P2) : B + Diagnostic(ErrorCode.ERR_BadRecordMemberForPositionalParameter, "P2").WithArguments("B.P2", "object", "P2").WithLocation(11, 28)); + var actualMembers = GetProperties(comp, "C").ToTestDisplayStrings(); + AssertEx.Equal(new[] { "System.Type C.EqualityContract { get; }" }, actualMembers); } - [Fact, WorkItem(44902, "https://github.com/dotnet/roslyn/issues/44902")] - public void CopyCtor_WithObsoleteCopyConstructor() + [Fact] + public void Inheritance_24() { var source = -@"public record B(object N1, object N2) +@"record A { - [System.Obsolete(""Obsolete"", true)] - public B(B b) { } + public object get_P() => null; + public object set_Q() => null; } -public record C(object P1, object P2) : B(3, 4) { } -"; - var comp = CreateCompilation(new[] { source, IsExternalInitTypeDefinition }, parseOptions: TestOptions.RegularPreview); - comp.VerifyDiagnostics(); - } - - [Fact, WorkItem(44902, "https://github.com/dotnet/roslyn/issues/44902")] - public void CopyCtor_WithParamsCopyConstructor() - { - var source = -@"public record B(object N1, object N2) +record B(object P, object Q) : A { - public B(B b, params int[] i) : this(30, 40) { } } -public record C(object P1, object P2) : B(3, 4) { } -"; +record C(object P) +{ + public object get_P() => null; + public object set_Q() => null; +}"; var comp = CreateCompilation(source); - comp.VerifyDiagnostics(); + comp.VerifyDiagnostics( + // (9,17): error CS0082: Type 'C' already reserves a member called 'get_P' with the same parameter types + // record C(object P) + Diagnostic(ErrorCode.ERR_MemberReserved, "P").WithArguments("get_P", "C").WithLocation(9, 17)); - var actualMembers = comp.GetMember("B").GetMembers().Where(m => m.Name == ".ctor").ToTestDisplayStrings(); var expectedMembers = new[] { - "B..ctor(System.Object N1, System.Object N2)", - "B..ctor(B b, params System.Int32[] i)", - "B..ctor(B )" + "A B.<>Clone()", + "System.Type B.EqualityContract.get", + "System.Type B.EqualityContract { get; }", + "B..ctor(System.Object P, System.Object Q)", + "System.Object B.

k__BackingField", + "System.Object B.P.get", + "void modreq(System.Runtime.CompilerServices.IsExternalInit) B.P.init", + "System.Object B.P { get; init; }", + "System.Object B.k__BackingField", + "System.Object B.Q.get", + "void modreq(System.Runtime.CompilerServices.IsExternalInit) B.Q.init", + "System.Object B.Q { get; init; }", + "System.Int32 B.GetHashCode()", + "System.Boolean B.Equals(System.Object? )", + "System.Boolean B.Equals(A? )", + "System.Boolean B.Equals(B? )", + "B..ctor(B )", + "void B.Deconstruct(out System.Object P, out System.Object Q)" }; - AssertEx.Equal(expectedMembers, actualMembers); + AssertEx.Equal(expectedMembers, comp.GetMember("B").GetMembers().ToTestDisplayStrings()); - var verifier = CompileAndVerify(comp, verify: ExecutionConditionUtil.IsCoreClr ? Verification.Skipped : Verification.Fails); - verifier.VerifyIL("C..ctor(C)", @" -{ - // Code size 32 (0x20) - .maxstack 2 - IL_0000: ldarg.0 - IL_0001: ldarg.1 - IL_0002: call ""B..ctor(B)"" - IL_0007: ldarg.0 - IL_0008: ldarg.1 - IL_0009: ldfld ""object C.k__BackingField"" - IL_000e: stfld ""object C.k__BackingField"" - IL_0013: ldarg.0 - IL_0014: ldarg.1 - IL_0015: ldfld ""object C.k__BackingField"" - IL_001a: stfld ""object C.k__BackingField"" - IL_001f: ret -} -"); + expectedMembers = new[] + { + "C C.<>Clone()", + "System.Type C.EqualityContract.get", + "System.Type C.EqualityContract { get; }", + "C..ctor(System.Object P)", + "System.Object C.

k__BackingField", + "System.Object C.P.get", + "void modreq(System.Runtime.CompilerServices.IsExternalInit) C.P.init", + "System.Object C.P { get; init; }", + "System.Object C.get_P()", + "System.Object C.set_Q()", + "System.Int32 C.GetHashCode()", + "System.Boolean C.Equals(System.Object? )", + "System.Boolean C.Equals(C? )", + "C..ctor(C )", + "void C.Deconstruct(out System.Object P)" + }; + AssertEx.Equal(expectedMembers, comp.GetMember("C").GetMembers().ToTestDisplayStrings()); } - [Fact, WorkItem(44902, "https://github.com/dotnet/roslyn/issues/44902")] - public void CopyCtor_WithInitializers() + [Fact] + public void Inheritance_25() { - var source = -@"public record C(object N1, object N2) + var sourceA = +@"public record A { - private int field = 42; - public int Property = 43; + public class P1 { } + internal object P2 = 2; + public int P3(object o) => 3; + internal int P4(T t) => 4; }"; - var comp = CreateCompilation(source); - comp.VerifyDiagnostics(); - - var verifier = CompileAndVerify(comp, verify: ExecutionConditionUtil.IsCoreClr ? Verification.Skipped : Verification.Fails); - verifier.VerifyIL("C..ctor(C)", @" + var sourceB = +@"record B(object P1, object P2, object P3, object P4) : A { - // Code size 55 (0x37) - .maxstack 2 - IL_0000: ldarg.0 - IL_0001: call ""object..ctor()"" - IL_0006: ldarg.0 - IL_0007: ldarg.1 - IL_0008: ldfld ""object C.k__BackingField"" - IL_000d: stfld ""object C.k__BackingField"" - IL_0012: ldarg.0 - IL_0013: ldarg.1 - IL_0014: ldfld ""object C.k__BackingField"" - IL_0019: stfld ""object C.k__BackingField"" - IL_001e: ldarg.0 - IL_001f: ldarg.1 - IL_0020: ldfld ""int C.field"" - IL_0025: stfld ""int C.field"" - IL_002a: ldarg.0 - IL_002b: ldarg.1 - IL_002c: ldfld ""int C.Property"" - IL_0031: stfld ""int C.Property"" - IL_0036: ret -}"); +}"; + var comp = CreateCompilation(new[] { sourceA, sourceB }); + comp.VerifyDiagnostics( + // (1,17): error CS8866: Record member 'A.P1' must be a readable instance property of type 'object' to match positional parameter 'P1'. + // record B(object P1, object P2, object P3, object P4) : A + Diagnostic(ErrorCode.ERR_BadRecordMemberForPositionalParameter, "P1").WithArguments("A.P1", "object", "P1").WithLocation(1, 17), + // (1,28): error CS8866: Record member 'A.P2' must be a readable instance property of type 'object' to match positional parameter 'P2'. + // record B(object P1, object P2, object P3, object P4) : A + Diagnostic(ErrorCode.ERR_BadRecordMemberForPositionalParameter, "P2").WithArguments("A.P2", "object", "P2").WithLocation(1, 28), + // (1,39): error CS8866: Record member 'A.P3' must be a readable instance property of type 'object' to match positional parameter 'P3'. + // record B(object P1, object P2, object P3, object P4) : A + Diagnostic(ErrorCode.ERR_BadRecordMemberForPositionalParameter, "P3").WithArguments("A.P3", "object", "P3").WithLocation(1, 39)); + var actualMembers = GetProperties(comp, "B").ToTestDisplayStrings(); + var expectedMembers = new[] + { + "System.Type B.EqualityContract { get; }", + "System.Object B.P4 { get; init; }", + }; + AssertEx.Equal(expectedMembers, actualMembers); + + comp = CreateCompilation(sourceA); + var refA = comp.EmitToImageReference(); + comp = CreateCompilation(sourceB, references: new[] { refA }, parseOptions: TestOptions.RegularPreview); + comp.VerifyDiagnostics( + // (1,17): error CS8866: Record member 'A.P1' must be a readable instance property of type 'object' to match positional parameter 'P1'. + // record B(object P1, object P2, object P3, object P4) : A + Diagnostic(ErrorCode.ERR_BadRecordMemberForPositionalParameter, "P1").WithArguments("A.P1", "object", "P1").WithLocation(1, 17), + // (1,39): error CS8866: Record member 'A.P3' must be a readable instance property of type 'object' to match positional parameter 'P3'. + // record B(object P1, object P2, object P3, object P4) : A + Diagnostic(ErrorCode.ERR_BadRecordMemberForPositionalParameter, "P3").WithArguments("A.P3", "object", "P3").WithLocation(1, 39)); + actualMembers = GetProperties(comp, "B").ToTestDisplayStrings(); + expectedMembers = new[] + { + "System.Type B.EqualityContract { get; }", + "System.Object B.P2 { get; init; }", + "System.Object B.P4 { get; init; }", + }; + AssertEx.Equal(expectedMembers, actualMembers); } - [Fact, WorkItem(44902, "https://github.com/dotnet/roslyn/issues/44902")] - public void CopyCtor_UserDefinedButDoesNotDelegateToBaseCopyCtor() + [Fact] + public void Inheritance_26() { - var source = -@"public record B(object N1, object N2) + var sourceA = +@"public record A { -} -public record C(object P1, object P2) : B(0, 1) + internal const int P = 4; +}"; + var sourceB = +@"record B(object P) : A { - public C(C c) // 1, 2 - { - } -} -"; - var comp = CreateCompilation(source); +}"; + var comp = CreateCompilation(new[] { sourceA, sourceB }); comp.VerifyDiagnostics( - // (6,12): error CS1729: 'B' does not contain a constructor that takes 0 arguments - // public C(C c) // 1, 2 - Diagnostic(ErrorCode.ERR_BadCtorArgCount, "C").WithArguments("B", "0").WithLocation(6, 12), - // (6,12): error CS8868: A copy constructor in a record must call a copy constructor of the base, or a parameterless object constructor if the record inherits from object. - // public C(C c) // 1, 2 - Diagnostic(ErrorCode.ERR_CopyConstructorMustInvokeBaseCopyConstructor, "C").WithLocation(6, 12) - ); + // (1,17): error CS8866: Record member 'A.P' must be a readable instance property of type 'object' to match positional parameter 'P'. + // record B(object P) : A + Diagnostic(ErrorCode.ERR_BadRecordMemberForPositionalParameter, "P").WithArguments("A.P", "object", "P").WithLocation(1, 17)); + AssertEx.Equal(new[] { "System.Type B.EqualityContract { get; }" }, GetProperties(comp, "B").ToTestDisplayStrings()); + + comp = CreateCompilation(sourceA); + var refA = comp.EmitToImageReference(); + comp = CreateCompilation(sourceB, references: new[] { refA }, parseOptions: TestOptions.RegularPreview); + comp.VerifyDiagnostics(); + AssertEx.Equal(new[] { "System.Type B.EqualityContract { get; }", "System.Object B.P { get; init; }" }, GetProperties(comp, "B").ToTestDisplayStrings()); } - [Fact, WorkItem(44902, "https://github.com/dotnet/roslyn/issues/44902")] - public void CopyCtor_UserDefinedButDoesNotDelegateToBaseCopyCtor_DerivesFromObject() + [Fact] + public void Inheritance_27() { var source = -@"public record C(int I) +@"record A { - public int I { get; set; } = 42; - public C(C c) - { - } - public static void Main() - { - var c = new C(1); - c.I = 2; - var c2 = new C(c); - System.Console.Write((c.I, c2.I)); - } + public object P { get; } + public object Q { get; set; } } -"; - var comp = CreateCompilation(new[] { source, IsExternalInitTypeDefinition }, parseOptions: TestOptions.RegularPreview, options: TestOptions.DebugExe); - comp.VerifyDiagnostics(); - var verifier = CompileAndVerify(comp, expectedOutput: "(2, 0)"); - verifier.VerifyIL("C..ctor(C)", @" +record B(object get_P, object set_Q) : A { - // Code size 9 (0x9) - .maxstack 1 - IL_0000: ldarg.0 - IL_0001: call ""object..ctor()"" - IL_0006: nop - IL_0007: nop - IL_0008: ret -} -"); +}"; + var comp = CreateCompilation(source); + comp.VerifyDiagnostics(); + var actualMembers = GetProperties(comp, "B").ToTestDisplayStrings(); + var expectedMembers = new[] + { + "System.Type B.EqualityContract { get; }", + "System.Object B.get_P { get; init; }", + "System.Object B.set_Q { get; init; }", + }; + AssertEx.Equal(expectedMembers, actualMembers); } - [Fact, WorkItem(44902, "https://github.com/dotnet/roslyn/issues/44902")] - public void CopyCtor_UserDefinedButDoesNotDelegateToBaseCopyCtor_DerivesFromObject_WithFieldInitializer() + [Fact] + public void Inheritance_28() { var source = -@"public record C(int I) +@"interface I { - public int I { get; set; } = 42; - public int field = 43; - public C(C c) - { - System.Console.Write("" RAN ""); - } - public static void Main() - { - var c = new C(1); - c.I = 2; - c.field = 100; - System.Console.Write((c.I, c.field)); - - var c2 = new C(c); - System.Console.Write((c2.I, c2.field)); - } + object P { get; } } -"; - var comp = CreateCompilation(new[] { source, IsExternalInitTypeDefinition }, parseOptions: TestOptions.RegularPreview, options: TestOptions.DebugExe); - comp.VerifyDiagnostics(); - var verifier = CompileAndVerify(comp, expectedOutput: "(2, 100) RAN (0, 0)"); - verifier.VerifyIL("C..ctor(C)", @" +record A : I { - // Code size 20 (0x14) - .maxstack 1 - IL_0000: ldarg.0 - IL_0001: call ""object..ctor()"" - IL_0006: nop - IL_0007: nop - IL_0008: ldstr "" RAN "" - IL_000d: call ""void System.Console.Write(string)"" - IL_0012: nop - IL_0013: ret + object I.P => null; } -"); - } - - [Fact, WorkItem(44902, "https://github.com/dotnet/roslyn/issues/44902")] - public void CopyCtor_DerivesFromObject_GivesParameterToBase() - { - var source = @" -public record C(object I) +record B(object P) : A { - public C(C c) : base(1) { } } -"; +record C(object P) : I +{ + object I.P => null; +}"; var comp = CreateCompilation(source); - comp.VerifyDiagnostics( - // (4,21): error CS1729: 'object' does not contain a constructor that takes 1 arguments - // public C(C c) : base(1) { } - Diagnostic(ErrorCode.ERR_BadCtorArgCount, "base").WithArguments("object", "1").WithLocation(4, 21), - // (4,21): error CS8868: A copy constructor in a record must call a copy constructor of the base, or a parameterless object constructor if the record inherits from object. - // public C(C c) : base(1) { } - Diagnostic(ErrorCode.ERR_CopyConstructorMustInvokeBaseCopyConstructor, "base").WithLocation(4, 21) - ); + comp.VerifyDiagnostics(); + AssertEx.Equal(new[] { "System.Type B.EqualityContract { get; }", "System.Object B.P { get; init; }" }, GetProperties(comp, "B").ToTestDisplayStrings()); + AssertEx.Equal(new[] { "System.Type C.EqualityContract { get; }", "System.Object C.P { get; init; }", "System.Object C.I.P { get; }" }, GetProperties(comp, "C").ToTestDisplayStrings()); } - [Fact, WorkItem(44902, "https://github.com/dotnet/roslyn/issues/44902")] - public void CopyCtor_DerivesFromObject_WithSomeOtherConstructor() + [Fact] + public void Inheritance_29() { - var source = @" -public record C(object I) -{ - public C(int i) : this((object)null) { } - public static void Main() - { - var c = new C((object)null); - var c2 = new C(1); - var c3 = new C(c); - System.Console.Write(""RAN""); - } -} + var sourceA = +@"Public Class A + Public Property P(o As Object) As Object + Get + Return Nothing + End Get + Set + End Set + End Property + Public Property Q(x As Object, y As Object) As Object + Get + Return Nothing + End Get + Set + End Set + End Property +End Class "; - var comp = CreateCompilation(new[] { source, IsExternalInitTypeDefinition }, parseOptions: TestOptions.RegularPreview, options: TestOptions.DebugExe); - comp.VerifyDiagnostics(); - var verifier = CompileAndVerify(comp, expectedOutput: "RAN", verify: ExecutionConditionUtil.IsCoreClr ? Verification.Skipped : Verification.Fails); - verifier.VerifyIL("C..ctor(int)", @" + var compA = CreateVisualBasicCompilation(sourceA); + compA.VerifyDiagnostics(); + var refA = compA.EmitToImageReference(); + + var sourceB = +@"record B(object P, object Q) : A { - // Code size 10 (0xa) - .maxstack 2 - IL_0000: ldarg.0 - IL_0001: ldnull - IL_0002: call ""C..ctor(object)"" - IL_0007: nop - IL_0008: nop - IL_0009: ret -} -"); + object P { get; } +}"; + var compB = CreateCompilation(new[] { sourceB, IsExternalInitTypeDefinition }, references: new[] { refA }, parseOptions: TestOptions.RegularPreview); + compB.VerifyDiagnostics( + // (1,8): error CS8867: No accessible copy constructor found in base type 'A'. + // record B(object P, object Q) : A + Diagnostic(ErrorCode.ERR_NoCopyConstructorInBaseType, "B").WithArguments("A").WithLocation(1, 8), + // (1,32): error CS8864: Records may only inherit from object or another record + // record B(object P, object Q) : A + Diagnostic(ErrorCode.ERR_BadRecordBase, "A").WithLocation(1, 32) + ); + + var actualMembers = GetProperties(compB, "B").ToTestDisplayStrings(); + var expectedMembers = new[] + { + "System.Type B.EqualityContract { get; }", + "System.Object B.Q { get; init; }", + "System.Object B.P { get; }", + }; + AssertEx.Equal(expectedMembers, actualMembers); } - [Fact, WorkItem(44902, "https://github.com/dotnet/roslyn/issues/44902")] - public void CopyCtor_UserDefinedButDoesNotDelegateToBaseCopyCtor_DerivesFromObject_UsesThis() + [Fact] + public void Inheritance_30() { - var source = -@"public record C(int I) -{ - public C(C c) : this(c.I) - { - } -} + var sourceA = +@"Public Class A + Public ReadOnly Overloads Property P() As Object + Get + Return Nothing + End Get + End Property + Public ReadOnly Overloads Property P(o As Object) As Object + Get + Return Nothing + End Get + End Property + Public Overloads Property Q(o As Object) As Object + Get + Return Nothing + End Get + Set + End Set + End Property + Public Overloads Property Q() As Object + Get + Return Nothing + End Get + Set + End Set + End Property +End Class "; - var comp = CreateCompilation(source); - comp.VerifyDiagnostics( - // (3,21): error CS8868: A copy constructor in a record must call a copy constructor of the base, or a parameterless object constructor if the record inherits from object. - // public C(C c) : this(c.I) - Diagnostic(ErrorCode.ERR_CopyConstructorMustInvokeBaseCopyConstructor, "this").WithLocation(3, 21) - ); + var compA = CreateVisualBasicCompilation(sourceA); + compA.VerifyDiagnostics(); + var refA = compA.EmitToImageReference(); + + var sourceB = +@"record B(object P, object Q) : A +{ +}"; + var compB = CreateCompilation(new[] { sourceB, IsExternalInitTypeDefinition }, references: new[] { refA }, parseOptions: TestOptions.RegularPreview); + compB.VerifyDiagnostics( + // (1,8): error CS8867: No accessible copy constructor found in base type 'A'. + // record B(object P, object Q) : A + Diagnostic(ErrorCode.ERR_NoCopyConstructorInBaseType, "B").WithArguments("A").WithLocation(1, 8), + // (1,32): error CS8864: Records may only inherit from object or another record + // record B(object P, object Q) : A + Diagnostic(ErrorCode.ERR_BadRecordBase, "A").WithLocation(1, 32) + ); + + var actualMembers = GetProperties(compB, "B").ToTestDisplayStrings(); + AssertEx.Equal(new[] { "System.Type B.EqualityContract { get; }" }, actualMembers); } - [Fact, WorkItem(44902, "https://github.com/dotnet/roslyn/issues/44902")] - public void CopyCtor_UserDefined_DerivesFromObject_UsesBase() + [Fact] + public void Inheritance_31() { - var source = -@"public record C(int I) -{ - public C(C c) : base() - { - System.Console.Write(""RAN ""); - } - public static void Main() - { - var c = new C(1); - System.Console.Write(c.I); - System.Console.Write("" ""); - var c2 = c with { I = 2 }; - System.Console.Write(c2.I); - } -} + var sourceA = +@"Public Class A + Public ReadOnly Property P() As Object + Get + Return Nothing + End Get + End Property + Public Property Q(o As Object) As Object + Get + Return Nothing + End Get + Set + End Set + End Property + Public Property R(o As Object) As Object + Get + Return Nothing + End Get + Set + End Set + End Property + Public Sub New(a as A) + End Sub +End Class +Public Class B + Inherits A + Public ReadOnly Overloads Property P(o As Object) As Object + Get + Return Nothing + End Get + End Property + Public Overloads Property Q() As Object + Get + Return Nothing + End Get + Set + End Set + End Property + Public Overloads Property R(x As Object, y As Object) As Object + Get + Return Nothing + End Get + Set + End Set + End Property + Public Sub New(b as B) + MyBase.New(b) + End Sub +End Class "; - var comp = CreateCompilation(new[] { source, IsExternalInitTypeDefinition }, parseOptions: TestOptions.RegularPreview, options: TestOptions.DebugExe); - comp.VerifyDiagnostics(); - var verifier = CompileAndVerify(comp, expectedOutput: "1 RAN 2", verify: ExecutionConditionUtil.IsCoreClr ? Verification.Skipped : Verification.Fails); - verifier.VerifyIL("C..ctor(C)", @" + var compA = CreateVisualBasicCompilation(sourceA); + compA.VerifyDiagnostics(); + var refA = compA.EmitToImageReference(); + + var sourceB = +@"record C(object P, object Q, object R) : B { - // Code size 20 (0x14) - .maxstack 1 - IL_0000: ldarg.0 - IL_0001: call ""object..ctor()"" - IL_0006: nop - IL_0007: nop - IL_0008: ldstr ""RAN "" - IL_000d: call ""void System.Console.Write(string)"" - IL_0012: nop - IL_0013: ret -} -"); +}"; + var compB = CreateCompilation(new[] { sourceB, IsExternalInitTypeDefinition }, references: new[] { refA }, parseOptions: TestOptions.RegularPreview); + compB.VerifyDiagnostics( + // (1,9): error CS7036: There is no argument given that corresponds to the required formal parameter 'b' of 'B.B(B)' + // record C(object P, object Q, object R) : B + Diagnostic(ErrorCode.ERR_NoCorrespondingArgument, "(object P, object Q, object R)").WithArguments("b", "B.B(B)").WithLocation(1, 9), + // (1,42): error CS8864: Records may only inherit from object or another record + // record C(object P, object Q, object R) : B + Diagnostic(ErrorCode.ERR_BadRecordBase, "B").WithLocation(1, 42) + ); + + var actualMembers = GetProperties(compB, "C").ToTestDisplayStrings(); + var expectedMembers = new[] + { + "System.Type C.EqualityContract { get; }", + "System.Object C.R { get; init; }", + }; + AssertEx.Equal(expectedMembers, actualMembers); } - [Fact, WorkItem(44902, "https://github.com/dotnet/roslyn/issues/44902")] - public void CopyCtor_UserDefinedButDoesNotDelegateToBaseCopyCtor_NoPositionalMembers() + [Theory, WorkItem(44902, "https://github.com/dotnet/roslyn/issues/44902")] + [InlineData(false)] + [InlineData(true)] + public void CopyCtor(bool useCompilationReference) { - var source = + var sourceA = @"public record B(object N1, object N2) { -} -public record C(object P1) : B(0, 1) -{ - public C(C c) // 1, 2 - { - } -} -"; - var comp = CreateCompilation(source); - comp.VerifyDiagnostics( - // (6,12): error CS1729: 'B' does not contain a constructor that takes 0 arguments - // public C(C c) // 1, 2 - Diagnostic(ErrorCode.ERR_BadCtorArgCount, "C").WithArguments("B", "0").WithLocation(6, 12), - // (6,12): error CS8868: A copy constructor in a record must call a copy constructor of the base, or a parameterless object constructor if the record inherits from object. - // public C(C c) // 1, 2 - Diagnostic(ErrorCode.ERR_CopyConstructorMustInvokeBaseCopyConstructor, "C").WithLocation(6, 12) - ); - } +}"; + var compA = CreateCompilation(sourceA); + var verifierA = CompileAndVerify(compA, verify: ExecutionConditionUtil.IsCoreClr ? Verification.Skipped : Verification.Fails); - [Fact, WorkItem(44902, "https://github.com/dotnet/roslyn/issues/44902")] - public void CopyCtor_UserDefinedButDoesNotDelegateToBaseCopyCtor_UsesThis() - { - var source = -@"public record B(object N1, object N2) + verifierA.VerifyIL("B..ctor(B)", @" { -} -public record C(object P1, object P2) : B(0, 1) + // Code size 31 (0x1f) + .maxstack 2 + IL_0000: ldarg.0 + IL_0001: call ""object..ctor()"" + IL_0006: ldarg.0 + IL_0007: ldarg.1 + IL_0008: ldfld ""object B.k__BackingField"" + IL_000d: stfld ""object B.k__BackingField"" + IL_0012: ldarg.0 + IL_0013: ldarg.1 + IL_0014: ldfld ""object B.k__BackingField"" + IL_0019: stfld ""object B.k__BackingField"" + IL_001e: ret +}"); + + var refA = useCompilationReference ? compA.ToMetadataReference() : compA.EmitToImageReference(); + + var sourceB = +@"record C(object P1, object P2) : B(3, 4) { - public C(C c) : this(1, 2) // 1 + static void Main() { - } -} -"; - var comp = CreateCompilation(source); - comp.VerifyDiagnostics( - // (6,21): error CS8868: A copy constructor in a record must call a copy constructor of the base, or a parameterless object constructor if the record inherits from object. - // public C(C c) : this(1, 2) // 1 - Diagnostic(ErrorCode.ERR_CopyConstructorMustInvokeBaseCopyConstructor, "this").WithLocation(6, 21) - ); + var c1 = new C(1, 2); + System.Console.Write((c1.P1, c1.P2, c1.N1, c1.N2)); + System.Console.Write("" ""); + + var c2 = new C(c1); + System.Console.Write((c2.P1, c2.P2, c2.N1, c2.N2)); + System.Console.Write("" ""); + + var c3 = c1 with { P1 = 10, N1 = 30 }; + System.Console.Write((c3.P1, c3.P2, c3.N1, c3.N2)); + } +}"; + var compB = CreateCompilation(sourceB, references: new[] { refA }, parseOptions: TestOptions.RegularPreview, options: TestOptions.ReleaseExe); + compB.VerifyDiagnostics(); + + var verifierB = CompileAndVerify(compB, expectedOutput: "(1, 2, 3, 4) (1, 2, 3, 4) (10, 2, 30, 4)", verify: ExecutionConditionUtil.IsCoreClr ? Verification.Skipped : Verification.Fails); + // call base copy constructor B..ctor(B) + verifierB.VerifyIL("C..ctor(C)", @" +{ + // Code size 32 (0x20) + .maxstack 2 + IL_0000: ldarg.0 + IL_0001: ldarg.1 + IL_0002: call ""B..ctor(B)"" + IL_0007: ldarg.0 + IL_0008: ldarg.1 + IL_0009: ldfld ""object C.k__BackingField"" + IL_000e: stfld ""object C.k__BackingField"" + IL_0013: ldarg.0 + IL_0014: ldarg.1 + IL_0015: ldfld ""object C.k__BackingField"" + IL_001a: stfld ""object C.k__BackingField"" + IL_001f: ret +}"); } [Fact, WorkItem(44902, "https://github.com/dotnet/roslyn/issues/44902")] - public void CopyCtor_UserDefinedButDoesNotDelegateToBaseCopyCtor_UsesBase() + public void CopyCtor_WithOtherOverload() { var source = -@"public record B(int i) +@"public record B(object N1, object N2) { + public B(C c) : this(30, 40) => throw null; } -public record C(int j) : B(0) +public record C(object P1, object P2) : B(3, 4) { - public C(C c) : base(1) // 1 + static void Main() { + var c1 = new C(1, 2); + System.Console.Write((c1.P1, c1.P2, c1.N1, c1.N2)); + System.Console.Write("" ""); + + var c2 = c1 with { P1 = 10, P2 = 20, N1 = 30, N2 = 40 }; + System.Console.Write((c2.P1, c2.P2, c2.N1, c2.N2)); } -} -#nullable enable -public record D(int j) : B(0) +}"; + var comp = CreateCompilation(new[] { source, IsExternalInitTypeDefinition }, parseOptions: TestOptions.RegularPreview, options: TestOptions.ReleaseExe); + comp.VerifyDiagnostics(); + + var verifier = CompileAndVerify(comp, expectedOutput: "(1, 2, 3, 4) (10, 20, 30, 40)", verify: ExecutionConditionUtil.IsCoreClr ? Verification.Skipped : Verification.Fails); + // call base copy constructor B..ctor(B) + verifier.VerifyIL("C..ctor(C)", @" { - public D(D? d) : base(1) // 2 - { - } -} -"; - var comp = CreateCompilation(source); - comp.VerifyDiagnostics( - // (6,21): error CS8868: A copy constructor in a record must call a copy constructor of the base, or a parameterless object constructor if the record inherits from object. - // public C(C c) : base(1) // 1 - Diagnostic(ErrorCode.ERR_CopyConstructorMustInvokeBaseCopyConstructor, "base").WithLocation(6, 21), - // (13,22): error CS8868: A copy constructor in a record must call a copy constructor of the base, or a parameterless object constructor if the record inherits from object. - // public D(D? d) : base(1) // 2 - Diagnostic(ErrorCode.ERR_CopyConstructorMustInvokeBaseCopyConstructor, "base").WithLocation(13, 22) - ); + // Code size 32 (0x20) + .maxstack 2 + IL_0000: ldarg.0 + IL_0001: ldarg.1 + IL_0002: call ""B..ctor(B)"" + IL_0007: ldarg.0 + IL_0008: ldarg.1 + IL_0009: ldfld ""object C.k__BackingField"" + IL_000e: stfld ""object C.k__BackingField"" + IL_0013: ldarg.0 + IL_0014: ldarg.1 + IL_0015: ldfld ""object C.k__BackingField"" + IL_001a: stfld ""object C.k__BackingField"" + IL_001f: ret +}"); } [Fact, WorkItem(44902, "https://github.com/dotnet/roslyn/issues/44902")] - public void CopyCtor_UserDefined_WithFieldInitializers() + public void CopyCtor_WithObsoleteCopyConstructor() { var source = -@"public record C(int I) +@"public record B(object N1, object N2) { + [System.Obsolete(""Obsolete"", true)] + public B(B b) { } } -public record D(int J) : C(1) -{ - public int field = 42; - public D(D d) : base(d) - { - System.Console.Write(""RAN ""); - } - public static void Main() - { - var d = new D(2); - System.Console.Write((d.I, d.J, d.field)); - System.Console.Write("" ""); +public record C(object P1, object P2) : B(3, 4) { } +"; + var comp = CreateCompilation(new[] { source, IsExternalInitTypeDefinition }, parseOptions: TestOptions.RegularPreview); + comp.VerifyDiagnostics(); + } - var d2 = d with { I = 10, J = 20 }; - System.Console.Write((d2.I, d2.J, d.field)); - } + [Fact, WorkItem(44902, "https://github.com/dotnet/roslyn/issues/44902")] + public void CopyCtor_WithParamsCopyConstructor() + { + var source = +@"public record B(object N1, object N2) +{ + public B(B b, params int[] i) : this(30, 40) { } } +public record C(object P1, object P2) : B(3, 4) { } "; - var comp = CreateCompilation(new[] { source, IsExternalInitTypeDefinition }, parseOptions: TestOptions.RegularPreview, options: TestOptions.DebugExe); + var comp = CreateCompilation(source); comp.VerifyDiagnostics(); - var verifier = CompileAndVerify(comp, expectedOutput: "(1, 2, 42) RAN (10, 20, 42)", verify: ExecutionConditionUtil.IsCoreClr ? Verification.Skipped : Verification.Fails); - verifier.VerifyIL("D..ctor(D)", @" + + var actualMembers = comp.GetMember("B").GetMembers().Where(m => m.Name == ".ctor").ToTestDisplayStrings(); + var expectedMembers = new[] + { + "B..ctor(System.Object N1, System.Object N2)", + "B..ctor(B b, params System.Int32[] i)", + "B..ctor(B )" + }; + AssertEx.Equal(expectedMembers, actualMembers); + + var verifier = CompileAndVerify(comp, verify: ExecutionConditionUtil.IsCoreClr ? Verification.Skipped : Verification.Fails); + verifier.VerifyIL("C..ctor(C)", @" { - // Code size 21 (0x15) + // Code size 32 (0x20) .maxstack 2 IL_0000: ldarg.0 IL_0001: ldarg.1 - IL_0002: call ""C..ctor(C)"" - IL_0007: nop - IL_0008: nop - IL_0009: ldstr ""RAN "" - IL_000e: call ""void System.Console.Write(string)"" - IL_0013: nop - IL_0014: ret + IL_0002: call ""B..ctor(B)"" + IL_0007: ldarg.0 + IL_0008: ldarg.1 + IL_0009: ldfld ""object C.k__BackingField"" + IL_000e: stfld ""object C.k__BackingField"" + IL_0013: ldarg.0 + IL_0014: ldarg.1 + IL_0015: ldfld ""object C.k__BackingField"" + IL_001a: stfld ""object C.k__BackingField"" + IL_001f: ret } "); } [Fact, WorkItem(44902, "https://github.com/dotnet/roslyn/issues/44902")] - public void CopyCtor_Synthesized_WithFieldInitializers() + public void CopyCtor_WithInitializers() { var source = -@"public record C(int I) -{ -} -public record D(int J) : C(1) +@"public record C(object N1, object N2) { - public int field = 42; - public static void Main() - { - var d = new D(2); - System.Console.Write((d.I, d.J, d.field)); - System.Console.Write("" ""); - - var d2 = d with { I = 10, J = 20 }; - System.Console.Write((d2.I, d2.J, d.field)); - } -} -"; - var comp = CreateCompilation(new[] { source, IsExternalInitTypeDefinition }, parseOptions: TestOptions.RegularPreview, options: TestOptions.DebugExe); + private int field = 42; + public int Property = 43; +}"; + var comp = CreateCompilation(source); comp.VerifyDiagnostics(); - var verifier = CompileAndVerify(comp, expectedOutput: "(1, 2, 42) (10, 20, 42)", verify: ExecutionConditionUtil.IsCoreClr ? Verification.Skipped : Verification.Fails); - verifier.VerifyIL("D..ctor(D)", @" - { - // Code size 33 (0x21) - .maxstack 2 - IL_0000: ldarg.0 - IL_0001: ldarg.1 - IL_0002: call ""C..ctor(C)"" - IL_0007: nop - IL_0008: ldarg.0 - IL_0009: ldarg.1 - IL_000a: ldfld ""int D.k__BackingField"" - IL_000f: stfld ""int D.k__BackingField"" - IL_0014: ldarg.0 - IL_0015: ldarg.1 - IL_0016: ldfld ""int D.field"" - IL_001b: stfld ""int D.field"" - IL_0020: ret - } -"); + + var verifier = CompileAndVerify(comp, verify: ExecutionConditionUtil.IsCoreClr ? Verification.Skipped : Verification.Fails); + verifier.VerifyIL("C..ctor(C)", @" +{ + // Code size 55 (0x37) + .maxstack 2 + IL_0000: ldarg.0 + IL_0001: call ""object..ctor()"" + IL_0006: ldarg.0 + IL_0007: ldarg.1 + IL_0008: ldfld ""object C.k__BackingField"" + IL_000d: stfld ""object C.k__BackingField"" + IL_0012: ldarg.0 + IL_0013: ldarg.1 + IL_0014: ldfld ""object C.k__BackingField"" + IL_0019: stfld ""object C.k__BackingField"" + IL_001e: ldarg.0 + IL_001f: ldarg.1 + IL_0020: ldfld ""int C.field"" + IL_0025: stfld ""int C.field"" + IL_002a: ldarg.0 + IL_002b: ldarg.1 + IL_002c: ldfld ""int C.Property"" + IL_0031: stfld ""int C.Property"" + IL_0036: ret +}"); } [Fact, WorkItem(44902, "https://github.com/dotnet/roslyn/issues/44902")] - public void CopyCtor_UserDefinedButPrivate() + public void CopyCtor_UserDefinedButDoesNotDelegateToBaseCopyCtor() { var source = @"public record B(object N1, object N2) { - private B(B b) { } } public record C(object P1, object P2) : B(0, 1) { - private C(C c) : base(2, 3) { } // 1 -} -public record D(object P1, object P2) : B(0, 1) -{ - private D(D d) : base(d) { } // 2 + public C(C c) // 1, 2 + { + } } -public record E(object P1, object P2) : B(0, 1); // 3 "; var comp = CreateCompilation(source); comp.VerifyDiagnostics( - // (7,22): error CS8868: A copy constructor in a record must call a copy constructor of the base, or a parameterless object constructor if the record inherits from object. - // private C(C c) : base(2, 3) { } // 1 - Diagnostic(ErrorCode.ERR_CopyConstructorMustInvokeBaseCopyConstructor, "base").WithLocation(7, 22), - // (11,22): error CS0122: 'B.B(B)' is inaccessible due to its protection level - // private D(D d) : base(d) { } // 2 - Diagnostic(ErrorCode.ERR_BadAccess, "base").WithArguments("B.B(B)").WithLocation(11, 22), - // (13,15): error CS8867: No accessible copy constructor found in base type 'B'. - // public record E(object P1, object P2) : B(0, 1); // 3 - Diagnostic(ErrorCode.ERR_NoCopyConstructorInBaseType, "E").WithArguments("B").WithLocation(13, 15) + // (6,12): error CS1729: 'B' does not contain a constructor that takes 0 arguments + // public C(C c) // 1, 2 + Diagnostic(ErrorCode.ERR_BadCtorArgCount, "C").WithArguments("B", "0").WithLocation(6, 12), + // (6,12): error CS8868: A copy constructor in a record must call a copy constructor of the base, or a parameterless object constructor if the record inherits from object. + // public C(C c) // 1, 2 + Diagnostic(ErrorCode.ERR_CopyConstructorMustInvokeBaseCopyConstructor, "C").WithLocation(6, 12) ); - // Should we complain about private user-defined copy constructor on unsealed type (ie. will prevent inheritance)? - // https://github.com/dotnet/roslyn/issues/45012 } [Fact, WorkItem(44902, "https://github.com/dotnet/roslyn/issues/44902")] - public void CopyCtor_InaccessibleToCallerFromPE() + public void CopyCtor_UserDefinedButDoesNotDelegateToBaseCopyCtor_DerivesFromObject() { - var sourceA = -@"public record B(object N1, object N2) + var source = +@"public record C(int I) { - internal B(B b) { } -}"; - var compA = CreateCompilation(sourceA); - var refA = compA.EmitToImageReference(); - - var sourceB = @" -record C(object P1, object P2) : B(3, 4); // 1 + public int I { get; set; } = 42; + public C(C c) + { + } + public static void Main() + { + var c = new C(1); + c.I = 2; + var c2 = new C(c); + System.Console.Write((c.I, c2.I)); + } +} "; - var compB = CreateCompilation(sourceB, references: new[] { refA }, parseOptions: TestOptions.RegularPreview); - compB.VerifyDiagnostics( - // (2,8): error CS8867: No accessible copy constructor found in base type 'B'. - // record C(object P1, object P2) : B(3, 4); // 1 - Diagnostic(ErrorCode.ERR_NoCopyConstructorInBaseType, "C").WithArguments("B").WithLocation(2, 8) - ); - - var sourceC = @" -record C(object P1, object P2) : B(3, 4) + var comp = CreateCompilation(new[] { source, IsExternalInitTypeDefinition }, parseOptions: TestOptions.RegularPreview, options: TestOptions.DebugExe); + comp.VerifyDiagnostics(); + var verifier = CompileAndVerify(comp, expectedOutput: "(2, 0)"); + verifier.VerifyIL("C..ctor(C)", @" { - protected C(C c) : base(c) { } // 1, 2 + // Code size 9 (0x9) + .maxstack 1 + IL_0000: ldarg.0 + IL_0001: call ""object..ctor()"" + IL_0006: nop + IL_0007: nop + IL_0008: ret } -"; - var compC = CreateCompilation(sourceC, references: new[] { refA }, parseOptions: TestOptions.RegularPreview); - compC.VerifyDiagnostics( - // (4,24): error CS7036: There is no argument given that corresponds to the required formal parameter 'N2' of 'B.B(object, object)' - // protected C(C c) : base(c) { } // 1, 2 - Diagnostic(ErrorCode.ERR_NoCorrespondingArgument, "base").WithArguments("N2", "B.B(object, object)").WithLocation(4, 24), - // (4,24): error CS8868: A copy constructor in a record must call a copy constructor of the base, or a parameterless object constructor if the record inherits from object. - // protected C(C c) : base(c) { } // 1, 2 - Diagnostic(ErrorCode.ERR_CopyConstructorMustInvokeBaseCopyConstructor, "base").WithLocation(4, 24) - ); +"); } [Fact, WorkItem(44902, "https://github.com/dotnet/roslyn/issues/44902")] - public void CopyCtor_InaccessibleToCallerFromPE_WithIVT() + public void CopyCtor_UserDefinedButDoesNotDelegateToBaseCopyCtor_DerivesFromObject_WithFieldInitializer() { - var sourceA = @" -using System.Runtime.CompilerServices; -[assembly: InternalsVisibleTo(""AssemblyB"")] - -public record B(object N1, object N2) + var source = +@"public record C(int I) { - internal B(B b) { } -}"; - var compA = CreateCompilation(new[] { sourceA, IsExternalInitTypeDefinition }, assemblyName: "AssemblyA", parseOptions: TestOptions.RegularPreview); - var refA = compA.EmitToImageReference(); + public int I { get; set; } = 42; + public int field = 43; + public C(C c) + { + System.Console.Write("" RAN ""); + } + public static void Main() + { + var c = new C(1); + c.I = 2; + c.field = 100; + System.Console.Write((c.I, c.field)); - var sourceB = @" -record C(int j) : B(3, 4); + var c2 = new C(c); + System.Console.Write((c2.I, c2.field)); + } +} "; - var compB = CreateCompilation(sourceB, references: new[] { refA }, parseOptions: TestOptions.RegularPreview, assemblyName: "AssemblyB"); - compB.VerifyDiagnostics(); - - var sourceC = @" -record C(int j) : B(3, 4) + var comp = CreateCompilation(new[] { source, IsExternalInitTypeDefinition }, parseOptions: TestOptions.RegularPreview, options: TestOptions.DebugExe); + comp.VerifyDiagnostics(); + var verifier = CompileAndVerify(comp, expectedOutput: "(2, 100) RAN (0, 0)"); + verifier.VerifyIL("C..ctor(C)", @" { - protected C(C c) : base(c) { } + // Code size 20 (0x14) + .maxstack 1 + IL_0000: ldarg.0 + IL_0001: call ""object..ctor()"" + IL_0006: nop + IL_0007: nop + IL_0008: ldstr "" RAN "" + IL_000d: call ""void System.Console.Write(string)"" + IL_0012: nop + IL_0013: ret } -"; - var compC = CreateCompilation(sourceC, references: new[] { refA }, parseOptions: TestOptions.RegularPreview, assemblyName: "AssemblyB"); - compC.VerifyDiagnostics(); +"); } [Fact, WorkItem(44902, "https://github.com/dotnet/roslyn/issues/44902")] - [WorkItem(45012, "https://github.com/dotnet/roslyn/issues/45012")] - public void CopyCtor_UserDefinedButPrivate_InSealedType() + public void CopyCtor_DerivesFromObject_GivesParameterToBase() { - var source = -@"public record B(int i) -{ -} -public sealed record C(int j) : B(0) + var source = @" +public record C(object I) { - private C(C c) : base(c) - { - } + public C(C c) : base(1) { } } "; var comp = CreateCompilation(source); - comp.VerifyDiagnostics(); - var copyCtor = comp.GetMembers("C..ctor")[0]; - Assert.Equal("C..ctor(C c)", copyCtor.ToTestDisplayString()); - Assert.True(copyCtor.DeclaredAccessibility == Accessibility.Private); + comp.VerifyDiagnostics( + // (4,21): error CS1729: 'object' does not contain a constructor that takes 1 arguments + // public C(C c) : base(1) { } + Diagnostic(ErrorCode.ERR_BadCtorArgCount, "base").WithArguments("object", "1").WithLocation(4, 21), + // (4,21): error CS8868: A copy constructor in a record must call a copy constructor of the base, or a parameterless object constructor if the record inherits from object. + // public C(C c) : base(1) { } + Diagnostic(ErrorCode.ERR_CopyConstructorMustInvokeBaseCopyConstructor, "base").WithLocation(4, 21) + ); } [Fact, WorkItem(44902, "https://github.com/dotnet/roslyn/issues/44902")] - [WorkItem(45012, "https://github.com/dotnet/roslyn/issues/45012")] - public void CopyCtor_UserDefinedButInternal() + public void CopyCtor_DerivesFromObject_WithSomeOtherConstructor() { - var source = -@"public record B(object N1, object N2) -{ -} -public sealed record Sealed(object P1, object P2) : B(0, 1) -{ - internal Sealed(Sealed s) : base(s) - { - } -} -public record Unsealed(object P1, object P2) : B(0, 1) + var source = @" +public record C(object I) { - internal Unsealed(Unsealed s) : base(s) + public C(int i) : this((object)null) { } + public static void Main() { + var c = new C((object)null); + var c2 = new C(1); + var c3 = new C(c); + System.Console.Write(""RAN""); } } "; - var comp = CreateCompilation(source); + var comp = CreateCompilation(new[] { source, IsExternalInitTypeDefinition }, parseOptions: TestOptions.RegularPreview, options: TestOptions.DebugExe); comp.VerifyDiagnostics(); - - var sealedCopyCtor = comp.GetMembers("Sealed..ctor")[0]; - Assert.Equal("Sealed..ctor(Sealed s)", sealedCopyCtor.ToTestDisplayString()); - Assert.True(sealedCopyCtor.DeclaredAccessibility == Accessibility.Internal); - - var unsealedCopyCtor = comp.GetMembers("Unsealed..ctor")[0]; - Assert.Equal("Unsealed..ctor(Unsealed s)", unsealedCopyCtor.ToTestDisplayString()); - Assert.True(unsealedCopyCtor.DeclaredAccessibility == Accessibility.Internal); + var verifier = CompileAndVerify(comp, expectedOutput: "RAN", verify: ExecutionConditionUtil.IsCoreClr ? Verification.Skipped : Verification.Fails); + verifier.VerifyIL("C..ctor(int)", @" +{ + // Code size 10 (0xa) + .maxstack 2 + IL_0000: ldarg.0 + IL_0001: ldnull + IL_0002: call ""C..ctor(object)"" + IL_0007: nop + IL_0008: nop + IL_0009: ret +} +"); } [Fact, WorkItem(44902, "https://github.com/dotnet/roslyn/issues/44902")] - public void CopyCtor_BaseHasRefKind() + public void CopyCtor_UserDefinedButDoesNotDelegateToBaseCopyCtor_DerivesFromObject_UsesThis() { var source = -@"public record B(int i) -{ - public B(ref B b) => throw null; // 1, not recognized as copy constructor -} -public record C(int j) : B(1) +@"public record C(int I) { - internal C(C c) : base(c) + public C(C c) : this(c.I) { } } "; var comp = CreateCompilation(source); comp.VerifyDiagnostics( - // (3,12): error CS8862: A constructor declared in a record with parameters must have 'this' constructor initializer. - // public B(ref B b) => throw null; // 1, not recognized as copy constructor - Diagnostic(ErrorCode.ERR_UnexpectedOrMissingConstructorInitializerInRecord, "B").WithLocation(3, 12) + // (3,21): error CS8868: A copy constructor in a record must call a copy constructor of the base, or a parameterless object constructor if the record inherits from object. + // public C(C c) : this(c.I) + Diagnostic(ErrorCode.ERR_CopyConstructorMustInvokeBaseCopyConstructor, "this").WithLocation(3, 21) ); } [Fact, WorkItem(44902, "https://github.com/dotnet/roslyn/issues/44902")] - public void CopyCtor_BaseHasRefKind_WithThisInitializer() + public void CopyCtor_UserDefined_DerivesFromObject_UsesBase() { var source = -@"public record B(int i) -{ - public B(ref B b) : this(0) => throw null; // 1, not recognized as copy constructor -} -public record C(int j) : B(1) +@"public record C(int I) { - internal C(C c) : base(c) + public C(C c) : base() + { + System.Console.Write(""RAN ""); + } + public static void Main() { + var c = new C(1); + System.Console.Write(c.I); + System.Console.Write("" ""); + var c2 = c with { I = 2 }; + System.Console.Write(c2.I); } } "; - var comp = CreateCompilation(source); + var comp = CreateCompilation(new[] { source, IsExternalInitTypeDefinition }, parseOptions: TestOptions.RegularPreview, options: TestOptions.DebugExe); comp.VerifyDiagnostics(); - - var actualMembers = comp.GetMember("B").GetMembers().Where(m => m.Name == ".ctor").ToTestDisplayStrings(); - var expectedMembers = new[] - { - "B..ctor(System.Int32 i)", - "B..ctor(ref B b)", - "B..ctor(B )" - }; - AssertEx.Equal(expectedMembers, actualMembers); + var verifier = CompileAndVerify(comp, expectedOutput: "1 RAN 2", verify: ExecutionConditionUtil.IsCoreClr ? Verification.Skipped : Verification.Fails); + verifier.VerifyIL("C..ctor(C)", @" +{ + // Code size 20 (0x14) + .maxstack 1 + IL_0000: ldarg.0 + IL_0001: call ""object..ctor()"" + IL_0006: nop + IL_0007: nop + IL_0008: ldstr ""RAN "" + IL_000d: call ""void System.Console.Write(string)"" + IL_0012: nop + IL_0013: ret +} +"); } [Fact, WorkItem(44902, "https://github.com/dotnet/roslyn/issues/44902")] - public void CopyCtor_WithPrivateField() + public void CopyCtor_UserDefinedButDoesNotDelegateToBaseCopyCtor_NoPositionalMembers() { var source = @"public record B(object N1, object N2) { - private int field1 = 100; - public int GetField1() => field1; } -public record C(object P1, object P2) : B(3, 4) +public record C(object P1) : B(0, 1) { - private int field2 = 200; - public int GetField2() => field2; - - static void Main() + public C(C c) // 1, 2 { - var c1 = new C(1, 2); - var c2 = new C(c1); - System.Console.Write((c2.P1, c2.P2, c2.N1, c2.N2, c2.GetField1(), c2.GetField2())); } -}"; - var comp = CreateCompilation(new[] { source, IsExternalInitTypeDefinition }, parseOptions: TestOptions.RegularPreview, options: TestOptions.ReleaseExe); - comp.VerifyDiagnostics(); - - var verifier = CompileAndVerify(comp, expectedOutput: "(1, 2, 3, 4, 100, 200)", verify: ExecutionConditionUtil.IsCoreClr ? Verification.Skipped : Verification.Fails); - verifier.VerifyIL("C..ctor(C)", @" -{ - // Code size 44 (0x2c) - .maxstack 2 - IL_0000: ldarg.0 - IL_0001: ldarg.1 - IL_0002: call ""B..ctor(B)"" - IL_0007: ldarg.0 - IL_0008: ldarg.1 - IL_0009: ldfld ""object C.k__BackingField"" - IL_000e: stfld ""object C.k__BackingField"" - IL_0013: ldarg.0 - IL_0014: ldarg.1 - IL_0015: ldfld ""object C.k__BackingField"" - IL_001a: stfld ""object C.k__BackingField"" - IL_001f: ldarg.0 - IL_0020: ldarg.1 - IL_0021: ldfld ""int C.field2"" - IL_0026: stfld ""int C.field2"" - IL_002b: ret -}"); +} +"; + var comp = CreateCompilation(source); + comp.VerifyDiagnostics( + // (6,12): error CS1729: 'B' does not contain a constructor that takes 0 arguments + // public C(C c) // 1, 2 + Diagnostic(ErrorCode.ERR_BadCtorArgCount, "C").WithArguments("B", "0").WithLocation(6, 12), + // (6,12): error CS8868: A copy constructor in a record must call a copy constructor of the base, or a parameterless object constructor if the record inherits from object. + // public C(C c) // 1, 2 + Diagnostic(ErrorCode.ERR_CopyConstructorMustInvokeBaseCopyConstructor, "C").WithLocation(6, 12) + ); } [Fact, WorkItem(44902, "https://github.com/dotnet/roslyn/issues/44902")] - public void CopyCtor_MissingInMetadata() + public void CopyCtor_UserDefinedButDoesNotDelegateToBaseCopyCtor_UsesThis() { - // IL for `public record B { }` - var ilSource = @" -.class public auto ansi beforefieldinit B extends [mscorlib]System.Object + var source = +@"public record B(object N1, object N2) { - .method public hidebysig specialname newslot virtual instance class B '<>Clone' () cil managed - { - IL_0000: ldnull - IL_0001: throw - } - - .method family hidebysig newslot virtual instance class [mscorlib]System.Type get_EqualityContract () cil managed - { - IL_0000: ldnull - IL_0001: throw - } - - .method public hidebysig virtual instance int32 GetHashCode () cil managed - { - IL_0000: ldnull - IL_0001: throw - } - - .method public hidebysig virtual instance bool Equals ( object '' ) cil managed - { - IL_0000: ldnull - IL_0001: throw - } - - .method public newslot virtual instance bool Equals ( class B '' ) cil managed - { - IL_0000: ldnull - IL_0001: throw - } - - // Removed copy constructor - //.method public hidebysig specialname rtspecialname instance void .ctor ( class B '' ) cil managed - - .method public hidebysig specialname rtspecialname instance void .ctor () cil managed - { - IL_0000: ldnull - IL_0001: throw - } - - .property instance class [mscorlib]System.Type EqualityContract() +} +public record C(object P1, object P2) : B(0, 1) +{ + public C(C c) : this(1, 2) // 1 { - .get instance class [mscorlib]System.Type B::get_EqualityContract() } } "; - var source = @" -public record C : B { -}"; - var comp = CreateCompilationWithIL(new[] { source, IsExternalInitTypeDefinition }, ilSource: ilSource, parseOptions: TestOptions.RegularPreview); + var comp = CreateCompilation(source); comp.VerifyDiagnostics( - // (2,15): error CS8867: No accessible copy constructor found in base type 'B'. - // public record C : B { - Diagnostic(ErrorCode.ERR_NoCopyConstructorInBaseType, "C").WithArguments("B").WithLocation(2, 15) - ); - - var source2 = @" -public record C : B -{ - public C(C c) { } -}"; - var comp2 = CreateCompilationWithIL(new[] { source2, IsExternalInitTypeDefinition }, ilSource: ilSource, parseOptions: TestOptions.RegularPreview); - comp2.VerifyDiagnostics( - // (4,12): error CS8868: A copy constructor in a record must call a copy constructor of the base, or a parameterless object constructor if the record inherits from object. - // public C(C c) { } - Diagnostic(ErrorCode.ERR_CopyConstructorMustInvokeBaseCopyConstructor, "C").WithLocation(4, 12) + // (6,21): error CS8868: A copy constructor in a record must call a copy constructor of the base, or a parameterless object constructor if the record inherits from object. + // public C(C c) : this(1, 2) // 1 + Diagnostic(ErrorCode.ERR_CopyConstructorMustInvokeBaseCopyConstructor, "this").WithLocation(6, 21) ); } [Fact, WorkItem(44902, "https://github.com/dotnet/roslyn/issues/44902")] - public void CopyCtor_InaccessibleInMetadata() + public void CopyCtor_UserDefinedButDoesNotDelegateToBaseCopyCtor_UsesBase() { - // IL for `public record B { }` - var ilSource = @" -.class public auto ansi beforefieldinit B extends [mscorlib]System.Object + var source = +@"public record B(int i) { - .method public hidebysig specialname newslot virtual instance class B '<>Clone' () cil managed - { - IL_0000: ldnull - IL_0001: throw - } - - .method family hidebysig newslot virtual instance class [mscorlib]System.Type get_EqualityContract () cil managed - { - IL_0000: ldnull - IL_0001: throw - } - - .method public hidebysig virtual instance int32 GetHashCode () cil managed - { - IL_0000: ldnull - IL_0001: throw - } - - .method public hidebysig virtual instance bool Equals ( object '' ) cil managed - { - IL_0000: ldnull - IL_0001: throw - } - - .method public newslot virtual instance bool Equals ( class B '' ) cil managed - { - IL_0000: ldnull - IL_0001: throw - } - - // Inaccessible copy constructor - .method private hidebysig specialname rtspecialname instance void .ctor ( class B '' ) cil managed - { - IL_0000: ldnull - IL_0001: throw - } - - .method public hidebysig specialname rtspecialname instance void .ctor () cil managed +} +public record C(int j) : B(0) +{ + public C(C c) : base(1) // 1 { - IL_0000: ldnull - IL_0001: throw } - - .property instance class [mscorlib]System.Type EqualityContract() +} +#nullable enable +public record D(int j) : B(0) +{ + public D(D? d) : base(1) // 2 { - .get instance class [mscorlib]System.Type B::get_EqualityContract() } } "; - var source = @" -public record C : B { -}"; - var comp = CreateCompilationWithIL(new[] { source, IsExternalInitTypeDefinition }, ilSource: ilSource, parseOptions: TestOptions.RegularPreview); + var comp = CreateCompilation(source); comp.VerifyDiagnostics( - // (2,15): error CS8867: No accessible copy constructor found in base type 'B'. - // public record C : B { - Diagnostic(ErrorCode.ERR_NoCopyConstructorInBaseType, "C").WithArguments("B").WithLocation(2, 15) + // (6,21): error CS8868: A copy constructor in a record must call a copy constructor of the base, or a parameterless object constructor if the record inherits from object. + // public C(C c) : base(1) // 1 + Diagnostic(ErrorCode.ERR_CopyConstructorMustInvokeBaseCopyConstructor, "base").WithLocation(6, 21), + // (13,22): error CS8868: A copy constructor in a record must call a copy constructor of the base, or a parameterless object constructor if the record inherits from object. + // public D(D? d) : base(1) // 2 + Diagnostic(ErrorCode.ERR_CopyConstructorMustInvokeBaseCopyConstructor, "base").WithLocation(13, 22) ); } - [Fact] - public void Inheritance_22() + [Fact, WorkItem(44902, "https://github.com/dotnet/roslyn/issues/44902")] + public void CopyCtor_UserDefined_WithFieldInitializers() { var source = -@"record A +@"public record C(int I) { - public ref object P1 => throw null; - public object P2 => throw null; } -record B : A +public record D(int J) : C(1) { - public new object P1 => throw null; - public new ref object P2 => throw null; + public int field = 42; + public D(D d) : base(d) + { + System.Console.Write(""RAN ""); + } + public static void Main() + { + var d = new D(2); + System.Console.Write((d.I, d.J, d.field)); + System.Console.Write("" ""); + + var d2 = d with { I = 10, J = 20 }; + System.Console.Write((d2.I, d2.J, d.field)); + } } -record C(object P1, object P2) : B -{ -}"; - var comp = CreateCompilation(source); +"; + var comp = CreateCompilation(new[] { source, IsExternalInitTypeDefinition }, parseOptions: TestOptions.RegularPreview, options: TestOptions.DebugExe); comp.VerifyDiagnostics(); - var actualMembers = GetProperties(comp, "C").ToTestDisplayStrings(); - AssertEx.Equal(new[] { "System.Type C.EqualityContract { get; }" }, actualMembers); + var verifier = CompileAndVerify(comp, expectedOutput: "(1, 2, 42) RAN (10, 20, 42)", verify: ExecutionConditionUtil.IsCoreClr ? Verification.Skipped : Verification.Fails); + verifier.VerifyIL("D..ctor(D)", @" +{ + // Code size 21 (0x15) + .maxstack 2 + IL_0000: ldarg.0 + IL_0001: ldarg.1 + IL_0002: call ""C..ctor(C)"" + IL_0007: nop + IL_0008: nop + IL_0009: ldstr ""RAN "" + IL_000e: call ""void System.Console.Write(string)"" + IL_0013: nop + IL_0014: ret +} +"); } - [Fact] - public void Inheritance_23() + [Fact, WorkItem(44902, "https://github.com/dotnet/roslyn/issues/44902")] + public void CopyCtor_Synthesized_WithFieldInitializers() { var source = -@"record A +@"public record C(int I) { - public static object P1 { get; } - public object P2 { get; } } -record B : A +public record D(int J) : C(1) { - public new object P1 { get; } - public new static object P2 { get; } + public int field = 42; + public static void Main() + { + var d = new D(2); + System.Console.Write((d.I, d.J, d.field)); + System.Console.Write("" ""); + + var d2 = d with { I = 10, J = 20 }; + System.Console.Write((d2.I, d2.J, d.field)); + } } -record C(object P1, object P2) : B -{ -}"; - var comp = CreateCompilation(source); - comp.VerifyDiagnostics( - // (11,28): error CS8866: Record member 'B.P2' must be a readable instance property of type 'object' to match positional parameter 'P2'. - // record C(object P1, object P2) : B - Diagnostic(ErrorCode.ERR_BadRecordMemberForPositionalParameter, "P2").WithArguments("B.P2", "object", "P2").WithLocation(11, 28)); - var actualMembers = GetProperties(comp, "C").ToTestDisplayStrings(); - AssertEx.Equal(new[] { "System.Type C.EqualityContract { get; }" }, actualMembers); +"; + var comp = CreateCompilation(new[] { source, IsExternalInitTypeDefinition }, parseOptions: TestOptions.RegularPreview, options: TestOptions.DebugExe); + comp.VerifyDiagnostics(); + var verifier = CompileAndVerify(comp, expectedOutput: "(1, 2, 42) (10, 20, 42)", verify: ExecutionConditionUtil.IsCoreClr ? Verification.Skipped : Verification.Fails); + verifier.VerifyIL("D..ctor(D)", @" + { + // Code size 33 (0x21) + .maxstack 2 + IL_0000: ldarg.0 + IL_0001: ldarg.1 + IL_0002: call ""C..ctor(C)"" + IL_0007: nop + IL_0008: ldarg.0 + IL_0009: ldarg.1 + IL_000a: ldfld ""int D.k__BackingField"" + IL_000f: stfld ""int D.k__BackingField"" + IL_0014: ldarg.0 + IL_0015: ldarg.1 + IL_0016: ldfld ""int D.field"" + IL_001b: stfld ""int D.field"" + IL_0020: ret + } +"); } - [Fact] - public void Inheritance_24() + [Fact, WorkItem(44902, "https://github.com/dotnet/roslyn/issues/44902")] + public void CopyCtor_UserDefinedButPrivate() { var source = -@"record A +@"public record B(object N1, object N2) { - public object get_P() => null; - public object set_Q() => null; + private B(B b) { } } -record B(object P, object Q) : A +public record C(object P1, object P2) : B(0, 1) { + private C(C c) : base(2, 3) { } // 1 } -record C(object P) +public record D(object P1, object P2) : B(0, 1) { - public object get_P() => null; - public object set_Q() => null; -}"; + private D(D d) : base(d) { } // 2 +} +public record E(object P1, object P2) : B(0, 1); // 3 +"; var comp = CreateCompilation(source); comp.VerifyDiagnostics( - // (9,17): error CS0082: Type 'C' already reserves a member called 'get_P' with the same parameter types - // record C(object P) - Diagnostic(ErrorCode.ERR_MemberReserved, "P").WithArguments("get_P", "C").WithLocation(9, 17)); - - var expectedMembers = new[] - { - "A B.<>Clone()", - "System.Type B.EqualityContract.get", - "System.Type B.EqualityContract { get; }", - "B..ctor(System.Object P, System.Object Q)", - "System.Object B.

k__BackingField", - "System.Object B.P.get", - "void modreq(System.Runtime.CompilerServices.IsExternalInit) B.P.init", - "System.Object B.P { get; init; }", - "System.Object B.k__BackingField", - "System.Object B.Q.get", - "void modreq(System.Runtime.CompilerServices.IsExternalInit) B.Q.init", - "System.Object B.Q { get; init; }", - "System.Int32 B.GetHashCode()", - "System.Boolean B.Equals(System.Object? )", - "System.Boolean B.Equals(A? )", - "System.Boolean B.Equals(B? )", - "B..ctor(B )", - "void B.Deconstruct(out System.Object P, out System.Object Q)" - }; - AssertEx.Equal(expectedMembers, comp.GetMember("B").GetMembers().ToTestDisplayStrings()); - - expectedMembers = new[] - { - "C C.<>Clone()", - "System.Type C.EqualityContract.get", - "System.Type C.EqualityContract { get; }", - "C..ctor(System.Object P)", - "System.Object C.

k__BackingField", - "System.Object C.P.get", - "void modreq(System.Runtime.CompilerServices.IsExternalInit) C.P.init", - "System.Object C.P { get; init; }", - "System.Object C.get_P()", - "System.Object C.set_Q()", - "System.Int32 C.GetHashCode()", - "System.Boolean C.Equals(System.Object? )", - "System.Boolean C.Equals(C? )", - "C..ctor(C )", - "void C.Deconstruct(out System.Object P)" - }; - AssertEx.Equal(expectedMembers, comp.GetMember("C").GetMembers().ToTestDisplayStrings()); + // (7,22): error CS8868: A copy constructor in a record must call a copy constructor of the base, or a parameterless object constructor if the record inherits from object. + // private C(C c) : base(2, 3) { } // 1 + Diagnostic(ErrorCode.ERR_CopyConstructorMustInvokeBaseCopyConstructor, "base").WithLocation(7, 22), + // (11,22): error CS0122: 'B.B(B)' is inaccessible due to its protection level + // private D(D d) : base(d) { } // 2 + Diagnostic(ErrorCode.ERR_BadAccess, "base").WithArguments("B.B(B)").WithLocation(11, 22), + // (13,15): error CS8867: No accessible copy constructor found in base type 'B'. + // public record E(object P1, object P2) : B(0, 1); // 3 + Diagnostic(ErrorCode.ERR_NoCopyConstructorInBaseType, "E").WithArguments("B").WithLocation(13, 15) + ); + // Should we complain about private user-defined copy constructor on unsealed type (ie. will prevent inheritance)? + // https://github.com/dotnet/roslyn/issues/45012 } - [Fact] - public void Inheritance_25() + [Fact, WorkItem(44902, "https://github.com/dotnet/roslyn/issues/44902")] + public void CopyCtor_InaccessibleToCallerFromPE() { var sourceA = -@"public record A -{ - public class P1 { } - internal object P2 = 2; - public int P3(object o) => 3; - internal int P4(T t) => 4; -}"; - var sourceB = -@"record B(object P1, object P2, object P3, object P4) : A +@"public record B(object N1, object N2) { + internal B(B b) { } }"; - var comp = CreateCompilation(new[] { sourceA, sourceB }); - comp.VerifyDiagnostics( - // (1,17): error CS8866: Record member 'A.P1' must be a readable instance property of type 'object' to match positional parameter 'P1'. - // record B(object P1, object P2, object P3, object P4) : A - Diagnostic(ErrorCode.ERR_BadRecordMemberForPositionalParameter, "P1").WithArguments("A.P1", "object", "P1").WithLocation(1, 17), - // (1,28): error CS8866: Record member 'A.P2' must be a readable instance property of type 'object' to match positional parameter 'P2'. - // record B(object P1, object P2, object P3, object P4) : A - Diagnostic(ErrorCode.ERR_BadRecordMemberForPositionalParameter, "P2").WithArguments("A.P2", "object", "P2").WithLocation(1, 28), - // (1,39): error CS8866: Record member 'A.P3' must be a readable instance property of type 'object' to match positional parameter 'P3'. - // record B(object P1, object P2, object P3, object P4) : A - Diagnostic(ErrorCode.ERR_BadRecordMemberForPositionalParameter, "P3").WithArguments("A.P3", "object", "P3").WithLocation(1, 39)); - var actualMembers = GetProperties(comp, "B").ToTestDisplayStrings(); - var expectedMembers = new[] - { - "System.Type B.EqualityContract { get; }", - "System.Object B.P4 { get; init; }", - }; - AssertEx.Equal(expectedMembers, actualMembers); + var compA = CreateCompilation(sourceA); + var refA = compA.EmitToImageReference(); - comp = CreateCompilation(sourceA); - var refA = comp.EmitToImageReference(); - comp = CreateCompilation(sourceB, references: new[] { refA }, parseOptions: TestOptions.RegularPreview); - comp.VerifyDiagnostics( - // (1,17): error CS8866: Record member 'A.P1' must be a readable instance property of type 'object' to match positional parameter 'P1'. - // record B(object P1, object P2, object P3, object P4) : A - Diagnostic(ErrorCode.ERR_BadRecordMemberForPositionalParameter, "P1").WithArguments("A.P1", "object", "P1").WithLocation(1, 17), - // (1,39): error CS8866: Record member 'A.P3' must be a readable instance property of type 'object' to match positional parameter 'P3'. - // record B(object P1, object P2, object P3, object P4) : A - Diagnostic(ErrorCode.ERR_BadRecordMemberForPositionalParameter, "P3").WithArguments("A.P3", "object", "P3").WithLocation(1, 39)); - actualMembers = GetProperties(comp, "B").ToTestDisplayStrings(); - expectedMembers = new[] - { - "System.Type B.EqualityContract { get; }", - "System.Object B.P2 { get; init; }", - "System.Object B.P4 { get; init; }", - }; - AssertEx.Equal(expectedMembers, actualMembers); + var sourceB = @" +record C(object P1, object P2) : B(3, 4); // 1 +"; + var compB = CreateCompilation(sourceB, references: new[] { refA }, parseOptions: TestOptions.RegularPreview); + compB.VerifyDiagnostics( + // (2,8): error CS8867: No accessible copy constructor found in base type 'B'. + // record C(object P1, object P2) : B(3, 4); // 1 + Diagnostic(ErrorCode.ERR_NoCopyConstructorInBaseType, "C").WithArguments("B").WithLocation(2, 8) + ); + + var sourceC = @" +record C(object P1, object P2) : B(3, 4) +{ + protected C(C c) : base(c) { } // 1, 2 +} +"; + var compC = CreateCompilation(sourceC, references: new[] { refA }, parseOptions: TestOptions.RegularPreview); + compC.VerifyDiagnostics( + // (4,24): error CS7036: There is no argument given that corresponds to the required formal parameter 'N2' of 'B.B(object, object)' + // protected C(C c) : base(c) { } // 1, 2 + Diagnostic(ErrorCode.ERR_NoCorrespondingArgument, "base").WithArguments("N2", "B.B(object, object)").WithLocation(4, 24), + // (4,24): error CS8868: A copy constructor in a record must call a copy constructor of the base, or a parameterless object constructor if the record inherits from object. + // protected C(C c) : base(c) { } // 1, 2 + Diagnostic(ErrorCode.ERR_CopyConstructorMustInvokeBaseCopyConstructor, "base").WithLocation(4, 24) + ); } - [Fact] - public void Inheritance_26() + [Fact, WorkItem(44902, "https://github.com/dotnet/roslyn/issues/44902")] + public void CopyCtor_InaccessibleToCallerFromPE_WithIVT() { - var sourceA = -@"public record A -{ - internal const int P = 4; -}"; - var sourceB = -@"record B(object P) : A + var sourceA = @" +using System.Runtime.CompilerServices; +[assembly: InternalsVisibleTo(""AssemblyB"")] + +public record B(object N1, object N2) { + internal B(B b) { } }"; - var comp = CreateCompilation(new[] { sourceA, sourceB }); - comp.VerifyDiagnostics( - // (1,17): error CS8866: Record member 'A.P' must be a readable instance property of type 'object' to match positional parameter 'P'. - // record B(object P) : A - Diagnostic(ErrorCode.ERR_BadRecordMemberForPositionalParameter, "P").WithArguments("A.P", "object", "P").WithLocation(1, 17)); - AssertEx.Equal(new[] { "System.Type B.EqualityContract { get; }" }, GetProperties(comp, "B").ToTestDisplayStrings()); + var compA = CreateCompilation(new[] { sourceA, IsExternalInitTypeDefinition }, assemblyName: "AssemblyA", parseOptions: TestOptions.RegularPreview); + var refA = compA.EmitToImageReference(); - comp = CreateCompilation(sourceA); - var refA = comp.EmitToImageReference(); - comp = CreateCompilation(sourceB, references: new[] { refA }, parseOptions: TestOptions.RegularPreview); - comp.VerifyDiagnostics(); - AssertEx.Equal(new[] { "System.Type B.EqualityContract { get; }", "System.Object B.P { get; init; }" }, GetProperties(comp, "B").ToTestDisplayStrings()); + var sourceB = @" +record C(int j) : B(3, 4); +"; + var compB = CreateCompilation(sourceB, references: new[] { refA }, parseOptions: TestOptions.RegularPreview, assemblyName: "AssemblyB"); + compB.VerifyDiagnostics(); + + var sourceC = @" +record C(int j) : B(3, 4) +{ + protected C(C c) : base(c) { } +} +"; + var compC = CreateCompilation(sourceC, references: new[] { refA }, parseOptions: TestOptions.RegularPreview, assemblyName: "AssemblyB"); + compC.VerifyDiagnostics(); } - [Fact] - public void Inheritance_27() + [Fact, WorkItem(44902, "https://github.com/dotnet/roslyn/issues/44902")] + [WorkItem(45012, "https://github.com/dotnet/roslyn/issues/45012")] + public void CopyCtor_UserDefinedButPrivate_InSealedType() { var source = -@"record A +@"public record B(int i) { - public object P { get; } - public object Q { get; set; } } -record B(object get_P, object set_Q) : A +public sealed record C(int j) : B(0) { -}"; + private C(C c) : base(c) + { + } +} +"; var comp = CreateCompilation(source); comp.VerifyDiagnostics(); - var actualMembers = GetProperties(comp, "B").ToTestDisplayStrings(); - var expectedMembers = new[] - { - "System.Type B.EqualityContract { get; }", - "System.Object B.get_P { get; init; }", - "System.Object B.set_Q { get; init; }", - }; - AssertEx.Equal(expectedMembers, actualMembers); + var copyCtor = comp.GetMembers("C..ctor")[0]; + Assert.Equal("C..ctor(C c)", copyCtor.ToTestDisplayString()); + Assert.True(copyCtor.DeclaredAccessibility == Accessibility.Private); } - [Fact] - public void Inheritance_28() + [Fact, WorkItem(44902, "https://github.com/dotnet/roslyn/issues/44902")] + [WorkItem(45012, "https://github.com/dotnet/roslyn/issues/45012")] + public void CopyCtor_UserDefinedButInternal() { var source = -@"interface I +@"public record B(object N1, object N2) { - object P { get; } } -record A : I +public sealed record Sealed(object P1, object P2) : B(0, 1) { - object I.P => null; + internal Sealed(Sealed s) : base(s) + { + } } -record B(object P) : A +public record Unsealed(object P1, object P2) : B(0, 1) { + internal Unsealed(Unsealed s) : base(s) + { + } } -record C(object P) : I -{ - object I.P => null; -}"; +"; var comp = CreateCompilation(source); comp.VerifyDiagnostics(); - AssertEx.Equal(new[] { "System.Type B.EqualityContract { get; }", "System.Object B.P { get; init; }" }, GetProperties(comp, "B").ToTestDisplayStrings()); - AssertEx.Equal(new[] { "System.Type C.EqualityContract { get; }", "System.Object C.P { get; init; }", "System.Object C.I.P { get; }" }, GetProperties(comp, "C").ToTestDisplayStrings()); + + var sealedCopyCtor = comp.GetMembers("Sealed..ctor")[0]; + Assert.Equal("Sealed..ctor(Sealed s)", sealedCopyCtor.ToTestDisplayString()); + Assert.True(sealedCopyCtor.DeclaredAccessibility == Accessibility.Internal); + + var unsealedCopyCtor = comp.GetMembers("Unsealed..ctor")[0]; + Assert.Equal("Unsealed..ctor(Unsealed s)", unsealedCopyCtor.ToTestDisplayString()); + Assert.True(unsealedCopyCtor.DeclaredAccessibility == Accessibility.Internal); } - [Fact] - public void Inheritance_29() + [Fact, WorkItem(44902, "https://github.com/dotnet/roslyn/issues/44902")] + public void CopyCtor_BaseHasRefKind() { - var sourceA = -@"Public Class A - Public Property P(o As Object) As Object - Get - Return Nothing - End Get - Set - End Set - End Property - Public Property Q(x As Object, y As Object) As Object - Get - Return Nothing - End Get - Set - End Set - End Property -End Class + var source = +@"public record B(int i) +{ + public B(ref B b) => throw null; // 1, not recognized as copy constructor +} +public record C(int j) : B(1) +{ + internal C(C c) : base(c) + { + } +} "; - var compA = CreateVisualBasicCompilation(sourceA); - compA.VerifyDiagnostics(); - var refA = compA.EmitToImageReference(); + var comp = CreateCompilation(source); + comp.VerifyDiagnostics( + // (3,12): error CS8862: A constructor declared in a record with parameters must have 'this' constructor initializer. + // public B(ref B b) => throw null; // 1, not recognized as copy constructor + Diagnostic(ErrorCode.ERR_UnexpectedOrMissingConstructorInitializerInRecord, "B").WithLocation(3, 12) + ); + } - var sourceB = -@"record B(object P, object Q) : A + [Fact, WorkItem(44902, "https://github.com/dotnet/roslyn/issues/44902")] + public void CopyCtor_BaseHasRefKind_WithThisInitializer() + { + var source = +@"public record B(int i) { - object P { get; } -}"; - var compB = CreateCompilation(new[] { sourceB, IsExternalInitTypeDefinition }, references: new[] { refA }, parseOptions: TestOptions.RegularPreview); - compB.VerifyDiagnostics( - // (1,8): error CS8867: No accessible copy constructor found in base type 'A'. - // record B(object P, object Q) : A - Diagnostic(ErrorCode.ERR_NoCopyConstructorInBaseType, "B").WithArguments("A").WithLocation(1, 8), - // (1,32): error CS8864: Records may only inherit from object or another record - // record B(object P, object Q) : A - Diagnostic(ErrorCode.ERR_BadRecordBase, "A").WithLocation(1, 32) - ); + public B(ref B b) : this(0) => throw null; // 1, not recognized as copy constructor +} +public record C(int j) : B(1) +{ + internal C(C c) : base(c) + { + } +} +"; + var comp = CreateCompilation(source); + comp.VerifyDiagnostics(); - var actualMembers = GetProperties(compB, "B").ToTestDisplayStrings(); + var actualMembers = comp.GetMember("B").GetMembers().Where(m => m.Name == ".ctor").ToTestDisplayStrings(); var expectedMembers = new[] { - "System.Type B.EqualityContract { get; }", - "System.Object B.Q { get; init; }", - "System.Object B.P { get; }", + "B..ctor(System.Int32 i)", + "B..ctor(ref B b)", + "B..ctor(B )" }; AssertEx.Equal(expectedMembers, actualMembers); } - [Fact] - public void Inheritance_30() + [Fact, WorkItem(44902, "https://github.com/dotnet/roslyn/issues/44902")] + public void CopyCtor_WithPrivateField() { - var sourceA = -@"Public Class A - Public ReadOnly Overloads Property P() As Object - Get - Return Nothing - End Get - End Property - Public ReadOnly Overloads Property P(o As Object) As Object - Get - Return Nothing - End Get - End Property - Public Overloads Property Q(o As Object) As Object - Get - Return Nothing - End Get - Set - End Set - End Property - Public Overloads Property Q() As Object - Get - Return Nothing - End Get - Set - End Set - End Property -End Class -"; - var compA = CreateVisualBasicCompilation(sourceA); - compA.VerifyDiagnostics(); - var refA = compA.EmitToImageReference(); - - var sourceB = -@"record B(object P, object Q) : A + var source = +@"public record B(object N1, object N2) { + private int field1 = 100; + public int GetField1() => field1; +} +public record C(object P1, object P2) : B(3, 4) +{ + private int field2 = 200; + public int GetField2() => field2; + + static void Main() + { + var c1 = new C(1, 2); + var c2 = new C(c1); + System.Console.Write((c2.P1, c2.P2, c2.N1, c2.N2, c2.GetField1(), c2.GetField2())); + } }"; - var compB = CreateCompilation(new[] { sourceB, IsExternalInitTypeDefinition }, references: new[] { refA }, parseOptions: TestOptions.RegularPreview); - compB.VerifyDiagnostics( - // (1,8): error CS8867: No accessible copy constructor found in base type 'A'. - // record B(object P, object Q) : A - Diagnostic(ErrorCode.ERR_NoCopyConstructorInBaseType, "B").WithArguments("A").WithLocation(1, 8), - // (1,32): error CS8864: Records may only inherit from object or another record - // record B(object P, object Q) : A - Diagnostic(ErrorCode.ERR_BadRecordBase, "A").WithLocation(1, 32) - ); + var comp = CreateCompilation(new[] { source, IsExternalInitTypeDefinition }, parseOptions: TestOptions.RegularPreview, options: TestOptions.ReleaseExe); + comp.VerifyDiagnostics(); - var actualMembers = GetProperties(compB, "B").ToTestDisplayStrings(); - AssertEx.Equal(new[] { "System.Type B.EqualityContract { get; }" }, actualMembers); + var verifier = CompileAndVerify(comp, expectedOutput: "(1, 2, 3, 4, 100, 200)", verify: ExecutionConditionUtil.IsCoreClr ? Verification.Skipped : Verification.Fails); + verifier.VerifyIL("C..ctor(C)", @" +{ + // Code size 44 (0x2c) + .maxstack 2 + IL_0000: ldarg.0 + IL_0001: ldarg.1 + IL_0002: call ""B..ctor(B)"" + IL_0007: ldarg.0 + IL_0008: ldarg.1 + IL_0009: ldfld ""object C.k__BackingField"" + IL_000e: stfld ""object C.k__BackingField"" + IL_0013: ldarg.0 + IL_0014: ldarg.1 + IL_0015: ldfld ""object C.k__BackingField"" + IL_001a: stfld ""object C.k__BackingField"" + IL_001f: ldarg.0 + IL_0020: ldarg.1 + IL_0021: ldfld ""int C.field2"" + IL_0026: stfld ""int C.field2"" + IL_002b: ret +}"); } - [Fact] - public void Inheritance_31() + [Fact, WorkItem(44902, "https://github.com/dotnet/roslyn/issues/44902")] + public void CopyCtor_MissingInMetadata() { - var sourceA = -@"Public Class A - Public ReadOnly Property P() As Object - Get - Return Nothing - End Get - End Property - Public Property Q(o As Object) As Object - Get - Return Nothing - End Get - Set - End Set - End Property - Public Property R(o As Object) As Object - Get - Return Nothing - End Get - Set - End Set - End Property - Public Sub New(a as A) - End Sub -End Class -Public Class B - Inherits A - Public ReadOnly Overloads Property P(o As Object) As Object - Get - Return Nothing - End Get - End Property - Public Overloads Property Q() As Object - Get - Return Nothing - End Get - Set - End Set - End Property - Public Overloads Property R(x As Object, y As Object) As Object - Get - Return Nothing - End Get - Set - End Set - End Property - Public Sub New(b as B) - MyBase.New(b) - End Sub -End Class + // IL for `public record B { }` + var ilSource = @" +.class public auto ansi beforefieldinit B extends [mscorlib]System.Object +{ + .method public hidebysig specialname newslot virtual instance class B '<>Clone' () cil managed + { + IL_0000: ldnull + IL_0001: throw + } + + .method family hidebysig newslot virtual instance class [mscorlib]System.Type get_EqualityContract () cil managed + { + IL_0000: ldnull + IL_0001: throw + } + + .method public hidebysig virtual instance int32 GetHashCode () cil managed + { + IL_0000: ldnull + IL_0001: throw + } + + .method public hidebysig virtual instance bool Equals ( object '' ) cil managed + { + IL_0000: ldnull + IL_0001: throw + } + + .method public newslot virtual instance bool Equals ( class B '' ) cil managed + { + IL_0000: ldnull + IL_0001: throw + } + + // Removed copy constructor + //.method public hidebysig specialname rtspecialname instance void .ctor ( class B '' ) cil managed + + .method public hidebysig specialname rtspecialname instance void .ctor () cil managed + { + IL_0000: ldnull + IL_0001: throw + } + + .property instance class [mscorlib]System.Type EqualityContract() + { + .get instance class [mscorlib]System.Type B::get_EqualityContract() + } +} "; - var compA = CreateVisualBasicCompilation(sourceA); - compA.VerifyDiagnostics(); - var refA = compA.EmitToImageReference(); + var source = @" +public record C : B { +}"; + var comp = CreateCompilationWithIL(new[] { source, IsExternalInitTypeDefinition }, ilSource: ilSource, parseOptions: TestOptions.RegularPreview); + comp.VerifyDiagnostics( + // (2,15): error CS8867: No accessible copy constructor found in base type 'B'. + // public record C : B { + Diagnostic(ErrorCode.ERR_NoCopyConstructorInBaseType, "C").WithArguments("B").WithLocation(2, 15) + ); - var sourceB = -@"record C(object P, object Q, object R) : B + var source2 = @" +public record C : B { + public C(C c) { } }"; - var compB = CreateCompilation(new[] { sourceB, IsExternalInitTypeDefinition }, references: new[] { refA }, parseOptions: TestOptions.RegularPreview); - compB.VerifyDiagnostics( - // (1,9): error CS7036: There is no argument given that corresponds to the required formal parameter 'b' of 'B.B(B)' - // record C(object P, object Q, object R) : B - Diagnostic(ErrorCode.ERR_NoCorrespondingArgument, "(object P, object Q, object R)").WithArguments("b", "B.B(B)").WithLocation(1, 9), - // (1,42): error CS8864: Records may only inherit from object or another record - // record C(object P, object Q, object R) : B - Diagnostic(ErrorCode.ERR_BadRecordBase, "B").WithLocation(1, 42) - ); + var comp2 = CreateCompilationWithIL(new[] { source2, IsExternalInitTypeDefinition }, ilSource: ilSource, parseOptions: TestOptions.RegularPreview); + comp2.VerifyDiagnostics( + // (4,12): error CS8868: A copy constructor in a record must call a copy constructor of the base, or a parameterless object constructor if the record inherits from object. + // public C(C c) { } + Diagnostic(ErrorCode.ERR_CopyConstructorMustInvokeBaseCopyConstructor, "C").WithLocation(4, 12) + ); + } - var actualMembers = GetProperties(compB, "C").ToTestDisplayStrings(); - var expectedMembers = new[] - { - "System.Type C.EqualityContract { get; }", - "System.Object C.R { get; init; }", - }; - AssertEx.Equal(expectedMembers, actualMembers); + [Fact, WorkItem(44902, "https://github.com/dotnet/roslyn/issues/44902")] + public void CopyCtor_InaccessibleInMetadata() + { + // IL for `public record B { }` + var ilSource = @" +.class public auto ansi beforefieldinit B extends [mscorlib]System.Object +{ + .method public hidebysig specialname newslot virtual instance class B '<>Clone' () cil managed + { + IL_0000: ldnull + IL_0001: throw + } + + .method family hidebysig newslot virtual instance class [mscorlib]System.Type get_EqualityContract () cil managed + { + IL_0000: ldnull + IL_0001: throw + } + + .method public hidebysig virtual instance int32 GetHashCode () cil managed + { + IL_0000: ldnull + IL_0001: throw + } + + .method public hidebysig virtual instance bool Equals ( object '' ) cil managed + { + IL_0000: ldnull + IL_0001: throw + } + + .method public newslot virtual instance bool Equals ( class B '' ) cil managed + { + IL_0000: ldnull + IL_0001: throw + } + + // Inaccessible copy constructor + .method private hidebysig specialname rtspecialname instance void .ctor ( class B '' ) cil managed + { + IL_0000: ldnull + IL_0001: throw + } + + .method public hidebysig specialname rtspecialname instance void .ctor () cil managed + { + IL_0000: ldnull + IL_0001: throw + } + + .property instance class [mscorlib]System.Type EqualityContract() + { + .get instance class [mscorlib]System.Type B::get_EqualityContract() + } +} +"; + var source = @" +public record C : B { +}"; + var comp = CreateCompilationWithIL(new[] { source, IsExternalInitTypeDefinition }, ilSource: ilSource, parseOptions: TestOptions.RegularPreview); + comp.VerifyDiagnostics( + // (2,15): error CS8867: No accessible copy constructor found in base type 'B'. + // public record C : B { + Diagnostic(ErrorCode.ERR_NoCopyConstructorInBaseType, "C").WithArguments("B").WithLocation(2, 15) + ); } [Fact]