diff --git a/src/Compilers/CSharp/Test/Emit3/FieldKeywordTests.cs b/src/Compilers/CSharp/Test/Emit3/FieldKeywordTests.cs index b0ee7260f1759..6e7364596a931 100644 --- a/src/Compilers/CSharp/Test/Emit3/FieldKeywordTests.cs +++ b/src/Compilers/CSharp/Test/Emit3/FieldKeywordTests.cs @@ -636,6 +636,10 @@ interface I { static object P1 { get; set { _ = field; } } static object P2 { get { return field; } set; } + static object P3 { get; set { } } + static object P4 { get { return null; } set; } + static object P5 { get; } + static object P6 { get; set; } } """; @@ -658,43 +662,78 @@ interface I Diagnostic(ErrorCode.ERR_FeatureInPreview, "P2").WithArguments("field keyword").WithLocation(4, 19), // (4,37): error CS0103: The name 'field' does not exist in the current context // static object P2 { get { return field; } set; } - Diagnostic(ErrorCode.ERR_NameNotInContext, "field").WithArguments("field").WithLocation(4, 37)); + Diagnostic(ErrorCode.ERR_NameNotInContext, "field").WithArguments("field").WithLocation(4, 37), + // (5,19): error CS8652: The feature 'field keyword' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // static object P3 { get; set { } } + Diagnostic(ErrorCode.ERR_FeatureInPreview, "P3").WithArguments("field keyword").WithLocation(5, 19), + // (6,19): error CS8652: The feature 'field keyword' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // static object P4 { get { return null; } set; } + Diagnostic(ErrorCode.ERR_FeatureInPreview, "P4").WithArguments("field keyword").WithLocation(6, 19)); } else { var verifier = CompileAndVerify(comp, verify: Verification.Skipped); verifier.VerifyIL("I.P1.get", """ - { - // Code size 6 (0x6) - .maxstack 1 - IL_0000: ldsfld "object I.k__BackingField" - IL_0005: ret - } - """); + { + // Code size 6 (0x6) + .maxstack 1 + IL_0000: ldsfld "object I.k__BackingField" + IL_0005: ret + } + """); verifier.VerifyIL("I.P2.set", """ - { - // Code size 7 (0x7) - .maxstack 1 - IL_0000: ldarg.0 - IL_0001: stsfld "object I.k__BackingField" - IL_0006: ret - } - """); + { + // Code size 7 (0x7) + .maxstack 1 + IL_0000: ldarg.0 + IL_0001: stsfld "object I.k__BackingField" + IL_0006: ret + } + """); + verifier.VerifyIL("I.P5.get", """ + { + // Code size 6 (0x6) + .maxstack 1 + IL_0000: ldsfld "object I.k__BackingField" + IL_0005: ret + } + """); + verifier.VerifyIL("I.P6.set", """ + { + // Code size 7 (0x7) + .maxstack 1 + IL_0000: ldarg.0 + IL_0001: stsfld "object I.k__BackingField" + IL_0006: ret + } + """); } - var actualMembers = comp.GetMember("I").GetMembers().ToTestDisplayStrings(); - var expectedMembers = new[] - { - "System.Object I.k__BackingField", - "System.Object I.P1 { get; set; }", - "System.Object I.P1.get", - "void I.P1.set", - "System.Object I.k__BackingField", - "System.Object I.P2 { get; set; }", - "System.Object I.P2.get", - "void I.P2.set", - }; - AssertEx.Equal(expectedMembers, actualMembers); + var containingType = comp.GetMember("I"); + var actualFields = containingType.GetMembers().OfType().ToImmutableArray(); + var expectedFields = new[] + { + "System.Object I.k__BackingField", + "System.Object I.k__BackingField", + "System.Object I.k__BackingField", + "System.Object I.k__BackingField", + "System.Object I.k__BackingField", + "System.Object I.k__BackingField", + }; + AssertEx.Equal(expectedFields, actualFields.ToTestDisplayStrings()); + + var actualProperties = containingType.GetMembers().OfType().ToImmutableArray(); + Assert.Equal(6, actualProperties.Length); + Assert.True(actualProperties[0] is SourcePropertySymbol { Name: "P1", IsAutoProperty: true, BackingField: { } }); + Assert.True(actualProperties[1] is SourcePropertySymbol { Name: "P2", IsAutoProperty: true, BackingField: { } }); + Assert.True(actualProperties[2] is SourcePropertySymbol { Name: "P3", IsAutoProperty: true, UsesFieldKeyword: false, BackingField: { } }); + Assert.True(actualProperties[3] is SourcePropertySymbol { Name: "P4", IsAutoProperty: true, UsesFieldKeyword: false, BackingField: { } }); + Assert.True(actualProperties[4] is SourcePropertySymbol { Name: "P5", IsAutoProperty: true, UsesFieldKeyword: false, BackingField: { } }); + Assert.True(actualProperties[5] is SourcePropertySymbol { Name: "P6", IsAutoProperty: true, UsesFieldKeyword: false, BackingField: { } }); + Assert.Equal(languageVersion > LanguageVersion.CSharp13, ((SourcePropertySymbol)actualProperties[0]).UsesFieldKeyword); + Assert.Equal(languageVersion > LanguageVersion.CSharp13, ((SourcePropertySymbol)actualProperties[1]).UsesFieldKeyword); + + VerifyMergedProperties(actualProperties, actualFields); } [Theory] @@ -788,8 +827,6 @@ interface I Assert.True(actualProperties[3] is SourcePropertySymbol { Name: "Q4", IsAutoProperty: true, UsesFieldKeyword: false, BackingField: { } }); Assert.Equal(languageVersion > LanguageVersion.CSharp13, ((SourcePropertySymbol)actualProperties[0]).UsesFieldKeyword); Assert.Equal(languageVersion > LanguageVersion.CSharp13, ((SourcePropertySymbol)actualProperties[1]).UsesFieldKeyword); - Assert.False(((SourcePropertySymbol)actualProperties[2]).UsesFieldKeyword); - Assert.False(((SourcePropertySymbol)actualProperties[3]).UsesFieldKeyword); VerifyMergedProperties(actualProperties, actualFields); } @@ -1133,14 +1170,16 @@ class Program { static void Main() { + foreach (var property in typeof(B).GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static)) + ReportMember(property); foreach (var field in typeof(B).GetFields(BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static)) - ReportField(field); + ReportMember(field); } - static void ReportField(FieldInfo field) + static void ReportMember(MemberInfo member) { - Console.Write("{0}.{1}:", field.DeclaringType.Name, field.Name); - foreach (var obj in field.GetCustomAttributes()) + Console.Write("{0}.{1}:", member.DeclaringType.Name, member.Name); + foreach (var obj in member.GetCustomAttributes()) Console.Write(" {0},", obj.ToString()); Console.WriteLine(); } @@ -1163,6 +1202,18 @@ static void ReportField(FieldInfo field) Diagnostic(ErrorCode.WRN_AttributeLocationOnBadDeclaration, "field").WithArguments("field", "method, param, return").WithLocation(23, 54)); CompileAndVerify(comp, verify: Verification.Skipped, expectedOutput: IncludeExpectedOutput(""" + B.P1: A(0), + B.P2: + B.P3: + B.P4: + B.P5: + B.Q1: A(0), + B.Q2: + B.Q3: + B.Q4: + B.Q5: + B.Q6: + B.Q7: B.k__BackingField: System.Runtime.CompilerServices.CompilerGeneratedAttribute, A(1), B.k__BackingField: System.Runtime.CompilerServices.CompilerGeneratedAttribute, A(3), B.k__BackingField: System.Runtime.CompilerServices.CompilerGeneratedAttribute, @@ -1178,6 +1229,73 @@ static void ReportField(FieldInfo field) """)); } + [Fact] + public void ObsoleteAttribute() + { + string source = $$""" + using System; + using System.Reflection; + class C + { + [Obsolete] public static object P1 { get => field; set { } } + [field: Obsolete] public static object P2 { get => field; set { } } + [Obsolete] public object P3 { get => field; set { } } + [field: Obsolete] public object P4 { get => field; set { } } + } + + class Program + { + static void Main() + { + _ = C.P1; + _ = C.P2; + C.P1 = 1; + C.P2 = 2; + var c = new C(); + _ = c.P3; + _ = c.P4; + c.P3 = 3; + c.P4 = 4; + foreach (var property in typeof(C).GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static)) + ReportMember(property); + foreach (var field in typeof(C).GetFields(BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static)) + ReportMember(field); + } + + static void ReportMember(MemberInfo member) + { + Console.Write("{0}.{1}:", member.DeclaringType.Name, member.Name); + foreach (var obj in member.GetCustomAttributes()) + Console.Write(" {0},", obj.ToString()); + Console.WriteLine(); + } + } + """; + var verifier = CompileAndVerify(source, verify: Verification.Skipped, expectedOutput: """ + C.P1: System.ObsoleteAttribute, + C.P2: + C.P3: System.ObsoleteAttribute, + C.P4: + C.k__BackingField: System.Runtime.CompilerServices.CompilerGeneratedAttribute, + C.k__BackingField: System.Runtime.CompilerServices.CompilerGeneratedAttribute, System.ObsoleteAttribute, + C.k__BackingField: System.Runtime.CompilerServices.CompilerGeneratedAttribute, + C.k__BackingField: System.Runtime.CompilerServices.CompilerGeneratedAttribute, System.ObsoleteAttribute, + """); + verifier.VerifyDiagnostics( + // (15,13): warning CS0612: 'C.P1' is obsolete + // _ = C.P1; + Diagnostic(ErrorCode.WRN_DeprecatedSymbol, "C.P1").WithArguments("C.P1").WithLocation(15, 13), + // (17,9): warning CS0612: 'C.P1' is obsolete + // C.P1 = 1; + Diagnostic(ErrorCode.WRN_DeprecatedSymbol, "C.P1").WithArguments("C.P1").WithLocation(17, 9), + // (20,13): warning CS0612: 'C.P3' is obsolete + // _ = c.P3; + Diagnostic(ErrorCode.WRN_DeprecatedSymbol, "c.P3").WithArguments("C.P3").WithLocation(20, 13), + // (22,9): warning CS0612: 'C.P3' is obsolete + // c.P3 = 3; + Diagnostic(ErrorCode.WRN_DeprecatedSymbol, "c.P3").WithArguments("C.P3").WithLocation(22, 9)); + } + [Theory] [CombinatorialData] public void Initializer_01A([CombinatorialValues("class", "struct", "ref struct", "interface")] string typeKind) @@ -4805,6 +4923,124 @@ public void RefReturning_02(bool useStruct, bool useRefReadOnly) Diagnostic(ErrorCode.ERR_RefPropertyMustHaveGetAccessor, "PI").WithLocation(12, 32)); } + [Fact] + public void PassByReference_01() + { + string source = $$""" + struct S + { + object P1 => F(ref field); + readonly object P2 => F(ref field); + object P3 { readonly get { return F(ref field); } set { } } + readonly object P4 { init { F(ref field); } } + static object F(ref object o) => o; + } + """; + var comp = CreateCompilation(source, targetFramework: TargetFramework.Net80); + comp.VerifyEmitDiagnostics( + // (4,33): error CS0192: A readonly field cannot be used as a ref or out value (except in a constructor) + // readonly object P2 => F(ref field); + Diagnostic(ErrorCode.ERR_RefReadonly, "field").WithLocation(4, 33), + // (5,45): error CS1605: Cannot use 'field' as a ref or out value because it is read-only + // object P3 { readonly get { return F(ref field); } set { } } + Diagnostic(ErrorCode.ERR_RefReadonlyLocal, "field").WithArguments("field").WithLocation(5, 45)); + } + + [Fact] + public void PassByReference_02() + { + string source = $$""" + struct S + { + object P1 => F(in field); + readonly object P2 => F(in field); + object P3 { readonly get { return F(in field); } set { } } + readonly object P4 { init { F(in field); } } + static object F(in object o) => o; + } + """; + var comp = CreateCompilation(source, targetFramework: TargetFramework.Net80); + comp.VerifyEmitDiagnostics(); + } + + [Fact] + public void PassByReference_03() + { + string source = $$""" + struct S + { + object P1 => F(field); + readonly object P2 => F(field); + object P3 { readonly get { return F(field); } set { } } + readonly object P4 { init { F(field); } } + static object F(in object o) => o; + } + """; + var comp = CreateCompilation(source, targetFramework: TargetFramework.Net80); + comp.VerifyEmitDiagnostics(); + } + + [Fact] + public void PassByReference_04() + { + string source = $$""" + struct S + { + object P1 => field; + readonly object P2 => field; + object P3 { readonly get => field; set { } } + readonly object P4 { init { field = value; } } + S(bool unused) + { + F(ref P1); + F(ref P2); + F(ref P3); + F(ref P4); + } + static object F(ref object o) => o; + } + """; + var comp = CreateCompilation(source, targetFramework: TargetFramework.Net80); + comp.VerifyEmitDiagnostics( + // (9,15): error CS0206: A non ref-returning property or indexer may not be used as an out or ref value + // F(ref P1); + Diagnostic(ErrorCode.ERR_RefProperty, "P1").WithLocation(9, 15), + // (10,15): error CS0206: A non ref-returning property or indexer may not be used as an out or ref value + // F(ref P2); + Diagnostic(ErrorCode.ERR_RefProperty, "P2").WithLocation(10, 15), + // (11,15): error CS0206: A non ref-returning property or indexer may not be used as an out or ref value + // F(ref P3); + Diagnostic(ErrorCode.ERR_RefProperty, "P3").WithLocation(11, 15), + // (12,15): error CS0206: A non ref-returning property or indexer may not be used as an out or ref value + // F(ref P4); + Diagnostic(ErrorCode.ERR_RefProperty, "P4").WithLocation(12, 15)); + } + + [Fact] + public void PassByReference_05() + { + string source = $$""" + struct S1 + { + ref object P1 => ref F1(ref field); + static ref object F1(ref object o) => ref o; + } + readonly struct S2 + { + ref readonly object P2 => ref F2(in field); + static ref readonly object F2(in object o) => ref o; + } + """; + var comp = CreateCompilation(source, targetFramework: TargetFramework.Net80); + comp.VerifyEmitDiagnostics( + // (3,16): error CS8145: Auto-implemented properties cannot return by reference + // ref object P1 => ref F1(ref field); + Diagnostic(ErrorCode.ERR_AutoPropertyCannotBeRefReturning, "P1").WithLocation(3, 16), + // (8,25): error CS8145: Auto-implemented properties cannot return by reference + // ref readonly object P2 => ref F2(in field); + Diagnostic(ErrorCode.ERR_AutoPropertyCannotBeRefReturning, "P2").WithLocation(8, 25)); + } + [Theory] [CombinatorialData] public void Nullability_01(bool useNullableAnnotation) @@ -7445,6 +7681,61 @@ interface I Diagnostic(ErrorCode.ERR_InterfacesCantContainFields, "Q3").WithLocation(11, 7)); } + [Theory] + [CombinatorialData] + public void RefAssembly(bool useStatic, bool includePrivateMembers) + { + string modifier = useStatic ? "static" : " "; + string sourceA = $$""" + using System; + public struct S0 + { + public {{modifier}} object P0 { get; set; } + } + public struct S1 + { + public {{modifier}} object P1 { get => null; set { } } + } + public struct S2 + { + public {{modifier}} object P2 { get => field; set { field = value; } } + } + """; + var comp = CreateCompilation(sourceA); + var refA = comp.EmitToImageReference( + Microsoft.CodeAnalysis.Emit.EmitOptions.Default.WithEmitMetadataOnly(true).WithIncludePrivateMembers(includePrivateMembers)); + + string sourceB = """ + class Program + { + static void Main() + { + S0 s0; + _ = s0.ToString(); + S1 s1; + _ = s1.ToString(); + S2 s2; + _ = s2.ToString(); + } + } + """; + comp = CreateCompilation(sourceB, references: [refA]); + if (useStatic) + { + comp.VerifyEmitDiagnostics(); + } + else + { + comp.VerifyEmitDiagnostics( + // (6,13): warning CS8887: Use of unassigned local variable 's0' + // _ = s0.ToString(); + Diagnostic(ErrorCode.WRN_UseDefViolation, "s0").WithArguments("s0").WithLocation(6, 13), + // (10,13): warning CS8887: Use of unassigned local variable 's2' + // _ = s2.ToString(); + Diagnostic(ErrorCode.WRN_UseDefViolation, "s2").WithArguments("s2").WithLocation(10, 13)); + } + } + [Theory] [CombinatorialData] public void PartialProperty_01( diff --git a/src/Compilers/CSharp/Test/Syntax/Syntax/FieldAndValueKeywordTests.cs b/src/Compilers/CSharp/Test/Syntax/Syntax/FieldAndValueKeywordTests.cs index d70cc8725e2dc..ce22d5439b0db 100644 --- a/src/Compilers/CSharp/Test/Syntax/Syntax/FieldAndValueKeywordTests.cs +++ b/src/Compilers/CSharp/Test/Syntax/Syntax/FieldAndValueKeywordTests.cs @@ -81,7 +81,7 @@ object this[int @field] } } """; - var comp = CreateCompilation(source, parseOptions: TestOptions.Regular12); + var comp = CreateCompilation(source, parseOptions: TestOptions.Regular13); // No diagnostics expected for field in indexers. comp.VerifyEmitDiagnostics(); } @@ -577,8 +577,8 @@ public void IdentifierToken_TypeParameterSyntax( #pragma warning disable 8321, 8981 class C { - object P1 { get { void F1() { } return null; } } - object P2 { get { void F2<@field>() { } return null; } } + object P1 { get { object F1() { return default(@field); } return null; } } + object P2 { get { object F2<@field>() { return default(field); } return null; } } } """; var comp = CreateCompilation(source, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion)); @@ -678,6 +678,39 @@ static object P1 } } + [Theory] + [CombinatorialData] + public void Local( + [CombinatorialValues(LanguageVersion.CSharp13, LanguageVersionFacts.CSharpNext)] LanguageVersion languageVersion) + { + string source = """ + class C + { + object P + { + set + { + object field = 1; + _ = field; + _ = @field; + } + } + } + """; + var comp = CreateCompilation(source, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion)); + if (languageVersion > LanguageVersion.CSharp13) + { + comp.VerifyEmitDiagnostics( + // (8,17): warning CS9258: In language version preview, the 'field' keyword binds to a synthesized backing field for the property. To avoid generating a synthesized backing field, and to refer to the existing member, use 'this.field' or '@field' instead. + // _ = field; + Diagnostic(ErrorCode.WRN_FieldIsAmbiguous, "field").WithArguments("preview").WithLocation(8, 17)); + } + else + { + comp.VerifyEmitDiagnostics(); + } + } + [Theory] [CombinatorialData] public void Lambda_01( @@ -752,8 +785,10 @@ object P } } - [Fact] - public void Lambda_Local() + [Theory] + [CombinatorialData] + public void Lambda_Local( + [CombinatorialValues(LanguageVersion.CSharp13, LanguageVersionFacts.CSharpNext)] LanguageVersion languageVersion) { string source = """ #pragma warning disable 649 @@ -765,19 +800,31 @@ object P get { Func f; - f = () => { object field = 1; return null; }; - f = () => { object @field = 2; return null; }; + f = () => { object field = 1; return field; }; + f = () => { object @field = 2; return @field; }; return null; } } } """; - var comp = CreateCompilation(source, parseOptions: TestOptions.Regular12); - comp.VerifyEmitDiagnostics(); + var comp = CreateCompilation(source, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion)); + if (languageVersion > LanguageVersion.CSharp13) + { + comp.VerifyEmitDiagnostics( + // (10,50): warning CS9258: In language version preview, the 'field' keyword binds to a synthesized backing field for the property. To avoid generating a synthesized backing field, and to refer to the existing member, use 'this.field' or '@field' instead. + // f = () => { object field = 1; return field; }; + Diagnostic(ErrorCode.WRN_FieldIsAmbiguous, "field").WithArguments("preview").WithLocation(10, 50)); + } + else + { + comp.VerifyEmitDiagnostics(); + } } - [Fact] - public void Lambda_Parameter_01() + [Theory] + [CombinatorialData] + public void Lambda_Parameter_01( + [CombinatorialValues(LanguageVersion.CSharp13, LanguageVersionFacts.CSharpNext)] LanguageVersion languageVersion) { string source = """ #pragma warning disable 649 @@ -789,15 +836,25 @@ object P get { Func f; - f = field => null; - f = @field => null; + f = field => @field; + f = @field => field; return null; } } } """; - var comp = CreateCompilation(source, parseOptions: TestOptions.Regular12); - comp.VerifyEmitDiagnostics(); + var comp = CreateCompilation(source, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion)); + if (languageVersion > LanguageVersion.CSharp13) + { + comp.VerifyEmitDiagnostics( + // (11,27): warning CS9258: In language version preview, the 'field' keyword binds to a synthesized backing field for the property. To avoid generating a synthesized backing field, and to refer to the existing member, use 'this.field' or '@field' instead. + // f = @field => field; + Diagnostic(ErrorCode.WRN_FieldIsAmbiguous, "field").WithArguments("preview").WithLocation(11, 27)); + } + else + { + comp.VerifyEmitDiagnostics(); + } } [Fact] @@ -819,7 +876,7 @@ object P } } """; - var comp = CreateCompilation(source, parseOptions: TestOptions.Regular12); + var comp = CreateCompilation(source, parseOptions: TestOptions.Regular13); comp.VerifyEmitDiagnostics(); } @@ -842,12 +899,14 @@ object P } } """; - var comp = CreateCompilation(source, parseOptions: TestOptions.Regular12); + var comp = CreateCompilation(source, parseOptions: TestOptions.Regular13); comp.VerifyEmitDiagnostics(); } - [Fact] - public void LocalFunction_Local() + [Theory] + [CombinatorialData] + public void LocalFunction_Local( + [CombinatorialValues(LanguageVersion.CSharp13, LanguageVersionFacts.CSharpNext)] LanguageVersion languageVersion) { string source = """ #pragma warning disable 649, 8321 @@ -857,19 +916,31 @@ object P { get { - object F1() { object field = 1; return null; }; - object F2() { object @field = 2; return null; }; + object F1() { object field = 1; return field; }; + object F2() { object @field = 2; return @field; }; return null; } } } """; - var comp = CreateCompilation(source, parseOptions: TestOptions.Regular12); - comp.VerifyEmitDiagnostics(); + var comp = CreateCompilation(source, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion)); + if (languageVersion > LanguageVersion.CSharp13) + { + comp.VerifyEmitDiagnostics( + // (8,52): warning CS9258: In language version preview, the 'field' keyword binds to a synthesized backing field for the property. To avoid generating a synthesized backing field, and to refer to the existing member, use 'this.field' or '@field' instead. + // object F1() { object field = 1; return field; }; + Diagnostic(ErrorCode.WRN_FieldIsAmbiguous, "field").WithArguments("preview").WithLocation(8, 52)); + } + else + { + comp.VerifyEmitDiagnostics(); + } } - [Fact] - public void LocalFunction_Parameter() + [Theory] + [CombinatorialData] + public void LocalFunction_Parameter( + [CombinatorialValues(LanguageVersion.CSharp13, LanguageVersionFacts.CSharpNext)] LanguageVersion languageVersion) { string source = """ #pragma warning disable 649, 8321 @@ -879,15 +950,84 @@ object P { get { - object F1(object field) => null; - object F2(object @field) => null; + object F1(object field) => @field; + object F2(object @field) => field; return null; } } } """; - var comp = CreateCompilation(source, parseOptions: TestOptions.Regular12); - comp.VerifyEmitDiagnostics(); + var comp = CreateCompilation(source, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion)); + if (languageVersion > LanguageVersion.CSharp13) + { + comp.VerifyEmitDiagnostics( + // (9,41): warning CS9258: In language version preview, the 'field' keyword binds to a synthesized backing field for the property. To avoid generating a synthesized backing field, and to refer to the existing member, use 'this.field' or '@field' instead. + // object F2(object @field) => field; + Diagnostic(ErrorCode.WRN_FieldIsAmbiguous, "field").WithArguments("preview").WithLocation(9, 41)); + } + else + { + comp.VerifyEmitDiagnostics(); + } + } + + [Theory] + [CombinatorialData] + public void TypeParameter( + [CombinatorialValues(LanguageVersion.CSharp13, LanguageVersionFacts.CSharpNext)] LanguageVersion languageVersion) + { + string source = """ + class C1 + { + object P1 => default(@field); + } + class C2<@field> + { + object P2 => default(field); + } + """; + var comp = CreateCompilation(source, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion)); + comp.VerifyEmitDiagnostics( + // (1,10): warning CS8981: The type name 'field' only contains lower-cased ascii characters. Such names may become reserved for the language. + // class C1 + Diagnostic(ErrorCode.WRN_LowerCaseTypeName, "field").WithArguments("field").WithLocation(1, 10)); + } + + [Theory] + [CombinatorialData] + public void ParameterDefaultValue( + [CombinatorialValues(LanguageVersion.CSharp13, LanguageVersionFacts.CSharpNext)] LanguageVersion languageVersion) + { + string source = """ + #pragma warning disable 649, 8321 + class C + { + const int field = 0; + object P + { + set + { + static void F1(int v = field) { } + static void F2(int v = @field) { } + } + } + } + """; + var comp = CreateCompilation(source, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion)); + if (languageVersion > LanguageVersion.CSharp13) + { + comp.VerifyEmitDiagnostics( + // (9,36): warning CS9258: In language version preview, the 'field' keyword binds to a synthesized backing field for the property. To avoid generating a synthesized backing field, and to refer to the existing member, use 'this.field' or '@field' instead. + // static void F1(int v = field) { } + Diagnostic(ErrorCode.WRN_FieldIsAmbiguous, "field").WithArguments("preview").WithLocation(9, 36), + // (9,36): error CS1736: Default parameter value for 'v' must be a compile-time constant + // static void F1(int v = field) { } + Diagnostic(ErrorCode.ERR_DefaultValueMustBeConstant, "field").WithArguments("v").WithLocation(9, 36)); + } + else + { + comp.VerifyEmitDiagnostics(); + } } [Theory] @@ -1145,5 +1285,44 @@ static void verify(CSharpCompilation comp, bool synthesizeField) AssertEx.Equal(expectedFields, actualFields); } } + + [Theory] + [CombinatorialData] + public void Conditional( + [CombinatorialValues(LanguageVersion.CSharp13, LanguageVersionFacts.CSharpNext)] LanguageVersion languageVersion, + bool useDEBUG) + { + string source = """ + using System.Diagnostics; + class C + { + const int field = 0; + object P1 { get { M(field); return null; } } + object P2 { set { M(field); } } + [Conditional("DEBUG")] + static void M( object o) { } + } + """; + var parseOptions = TestOptions.Regular.WithLanguageVersion(languageVersion); + if (useDEBUG) + { + parseOptions = parseOptions.WithPreprocessorSymbols("DEBUG"); + } + var comp = CreateCompilation(source, parseOptions: parseOptions); + if (languageVersion > LanguageVersion.CSharp13) + { + comp.VerifyEmitDiagnostics( + // (5,25): warning CS9258: In language version preview, the 'field' keyword binds to a synthesized backing field for the property. To avoid generating a synthesized backing field, and to refer to the existing member, use 'this.field' or '@field' instead. + // object P1 { get { M(field); return null; } } + Diagnostic(ErrorCode.WRN_FieldIsAmbiguous, "field").WithArguments("preview").WithLocation(5, 25), + // (6,25): warning CS9258: In language version preview, the 'field' keyword binds to a synthesized backing field for the property. To avoid generating a synthesized backing field, and to refer to the existing member, use 'this.field' or '@field' instead. + // object P2 { set { M(field); } } + Diagnostic(ErrorCode.WRN_FieldIsAmbiguous, "field").WithArguments("preview").WithLocation(6, 25)); + } + else + { + comp.VerifyEmitDiagnostics(); + } + } } }