diff --git a/src/Compilers/CSharp/Portable/CSharpResources.resx b/src/Compilers/CSharp/Portable/CSharpResources.resx
index 0dc34093a0e1c..8e03ebf86f977 100644
--- a/src/Compilers/CSharp/Portable/CSharpResources.resx
+++ b/src/Compilers/CSharp/Portable/CSharpResources.resx
@@ -6212,7 +6212,7 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ
init-only setters
- A positional record must have both a 'data' modifier and non-empty parameter list
+ A positional record must have a non-empty parameter listThe receiver of a `with` expression must have a non-void type.
diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf
index 264a6876ee59c..a40fba9b77710 100644
--- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf
+++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf
@@ -138,8 +138,8 @@
-
- Poziční záznam musí mít modifikátor data a neprázdný seznam parametrů.
+
+ Poziční záznam musí mít modifikátor data a neprázdný seznam parametrů.
diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf
index 43917bf2dafbc..7aceebcd28eb1 100644
--- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf
+++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf
@@ -138,8 +138,8 @@
-
- Ein positioneller Datensatz muss sowohl einen data-Modifizierer als auch eine nicht leere Parameterliste aufweisen.
+
+ Ein positioneller Datensatz muss sowohl einen data-Modifizierer als auch eine nicht leere Parameterliste aufweisen.
diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf
index 9bc27156d91a6..b11ba3d893ad0 100644
--- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf
+++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf
@@ -138,8 +138,8 @@
-
- Un registro posicional debe tener un modificador "data" y una lista de parámetros no vacía
+
+ Un registro posicional debe tener un modificador "data" y una lista de parámetros no vacía
diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf
index 250dac25b7894..f7bdf54251b38 100644
--- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf
+++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf
@@ -138,8 +138,8 @@
-
- Un enregistrement positionnel doit avoir à la fois un modificateur 'data' et une liste de paramètres non vide
+
+ Un enregistrement positionnel doit avoir à la fois un modificateur 'data' et une liste de paramètres non vide
diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf
index 991508a364e72..88739140a5f59 100644
--- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf
+++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf
@@ -138,8 +138,8 @@
-
- Un record posizionale deve include sia un modificatore 'data' che un elenco di parametri non vuoto
+
+ Un record posizionale deve include sia un modificatore 'data' che un elenco di parametri non vuoto
diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf
index 226489ab90f35..4b85334bc2c9b 100644
--- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf
+++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf
@@ -138,8 +138,8 @@
-
- 位置指定レコードには、'data' 修飾子と空でないパラメーター リストの両方が必要です
+
+ 位置指定レコードには、'data' 修飾子と空でないパラメーター リストの両方が必要です
diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf
index 7f54d5272385f..931b55830f995 100644
--- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf
+++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf
@@ -138,8 +138,8 @@
-
- 위치 레코드에는 'data' 한정자와 비어 있지 않은 매개 변수 목록이 둘 다 있어야 합니다.
+
+ 위치 레코드에는 'data' 한정자와 비어 있지 않은 매개 변수 목록이 둘 다 있어야 합니다.
diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf
index f3a92910ee907..75d1cdc8a54c3 100644
--- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf
+++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf
@@ -138,8 +138,8 @@
-
- Rekord pozycyjny musi mieć zarówno modyfikator „data”, jak i niepustą listę parametrów
+
+ Rekord pozycyjny musi mieć zarówno modyfikator „data”, jak i niepustą listę parametrów
diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf
index 324f851bae83e..709acb7ea93e9 100644
--- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf
+++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf
@@ -138,8 +138,8 @@
-
- Um registro posicional precisa ter um modificador 'data' e uma lista de parâmetros não vazios
+
+ Um registro posicional precisa ter um modificador 'data' e uma lista de parâmetros não vazios
diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf
index 3ffdd5d944674..031628ceca3f3 100644
--- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf
+++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf
@@ -138,8 +138,8 @@
-
- Позиционная запись должна иметь модификатор "data" и непустой список параметров.
+
+ Позиционная запись должна иметь модификатор "data" и непустой список параметров.
diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf
index 9d89405eaecba..6d534b54aa4ef 100644
--- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf
+++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf
@@ -138,8 +138,8 @@
-
- Konumsal bir kaydın hem 'data' değiştiricisi hem de boş olmayan bir parametre listesi olmalıdır
+
+ Konumsal bir kaydın hem 'data' değiştiricisi hem de boş olmayan bir parametre listesi olmalıdır
diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf
index 2bc01e35e4bcf..2081ce715b081 100644
--- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf
+++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf
@@ -138,8 +138,8 @@
-
- 位置记录必须同时具有 "data" 修饰符和非空参数列表
+
+ 位置记录必须同时具有 "data" 修饰符和非空参数列表
diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf
index 04884e12b25e8..7ad3d8242de9e 100644
--- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf
+++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf
@@ -138,8 +138,8 @@
-
- 位置記錄必須同時具有 'data' 修飾元及非空白的參數清單
+
+ 位置記錄必須同時具有 'data' 修飾元及非空白的參數清單
diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/RecordTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/RecordTests.cs
index c773704ed041d..f83cc1df04088 100644
--- a/src/Compilers/CSharp/Test/Semantic/Semantics/RecordTests.cs
+++ b/src/Compilers/CSharp/Test/Semantic/Semantics/RecordTests.cs
@@ -41,7 +41,7 @@ private CompilationVerifier CompileAndVerify(
// init-only is unverifiable
verify: Verification.Skipped);
- [Fact]
+ [Fact, WorkItem(45900, "https://github.com/dotnet/roslyn/issues/45900")]
public void RecordLanguageVersion()
{
var src1 = @"
@@ -151,6 +151,86 @@ record Point(int x, int y);
comp.VerifyDiagnostics();
}
+ [Fact, WorkItem(45900, "https://github.com/dotnet/roslyn/issues/45900")]
+ public void RecordLanguageVersion_Nested()
+ {
+ var src1 = @"
+class C
+{
+ class Point(int x, int y);
+}
+";
+ var src2 = @"
+class D
+{
+ record Point { }
+}
+";
+ var src3 = @"
+class E
+{
+ record Point(int x, int y);
+}
+";
+ var comp = CreateCompilation(src1, parseOptions: TestOptions.Regular8);
+ comp.VerifyDiagnostics(
+ // (4,16): error CS1514: { expected
+ // class Point(int x, int y);
+ Diagnostic(ErrorCode.ERR_LbraceExpected, "(").WithLocation(4, 16),
+ // (4,16): error CS1513: } expected
+ // class Point(int x, int y);
+ Diagnostic(ErrorCode.ERR_RbraceExpected, "(").WithLocation(4, 16),
+ // (4,30): error CS1519: Invalid token ';' in class, struct, or interface member declaration
+ // class Point(int x, int y);
+ Diagnostic(ErrorCode.ERR_InvalidMemberDecl, ";").WithArguments(";").WithLocation(4, 30),
+ // (4,30): error CS1519: Invalid token ';' in class, struct, or interface member declaration
+ // class Point(int x, int y);
+ Diagnostic(ErrorCode.ERR_InvalidMemberDecl, ";").WithArguments(";").WithLocation(4, 30)
+ );
+
+ comp = CreateCompilation(src2, parseOptions: TestOptions.Regular8);
+ comp.VerifyDiagnostics(
+ // (4,5): error CS0246: The type or namespace name 'record' could not be found (are you missing a using directive or an assembly reference?)
+ // record Point { }
+ Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "record").WithArguments("record").WithLocation(4, 5),
+ // (4,12): error CS0548: 'D.Point': property or indexer must have at least one accessor
+ // record Point { }
+ Diagnostic(ErrorCode.ERR_PropertyWithNoAccessors, "Point").WithArguments("D.Point").WithLocation(4, 12)
+ );
+
+ comp = CreateCompilation(src3, parseOptions: TestOptions.Regular8);
+ comp.VerifyDiagnostics(
+ // (4,5): error CS0246: The type or namespace name 'record' could not be found (are you missing a using directive or an assembly reference?)
+ // record Point(int x, int y);
+ Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "record").WithArguments("record").WithLocation(4, 5),
+ // (4,12): error CS0501: 'E.Point(int, int)' must declare a body because it is not marked abstract, extern, or partial
+ // record Point(int x, int y);
+ Diagnostic(ErrorCode.ERR_ConcreteMissingBody, "Point").WithArguments("E.Point(int, int)").WithLocation(4, 12)
+ );
+
+ comp = CreateCompilation(src1);
+ comp.VerifyDiagnostics(
+ // (4,16): error CS1514: { expected
+ // class Point(int x, int y);
+ Diagnostic(ErrorCode.ERR_LbraceExpected, "(").WithLocation(4, 16),
+ // (4,16): error CS1513: } expected
+ // class Point(int x, int y);
+ Diagnostic(ErrorCode.ERR_RbraceExpected, "(").WithLocation(4, 16),
+ // (4,30): error CS1519: Invalid token ';' in class, struct, or interface member declaration
+ // class Point(int x, int y);
+ Diagnostic(ErrorCode.ERR_InvalidMemberDecl, ";").WithArguments(";").WithLocation(4, 30),
+ // (4,30): error CS1519: Invalid token ';' in class, struct, or interface member declaration
+ // class Point(int x, int y);
+ Diagnostic(ErrorCode.ERR_InvalidMemberDecl, ";").WithArguments(";").WithLocation(4, 30)
+ );
+
+ comp = CreateCompilation(src2);
+ comp.VerifyDiagnostics();
+
+ comp = CreateCompilation(src3);
+ comp.VerifyDiagnostics();
+ }
+
[Fact, WorkItem(46123, "https://github.com/dotnet/roslyn/issues/46123")]
public void IncompletePositionalRecord()
{
@@ -410,7 +490,7 @@ public static void M()
}
[Fact]
- public void PartialRecordMixedWithClass()
+ public void PartialRecord_MixedWithClass()
{
var src = @"
partial record C(int X, int Y)
@@ -428,6 +508,43 @@ partial class C
);
}
+ [Fact]
+ public void PartialRecord_ParametersInScopeOfBothParts()
+ {
+ var src = @"
+var c = new C(2);
+System.Console.Write((c.P1, c.P2));
+
+public partial record C(int X)
+{
+ public int P1 { get; set; } = X;
+}
+public partial record C
+{
+ public int P2 { get; set; } = X;
+}
+";
+ var comp = CreateCompilation(new[] { src, IsExternalInitTypeDefinition }, options: TestOptions.DebugExe, parseOptions: TestOptions.RegularPreview);
+ CompileAndVerify(comp, expectedOutput: "(2, 2)", verify: Verification.Skipped /* init-only */).VerifyDiagnostics();
+ }
+
+ [Fact]
+ public void RecordInsideGenericType()
+ {
+ var src = @"
+var c = new C.Nested(2);
+System.Console.Write(c.T);
+
+public class C
+{
+ public record Nested(T T);
+}
+";
+ var comp = CreateCompilation(new[] { src, IsExternalInitTypeDefinition }, options: TestOptions.DebugExe, parseOptions: TestOptions.RegularPreview);
+ comp.VerifyDiagnostics();
+ CompileAndVerify(comp, expectedOutput: "2", verify: Verification.Skipped /* init-only */);
+ }
+
[Fact]
public void RecordProperties_01()
{
@@ -700,7 +817,7 @@ record C(); ";
var comp = CreateCompilation(src);
comp.VerifyEmitDiagnostics(
- // (2,9): error CS8850: A positional record must have both a 'data' modifier and non-empty parameter list
+ // (2,9): error CS8850: A positional record must have a non-empty parameter list
// record C();
Diagnostic(ErrorCode.ERR_BadRecordDeclaration, "()").WithLocation(2, 9)
);
@@ -1465,6 +1582,204 @@ public static void Main()
);
}
+ [Fact]
+ public void WithExpr24_Dynamic()
+ {
+ var src = @"
+record C(int X)
+{
+ public static void Main()
+ {
+ dynamic c = new C(1);
+ var x = c with { X = 2 };
+ }
+}";
+ var comp = CreateCompilation(src);
+ comp.VerifyDiagnostics(
+ // (7,17): error CS8858: The receiver type 'dynamic' is not a valid record type.
+ // var x = c with { X = 2 };
+ Diagnostic(ErrorCode.ERR_NoSingleCloneMethod, "c").WithArguments("dynamic").WithLocation(7, 17)
+ );
+ }
+
+ [Fact, WorkItem(46427, "https://github.com/dotnet/roslyn/issues/46427")]
+ public void WithExpr25_TypeParameterWithRecordConstraint()
+ {
+ var src = @"
+record R(int X);
+
+class C
+{
+ public static void M(T t) where T : R
+ {
+ _ = t with { X = 2 };
+ }
+}";
+ var comp = CreateCompilation(src);
+ comp.VerifyDiagnostics(
+ // (8,13): error CS8858: The receiver type 'T' is not a valid record type.
+ // _ = t with { X = 2 };
+ Diagnostic(ErrorCode.ERR_NoSingleCloneMethod, "t").WithArguments("T").WithLocation(8, 13)
+ );
+ }
+
+ [Fact, WorkItem(46427, "https://github.com/dotnet/roslyn/issues/46427")]
+ public void WithExpr26_TypeParameterWithRecordAndInterfaceConstraint()
+ {
+ var src = @"
+record R(int X);
+interface I { int Property { get; set; } }
+
+class C
+{
+ public static void M(T t) where T : R, I
+ {
+ _ = t with { X = 2, Property = 3 };
+ }
+}";
+ var comp = CreateCompilation(src);
+ comp.VerifyDiagnostics(
+ // (9,13): error CS8858: The receiver type 'T' is not a valid record type.
+ // _ = t with { X = 2, Property = 3 };
+ Diagnostic(ErrorCode.ERR_NoSingleCloneMethod, "t").WithArguments("T").WithLocation(9, 13)
+ );
+ }
+
+ [Fact]
+ public void WithExpr27_InExceptionFilter()
+ {
+ var src = @"
+var r = new R(1);
+
+try
+{
+ throw new System.Exception();
+}
+catch (System.Exception) when ((r = r with { X = 2 }).X == 2)
+{
+ System.Console.Write(""RAN "");
+ System.Console.Write(r.X);
+}
+
+record R(int X);
+";
+ var comp = CreateCompilation(new[] { src, IsExternalInitTypeDefinition }, options: TestOptions.DebugExe, parseOptions: TestOptions.RegularPreview);
+ comp.VerifyDiagnostics();
+ CompileAndVerify(comp, expectedOutput: "RAN 2", verify: Verification.Skipped /* init-only */);
+ }
+
+ [Fact]
+ public void WithExpr28_WithAwait()
+ {
+ var src = @"
+var r = new R(1);
+r = r with { X = await System.Threading.Tasks.Task.FromResult(42) };
+System.Console.Write(r.X);
+
+record R(int X);
+";
+ var comp = CreateCompilation(new[] { src, IsExternalInitTypeDefinition }, options: TestOptions.DebugExe, parseOptions: TestOptions.RegularPreview);
+ comp.VerifyDiagnostics();
+ CompileAndVerify(comp, expectedOutput: "42", verify: Verification.Skipped /* init-only */);
+
+ var tree = comp.SyntaxTrees[0];
+ var model = comp.GetSemanticModel(tree, ignoreAccessibility: false);
+ var x = tree.GetRoot().DescendantNodes().OfType().Last().Left;
+ Assert.Equal("X", x.ToString());
+ var symbol = model.GetSymbolInfo(x).Symbol;
+ Assert.Equal("System.Int32 R.X { get; init; }", symbol.ToTestDisplayString());
+ }
+
+ [Fact, WorkItem(46465, "https://github.com/dotnet/roslyn/issues/46465")]
+ public void WithExpr29_DisallowedAsExpressionStatement()
+ {
+ var src = @"
+record R(int X)
+{
+ void M()
+ {
+ var r = new R(1);
+ r with { X = 2 };
+ }
+}
+";
+ // Note: we didn't parse the `with` as a `with` expression, but as a broken local declaration
+ // Tracked by https://github.com/dotnet/roslyn/issues/46465
+ var comp = CreateCompilation(src);
+ comp.VerifyEmitDiagnostics(
+ // (7,9): error CS0118: 'r' is a variable but is used like a type
+ // r with { X = 2 };
+ Diagnostic(ErrorCode.ERR_BadSKknown, "r").WithArguments("r", "variable", "type").WithLocation(7, 9),
+ // (7,11): warning CS0168: The variable 'with' is declared but never used
+ // r with { X = 2 };
+ Diagnostic(ErrorCode.WRN_UnreferencedVar, "with").WithArguments("with").WithLocation(7, 11),
+ // (7,16): error CS1002: ; expected
+ // r with { X = 2 };
+ Diagnostic(ErrorCode.ERR_SemicolonExpected, "{").WithLocation(7, 16),
+ // (7,18): error CS8852: Init-only property or indexer 'R.X' can only be assigned in an object initializer, or on 'this' or 'base' in an instance constructor or an 'init' accessor.
+ // r with { X = 2 };
+ Diagnostic(ErrorCode.ERR_AssignmentInitOnly, "X").WithArguments("R.X").WithLocation(7, 18),
+ // (7,24): error CS1002: ; expected
+ // r with { X = 2 };
+ Diagnostic(ErrorCode.ERR_SemicolonExpected, "}").WithLocation(7, 24)
+ );
+ }
+
+ [Fact]
+ public void TypeNamedRecord()
+ {
+ var src = @"
+class record { }
+
+class C
+{
+ record M(record r) => r;
+}";
+ var comp = CreateCompilation(src);
+ comp.VerifyDiagnostics(
+ // (6,24): error CS1514: { expected
+ // record M(record r) => r;
+ Diagnostic(ErrorCode.ERR_LbraceExpected, "=>").WithLocation(6, 24),
+ // (6,24): error CS1513: } expected
+ // record M(record r) => r;
+ Diagnostic(ErrorCode.ERR_RbraceExpected, "=>").WithLocation(6, 24),
+ // (6,24): error CS1519: Invalid token '=>' in class, struct, or interface member declaration
+ // record M(record r) => r;
+ Diagnostic(ErrorCode.ERR_InvalidMemberDecl, "=>").WithArguments("=>").WithLocation(6, 24),
+ // (6,28): error CS1519: Invalid token ';' in class, struct, or interface member declaration
+ // record M(record r) => r;
+ Diagnostic(ErrorCode.ERR_InvalidMemberDecl, ";").WithArguments(";").WithLocation(6, 28),
+ // (6,28): error CS1519: Invalid token ';' in class, struct, or interface member declaration
+ // record M(record r) => r;
+ Diagnostic(ErrorCode.ERR_InvalidMemberDecl, ";").WithArguments(";").WithLocation(6, 28)
+ );
+ }
+
+ [Fact]
+ public void TypeNamedRecord_EscapedReturnType()
+ {
+ var src = @"
+class record { }
+
+class C
+{
+ @record M(record r)
+ {
+ System.Console.Write(""RAN"");
+ return r;
+ }
+
+ public static void Main()
+ {
+ var c = new C();
+ _ = c.M(new record());
+ }
+}";
+ var comp = CreateCompilation(src, options: TestOptions.DebugExe);
+ comp.VerifyEmitDiagnostics();
+ CompileAndVerify(comp, expectedOutput: "RAN");
+ }
+
[Fact, WorkItem(45591, "https://github.com/dotnet/roslyn/issues/45591")]
public void Clone_DisallowedInSource()
{
@@ -9949,7 +10264,7 @@ static void Main()
";
var comp = CreateCompilation(source);
comp.VerifyDiagnostics(
- // (2,9): error CS8850: A positional record must have both a 'data' modifier and non-empty parameter list
+ // (2,9): error CS8850: A positional record must have a non-empty parameter list
// record C()
Diagnostic(ErrorCode.ERR_BadRecordDeclaration, "()").WithLocation(2, 9));
@@ -18177,6 +18492,34 @@ record B : IEquatable>
Diagnostic(ErrorCode.ERR_UnifyingInterfaceInstantiations, "B").WithArguments("A.B", "System.IEquatable.B>", "System.IEquatable.B>").WithLocation(4, 12));
}
+ [Fact]
+ public void InterfaceImplementation()
+ {
+ var source = @"
+interface I
+{
+ int P1 { get; init; }
+ int P2 { get; init; }
+ int P3 { get; set; }
+}
+record R(int P1) : I
+{
+ public int P2 { get; init; }
+ int I.P3 { get; set; }
+
+ public static void Main()
+ {
+ I r = new R(42) { P2 = 43 };
+ r.P3 = 44;
+ System.Console.Write((r.P1, r.P2, r.P3));
+ }
+}
+";
+ var comp = CreateCompilation(new[] { source, IsExternalInitTypeDefinition }, parseOptions: TestOptions.RegularPreview, options: TestOptions.DebugExe);
+ comp.VerifyEmitDiagnostics();
+ CompileAndVerify(comp, expectedOutput: "(42, 43, 44)", verify: Verification.Skipped /* init-only */);
+ }
+
[Fact]
public void Initializers_01()
{
@@ -19119,6 +19462,28 @@ protected C(C other)
);
}
+ [Fact]
+ public void AttributesOnPrimaryConstructorParameters_09_CallerMemberName()
+ {
+ string source = @"
+using System.Runtime.CompilerServices;
+record R([CallerMemberName] string S = """");
+
+class C
+{
+ public static void Main()
+ {
+ var r = new R();
+ System.Console.Write(r.S);
+ }
+}
+";
+ var comp = CompileAndVerify(new[] { source, IsExternalInitTypeDefinition }, expectedOutput: "Main",
+ parseOptions: TestOptions.RegularPreview, options: TestOptions.DebugExe, verify: Verification.Skipped /* init-only */);
+
+ comp.VerifyDiagnostics();
+ }
+
[Fact]
public void RecordWithConstraints_NullableWarning()
{
diff --git a/src/Compilers/CSharp/Test/Symbol/Symbols/Source/RecordTests.cs b/src/Compilers/CSharp/Test/Symbol/Symbols/Source/RecordTests.cs
index 49b26f6790879..456a890d265d4 100644
--- a/src/Compilers/CSharp/Test/Symbol/Symbols/Source/RecordTests.cs
+++ b/src/Compilers/CSharp/Test/Symbol/Symbols/Source/RecordTests.cs
@@ -1176,6 +1176,21 @@ .maxstack 2
}");
}
+ [Fact]
+ public void PartialTypes_04_PartialBeforeModifiers()
+ {
+ var src = @"
+partial public record C
+{
+}
+";
+ CreateCompilation(src).VerifyDiagnostics(
+ // (2,1): error CS0267: The 'partial' modifier can only appear immediately before 'class', 'record', 'struct', 'interface', or 'void'
+ // partial public record C
+ Diagnostic(ErrorCode.ERR_PartialMisplaced, "partial").WithLocation(2, 1)
+ );
+ }
+
[Fact]
public void DataClassAndStruct()
{