未验证 提交 00c35693 编写于 作者: J Julien Couvreur 提交者: GitHub

Add some tests from records test plan (#46466)

上级 06c9048f
......@@ -6212,7 +6212,7 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ
<value>init-only setters</value>
</data>
<data name="ERR_BadRecordDeclaration" xml:space="preserve">
<value>A positional record must have both a 'data' modifier and non-empty parameter list</value>
<value>A positional record must have a non-empty parameter list</value>
</data>
<data name="ERR_InvalidWithReceiverType" xml:space="preserve">
<value>The receiver of a `with` expression must have a non-void type.</value>
......
......@@ -138,8 +138,8 @@
<note />
</trans-unit>
<trans-unit id="ERR_BadRecordDeclaration">
<source>A positional record must have both a 'data' modifier and non-empty parameter list</source>
<target state="translated">Poziční záznam musí mít modifikátor data a neprázdný seznam parametrů.</target>
<source>A positional record must have a non-empty parameter list</source>
<target state="needs-review-translation">Poziční záznam musí mít modifikátor data a neprázdný seznam parametrů.</target>
<note />
</trans-unit>
<trans-unit id="ERR_BadRecordMemberForPositionalParameter">
......
......@@ -138,8 +138,8 @@
<note />
</trans-unit>
<trans-unit id="ERR_BadRecordDeclaration">
<source>A positional record must have both a 'data' modifier and non-empty parameter list</source>
<target state="translated">Ein positioneller Datensatz muss sowohl einen data-Modifizierer als auch eine nicht leere Parameterliste aufweisen.</target>
<source>A positional record must have a non-empty parameter list</source>
<target state="needs-review-translation">Ein positioneller Datensatz muss sowohl einen data-Modifizierer als auch eine nicht leere Parameterliste aufweisen.</target>
<note />
</trans-unit>
<trans-unit id="ERR_BadRecordMemberForPositionalParameter">
......
......@@ -138,8 +138,8 @@
<note />
</trans-unit>
<trans-unit id="ERR_BadRecordDeclaration">
<source>A positional record must have both a 'data' modifier and non-empty parameter list</source>
<target state="translated">Un registro posicional debe tener un modificador "data" y una lista de parámetros no vacía</target>
<source>A positional record must have a non-empty parameter list</source>
<target state="needs-review-translation">Un registro posicional debe tener un modificador "data" y una lista de parámetros no vacía</target>
<note />
</trans-unit>
<trans-unit id="ERR_BadRecordMemberForPositionalParameter">
......
......@@ -138,8 +138,8 @@
<note />
</trans-unit>
<trans-unit id="ERR_BadRecordDeclaration">
<source>A positional record must have both a 'data' modifier and non-empty parameter list</source>
<target state="translated">Un enregistrement positionnel doit avoir à la fois un modificateur 'data' et une liste de paramètres non vide</target>
<source>A positional record must have a non-empty parameter list</source>
<target state="needs-review-translation">Un enregistrement positionnel doit avoir à la fois un modificateur 'data' et une liste de paramètres non vide</target>
<note />
</trans-unit>
<trans-unit id="ERR_BadRecordMemberForPositionalParameter">
......
......@@ -138,8 +138,8 @@
<note />
</trans-unit>
<trans-unit id="ERR_BadRecordDeclaration">
<source>A positional record must have both a 'data' modifier and non-empty parameter list</source>
<target state="translated">Un record posizionale deve include sia un modificatore 'data' che un elenco di parametri non vuoto</target>
<source>A positional record must have a non-empty parameter list</source>
<target state="needs-review-translation">Un record posizionale deve include sia un modificatore 'data' che un elenco di parametri non vuoto</target>
<note />
</trans-unit>
<trans-unit id="ERR_BadRecordMemberForPositionalParameter">
......
......@@ -138,8 +138,8 @@
<note />
</trans-unit>
<trans-unit id="ERR_BadRecordDeclaration">
<source>A positional record must have both a 'data' modifier and non-empty parameter list</source>
<target state="translated">位置指定レコードには、'data' 修飾子と空でないパラメーター リストの両方が必要です</target>
<source>A positional record must have a non-empty parameter list</source>
<target state="needs-review-translation">位置指定レコードには、'data' 修飾子と空でないパラメーター リストの両方が必要です</target>
<note />
</trans-unit>
<trans-unit id="ERR_BadRecordMemberForPositionalParameter">
......
......@@ -138,8 +138,8 @@
<note />
</trans-unit>
<trans-unit id="ERR_BadRecordDeclaration">
<source>A positional record must have both a 'data' modifier and non-empty parameter list</source>
<target state="translated">위치 레코드에는 'data' 한정자와 비어 있지 않은 매개 변수 목록이 둘 다 있어야 합니다.</target>
<source>A positional record must have a non-empty parameter list</source>
<target state="needs-review-translation">위치 레코드에는 'data' 한정자와 비어 있지 않은 매개 변수 목록이 둘 다 있어야 합니다.</target>
<note />
</trans-unit>
<trans-unit id="ERR_BadRecordMemberForPositionalParameter">
......
......@@ -138,8 +138,8 @@
<note />
</trans-unit>
<trans-unit id="ERR_BadRecordDeclaration">
<source>A positional record must have both a 'data' modifier and non-empty parameter list</source>
<target state="translated">Rekord pozycyjny musi mieć zarówno modyfikator „data”, jak i niepustą listę parametrów</target>
<source>A positional record must have a non-empty parameter list</source>
<target state="needs-review-translation">Rekord pozycyjny musi mieć zarówno modyfikator „data”, jak i niepustą listę parametrów</target>
<note />
</trans-unit>
<trans-unit id="ERR_BadRecordMemberForPositionalParameter">
......
......@@ -138,8 +138,8 @@
<note />
</trans-unit>
<trans-unit id="ERR_BadRecordDeclaration">
<source>A positional record must have both a 'data' modifier and non-empty parameter list</source>
<target state="translated">Um registro posicional precisa ter um modificador 'data' e uma lista de parâmetros não vazios</target>
<source>A positional record must have a non-empty parameter list</source>
<target state="needs-review-translation">Um registro posicional precisa ter um modificador 'data' e uma lista de parâmetros não vazios</target>
<note />
</trans-unit>
<trans-unit id="ERR_BadRecordMemberForPositionalParameter">
......
......@@ -138,8 +138,8 @@
<note />
</trans-unit>
<trans-unit id="ERR_BadRecordDeclaration">
<source>A positional record must have both a 'data' modifier and non-empty parameter list</source>
<target state="translated">Позиционная запись должна иметь модификатор "data" и непустой список параметров.</target>
<source>A positional record must have a non-empty parameter list</source>
<target state="needs-review-translation">Позиционная запись должна иметь модификатор "data" и непустой список параметров.</target>
<note />
</trans-unit>
<trans-unit id="ERR_BadRecordMemberForPositionalParameter">
......
......@@ -138,8 +138,8 @@
<note />
</trans-unit>
<trans-unit id="ERR_BadRecordDeclaration">
<source>A positional record must have both a 'data' modifier and non-empty parameter list</source>
<target state="translated">Konumsal bir kaydın hem 'data' değiştiricisi hem de boş olmayan bir parametre listesi olmalıdır</target>
<source>A positional record must have a non-empty parameter list</source>
<target state="needs-review-translation">Konumsal bir kaydın hem 'data' değiştiricisi hem de boş olmayan bir parametre listesi olmalıdır</target>
<note />
</trans-unit>
<trans-unit id="ERR_BadRecordMemberForPositionalParameter">
......
......@@ -138,8 +138,8 @@
<note />
</trans-unit>
<trans-unit id="ERR_BadRecordDeclaration">
<source>A positional record must have both a 'data' modifier and non-empty parameter list</source>
<target state="translated">位置记录必须同时具有 "data" 修饰符和非空参数列表</target>
<source>A positional record must have a non-empty parameter list</source>
<target state="needs-review-translation">位置记录必须同时具有 "data" 修饰符和非空参数列表</target>
<note />
</trans-unit>
<trans-unit id="ERR_BadRecordMemberForPositionalParameter">
......
......@@ -138,8 +138,8 @@
<note />
</trans-unit>
<trans-unit id="ERR_BadRecordDeclaration">
<source>A positional record must have both a 'data' modifier and non-empty parameter list</source>
<target state="translated">位置記錄必須同時具有 'data' 修飾元及非空白的參數清單</target>
<source>A positional record must have a non-empty parameter list</source>
<target state="needs-review-translation">位置記錄必須同時具有 'data' 修飾元及非空白的參數清單</target>
<note />
</trans-unit>
<trans-unit id="ERR_BadRecordMemberForPositionalParameter">
......
......@@ -41,7 +41,7 @@ private static CSharpCompilation CreateCompilation(CSharpTestSource source)
// 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 @@ class 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<int>.Nested(2);
System.Console.Write(c.T);
public class C<T>
{
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 @@ public void EmptyRecord()
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 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 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<AssignmentExpressionSyntax>().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 @@ class A<T>
Diagnostic(ErrorCode.ERR_UnifyingInterfaceInstantiations, "B").WithArguments("A<T>.B<U>", "System.IEquatable<A<T>.B<T>>", "System.IEquatable<A<T>.B<U>>").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<T> 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()
{
......
......@@ -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()
{
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册