From 5188aac513e525b08db68da6ef19c316382be789 Mon Sep 17 00:00:00 2001 From: Charles Stoner <10732005+cston@users.noreply.github.com> Date: Wed, 14 Aug 2024 15:30:48 -0700 Subject: [PATCH 01/21] Field-backed properties: update uses of IsAutoProperty --- .../Portable/Binder/Binder_Statements.cs | 2 +- .../LocalRewriter_AssignmentOperator.cs | 3 +- .../Source/SourcePropertySymbolBase.cs | 35 +- .../SynthesizedBackingFieldSymbol.cs | 2 +- .../CSharp/Test/Emit3/FieldKeywordTests.cs | 1299 ++++++++++++++++- 5 files changed, 1321 insertions(+), 20 deletions(-) diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Statements.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Statements.cs index c2c03dddb53f8..c434f180c41c5 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder_Statements.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder_Statements.cs @@ -1765,7 +1765,7 @@ private static bool AccessingAutoPropertyFromConstructor(BoundExpression receive var propertyIsStatic = propertySymbol.IsStatic; return (object)sourceProperty != null && - sourceProperty.IsAutoProperty && + sourceProperty.HasSynthesizedBackingField && TypeSymbol.Equals(sourceProperty.ContainingType, fromMember.ContainingType, TypeCompareKind.AllIgnoreOptions) && IsConstructorOrField(fromMember, isStatic: propertyIsStatic) && (propertyIsStatic || receiver.Kind == BoundKind.ThisReference); diff --git a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_AssignmentOperator.cs b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_AssignmentOperator.cs index 5ff4636c6c674..4d96adb6330df 100644 --- a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_AssignmentOperator.cs +++ b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_AssignmentOperator.cs @@ -281,8 +281,9 @@ private BoundExpression MakePropertyAssignment( if (setMethod is null) { var autoProp = (SourcePropertySymbolBase)property.OriginalDefinition; - Debug.Assert(autoProp.IsAutoProperty, + Debug.Assert(autoProp.HasSynthesizedBackingField, "only autoproperties can be assignable without having setters"); + Debug.Assert(_factory.CurrentFunction.IsConstructor()); Debug.Assert(property.Equals(autoProp, TypeCompareKind.IgnoreNullableModifiersForReferenceTypes)); var backingField = autoProp.BackingField; diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertySymbolBase.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertySymbolBase.cs index 95fa2f85e9da4..d50d8586b0b5d 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertySymbolBase.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertySymbolBase.cs @@ -302,7 +302,7 @@ protected void CheckInitializerIfNeeded(BindingDiagnosticBag diagnostics) { diagnostics.Add(ErrorCode.ERR_InstancePropertyInitializerInInterface, Location); } - else if (!IsAutoProperty) + else if (!HasSynthesizedBackingField) { diagnostics.Add(ErrorCode.ERR_InitializerOnNonAutoProperty, Location); } @@ -650,10 +650,7 @@ public bool HasSkipLocalsInitAttribute } } - internal bool IsAutoPropertyOrUsesFieldKeyword - => IsAutoProperty || UsesFieldKeyword; - - protected bool UsesFieldKeyword + private bool UsesFieldKeyword => (_propertyFlags & Flags.UsesFieldKeyword) != 0; protected bool HasExplicitAccessModifier @@ -665,9 +662,14 @@ internal bool IsAutoProperty protected bool AccessorsHaveImplementation => (_propertyFlags & Flags.AccessorsHaveImplementation) != 0; + // PROTOTYPE: Should this be IsAutoProperty? + internal bool HasSynthesizedBackingField + => IsAutoProperty || UsesFieldKeyword; + /// - /// Backing field for automatically implemented property, or - /// for a property with an initializer. + /// Backing field for an automatically implemented property, or + /// a property with an accessor using the 'field' keyword, or + /// a property with an initializer. /// internal SynthesizedBackingFieldSymbol BackingField { get; } @@ -715,9 +717,9 @@ internal override void AfterAddingTypeMembersChecks(ConversionsBase conversions, diagnostics.Add(ErrorCode.ERR_RefReturningPropertiesCannotBeRequired, Location); } - if (IsAutoProperty) + if (HasSynthesizedBackingField) { - if (!IsStatic && SetMethod is { IsInitOnly: false }) + if (!IsStatic && ((_propertyFlags & Flags.HasAutoPropertySet) != 0) && SetMethod is { IsInitOnly: false }) { if (ContainingType.IsReadOnly) { @@ -738,10 +740,15 @@ internal override void AfterAddingTypeMembersChecks(ConversionsBase conversions, diagnostics.Add(ErrorCode.ERR_AutoPropertyCannotBeRefReturning, Location); } - // get-only auto property should not override settable properties - if (this.IsOverride && SetMethod is null && !this.IsReadOnly) + // Auto property should override both accessors. + if (this.IsOverride) { - diagnostics.Add(ErrorCode.ERR_AutoPropertyMustOverrideSet, Location); + var overriddenProperty = (PropertySymbol)this.GetLeastOverriddenMember(this.ContainingType); + if ((overriddenProperty.GetMethod is { } && GetMethod is null) || + (overriddenProperty.SetMethod is { } && SetMethod is null)) + { + diagnostics.Add(ErrorCode.ERR_AutoPropertyMustOverrideSet, Location); + } } } @@ -1095,7 +1102,7 @@ private SynthesizedSealedPropertyAccessor MakeSynthesizedSealedAccessor() AttributeLocation IAttributeTargetSymbol.DefaultAttributeLocation => AttributeLocation.Property; AttributeLocation IAttributeTargetSymbol.AllowedAttributeLocations - => IsAutoPropertyOrUsesFieldKeyword + => HasSynthesizedBackingField ? AttributeLocation.Property | AttributeLocation.Field : AttributeLocation.Property; @@ -1660,7 +1667,7 @@ protected virtual void ValidatePropertyType(BindingDiagnosticBag diagnostics) { diagnostics.Add(ErrorCode.ERR_FieldCantBeRefAny, TypeLocation, type); } - else if (this.IsAutoPropertyOrUsesFieldKeyword && type.IsRefLikeOrAllowsRefLikeType() && (this.IsStatic || !this.ContainingType.IsRefLikeType)) + else if (this.HasSynthesizedBackingField && type.IsRefLikeOrAllowsRefLikeType() && (this.IsStatic || !this.ContainingType.IsRefLikeType)) { diagnostics.Add(ErrorCode.ERR_FieldAutoPropCantBeByRefLike, TypeLocation, type); } diff --git a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedBackingFieldSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedBackingFieldSymbol.cs index a56bf57992fb0..62691a173ee98 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedBackingFieldSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedBackingFieldSymbol.cs @@ -149,7 +149,7 @@ internal override void PostDecodeWellKnownAttributes(ImmutableArray field; } = field; - Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "P").WithLocation(3, 12), // (3,34): error CS0103: The name 'field' does not exist in the current context // object P { get => field; } = field; Diagnostic(ErrorCode.ERR_NameNotInContext, "field").WithArguments("field").WithLocation(3, 34)); @@ -1031,6 +1028,1302 @@ static void ReportField(FieldInfo field) """)); } + // PROTOTYPE: Confirm we want to allow mixed auto- and explicitly-implemented + // accessors when explicitly-implemented accessors do not use 'field'. + [Fact] + public void Initializer_01() + { + string source = """ + using System; + class C + { + public static int P1 { get; } = 1; + public static int P2 { get => field; } = 2; + public static int P3 { get => field; set; } = 3; + public static int P5 { get => field; set { } } = 5; + public static int P7 { get => 0; set; } = 7; + public static int P9 { get; set; } = 9; + public static int PB { get; set { } } = 11; + public static int PD { set { field = value; } } = 13; + } + class Program + { + static void Main() + { + Console.WriteLine((C.P1, C.P2, C.P3, C.P5, C.P7, C.P9, C.PB)); + } + } + """; + var verifier = CompileAndVerify(source, expectedOutput: "(1, 2, 3, 5, 0, 9, 11)"); + verifier.VerifyIL("C..cctor", """ + { + // Code size 52 (0x34) + .maxstack 1 + IL_0000: ldc.i4.1 + IL_0001: stsfld "int C.k__BackingField" + IL_0006: ldc.i4.2 + IL_0007: stsfld "int C.k__BackingField" + IL_000c: ldc.i4.3 + IL_000d: stsfld "int C.k__BackingField" + IL_0012: ldc.i4.5 + IL_0013: stsfld "int C.k__BackingField" + IL_0018: ldc.i4.7 + IL_0019: stsfld "int C.k__BackingField" + IL_001e: ldc.i4.s 9 + IL_0020: stsfld "int C.k__BackingField" + IL_0025: ldc.i4.s 11 + IL_0027: stsfld "int C.k__BackingField" + IL_002c: ldc.i4.s 13 + IL_002e: stsfld "int C.k__BackingField" + IL_0033: ret + } + """); + } + + [Fact] + public void Initializer_02() + { + string source = """ + using System; + class C + { + public int P1 { get; } = 1; + public int P2 { get => field; } = 2; + public int P3 { get => field; set; } = 3; + public int P4 { get => field; init; } = 4; + public int P5 { get => field; set { } } = 5; + public int P6 { get => field; init { } } = 6; + public int P7 { get => 0; set; } = 7; + public int P8 { get => 0; init; } = 8; + public int P9 { get; set; } = 9; + public int PA { get; init; } = 10; + public int PB { get; set { } } = 11; + public int PC { get; init { } } = 12; + public int PD { set { field = value; } } = 13; + public int PE { init { field = value; } } = 14; + } + class Program + { + static void Main() + { + var c = new C(); + Console.WriteLine((c.P1, c.P2, c.P3, c.P4, c.P5, c.P6, c.P7, c.P8, c.P9, c.PA, c.PB, c.PC)); + } + } + """; + var verifier = CompileAndVerify(source, targetFramework: TargetFramework.Net80, verify: Verification.Skipped, expectedOutput: IncludeExpectedOutput("(1, 2, 3, 4, 5, 6, 0, 0, 9, 10, 11, 12)")); + verifier.VerifyIL("C..ctor", """ + { + // Code size 111 (0x6f) + .maxstack 2 + IL_0000: ldarg.0 + IL_0001: ldc.i4.1 + IL_0002: stfld "int C.k__BackingField" + IL_0007: ldarg.0 + IL_0008: ldc.i4.2 + IL_0009: stfld "int C.k__BackingField" + IL_000e: ldarg.0 + IL_000f: ldc.i4.3 + IL_0010: stfld "int C.k__BackingField" + IL_0015: ldarg.0 + IL_0016: ldc.i4.4 + IL_0017: stfld "int C.k__BackingField" + IL_001c: ldarg.0 + IL_001d: ldc.i4.5 + IL_001e: stfld "int C.k__BackingField" + IL_0023: ldarg.0 + IL_0024: ldc.i4.6 + IL_0025: stfld "int C.k__BackingField" + IL_002a: ldarg.0 + IL_002b: ldc.i4.7 + IL_002c: stfld "int C.k__BackingField" + IL_0031: ldarg.0 + IL_0032: ldc.i4.8 + IL_0033: stfld "int C.k__BackingField" + IL_0038: ldarg.0 + IL_0039: ldc.i4.s 9 + IL_003b: stfld "int C.k__BackingField" + IL_0040: ldarg.0 + IL_0041: ldc.i4.s 10 + IL_0043: stfld "int C.k__BackingField" + IL_0048: ldarg.0 + IL_0049: ldc.i4.s 11 + IL_004b: stfld "int C.k__BackingField" + IL_0050: ldarg.0 + IL_0051: ldc.i4.s 12 + IL_0053: stfld "int C.k__BackingField" + IL_0058: ldarg.0 + IL_0059: ldc.i4.s 13 + IL_005b: stfld "int C.k__BackingField" + IL_0060: ldarg.0 + IL_0061: ldc.i4.s 14 + IL_0063: stfld "int C.k__BackingField" + IL_0068: ldarg.0 + IL_0069: call "object..ctor()" + IL_006e: ret + } + """); + } + + [Fact] + public void Initializer_03() + { + string source = """ + class C + { + public static int P1 { get => 0; } = 1; + public static int P2 { get => 0; set { } } = 2; + public int P3 { get => 0; } = 3; + public int P4 { get => 0; set { } } = 4; + public int P5 { get => 0; init { } } = 5; + } + """; + var comp = CreateCompilation(source, targetFramework: TargetFramework.Net80); + comp.VerifyEmitDiagnostics( + // (3,23): error CS8050: Only auto-implemented properties can have initializers. + // public static int P1 { get => 0; } = 1; + Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "P1").WithLocation(3, 23), + // (4,23): error CS8050: Only auto-implemented properties can have initializers. + // public static int P2 { get => 0; set { } } = 2; + Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "P2").WithLocation(4, 23), + // (5,16): error CS8050: Only auto-implemented properties can have initializers. + // public int P3 { get => 0; } = 3; + Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "P3").WithLocation(5, 16), + // (6,16): error CS8050: Only auto-implemented properties can have initializers. + // public int P4 { get => 0; set { } } = 4; + Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "P4").WithLocation(6, 16), + // (7,16): error CS8050: Only auto-implemented properties can have initializers. + // public int P5 { get => 0; init { } } = 5; + Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "P5").WithLocation(7, 16)); + } + + [Fact] + public void ConstructorAssignment_01() + { + string source = """ + using System; + class C + { + public static int P1 { get; } + public static int P2 { get => field; } + public static int P3 { get => field; set; } + public static int P5 { get => field; set { } } + public static int P7 { get => 0; set; } + public static int P9 { get; set; } + public static int PB { get; set { } } + public static int PD { set { field = value; } } + static C() + { + P1 = 1; + P2 = 2; + P3 = 3; + P5 = 5; + P7 = 7; + P9 = 9; + PB = 11; + PD = 13; + } + } + class Program + { + static void Main() + { + Console.WriteLine((C.P1, C.P2, C.P3, C.P5, C.P7, C.P9, C.PB)); + } + } + """; + var verifier = CompileAndVerify(source, expectedOutput: "(1, 2, 3, 0, 0, 9, 0)"); + verifier.VerifyIL("C..cctor", """ + { + // Code size 52 (0x34) + .maxstack 1 + IL_0000: ldc.i4.1 + IL_0001: stsfld "int C.k__BackingField" + IL_0006: ldc.i4.2 + IL_0007: stsfld "int C.k__BackingField" + IL_000c: ldc.i4.3 + IL_000d: call "void C.P3.set" + IL_0012: ldc.i4.5 + IL_0013: call "void C.P5.set" + IL_0018: ldc.i4.7 + IL_0019: call "void C.P7.set" + IL_001e: ldc.i4.s 9 + IL_0020: call "void C.P9.set" + IL_0025: ldc.i4.s 11 + IL_0027: call "void C.PB.set" + IL_002c: ldc.i4.s 13 + IL_002e: call "void C.PD.set" + IL_0033: ret + } + """); + } + + [Fact] + public void ConstructorAssignment_02() + { + string source = """ + using System; + class C + { + public int P1 { get; } + public int P2 { get => field; } + public int P3 { get => field; set; } + public int P4 { get => field; init; } + public int P5 { get => field; set { } } + public int P6 { get => field; init { } } + public int P7 { get => 0; set; } + public int P8 { get => 0; init; } + public int P9 { get; set; } + public int PA { get; init; } + public int PB { get; set { } } + public int PC { get; init { } } + public int PD { set { field = value; } } + public int PE { init { field = value; } } + public C() + { + P1 = 1; + P2 = 2; + P3 = 3; + P4 = 4; + P5 = 5; + P6 = 6; + P7 = 7; + P8 = 8; + P9 = 9; + PA = 10; + PB = 11; + PC = 12; + PD = 13; + PE = 14; + } + } + class Program + { + static void Main() + { + var c = new C(); + Console.WriteLine((c.P1, c.P2, c.P3, c.P4, c.P5, c.P6, c.P7, c.P8, c.P9, c.PA, c.PB, c.PC)); + } + } + """; + var verifier = CompileAndVerify(source, targetFramework: TargetFramework.Net80, verify: Verification.Skipped, expectedOutput: IncludeExpectedOutput("(1, 2, 3, 4, 0, 0, 0, 0, 9, 10, 0, 0)")); + verifier.VerifyIL("C..ctor", """ + { + // Code size 111 (0x6f) + .maxstack 2 + IL_0000: ldarg.0 + IL_0001: call "object..ctor()" + IL_0006: ldarg.0 + IL_0007: ldc.i4.1 + IL_0008: stfld "int C.k__BackingField" + IL_000d: ldarg.0 + IL_000e: ldc.i4.2 + IL_000f: stfld "int C.k__BackingField" + IL_0014: ldarg.0 + IL_0015: ldc.i4.3 + IL_0016: call "void C.P3.set" + IL_001b: ldarg.0 + IL_001c: ldc.i4.4 + IL_001d: call "void C.P4.init" + IL_0022: ldarg.0 + IL_0023: ldc.i4.5 + IL_0024: call "void C.P5.set" + IL_0029: ldarg.0 + IL_002a: ldc.i4.6 + IL_002b: call "void C.P6.init" + IL_0030: ldarg.0 + IL_0031: ldc.i4.7 + IL_0032: call "void C.P7.set" + IL_0037: ldarg.0 + IL_0038: ldc.i4.8 + IL_0039: call "void C.P8.init" + IL_003e: ldarg.0 + IL_003f: ldc.i4.s 9 + IL_0041: call "void C.P9.set" + IL_0046: ldarg.0 + IL_0047: ldc.i4.s 10 + IL_0049: call "void C.PA.init" + IL_004e: ldarg.0 + IL_004f: ldc.i4.s 11 + IL_0051: call "void C.PB.set" + IL_0056: ldarg.0 + IL_0057: ldc.i4.s 12 + IL_0059: call "void C.PC.init" + IL_005e: ldarg.0 + IL_005f: ldc.i4.s 13 + IL_0061: call "void C.PD.set" + IL_0066: ldarg.0 + IL_0067: ldc.i4.s 14 + IL_0069: call "void C.PE.init" + IL_006e: ret + } + """); + } + + [Fact] + public void ConstructorAssignment_03() + { + string source = """ + using System; + class C + { + static int P1 => field; + int P2 => field; + static C() + { + P1 = 1; + M(() => { P1 = 2; }); + } + C(object o) + { + P2 = 3; + M(() => { P2 = 4; }); + } + static void M(Action a) + { + } + } + """; + var comp = CreateCompilation(source, targetFramework: TargetFramework.Net80); + comp.VerifyEmitDiagnostics( + // (9,19): error CS0200: Property or indexer 'C.P1' cannot be assigned to -- it is read only + // M(() => { P1 = 2; }); + Diagnostic(ErrorCode.ERR_AssgReadonlyProp, "P1").WithArguments("C.P1").WithLocation(9, 19), + // (14,19): error CS0200: Property or indexer 'C.P2' cannot be assigned to -- it is read only + // M(() => { P2 = 4; }); + Diagnostic(ErrorCode.ERR_AssgReadonlyProp, "P2").WithArguments("C.P2").WithLocation(14, 19)); + } + + [Fact] + public void ConstructorAssignment_04() + { + string source = """ + using System; + class A + { + public static int P1 { get; private set; } + public static int P3 { get => field; private set; } + public static int P5 { get => field; private set { } } + public static int P7 { get; private set { } } + } + class B : A + { + static B() + { + P1 = 1; + P3 = 3; + P5 = 5; + P7 = 7; + } + } + """; + var comp = CreateCompilation(source); + comp.VerifyEmitDiagnostics( + // (13,9): error CS0272: The property or indexer 'A.P1' cannot be used in this context because the set accessor is inaccessible + // P1 = 1; + Diagnostic(ErrorCode.ERR_InaccessibleSetter, "P1").WithArguments("A.P1").WithLocation(13, 9), + // (14,9): error CS0272: The property or indexer 'A.P3' cannot be used in this context because the set accessor is inaccessible + // P3 = 3; + Diagnostic(ErrorCode.ERR_InaccessibleSetter, "P3").WithArguments("A.P3").WithLocation(14, 9), + // (15,9): error CS0272: The property or indexer 'A.P5' cannot be used in this context because the set accessor is inaccessible + // P5 = 5; + Diagnostic(ErrorCode.ERR_InaccessibleSetter, "P5").WithArguments("A.P5").WithLocation(15, 9), + // (16,9): error CS0272: The property or indexer 'A.P7' cannot be used in this context because the set accessor is inaccessible + // P7 = 7; + Diagnostic(ErrorCode.ERR_InaccessibleSetter, "P7").WithArguments("A.P7").WithLocation(16, 9)); + } + + [Fact] + public void ConstructorAssignment_05() + { + string source = """ + using System; + class A + { + public int P1 { get; private set; } + public int P2 { get; private init; } + public int P3 { get => field; private set; } + public int P4 { get => field; private init; } + public int P5 { get => field; private set { } } + public int P6 { get => field; private init { } } + public int P7 { get; private set { } } + public int P8 { get; private init { } } + } + class B : A + { + public B() + { + P1 = 1; + P2 = 2; + P3 = 3; + P4 = 4; + P5 = 5; + P6 = 6; + P7 = 7; + P8 = 8; + } + } + """; + var comp = CreateCompilation(source, targetFramework: TargetFramework.Net80); + comp.VerifyEmitDiagnostics( + // (17,9): error CS0272: The property or indexer 'A.P1' cannot be used in this context because the set accessor is inaccessible + // P1 = 1; + Diagnostic(ErrorCode.ERR_InaccessibleSetter, "P1").WithArguments("A.P1").WithLocation(17, 9), + // (18,9): error CS0272: The property or indexer 'A.P2' cannot be used in this context because the set accessor is inaccessible + // P2 = 2; + Diagnostic(ErrorCode.ERR_InaccessibleSetter, "P2").WithArguments("A.P2").WithLocation(18, 9), + // (19,9): error CS0272: The property or indexer 'A.P3' cannot be used in this context because the set accessor is inaccessible + // P3 = 3; + Diagnostic(ErrorCode.ERR_InaccessibleSetter, "P3").WithArguments("A.P3").WithLocation(19, 9), + // (20,9): error CS0272: The property or indexer 'A.P4' cannot be used in this context because the set accessor is inaccessible + // P4 = 4; + Diagnostic(ErrorCode.ERR_InaccessibleSetter, "P4").WithArguments("A.P4").WithLocation(20, 9), + // (21,9): error CS0272: The property or indexer 'A.P5' cannot be used in this context because the set accessor is inaccessible + // P5 = 5; + Diagnostic(ErrorCode.ERR_InaccessibleSetter, "P5").WithArguments("A.P5").WithLocation(21, 9), + // (22,9): error CS0272: The property or indexer 'A.P6' cannot be used in this context because the set accessor is inaccessible + // P6 = 6; + Diagnostic(ErrorCode.ERR_InaccessibleSetter, "P6").WithArguments("A.P6").WithLocation(22, 9), + // (23,9): error CS0272: The property or indexer 'A.P7' cannot be used in this context because the set accessor is inaccessible + // P7 = 7; + Diagnostic(ErrorCode.ERR_InaccessibleSetter, "P7").WithArguments("A.P7").WithLocation(23, 9), + // (24,9): error CS0272: The property or indexer 'A.P8' cannot be used in this context because the set accessor is inaccessible + // P8 = 8; + Diagnostic(ErrorCode.ERR_InaccessibleSetter, "P8").WithArguments("A.P8").WithLocation(24, 9)); + } + + [Theory] + [CombinatorialData] + public void ReadOnly_01(bool useReadOnlyType, bool useReadOnlyProperty) + { + static string getReadOnlyModifier(bool useReadOnly) => useReadOnly ? "readonly" : " "; + string typeModifier = getReadOnlyModifier(useReadOnlyType); + string propertyModifier = getReadOnlyModifier(useReadOnlyProperty); + string source = $$""" + {{typeModifier}} struct S + { + {{propertyModifier}} object P1 { get; } + {{propertyModifier}} object P2 { get => field; } + {{propertyModifier}} object P3 { get => field; set; } + {{propertyModifier}} object P4 { get => field; init; } + {{propertyModifier}} object P5 { get => field; set { } } + {{propertyModifier}} object P6 { get => field; init { } } + {{propertyModifier}} object P7 { get => null; } + {{propertyModifier}} object P8 { get => null; set; } + {{propertyModifier}} object P9 { get => null; init; } + {{propertyModifier}} object PA { get => null; set { } } + {{propertyModifier}} object PB { get => null; init { } } + {{propertyModifier}} object PC { get => null; set { _ = field; } } + {{propertyModifier}} object PD { get => null; init { _ = field; } } + {{propertyModifier}} object PE { get; set; } + {{propertyModifier}} object PF { get; init; } + {{propertyModifier}} object PG { get; set { } } + {{propertyModifier}} object PH { get; init { } } + {{propertyModifier}} object PI { set { _ = field; } } + {{propertyModifier}} object PJ { init { _ = field; } } + {{propertyModifier}} object PK { get { field = null; return null; } } + {{propertyModifier}} object PL { get; set { field = value; } } + {{propertyModifier}} object PM { get; init { field = value; } } + {{propertyModifier}} object PN { set { field = value; } } + {{propertyModifier}} object PO { init { field = value; } } + } + """; + var comp = CreateCompilation(source, targetFramework: TargetFramework.Net80); + if (useReadOnlyType) + { + comp.VerifyEmitDiagnostics( + // (5,21): error CS8341: Auto-implemented instance properties in readonly structs must be readonly. + // object P3 { get => field; set; } + Diagnostic(ErrorCode.ERR_AutoPropsInRoStruct, "P3").WithLocation(5, 21), + // (10,21): error CS8341: Auto-implemented instance properties in readonly structs must be readonly. + // object P8 { get => null; set; } + Diagnostic(ErrorCode.ERR_AutoPropsInRoStruct, "P8").WithLocation(10, 21), + // (16,21): error CS8341: Auto-implemented instance properties in readonly structs must be readonly. + // object PE { get; set; } + Diagnostic(ErrorCode.ERR_AutoPropsInRoStruct, "PE").WithLocation(16, 21), + // (22,32): error CS1604: Cannot assign to 'field' because it is read-only + // object PK { get { field = null; return null; } } + Diagnostic(ErrorCode.ERR_AssgReadonlyLocal, "field").WithArguments("field").WithLocation(22, 32), + // (23,37): error CS1604: Cannot assign to 'field' because it is read-only + // object PL { get; set { field = value; } } + Diagnostic(ErrorCode.ERR_AssgReadonlyLocal, "field").WithArguments("field").WithLocation(23, 37), + // (25,32): error CS1604: Cannot assign to 'field' because it is read-only + // object PN { set { field = value; } } + Diagnostic(ErrorCode.ERR_AssgReadonlyLocal, "field").WithArguments("field").WithLocation(25, 32)); + } + else if (useReadOnlyProperty) + { + comp.VerifyEmitDiagnostics( + // (5,21): error CS8659: Auto-implemented property 'S.P3' cannot be marked 'readonly' because it has a 'set' accessor. + // readonly object P3 { get => field; set; } + Diagnostic(ErrorCode.ERR_AutoPropertyWithSetterCantBeReadOnly, "P3").WithArguments("S.P3").WithLocation(5, 21), + // (10,21): error CS8659: Auto-implemented property 'S.P8' cannot be marked 'readonly' because it has a 'set' accessor. + // readonly object P8 { get => null; set; } + Diagnostic(ErrorCode.ERR_AutoPropertyWithSetterCantBeReadOnly, "P8").WithArguments("S.P8").WithLocation(10, 21), + // (16,21): error CS8659: Auto-implemented property 'S.PE' cannot be marked 'readonly' because it has a 'set' accessor. + // readonly object PE { get; set; } + Diagnostic(ErrorCode.ERR_AutoPropertyWithSetterCantBeReadOnly, "PE").WithArguments("S.PE").WithLocation(16, 21), + // (22,32): error CS1604: Cannot assign to 'field' because it is read-only + // readonly object PK { get { field = null; return null; } } + Diagnostic(ErrorCode.ERR_AssgReadonlyLocal, "field").WithArguments("field").WithLocation(22, 32), + // (23,37): error CS1604: Cannot assign to 'field' because it is read-only + // readonly object PL { get; set { field = value; } } + Diagnostic(ErrorCode.ERR_AssgReadonlyLocal, "field").WithArguments("field").WithLocation(23, 37), + // (25,32): error CS1604: Cannot assign to 'field' because it is read-only + // readonly object PN { set { field = value; } } + Diagnostic(ErrorCode.ERR_AssgReadonlyLocal, "field").WithArguments("field").WithLocation(25, 32)); + } + else + { + comp.VerifyEmitDiagnostics(); + } + } + + [Theory] + [CombinatorialData] + public void ReadOnly_02(bool useReadOnlyType, bool useReadOnlyOnGet) + { + static string getReadOnlyModifier(bool useReadOnly) => useReadOnly ? "readonly" : " "; + string typeModifier = getReadOnlyModifier(useReadOnlyType); + string getModifier = getReadOnlyModifier(useReadOnlyOnGet); + string setModifier = getReadOnlyModifier(!useReadOnlyOnGet); + string source = $$""" + {{typeModifier}} struct S + { + object P3 { {{getModifier}} get => field; {{setModifier}} set; } + object P5 { {{getModifier}} get => field; {{setModifier}} set { } } + object P8 { {{getModifier}} get => null; {{setModifier}} set; } + object PA { {{getModifier}} get => null; {{setModifier}} set { } } + object PC { {{getModifier}} get => null; {{setModifier}} set { _ = field; } } + object PE { {{getModifier}} get; {{setModifier}} set; } + object PG { {{getModifier}} get; {{setModifier}} set { } } + object PK { {{getModifier}} get { field = null; return null; } set { } } + object PL { {{getModifier}} get; {{setModifier}} set { field = value; } } + } + """; + var comp = CreateCompilation(source, targetFramework: TargetFramework.Net80); + if (useReadOnlyType) + { + if (useReadOnlyOnGet) + { + comp.VerifyEmitDiagnostics( + // (3,12): error CS8341: Auto-implemented instance properties in readonly structs must be readonly. + // object P3 { readonly get => field; set; } + Diagnostic(ErrorCode.ERR_AutoPropsInRoStruct, "P3").WithLocation(3, 12), + // (5,12): error CS8341: Auto-implemented instance properties in readonly structs must be readonly. + // object P8 { readonly get => null; set; } + Diagnostic(ErrorCode.ERR_AutoPropsInRoStruct, "P8").WithLocation(5, 12), + // (8,12): error CS8341: Auto-implemented instance properties in readonly structs must be readonly. + // object PE { readonly get; set; } + Diagnostic(ErrorCode.ERR_AutoPropsInRoStruct, "PE").WithLocation(8, 12), + // (10,32): error CS1604: Cannot assign to 'field' because it is read-only + // object PK { readonly get { field = null; return null; } set { } } + Diagnostic(ErrorCode.ERR_AssgReadonlyLocal, "field").WithArguments("field").WithLocation(10, 32), + // (11,46): error CS1604: Cannot assign to 'field' because it is read-only + // object PL { readonly get; set { field = value; } } + Diagnostic(ErrorCode.ERR_AssgReadonlyLocal, "field").WithArguments("field").WithLocation(11, 46)); + } + else + { + comp.VerifyEmitDiagnostics( + // (3,12): error CS8341: Auto-implemented instance properties in readonly structs must be readonly. + // object P3 { get => field; readonly set; } + Diagnostic(ErrorCode.ERR_AutoPropsInRoStruct, "P3").WithLocation(3, 12), + // (3,49): error CS8658: Auto-implemented 'set' accessor 'S.P3.set' cannot be marked 'readonly'. + // object P3 { get => field; readonly set; } + Diagnostic(ErrorCode.ERR_AutoSetterCantBeReadOnly, "set").WithArguments("S.P3.set").WithLocation(3, 49), + // (5,12): error CS8341: Auto-implemented instance properties in readonly structs must be readonly. + // object P8 { get => null; readonly set; } + Diagnostic(ErrorCode.ERR_AutoPropsInRoStruct, "P8").WithLocation(5, 12), + // (5,48): error CS8658: Auto-implemented 'set' accessor 'S.P8.set' cannot be marked 'readonly'. + // object P8 { get => null; readonly set; } + Diagnostic(ErrorCode.ERR_AutoSetterCantBeReadOnly, "set").WithArguments("S.P8.set").WithLocation(5, 48), + // (8,12): error CS8341: Auto-implemented instance properties in readonly structs must be readonly. + // object PE { get; readonly set; } + Diagnostic(ErrorCode.ERR_AutoPropsInRoStruct, "PE").WithLocation(8, 12), + // (8,40): error CS8658: Auto-implemented 'set' accessor 'S.PE.set' cannot be marked 'readonly'. + // object PE { get; readonly set; } + Diagnostic(ErrorCode.ERR_AutoSetterCantBeReadOnly, "set").WithArguments("S.PE.set").WithLocation(8, 40), + // (10,32): error CS1604: Cannot assign to 'field' because it is read-only + // object PK { get { field = null; return null; } set { } } + Diagnostic(ErrorCode.ERR_AssgReadonlyLocal, "field").WithArguments("field").WithLocation(10, 32), + // (11,46): error CS1604: Cannot assign to 'field' because it is read-only + // object PL { get; readonly set { field = value; } } + Diagnostic(ErrorCode.ERR_AssgReadonlyLocal, "field").WithArguments("field").WithLocation(11, 46)); + } + } + else + { + if (useReadOnlyOnGet) + { + comp.VerifyEmitDiagnostics( + // (10,32): error CS1604: Cannot assign to 'field' because it is read-only + // object PK { readonly get { field = null; return null; } set { } } + Diagnostic(ErrorCode.ERR_AssgReadonlyLocal, "field").WithArguments("field").WithLocation(10, 32)); + } + else + { + comp.VerifyEmitDiagnostics( + // (3,49): error CS8658: Auto-implemented 'set' accessor 'S.P3.set' cannot be marked 'readonly'. + // object P3 { get => field; readonly set; } + Diagnostic(ErrorCode.ERR_AutoSetterCantBeReadOnly, "set").WithArguments("S.P3.set").WithLocation(3, 49), + // (5,48): error CS8658: Auto-implemented 'set' accessor 'S.P8.set' cannot be marked 'readonly'. + // object P8 { get => null; readonly set; } + Diagnostic(ErrorCode.ERR_AutoSetterCantBeReadOnly, "set").WithArguments("S.P8.set").WithLocation(5, 48), + // (8,40): error CS8658: Auto-implemented 'set' accessor 'S.PE.set' cannot be marked 'readonly'. + // object PE { get; readonly set; } + Diagnostic(ErrorCode.ERR_AutoSetterCantBeReadOnly, "set").WithArguments("S.PE.set").WithLocation(8, 40), + // (11,46): error CS1604: Cannot assign to 'field' because it is read-only + // object PL { get; readonly set { field = value; } } + Diagnostic(ErrorCode.ERR_AssgReadonlyLocal, "field").WithArguments("field").WithLocation(11, 46)); + } + } + } + + [Theory] + [CombinatorialData] + public void ReadOnly_03(bool useReadOnlyType, bool useReadOnlyProperty) + { + static string getReadOnlyModifier(bool useReadOnly) => useReadOnly ? "readonly" : " "; + string typeModifier = getReadOnlyModifier(useReadOnlyType); + string propertyModifier = getReadOnlyModifier(useReadOnlyProperty); + string source = $$""" + {{typeModifier}} struct S + { + static {{propertyModifier}} object P1 { get; } + static {{propertyModifier}} object P2 { get => field; } + static {{propertyModifier}} object P3 { get => field; set; } + static {{propertyModifier}} object PE { get; set; } + static {{propertyModifier}} object PG { get; set { } } + static {{propertyModifier}} object PL { get; set { field = value; } } + static {{propertyModifier}} object PN { set { field = value; } } + } + """; + var comp = CreateCompilation(source, targetFramework: TargetFramework.Net80); + if (useReadOnlyProperty) + { + comp.VerifyEmitDiagnostics( + // (3,28): error CS8657: Static member 'S.P1' cannot be marked 'readonly'. + // static readonly object P1 { get; } + Diagnostic(ErrorCode.ERR_StaticMemberCantBeReadOnly, "P1").WithArguments("S.P1").WithLocation(3, 28), + // (4,28): error CS8657: Static member 'S.P2' cannot be marked 'readonly'. + // static readonly object P2 { get => field; } + Diagnostic(ErrorCode.ERR_StaticMemberCantBeReadOnly, "P2").WithArguments("S.P2").WithLocation(4, 28), + // (5,28): error CS8657: Static member 'S.P3' cannot be marked 'readonly'. + // static readonly object P3 { get => field; set; } + Diagnostic(ErrorCode.ERR_StaticMemberCantBeReadOnly, "P3").WithArguments("S.P3").WithLocation(5, 28), + // (6,28): error CS8657: Static member 'S.PE' cannot be marked 'readonly'. + // static readonly object PE { get; set; } + Diagnostic(ErrorCode.ERR_StaticMemberCantBeReadOnly, "PE").WithArguments("S.PE").WithLocation(6, 28), + // (7,28): error CS8657: Static member 'S.PG' cannot be marked 'readonly'. + // static readonly object PG { get; set { } } + Diagnostic(ErrorCode.ERR_StaticMemberCantBeReadOnly, "PG").WithArguments("S.PG").WithLocation(7, 28), + // (8,28): error CS8657: Static member 'S.PL' cannot be marked 'readonly'. + // static readonly object PL { get; set { field = value; } } + Diagnostic(ErrorCode.ERR_StaticMemberCantBeReadOnly, "PL").WithArguments("S.PL").WithLocation(8, 28), + // (9,28): error CS8657: Static member 'S.PN' cannot be marked 'readonly'. + // static readonly object PN { set { field = value; } } + Diagnostic(ErrorCode.ERR_StaticMemberCantBeReadOnly, "PN").WithArguments("S.PN").WithLocation(9, 28)); + } + else + { + comp.VerifyEmitDiagnostics(); + } + } + + [Theory] + [CombinatorialData] + public void ReadOnly_04(bool useReadOnlyType, bool useReadOnlyOnGet) + { + static string getReadOnlyModifier(bool useReadOnly) => useReadOnly ? "readonly" : " "; + string typeModifier = getReadOnlyModifier(useReadOnlyType); + string getModifier = getReadOnlyModifier(useReadOnlyOnGet); + string setModifier = getReadOnlyModifier(!useReadOnlyOnGet); + string source = $$""" + {{typeModifier}} struct S + { + static object P3 { {{getModifier}} get => field; {{setModifier}} set; } + static object PE { {{getModifier}} get; {{setModifier}} set; } + static object PL { {{getModifier}} get; {{setModifier}} set { field = value; } } + } + """; + var comp = CreateCompilation(source, targetFramework: TargetFramework.Net80); + if (useReadOnlyOnGet) + { + comp.VerifyEmitDiagnostics( + // (3,33): error CS8657: Static member 'S.P3.get' cannot be marked 'readonly'. + // static object P3 { readonly get => field; set; } + Diagnostic(ErrorCode.ERR_StaticMemberCantBeReadOnly, "get").WithArguments("S.P3.get").WithLocation(3, 33), + // (4,33): error CS8657: Static member 'S.PE.get' cannot be marked 'readonly'. + // static object PE { readonly get; set; } + Diagnostic(ErrorCode.ERR_StaticMemberCantBeReadOnly, "get").WithArguments("S.PE.get").WithLocation(4, 33), + // (5,33): error CS8657: Static member 'S.PL.get' cannot be marked 'readonly'. + // static object PL { readonly get; set { field = value; } } + Diagnostic(ErrorCode.ERR_StaticMemberCantBeReadOnly, "get").WithArguments("S.PL.get").WithLocation(5, 33)); + } + else + { + comp.VerifyEmitDiagnostics( + // (3,56): error CS8657: Static member 'S.P3.set' cannot be marked 'readonly'. + // static object P3 { get => field; readonly set; } + Diagnostic(ErrorCode.ERR_StaticMemberCantBeReadOnly, "set").WithArguments("S.P3.set").WithLocation(3, 56), + // (4,47): error CS8657: Static member 'S.PE.set' cannot be marked 'readonly'. + // static object PE { get; readonly set; } + Diagnostic(ErrorCode.ERR_StaticMemberCantBeReadOnly, "set").WithArguments("S.PE.set").WithLocation(4, 47), + // (5,47): error CS8657: Static member 'S.PL.set' cannot be marked 'readonly'. + // static object PL { get; readonly set { field = value; } } + Diagnostic(ErrorCode.ERR_StaticMemberCantBeReadOnly, "set").WithArguments("S.PL.set").WithLocation(5, 47)); + } + } + + [Theory] + [CombinatorialData] + public void RefReturning_01(bool useStruct, bool useRefReadOnly) + { + string type = useStruct ? "struct" : "class"; + string refModifier = useRefReadOnly ? "ref readonly" : "ref "; + string source = $$""" + {{type}} S + { + {{refModifier}} object P1 { get; } + {{refModifier}} object P2 { get => ref field; } + {{refModifier}} object P3 { get => ref field; set; } + {{refModifier}} object P4 { get => ref field; init; } + {{refModifier}} object P5 { get => ref field; set { } } + {{refModifier}} object P6 { get => ref field; init { } } + {{refModifier}} object P7 { get => throw null; } + {{refModifier}} object P8 { get => throw null; set; } + {{refModifier}} object P9 { get => throw null; init; } + {{refModifier}} object PC { get => throw null; set { _ = field; } } + {{refModifier}} object PD { get => throw null; init { _ = field; } } + {{refModifier}} object PE { get; set; } + {{refModifier}} object PF { get; init; } + {{refModifier}} object PG { get; set { } } + {{refModifier}} object PH { get; init { } } + {{refModifier}} object PI { set { _ = field; } } + {{refModifier}} object PJ { init { _ = field; } } + } + """; + var comp = CreateCompilation(source, targetFramework: TargetFramework.Net80); + comp.VerifyEmitDiagnostics( + // (3,25): error CS8145: Auto-implemented properties cannot return by reference + // ref object P1 { get; } + Diagnostic(ErrorCode.ERR_AutoPropertyCannotBeRefReturning, "P1").WithLocation(3, 25), + // (4,25): error CS8145: Auto-implemented properties cannot return by reference + // ref object P2 { get => ref field; } + Diagnostic(ErrorCode.ERR_AutoPropertyCannotBeRefReturning, "P2").WithLocation(4, 25), + // (5,25): error CS8145: Auto-implemented properties cannot return by reference + // ref object P3 { get => ref field; set; } + Diagnostic(ErrorCode.ERR_AutoPropertyCannotBeRefReturning, "P3").WithLocation(5, 25), + // (5,48): error CS8147: Properties which return by reference cannot have set accessors + // ref object P3 { get => ref field; set; } + Diagnostic(ErrorCode.ERR_RefPropertyCannotHaveSetAccessor, "set").WithLocation(5, 48), + // (6,25): error CS8145: Auto-implemented properties cannot return by reference + // ref object P4 { get => ref field; init; } + Diagnostic(ErrorCode.ERR_AutoPropertyCannotBeRefReturning, "P4").WithLocation(6, 25), + // (6,48): error CS8147: Properties which return by reference cannot have set accessors + // ref object P4 { get => ref field; init; } + Diagnostic(ErrorCode.ERR_RefPropertyCannotHaveSetAccessor, "init").WithLocation(6, 48), + // (7,25): error CS8145: Auto-implemented properties cannot return by reference + // ref object P5 { get => ref field; set { } } + Diagnostic(ErrorCode.ERR_AutoPropertyCannotBeRefReturning, "P5").WithLocation(7, 25), + // (7,48): error CS8147: Properties which return by reference cannot have set accessors + // ref object P5 { get => ref field; set { } } + Diagnostic(ErrorCode.ERR_RefPropertyCannotHaveSetAccessor, "set").WithLocation(7, 48), + // (8,25): error CS8145: Auto-implemented properties cannot return by reference + // ref object P6 { get => ref field; init { } } + Diagnostic(ErrorCode.ERR_AutoPropertyCannotBeRefReturning, "P6").WithLocation(8, 25), + // (8,48): error CS8147: Properties which return by reference cannot have set accessors + // ref object P6 { get => ref field; init { } } + Diagnostic(ErrorCode.ERR_RefPropertyCannotHaveSetAccessor, "init").WithLocation(8, 48), + // (10,25): error CS8145: Auto-implemented properties cannot return by reference + // ref object P8 { get => throw null; set; } + Diagnostic(ErrorCode.ERR_AutoPropertyCannotBeRefReturning, "P8").WithLocation(10, 25), + // (10,49): error CS8147: Properties which return by reference cannot have set accessors + // ref object P8 { get => throw null; set; } + Diagnostic(ErrorCode.ERR_RefPropertyCannotHaveSetAccessor, "set").WithLocation(10, 49), + // (11,25): error CS8145: Auto-implemented properties cannot return by reference + // ref object P9 { get => throw null; init; } + Diagnostic(ErrorCode.ERR_AutoPropertyCannotBeRefReturning, "P9").WithLocation(11, 25), + // (11,49): error CS8147: Properties which return by reference cannot have set accessors + // ref object P9 { get => throw null; init; } + Diagnostic(ErrorCode.ERR_RefPropertyCannotHaveSetAccessor, "init").WithLocation(11, 49), + // (12,25): error CS8145: Auto-implemented properties cannot return by reference + // ref object PC { get => throw null; set { _ = field; } } + Diagnostic(ErrorCode.ERR_AutoPropertyCannotBeRefReturning, "PC").WithLocation(12, 25), + // (12,49): error CS8147: Properties which return by reference cannot have set accessors + // ref object PC { get => throw null; set { _ = field; } } + Diagnostic(ErrorCode.ERR_RefPropertyCannotHaveSetAccessor, "set").WithLocation(12, 49), + // (13,25): error CS8145: Auto-implemented properties cannot return by reference + // ref object PD { get => throw null; init { _ = field; } } + Diagnostic(ErrorCode.ERR_AutoPropertyCannotBeRefReturning, "PD").WithLocation(13, 25), + // (13,49): error CS8147: Properties which return by reference cannot have set accessors + // ref object PD { get => throw null; init { _ = field; } } + Diagnostic(ErrorCode.ERR_RefPropertyCannotHaveSetAccessor, "init").WithLocation(13, 49), + // (14,25): error CS8145: Auto-implemented properties cannot return by reference + // ref object PE { get; set; } + Diagnostic(ErrorCode.ERR_AutoPropertyCannotBeRefReturning, "PE").WithLocation(14, 25), + // (14,35): error CS8147: Properties which return by reference cannot have set accessors + // ref object PE { get; set; } + Diagnostic(ErrorCode.ERR_RefPropertyCannotHaveSetAccessor, "set").WithLocation(14, 35), + // (15,25): error CS8145: Auto-implemented properties cannot return by reference + // ref object PF { get; init; } + Diagnostic(ErrorCode.ERR_AutoPropertyCannotBeRefReturning, "PF").WithLocation(15, 25), + // (15,35): error CS8147: Properties which return by reference cannot have set accessors + // ref object PF { get; init; } + Diagnostic(ErrorCode.ERR_RefPropertyCannotHaveSetAccessor, "init").WithLocation(15, 35), + // (16,25): error CS8145: Auto-implemented properties cannot return by reference + // ref object PG { get; set { } } + Diagnostic(ErrorCode.ERR_AutoPropertyCannotBeRefReturning, "PG").WithLocation(16, 25), + // (16,35): error CS8147: Properties which return by reference cannot have set accessors + // ref object PG { get; set { } } + Diagnostic(ErrorCode.ERR_RefPropertyCannotHaveSetAccessor, "set").WithLocation(16, 35), + // (17,25): error CS8145: Auto-implemented properties cannot return by reference + // ref object PH { get; init { } } + Diagnostic(ErrorCode.ERR_AutoPropertyCannotBeRefReturning, "PH").WithLocation(17, 25), + // (17,35): error CS8147: Properties which return by reference cannot have set accessors + // ref object PH { get; init { } } + Diagnostic(ErrorCode.ERR_RefPropertyCannotHaveSetAccessor, "init").WithLocation(17, 35), + // (18,25): error CS8145: Auto-implemented properties cannot return by reference + // ref object PI { set { _ = field; } } + Diagnostic(ErrorCode.ERR_AutoPropertyCannotBeRefReturning, "PI").WithLocation(18, 25), + // (18,25): error CS8146: Properties which return by reference must have a get accessor + // ref object PI { set { _ = field; } } + Diagnostic(ErrorCode.ERR_RefPropertyMustHaveGetAccessor, "PI").WithLocation(18, 25), + // (19,25): error CS8145: Auto-implemented properties cannot return by reference + // ref object PJ { init { _ = field; } } + Diagnostic(ErrorCode.ERR_AutoPropertyCannotBeRefReturning, "PJ").WithLocation(19, 25), + // (19,25): error CS8146: Properties which return by reference must have a get accessor + // ref object PJ { init { _ = field; } } + Diagnostic(ErrorCode.ERR_RefPropertyMustHaveGetAccessor, "PJ").WithLocation(19, 25)); + } + + [Theory] + [CombinatorialData] + public void RefReturning_02(bool useStruct, bool useRefReadOnly) + { + string type = useStruct ? "struct" : "class"; + string refModifier = useRefReadOnly ? "ref readonly" : "ref "; + string source = $$""" + {{type}} S + { + static {{refModifier}} object P1 { get; } + static {{refModifier}} object P2 { get => ref field; } + static {{refModifier}} object P3 { get => ref field; set; } + static {{refModifier}} object P5 { get => ref field; set { } } + static {{refModifier}} object P7 { get => throw null; } + static {{refModifier}} object P8 { get => throw null; set; } + static {{refModifier}} object PC { get => throw null; set { _ = field; } } + static {{refModifier}} object PE { get; set; } + static {{refModifier}} object PG { get; set { } } + static {{refModifier}} object PI { set { _ = field; } } + } + """; + var comp = CreateCompilation(source, targetFramework: TargetFramework.Net80); + comp.VerifyEmitDiagnostics( + // (3,32): error CS8145: Auto-implemented properties cannot return by reference + // static ref object P1 { get; } + Diagnostic(ErrorCode.ERR_AutoPropertyCannotBeRefReturning, "P1").WithLocation(3, 32), + // (4,32): error CS8145: Auto-implemented properties cannot return by reference + // static ref object P2 { get => ref field; } + Diagnostic(ErrorCode.ERR_AutoPropertyCannotBeRefReturning, "P2").WithLocation(4, 32), + // (5,32): error CS8145: Auto-implemented properties cannot return by reference + // static ref object P3 { get => ref field; set; } + Diagnostic(ErrorCode.ERR_AutoPropertyCannotBeRefReturning, "P3").WithLocation(5, 32), + // (5,55): error CS8147: Properties which return by reference cannot have set accessors + // static ref object P3 { get => ref field; set; } + Diagnostic(ErrorCode.ERR_RefPropertyCannotHaveSetAccessor, "set").WithLocation(5, 55), + // (6,32): error CS8145: Auto-implemented properties cannot return by reference + // static ref object P5 { get => ref field; set { } } + Diagnostic(ErrorCode.ERR_AutoPropertyCannotBeRefReturning, "P5").WithLocation(6, 32), + // (6,55): error CS8147: Properties which return by reference cannot have set accessors + // static ref object P5 { get => ref field; set { } } + Diagnostic(ErrorCode.ERR_RefPropertyCannotHaveSetAccessor, "set").WithLocation(6, 55), + // (8,32): error CS8145: Auto-implemented properties cannot return by reference + // static ref object P8 { get => throw null; set; } + Diagnostic(ErrorCode.ERR_AutoPropertyCannotBeRefReturning, "P8").WithLocation(8, 32), + // (8,56): error CS8147: Properties which return by reference cannot have set accessors + // static ref object P8 { get => throw null; set; } + Diagnostic(ErrorCode.ERR_RefPropertyCannotHaveSetAccessor, "set").WithLocation(8, 56), + // (9,32): error CS8145: Auto-implemented properties cannot return by reference + // static ref object PC { get => throw null; set { _ = field; } } + Diagnostic(ErrorCode.ERR_AutoPropertyCannotBeRefReturning, "PC").WithLocation(9, 32), + // (9,56): error CS8147: Properties which return by reference cannot have set accessors + // static ref object PC { get => throw null; set { _ = field; } } + Diagnostic(ErrorCode.ERR_RefPropertyCannotHaveSetAccessor, "set").WithLocation(9, 56), + // (10,32): error CS8145: Auto-implemented properties cannot return by reference + // static ref object PE { get; set; } + Diagnostic(ErrorCode.ERR_AutoPropertyCannotBeRefReturning, "PE").WithLocation(10, 32), + // (10,42): error CS8147: Properties which return by reference cannot have set accessors + // static ref object PE { get; set; } + Diagnostic(ErrorCode.ERR_RefPropertyCannotHaveSetAccessor, "set").WithLocation(10, 42), + // (11,32): error CS8145: Auto-implemented properties cannot return by reference + // static ref object PG { get; set { } } + Diagnostic(ErrorCode.ERR_AutoPropertyCannotBeRefReturning, "PG").WithLocation(11, 32), + // (11,42): error CS8147: Properties which return by reference cannot have set accessors + // static ref object PG { get; set { } } + Diagnostic(ErrorCode.ERR_RefPropertyCannotHaveSetAccessor, "set").WithLocation(11, 42), + // (12,32): error CS8145: Auto-implemented properties cannot return by reference + // static ref object PI { set { _ = field; } } + Diagnostic(ErrorCode.ERR_AutoPropertyCannotBeRefReturning, "PI").WithLocation(12, 32), + // (12,32): error CS8146: Properties which return by reference must have a get accessor + // static ref object PI { set { _ = field; } } + Diagnostic(ErrorCode.ERR_RefPropertyMustHaveGetAccessor, "PI").WithLocation(12, 32)); + } + + // PROTOTYPE: Confirm that both accessors must be overridden. + [Theory] + [CombinatorialData] + public void Override_VirtualBase_01(bool useInit) + { + string setter = useInit ? "init" : "set"; + string sourceA = $$""" + class A + { + public virtual object P1 { get; {{setter}}; } + public virtual object P2 { get; } + public virtual object P3 { {{setter}}; } + } + """; + string sourceB0 = $$""" + class B0 : A + { + public override object P1 { get; } + public override object P2 { get; } + public override object P3 { get; } + } + """; + var comp = CreateCompilation([sourceA, sourceB0], targetFramework: TargetFramework.Net80); + comp.VerifyEmitDiagnostics( + // (3,28): error CS8080: Auto-implemented properties must override all accessors of the overridden property. + // public override object P1 { get; } + Diagnostic(ErrorCode.ERR_AutoPropertyMustOverrideSet, "P1").WithLocation(3, 28), + // (5,28): error CS8080: Auto-implemented properties must override all accessors of the overridden property. + // public override object P3 { get; } + Diagnostic(ErrorCode.ERR_AutoPropertyMustOverrideSet, "P3").WithLocation(5, 28), + // (5,32): error CS8051: Auto-implemented properties must have get accessors. + // public virtual object P3 { set; } + Diagnostic(ErrorCode.ERR_AutoPropertyMustHaveGetAccessor, setter).WithLocation(5, 32), + // (5,33): error CS0545: 'B0.P3.get': cannot override because 'A.P3' does not have an overridable get accessor + // public override object P3 { get; } + Diagnostic(ErrorCode.ERR_NoGetToOverride, "get").WithArguments("B0.P3.get", "A.P3").WithLocation(5, 33)); + + string sourceB1 = $$""" + class B1 : A + { + public override object P1 { get; {{setter}}; } + public override object P2 { get; {{setter}}; } + public override object P3 { get; {{setter}}; } + } + """; + comp = CreateCompilation([sourceA, sourceB1], targetFramework: TargetFramework.Net80); + comp.VerifyEmitDiagnostics( + // (4,38): error CS0546: 'B1.P2.set': cannot override because 'A.P2' does not have an overridable set accessor + // public override object P2 { get; set; } + Diagnostic(ErrorCode.ERR_NoSetToOverride, setter).WithArguments($"B1.P2.{setter}", "A.P2").WithLocation(4, 38), + // (5,32): error CS8051: Auto-implemented properties must have get accessors. + // public virtual object P3 { set; } + Diagnostic(ErrorCode.ERR_AutoPropertyMustHaveGetAccessor, setter).WithLocation(5, 32), + // (5,33): error CS0545: 'B1.P3.get': cannot override because 'A.P3' does not have an overridable get accessor + // public override object P3 { get; set; } + Diagnostic(ErrorCode.ERR_NoGetToOverride, "get").WithArguments("B1.P3.get", "A.P3").WithLocation(5, 33)); + + string sourceB2 = $$""" + class B2 : A + { + public override object P1 { get => field; {{setter}} { } } + public override object P2 { get => field; {{setter}} { } } + public override object P3 { get => field; {{setter}} { } } + } + """; + comp = CreateCompilation([sourceA, sourceB2], targetFramework: TargetFramework.Net80); + comp.VerifyEmitDiagnostics( + // (4,47): error CS0546: 'B2.P2.set': cannot override because 'A.P2' does not have an overridable set accessor + // public override object P2 { get => field; set { } } + Diagnostic(ErrorCode.ERR_NoSetToOverride, setter).WithArguments($"B2.P2.{setter}", "A.P2").WithLocation(4, 47), + // (5,32): error CS8051: Auto-implemented properties must have get accessors. + // public virtual object P3 { set; } + Diagnostic(ErrorCode.ERR_AutoPropertyMustHaveGetAccessor, setter).WithLocation(5, 32), + // (5,33): error CS0545: 'B2.P3.get': cannot override because 'A.P3' does not have an overridable get accessor + // public override object P3 { get => field; set { } } + Diagnostic(ErrorCode.ERR_NoGetToOverride, "get").WithArguments("B2.P3.get", "A.P3").WithLocation(5, 33)); + + string sourceB3 = $$""" + class B3 : A + { + public override object P1 { get => field; } + public override object P2 { get => field; } + public override object P3 { get => field; } + } + """; + comp = CreateCompilation([sourceA, sourceB3], targetFramework: TargetFramework.Net80); + comp.VerifyEmitDiagnostics( + // (3,28): error CS8080: Auto-implemented properties must override all accessors of the overridden property. + // public override object P1 { get => field; } + Diagnostic(ErrorCode.ERR_AutoPropertyMustOverrideSet, "P1").WithLocation(3, 28), + // (5,28): error CS8080: Auto-implemented properties must override all accessors of the overridden property. + // public override object P3 { get => field; } + Diagnostic(ErrorCode.ERR_AutoPropertyMustOverrideSet, "P3").WithLocation(5, 28), + // (5,32): error CS8051: Auto-implemented properties must have get accessors. + // public virtual object P3 { set; } + Diagnostic(ErrorCode.ERR_AutoPropertyMustHaveGetAccessor, setter).WithLocation(5, 32), + // (5,33): error CS0545: 'B3.P3.get': cannot override because 'A.P3' does not have an overridable get accessor + // public override object P3 { get => field; } + Diagnostic(ErrorCode.ERR_NoGetToOverride, "get").WithArguments("B3.P3.get", "A.P3").WithLocation(5, 33)); + + string sourceB4 = $$""" + class B4 : A + { + public override object P1 { {{setter}} { field = value; } } + public override object P2 { {{setter}} { field = value; } } + public override object P3 { {{setter}} { field = value; } } + } + """; + comp = CreateCompilation([sourceA, sourceB4], targetFramework: TargetFramework.Net80); + comp.VerifyEmitDiagnostics( + // (3,28): error CS8080: Auto-implemented properties must override all accessors of the overridden property. + // public override object P1 { set { field = value; } } + Diagnostic(ErrorCode.ERR_AutoPropertyMustOverrideSet, "P1").WithLocation(3, 28), + // (4,28): error CS8080: Auto-implemented properties must override all accessors of the overridden property. + // public override object P2 { set { field = value; } } + Diagnostic(ErrorCode.ERR_AutoPropertyMustOverrideSet, "P2").WithLocation(4, 28), + // (4,33): error CS0546: 'B4.P2.set': cannot override because 'A.P2' does not have an overridable set accessor + // public override object P2 { set { field = value; } } + Diagnostic(ErrorCode.ERR_NoSetToOverride, setter).WithArguments($"B4.P2.{setter}", "A.P2").WithLocation(4, 33), + // (5,32): error CS8051: Auto-implemented properties must have get accessors. + // public virtual object P3 { set; } + Diagnostic(ErrorCode.ERR_AutoPropertyMustHaveGetAccessor, setter).WithLocation(5, 32)); + } + + [Theory] + [CombinatorialData] + public void Override_AbstractBase_01(bool useInit) + { + string setter = useInit ? "init" : "set"; + string sourceA = $$""" + abstract class A + { + public abstract object P1 { get; {{setter}}; } + public abstract object P2 { get; } + public abstract object P3 { {{setter}}; } + } + """; + string sourceB0 = $$""" + class B0 : A + { + public override object P1 { get; } + public override object P2 { get; } + public override object P3 { get; } + } + """; + var comp = CreateCompilation([sourceA, sourceB0], targetFramework: TargetFramework.Net80); + comp.VerifyEmitDiagnostics( + // (1,7): error CS0534: 'B0' does not implement inherited abstract member 'A.P3.set' + // class B0 : A + Diagnostic(ErrorCode.ERR_UnimplementedAbstractMethod, "B0").WithArguments("B0", $"A.P3.{setter}").WithLocation(1, 7), + // (1,7): error CS0534: 'B0' does not implement inherited abstract member 'A.P1.set' + // class B0 : A + Diagnostic(ErrorCode.ERR_UnimplementedAbstractMethod, "B0").WithArguments("B0", $"A.P1.{setter}").WithLocation(1, 7), + // (3,28): error CS8080: Auto-implemented properties must override all accessors of the overridden property. + // public override object P1 { get; } + Diagnostic(ErrorCode.ERR_AutoPropertyMustOverrideSet, "P1").WithLocation(3, 28), + // (5,28): error CS8080: Auto-implemented properties must override all accessors of the overridden property. + // public override object P3 { get; } + Diagnostic(ErrorCode.ERR_AutoPropertyMustOverrideSet, "P3").WithLocation(5, 28), + // (5,33): error CS0545: 'B0.P3.get': cannot override because 'A.P3' does not have an overridable get accessor + // public override object P3 { get; } + Diagnostic(ErrorCode.ERR_NoGetToOverride, "get").WithArguments("B0.P3.get", "A.P3").WithLocation(5, 33)); + + string sourceB1 = $$""" + class B1 : A + { + public override object P1 { get; {{setter}}; } + public override object P2 { get; {{setter}}; } + public override object P3 { get; {{setter}}; } + } + """; + comp = CreateCompilation([sourceA, sourceB1], targetFramework: TargetFramework.Net80); + comp.VerifyEmitDiagnostics( + // (4,38): error CS0546: 'B1.P2.set': cannot override because 'A.P2' does not have an overridable set accessor + // public override object P2 { get; set; } + Diagnostic(ErrorCode.ERR_NoSetToOverride, setter).WithArguments($"B1.P2.{setter}", "A.P2").WithLocation(4, 38), + // (5,33): error CS0545: 'B1.P3.get': cannot override because 'A.P3' does not have an overridable get accessor + // public override object P3 { get; set; } + Diagnostic(ErrorCode.ERR_NoGetToOverride, "get").WithArguments("B1.P3.get", "A.P3").WithLocation(5, 33)); + + string sourceB2 = $$""" + class B2 : A + { + public override object P1 { get => field; {{setter}} { } } + public override object P2 { get => field; {{setter}} { } } + public override object P3 { get => field; {{setter}} { } } + } + """; + comp = CreateCompilation([sourceA, sourceB2], targetFramework: TargetFramework.Net80); + comp.VerifyEmitDiagnostics( + // (4,47): error CS0546: 'B2.P2.set': cannot override because 'A.P2' does not have an overridable set accessor + // public override object P2 { get => field; set { } } + Diagnostic(ErrorCode.ERR_NoSetToOverride, setter).WithArguments($"B2.P2.{setter}", "A.P2").WithLocation(4, 47), + // (5,33): error CS0545: 'B2.P3.get': cannot override because 'A.P3' does not have an overridable get accessor + // public override object P3 { get => field; set { } } + Diagnostic(ErrorCode.ERR_NoGetToOverride, "get").WithArguments("B2.P3.get", "A.P3").WithLocation(5, 33)); + + string sourceB3 = $$""" + class B3 : A + { + public override object P1 { get => field; } + public override object P2 { get => field; } + public override object P3 { get => field; } + } + """; + comp = CreateCompilation([sourceA, sourceB3], targetFramework: TargetFramework.Net80); + comp.VerifyEmitDiagnostics( + // (1,7): error CS0534: 'B3' does not implement inherited abstract member 'A.P3.set' + // class B3 : A + Diagnostic(ErrorCode.ERR_UnimplementedAbstractMethod, "B3").WithArguments("B3", $"A.P3.{setter}").WithLocation(1, 7), + // (1,7): error CS0534: 'B3' does not implement inherited abstract member 'A.P1.set' + // class B3 : A + Diagnostic(ErrorCode.ERR_UnimplementedAbstractMethod, "B3").WithArguments("B3", $"A.P1.{setter}").WithLocation(1, 7), + // (3,28): error CS8080: Auto-implemented properties must override all accessors of the overridden property. + // public override object P1 { get => field; } + Diagnostic(ErrorCode.ERR_AutoPropertyMustOverrideSet, "P1").WithLocation(3, 28), + // (5,28): error CS8080: Auto-implemented properties must override all accessors of the overridden property. + // public override object P3 { get => field; } + Diagnostic(ErrorCode.ERR_AutoPropertyMustOverrideSet, "P3").WithLocation(5, 28), + // (5,33): error CS0545: 'B3.P3.get': cannot override because 'A.P3' does not have an overridable get accessor + // public override object P3 { get => field; } + Diagnostic(ErrorCode.ERR_NoGetToOverride, "get").WithArguments("B3.P3.get", "A.P3").WithLocation(5, 33)); + + string sourceB4 = $$""" + class B4 : A + { + public override object P1 { {{setter}} { field = value; } } + public override object P2 { {{setter}} { field = value; } } + public override object P3 { {{setter}} { field = value; } } + } + """; + comp = CreateCompilation([sourceA, sourceB4], targetFramework: TargetFramework.Net80); + comp.VerifyEmitDiagnostics( + // (1,7): error CS0534: 'B4' does not implement inherited abstract member 'A.P1.get' + // class B4 : A + Diagnostic(ErrorCode.ERR_UnimplementedAbstractMethod, "B4").WithArguments("B4", "A.P1.get").WithLocation(1, 7), + // (1,7): error CS0534: 'B4' does not implement inherited abstract member 'A.P2.get' + // class B4 : A + Diagnostic(ErrorCode.ERR_UnimplementedAbstractMethod, "B4").WithArguments("B4", "A.P2.get").WithLocation(1, 7), + // (3,28): error CS8080: Auto-implemented properties must override all accessors of the overridden property. + // public override object P1 { set { field = value; } } + Diagnostic(ErrorCode.ERR_AutoPropertyMustOverrideSet, "P1").WithLocation(3, 28), + // (4,28): error CS8080: Auto-implemented properties must override all accessors of the overridden property. + // public override object P2 { set { field = value; } } + Diagnostic(ErrorCode.ERR_AutoPropertyMustOverrideSet, "P2").WithLocation(4, 28), + // (4,33): error CS0546: 'B4.P2.set': cannot override because 'A.P2' does not have an overridable set accessor + // public override object P2 { set { field = value; } } + Diagnostic(ErrorCode.ERR_NoSetToOverride, setter).WithArguments($"B4.P2.{setter}", "A.P2").WithLocation(4, 33)); + } + + [Theory] + [CombinatorialData] + public void New_01(bool useInit) + { + string setter = useInit ? "init" : "set"; + string source = $$""" + class A + { + public virtual object P1 { get; {{setter}}; } + public virtual object P2 { get; } + public virtual object P3 { {{setter}}; } + } + class B0 : A + { + public new object P1 { get; } + public new object P2 { get; } + public new object P3 { get; } + } + class B1 : A + { + public new object P1 { get; {{setter}}; } + public new object P2 { get; {{setter}}; } + public new object P3 { get; {{setter}}; } + } + class B2 : A + { + public new object P1 { get => field; {{setter}} { } } + public new object P2 { get => field; {{setter}} { } } + public new object P3 { get => field; {{setter}} { } } + } + class B3 : A + { + public new object P1 { get => field; } + public new object P2 { get => field; } + public new object P3 { get => field; } + } + class B4 : A + { + public new object P1 { {{setter}} { field = value; } } + public new object P2 { {{setter}} { field = value; } } + public new object P3 { {{setter}} { field = value; } } + } + """; + var comp = CreateCompilation(source, targetFramework: TargetFramework.Net80); + comp.VerifyEmitDiagnostics( + // (5,32): error CS8051: Auto-implemented properties must have get accessors. + // public virtual object P3 { set; } + Diagnostic(ErrorCode.ERR_AutoPropertyMustHaveGetAccessor, setter).WithLocation(5, 32)); + } + + [Theory] + [InlineData(false, false)] + [InlineData(false, true)] + [InlineData(true, false)] + public void CompilerGeneratedAttribute(bool missingType, bool missingConstructor) + { + string source = """ + using System; + using System.Reflection; + + class C + { + public int P1 { get; } + public int P2 { get => field; } + public int P3 { set { field = value; } } + public int P4 { init { field = value; } } + } + + class Program + { + static void Main() + { + foreach (var field in typeof(C).GetFields(BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static)) + ReportField(field); + } + + static void ReportField(FieldInfo field) + { + Console.Write("{0}.{1}:", field.DeclaringType.Name, field.Name); + foreach (var obj in field.GetCustomAttributes()) + Console.Write(" {0},", obj.ToString()); + Console.WriteLine(); + } + } + """; + var comp = CreateCompilation(source, targetFramework: TargetFramework.Net80, options: TestOptions.ReleaseExe); + if (missingType) + { + comp.MakeTypeMissing(WellKnownType.System_Runtime_CompilerServices_CompilerGeneratedAttribute); + } + if (missingConstructor) + { + comp.MakeMemberMissing(WellKnownMember.System_Runtime_CompilerServices_CompilerGeneratedAttribute__ctor); + } + string expectedAttributes = (missingType || missingConstructor) ? "" : " System.Runtime.CompilerServices.CompilerGeneratedAttribute,"; + CompileAndVerify(comp, verify: Verification.Skipped, expectedOutput: IncludeExpectedOutput($$""" + C.k__BackingField:{{expectedAttributes}} + C.k__BackingField:{{expectedAttributes}} + C.k__BackingField:{{expectedAttributes}} + C.k__BackingField:{{expectedAttributes}} + """)); + } + [Fact] public void RestrictedTypes() { From 793a04b1682c8811a4830bb7639fa054490bcef1 Mon Sep 17 00:00:00 2001 From: Charles Stoner <10732005+cston@users.noreply.github.com> Date: Sun, 18 Aug 2024 21:26:00 -0700 Subject: [PATCH 02/21] Fix tests --- .../CSharp/Test/Emit/CodeGen/CodeGenRefLocalTests.cs | 4 ++-- .../CSharp/Test/Emit/CodeGen/CodeGenRefReturnTests.cs | 4 ++-- .../Test/Semantic/Semantics/NullableReferenceTypesTests.cs | 3 +++ 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenRefLocalTests.cs b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenRefLocalTests.cs index 23cf311d431af..70450c3879552 100644 --- a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenRefLocalTests.cs +++ b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenRefLocalTests.cs @@ -1761,7 +1761,7 @@ public void RefAssignStaticProperty() class Program { static int field = 0; - static ref int P { get { return ref field; } } + static ref int P { get { return ref @field; } } static void M() { @@ -1789,7 +1789,7 @@ public void RefAssignClassInstanceProperty() class Program { int field = 0; - ref int P { get { return ref field; } } + ref int P { get { return ref @field; } } void M() { diff --git a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenRefReturnTests.cs b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenRefReturnTests.cs index c9ead91a833c5..82cd6e6b97d32 100644 --- a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenRefReturnTests.cs +++ b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenRefReturnTests.cs @@ -1258,7 +1258,7 @@ class Program { int field = 0; - ref int P { get { return ref field; } } + ref int P { get { return ref @field; } } ref int this[int i] { get { return ref field; } } @@ -1455,7 +1455,7 @@ class Program { int field = 0; - ref int P { get { return ref field; } } + ref int P { get { return ref @field; } } ref int this[int i] { get { return ref field; } } diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/NullableReferenceTypesTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/NullableReferenceTypesTests.cs index 1f13aa457cc29..3569fdcb0d1b4 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/NullableReferenceTypesTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/NullableReferenceTypesTests.cs @@ -15264,6 +15264,9 @@ public override Func P1 { set {} } // warn // (15,39): warning CS8767: Nullability of reference types in type of parameter 'value' of 'void C.P1.set' doesn't match implicitly implemented member 'void A.P1.set' (possibly because of nullability attributes). // public override Func P1 { set {} } // warn Diagnostic(ErrorCode.WRN_TopLevelNullabilityMismatchInParameterTypeOnImplicitImplementation, "set").WithArguments("value", "void C.P1.set", "void A.P1.set").WithLocation(15, 39), + // (16,34): error CS8080: Auto-implemented properties must override all accessors of the overridden property. + // public override Func P2 { set; } // warn + Diagnostic(ErrorCode.ERR_AutoPropertyMustOverrideSet, "P2").WithLocation(16, 34), // (16,34): warning CS8618: Non-nullable property 'P2' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the property as nullable. // public override Func P2 { set; } // warn Diagnostic(ErrorCode.WRN_UninitializedNonNullableField, "P2").WithArguments("property", "P2").WithLocation(16, 34), From 9630eb5aa86847c210d584f5adf095ca356b51d3 Mon Sep 17 00:00:00 2001 From: Charles Stoner <10732005+cston@users.noreply.github.com> Date: Mon, 19 Aug 2024 16:50:12 -0700 Subject: [PATCH 03/21] Verify ERR_AutoPropertyMustHaveGetAccessor for { set; } only --- .../Source/SourcePropertySymbolBase.cs | 3 ++ .../CSharp/Test/Emit3/FieldKeywordTests.cs | 43 +++++++++++++++++++ 2 files changed, 46 insertions(+) diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertySymbolBase.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertySymbolBase.cs index d50d8586b0b5d..b3a47c4ffdc90 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertySymbolBase.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertySymbolBase.cs @@ -798,6 +798,9 @@ internal override void AfterAddingTypeMembersChecks(ConversionsBase conversions, } else if (!hasGetAccessor && IsAutoProperty) { + // The only forms of auto-property that are disallowed are { set; } and { init; }. + // Other forms of auto- or explicitly-implemented accessors are allowed + // including equivalent field cases such as { set { field = value; } }. diagnostics.Add(ErrorCode.ERR_AutoPropertyMustHaveGetAccessor, _setMethod!.GetFirstLocation()); } diff --git a/src/Compilers/CSharp/Test/Emit3/FieldKeywordTests.cs b/src/Compilers/CSharp/Test/Emit3/FieldKeywordTests.cs index 56c29390e318c..19954392fa8bf 100644 --- a/src/Compilers/CSharp/Test/Emit3/FieldKeywordTests.cs +++ b/src/Compilers/CSharp/Test/Emit3/FieldKeywordTests.cs @@ -1971,6 +1971,49 @@ public void RefReturning_02(bool useStruct, bool useRefReadOnly) Diagnostic(ErrorCode.ERR_RefPropertyMustHaveGetAccessor, "PI").WithLocation(12, 32)); } + [Theory] + [InlineData(false, false)] + [InlineData(false, true)] + [InlineData(true, false)] + public void SetOnly(bool useStatic, bool useInit) + { + string modifier = useStatic ? "static" : " "; + string setter = useInit ? "init" : "set"; + string source = $$""" + class C + { + {{modifier}} object P02 { {{setter}}; } + {{modifier}} object P03 { {{setter}} { } } + {{modifier}} object P04 { {{setter}} { field = value; } } + {{modifier}} object P11 { get; } + {{modifier}} object P12 { get; {{setter}}; } + {{modifier}} object P13 { get; {{setter}} { } } + {{modifier}} object P14 { get; {{setter}} { field = value; } } + {{modifier}} object P21 { get => field; } + {{modifier}} object P22 { get => field; {{setter}}; } + {{modifier}} object P23 { get => field; {{setter}} { } } + {{modifier}} object P24 { get => field; {{setter}} { field = value; } } + {{modifier}} object P31 { get => null; } + {{modifier}} object P32 { get => null; {{setter}}; } + {{modifier}} object P33 { get => null; {{setter}} { } } + {{modifier}} object P34 { get => null; {{setter}} { field = value; } } + {{modifier}} object P41 { get { return field; } } + {{modifier}} object P42 { get { return field; } {{setter}}; } + {{modifier}} object P43 { get { return field; } {{setter}} { } } + {{modifier}} object P44 { get { return field; } {{setter}} { field = value; } } + {{modifier}} object P51 { get { return null; } } + {{modifier}} object P52 { get { return null; } {{setter}}; } + {{modifier}} object P53 { get { return null; } {{setter}} { } } + {{modifier}} object P54 { get { return null; } {{setter}} { field = value; } } + } + """; + var comp = CreateCompilation(source, targetFramework: TargetFramework.Net80); + comp.VerifyEmitDiagnostics( + // (3,25): error CS8051: Auto-implemented properties must have get accessors. + // object P02 { set; } + Diagnostic(ErrorCode.ERR_AutoPropertyMustHaveGetAccessor, setter).WithLocation(3, 25)); + } + // PROTOTYPE: Confirm that both accessors must be overridden. [Theory] [CombinatorialData] From 571a39278b10e680c57d47cb08763f89181b27c3 Mon Sep 17 00:00:00 2001 From: Charles Stoner <10732005+cston@users.noreply.github.com> Date: Tue, 20 Aug 2024 13:33:45 -0700 Subject: [PATCH 04/21] Add default implementation tests --- .../DefaultInterfaceImplementationTests.cs | 120 +++++++++++++++++- 1 file changed, 118 insertions(+), 2 deletions(-) diff --git a/src/Compilers/CSharp/Test/Symbol/Symbols/DefaultInterfaceImplementationTests.cs b/src/Compilers/CSharp/Test/Symbol/Symbols/DefaultInterfaceImplementationTests.cs index 9e8c95afbbc13..9993a1b66ffd2 100644 --- a/src/Compilers/CSharp/Test/Symbol/Symbols/DefaultInterfaceImplementationTests.cs +++ b/src/Compilers/CSharp/Test/Symbol/Symbols/DefaultInterfaceImplementationTests.cs @@ -3346,7 +3346,7 @@ public interface I1 [Theory] [CombinatorialData] - public void PropertyImplementation_109(bool isStatic, bool useCSharp13) + public void PropertyImplementation_109A(bool isStatic, bool useCSharp13) { string declModifiers = isStatic ? "static virtual " : ""; @@ -3419,9 +3419,69 @@ class Test1 : I1 Assert.True(setP1.IsMetadataVirtual()); } + [Fact] + public void PropertyImplementation_109B() + { + var source1 = +@" +public interface I1 +{ + static int P1 + { + get + { + System.Console.WriteLine(""get P1""); + return 0; + } + set; + } +} + +class Test1 : I1 +{} +"; + var compilation1 = CreateCompilation(source1, options: TestOptions.DebugDll, + parseOptions: TestOptions.RegularPreview, + targetFramework: TargetFramework.Net60); + Assert.True(compilation1.Assembly.RuntimeSupportsDefaultInterfaceImplementation); + + // According to LDM decision captured at https://github.com/dotnet/csharplang/blob/main/meetings/2017/LDM-2017-04-18.md, + // we don't want to allow only one accessor to have an implementation. + compilation1.VerifyDiagnostics( + // (11,9): error CS0501: 'I1.P1.set' must declare a body because it is not marked abstract, extern, or partial + // set; + Diagnostic(ErrorCode.ERR_ConcreteMissingBody, "set").WithArguments("I1.P1.set").WithLocation(11, 9) + ); + + var p1 = compilation1.GetMember("I1.P1"); + var getP1 = p1.GetMethod; + var setP1 = p1.SetMethod; + Assert.False(p1.IsReadOnly); + Assert.False(p1.IsWriteOnly); + + var field1 = ((SourcePropertySymbolBase)p1).BackingField; + Assert.Equal("System.Int32 I1.k__BackingField", field1?.ToTestDisplayString()); + + Assert.False(p1.IsAbstract); + Assert.False(p1.IsVirtual); + Assert.False(getP1.IsAbstract); + Assert.False(getP1.IsVirtual); + Assert.False(setP1.IsAbstract); + Assert.False(setP1.IsVirtual); + + var test1 = compilation1.GetTypeByMetadataName("Test1"); + + Assert.Null(test1.FindImplementationForInterfaceMember(p1)); + Assert.Null(test1.FindImplementationForInterfaceMember(getP1)); + Assert.Null(test1.FindImplementationForInterfaceMember(setP1)); + + Assert.False(getP1.IsMetadataVirtual()); + Assert.False(setP1.IsMetadataVirtual()); + } + [Theory] [CombinatorialData] - public void PropertyImplementation_110(bool isStatic, bool useCSharp13) + public void PropertyImplementation_110A(bool isStatic, bool useCSharp13) { string declModifiers = isStatic ? "static virtual " : ""; @@ -3490,6 +3550,62 @@ class Test1 : I1 Assert.True(setP1.IsMetadataVirtual()); } + [Fact] + public void PropertyImplementation_110B() + { + var source1 = +@" +public interface I1 +{ + static int P1 + { + get; + set => System.Console.WriteLine(""set P1""); + } +} + +class Test1 : I1 +{} +"; + var compilation1 = CreateCompilation(source1, options: TestOptions.DebugDll, + parseOptions: TestOptions.RegularPreview, + targetFramework: TargetFramework.Net60); + Assert.True(compilation1.Assembly.RuntimeSupportsDefaultInterfaceImplementation); + + // According to LDM decision captured at https://github.com/dotnet/csharplang/blob/main/meetings/2017/LDM-2017-04-18.md, + // we don't want to allow only one accessor to have an implementation. + compilation1.VerifyDiagnostics( + // (6,9): error CS0501: 'I1.P1.get' must declare a body because it is not marked abstract, extern, or partial + // get; + Diagnostic(ErrorCode.ERR_ConcreteMissingBody, "get").WithArguments("I1.P1.get").WithLocation(6, 9) + ); + + var p1 = compilation1.GetMember("I1.P1"); + var getP1 = p1.GetMethod; + var setP1 = p1.SetMethod; + Assert.False(p1.IsReadOnly); + Assert.False(p1.IsWriteOnly); + + var field1 = ((SourcePropertySymbolBase)p1).BackingField; + Assert.Equal("System.Int32 I1.k__BackingField", field1?.ToTestDisplayString()); + + Assert.False(p1.IsAbstract); + Assert.False(p1.IsVirtual); + Assert.False(getP1.IsAbstract); + Assert.False(getP1.IsVirtual); + Assert.False(setP1.IsAbstract); + Assert.False(setP1.IsVirtual); + + var test1 = compilation1.GetTypeByMetadataName("Test1"); + + Assert.Null(test1.FindImplementationForInterfaceMember(p1)); + Assert.Null(test1.FindImplementationForInterfaceMember(getP1)); + Assert.Null(test1.FindImplementationForInterfaceMember(setP1)); + + Assert.False(getP1.IsMetadataVirtual()); + Assert.False(setP1.IsMetadataVirtual()); + } + [Theory] [CombinatorialData] public void PropertyImplementation_201(bool isStatic) From e083fc01a965669cc406a34486eeaf5ec0f0380c Mon Sep 17 00:00:00 2001 From: Charles Stoner <10732005+cston@users.noreply.github.com> Date: Tue, 20 Aug 2024 13:34:57 -0700 Subject: [PATCH 05/21] Update default implementation tests --- .../DefaultInterfaceImplementationTests.cs | 66 +++++++++++-------- 1 file changed, 40 insertions(+), 26 deletions(-) diff --git a/src/Compilers/CSharp/Test/Symbol/Symbols/DefaultInterfaceImplementationTests.cs b/src/Compilers/CSharp/Test/Symbol/Symbols/DefaultInterfaceImplementationTests.cs index 9993a1b66ffd2..2f460948136dd 100644 --- a/src/Compilers/CSharp/Test/Symbol/Symbols/DefaultInterfaceImplementationTests.cs +++ b/src/Compilers/CSharp/Test/Symbol/Symbols/DefaultInterfaceImplementationTests.cs @@ -3373,9 +3373,6 @@ class Test1 : I1 targetFramework: TargetFramework.Net60); Assert.True(compilation1.Assembly.RuntimeSupportsDefaultInterfaceImplementation); - // PROTOTYPE: Confirm that we now allow one accessor to have an implementation. - // According to LDM decision captured at https://github.com/dotnet/csharplang/blob/main/meetings/2017/LDM-2017-04-18.md, - // we don't want to allow only one accessor to have an implementation. if (isStatic && useCSharp13) { compilation1.VerifyDiagnostics( @@ -3389,6 +3386,8 @@ class Test1 : I1 } else { + // According to LDM decision captured at https://github.com/dotnet/csharplang/blob/main/meetings/2017/LDM-2017-04-18.md, + // we don't want to allow only one accessor to have an implementation. compilation1.VerifyDiagnostics( // (11,9): error CS0501: 'I1.P1.set' must declare a body because it is not marked abstract, extern, or partial // set; @@ -3402,6 +3401,9 @@ class Test1 : I1 Assert.False(p1.IsReadOnly); Assert.False(p1.IsWriteOnly); + var field1 = ((SourcePropertySymbolBase)p1).BackingField; + Assert.Equal(isStatic ? "System.Int32 I1.k__BackingField" : null, field1?.ToTestDisplayString()); + Assert.False(p1.IsAbstract); Assert.True(p1.IsVirtual); Assert.False(getP1.IsAbstract); @@ -3419,8 +3421,9 @@ class Test1 : I1 Assert.True(setP1.IsMetadataVirtual()); } - [Fact] - public void PropertyImplementation_109B() + [Theory] + [CombinatorialData] + public void PropertyImplementation_109B(bool useCSharp13) { var source1 = @" @@ -3441,17 +3444,21 @@ class Test1 : I1 {} "; var compilation1 = CreateCompilation(source1, options: TestOptions.DebugDll, - parseOptions: TestOptions.RegularPreview, + parseOptions: useCSharp13 ? TestOptions.Regular13 : TestOptions.RegularPreview, targetFramework: TargetFramework.Net60); Assert.True(compilation1.Assembly.RuntimeSupportsDefaultInterfaceImplementation); - // According to LDM decision captured at https://github.com/dotnet/csharplang/blob/main/meetings/2017/LDM-2017-04-18.md, - // we don't want to allow only one accessor to have an implementation. - compilation1.VerifyDiagnostics( - // (11,9): error CS0501: 'I1.P1.set' must declare a body because it is not marked abstract, extern, or partial - // set; - Diagnostic(ErrorCode.ERR_ConcreteMissingBody, "set").WithArguments("I1.P1.set").WithLocation(11, 9) - ); + if (useCSharp13) + { + compilation1.VerifyDiagnostics( + // (4,16): error CS8652: The feature 'field keyword' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // static int P1 + Diagnostic(ErrorCode.ERR_FeatureInPreview, "P1").WithArguments("field keyword").WithLocation(4, 16)); + } + else + { + compilation1.VerifyDiagnostics(); + } var p1 = compilation1.GetMember("I1.P1"); var getP1 = p1.GetMethod; @@ -3504,9 +3511,6 @@ class Test1 : I1 targetFramework: TargetFramework.Net60); Assert.True(compilation1.Assembly.RuntimeSupportsDefaultInterfaceImplementation); - // PROTOTYPE: Confirm that we now allow one accessor to have an implementation. - // According to LDM decision captured at https://github.com/dotnet/csharplang/blob/main/meetings/2017/LDM-2017-04-18.md, - // we don't want to allow only one accessor to have an implementation. if (isStatic && useCSharp13) { compilation1.VerifyDiagnostics( @@ -3520,6 +3524,8 @@ class Test1 : I1 } else { + // According to LDM decision captured at https://github.com/dotnet/csharplang/blob/main/meetings/2017/LDM-2017-04-18.md, + // we don't want to allow only one accessor to have an implementation. compilation1.VerifyDiagnostics( // (6,9): error CS0501: 'I1.P1.get' must declare a body because it is not marked abstract, extern, or partial // get; @@ -3533,6 +3539,9 @@ class Test1 : I1 Assert.False(p1.IsReadOnly); Assert.False(p1.IsWriteOnly); + var field1 = ((SourcePropertySymbolBase)p1).BackingField; + Assert.Equal(isStatic ? "System.Int32 I1.k__BackingField" : null, field1?.ToTestDisplayString()); + Assert.False(p1.IsAbstract); Assert.True(p1.IsVirtual); Assert.False(getP1.IsAbstract); @@ -3550,8 +3559,9 @@ class Test1 : I1 Assert.True(setP1.IsMetadataVirtual()); } - [Fact] - public void PropertyImplementation_110B() + [Theory] + [CombinatorialData] + public void PropertyImplementation_110B(bool useCSharp13) { var source1 = @" @@ -3568,17 +3578,21 @@ class Test1 : I1 {} "; var compilation1 = CreateCompilation(source1, options: TestOptions.DebugDll, - parseOptions: TestOptions.RegularPreview, + parseOptions: useCSharp13 ? TestOptions.Regular13 : TestOptions.RegularPreview, targetFramework: TargetFramework.Net60); Assert.True(compilation1.Assembly.RuntimeSupportsDefaultInterfaceImplementation); - // According to LDM decision captured at https://github.com/dotnet/csharplang/blob/main/meetings/2017/LDM-2017-04-18.md, - // we don't want to allow only one accessor to have an implementation. - compilation1.VerifyDiagnostics( - // (6,9): error CS0501: 'I1.P1.get' must declare a body because it is not marked abstract, extern, or partial - // get; - Diagnostic(ErrorCode.ERR_ConcreteMissingBody, "get").WithArguments("I1.P1.get").WithLocation(6, 9) - ); + if (useCSharp13) + { + compilation1.VerifyDiagnostics( + // (4,16): error CS8652: The feature 'field keyword' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // static int P1 + Diagnostic(ErrorCode.ERR_FeatureInPreview, "P1").WithArguments("field keyword").WithLocation(4, 16)); + } + else + { + compilation1.VerifyDiagnostics(); + } var p1 = compilation1.GetMember("I1.P1"); var getP1 = p1.GetMethod; From 2adf311dc1e681261cff091fa76a0071fac0b361 Mon Sep 17 00:00:00 2001 From: Charles Stoner <10732005+cston@users.noreply.github.com> Date: Tue, 20 Aug 2024 13:45:44 -0700 Subject: [PATCH 06/21] Remove comments --- .../CSharp/Portable/Symbols/Source/SourcePropertySymbolBase.cs | 1 - src/Compilers/CSharp/Test/Emit3/FieldKeywordTests.cs | 3 --- 2 files changed, 4 deletions(-) diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertySymbolBase.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertySymbolBase.cs index b3a47c4ffdc90..659e631e97b7b 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertySymbolBase.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertySymbolBase.cs @@ -662,7 +662,6 @@ internal bool IsAutoProperty protected bool AccessorsHaveImplementation => (_propertyFlags & Flags.AccessorsHaveImplementation) != 0; - // PROTOTYPE: Should this be IsAutoProperty? internal bool HasSynthesizedBackingField => IsAutoProperty || UsesFieldKeyword; diff --git a/src/Compilers/CSharp/Test/Emit3/FieldKeywordTests.cs b/src/Compilers/CSharp/Test/Emit3/FieldKeywordTests.cs index 19954392fa8bf..b8a0eaaa4c364 100644 --- a/src/Compilers/CSharp/Test/Emit3/FieldKeywordTests.cs +++ b/src/Compilers/CSharp/Test/Emit3/FieldKeywordTests.cs @@ -1028,8 +1028,6 @@ static void ReportField(FieldInfo field) """)); } - // PROTOTYPE: Confirm we want to allow mixed auto- and explicitly-implemented - // accessors when explicitly-implemented accessors do not use 'field'. [Fact] public void Initializer_01() { @@ -2014,7 +2012,6 @@ class C Diagnostic(ErrorCode.ERR_AutoPropertyMustHaveGetAccessor, setter).WithLocation(3, 25)); } - // PROTOTYPE: Confirm that both accessors must be overridden. [Theory] [CombinatorialData] public void Override_VirtualBase_01(bool useInit) From 889c4e44a248ff9f11973a51366f8c63813e4347 Mon Sep 17 00:00:00 2001 From: Charles Stoner <10732005+cston@users.noreply.github.com> Date: Tue, 20 Aug 2024 14:58:49 -0700 Subject: [PATCH 07/21] Add ConditionalAttribute test --- .../CSharp/Test/Emit3/FieldKeywordTests.cs | 96 +++++++++++++++++++ 1 file changed, 96 insertions(+) diff --git a/src/Compilers/CSharp/Test/Emit3/FieldKeywordTests.cs b/src/Compilers/CSharp/Test/Emit3/FieldKeywordTests.cs index b8a0eaaa4c364..42c985e7b413b 100644 --- a/src/Compilers/CSharp/Test/Emit3/FieldKeywordTests.cs +++ b/src/Compilers/CSharp/Test/Emit3/FieldKeywordTests.cs @@ -2364,6 +2364,102 @@ static void ReportField(FieldInfo field) """)); } + [Theory] + [CombinatorialData] + public void Conditional(bool useDEBUG) + { + string sourceA = """ + using System.Diagnostics; + class C + { + public static object P1 { get { M(field); return null; } set { } } + public static object P2 { get { return null; } set { M(field); } } + public object P3 { get { M(field); return null; } } + public object P4 { set { M(field); } } + public object P5 { init { M(field); } } + [Conditional("DEBUG")] + static void M( object o) { } + } + """; + string sourceB = """ + using System; + using System.Reflection; + class Program + { + static void Main() + { + foreach (var field in typeof(C).GetFields(BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static)) + ReportField(field); + } + static void ReportField(FieldInfo field) + { + Console.Write("{0}.{1}:", field.DeclaringType.Name, field.Name); + foreach (var obj in field.GetCustomAttributes()) + Console.Write(" {0},", obj.ToString()); + Console.WriteLine(); + } + } + """; + var parseOptions = TestOptions.RegularNext; + if (useDEBUG) + { + parseOptions = parseOptions.WithPreprocessorSymbols("DEBUG"); + } + var verifier = CompileAndVerify( + [sourceA, sourceB], + parseOptions: parseOptions, + targetFramework: TargetFramework.Net80, + verify: Verification.Skipped, + expectedOutput: """ + C.k__BackingField: System.Runtime.CompilerServices.CompilerGeneratedAttribute, + C.k__BackingField: System.Runtime.CompilerServices.CompilerGeneratedAttribute, + C.k__BackingField: System.Runtime.CompilerServices.CompilerGeneratedAttribute, + C.k__BackingField: System.Runtime.CompilerServices.CompilerGeneratedAttribute, + C.k__BackingField: System.Runtime.CompilerServices.CompilerGeneratedAttribute, + """); + if (useDEBUG) + { + verifier.VerifyIL("C.P1.get", """ + { + // Code size 12 (0xc) + .maxstack 1 + IL_0000: ldsfld "object C.k__BackingField" + IL_0005: call "void C.M(object)" + IL_000a: ldnull + IL_000b: ret + } + """); + verifier.VerifyIL("C.P4.set", """ + { + // Code size 12 (0xc) + .maxstack 1 + IL_0000: ldarg.0 + IL_0001: ldfld "object C.k__BackingField" + IL_0006: call "void C.M(object)" + IL_000b: ret + } + """); + } + else + { + verifier.VerifyIL("C.P1.get", """ + { + // Code size 2 (0x2) + .maxstack 1 + IL_0000: ldnull + IL_0001: ret + } + """); + verifier.VerifyIL("C.P4.set", """ + { + // Code size 1 (0x1) + .maxstack 0 + IL_0000: ret + } + """); + } + } + [Fact] public void RestrictedTypes() { From 4501eb8b5911867c7796715ee2f4f725459af29e Mon Sep 17 00:00:00 2001 From: Charles Stoner <10732005+cston@users.noreply.github.com> Date: Tue, 20 Aug 2024 19:18:49 -0700 Subject: [PATCH 08/21] Fix test --- src/Compilers/CSharp/Test/Emit3/FieldKeywordTests.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Compilers/CSharp/Test/Emit3/FieldKeywordTests.cs b/src/Compilers/CSharp/Test/Emit3/FieldKeywordTests.cs index 42c985e7b413b..d9488026663cf 100644 --- a/src/Compilers/CSharp/Test/Emit3/FieldKeywordTests.cs +++ b/src/Compilers/CSharp/Test/Emit3/FieldKeywordTests.cs @@ -2410,13 +2410,13 @@ static void ReportField(FieldInfo field) parseOptions: parseOptions, targetFramework: TargetFramework.Net80, verify: Verification.Skipped, - expectedOutput: """ + expectedOutput: IncludeExpectedOutput(""" C.k__BackingField: System.Runtime.CompilerServices.CompilerGeneratedAttribute, C.k__BackingField: System.Runtime.CompilerServices.CompilerGeneratedAttribute, C.k__BackingField: System.Runtime.CompilerServices.CompilerGeneratedAttribute, C.k__BackingField: System.Runtime.CompilerServices.CompilerGeneratedAttribute, C.k__BackingField: System.Runtime.CompilerServices.CompilerGeneratedAttribute, - """); + """)); if (useDEBUG) { verifier.VerifyIL("C.P1.get", """ From 8fdd1e32d9b460b82c1b5393bcca206474f994a2 Mon Sep 17 00:00:00 2001 From: Charles Stoner <10732005+cston@users.noreply.github.com> Date: Wed, 21 Aug 2024 18:08:04 -0700 Subject: [PATCH 09/21] Revert name change for IsAutoPropertyOrUsesFieldKeyword --- .../CSharp/Portable/Binder/Binder_Statements.cs | 2 +- .../LocalRewriter_AssignmentOperator.cs | 2 +- .../Symbols/Source/SourcePropertySymbolBase.cs | 14 +++++++------- .../Synthesized/SynthesizedBackingFieldSymbol.cs | 2 +- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Statements.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Statements.cs index c434f180c41c5..64e79b538710c 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder_Statements.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder_Statements.cs @@ -1765,7 +1765,7 @@ private static bool AccessingAutoPropertyFromConstructor(BoundExpression receive var propertyIsStatic = propertySymbol.IsStatic; return (object)sourceProperty != null && - sourceProperty.HasSynthesizedBackingField && + sourceProperty.IsAutoPropertyOrUsesFieldKeyword && TypeSymbol.Equals(sourceProperty.ContainingType, fromMember.ContainingType, TypeCompareKind.AllIgnoreOptions) && IsConstructorOrField(fromMember, isStatic: propertyIsStatic) && (propertyIsStatic || receiver.Kind == BoundKind.ThisReference); diff --git a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_AssignmentOperator.cs b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_AssignmentOperator.cs index 4d96adb6330df..9a2d1ec5b9caa 100644 --- a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_AssignmentOperator.cs +++ b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_AssignmentOperator.cs @@ -281,7 +281,7 @@ private BoundExpression MakePropertyAssignment( if (setMethod is null) { var autoProp = (SourcePropertySymbolBase)property.OriginalDefinition; - Debug.Assert(autoProp.HasSynthesizedBackingField, + Debug.Assert(autoProp.IsAutoPropertyOrUsesFieldKeyword, "only autoproperties can be assignable without having setters"); Debug.Assert(_factory.CurrentFunction.IsConstructor()); Debug.Assert(property.Equals(autoProp, TypeCompareKind.IgnoreNullableModifiersForReferenceTypes)); diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertySymbolBase.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertySymbolBase.cs index 659e631e97b7b..5819a753625f0 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertySymbolBase.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertySymbolBase.cs @@ -302,7 +302,7 @@ protected void CheckInitializerIfNeeded(BindingDiagnosticBag diagnostics) { diagnostics.Add(ErrorCode.ERR_InstancePropertyInitializerInInterface, Location); } - else if (!HasSynthesizedBackingField) + else if (!IsAutoPropertyOrUsesFieldKeyword) { diagnostics.Add(ErrorCode.ERR_InitializerOnNonAutoProperty, Location); } @@ -650,6 +650,9 @@ public bool HasSkipLocalsInitAttribute } } + internal bool IsAutoPropertyOrUsesFieldKeyword + => IsAutoProperty || UsesFieldKeyword; + private bool UsesFieldKeyword => (_propertyFlags & Flags.UsesFieldKeyword) != 0; @@ -662,9 +665,6 @@ internal bool IsAutoProperty protected bool AccessorsHaveImplementation => (_propertyFlags & Flags.AccessorsHaveImplementation) != 0; - internal bool HasSynthesizedBackingField - => IsAutoProperty || UsesFieldKeyword; - /// /// Backing field for an automatically implemented property, or /// a property with an accessor using the 'field' keyword, or @@ -716,7 +716,7 @@ internal override void AfterAddingTypeMembersChecks(ConversionsBase conversions, diagnostics.Add(ErrorCode.ERR_RefReturningPropertiesCannotBeRequired, Location); } - if (HasSynthesizedBackingField) + if (IsAutoPropertyOrUsesFieldKeyword) { if (!IsStatic && ((_propertyFlags & Flags.HasAutoPropertySet) != 0) && SetMethod is { IsInitOnly: false }) { @@ -1104,7 +1104,7 @@ private SynthesizedSealedPropertyAccessor MakeSynthesizedSealedAccessor() AttributeLocation IAttributeTargetSymbol.DefaultAttributeLocation => AttributeLocation.Property; AttributeLocation IAttributeTargetSymbol.AllowedAttributeLocations - => HasSynthesizedBackingField + => IsAutoPropertyOrUsesFieldKeyword ? AttributeLocation.Property | AttributeLocation.Field : AttributeLocation.Property; @@ -1669,7 +1669,7 @@ protected virtual void ValidatePropertyType(BindingDiagnosticBag diagnostics) { diagnostics.Add(ErrorCode.ERR_FieldCantBeRefAny, TypeLocation, type); } - else if (this.HasSynthesizedBackingField && type.IsRefLikeOrAllowsRefLikeType() && (this.IsStatic || !this.ContainingType.IsRefLikeType)) + else if (this.IsAutoPropertyOrUsesFieldKeyword && type.IsRefLikeOrAllowsRefLikeType() && (this.IsStatic || !this.ContainingType.IsRefLikeType)) { diagnostics.Add(ErrorCode.ERR_FieldAutoPropCantBeByRefLike, TypeLocation, type); } diff --git a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedBackingFieldSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedBackingFieldSymbol.cs index 62691a173ee98..a56bf57992fb0 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedBackingFieldSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedBackingFieldSymbol.cs @@ -149,7 +149,7 @@ internal override void PostDecodeWellKnownAttributes(ImmutableArray Date: Wed, 21 Aug 2024 18:17:37 -0700 Subject: [PATCH 10/21] Update diagnostic message --- .../CSharp/Portable/CSharpResources.resx | 2 +- .../Portable/xlf/CSharpResources.cs.xlf | 4 ++-- .../Portable/xlf/CSharpResources.de.xlf | 4 ++-- .../Portable/xlf/CSharpResources.es.xlf | 4 ++-- .../Portable/xlf/CSharpResources.fr.xlf | 4 ++-- .../Portable/xlf/CSharpResources.it.xlf | 4 ++-- .../Portable/xlf/CSharpResources.ja.xlf | 4 ++-- .../Portable/xlf/CSharpResources.ko.xlf | 4 ++-- .../Portable/xlf/CSharpResources.pl.xlf | 4 ++-- .../Portable/xlf/CSharpResources.pt-BR.xlf | 4 ++-- .../Portable/xlf/CSharpResources.ru.xlf | 4 ++-- .../Portable/xlf/CSharpResources.tr.xlf | 4 ++-- .../Portable/xlf/CSharpResources.zh-Hans.xlf | 4 ++-- .../Portable/xlf/CSharpResources.zh-Hant.xlf | 4 ++-- .../CSharp/Test/Emit3/FieldKeywordTests.cs | 16 ++++++++----- .../Semantic/Semantics/RecordStructTests.cs | 4 ++-- .../Test/Semantic/Semantics/StructsTests.cs | 4 ++-- .../UninitializedNonNullableFieldTests.cs | 2 +- .../DefaultInterfaceImplementationTests.cs | 12 +++++----- .../Symbol/Symbols/PartialPropertiesTests.cs | 24 +++++++++---------- .../Test/Symbol/Symbols/SymbolErrorTests.cs | 6 ++--- 21 files changed, 63 insertions(+), 59 deletions(-) diff --git a/src/Compilers/CSharp/Portable/CSharpResources.resx b/src/Compilers/CSharp/Portable/CSharpResources.resx index e5af9ff4a7b96..7dc33bc7d57fe 100644 --- a/src/Compilers/CSharp/Portable/CSharpResources.resx +++ b/src/Compilers/CSharp/Portable/CSharpResources.resx @@ -4891,7 +4891,7 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ Expected identifier or numeric literal - Only auto-implemented properties can have initializers. + Only properties with backing fields can have initializers. Instance properties in interfaces cannot have initializers. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf index c070c270fb61b..23bc5a236bca0 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf @@ -12160,8 +12160,8 @@ Pokud chcete odstranit toto varování, můžete místo toho použít /reference - Only auto-implemented properties can have initializers. - Jenom automaticky implementované vlastnosti můžou mít inicializátory. + Only properties with backing fields can have initializers. + Jenom automaticky implementované vlastnosti můžou mít inicializátory. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf index 0078527e65793..33fcd7ec3203d 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf @@ -12160,8 +12160,8 @@ Um die Warnung zu beheben, können Sie stattdessen /reference verwenden (Einbett - Only auto-implemented properties can have initializers. - Nur automatisch implementierte Eigenschaften können Initialisierer aufweisen. + Only properties with backing fields can have initializers. + Nur automatisch implementierte Eigenschaften können Initialisierer aufweisen. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf index fe8b9998c951b..008d0075a1c71 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf @@ -12160,8 +12160,8 @@ Para eliminar la advertencia puede usar /reference (establezca la propiedad Embe - Only auto-implemented properties can have initializers. - Solo las propiedades implementadas automáticamente pueden tener inicializadores. + Only properties with backing fields can have initializers. + Solo las propiedades implementadas automáticamente pueden tener inicializadores. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf index 0d55d57e5c894..e8e690e2430d2 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf @@ -12160,8 +12160,8 @@ Pour supprimer l'avertissement, vous pouvez utiliser la commande /reference (dé - Only auto-implemented properties can have initializers. - Seules les propriétés implémentées automatiquement peuvent avoir des initialiseurs. + Only properties with backing fields can have initializers. + Seules les propriétés implémentées automatiquement peuvent avoir des initialiseurs. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf index e0d85c231f8e7..523efe91e437e 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf @@ -12160,8 +12160,8 @@ Per rimuovere l'avviso, è invece possibile usare /reference (impostare la propr - Only auto-implemented properties can have initializers. - Solo le proprietà implementate automaticamente possono avere inizializzatori. + Only properties with backing fields can have initializers. + Solo le proprietà implementate automaticamente possono avere inizializzatori. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf index 8ecfc63478d6c..e6ea20c9b9a78 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf @@ -12160,8 +12160,8 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ - Only auto-implemented properties can have initializers. - 自動実装プロパティのみが初期化子を持つことができます。 + Only properties with backing fields can have initializers. + 自動実装プロパティのみが初期化子を持つことができます。 diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf index ae92ac759f259..a64c09b48b9db 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf @@ -12160,8 +12160,8 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ - Only auto-implemented properties can have initializers. - 자동 구현 속성만 이니셜라이저를 사용할 수 있습니다. + Only properties with backing fields can have initializers. + 자동 구현 속성만 이니셜라이저를 사용할 수 있습니다. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf index 0f18b1d6b3ad5..ff066bcbabc8a 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf @@ -12160,8 +12160,8 @@ Aby usunąć ostrzeżenie, możesz zamiast tego użyć opcji /reference (ustaw w - Only auto-implemented properties can have initializers. - Tylko właściwości zaimplementowane automatycznie mogą mieć inicjatory. + Only properties with backing fields can have initializers. + Tylko właściwości zaimplementowane automatycznie mogą mieć inicjatory. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf index 5b182e2af6227..20af7c3a08e19 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf @@ -12160,8 +12160,8 @@ Para incorporar informações de tipo de interoperabilidade para os dois assembl - Only auto-implemented properties can have initializers. - Somente propriedades implementadas automaticamente podem ter inicializadores. + Only properties with backing fields can have initializers. + Somente propriedades implementadas automaticamente podem ter inicializadores. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf index f660d123cf6ef..12a91dc40179c 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf @@ -12161,8 +12161,8 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ - Only auto-implemented properties can have initializers. - Инициализаторы могут иметь только автоматически реализованные свойства. + Only properties with backing fields can have initializers. + Инициализаторы могут иметь только автоматически реализованные свойства. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf index b7ccaf7545791..d968cf3f7ec7e 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf @@ -12160,8 +12160,8 @@ Uyarıyı kaldırmak için, /reference kullanabilirsiniz (Birlikte Çalışma T - Only auto-implemented properties can have initializers. - Yalnızca otomatik uygulanan özelliklerin başlatıcıları olabilir. + Only properties with backing fields can have initializers. + Yalnızca otomatik uygulanan özelliklerin başlatıcıları olabilir. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf index ac1f52a36f53b..391474b9ab2f4 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf @@ -12160,8 +12160,8 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ - Only auto-implemented properties can have initializers. - 只有自动实现的属性才能具有初始值设定项。 + Only properties with backing fields can have initializers. + 只有自动实现的属性才能具有初始值设定项。 diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf index b3f556c0b0476..e53f6d0d305a5 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf @@ -12160,8 +12160,8 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ - Only auto-implemented properties can have initializers. - 只有自動實作的屬性可以有初始設定式。 + Only properties with backing fields can have initializers. + 只有自動實作的屬性可以有初始設定式。 diff --git a/src/Compilers/CSharp/Test/Emit3/FieldKeywordTests.cs b/src/Compilers/CSharp/Test/Emit3/FieldKeywordTests.cs index d9488026663cf..81a1d4be1d20a 100644 --- a/src/Compilers/CSharp/Test/Emit3/FieldKeywordTests.cs +++ b/src/Compilers/CSharp/Test/Emit3/FieldKeywordTests.cs @@ -301,7 +301,7 @@ class C """; var comp = CreateCompilation(source); comp.VerifyEmitDiagnostics( - // (3,12): error CS8050: Only auto-implemented properties can have initializers. + // (3,12): error CS8050: Only properties with backing fields can have initializers. // object P { set { } } = field; Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "P").WithLocation(3, 12), // (3,28): error CS0103: The name 'field' does not exist in the current context @@ -1053,6 +1053,7 @@ static void Main() } """; var verifier = CompileAndVerify(source, expectedOutput: "(1, 2, 3, 5, 0, 9, 11)"); + verifier.Compilation.VerifyDiagnostics(); verifier.VerifyIL("C..cctor", """ { // Code size 52 (0x34) @@ -1110,6 +1111,7 @@ static void Main() } """; var verifier = CompileAndVerify(source, targetFramework: TargetFramework.Net80, verify: Verification.Skipped, expectedOutput: IncludeExpectedOutput("(1, 2, 3, 4, 5, 6, 0, 0, 9, 10, 11, 12)")); + verifier.Compilation.VerifyDiagnostics(); verifier.VerifyIL("C..ctor", """ { // Code size 111 (0x6f) @@ -1178,19 +1180,19 @@ class C """; var comp = CreateCompilation(source, targetFramework: TargetFramework.Net80); comp.VerifyEmitDiagnostics( - // (3,23): error CS8050: Only auto-implemented properties can have initializers. + // (3,23): error CS8050: Only properties with backing fields can have initializers. // public static int P1 { get => 0; } = 1; Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "P1").WithLocation(3, 23), - // (4,23): error CS8050: Only auto-implemented properties can have initializers. + // (4,23): error CS8050: Only properties with backing fields can have initializers. // public static int P2 { get => 0; set { } } = 2; Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "P2").WithLocation(4, 23), - // (5,16): error CS8050: Only auto-implemented properties can have initializers. + // (5,16): error CS8050: Only properties with backing fields can have initializers. // public int P3 { get => 0; } = 3; Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "P3").WithLocation(5, 16), - // (6,16): error CS8050: Only auto-implemented properties can have initializers. + // (6,16): error CS8050: Only properties with backing fields can have initializers. // public int P4 { get => 0; set { } } = 4; Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "P4").WithLocation(6, 16), - // (7,16): error CS8050: Only auto-implemented properties can have initializers. + // (7,16): error CS8050: Only properties with backing fields can have initializers. // public int P5 { get => 0; init { } } = 5; Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "P5").WithLocation(7, 16)); } @@ -1231,6 +1233,7 @@ static void Main() } """; var verifier = CompileAndVerify(source, expectedOutput: "(1, 2, 3, 0, 0, 9, 0)"); + verifier.Compilation.VerifyDiagnostics(); verifier.VerifyIL("C..cctor", """ { // Code size 52 (0x34) @@ -1305,6 +1308,7 @@ static void Main() } """; var verifier = CompileAndVerify(source, targetFramework: TargetFramework.Net80, verify: Verification.Skipped, expectedOutput: IncludeExpectedOutput("(1, 2, 3, 4, 0, 0, 0, 0, 9, 10, 0, 0)")); + verifier.Compilation.VerifyDiagnostics(); verifier.VerifyIL("C..ctor", """ { // Code size 111 (0x6f) diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/RecordStructTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/RecordStructTests.cs index ddb864685943f..0be2253568ac9 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/RecordStructTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/RecordStructTests.cs @@ -3997,14 +3997,14 @@ record struct Pos2(int X) // (2,15): error CS0171: Field 'Pos.x' must be fully assigned before control is returned to the caller. Consider updating to language version '11.0' to auto-default the field. // record struct Pos(int X) Diagnostic(ErrorCode.ERR_UnassignedThisUnsupportedVersion, "Pos").WithArguments("Pos.x", "11.0").WithLocation(2, 15), - // (5,16): error CS8050: Only auto-implemented properties can have initializers. + // (5,16): error CS8050: Only properties with backing fields can have initializers. // public int X { get { return x; } set { x = value; } } = X; Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "X").WithLocation(5, 16) ); comp = CreateCompilation(source, parseOptions: TestOptions.Regular11); comp.VerifyEmitDiagnostics( - // (5,16): error CS8050: Only auto-implemented properties can have initializers. + // (5,16): error CS8050: Only properties with backing fields can have initializers. // public int X { get { return x; } set { x = value; } } = X; Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "X").WithLocation(5, 16) ); diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/StructsTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/StructsTests.cs index 853cac424e3ae..03c8191cf1301 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/StructsTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/StructsTests.cs @@ -673,7 +673,7 @@ public void StructNonAutoPropertyInitializer() // (3,16): error CS8773: Feature 'struct field initializers' is not available in C# 9.0. Please use language version 10.0 or greater. // public int I { get { throw null; } set {} } = 9; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion9, "I").WithArguments("struct field initializers", "10.0").WithLocation(3, 16), - // (3,16): error CS8050: Only auto-implemented properties can have initializers. + // (3,16): error CS8050: Only properties with backing fields can have initializers. // public int I { get { throw null; } set {} } = 9; Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "I").WithLocation(3, 16)); @@ -682,7 +682,7 @@ public void StructNonAutoPropertyInitializer() // (1,8): error CS8983: A 'struct' with field initializers must include an explicitly declared constructor. // struct S Diagnostic(ErrorCode.ERR_StructHasInitializersAndNoDeclaredConstructor, "S").WithLocation(1, 8), - // (3,16): error CS8050: Only auto-implemented properties can have initializers. + // (3,16): error CS8050: Only properties with backing fields can have initializers. // public int I { get { throw null; } set {} } = 9; Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "I").WithLocation(3, 16)); } diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/UninitializedNonNullableFieldTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/UninitializedNonNullableFieldTests.cs index 44ff7a3e97c93..47c7d4db26c96 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/UninitializedNonNullableFieldTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/UninitializedNonNullableFieldTests.cs @@ -2631,7 +2631,7 @@ public C() // (5,19): error CS0548: 'C.P': property or indexer must have at least one accessor // public string P { } Diagnostic(ErrorCode.ERR_PropertyWithNoAccessors, "P").WithArguments("C.P").WithLocation(5, 19), - // (7,19): error CS8050: Only auto-implemented properties can have initializers. + // (7,19): error CS8050: Only properties with backing fields can have initializers. // public string P3 { } = string.Empty; Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "P3").WithLocation(7, 19), // (7,19): error CS0548: 'C.P3': property or indexer must have at least one accessor diff --git a/src/Compilers/CSharp/Test/Symbol/Symbols/DefaultInterfaceImplementationTests.cs b/src/Compilers/CSharp/Test/Symbol/Symbols/DefaultInterfaceImplementationTests.cs index 2f460948136dd..afe7f3a36609b 100644 --- a/src/Compilers/CSharp/Test/Symbol/Symbols/DefaultInterfaceImplementationTests.cs +++ b/src/Compilers/CSharp/Test/Symbol/Symbols/DefaultInterfaceImplementationTests.cs @@ -3217,7 +3217,7 @@ public interface I1 // (4,34): error CS1014: A get or set accessor expected // static abstract int P1 {add; remove;} = 0; Diagnostic(ErrorCode.ERR_GetOrSetExpected, "remove").WithLocation(4, 34), - // (4,25): error CS8050: Only auto-implemented properties can have initializers. + // (4,25): error CS8050: Only properties with backing fields can have initializers. // static abstract int P1 {add; remove;} = 0; Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "P1").WithLocation(4, 25), // (4,25): error CS0548: 'I1.P1': property or indexer must have at least one accessor @@ -3251,7 +3251,7 @@ public interface I1 // (4,33): error CS1014: A get or set accessor expected // static virtual int P1 {add; remove;} = 0; Diagnostic(ErrorCode.ERR_GetOrSetExpected, "remove").WithLocation(4, 33), - // (4,24): error CS8050: Only auto-implemented properties can have initializers. + // (4,24): error CS8050: Only properties with backing fields can have initializers. // static virtual int P1 {add; remove;} = 0; Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "P1").WithLocation(4, 24), // (4,24): error CS0548: 'I1.P1': property or indexer must have at least one accessor @@ -3309,7 +3309,7 @@ public interface I1 targetFramework: TargetFramework.Net60); Assert.True(compilation1.Assembly.RuntimeSupportsDefaultInterfaceImplementation); compilation1.VerifyEmitDiagnostics( - // (4,25): error CS8050: Only auto-implemented properties can have initializers. + // (4,25): error CS8050: Only properties with backing fields can have initializers. // static abstract int P1 {get; set;} = 0; Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "P1").WithLocation(4, 25) ); @@ -56844,7 +56844,7 @@ class Test1 : I2 } "; ValidatePropertyReAbstraction_014(source1, isStatic: true, - // (9,28): error CS8050: Only auto-implemented properties can have initializers. + // (9,28): error CS8050: Only properties with backing fields can have initializers. // static abstract int I1.P1 { get; set; } = 0; Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "P1").WithLocation(9, 28), // (12,15): error CS0535: 'Test1' does not implement interface member 'I1.P1' @@ -56902,7 +56902,7 @@ class Test1 : I2 } "; ValidatePropertyReAbstraction_014(source1, isStatic: true, - // (9,28): error CS8050: Only auto-implemented properties can have initializers. + // (9,28): error CS8050: Only properties with backing fields can have initializers. // static abstract int I1.P1 { get; } = 0; Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "P1").WithLocation(9, 28), // (12,15): error CS0535: 'Test1' does not implement interface member 'I1.P1' @@ -56960,7 +56960,7 @@ class Test1 : I2 } "; ValidatePropertyReAbstraction_014(source1, isStatic: true, - // (9,28): error CS8050: Only auto-implemented properties can have initializers. + // (9,28): error CS8050: Only properties with backing fields can have initializers. // static abstract int I1.P1 { set; } = 0; Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "P1").WithLocation(9, 28), // (12,15): error CS0535: 'Test1' does not implement interface member 'I1.P1' diff --git a/src/Compilers/CSharp/Test/Symbol/Symbols/PartialPropertiesTests.cs b/src/Compilers/CSharp/Test/Symbol/Symbols/PartialPropertiesTests.cs index d1a8b34d21ea1..195705f1db7f8 100644 --- a/src/Compilers/CSharp/Test/Symbol/Symbols/PartialPropertiesTests.cs +++ b/src/Compilers/CSharp/Test/Symbol/Symbols/PartialPropertiesTests.cs @@ -3771,16 +3771,16 @@ partial class C var comp = CreateCompilation(source); comp.VerifyEmitDiagnostics( - // (3,27): error CS8050: Only auto-implemented properties can have initializers. + // (3,27): error CS8050: Only properties with backing fields can have initializers. // public partial string P1 { get; set; } = "a"; Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "P1").WithLocation(3, 27), - // (7,27): error CS8050: Only auto-implemented properties can have initializers. + // (7,27): error CS8050: Only properties with backing fields can have initializers. // public partial string P2 { get => ""; set { } } = "b"; Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "P2").WithLocation(7, 27), - // (9,27): error CS8050: Only auto-implemented properties can have initializers. + // (9,27): error CS8050: Only properties with backing fields can have initializers. // public partial string P3 { get; set; } = "c"; Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "P3").WithLocation(9, 27), - // (10,27): error CS8050: Only auto-implemented properties can have initializers. + // (10,27): error CS8050: Only properties with backing fields can have initializers. // public partial string P3 { get => ""; set { } } = "d"; Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "P3").WithLocation(10, 27)); } @@ -3804,25 +3804,25 @@ partial class C var comp = CreateCompilation(source); comp.VerifyEmitDiagnostics( - // (3,27): error CS8050: Only auto-implemented properties can have initializers. + // (3,27): error CS8050: Only properties with backing fields can have initializers. // public partial string P1 { get; set; } = ERROR; Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "P1").WithLocation(3, 27), // (3,46): error CS0103: The name 'ERROR' does not exist in the current context // public partial string P1 { get; set; } = ERROR; Diagnostic(ErrorCode.ERR_NameNotInContext, "ERROR").WithArguments("ERROR").WithLocation(3, 46), - // (7,27): error CS8050: Only auto-implemented properties can have initializers. + // (7,27): error CS8050: Only properties with backing fields can have initializers. // public partial string P2 { get => ""; set { } } = ERROR; Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "P2").WithLocation(7, 27), // (7,55): error CS0103: The name 'ERROR' does not exist in the current context // public partial string P2 { get => ""; set { } } = ERROR; Diagnostic(ErrorCode.ERR_NameNotInContext, "ERROR").WithArguments("ERROR").WithLocation(7, 55), - // (9,27): error CS8050: Only auto-implemented properties can have initializers. + // (9,27): error CS8050: Only properties with backing fields can have initializers. // public partial string P3 { get; set; } = ERROR; Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "P3").WithLocation(9, 27), // (9,46): error CS0103: The name 'ERROR' does not exist in the current context // public partial string P3 { get; set; } = ERROR; Diagnostic(ErrorCode.ERR_NameNotInContext, "ERROR").WithArguments("ERROR").WithLocation(9, 46), - // (10,27): error CS8050: Only auto-implemented properties can have initializers. + // (10,27): error CS8050: Only properties with backing fields can have initializers. // public partial string P3 { get => ""; set { } } = ERROR; Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "P3").WithLocation(10, 27), // (10,55): error CS0103: The name 'ERROR' does not exist in the current context @@ -3862,7 +3862,7 @@ partial class C // (6,6): warning CS0657: 'field' is not a valid attribute location for this declaration. Valid attribute locations for this declaration are 'property'. All attributes in this block will be ignored. // [field: Attr1] Diagnostic(ErrorCode.WRN_AttributeLocationOnBadDeclaration, "field").WithArguments("field", "property").WithLocation(6, 6), - // (7,27): error CS8050: Only auto-implemented properties can have initializers. + // (7,27): error CS8050: Only properties with backing fields can have initializers. // public partial string P1 { get; set; } = "a"; Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "P1").WithLocation(7, 27), // (8,6): warning CS0657: 'field' is not a valid attribute location for this declaration. Valid attribute locations for this declaration are 'property'. All attributes in this block will be ignored. @@ -3874,19 +3874,19 @@ partial class C // (13,6): warning CS0657: 'field' is not a valid attribute location for this declaration. Valid attribute locations for this declaration are 'property'. All attributes in this block will be ignored. // [field: Attr2] Diagnostic(ErrorCode.WRN_AttributeLocationOnBadDeclaration, "field").WithArguments("field", "property").WithLocation(13, 6), - // (14,27): error CS8050: Only auto-implemented properties can have initializers. + // (14,27): error CS8050: Only properties with backing fields can have initializers. // public partial string P2 { get => ""; set { } } = "b"; Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "P2").WithLocation(14, 27), // (16,6): warning CS0657: 'field' is not a valid attribute location for this declaration. Valid attribute locations for this declaration are 'property'. All attributes in this block will be ignored. // [field: Attr1] Diagnostic(ErrorCode.WRN_AttributeLocationOnBadDeclaration, "field").WithArguments("field", "property").WithLocation(16, 6), - // (17,27): error CS8050: Only auto-implemented properties can have initializers. + // (17,27): error CS8050: Only properties with backing fields can have initializers. // public partial string P3 { get; set; } = "c"; Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "P3").WithLocation(17, 27), // (18,6): warning CS0657: 'field' is not a valid attribute location for this declaration. Valid attribute locations for this declaration are 'property'. All attributes in this block will be ignored. // [field: Attr2] Diagnostic(ErrorCode.WRN_AttributeLocationOnBadDeclaration, "field").WithArguments("field", "property").WithLocation(18, 6), - // (19,27): error CS8050: Only auto-implemented properties can have initializers. + // (19,27): error CS8050: Only properties with backing fields can have initializers. // public partial string P3 { get => ""; set { } } = "d"; Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "P3").WithLocation(19, 27)); diff --git a/src/Compilers/CSharp/Test/Symbol/Symbols/SymbolErrorTests.cs b/src/Compilers/CSharp/Test/Symbol/Symbols/SymbolErrorTests.cs index 31be06d2e2ace..d05bc29d82370 100644 --- a/src/Compilers/CSharp/Test/Symbol/Symbols/SymbolErrorTests.cs +++ b/src/Compilers/CSharp/Test/Symbol/Symbols/SymbolErrorTests.cs @@ -16859,13 +16859,13 @@ public void CS8050ERR_InitializerOnNonAutoProperty() protected int P { get { throw null; } set { } } = 1; }"; CreateCompilation(source).VerifyDiagnostics( - // (5,9): error CS8050: Only auto-implemented properties can have initializers. + // (5,9): error CS8050: Only properties with backing fields can have initializers. // int I { get { throw null; } set { } } = 1; Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "I").WithLocation(5, 9), - // (6,16): error CS8050: Only auto-implemented properties can have initializers. + // (6,16): error CS8050: Only properties with backing fields can have initializers. // static int S { get { throw null; } set { } } = 1; Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "S").WithLocation(6, 16), - // (7,19): error CS8050: Only auto-implemented properties can have initializers. + // (7,19): error CS8050: Only properties with backing fields can have initializers. // protected int P { get { throw null; } set { } } = 1; Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "P").WithLocation(7, 19) ); From 5172975c032d71607c5572efed5da3f88cf3b681 Mon Sep 17 00:00:00 2001 From: Charles Stoner <10732005+cston@users.noreply.github.com> Date: Wed, 21 Aug 2024 18:19:27 -0700 Subject: [PATCH 11/21] Rename test --- src/Compilers/CSharp/Test/Emit3/FieldKeywordTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Compilers/CSharp/Test/Emit3/FieldKeywordTests.cs b/src/Compilers/CSharp/Test/Emit3/FieldKeywordTests.cs index 81a1d4be1d20a..a221c000f834a 100644 --- a/src/Compilers/CSharp/Test/Emit3/FieldKeywordTests.cs +++ b/src/Compilers/CSharp/Test/Emit3/FieldKeywordTests.cs @@ -1977,7 +1977,7 @@ public void RefReturning_02(bool useStruct, bool useRefReadOnly) [InlineData(false, false)] [InlineData(false, true)] [InlineData(true, false)] - public void SetOnly(bool useStatic, bool useInit) + public void AutoPropertyMustHaveGetAccessor(bool useStatic, bool useInit) { string modifier = useStatic ? "static" : " "; string setter = useInit ? "init" : "set"; From f8fa5d402784083ea8c0419c2bd2d21cc72d5b8d Mon Sep 17 00:00:00 2001 From: Charles Stoner <10732005+cston@users.noreply.github.com> Date: Wed, 21 Aug 2024 18:24:54 -0700 Subject: [PATCH 12/21] Verify fields --- src/Compilers/CSharp/Test/Emit3/FieldKeywordTests.cs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/Compilers/CSharp/Test/Emit3/FieldKeywordTests.cs b/src/Compilers/CSharp/Test/Emit3/FieldKeywordTests.cs index a221c000f834a..a1f72d4795603 100644 --- a/src/Compilers/CSharp/Test/Emit3/FieldKeywordTests.cs +++ b/src/Compilers/CSharp/Test/Emit3/FieldKeywordTests.cs @@ -2462,6 +2462,17 @@ .maxstack 0 } """); } + var comp = (CSharpCompilation)verifier.Compilation; + var actualMembers = comp.GetMember("C").GetMembers().OfType().ToTestDisplayStrings(); + var expectedMembers = new[] + { + "System.Object C.k__BackingField", + "System.Object C.k__BackingField", + "System.Object C.k__BackingField", + "System.Object C.k__BackingField", + "System.Object C.k__BackingField", + }; + AssertEx.Equal(expectedMembers, actualMembers); } [Fact] From 2aa8e19805b8d89e927f1584ba949dc9ce002758 Mon Sep 17 00:00:00 2001 From: Charles Stoner <10732005+cston@users.noreply.github.com> Date: Thu, 22 Aug 2024 12:12:01 -0700 Subject: [PATCH 13/21] Use CompilationVerifier.VerifyDiagnostics() --- src/Compilers/CSharp/Test/Emit3/FieldKeywordTests.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Compilers/CSharp/Test/Emit3/FieldKeywordTests.cs b/src/Compilers/CSharp/Test/Emit3/FieldKeywordTests.cs index a1f72d4795603..6c5305ecc09c6 100644 --- a/src/Compilers/CSharp/Test/Emit3/FieldKeywordTests.cs +++ b/src/Compilers/CSharp/Test/Emit3/FieldKeywordTests.cs @@ -1053,7 +1053,7 @@ static void Main() } """; var verifier = CompileAndVerify(source, expectedOutput: "(1, 2, 3, 5, 0, 9, 11)"); - verifier.Compilation.VerifyDiagnostics(); + verifier.VerifyDiagnostics(); verifier.VerifyIL("C..cctor", """ { // Code size 52 (0x34) @@ -1111,7 +1111,7 @@ static void Main() } """; var verifier = CompileAndVerify(source, targetFramework: TargetFramework.Net80, verify: Verification.Skipped, expectedOutput: IncludeExpectedOutput("(1, 2, 3, 4, 5, 6, 0, 0, 9, 10, 11, 12)")); - verifier.Compilation.VerifyDiagnostics(); + verifier.VerifyDiagnostics(); verifier.VerifyIL("C..ctor", """ { // Code size 111 (0x6f) @@ -1233,7 +1233,7 @@ static void Main() } """; var verifier = CompileAndVerify(source, expectedOutput: "(1, 2, 3, 0, 0, 9, 0)"); - verifier.Compilation.VerifyDiagnostics(); + verifier.VerifyDiagnostics(); verifier.VerifyIL("C..cctor", """ { // Code size 52 (0x34) @@ -1308,7 +1308,7 @@ static void Main() } """; var verifier = CompileAndVerify(source, targetFramework: TargetFramework.Net80, verify: Verification.Skipped, expectedOutput: IncludeExpectedOutput("(1, 2, 3, 4, 0, 0, 0, 0, 9, 10, 0, 0)")); - verifier.Compilation.VerifyDiagnostics(); + verifier.VerifyDiagnostics(); verifier.VerifyIL("C..ctor", """ { // Code size 111 (0x6f) From 3724d79dcbc5706520d52ff667b4b9ca5a7f731b Mon Sep 17 00:00:00 2001 From: Charles Stoner <10732005+cston@users.noreply.github.com> Date: Thu, 22 Aug 2024 13:24:33 -0700 Subject: [PATCH 14/21] Report error for initializer on auto-property with manually-implemented setter --- .../Source/SourcePropertySymbolBase.cs | 5 +- .../CSharp/Test/Emit3/FieldKeywordTests.cs | 282 ++++++++---------- 2 files changed, 134 insertions(+), 153 deletions(-) diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertySymbolBase.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertySymbolBase.cs index 5819a753625f0..85160a8246e40 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertySymbolBase.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertySymbolBase.cs @@ -302,7 +302,8 @@ protected void CheckInitializerIfNeeded(BindingDiagnosticBag diagnostics) { diagnostics.Add(ErrorCode.ERR_InstancePropertyInitializerInInterface, Location); } - else if (!IsAutoPropertyOrUsesFieldKeyword) + else if (!IsAutoPropertyOrUsesFieldKeyword || + ((_propertyFlags & Flags.HasAutoPropertySet) == 0) && SetMethod is { }) { diagnostics.Add(ErrorCode.ERR_InitializerOnNonAutoProperty, Location); } @@ -798,7 +799,7 @@ internal override void AfterAddingTypeMembersChecks(ConversionsBase conversions, else if (!hasGetAccessor && IsAutoProperty) { // The only forms of auto-property that are disallowed are { set; } and { init; }. - // Other forms of auto- or explicitly-implemented accessors are allowed + // Other forms of auto- or manually-implemented accessors are allowed // including equivalent field cases such as { set { field = value; } }. diagnostics.Add(ErrorCode.ERR_AutoPropertyMustHaveGetAccessor, _setMethod!.GetFirstLocation()); } diff --git a/src/Compilers/CSharp/Test/Emit3/FieldKeywordTests.cs b/src/Compilers/CSharp/Test/Emit3/FieldKeywordTests.cs index 6c5305ecc09c6..488fd0ae3b0e5 100644 --- a/src/Compilers/CSharp/Test/Emit3/FieldKeywordTests.cs +++ b/src/Compilers/CSharp/Test/Emit3/FieldKeywordTests.cs @@ -1038,25 +1038,22 @@ class C public static int P1 { get; } = 1; public static int P2 { get => field; } = 2; public static int P3 { get => field; set; } = 3; - public static int P5 { get => field; set { } } = 5; - public static int P7 { get => 0; set; } = 7; - public static int P9 { get; set; } = 9; - public static int PB { get; set { } } = 11; - public static int PD { set { field = value; } } = 13; + public static int P5 { get => 0; set; } = 5; + public static int P6 { get; set; } = 6; } class Program { static void Main() { - Console.WriteLine((C.P1, C.P2, C.P3, C.P5, C.P7, C.P9, C.PB)); + Console.WriteLine((C.P1, C.P2, C.P3, C.P5, C.P6)); } } """; - var verifier = CompileAndVerify(source, expectedOutput: "(1, 2, 3, 5, 0, 9, 11)"); + var verifier = CompileAndVerify(source, expectedOutput: "(1, 2, 3, 0, 6)"); verifier.VerifyDiagnostics(); verifier.VerifyIL("C..cctor", """ { - // Code size 52 (0x34) + // Code size 31 (0x1f) .maxstack 1 IL_0000: ldc.i4.1 IL_0001: stsfld "int C.k__BackingField" @@ -1066,55 +1063,42 @@ .maxstack 1 IL_000d: stsfld "int C.k__BackingField" IL_0012: ldc.i4.5 IL_0013: stsfld "int C.k__BackingField" - IL_0018: ldc.i4.7 - IL_0019: stsfld "int C.k__BackingField" - IL_001e: ldc.i4.s 9 - IL_0020: stsfld "int C.k__BackingField" - IL_0025: ldc.i4.s 11 - IL_0027: stsfld "int C.k__BackingField" - IL_002c: ldc.i4.s 13 - IL_002e: stsfld "int C.k__BackingField" - IL_0033: ret + IL_0018: ldc.i4.6 + IL_0019: stsfld "int C.k__BackingField" + IL_001e: ret } """); } - [Fact] - public void Initializer_02() + [Theory] + [CombinatorialData] + public void Initializer_02(bool useInit) { - string source = """ + string setter = useInit ? "init" : "set"; + string source = $$""" using System; class C { public int P1 { get; } = 1; public int P2 { get => field; } = 2; - public int P3 { get => field; set; } = 3; - public int P4 { get => field; init; } = 4; - public int P5 { get => field; set { } } = 5; - public int P6 { get => field; init { } } = 6; - public int P7 { get => 0; set; } = 7; - public int P8 { get => 0; init; } = 8; - public int P9 { get; set; } = 9; - public int PA { get; init; } = 10; - public int PB { get; set { } } = 11; - public int PC { get; init { } } = 12; - public int PD { set { field = value; } } = 13; - public int PE { init { field = value; } } = 14; + public int P3 { get => field; {{setter}}; } = 3; + public int P5 { get => 0; {{setter}}; } = 5; + public int P6 { get; {{setter}}; } = 6; } class Program { static void Main() { var c = new C(); - Console.WriteLine((c.P1, c.P2, c.P3, c.P4, c.P5, c.P6, c.P7, c.P8, c.P9, c.PA, c.PB, c.PC)); + Console.WriteLine((c.P1, c.P2, c.P3, c.P5, c.P6)); } } """; - var verifier = CompileAndVerify(source, targetFramework: TargetFramework.Net80, verify: Verification.Skipped, expectedOutput: IncludeExpectedOutput("(1, 2, 3, 4, 5, 6, 0, 0, 9, 10, 11, 12)")); + var verifier = CompileAndVerify(source, targetFramework: TargetFramework.Net80, verify: Verification.Skipped, expectedOutput: IncludeExpectedOutput("(1, 2, 3, 0, 6)")); verifier.VerifyDiagnostics(); verifier.VerifyIL("C..ctor", """ { - // Code size 111 (0x6f) + // Code size 42 (0x2a) .maxstack 2 IL_0000: ldarg.0 IL_0001: ldc.i4.1 @@ -1126,41 +1110,14 @@ .maxstack 2 IL_000f: ldc.i4.3 IL_0010: stfld "int C.k__BackingField" IL_0015: ldarg.0 - IL_0016: ldc.i4.4 - IL_0017: stfld "int C.k__BackingField" + IL_0016: ldc.i4.5 + IL_0017: stfld "int C.k__BackingField" IL_001c: ldarg.0 - IL_001d: ldc.i4.5 - IL_001e: stfld "int C.k__BackingField" + IL_001d: ldc.i4.6 + IL_001e: stfld "int C.k__BackingField" IL_0023: ldarg.0 - IL_0024: ldc.i4.6 - IL_0025: stfld "int C.k__BackingField" - IL_002a: ldarg.0 - IL_002b: ldc.i4.7 - IL_002c: stfld "int C.k__BackingField" - IL_0031: ldarg.0 - IL_0032: ldc.i4.8 - IL_0033: stfld "int C.k__BackingField" - IL_0038: ldarg.0 - IL_0039: ldc.i4.s 9 - IL_003b: stfld "int C.k__BackingField" - IL_0040: ldarg.0 - IL_0041: ldc.i4.s 10 - IL_0043: stfld "int C.k__BackingField" - IL_0048: ldarg.0 - IL_0049: ldc.i4.s 11 - IL_004b: stfld "int C.k__BackingField" - IL_0050: ldarg.0 - IL_0051: ldc.i4.s 12 - IL_0053: stfld "int C.k__BackingField" - IL_0058: ldarg.0 - IL_0059: ldc.i4.s 13 - IL_005b: stfld "int C.k__BackingField" - IL_0060: ldarg.0 - IL_0061: ldc.i4.s 14 - IL_0063: stfld "int C.k__BackingField" - IL_0068: ldarg.0 - IL_0069: call "object..ctor()" - IL_006e: ret + IL_0024: call "object..ctor()" + IL_0029: ret } """); } @@ -1171,30 +1128,72 @@ public void Initializer_03() string source = """ class C { - public static int P1 { get => 0; } = 1; - public static int P2 { get => 0; set { } } = 2; - public int P3 { get => 0; } = 3; - public int P4 { get => 0; set { } } = 4; - public int P5 { get => 0; init { } } = 5; + public static int P4 { get => field; set { } } = 4; + public static int P7 { get; set { } } = 7; + public static int P8 { set { field = value; } } = 8; + public static int P9 { get { return field; } set { field = value; } } = 9; + public static int PA { get => 0; } = 10; + public static int PB { get => 0; set { } } = 11; } """; var comp = CreateCompilation(source, targetFramework: TargetFramework.Net80); comp.VerifyEmitDiagnostics( // (3,23): error CS8050: Only properties with backing fields can have initializers. - // public static int P1 { get => 0; } = 1; - Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "P1").WithLocation(3, 23), + // public static int P4 { get => field; set { } } = 4; + Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "P4").WithLocation(3, 23), // (4,23): error CS8050: Only properties with backing fields can have initializers. - // public static int P2 { get => 0; set { } } = 2; - Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "P2").WithLocation(4, 23), + // public static int P7 { get; set { } } = 7; + Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "P7").WithLocation(4, 23), + // (5,23): error CS8050: Only properties with backing fields can have initializers. + // public static int P8 { set { field = value; } } = 8; + Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "P8").WithLocation(5, 23), + // (6,23): error CS8050: Only properties with backing fields can have initializers. + // public static int P9 { get { return field; } set { field = value; } } = 9; + Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "P9").WithLocation(6, 23), + // (7,23): error CS8050: Only properties with backing fields can have initializers. + // public static int PA { get => 0; } = 10; + Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "PA").WithLocation(7, 23), + // (8,23): error CS8050: Only properties with backing fields can have initializers. + // public static int PB { get => 0; set { } } = 11; + Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "PB").WithLocation(8, 23)); + } + + [Theory] + [CombinatorialData] + public void Initializer_04(bool useInit) + { + string setter = useInit ? "init" : "set"; + string source = $$""" + class C + { + public int P4 { get => field; {{setter}} { } } = 4; + public int P7 { get; {{setter}} { } } = 7; + public int P8 { {{setter}} { field = value; } } = 8; + public int P9 { get { return field; } {{setter}} { field = value; } } = 9; + public int PA { get => 0; } = 10; + public int PB { get => 0; {{setter}} { } } = 11; + } + """; + var comp = CreateCompilation(source, targetFramework: TargetFramework.Net80); + comp.VerifyEmitDiagnostics( + // (3,16): error CS8050: Only properties with backing fields can have initializers. + // public int P4 { get => field; set { } } = 4; + Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "P4").WithLocation(3, 16), + // (4,16): error CS8050: Only properties with backing fields can have initializers. + // public int P7 { get; set { } } = 7; + Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "P7").WithLocation(4, 16), // (5,16): error CS8050: Only properties with backing fields can have initializers. - // public int P3 { get => 0; } = 3; - Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "P3").WithLocation(5, 16), + // public int P8 { set { field = value; } } = 8; + Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "P8").WithLocation(5, 16), // (6,16): error CS8050: Only properties with backing fields can have initializers. - // public int P4 { get => 0; set { } } = 4; - Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "P4").WithLocation(6, 16), + // public int P9 { get { return field; } set { field = value; } } = 9; + Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "P9").WithLocation(6, 16), // (7,16): error CS8050: Only properties with backing fields can have initializers. - // public int P5 { get => 0; init { } } = 5; - Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "P5").WithLocation(7, 16)); + // public int PA { get => 0; } = 10; + Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "PA").WithLocation(7, 16), + // (8,16): error CS8050: Only properties with backing fields can have initializers. + // public int PB { get => 0; set { } } = 11; + Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "PB").WithLocation(8, 16)); } [Fact] @@ -1207,36 +1206,38 @@ class C public static int P1 { get; } public static int P2 { get => field; } public static int P3 { get => field; set; } - public static int P5 { get => field; set { } } - public static int P7 { get => 0; set; } - public static int P9 { get; set; } - public static int PB { get; set { } } - public static int PD { set { field = value; } } + public static int P4 { get => field; set { } } + public static int P5 { get => 0; set; } + public static int P6 { get; set; } + public static int P7 { get; set { } } + public static int P8 { set { field = value; } } + public static int P9 { get { return field; } set { field = value; } } static C() { P1 = 1; P2 = 2; P3 = 3; + P4 = 4; P5 = 5; + P6 = 6; P7 = 7; + P8 = 8; P9 = 9; - PB = 11; - PD = 13; } } class Program { static void Main() { - Console.WriteLine((C.P1, C.P2, C.P3, C.P5, C.P7, C.P9, C.PB)); + Console.WriteLine((C.P1, C.P2, C.P3, C.P4, C.P5, C.P6, C.P7, C.P9)); } } """; - var verifier = CompileAndVerify(source, expectedOutput: "(1, 2, 3, 0, 0, 9, 0)"); + var verifier = CompileAndVerify(source, expectedOutput: "(1, 2, 3, 0, 0, 6, 0, 9)"); verifier.VerifyDiagnostics(); verifier.VerifyIL("C..cctor", """ { - // Code size 52 (0x34) + // Code size 56 (0x38) .maxstack 1 IL_0000: ldc.i4.1 IL_0001: stsfld "int C.k__BackingField" @@ -1244,42 +1245,41 @@ .maxstack 1 IL_0007: stsfld "int C.k__BackingField" IL_000c: ldc.i4.3 IL_000d: call "void C.P3.set" - IL_0012: ldc.i4.5 - IL_0013: call "void C.P5.set" - IL_0018: ldc.i4.7 - IL_0019: call "void C.P7.set" - IL_001e: ldc.i4.s 9 - IL_0020: call "void C.P9.set" - IL_0025: ldc.i4.s 11 - IL_0027: call "void C.PB.set" - IL_002c: ldc.i4.s 13 - IL_002e: call "void C.PD.set" - IL_0033: ret + IL_0012: ldc.i4.4 + IL_0013: call "void C.P4.set" + IL_0018: ldc.i4.5 + IL_0019: call "void C.P5.set" + IL_001e: ldc.i4.6 + IL_001f: call "void C.P6.set" + IL_0024: ldc.i4.7 + IL_0025: call "void C.P7.set" + IL_002a: ldc.i4.8 + IL_002b: call "void C.P8.set" + IL_0030: ldc.i4.s 9 + IL_0032: call "void C.P9.set" + IL_0037: ret } """); } - [Fact] - public void ConstructorAssignment_02() + [Theory] + [CombinatorialData] + public void ConstructorAssignment_02(bool useInit) { - string source = """ + string setter = useInit ? "init" : "set"; + string source = $$""" using System; class C { public int P1 { get; } public int P2 { get => field; } - public int P3 { get => field; set; } - public int P4 { get => field; init; } - public int P5 { get => field; set { } } - public int P6 { get => field; init { } } - public int P7 { get => 0; set; } - public int P8 { get => 0; init; } - public int P9 { get; set; } - public int PA { get; init; } - public int PB { get; set { } } - public int PC { get; init { } } - public int PD { set { field = value; } } - public int PE { init { field = value; } } + public int P3 { get => field; {{setter}}; } + public int P4 { get => field; {{setter}} { } } + public int P5 { get => 0; {{setter}}; } + public int P6 { get; {{setter}}; } + public int P7 { get; {{setter}} { } } + public int P8 { {{setter}} { field = value; } } + public int P9 { get { return field; } {{setter}} { field = value; } } public C() { P1 = 1; @@ -1291,11 +1291,6 @@ public C() P7 = 7; P8 = 8; P9 = 9; - PA = 10; - PB = 11; - PC = 12; - PD = 13; - PE = 14; } } class Program @@ -1303,15 +1298,15 @@ class Program static void Main() { var c = new C(); - Console.WriteLine((c.P1, c.P2, c.P3, c.P4, c.P5, c.P6, c.P7, c.P8, c.P9, c.PA, c.PB, c.PC)); + Console.WriteLine((c.P1, c.P2, c.P3, c.P4, c.P5, c.P6, c.P7, c.P9)); } } """; - var verifier = CompileAndVerify(source, targetFramework: TargetFramework.Net80, verify: Verification.Skipped, expectedOutput: IncludeExpectedOutput("(1, 2, 3, 4, 0, 0, 0, 0, 9, 10, 0, 0)")); + var verifier = CompileAndVerify(source, targetFramework: TargetFramework.Net80, verify: Verification.Skipped, expectedOutput: IncludeExpectedOutput("(1, 2, 3, 0, 0, 6, 0, 9)")); verifier.VerifyDiagnostics(); - verifier.VerifyIL("C..ctor", """ + verifier.VerifyIL("C..ctor", $$""" { - // Code size 111 (0x6f) + // Code size 71 (0x47) .maxstack 2 IL_0000: ldarg.0 IL_0001: call "object..ctor()" @@ -1323,41 +1318,26 @@ .maxstack 2 IL_000f: stfld "int C.k__BackingField" IL_0014: ldarg.0 IL_0015: ldc.i4.3 - IL_0016: call "void C.P3.set" + IL_0016: call "void C.P3.{{setter}}" IL_001b: ldarg.0 IL_001c: ldc.i4.4 - IL_001d: call "void C.P4.init" + IL_001d: call "void C.P4.{{setter}}" IL_0022: ldarg.0 IL_0023: ldc.i4.5 - IL_0024: call "void C.P5.set" + IL_0024: call "void C.P5.{{setter}}" IL_0029: ldarg.0 IL_002a: ldc.i4.6 - IL_002b: call "void C.P6.init" + IL_002b: call "void C.P6.{{setter}}" IL_0030: ldarg.0 IL_0031: ldc.i4.7 - IL_0032: call "void C.P7.set" + IL_0032: call "void C.P7.{{setter}}" IL_0037: ldarg.0 IL_0038: ldc.i4.8 - IL_0039: call "void C.P8.init" + IL_0039: call "void C.P8.{{setter}}" IL_003e: ldarg.0 IL_003f: ldc.i4.s 9 - IL_0041: call "void C.P9.set" - IL_0046: ldarg.0 - IL_0047: ldc.i4.s 10 - IL_0049: call "void C.PA.init" - IL_004e: ldarg.0 - IL_004f: ldc.i4.s 11 - IL_0051: call "void C.PB.set" - IL_0056: ldarg.0 - IL_0057: ldc.i4.s 12 - IL_0059: call "void C.PC.init" - IL_005e: ldarg.0 - IL_005f: ldc.i4.s 13 - IL_0061: call "void C.PD.set" - IL_0066: ldarg.0 - IL_0067: ldc.i4.s 14 - IL_0069: call "void C.PE.init" - IL_006e: ret + IL_0041: call "void C.P9.{{setter}}" + IL_0046: ret } """); } From 8704d0cad0759f0254800ce01dd94646506a8bbd Mon Sep 17 00:00:00 2001 From: Charles Stoner <10732005+cston@users.noreply.github.com> Date: Thu, 22 Aug 2024 15:09:35 -0700 Subject: [PATCH 15/21] Update ERR_InitializerOnNonAutoProperty message --- .../CSharp/Portable/CSharpResources.resx | 2 +- .../Portable/xlf/CSharpResources.cs.xlf | 2 +- .../Portable/xlf/CSharpResources.de.xlf | 2 +- .../Portable/xlf/CSharpResources.es.xlf | 2 +- .../Portable/xlf/CSharpResources.fr.xlf | 2 +- .../Portable/xlf/CSharpResources.it.xlf | 2 +- .../Portable/xlf/CSharpResources.ja.xlf | 2 +- .../Portable/xlf/CSharpResources.ko.xlf | 2 +- .../Portable/xlf/CSharpResources.pl.xlf | 2 +- .../Portable/xlf/CSharpResources.pt-BR.xlf | 2 +- .../Portable/xlf/CSharpResources.ru.xlf | 2 +- .../Portable/xlf/CSharpResources.tr.xlf | 2 +- .../Portable/xlf/CSharpResources.zh-Hans.xlf | 2 +- .../Portable/xlf/CSharpResources.zh-Hant.xlf | 2 +- .../CSharp/Test/Emit3/FieldKeywordTests.cs | 26 +++++++++---------- .../Semantic/Semantics/RecordStructTests.cs | 4 +-- .../Test/Semantic/Semantics/StructsTests.cs | 4 +-- .../UninitializedNonNullableFieldTests.cs | 2 +- .../DefaultInterfaceImplementationTests.cs | 12 ++++----- .../Symbol/Symbols/PartialPropertiesTests.cs | 24 ++++++++--------- .../Test/Symbol/Symbols/SymbolErrorTests.cs | 6 ++--- 21 files changed, 53 insertions(+), 53 deletions(-) diff --git a/src/Compilers/CSharp/Portable/CSharpResources.resx b/src/Compilers/CSharp/Portable/CSharpResources.resx index 7dc33bc7d57fe..761f0ca5fd20b 100644 --- a/src/Compilers/CSharp/Portable/CSharpResources.resx +++ b/src/Compilers/CSharp/Portable/CSharpResources.resx @@ -4891,7 +4891,7 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ Expected identifier or numeric literal - Only properties with backing fields can have initializers. + Only a property with a backing field and no setter, or a property with an auto-implemented setter, can have an initializer. Instance properties in interfaces cannot have initializers. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf index 23bc5a236bca0..c07a8e382ea60 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf @@ -12160,7 +12160,7 @@ Pokud chcete odstranit toto varování, můžete místo toho použít /reference - Only properties with backing fields can have initializers. + Only a property with a backing field and no setter, or a property with an auto-implemented setter, can have an initializer. Jenom automaticky implementované vlastnosti můžou mít inicializátory. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf index 33fcd7ec3203d..88be54a823cd3 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf @@ -12160,7 +12160,7 @@ Um die Warnung zu beheben, können Sie stattdessen /reference verwenden (Einbett - Only properties with backing fields can have initializers. + Only a property with a backing field and no setter, or a property with an auto-implemented setter, can have an initializer. Nur automatisch implementierte Eigenschaften können Initialisierer aufweisen. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf index 008d0075a1c71..d000a4f306f39 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf @@ -12160,7 +12160,7 @@ Para eliminar la advertencia puede usar /reference (establezca la propiedad Embe - Only properties with backing fields can have initializers. + Only a property with a backing field and no setter, or a property with an auto-implemented setter, can have an initializer. Solo las propiedades implementadas automáticamente pueden tener inicializadores. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf index e8e690e2430d2..27b710cdf4cf4 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf @@ -12160,7 +12160,7 @@ Pour supprimer l'avertissement, vous pouvez utiliser la commande /reference (dé - Only properties with backing fields can have initializers. + Only a property with a backing field and no setter, or a property with an auto-implemented setter, can have an initializer. Seules les propriétés implémentées automatiquement peuvent avoir des initialiseurs. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf index 523efe91e437e..0da1482c09496 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf @@ -12160,7 +12160,7 @@ Per rimuovere l'avviso, è invece possibile usare /reference (impostare la propr - Only properties with backing fields can have initializers. + Only a property with a backing field and no setter, or a property with an auto-implemented setter, can have an initializer. Solo le proprietà implementate automaticamente possono avere inizializzatori. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf index e6ea20c9b9a78..518f3530203ac 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf @@ -12160,7 +12160,7 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ - Only properties with backing fields can have initializers. + Only a property with a backing field and no setter, or a property with an auto-implemented setter, can have an initializer. 自動実装プロパティのみが初期化子を持つことができます。 diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf index a64c09b48b9db..689c71b0af84d 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf @@ -12160,7 +12160,7 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ - Only properties with backing fields can have initializers. + Only a property with a backing field and no setter, or a property with an auto-implemented setter, can have an initializer. 자동 구현 속성만 이니셜라이저를 사용할 수 있습니다. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf index ff066bcbabc8a..fe8cc96762ce2 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf @@ -12160,7 +12160,7 @@ Aby usunąć ostrzeżenie, możesz zamiast tego użyć opcji /reference (ustaw w - Only properties with backing fields can have initializers. + Only a property with a backing field and no setter, or a property with an auto-implemented setter, can have an initializer. Tylko właściwości zaimplementowane automatycznie mogą mieć inicjatory. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf index 20af7c3a08e19..267ff0377e12a 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf @@ -12160,7 +12160,7 @@ Para incorporar informações de tipo de interoperabilidade para os dois assembl - Only properties with backing fields can have initializers. + Only a property with a backing field and no setter, or a property with an auto-implemented setter, can have an initializer. Somente propriedades implementadas automaticamente podem ter inicializadores. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf index 12a91dc40179c..aebf6340f76f7 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf @@ -12161,7 +12161,7 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ - Only properties with backing fields can have initializers. + Only a property with a backing field and no setter, or a property with an auto-implemented setter, can have an initializer. Инициализаторы могут иметь только автоматически реализованные свойства. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf index d968cf3f7ec7e..675a1a6296a5d 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf @@ -12160,7 +12160,7 @@ Uyarıyı kaldırmak için, /reference kullanabilirsiniz (Birlikte Çalışma T - Only properties with backing fields can have initializers. + Only a property with a backing field and no setter, or a property with an auto-implemented setter, can have an initializer. Yalnızca otomatik uygulanan özelliklerin başlatıcıları olabilir. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf index 391474b9ab2f4..baf91a5af6c8a 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf @@ -12160,7 +12160,7 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ - Only properties with backing fields can have initializers. + Only a property with a backing field and no setter, or a property with an auto-implemented setter, can have an initializer. 只有自动实现的属性才能具有初始值设定项。 diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf index e53f6d0d305a5..dce9041293762 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf @@ -12160,7 +12160,7 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ - Only properties with backing fields can have initializers. + Only a property with a backing field and no setter, or a property with an auto-implemented setter, can have an initializer. 只有自動實作的屬性可以有初始設定式。 diff --git a/src/Compilers/CSharp/Test/Emit3/FieldKeywordTests.cs b/src/Compilers/CSharp/Test/Emit3/FieldKeywordTests.cs index 488fd0ae3b0e5..bd465f70c3c40 100644 --- a/src/Compilers/CSharp/Test/Emit3/FieldKeywordTests.cs +++ b/src/Compilers/CSharp/Test/Emit3/FieldKeywordTests.cs @@ -301,7 +301,7 @@ class C """; var comp = CreateCompilation(source); comp.VerifyEmitDiagnostics( - // (3,12): error CS8050: Only properties with backing fields can have initializers. + // (3,12): error CS8050: Only a property with a backing field and no setter, or a property with an auto-implemented setter, can have an initializer. // object P { set { } } = field; Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "P").WithLocation(3, 12), // (3,28): error CS0103: The name 'field' does not exist in the current context @@ -1138,22 +1138,22 @@ class C """; var comp = CreateCompilation(source, targetFramework: TargetFramework.Net80); comp.VerifyEmitDiagnostics( - // (3,23): error CS8050: Only properties with backing fields can have initializers. + // (3,23): error CS8050: Only a property with a backing field and no setter, or a property with an auto-implemented setter, can have an initializer. // public static int P4 { get => field; set { } } = 4; Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "P4").WithLocation(3, 23), - // (4,23): error CS8050: Only properties with backing fields can have initializers. + // (4,23): error CS8050: Only a property with a backing field and no setter, or a property with an auto-implemented setter, can have an initializer. // public static int P7 { get; set { } } = 7; Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "P7").WithLocation(4, 23), - // (5,23): error CS8050: Only properties with backing fields can have initializers. + // (5,23): error CS8050: Only a property with a backing field and no setter, or a property with an auto-implemented setter, can have an initializer. // public static int P8 { set { field = value; } } = 8; Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "P8").WithLocation(5, 23), - // (6,23): error CS8050: Only properties with backing fields can have initializers. + // (6,23): error CS8050: Only a property with a backing field and no setter, or a property with an auto-implemented setter, can have an initializer. // public static int P9 { get { return field; } set { field = value; } } = 9; Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "P9").WithLocation(6, 23), - // (7,23): error CS8050: Only properties with backing fields can have initializers. + // (7,23): error CS8050: Only a property with a backing field and no setter, or a property with an auto-implemented setter, can have an initializer. // public static int PA { get => 0; } = 10; Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "PA").WithLocation(7, 23), - // (8,23): error CS8050: Only properties with backing fields can have initializers. + // (8,23): error CS8050: Only a property with a backing field and no setter, or a property with an auto-implemented setter, can have an initializer. // public static int PB { get => 0; set { } } = 11; Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "PB").WithLocation(8, 23)); } @@ -1176,22 +1176,22 @@ class C """; var comp = CreateCompilation(source, targetFramework: TargetFramework.Net80); comp.VerifyEmitDiagnostics( - // (3,16): error CS8050: Only properties with backing fields can have initializers. + // (3,16): error CS8050: Only a property with a backing field and no setter, or a property with an auto-implemented setter, can have an initializer. // public int P4 { get => field; set { } } = 4; Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "P4").WithLocation(3, 16), - // (4,16): error CS8050: Only properties with backing fields can have initializers. + // (4,16): error CS8050: Only a property with a backing field and no setter, or a property with an auto-implemented setter, can have an initializer. // public int P7 { get; set { } } = 7; Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "P7").WithLocation(4, 16), - // (5,16): error CS8050: Only properties with backing fields can have initializers. + // (5,16): error CS8050: Only a property with a backing field and no setter, or a property with an auto-implemented setter, can have an initializer. // public int P8 { set { field = value; } } = 8; Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "P8").WithLocation(5, 16), - // (6,16): error CS8050: Only properties with backing fields can have initializers. + // (6,16): error CS8050: Only a property with a backing field and no setter, or a property with an auto-implemented setter, can have an initializer. // public int P9 { get { return field; } set { field = value; } } = 9; Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "P9").WithLocation(6, 16), - // (7,16): error CS8050: Only properties with backing fields can have initializers. + // (7,16): error CS8050: Only a property with a backing field and no setter, or a property with an auto-implemented setter, can have an initializer. // public int PA { get => 0; } = 10; Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "PA").WithLocation(7, 16), - // (8,16): error CS8050: Only properties with backing fields can have initializers. + // (8,16): error CS8050: Only a property with a backing field and no setter, or a property with an auto-implemented setter, can have an initializer. // public int PB { get => 0; set { } } = 11; Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "PB").WithLocation(8, 16)); } diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/RecordStructTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/RecordStructTests.cs index 0be2253568ac9..5063dcc1e67ba 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/RecordStructTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/RecordStructTests.cs @@ -3997,14 +3997,14 @@ record struct Pos2(int X) // (2,15): error CS0171: Field 'Pos.x' must be fully assigned before control is returned to the caller. Consider updating to language version '11.0' to auto-default the field. // record struct Pos(int X) Diagnostic(ErrorCode.ERR_UnassignedThisUnsupportedVersion, "Pos").WithArguments("Pos.x", "11.0").WithLocation(2, 15), - // (5,16): error CS8050: Only properties with backing fields can have initializers. + // (5,16): error CS8050: Only a property with a backing field and no setter, or a property with an auto-implemented setter, can have an initializer. // public int X { get { return x; } set { x = value; } } = X; Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "X").WithLocation(5, 16) ); comp = CreateCompilation(source, parseOptions: TestOptions.Regular11); comp.VerifyEmitDiagnostics( - // (5,16): error CS8050: Only properties with backing fields can have initializers. + // (5,16): error CS8050: Only a property with a backing field and no setter, or a property with an auto-implemented setter, can have an initializer. // public int X { get { return x; } set { x = value; } } = X; Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "X").WithLocation(5, 16) ); diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/StructsTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/StructsTests.cs index 03c8191cf1301..43173c6e71414 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/StructsTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/StructsTests.cs @@ -673,7 +673,7 @@ public void StructNonAutoPropertyInitializer() // (3,16): error CS8773: Feature 'struct field initializers' is not available in C# 9.0. Please use language version 10.0 or greater. // public int I { get { throw null; } set {} } = 9; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion9, "I").WithArguments("struct field initializers", "10.0").WithLocation(3, 16), - // (3,16): error CS8050: Only properties with backing fields can have initializers. + // (3,16): error CS8050: Only a property with a backing field and no setter, or a property with an auto-implemented setter, can have an initializer. // public int I { get { throw null; } set {} } = 9; Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "I").WithLocation(3, 16)); @@ -682,7 +682,7 @@ public void StructNonAutoPropertyInitializer() // (1,8): error CS8983: A 'struct' with field initializers must include an explicitly declared constructor. // struct S Diagnostic(ErrorCode.ERR_StructHasInitializersAndNoDeclaredConstructor, "S").WithLocation(1, 8), - // (3,16): error CS8050: Only properties with backing fields can have initializers. + // (3,16): error CS8050: Only a property with a backing field and no setter, or a property with an auto-implemented setter, can have an initializer. // public int I { get { throw null; } set {} } = 9; Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "I").WithLocation(3, 16)); } diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/UninitializedNonNullableFieldTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/UninitializedNonNullableFieldTests.cs index 47c7d4db26c96..478fd2e1fc56f 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/UninitializedNonNullableFieldTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/UninitializedNonNullableFieldTests.cs @@ -2631,7 +2631,7 @@ public C() // (5,19): error CS0548: 'C.P': property or indexer must have at least one accessor // public string P { } Diagnostic(ErrorCode.ERR_PropertyWithNoAccessors, "P").WithArguments("C.P").WithLocation(5, 19), - // (7,19): error CS8050: Only properties with backing fields can have initializers. + // (7,19): error CS8050: Only a property with a backing field and no setter, or a property with an auto-implemented setter, can have an initializer. // public string P3 { } = string.Empty; Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "P3").WithLocation(7, 19), // (7,19): error CS0548: 'C.P3': property or indexer must have at least one accessor diff --git a/src/Compilers/CSharp/Test/Symbol/Symbols/DefaultInterfaceImplementationTests.cs b/src/Compilers/CSharp/Test/Symbol/Symbols/DefaultInterfaceImplementationTests.cs index afe7f3a36609b..455ecabf97a04 100644 --- a/src/Compilers/CSharp/Test/Symbol/Symbols/DefaultInterfaceImplementationTests.cs +++ b/src/Compilers/CSharp/Test/Symbol/Symbols/DefaultInterfaceImplementationTests.cs @@ -3217,7 +3217,7 @@ public interface I1 // (4,34): error CS1014: A get or set accessor expected // static abstract int P1 {add; remove;} = 0; Diagnostic(ErrorCode.ERR_GetOrSetExpected, "remove").WithLocation(4, 34), - // (4,25): error CS8050: Only properties with backing fields can have initializers. + // (4,25): error CS8050: Only a property with a backing field and no setter, or a property with an auto-implemented setter, can have an initializer. // static abstract int P1 {add; remove;} = 0; Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "P1").WithLocation(4, 25), // (4,25): error CS0548: 'I1.P1': property or indexer must have at least one accessor @@ -3251,7 +3251,7 @@ public interface I1 // (4,33): error CS1014: A get or set accessor expected // static virtual int P1 {add; remove;} = 0; Diagnostic(ErrorCode.ERR_GetOrSetExpected, "remove").WithLocation(4, 33), - // (4,24): error CS8050: Only properties with backing fields can have initializers. + // (4,24): error CS8050: Only a property with a backing field and no setter, or a property with an auto-implemented setter, can have an initializer. // static virtual int P1 {add; remove;} = 0; Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "P1").WithLocation(4, 24), // (4,24): error CS0548: 'I1.P1': property or indexer must have at least one accessor @@ -3309,7 +3309,7 @@ public interface I1 targetFramework: TargetFramework.Net60); Assert.True(compilation1.Assembly.RuntimeSupportsDefaultInterfaceImplementation); compilation1.VerifyEmitDiagnostics( - // (4,25): error CS8050: Only properties with backing fields can have initializers. + // (4,25): error CS8050: Only a property with a backing field and no setter, or a property with an auto-implemented setter, can have an initializer. // static abstract int P1 {get; set;} = 0; Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "P1").WithLocation(4, 25) ); @@ -56844,7 +56844,7 @@ class Test1 : I2 } "; ValidatePropertyReAbstraction_014(source1, isStatic: true, - // (9,28): error CS8050: Only properties with backing fields can have initializers. + // (9,28): error CS8050: Only a property with a backing field and no setter, or a property with an auto-implemented setter, can have an initializer. // static abstract int I1.P1 { get; set; } = 0; Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "P1").WithLocation(9, 28), // (12,15): error CS0535: 'Test1' does not implement interface member 'I1.P1' @@ -56902,7 +56902,7 @@ class Test1 : I2 } "; ValidatePropertyReAbstraction_014(source1, isStatic: true, - // (9,28): error CS8050: Only properties with backing fields can have initializers. + // (9,28): error CS8050: Only a property with a backing field and no setter, or a property with an auto-implemented setter, can have an initializer. // static abstract int I1.P1 { get; } = 0; Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "P1").WithLocation(9, 28), // (12,15): error CS0535: 'Test1' does not implement interface member 'I1.P1' @@ -56960,7 +56960,7 @@ class Test1 : I2 } "; ValidatePropertyReAbstraction_014(source1, isStatic: true, - // (9,28): error CS8050: Only properties with backing fields can have initializers. + // (9,28): error CS8050: Only a property with a backing field and no setter, or a property with an auto-implemented setter, can have an initializer. // static abstract int I1.P1 { set; } = 0; Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "P1").WithLocation(9, 28), // (12,15): error CS0535: 'Test1' does not implement interface member 'I1.P1' diff --git a/src/Compilers/CSharp/Test/Symbol/Symbols/PartialPropertiesTests.cs b/src/Compilers/CSharp/Test/Symbol/Symbols/PartialPropertiesTests.cs index 195705f1db7f8..18489bdd38a71 100644 --- a/src/Compilers/CSharp/Test/Symbol/Symbols/PartialPropertiesTests.cs +++ b/src/Compilers/CSharp/Test/Symbol/Symbols/PartialPropertiesTests.cs @@ -3771,16 +3771,16 @@ partial class C var comp = CreateCompilation(source); comp.VerifyEmitDiagnostics( - // (3,27): error CS8050: Only properties with backing fields can have initializers. + // (3,27): error CS8050: Only a property with a backing field and no setter, or a property with an auto-implemented setter, can have an initializer. // public partial string P1 { get; set; } = "a"; Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "P1").WithLocation(3, 27), - // (7,27): error CS8050: Only properties with backing fields can have initializers. + // (7,27): error CS8050: Only a property with a backing field and no setter, or a property with an auto-implemented setter, can have an initializer. // public partial string P2 { get => ""; set { } } = "b"; Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "P2").WithLocation(7, 27), - // (9,27): error CS8050: Only properties with backing fields can have initializers. + // (9,27): error CS8050: Only a property with a backing field and no setter, or a property with an auto-implemented setter, can have an initializer. // public partial string P3 { get; set; } = "c"; Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "P3").WithLocation(9, 27), - // (10,27): error CS8050: Only properties with backing fields can have initializers. + // (10,27): error CS8050: Only a property with a backing field and no setter, or a property with an auto-implemented setter, can have an initializer. // public partial string P3 { get => ""; set { } } = "d"; Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "P3").WithLocation(10, 27)); } @@ -3804,25 +3804,25 @@ partial class C var comp = CreateCompilation(source); comp.VerifyEmitDiagnostics( - // (3,27): error CS8050: Only properties with backing fields can have initializers. + // (3,27): error CS8050: Only a property with a backing field and no setter, or a property with an auto-implemented setter, can have an initializer. // public partial string P1 { get; set; } = ERROR; Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "P1").WithLocation(3, 27), // (3,46): error CS0103: The name 'ERROR' does not exist in the current context // public partial string P1 { get; set; } = ERROR; Diagnostic(ErrorCode.ERR_NameNotInContext, "ERROR").WithArguments("ERROR").WithLocation(3, 46), - // (7,27): error CS8050: Only properties with backing fields can have initializers. + // (7,27): error CS8050: Only a property with a backing field and no setter, or a property with an auto-implemented setter, can have an initializer. // public partial string P2 { get => ""; set { } } = ERROR; Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "P2").WithLocation(7, 27), // (7,55): error CS0103: The name 'ERROR' does not exist in the current context // public partial string P2 { get => ""; set { } } = ERROR; Diagnostic(ErrorCode.ERR_NameNotInContext, "ERROR").WithArguments("ERROR").WithLocation(7, 55), - // (9,27): error CS8050: Only properties with backing fields can have initializers. + // (9,27): error CS8050: Only a property with a backing field and no setter, or a property with an auto-implemented setter, can have an initializer. // public partial string P3 { get; set; } = ERROR; Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "P3").WithLocation(9, 27), // (9,46): error CS0103: The name 'ERROR' does not exist in the current context // public partial string P3 { get; set; } = ERROR; Diagnostic(ErrorCode.ERR_NameNotInContext, "ERROR").WithArguments("ERROR").WithLocation(9, 46), - // (10,27): error CS8050: Only properties with backing fields can have initializers. + // (10,27): error CS8050: Only a property with a backing field and no setter, or a property with an auto-implemented setter, can have an initializer. // public partial string P3 { get => ""; set { } } = ERROR; Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "P3").WithLocation(10, 27), // (10,55): error CS0103: The name 'ERROR' does not exist in the current context @@ -3862,7 +3862,7 @@ partial class C // (6,6): warning CS0657: 'field' is not a valid attribute location for this declaration. Valid attribute locations for this declaration are 'property'. All attributes in this block will be ignored. // [field: Attr1] Diagnostic(ErrorCode.WRN_AttributeLocationOnBadDeclaration, "field").WithArguments("field", "property").WithLocation(6, 6), - // (7,27): error CS8050: Only properties with backing fields can have initializers. + // (7,27): error CS8050: Only a property with a backing field and no setter, or a property with an auto-implemented setter, can have an initializer. // public partial string P1 { get; set; } = "a"; Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "P1").WithLocation(7, 27), // (8,6): warning CS0657: 'field' is not a valid attribute location for this declaration. Valid attribute locations for this declaration are 'property'. All attributes in this block will be ignored. @@ -3874,19 +3874,19 @@ partial class C // (13,6): warning CS0657: 'field' is not a valid attribute location for this declaration. Valid attribute locations for this declaration are 'property'. All attributes in this block will be ignored. // [field: Attr2] Diagnostic(ErrorCode.WRN_AttributeLocationOnBadDeclaration, "field").WithArguments("field", "property").WithLocation(13, 6), - // (14,27): error CS8050: Only properties with backing fields can have initializers. + // (14,27): error CS8050: Only a property with a backing field and no setter, or a property with an auto-implemented setter, can have an initializer. // public partial string P2 { get => ""; set { } } = "b"; Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "P2").WithLocation(14, 27), // (16,6): warning CS0657: 'field' is not a valid attribute location for this declaration. Valid attribute locations for this declaration are 'property'. All attributes in this block will be ignored. // [field: Attr1] Diagnostic(ErrorCode.WRN_AttributeLocationOnBadDeclaration, "field").WithArguments("field", "property").WithLocation(16, 6), - // (17,27): error CS8050: Only properties with backing fields can have initializers. + // (17,27): error CS8050: Only a property with a backing field and no setter, or a property with an auto-implemented setter, can have an initializer. // public partial string P3 { get; set; } = "c"; Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "P3").WithLocation(17, 27), // (18,6): warning CS0657: 'field' is not a valid attribute location for this declaration. Valid attribute locations for this declaration are 'property'. All attributes in this block will be ignored. // [field: Attr2] Diagnostic(ErrorCode.WRN_AttributeLocationOnBadDeclaration, "field").WithArguments("field", "property").WithLocation(18, 6), - // (19,27): error CS8050: Only properties with backing fields can have initializers. + // (19,27): error CS8050: Only a property with a backing field and no setter, or a property with an auto-implemented setter, can have an initializer. // public partial string P3 { get => ""; set { } } = "d"; Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "P3").WithLocation(19, 27)); diff --git a/src/Compilers/CSharp/Test/Symbol/Symbols/SymbolErrorTests.cs b/src/Compilers/CSharp/Test/Symbol/Symbols/SymbolErrorTests.cs index d05bc29d82370..056577bc6c36f 100644 --- a/src/Compilers/CSharp/Test/Symbol/Symbols/SymbolErrorTests.cs +++ b/src/Compilers/CSharp/Test/Symbol/Symbols/SymbolErrorTests.cs @@ -16859,13 +16859,13 @@ public void CS8050ERR_InitializerOnNonAutoProperty() protected int P { get { throw null; } set { } } = 1; }"; CreateCompilation(source).VerifyDiagnostics( - // (5,9): error CS8050: Only properties with backing fields can have initializers. + // (5,9): error CS8050: Only a property with a backing field and no setter, or a property with an auto-implemented setter, can have an initializer. // int I { get { throw null; } set { } } = 1; Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "I").WithLocation(5, 9), - // (6,16): error CS8050: Only properties with backing fields can have initializers. + // (6,16): error CS8050: Only a property with a backing field and no setter, or a property with an auto-implemented setter, can have an initializer. // static int S { get { throw null; } set { } } = 1; Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "S").WithLocation(6, 16), - // (7,19): error CS8050: Only properties with backing fields can have initializers. + // (7,19): error CS8050: Only a property with a backing field and no setter, or a property with an auto-implemented setter, can have an initializer. // protected int P { get { throw null; } set { } } = 1; Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "P").WithLocation(7, 19) ); From cf61a169c9498c7d30b6993dca0295a74aa19ef7 Mon Sep 17 00:00:00 2001 From: Charles Stoner <10732005+cston@users.noreply.github.com> Date: Fri, 23 Aug 2024 12:50:13 -0700 Subject: [PATCH 16/21] Allow initializer with implemented setter --- .../Source/SourcePropertySymbolBase.cs | 3 +- .../CSharp/Test/Emit3/FieldKeywordTests.cs | 106 +++++++++--------- 2 files changed, 52 insertions(+), 57 deletions(-) diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertySymbolBase.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertySymbolBase.cs index 85160a8246e40..85b0273488847 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertySymbolBase.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertySymbolBase.cs @@ -302,8 +302,7 @@ protected void CheckInitializerIfNeeded(BindingDiagnosticBag diagnostics) { diagnostics.Add(ErrorCode.ERR_InstancePropertyInitializerInInterface, Location); } - else if (!IsAutoPropertyOrUsesFieldKeyword || - ((_propertyFlags & Flags.HasAutoPropertySet) == 0) && SetMethod is { }) + else if (!IsAutoPropertyOrUsesFieldKeyword) { diagnostics.Add(ErrorCode.ERR_InitializerOnNonAutoProperty, Location); } diff --git a/src/Compilers/CSharp/Test/Emit3/FieldKeywordTests.cs b/src/Compilers/CSharp/Test/Emit3/FieldKeywordTests.cs index bd465f70c3c40..9dbbc6f0b37f7 100644 --- a/src/Compilers/CSharp/Test/Emit3/FieldKeywordTests.cs +++ b/src/Compilers/CSharp/Test/Emit3/FieldKeywordTests.cs @@ -1038,22 +1038,26 @@ class C public static int P1 { get; } = 1; public static int P2 { get => field; } = 2; public static int P3 { get => field; set; } = 3; + public static int P4 { get => field; set { } } = 4; public static int P5 { get => 0; set; } = 5; public static int P6 { get; set; } = 6; + public static int P7 { get; set { } } = 7; + public static int P8 { set { field = value; } } = 8; + public static int P9 { get { return field; } set { field = value; } } = 9; } class Program { static void Main() { - Console.WriteLine((C.P1, C.P2, C.P3, C.P5, C.P6)); + Console.WriteLine((C.P1, C.P2, C.P3, C.P4, C.P5, C.P6, C.P7, C.P9)); } } """; - var verifier = CompileAndVerify(source, expectedOutput: "(1, 2, 3, 0, 6)"); + var verifier = CompileAndVerify(source, expectedOutput: "(1, 2, 3, 4, 0, 6, 7, 9)"); verifier.VerifyDiagnostics(); verifier.VerifyIL("C..cctor", """ { - // Code size 31 (0x1f) + // Code size 56 (0x38) .maxstack 1 IL_0000: ldc.i4.1 IL_0001: stsfld "int C.k__BackingField" @@ -1061,11 +1065,19 @@ .maxstack 1 IL_0007: stsfld "int C.k__BackingField" IL_000c: ldc.i4.3 IL_000d: stsfld "int C.k__BackingField" - IL_0012: ldc.i4.5 - IL_0013: stsfld "int C.k__BackingField" - IL_0018: ldc.i4.6 - IL_0019: stsfld "int C.k__BackingField" - IL_001e: ret + IL_0012: ldc.i4.4 + IL_0013: stsfld "int C.k__BackingField" + IL_0018: ldc.i4.5 + IL_0019: stsfld "int C.k__BackingField" + IL_001e: ldc.i4.6 + IL_001f: stsfld "int C.k__BackingField" + IL_0024: ldc.i4.7 + IL_0025: stsfld "int C.k__BackingField" + IL_002a: ldc.i4.8 + IL_002b: stsfld "int C.k__BackingField" + IL_0030: ldc.i4.s 9 + IL_0032: stsfld "int C.k__BackingField" + IL_0037: ret } """); } @@ -1082,23 +1094,27 @@ class C public int P1 { get; } = 1; public int P2 { get => field; } = 2; public int P3 { get => field; {{setter}}; } = 3; + public int P4 { get => field; {{setter}} { } } = 4; public int P5 { get => 0; {{setter}}; } = 5; public int P6 { get; {{setter}}; } = 6; + public int P7 { get; {{setter}} { } } = 7; + public int P8 { {{setter}} { field = value; } } = 8; + public int P9 { get { return field; } {{setter}} { field = value; } } = 9; } class Program { static void Main() { var c = new C(); - Console.WriteLine((c.P1, c.P2, c.P3, c.P5, c.P6)); + Console.WriteLine((c.P1, c.P2, c.P3, c.P4, c.P5, c.P6, c.P7, c.P9)); } } """; - var verifier = CompileAndVerify(source, targetFramework: TargetFramework.Net80, verify: Verification.Skipped, expectedOutput: IncludeExpectedOutput("(1, 2, 3, 0, 6)")); + var verifier = CompileAndVerify(source, targetFramework: TargetFramework.Net80, verify: Verification.Skipped, expectedOutput: IncludeExpectedOutput("(1, 2, 3, 4, 0, 6, 7, 9)")); verifier.VerifyDiagnostics(); verifier.VerifyIL("C..ctor", """ { - // Code size 42 (0x2a) + // Code size 71 (0x47) .maxstack 2 IL_0000: ldarg.0 IL_0001: ldc.i4.1 @@ -1110,14 +1126,26 @@ .maxstack 2 IL_000f: ldc.i4.3 IL_0010: stfld "int C.k__BackingField" IL_0015: ldarg.0 - IL_0016: ldc.i4.5 - IL_0017: stfld "int C.k__BackingField" + IL_0016: ldc.i4.4 + IL_0017: stfld "int C.k__BackingField" IL_001c: ldarg.0 - IL_001d: ldc.i4.6 - IL_001e: stfld "int C.k__BackingField" + IL_001d: ldc.i4.5 + IL_001e: stfld "int C.k__BackingField" IL_0023: ldarg.0 - IL_0024: call "object..ctor()" - IL_0029: ret + IL_0024: ldc.i4.6 + IL_0025: stfld "int C.k__BackingField" + IL_002a: ldarg.0 + IL_002b: ldc.i4.7 + IL_002c: stfld "int C.k__BackingField" + IL_0031: ldarg.0 + IL_0032: ldc.i4.8 + IL_0033: stfld "int C.k__BackingField" + IL_0038: ldarg.0 + IL_0039: ldc.i4.s 9 + IL_003b: stfld "int C.k__BackingField" + IL_0040: ldarg.0 + IL_0041: call "object..ctor()" + IL_0046: ret } """); } @@ -1128,10 +1156,6 @@ public void Initializer_03() string source = """ class C { - public static int P4 { get => field; set { } } = 4; - public static int P7 { get; set { } } = 7; - public static int P8 { set { field = value; } } = 8; - public static int P9 { get { return field; } set { field = value; } } = 9; public static int PA { get => 0; } = 10; public static int PB { get => 0; set { } } = 11; } @@ -1139,23 +1163,11 @@ class C var comp = CreateCompilation(source, targetFramework: TargetFramework.Net80); comp.VerifyEmitDiagnostics( // (3,23): error CS8050: Only a property with a backing field and no setter, or a property with an auto-implemented setter, can have an initializer. - // public static int P4 { get => field; set { } } = 4; - Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "P4").WithLocation(3, 23), - // (4,23): error CS8050: Only a property with a backing field and no setter, or a property with an auto-implemented setter, can have an initializer. - // public static int P7 { get; set { } } = 7; - Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "P7").WithLocation(4, 23), - // (5,23): error CS8050: Only a property with a backing field and no setter, or a property with an auto-implemented setter, can have an initializer. - // public static int P8 { set { field = value; } } = 8; - Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "P8").WithLocation(5, 23), - // (6,23): error CS8050: Only a property with a backing field and no setter, or a property with an auto-implemented setter, can have an initializer. - // public static int P9 { get { return field; } set { field = value; } } = 9; - Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "P9").WithLocation(6, 23), - // (7,23): error CS8050: Only a property with a backing field and no setter, or a property with an auto-implemented setter, can have an initializer. // public static int PA { get => 0; } = 10; - Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "PA").WithLocation(7, 23), - // (8,23): error CS8050: Only a property with a backing field and no setter, or a property with an auto-implemented setter, can have an initializer. + Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "PA").WithLocation(3, 23), + // (4,23): error CS8050: Only a property with a backing field and no setter, or a property with an auto-implemented setter, can have an initializer. // public static int PB { get => 0; set { } } = 11; - Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "PB").WithLocation(8, 23)); + Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "PB").WithLocation(4, 23)); } [Theory] @@ -1166,10 +1178,6 @@ public void Initializer_04(bool useInit) string source = $$""" class C { - public int P4 { get => field; {{setter}} { } } = 4; - public int P7 { get; {{setter}} { } } = 7; - public int P8 { {{setter}} { field = value; } } = 8; - public int P9 { get { return field; } {{setter}} { field = value; } } = 9; public int PA { get => 0; } = 10; public int PB { get => 0; {{setter}} { } } = 11; } @@ -1177,23 +1185,11 @@ class C var comp = CreateCompilation(source, targetFramework: TargetFramework.Net80); comp.VerifyEmitDiagnostics( // (3,16): error CS8050: Only a property with a backing field and no setter, or a property with an auto-implemented setter, can have an initializer. - // public int P4 { get => field; set { } } = 4; - Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "P4").WithLocation(3, 16), - // (4,16): error CS8050: Only a property with a backing field and no setter, or a property with an auto-implemented setter, can have an initializer. - // public int P7 { get; set { } } = 7; - Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "P7").WithLocation(4, 16), - // (5,16): error CS8050: Only a property with a backing field and no setter, or a property with an auto-implemented setter, can have an initializer. - // public int P8 { set { field = value; } } = 8; - Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "P8").WithLocation(5, 16), - // (6,16): error CS8050: Only a property with a backing field and no setter, or a property with an auto-implemented setter, can have an initializer. - // public int P9 { get { return field; } set { field = value; } } = 9; - Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "P9").WithLocation(6, 16), - // (7,16): error CS8050: Only a property with a backing field and no setter, or a property with an auto-implemented setter, can have an initializer. // public int PA { get => 0; } = 10; - Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "PA").WithLocation(7, 16), - // (8,16): error CS8050: Only a property with a backing field and no setter, or a property with an auto-implemented setter, can have an initializer. + Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "PA").WithLocation(3, 16), + // (4,16): error CS8050: Only a property with a backing field and no setter, or a property with an auto-implemented setter, can have an initializer. // public int PB { get => 0; set { } } = 11; - Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "PB").WithLocation(8, 16)); + Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "PB").WithLocation(4, 16)); } [Fact] From cb56137d26f6703d066ddf2b4dac0214cef2ab07 Mon Sep 17 00:00:00 2001 From: Charles Stoner <10732005+cston@users.noreply.github.com> Date: Thu, 22 Aug 2024 17:04:57 -0700 Subject: [PATCH 17/21] Test structs and interfaces --- .../CSharp/Test/Emit3/FieldKeywordTests.cs | 380 +++++++++++++++--- 1 file changed, 332 insertions(+), 48 deletions(-) diff --git a/src/Compilers/CSharp/Test/Emit3/FieldKeywordTests.cs b/src/Compilers/CSharp/Test/Emit3/FieldKeywordTests.cs index 9dbbc6f0b37f7..dcdb0c43f2e33 100644 --- a/src/Compilers/CSharp/Test/Emit3/FieldKeywordTests.cs +++ b/src/Compilers/CSharp/Test/Emit3/FieldKeywordTests.cs @@ -1028,12 +1028,71 @@ static void ReportField(FieldInfo field) """)); } + [Theory] + [CombinatorialData] + public void Initializer_01A([CombinatorialValues("class", "struct", "ref struct", "interface")] string typeKind) + { + string source = $$""" + using System; + {{typeKind}} C + { + public static int P1 { get; } = 1; + public static int P2 { get => field; } = 2; + public static int P3 { get => field; set; } = 3; + public static int P4 { get => field; set { } } = 4; + public static int P5 { get => 0; set; } = 5; + public static int P6 { get; set; } = 6; + public static int P7 { get; set { } } = 7; + public static int P8 { set { field = value; } } = 8; + public static int P9 { get { return field; } set { field = value; } } = 9; + } + class Program + { + static void Main() + { + Console.WriteLine((C.P1, C.P2, C.P3, C.P4, C.P5, C.P6, C.P7, C.P9)); + } + } + """; + var verifier = CompileAndVerify( + source, + targetFramework: TargetFramework.Net80, + verify: Verification.Skipped, + expectedOutput: IncludeExpectedOutput("(1, 2, 3, 4, 0, 6, 7, 9)")); + verifier.VerifyDiagnostics(); + verifier.VerifyIL("C..cctor", """ + { + // Code size 56 (0x38) + .maxstack 1 + IL_0000: ldc.i4.1 + IL_0001: stsfld "int C.k__BackingField" + IL_0006: ldc.i4.2 + IL_0007: stsfld "int C.k__BackingField" + IL_000c: ldc.i4.3 + IL_000d: stsfld "int C.k__BackingField" + IL_0012: ldc.i4.4 + IL_0013: stsfld "int C.k__BackingField" + IL_0018: ldc.i4.5 + IL_0019: stsfld "int C.k__BackingField" + IL_001e: ldc.i4.6 + IL_001f: stsfld "int C.k__BackingField" + IL_0024: ldc.i4.7 + IL_0025: stsfld "int C.k__BackingField" + IL_002a: ldc.i4.8 + IL_002b: stsfld "int C.k__BackingField" + IL_0030: ldc.i4.s 9 + IL_0032: stsfld "int C.k__BackingField" + IL_0037: ret + } + """); + } + [Fact] - public void Initializer_01() + public void Initializer_01B() { string source = """ using System; - class C + interface C { public static int P1 { get; } = 1; public static int P2 { get => field; } = 2; @@ -1053,7 +1112,11 @@ static void Main() } } """; - var verifier = CompileAndVerify(source, expectedOutput: "(1, 2, 3, 4, 0, 6, 7, 9)"); + var verifier = CompileAndVerify( + source, + targetFramework: TargetFramework.Net80, + verify: Verification.Skipped, + expectedOutput: IncludeExpectedOutput("(1, 2, 3, 4, 0, 6, 7, 9)")); verifier.VerifyDiagnostics(); verifier.VerifyIL("C..cctor", """ { @@ -1084,7 +1147,7 @@ .maxstack 1 [Theory] [CombinatorialData] - public void Initializer_02(bool useInit) + public void Initializer_02A(bool useInit) { string setter = useInit ? "init" : "set"; string source = $$""" @@ -1110,7 +1173,11 @@ static void Main() } } """; - var verifier = CompileAndVerify(source, targetFramework: TargetFramework.Net80, verify: Verification.Skipped, expectedOutput: IncludeExpectedOutput("(1, 2, 3, 4, 0, 6, 7, 9)")); + var verifier = CompileAndVerify( + source, + targetFramework: TargetFramework.Net80, + verify: Verification.Skipped, + expectedOutput: IncludeExpectedOutput("(1, 2, 3, 4, 0, 6, 7, 9)")); verifier.VerifyDiagnostics(); verifier.VerifyIL("C..ctor", """ { @@ -1150,6 +1217,178 @@ .maxstack 2 """); } + [Theory] + [CombinatorialData] + public void Initializer_02B(bool useRefStruct, bool useInit) + { + string setter = useInit ? "init" : "set"; + string typeKind = useRefStruct ? "ref struct" : "struct"; + string source = $$""" + using System; + {{typeKind}} C + { + public int P1 { get; } = 1; + public int P2 { get => field; } = 2; + public int P3 { get => field; {{setter}}; } = 3; + public int P4 { get => field; {{setter}} { } } = 4; + public int P5 { get => 0; {{setter}}; } = 5; + public int P6 { get; {{setter}}; } = 6; + public int P7 { get; {{setter}} { } } = 7; + public int P8 { {{setter}} { field = value; } } = 8; + public int P9 { get { return field; } {{setter}} { field = value; } } = 9; + public C() { } + } + class Program + { + static void Main() + { + var c = new C(); + Console.WriteLine((c.P1, c.P2, c.P3, c.P4, c.P5, c.P6, c.P7, c.P9)); + } + } + """; + var verifier = CompileAndVerify( + source, + targetFramework: TargetFramework.Net80, + verify: Verification.Skipped, + expectedOutput: IncludeExpectedOutput("(1, 2, 3, 4, 0, 6, 7, 9)")); + verifier.VerifyDiagnostics(); + verifier.VerifyIL("C..ctor", """ + { + // Code size 65 (0x41) + .maxstack 2 + IL_0000: ldarg.0 + IL_0001: ldc.i4.1 + IL_0002: stfld "int C.k__BackingField" + IL_0007: ldarg.0 + IL_0008: ldc.i4.2 + IL_0009: stfld "int C.k__BackingField" + IL_000e: ldarg.0 + IL_000f: ldc.i4.3 + IL_0010: stfld "int C.k__BackingField" + IL_0015: ldarg.0 + IL_0016: ldc.i4.4 + IL_0017: stfld "int C.k__BackingField" + IL_001c: ldarg.0 + IL_001d: ldc.i4.5 + IL_001e: stfld "int C.k__BackingField" + IL_0023: ldarg.0 + IL_0024: ldc.i4.6 + IL_0025: stfld "int C.k__BackingField" + IL_002a: ldarg.0 + IL_002b: ldc.i4.7 + IL_002c: stfld "int C.k__BackingField" + IL_0031: ldarg.0 + IL_0032: ldc.i4.8 + IL_0033: stfld "int C.k__BackingField" + IL_0038: ldarg.0 + IL_0039: ldc.i4.s 9 + IL_003b: stfld "int C.k__BackingField" + IL_0040: ret + } + """); + } + + [Theory] + [CombinatorialData] + public void Initializer_02C(bool useInit) + { + string setter = useInit ? "init" : "set"; + string source = $$""" + using System; + interface C + { + public int P1 { get; } = 1; + public int P2 { get => field; } = 2; + public int P3 { get => field; {{setter}}; } = 3; + public int P4 { get => field; {{setter}} { } } = 4; + public int P5 { get => 0; {{setter}}; } = 5; + public int P6 { get; {{setter}}; } = 6; + public int P7 { get; {{setter}} { } } = 7; + public int P8 { {{setter}} { field = value; } } = 8; + public int P9 { get { return field; } {{setter}} { field = value; } } = 9; + } + """; + var comp = CreateCompilation(source, targetFramework: TargetFramework.Net80); + comp.VerifyEmitDiagnostics( + // (4,16): error CS8053: Instance properties in interfaces cannot have initializers. + // public int P1 { get; } = 1; + Diagnostic(ErrorCode.ERR_InstancePropertyInitializerInInterface, "P1").WithLocation(4, 16), + // (5,16): error CS8053: Instance properties in interfaces cannot have initializers. + // public int P2 { get => field; } = 2; + Diagnostic(ErrorCode.ERR_InstancePropertyInitializerInInterface, "P2").WithLocation(5, 16), + // (6,16): error CS8053: Instance properties in interfaces cannot have initializers. + // public int P3 { get => field; set; } = 3; + Diagnostic(ErrorCode.ERR_InstancePropertyInitializerInInterface, "P3").WithLocation(6, 16), + // (6,35): error CS0501: 'C.P3.set' must declare a body because it is not marked abstract, extern, or partial + // public int P3 { get => field; set; } = 3; + Diagnostic(ErrorCode.ERR_ConcreteMissingBody, setter).WithArguments($"C.P3.{setter}").WithLocation(6, 35), + // (7,16): error CS8053: Instance properties in interfaces cannot have initializers. + // public int P4 { get => field; set { } } = 4; + Diagnostic(ErrorCode.ERR_InstancePropertyInitializerInInterface, "P4").WithLocation(7, 16), + // (8,16): error CS8053: Instance properties in interfaces cannot have initializers. + // public int P5 { get => 0; set; } = 5; + Diagnostic(ErrorCode.ERR_InstancePropertyInitializerInInterface, "P5").WithLocation(8, 16), + // (8,31): error CS0501: 'C.P5.set' must declare a body because it is not marked abstract, extern, or partial + // public int P5 { get => 0; set; } = 5; + Diagnostic(ErrorCode.ERR_ConcreteMissingBody, setter).WithArguments($"C.P5.{setter}").WithLocation(8, 31), + // (9,16): error CS8053: Instance properties in interfaces cannot have initializers. + // public int P6 { get; set; } = 6; + Diagnostic(ErrorCode.ERR_InstancePropertyInitializerInInterface, "P6").WithLocation(9, 16), + // (10,16): error CS8053: Instance properties in interfaces cannot have initializers. + // public int P7 { get; set { } } = 7; + Diagnostic(ErrorCode.ERR_InstancePropertyInitializerInInterface, "P7").WithLocation(10, 16), + // (10,21): error CS0501: 'C.P7.get' must declare a body because it is not marked abstract, extern, or partial + // public int P7 { get; set { } } = 7; + Diagnostic(ErrorCode.ERR_ConcreteMissingBody, "get").WithArguments("C.P7.get").WithLocation(10, 21), + // (11,16): error CS8053: Instance properties in interfaces cannot have initializers. + // public int P8 { set { field = value; } } = 8; + Diagnostic(ErrorCode.ERR_InstancePropertyInitializerInInterface, "P8").WithLocation(11, 16), + // (12,16): error CS8053: Instance properties in interfaces cannot have initializers. + // public int P9 { get { return field; } set { field = value; } } = 9; + Diagnostic(ErrorCode.ERR_InstancePropertyInitializerInInterface, "P9").WithLocation(12, 16)); + } + + [Theory] + [CombinatorialData] + public void Initializer_02D(bool useRefStruct, bool useInit) + { + string setter = useInit ? "init" : "set"; + string typeKind = useRefStruct ? "ref struct" : " struct"; + string source = $$""" + {{typeKind}} S1 + { + public int P1 { get; } = 1; + } + {{typeKind}} S2 + { + public int P2 { get => field; } = 2; + } + {{typeKind}} S3 + { + public int P3 { get => field; {{setter}}; } = 3; + } + {{typeKind}} S6 + { + public int P6 { get; {{setter}}; } = 6; + } + """; + var comp = CreateCompilation(source, targetFramework: TargetFramework.Net80); + comp.VerifyEmitDiagnostics( + // (1,12): error CS8983: A 'struct' with field initializers must include an explicitly declared constructor. + // struct S1 + Diagnostic(ErrorCode.ERR_StructHasInitializersAndNoDeclaredConstructor, "S1").WithLocation(1, 12), + // (5,12): error CS8983: A 'struct' with field initializers must include an explicitly declared constructor. + // struct S2 + Diagnostic(ErrorCode.ERR_StructHasInitializersAndNoDeclaredConstructor, "S2").WithLocation(5, 12), + // (9,12): error CS8983: A 'struct' with field initializers must include an explicitly declared constructor. + // struct S3 + Diagnostic(ErrorCode.ERR_StructHasInitializersAndNoDeclaredConstructor, "S3").WithLocation(9, 12), + // (13,12): error CS8983: A 'struct' with field initializers must include an explicitly declared constructor. + // struct S6 + Diagnostic(ErrorCode.ERR_StructHasInitializersAndNoDeclaredConstructor, "S6").WithLocation(13, 12)); + } + [Fact] public void Initializer_03() { @@ -1192,12 +1431,13 @@ class C Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "PB").WithLocation(4, 16)); } - [Fact] - public void ConstructorAssignment_01() + [Theory] + [CombinatorialData] + public void ConstructorAssignment_01([CombinatorialValues("class", "struct", "ref struct", "interface")] string typeKind) { - string source = """ + string source = $$""" using System; - class C + {{typeKind}} C { public static int P1 { get; } public static int P2 { get => field; } @@ -1229,7 +1469,11 @@ static void Main() } } """; - var verifier = CompileAndVerify(source, expectedOutput: "(1, 2, 3, 0, 0, 6, 0, 9)"); + var verifier = CompileAndVerify( + source, + targetFramework: TargetFramework.Net80, + verify: Verification.Skipped, + expectedOutput: IncludeExpectedOutput("(1, 2, 3, 0, 0, 6, 0, 9)")); verifier.VerifyDiagnostics(); verifier.VerifyIL("C..cctor", """ { @@ -1260,12 +1504,12 @@ .maxstack 1 [Theory] [CombinatorialData] - public void ConstructorAssignment_02(bool useInit) + public void ConstructorAssignment_02([CombinatorialValues("class", "struct", "ref struct")] string typeKind, bool useInit) { string setter = useInit ? "init" : "set"; string source = $$""" using System; - class C + {{typeKind}} C { public int P1 { get; } public int P2 { get => field; } @@ -1300,42 +1544,82 @@ static void Main() """; var verifier = CompileAndVerify(source, targetFramework: TargetFramework.Net80, verify: Verification.Skipped, expectedOutput: IncludeExpectedOutput("(1, 2, 3, 0, 0, 6, 0, 9)")); verifier.VerifyDiagnostics(); - verifier.VerifyIL("C..ctor", $$""" - { - // Code size 71 (0x47) - .maxstack 2 - IL_0000: ldarg.0 - IL_0001: call "object..ctor()" - IL_0006: ldarg.0 - IL_0007: ldc.i4.1 - IL_0008: stfld "int C.k__BackingField" - IL_000d: ldarg.0 - IL_000e: ldc.i4.2 - IL_000f: stfld "int C.k__BackingField" - IL_0014: ldarg.0 - IL_0015: ldc.i4.3 - IL_0016: call "void C.P3.{{setter}}" - IL_001b: ldarg.0 - IL_001c: ldc.i4.4 - IL_001d: call "void C.P4.{{setter}}" - IL_0022: ldarg.0 - IL_0023: ldc.i4.5 - IL_0024: call "void C.P5.{{setter}}" - IL_0029: ldarg.0 - IL_002a: ldc.i4.6 - IL_002b: call "void C.P6.{{setter}}" - IL_0030: ldarg.0 - IL_0031: ldc.i4.7 - IL_0032: call "void C.P7.{{setter}}" - IL_0037: ldarg.0 - IL_0038: ldc.i4.8 - IL_0039: call "void C.P8.{{setter}}" - IL_003e: ldarg.0 - IL_003f: ldc.i4.s 9 - IL_0041: call "void C.P9.{{setter}}" - IL_0046: ret - } - """); + if (typeKind == "class") + { + verifier.VerifyIL("C..ctor", $$""" + { + // Code size 71 (0x47) + .maxstack 2 + IL_0000: ldarg.0 + IL_0001: call "object..ctor()" + IL_0006: ldarg.0 + IL_0007: ldc.i4.1 + IL_0008: stfld "int C.k__BackingField" + IL_000d: ldarg.0 + IL_000e: ldc.i4.2 + IL_000f: stfld "int C.k__BackingField" + IL_0014: ldarg.0 + IL_0015: ldc.i4.3 + IL_0016: call "void C.P3.{{setter}}" + IL_001b: ldarg.0 + IL_001c: ldc.i4.4 + IL_001d: call "void C.P4.{{setter}}" + IL_0022: ldarg.0 + IL_0023: ldc.i4.5 + IL_0024: call "void C.P5.{{setter}}" + IL_0029: ldarg.0 + IL_002a: ldc.i4.6 + IL_002b: call "void C.P6.{{setter}}" + IL_0030: ldarg.0 + IL_0031: ldc.i4.7 + IL_0032: call "void C.P7.{{setter}}" + IL_0037: ldarg.0 + IL_0038: ldc.i4.8 + IL_0039: call "void C.P8.{{setter}}" + IL_003e: ldarg.0 + IL_003f: ldc.i4.s 9 + IL_0041: call "void C.P9.{{setter}}" + IL_0046: ret + } + """); + } + else + { + verifier.VerifyIL("C..ctor", $$""" + { + // Code size 65 (0x41) + .maxstack 2 + IL_0000: ldarg.0 + IL_0001: ldc.i4.1 + IL_0002: stfld "int C.k__BackingField" + IL_0007: ldarg.0 + IL_0008: ldc.i4.2 + IL_0009: stfld "int C.k__BackingField" + IL_000e: ldarg.0 + IL_000f: ldc.i4.3 + IL_0010: call "void C.P3.{{setter}}" + IL_0015: ldarg.0 + IL_0016: ldc.i4.4 + IL_0017: call "void C.P4.{{setter}}" + IL_001c: ldarg.0 + IL_001d: ldc.i4.5 + IL_001e: call "void C.P5.{{setter}}" + IL_0023: ldarg.0 + IL_0024: ldc.i4.6 + IL_0025: call "void C.P6.{{setter}}" + IL_002a: ldarg.0 + IL_002b: ldc.i4.7 + IL_002c: call "void C.P7.{{setter}}" + IL_0031: ldarg.0 + IL_0032: ldc.i4.8 + IL_0033: call "void C.P8.{{setter}}" + IL_0038: ldarg.0 + IL_0039: ldc.i4.s 9 + IL_003b: call "void C.P9.{{setter}}" + IL_0040: ret + } + """); + } } [Fact] From ad68a0f0002f260c6e27a3e63a525cd50b288502 Mon Sep 17 00:00:00 2001 From: Charles Stoner <10732005+cston@users.noreply.github.com> Date: Fri, 23 Aug 2024 17:16:51 -0700 Subject: [PATCH 18/21] Update tests --- .../CSharp/Test/Emit3/FieldKeywordTests.cs | 294 ++++++++++-------- 1 file changed, 163 insertions(+), 131 deletions(-) diff --git a/src/Compilers/CSharp/Test/Emit3/FieldKeywordTests.cs b/src/Compilers/CSharp/Test/Emit3/FieldKeywordTests.cs index dcdb0c43f2e33..475df6d461011 100644 --- a/src/Compilers/CSharp/Test/Emit3/FieldKeywordTests.cs +++ b/src/Compilers/CSharp/Test/Emit3/FieldKeywordTests.cs @@ -1756,62 +1756,53 @@ public B() [Theory] [CombinatorialData] - public void ReadOnly_01(bool useReadOnlyType, bool useReadOnlyProperty) + public void ReadOnly_01(bool useReadOnlyType, bool useReadOnlyProperty, bool useInit) { static string getReadOnlyModifier(bool useReadOnly) => useReadOnly ? "readonly" : " "; string typeModifier = getReadOnlyModifier(useReadOnlyType); string propertyModifier = getReadOnlyModifier(useReadOnlyProperty); + string setter = useInit ? "init" : "set"; string source = $$""" {{typeModifier}} struct S { {{propertyModifier}} object P1 { get; } {{propertyModifier}} object P2 { get => field; } - {{propertyModifier}} object P3 { get => field; set; } - {{propertyModifier}} object P4 { get => field; init; } - {{propertyModifier}} object P5 { get => field; set { } } - {{propertyModifier}} object P6 { get => field; init { } } - {{propertyModifier}} object P7 { get => null; } - {{propertyModifier}} object P8 { get => null; set; } - {{propertyModifier}} object P9 { get => null; init; } - {{propertyModifier}} object PA { get => null; set { } } - {{propertyModifier}} object PB { get => null; init { } } - {{propertyModifier}} object PC { get => null; set { _ = field; } } - {{propertyModifier}} object PD { get => null; init { _ = field; } } - {{propertyModifier}} object PE { get; set; } - {{propertyModifier}} object PF { get; init; } - {{propertyModifier}} object PG { get; set { } } - {{propertyModifier}} object PH { get; init { } } - {{propertyModifier}} object PI { set { _ = field; } } - {{propertyModifier}} object PJ { init { _ = field; } } - {{propertyModifier}} object PK { get { field = null; return null; } } - {{propertyModifier}} object PL { get; set { field = value; } } - {{propertyModifier}} object PM { get; init { field = value; } } - {{propertyModifier}} object PN { set { field = value; } } - {{propertyModifier}} object PO { init { field = value; } } + {{propertyModifier}} object P3 { get => field; {{setter}}; } + {{propertyModifier}} object P4 { get => field; {{setter}} { } } + {{propertyModifier}} object P5 { get => null; } + {{propertyModifier}} object P6 { get => null; {{setter}}; } + {{propertyModifier}} object P7 { get => null; {{setter}} { } } + {{propertyModifier}} object P8 { get => null; {{setter}} { _ = field; } } + {{propertyModifier}} object P9 { get; {{setter}}; } + {{propertyModifier}} object PA { get; {{setter}} { } } + {{propertyModifier}} object PB { {{setter}} { _ = field; } } + {{propertyModifier}} object PC { get; {{setter}} { field = value; } } + {{propertyModifier}} object PD { {{setter}} { field = value; } } } """; var comp = CreateCompilation(source, targetFramework: TargetFramework.Net80); - if (useReadOnlyType) + if (useInit) + { + comp.VerifyEmitDiagnostics(); + } + else if (useReadOnlyType) { comp.VerifyEmitDiagnostics( // (5,21): error CS8341: Auto-implemented instance properties in readonly structs must be readonly. // object P3 { get => field; set; } Diagnostic(ErrorCode.ERR_AutoPropsInRoStruct, "P3").WithLocation(5, 21), - // (10,21): error CS8341: Auto-implemented instance properties in readonly structs must be readonly. - // object P8 { get => null; set; } - Diagnostic(ErrorCode.ERR_AutoPropsInRoStruct, "P8").WithLocation(10, 21), - // (16,21): error CS8341: Auto-implemented instance properties in readonly structs must be readonly. - // object PE { get; set; } - Diagnostic(ErrorCode.ERR_AutoPropsInRoStruct, "PE").WithLocation(16, 21), - // (22,32): error CS1604: Cannot assign to 'field' because it is read-only - // object PK { get { field = null; return null; } } - Diagnostic(ErrorCode.ERR_AssgReadonlyLocal, "field").WithArguments("field").WithLocation(22, 32), - // (23,37): error CS1604: Cannot assign to 'field' because it is read-only - // object PL { get; set { field = value; } } - Diagnostic(ErrorCode.ERR_AssgReadonlyLocal, "field").WithArguments("field").WithLocation(23, 37), - // (25,32): error CS1604: Cannot assign to 'field' because it is read-only - // object PN { set { field = value; } } - Diagnostic(ErrorCode.ERR_AssgReadonlyLocal, "field").WithArguments("field").WithLocation(25, 32)); + // (8,21): error CS8341: Auto-implemented instance properties in readonly structs must be readonly. + // object P6 { get => null; set; } + Diagnostic(ErrorCode.ERR_AutoPropsInRoStruct, "P6").WithLocation(8, 21), + // (11,21): error CS8341: Auto-implemented instance properties in readonly structs must be readonly. + // object P9 { get; set; } + Diagnostic(ErrorCode.ERR_AutoPropsInRoStruct, "P9").WithLocation(11, 21), + // (14,37): error CS1604: Cannot assign to 'field' because it is read-only + // object PC { get; set { field = value; } } + Diagnostic(ErrorCode.ERR_AssgReadonlyLocal, "field").WithArguments("field").WithLocation(14, 37), + // (15,32): error CS1604: Cannot assign to 'field' because it is read-only + // object PD { set { field = value; } } + Diagnostic(ErrorCode.ERR_AssgReadonlyLocal, "field").WithArguments("field").WithLocation(15, 32)); } else if (useReadOnlyProperty) { @@ -1819,21 +1810,18 @@ public void ReadOnly_01(bool useReadOnlyType, bool useReadOnlyProperty) // (5,21): error CS8659: Auto-implemented property 'S.P3' cannot be marked 'readonly' because it has a 'set' accessor. // readonly object P3 { get => field; set; } Diagnostic(ErrorCode.ERR_AutoPropertyWithSetterCantBeReadOnly, "P3").WithArguments("S.P3").WithLocation(5, 21), - // (10,21): error CS8659: Auto-implemented property 'S.P8' cannot be marked 'readonly' because it has a 'set' accessor. - // readonly object P8 { get => null; set; } - Diagnostic(ErrorCode.ERR_AutoPropertyWithSetterCantBeReadOnly, "P8").WithArguments("S.P8").WithLocation(10, 21), - // (16,21): error CS8659: Auto-implemented property 'S.PE' cannot be marked 'readonly' because it has a 'set' accessor. - // readonly object PE { get; set; } - Diagnostic(ErrorCode.ERR_AutoPropertyWithSetterCantBeReadOnly, "PE").WithArguments("S.PE").WithLocation(16, 21), - // (22,32): error CS1604: Cannot assign to 'field' because it is read-only - // readonly object PK { get { field = null; return null; } } - Diagnostic(ErrorCode.ERR_AssgReadonlyLocal, "field").WithArguments("field").WithLocation(22, 32), - // (23,37): error CS1604: Cannot assign to 'field' because it is read-only - // readonly object PL { get; set { field = value; } } - Diagnostic(ErrorCode.ERR_AssgReadonlyLocal, "field").WithArguments("field").WithLocation(23, 37), - // (25,32): error CS1604: Cannot assign to 'field' because it is read-only - // readonly object PN { set { field = value; } } - Diagnostic(ErrorCode.ERR_AssgReadonlyLocal, "field").WithArguments("field").WithLocation(25, 32)); + // (8,21): error CS8659: Auto-implemented property 'S.P6' cannot be marked 'readonly' because it has a 'set' accessor. + // readonly object P6 { get => null; set; } + Diagnostic(ErrorCode.ERR_AutoPropertyWithSetterCantBeReadOnly, "P6").WithArguments("S.P6").WithLocation(8, 21), + // (11,21): error CS8659: Auto-implemented property 'S.P9' cannot be marked 'readonly' because it has a 'set' accessor. + // readonly object P9 { get; set; } + Diagnostic(ErrorCode.ERR_AutoPropertyWithSetterCantBeReadOnly, "P9").WithArguments("S.P9").WithLocation(11, 21), + // (14,37): error CS1604: Cannot assign to 'field' because it is read-only + // readonly object PC { get; set { field = value; } } + Diagnostic(ErrorCode.ERR_AssgReadonlyLocal, "field").WithArguments("field").WithLocation(14, 37), + // (15,32): error CS1604: Cannot assign to 'field' because it is read-only + // readonly object PD { set { field = value; } } + Diagnostic(ErrorCode.ERR_AssgReadonlyLocal, "field").WithArguments("field").WithLocation(15, 32)); } else { @@ -1853,14 +1841,13 @@ public void ReadOnly_02(bool useReadOnlyType, bool useReadOnlyOnGet) {{typeModifier}} struct S { object P3 { {{getModifier}} get => field; {{setModifier}} set; } - object P5 { {{getModifier}} get => field; {{setModifier}} set { } } - object P8 { {{getModifier}} get => null; {{setModifier}} set; } - object PA { {{getModifier}} get => null; {{setModifier}} set { } } - object PC { {{getModifier}} get => null; {{setModifier}} set { _ = field; } } - object PE { {{getModifier}} get; {{setModifier}} set; } - object PG { {{getModifier}} get; {{setModifier}} set { } } - object PK { {{getModifier}} get { field = null; return null; } set { } } - object PL { {{getModifier}} get; {{setModifier}} set { field = value; } } + object P4 { {{getModifier}} get => field; {{setModifier}} set { } } + object P6 { {{getModifier}} get => null; {{setModifier}} set; } + object P7 { {{getModifier}} get => null; {{setModifier}} set { } } + object P8 { {{getModifier}} get => null; {{setModifier}} set { _ = field; } } + object P9 { {{getModifier}} get; {{setModifier}} set; } + object PA { {{getModifier}} get; {{setModifier}} set { } } + object PC { {{getModifier}} get; {{setModifier}} set { field = value; } } } """; var comp = CreateCompilation(source, targetFramework: TargetFramework.Net80); @@ -1873,17 +1860,14 @@ public void ReadOnly_02(bool useReadOnlyType, bool useReadOnlyOnGet) // object P3 { readonly get => field; set; } Diagnostic(ErrorCode.ERR_AutoPropsInRoStruct, "P3").WithLocation(3, 12), // (5,12): error CS8341: Auto-implemented instance properties in readonly structs must be readonly. - // object P8 { readonly get => null; set; } - Diagnostic(ErrorCode.ERR_AutoPropsInRoStruct, "P8").WithLocation(5, 12), + // object P6 { readonly get => null; set; } + Diagnostic(ErrorCode.ERR_AutoPropsInRoStruct, "P6").WithLocation(5, 12), // (8,12): error CS8341: Auto-implemented instance properties in readonly structs must be readonly. - // object PE { readonly get; set; } - Diagnostic(ErrorCode.ERR_AutoPropsInRoStruct, "PE").WithLocation(8, 12), - // (10,32): error CS1604: Cannot assign to 'field' because it is read-only - // object PK { readonly get { field = null; return null; } set { } } - Diagnostic(ErrorCode.ERR_AssgReadonlyLocal, "field").WithArguments("field").WithLocation(10, 32), - // (11,46): error CS1604: Cannot assign to 'field' because it is read-only - // object PL { readonly get; set { field = value; } } - Diagnostic(ErrorCode.ERR_AssgReadonlyLocal, "field").WithArguments("field").WithLocation(11, 46)); + // object P9 { readonly get; set; } + Diagnostic(ErrorCode.ERR_AutoPropsInRoStruct, "P9").WithLocation(8, 12), + // (10,46): error CS1604: Cannot assign to 'field' because it is read-only + // object PC { readonly get; set { field = value; } } + Diagnostic(ErrorCode.ERR_AssgReadonlyLocal, "field").WithArguments("field").WithLocation(10, 46)); } else { @@ -1895,33 +1879,27 @@ public void ReadOnly_02(bool useReadOnlyType, bool useReadOnlyOnGet) // object P3 { get => field; readonly set; } Diagnostic(ErrorCode.ERR_AutoSetterCantBeReadOnly, "set").WithArguments("S.P3.set").WithLocation(3, 49), // (5,12): error CS8341: Auto-implemented instance properties in readonly structs must be readonly. - // object P8 { get => null; readonly set; } - Diagnostic(ErrorCode.ERR_AutoPropsInRoStruct, "P8").WithLocation(5, 12), - // (5,48): error CS8658: Auto-implemented 'set' accessor 'S.P8.set' cannot be marked 'readonly'. - // object P8 { get => null; readonly set; } - Diagnostic(ErrorCode.ERR_AutoSetterCantBeReadOnly, "set").WithArguments("S.P8.set").WithLocation(5, 48), + // object P6 { get => null; readonly set; } + Diagnostic(ErrorCode.ERR_AutoPropsInRoStruct, "P6").WithLocation(5, 12), + // (5,48): error CS8658: Auto-implemented 'set' accessor 'S.P6.set' cannot be marked 'readonly'. + // object P6 { get => null; readonly set; } + Diagnostic(ErrorCode.ERR_AutoSetterCantBeReadOnly, "set").WithArguments("S.P6.set").WithLocation(5, 48), // (8,12): error CS8341: Auto-implemented instance properties in readonly structs must be readonly. - // object PE { get; readonly set; } - Diagnostic(ErrorCode.ERR_AutoPropsInRoStruct, "PE").WithLocation(8, 12), - // (8,40): error CS8658: Auto-implemented 'set' accessor 'S.PE.set' cannot be marked 'readonly'. - // object PE { get; readonly set; } - Diagnostic(ErrorCode.ERR_AutoSetterCantBeReadOnly, "set").WithArguments("S.PE.set").WithLocation(8, 40), - // (10,32): error CS1604: Cannot assign to 'field' because it is read-only - // object PK { get { field = null; return null; } set { } } - Diagnostic(ErrorCode.ERR_AssgReadonlyLocal, "field").WithArguments("field").WithLocation(10, 32), - // (11,46): error CS1604: Cannot assign to 'field' because it is read-only - // object PL { get; readonly set { field = value; } } - Diagnostic(ErrorCode.ERR_AssgReadonlyLocal, "field").WithArguments("field").WithLocation(11, 46)); + // object P9 { get; readonly set; } + Diagnostic(ErrorCode.ERR_AutoPropsInRoStruct, "P9").WithLocation(8, 12), + // (8,40): error CS8658: Auto-implemented 'set' accessor 'S.P9.set' cannot be marked 'readonly'. + // object P9 { get; readonly set; } + Diagnostic(ErrorCode.ERR_AutoSetterCantBeReadOnly, "set").WithArguments("S.P9.set").WithLocation(8, 40), + // (10,46): error CS1604: Cannot assign to 'field' because it is read-only + // object PC { get; readonly set { field = value; } } + Diagnostic(ErrorCode.ERR_AssgReadonlyLocal, "field").WithArguments("field").WithLocation(10, 46)); } } else { if (useReadOnlyOnGet) { - comp.VerifyEmitDiagnostics( - // (10,32): error CS1604: Cannot assign to 'field' because it is read-only - // object PK { readonly get { field = null; return null; } set { } } - Diagnostic(ErrorCode.ERR_AssgReadonlyLocal, "field").WithArguments("field").WithLocation(10, 32)); + comp.VerifyEmitDiagnostics(); } else { @@ -1929,15 +1907,15 @@ public void ReadOnly_02(bool useReadOnlyType, bool useReadOnlyOnGet) // (3,49): error CS8658: Auto-implemented 'set' accessor 'S.P3.set' cannot be marked 'readonly'. // object P3 { get => field; readonly set; } Diagnostic(ErrorCode.ERR_AutoSetterCantBeReadOnly, "set").WithArguments("S.P3.set").WithLocation(3, 49), - // (5,48): error CS8658: Auto-implemented 'set' accessor 'S.P8.set' cannot be marked 'readonly'. - // object P8 { get => null; readonly set; } - Diagnostic(ErrorCode.ERR_AutoSetterCantBeReadOnly, "set").WithArguments("S.P8.set").WithLocation(5, 48), - // (8,40): error CS8658: Auto-implemented 'set' accessor 'S.PE.set' cannot be marked 'readonly'. - // object PE { get; readonly set; } - Diagnostic(ErrorCode.ERR_AutoSetterCantBeReadOnly, "set").WithArguments("S.PE.set").WithLocation(8, 40), - // (11,46): error CS1604: Cannot assign to 'field' because it is read-only - // object PL { get; readonly set { field = value; } } - Diagnostic(ErrorCode.ERR_AssgReadonlyLocal, "field").WithArguments("field").WithLocation(11, 46)); + // (5,48): error CS8658: Auto-implemented 'set' accessor 'S.P6.set' cannot be marked 'readonly'. + // object P6 { get => null; readonly set; } + Diagnostic(ErrorCode.ERR_AutoSetterCantBeReadOnly, "set").WithArguments("S.P6.set").WithLocation(5, 48), + // (8,40): error CS8658: Auto-implemented 'set' accessor 'S.P9.set' cannot be marked 'readonly'. + // object P9 { get; readonly set; } + Diagnostic(ErrorCode.ERR_AutoSetterCantBeReadOnly, "set").WithArguments("S.P9.set").WithLocation(8, 40), + // (10,46): error CS1604: Cannot assign to 'field' because it is read-only + // object PC { get; readonly set { field = value; } } + Diagnostic(ErrorCode.ERR_AssgReadonlyLocal, "field").WithArguments("field").WithLocation(10, 46)); } } } @@ -1955,10 +1933,10 @@ public void ReadOnly_03(bool useReadOnlyType, bool useReadOnlyProperty) static {{propertyModifier}} object P1 { get; } static {{propertyModifier}} object P2 { get => field; } static {{propertyModifier}} object P3 { get => field; set; } - static {{propertyModifier}} object PE { get; set; } - static {{propertyModifier}} object PG { get; set { } } - static {{propertyModifier}} object PL { get; set { field = value; } } - static {{propertyModifier}} object PN { set { field = value; } } + static {{propertyModifier}} object P9 { get; set; } + static {{propertyModifier}} object PA { get; set { } } + static {{propertyModifier}} object PC { get; set { field = value; } } + static {{propertyModifier}} object PD { set { field = value; } } } """; var comp = CreateCompilation(source, targetFramework: TargetFramework.Net80); @@ -1974,18 +1952,18 @@ public void ReadOnly_03(bool useReadOnlyType, bool useReadOnlyProperty) // (5,28): error CS8657: Static member 'S.P3' cannot be marked 'readonly'. // static readonly object P3 { get => field; set; } Diagnostic(ErrorCode.ERR_StaticMemberCantBeReadOnly, "P3").WithArguments("S.P3").WithLocation(5, 28), - // (6,28): error CS8657: Static member 'S.PE' cannot be marked 'readonly'. - // static readonly object PE { get; set; } - Diagnostic(ErrorCode.ERR_StaticMemberCantBeReadOnly, "PE").WithArguments("S.PE").WithLocation(6, 28), - // (7,28): error CS8657: Static member 'S.PG' cannot be marked 'readonly'. - // static readonly object PG { get; set { } } - Diagnostic(ErrorCode.ERR_StaticMemberCantBeReadOnly, "PG").WithArguments("S.PG").WithLocation(7, 28), - // (8,28): error CS8657: Static member 'S.PL' cannot be marked 'readonly'. - // static readonly object PL { get; set { field = value; } } - Diagnostic(ErrorCode.ERR_StaticMemberCantBeReadOnly, "PL").WithArguments("S.PL").WithLocation(8, 28), - // (9,28): error CS8657: Static member 'S.PN' cannot be marked 'readonly'. - // static readonly object PN { set { field = value; } } - Diagnostic(ErrorCode.ERR_StaticMemberCantBeReadOnly, "PN").WithArguments("S.PN").WithLocation(9, 28)); + // (6,28): error CS8657: Static member 'S.P9' cannot be marked 'readonly'. + // static readonly object P9 { get; set; } + Diagnostic(ErrorCode.ERR_StaticMemberCantBeReadOnly, "P9").WithArguments("S.P9").WithLocation(6, 28), + // (7,28): error CS8657: Static member 'S.PA' cannot be marked 'readonly'. + // static readonly object PA { get; set { } } + Diagnostic(ErrorCode.ERR_StaticMemberCantBeReadOnly, "PA").WithArguments("S.PA").WithLocation(7, 28), + // (8,28): error CS8657: Static member 'S.PC' cannot be marked 'readonly'. + // static readonly object PC { get; set { field = value; } } + Diagnostic(ErrorCode.ERR_StaticMemberCantBeReadOnly, "PC").WithArguments("S.PC").WithLocation(8, 28), + // (9,28): error CS8657: Static member 'S.PD' cannot be marked 'readonly'. + // static readonly object PD { set { field = value; } } + Diagnostic(ErrorCode.ERR_StaticMemberCantBeReadOnly, "PD").WithArguments("S.PD").WithLocation(9, 28)); } else { @@ -2005,8 +1983,8 @@ public void ReadOnly_04(bool useReadOnlyType, bool useReadOnlyOnGet) {{typeModifier}} struct S { static object P3 { {{getModifier}} get => field; {{setModifier}} set; } - static object PE { {{getModifier}} get; {{setModifier}} set; } - static object PL { {{getModifier}} get; {{setModifier}} set { field = value; } } + static object P9 { {{getModifier}} get; {{setModifier}} set; } + static object PD { {{getModifier}} get; {{setModifier}} set { field = value; } } } """; var comp = CreateCompilation(source, targetFramework: TargetFramework.Net80); @@ -2016,12 +1994,12 @@ public void ReadOnly_04(bool useReadOnlyType, bool useReadOnlyOnGet) // (3,33): error CS8657: Static member 'S.P3.get' cannot be marked 'readonly'. // static object P3 { readonly get => field; set; } Diagnostic(ErrorCode.ERR_StaticMemberCantBeReadOnly, "get").WithArguments("S.P3.get").WithLocation(3, 33), - // (4,33): error CS8657: Static member 'S.PE.get' cannot be marked 'readonly'. - // static object PE { readonly get; set; } - Diagnostic(ErrorCode.ERR_StaticMemberCantBeReadOnly, "get").WithArguments("S.PE.get").WithLocation(4, 33), - // (5,33): error CS8657: Static member 'S.PL.get' cannot be marked 'readonly'. - // static object PL { readonly get; set { field = value; } } - Diagnostic(ErrorCode.ERR_StaticMemberCantBeReadOnly, "get").WithArguments("S.PL.get").WithLocation(5, 33)); + // (4,33): error CS8657: Static member 'S.P9.get' cannot be marked 'readonly'. + // static object P9 { readonly get; set; } + Diagnostic(ErrorCode.ERR_StaticMemberCantBeReadOnly, "get").WithArguments("S.P9.get").WithLocation(4, 33), + // (5,33): error CS8657: Static member 'S.PD.get' cannot be marked 'readonly'. + // static object PD { readonly get; set { field = value; } } + Diagnostic(ErrorCode.ERR_StaticMemberCantBeReadOnly, "get").WithArguments("S.PD.get").WithLocation(5, 33)); } else { @@ -2029,15 +2007,69 @@ public void ReadOnly_04(bool useReadOnlyType, bool useReadOnlyOnGet) // (3,56): error CS8657: Static member 'S.P3.set' cannot be marked 'readonly'. // static object P3 { get => field; readonly set; } Diagnostic(ErrorCode.ERR_StaticMemberCantBeReadOnly, "set").WithArguments("S.P3.set").WithLocation(3, 56), - // (4,47): error CS8657: Static member 'S.PE.set' cannot be marked 'readonly'. - // static object PE { get; readonly set; } - Diagnostic(ErrorCode.ERR_StaticMemberCantBeReadOnly, "set").WithArguments("S.PE.set").WithLocation(4, 47), - // (5,47): error CS8657: Static member 'S.PL.set' cannot be marked 'readonly'. - // static object PL { get; readonly set { field = value; } } - Diagnostic(ErrorCode.ERR_StaticMemberCantBeReadOnly, "set").WithArguments("S.PL.set").WithLocation(5, 47)); + // (4,47): error CS8657: Static member 'S.P9.set' cannot be marked 'readonly'. + // static object P9 { get; readonly set; } + Diagnostic(ErrorCode.ERR_StaticMemberCantBeReadOnly, "set").WithArguments("S.P9.set").WithLocation(4, 47), + // (5,47): error CS8657: Static member 'S.PD.set' cannot be marked 'readonly'. + // static object PD { get; readonly set { field = value; } } + Diagnostic(ErrorCode.ERR_StaticMemberCantBeReadOnly, "set").WithArguments("S.PD.set").WithLocation(5, 47)); } } + [Fact] + public void ReadOnly_05() + { + string source = """ + struct S0 + { + object P0 { get { field = null; return null; } } + } + struct S1 + { + object P1 { readonly get { field = null; return null; } } + } + struct S2 + { + readonly object P2 { get { field = null; return null; } } + } + readonly struct S3 + { + object P3 { get { field = null; return null; } } + } + readonly struct S4 + { + object P4 { readonly get { field = null; return null; } } + } + readonly struct S5 + { + readonly object P5 { get { field = null; return null; } } + } + """; + var comp = CreateCompilation(source); + comp.VerifyEmitDiagnostics( + // (7,12): error CS8664: 'S1.P1': 'readonly' can only be used on accessors if the property or indexer has both a get and a set accessor + // object P1 { readonly get { field = null; return null; } } + Diagnostic(ErrorCode.ERR_ReadOnlyModMissingAccessor, "P1").WithArguments("S1.P1").WithLocation(7, 12), + // (7,32): error CS1604: Cannot assign to 'field' because it is read-only + // object P1 { readonly get { field = null; return null; } } + Diagnostic(ErrorCode.ERR_AssgReadonlyLocal, "field").WithArguments("field").WithLocation(7, 32), + // (11,32): error CS1604: Cannot assign to 'field' because it is read-only + // readonly object P2 { get { field = null; return null; } } + Diagnostic(ErrorCode.ERR_AssgReadonlyLocal, "field").WithArguments("field").WithLocation(11, 32), + // (15,23): error CS1604: Cannot assign to 'field' because it is read-only + // object P3 { get { field = null; return null; } } + Diagnostic(ErrorCode.ERR_AssgReadonlyLocal, "field").WithArguments("field").WithLocation(15, 23), + // (19,12): error CS8664: 'S4.P4': 'readonly' can only be used on accessors if the property or indexer has both a get and a set accessor + // object P4 { readonly get { field = null; return null; } } + Diagnostic(ErrorCode.ERR_ReadOnlyModMissingAccessor, "P4").WithArguments("S4.P4").WithLocation(19, 12), + // (19,32): error CS1604: Cannot assign to 'field' because it is read-only + // object P4 { readonly get { field = null; return null; } } + Diagnostic(ErrorCode.ERR_AssgReadonlyLocal, "field").WithArguments("field").WithLocation(19, 32), + // (23,32): error CS1604: Cannot assign to 'field' because it is read-only + // readonly object P5 { get { field = null; return null; } } + Diagnostic(ErrorCode.ERR_AssgReadonlyLocal, "field").WithArguments("field").WithLocation(23, 32)); + } + [Theory] [CombinatorialData] public void RefReturning_01(bool useStruct, bool useRefReadOnly) From 7720d0d79a7d4ead5d37749183b558c1c42a9d3d Mon Sep 17 00:00:00 2001 From: Charles Stoner <10732005+cston@users.noreply.github.com> Date: Fri, 23 Aug 2024 17:31:08 -0700 Subject: [PATCH 19/21] Update src/Compilers/CSharp/Portable/CSharpResources.resx Co-authored-by: Fred Silberberg --- src/Compilers/CSharp/Portable/CSharpResources.resx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Compilers/CSharp/Portable/CSharpResources.resx b/src/Compilers/CSharp/Portable/CSharpResources.resx index 761f0ca5fd20b..d85e31bbcd749 100644 --- a/src/Compilers/CSharp/Portable/CSharpResources.resx +++ b/src/Compilers/CSharp/Portable/CSharpResources.resx @@ -4891,7 +4891,7 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ Expected identifier or numeric literal - Only a property with a backing field and no setter, or a property with an auto-implemented setter, can have an initializer. + Only auto-implemented properties, or properties that use the 'field' keyword, can have initializers. Instance properties in interfaces cannot have initializers. From 5cda54765ae0bba0b95de0c181929595fcb4c730 Mon Sep 17 00:00:00 2001 From: Charles Stoner <10732005+cston@users.noreply.github.com> Date: Fri, 23 Aug 2024 17:49:16 -0700 Subject: [PATCH 20/21] Update messages --- .../Portable/xlf/CSharpResources.cs.xlf | 2 +- .../Portable/xlf/CSharpResources.de.xlf | 2 +- .../Portable/xlf/CSharpResources.es.xlf | 2 +- .../Portable/xlf/CSharpResources.fr.xlf | 2 +- .../Portable/xlf/CSharpResources.it.xlf | 2 +- .../Portable/xlf/CSharpResources.ja.xlf | 2 +- .../Portable/xlf/CSharpResources.ko.xlf | 2 +- .../Portable/xlf/CSharpResources.pl.xlf | 2 +- .../Portable/xlf/CSharpResources.pt-BR.xlf | 2 +- .../Portable/xlf/CSharpResources.ru.xlf | 2 +- .../Portable/xlf/CSharpResources.tr.xlf | 2 +- .../Portable/xlf/CSharpResources.zh-Hans.xlf | 2 +- .../Portable/xlf/CSharpResources.zh-Hant.xlf | 2 +- .../CSharp/Test/Emit3/FieldKeywordTests.cs | 10 ++++---- .../Semantic/Semantics/RecordStructTests.cs | 4 ++-- .../Test/Semantic/Semantics/StructsTests.cs | 4 ++-- .../UninitializedNonNullableFieldTests.cs | 2 +- .../DefaultInterfaceImplementationTests.cs | 12 +++++----- .../Symbol/Symbols/PartialPropertiesTests.cs | 24 +++++++++---------- .../Test/Symbol/Symbols/SymbolErrorTests.cs | 6 ++--- 20 files changed, 44 insertions(+), 44 deletions(-) diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf index c07a8e382ea60..3e3c96569ce32 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf @@ -12160,7 +12160,7 @@ Pokud chcete odstranit toto varování, můžete místo toho použít /reference - Only a property with a backing field and no setter, or a property with an auto-implemented setter, can have an initializer. + Only auto-implemented properties, or properties that use the 'field' keyword, can have initializers. Jenom automaticky implementované vlastnosti můžou mít inicializátory. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf index 88be54a823cd3..e0c3e7f6cdf2f 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf @@ -12160,7 +12160,7 @@ Um die Warnung zu beheben, können Sie stattdessen /reference verwenden (Einbett - Only a property with a backing field and no setter, or a property with an auto-implemented setter, can have an initializer. + Only auto-implemented properties, or properties that use the 'field' keyword, can have initializers. Nur automatisch implementierte Eigenschaften können Initialisierer aufweisen. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf index d000a4f306f39..d14b5b75cece9 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf @@ -12160,7 +12160,7 @@ Para eliminar la advertencia puede usar /reference (establezca la propiedad Embe - Only a property with a backing field and no setter, or a property with an auto-implemented setter, can have an initializer. + Only auto-implemented properties, or properties that use the 'field' keyword, can have initializers. Solo las propiedades implementadas automáticamente pueden tener inicializadores. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf index 27b710cdf4cf4..2979a2f6128f6 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf @@ -12160,7 +12160,7 @@ Pour supprimer l'avertissement, vous pouvez utiliser la commande /reference (dé - Only a property with a backing field and no setter, or a property with an auto-implemented setter, can have an initializer. + Only auto-implemented properties, or properties that use the 'field' keyword, can have initializers. Seules les propriétés implémentées automatiquement peuvent avoir des initialiseurs. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf index 0da1482c09496..81fe93c7f4b76 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf @@ -12160,7 +12160,7 @@ Per rimuovere l'avviso, è invece possibile usare /reference (impostare la propr - Only a property with a backing field and no setter, or a property with an auto-implemented setter, can have an initializer. + Only auto-implemented properties, or properties that use the 'field' keyword, can have initializers. Solo le proprietà implementate automaticamente possono avere inizializzatori. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf index 518f3530203ac..056d3ac1f3559 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf @@ -12160,7 +12160,7 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ - Only a property with a backing field and no setter, or a property with an auto-implemented setter, can have an initializer. + Only auto-implemented properties, or properties that use the 'field' keyword, can have initializers. 自動実装プロパティのみが初期化子を持つことができます。 diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf index 689c71b0af84d..709344ded6891 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf @@ -12160,7 +12160,7 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ - Only a property with a backing field and no setter, or a property with an auto-implemented setter, can have an initializer. + Only auto-implemented properties, or properties that use the 'field' keyword, can have initializers. 자동 구현 속성만 이니셜라이저를 사용할 수 있습니다. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf index fe8cc96762ce2..0daffc73f4fd7 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf @@ -12160,7 +12160,7 @@ Aby usunąć ostrzeżenie, możesz zamiast tego użyć opcji /reference (ustaw w - Only a property with a backing field and no setter, or a property with an auto-implemented setter, can have an initializer. + Only auto-implemented properties, or properties that use the 'field' keyword, can have initializers. Tylko właściwości zaimplementowane automatycznie mogą mieć inicjatory. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf index 267ff0377e12a..41e99905d18d0 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf @@ -12160,7 +12160,7 @@ Para incorporar informações de tipo de interoperabilidade para os dois assembl - Only a property with a backing field and no setter, or a property with an auto-implemented setter, can have an initializer. + Only auto-implemented properties, or properties that use the 'field' keyword, can have initializers. Somente propriedades implementadas automaticamente podem ter inicializadores. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf index aebf6340f76f7..03bcaab1d8307 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf @@ -12161,7 +12161,7 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ - Only a property with a backing field and no setter, or a property with an auto-implemented setter, can have an initializer. + Only auto-implemented properties, or properties that use the 'field' keyword, can have initializers. Инициализаторы могут иметь только автоматически реализованные свойства. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf index 675a1a6296a5d..baadb43153104 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf @@ -12160,7 +12160,7 @@ Uyarıyı kaldırmak için, /reference kullanabilirsiniz (Birlikte Çalışma T - Only a property with a backing field and no setter, or a property with an auto-implemented setter, can have an initializer. + Only auto-implemented properties, or properties that use the 'field' keyword, can have initializers. Yalnızca otomatik uygulanan özelliklerin başlatıcıları olabilir. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf index baf91a5af6c8a..2423d50dbab33 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf @@ -12160,7 +12160,7 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ - Only a property with a backing field and no setter, or a property with an auto-implemented setter, can have an initializer. + Only auto-implemented properties, or properties that use the 'field' keyword, can have initializers. 只有自动实现的属性才能具有初始值设定项。 diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf index dce9041293762..b8e18bf92daa3 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf @@ -12160,7 +12160,7 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ - Only a property with a backing field and no setter, or a property with an auto-implemented setter, can have an initializer. + Only auto-implemented properties, or properties that use the 'field' keyword, can have initializers. 只有自動實作的屬性可以有初始設定式。 diff --git a/src/Compilers/CSharp/Test/Emit3/FieldKeywordTests.cs b/src/Compilers/CSharp/Test/Emit3/FieldKeywordTests.cs index 475df6d461011..14918df86b0ef 100644 --- a/src/Compilers/CSharp/Test/Emit3/FieldKeywordTests.cs +++ b/src/Compilers/CSharp/Test/Emit3/FieldKeywordTests.cs @@ -301,7 +301,7 @@ class C """; var comp = CreateCompilation(source); comp.VerifyEmitDiagnostics( - // (3,12): error CS8050: Only a property with a backing field and no setter, or a property with an auto-implemented setter, can have an initializer. + // (3,12): error CS8050: Only auto-implemented properties, or properties that use the 'field' keyword, can have initializers. // object P { set { } } = field; Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "P").WithLocation(3, 12), // (3,28): error CS0103: The name 'field' does not exist in the current context @@ -1401,10 +1401,10 @@ class C """; var comp = CreateCompilation(source, targetFramework: TargetFramework.Net80); comp.VerifyEmitDiagnostics( - // (3,23): error CS8050: Only a property with a backing field and no setter, or a property with an auto-implemented setter, can have an initializer. + // (3,23): error CS8050: Only auto-implemented properties, or properties that use the 'field' keyword, can have initializers. // public static int PA { get => 0; } = 10; Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "PA").WithLocation(3, 23), - // (4,23): error CS8050: Only a property with a backing field and no setter, or a property with an auto-implemented setter, can have an initializer. + // (4,23): error CS8050: Only auto-implemented properties, or properties that use the 'field' keyword, can have initializers. // public static int PB { get => 0; set { } } = 11; Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "PB").WithLocation(4, 23)); } @@ -1423,10 +1423,10 @@ class C """; var comp = CreateCompilation(source, targetFramework: TargetFramework.Net80); comp.VerifyEmitDiagnostics( - // (3,16): error CS8050: Only a property with a backing field and no setter, or a property with an auto-implemented setter, can have an initializer. + // (3,16): error CS8050: Only auto-implemented properties, or properties that use the 'field' keyword, can have initializers. // public int PA { get => 0; } = 10; Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "PA").WithLocation(3, 16), - // (4,16): error CS8050: Only a property with a backing field and no setter, or a property with an auto-implemented setter, can have an initializer. + // (4,16): error CS8050: Only auto-implemented properties, or properties that use the 'field' keyword, can have initializers. // public int PB { get => 0; set { } } = 11; Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "PB").WithLocation(4, 16)); } diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/RecordStructTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/RecordStructTests.cs index 5063dcc1e67ba..3b21e8954a2a3 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/RecordStructTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/RecordStructTests.cs @@ -3997,14 +3997,14 @@ record struct Pos2(int X) // (2,15): error CS0171: Field 'Pos.x' must be fully assigned before control is returned to the caller. Consider updating to language version '11.0' to auto-default the field. // record struct Pos(int X) Diagnostic(ErrorCode.ERR_UnassignedThisUnsupportedVersion, "Pos").WithArguments("Pos.x", "11.0").WithLocation(2, 15), - // (5,16): error CS8050: Only a property with a backing field and no setter, or a property with an auto-implemented setter, can have an initializer. + // (5,16): error CS8050: Only auto-implemented properties, or properties that use the 'field' keyword, can have initializers. // public int X { get { return x; } set { x = value; } } = X; Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "X").WithLocation(5, 16) ); comp = CreateCompilation(source, parseOptions: TestOptions.Regular11); comp.VerifyEmitDiagnostics( - // (5,16): error CS8050: Only a property with a backing field and no setter, or a property with an auto-implemented setter, can have an initializer. + // (5,16): error CS8050: Only auto-implemented properties, or properties that use the 'field' keyword, can have initializers. // public int X { get { return x; } set { x = value; } } = X; Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "X").WithLocation(5, 16) ); diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/StructsTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/StructsTests.cs index 43173c6e71414..03316ddba7223 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/StructsTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/StructsTests.cs @@ -673,7 +673,7 @@ public void StructNonAutoPropertyInitializer() // (3,16): error CS8773: Feature 'struct field initializers' is not available in C# 9.0. Please use language version 10.0 or greater. // public int I { get { throw null; } set {} } = 9; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion9, "I").WithArguments("struct field initializers", "10.0").WithLocation(3, 16), - // (3,16): error CS8050: Only a property with a backing field and no setter, or a property with an auto-implemented setter, can have an initializer. + // (3,16): error CS8050: Only auto-implemented properties, or properties that use the 'field' keyword, can have initializers. // public int I { get { throw null; } set {} } = 9; Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "I").WithLocation(3, 16)); @@ -682,7 +682,7 @@ public void StructNonAutoPropertyInitializer() // (1,8): error CS8983: A 'struct' with field initializers must include an explicitly declared constructor. // struct S Diagnostic(ErrorCode.ERR_StructHasInitializersAndNoDeclaredConstructor, "S").WithLocation(1, 8), - // (3,16): error CS8050: Only a property with a backing field and no setter, or a property with an auto-implemented setter, can have an initializer. + // (3,16): error CS8050: Only auto-implemented properties, or properties that use the 'field' keyword, can have initializers. // public int I { get { throw null; } set {} } = 9; Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "I").WithLocation(3, 16)); } diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/UninitializedNonNullableFieldTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/UninitializedNonNullableFieldTests.cs index 478fd2e1fc56f..22c58d94fdcf9 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/UninitializedNonNullableFieldTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/UninitializedNonNullableFieldTests.cs @@ -2631,7 +2631,7 @@ public C() // (5,19): error CS0548: 'C.P': property or indexer must have at least one accessor // public string P { } Diagnostic(ErrorCode.ERR_PropertyWithNoAccessors, "P").WithArguments("C.P").WithLocation(5, 19), - // (7,19): error CS8050: Only a property with a backing field and no setter, or a property with an auto-implemented setter, can have an initializer. + // (7,19): error CS8050: Only auto-implemented properties, or properties that use the 'field' keyword, can have initializers. // public string P3 { } = string.Empty; Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "P3").WithLocation(7, 19), // (7,19): error CS0548: 'C.P3': property or indexer must have at least one accessor diff --git a/src/Compilers/CSharp/Test/Symbol/Symbols/DefaultInterfaceImplementationTests.cs b/src/Compilers/CSharp/Test/Symbol/Symbols/DefaultInterfaceImplementationTests.cs index 455ecabf97a04..bbfac8d1ce82d 100644 --- a/src/Compilers/CSharp/Test/Symbol/Symbols/DefaultInterfaceImplementationTests.cs +++ b/src/Compilers/CSharp/Test/Symbol/Symbols/DefaultInterfaceImplementationTests.cs @@ -3217,7 +3217,7 @@ public interface I1 // (4,34): error CS1014: A get or set accessor expected // static abstract int P1 {add; remove;} = 0; Diagnostic(ErrorCode.ERR_GetOrSetExpected, "remove").WithLocation(4, 34), - // (4,25): error CS8050: Only a property with a backing field and no setter, or a property with an auto-implemented setter, can have an initializer. + // (4,25): error CS8050: Only auto-implemented properties, or properties that use the 'field' keyword, can have initializers. // static abstract int P1 {add; remove;} = 0; Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "P1").WithLocation(4, 25), // (4,25): error CS0548: 'I1.P1': property or indexer must have at least one accessor @@ -3251,7 +3251,7 @@ public interface I1 // (4,33): error CS1014: A get or set accessor expected // static virtual int P1 {add; remove;} = 0; Diagnostic(ErrorCode.ERR_GetOrSetExpected, "remove").WithLocation(4, 33), - // (4,24): error CS8050: Only a property with a backing field and no setter, or a property with an auto-implemented setter, can have an initializer. + // (4,24): error CS8050: Only auto-implemented properties, or properties that use the 'field' keyword, can have initializers. // static virtual int P1 {add; remove;} = 0; Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "P1").WithLocation(4, 24), // (4,24): error CS0548: 'I1.P1': property or indexer must have at least one accessor @@ -3309,7 +3309,7 @@ public interface I1 targetFramework: TargetFramework.Net60); Assert.True(compilation1.Assembly.RuntimeSupportsDefaultInterfaceImplementation); compilation1.VerifyEmitDiagnostics( - // (4,25): error CS8050: Only a property with a backing field and no setter, or a property with an auto-implemented setter, can have an initializer. + // (4,25): error CS8050: Only auto-implemented properties, or properties that use the 'field' keyword, can have initializers. // static abstract int P1 {get; set;} = 0; Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "P1").WithLocation(4, 25) ); @@ -56844,7 +56844,7 @@ class Test1 : I2 } "; ValidatePropertyReAbstraction_014(source1, isStatic: true, - // (9,28): error CS8050: Only a property with a backing field and no setter, or a property with an auto-implemented setter, can have an initializer. + // (9,28): error CS8050: Only auto-implemented properties, or properties that use the 'field' keyword, can have initializers. // static abstract int I1.P1 { get; set; } = 0; Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "P1").WithLocation(9, 28), // (12,15): error CS0535: 'Test1' does not implement interface member 'I1.P1' @@ -56902,7 +56902,7 @@ class Test1 : I2 } "; ValidatePropertyReAbstraction_014(source1, isStatic: true, - // (9,28): error CS8050: Only a property with a backing field and no setter, or a property with an auto-implemented setter, can have an initializer. + // (9,28): error CS8050: Only auto-implemented properties, or properties that use the 'field' keyword, can have initializers. // static abstract int I1.P1 { get; } = 0; Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "P1").WithLocation(9, 28), // (12,15): error CS0535: 'Test1' does not implement interface member 'I1.P1' @@ -56960,7 +56960,7 @@ class Test1 : I2 } "; ValidatePropertyReAbstraction_014(source1, isStatic: true, - // (9,28): error CS8050: Only a property with a backing field and no setter, or a property with an auto-implemented setter, can have an initializer. + // (9,28): error CS8050: Only auto-implemented properties, or properties that use the 'field' keyword, can have initializers. // static abstract int I1.P1 { set; } = 0; Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "P1").WithLocation(9, 28), // (12,15): error CS0535: 'Test1' does not implement interface member 'I1.P1' diff --git a/src/Compilers/CSharp/Test/Symbol/Symbols/PartialPropertiesTests.cs b/src/Compilers/CSharp/Test/Symbol/Symbols/PartialPropertiesTests.cs index 18489bdd38a71..9788d119e5e99 100644 --- a/src/Compilers/CSharp/Test/Symbol/Symbols/PartialPropertiesTests.cs +++ b/src/Compilers/CSharp/Test/Symbol/Symbols/PartialPropertiesTests.cs @@ -3771,16 +3771,16 @@ partial class C var comp = CreateCompilation(source); comp.VerifyEmitDiagnostics( - // (3,27): error CS8050: Only a property with a backing field and no setter, or a property with an auto-implemented setter, can have an initializer. + // (3,27): error CS8050: Only auto-implemented properties, or properties that use the 'field' keyword, can have initializers. // public partial string P1 { get; set; } = "a"; Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "P1").WithLocation(3, 27), - // (7,27): error CS8050: Only a property with a backing field and no setter, or a property with an auto-implemented setter, can have an initializer. + // (7,27): error CS8050: Only auto-implemented properties, or properties that use the 'field' keyword, can have initializers. // public partial string P2 { get => ""; set { } } = "b"; Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "P2").WithLocation(7, 27), - // (9,27): error CS8050: Only a property with a backing field and no setter, or a property with an auto-implemented setter, can have an initializer. + // (9,27): error CS8050: Only auto-implemented properties, or properties that use the 'field' keyword, can have initializers. // public partial string P3 { get; set; } = "c"; Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "P3").WithLocation(9, 27), - // (10,27): error CS8050: Only a property with a backing field and no setter, or a property with an auto-implemented setter, can have an initializer. + // (10,27): error CS8050: Only auto-implemented properties, or properties that use the 'field' keyword, can have initializers. // public partial string P3 { get => ""; set { } } = "d"; Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "P3").WithLocation(10, 27)); } @@ -3804,25 +3804,25 @@ partial class C var comp = CreateCompilation(source); comp.VerifyEmitDiagnostics( - // (3,27): error CS8050: Only a property with a backing field and no setter, or a property with an auto-implemented setter, can have an initializer. + // (3,27): error CS8050: Only auto-implemented properties, or properties that use the 'field' keyword, can have initializers. // public partial string P1 { get; set; } = ERROR; Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "P1").WithLocation(3, 27), // (3,46): error CS0103: The name 'ERROR' does not exist in the current context // public partial string P1 { get; set; } = ERROR; Diagnostic(ErrorCode.ERR_NameNotInContext, "ERROR").WithArguments("ERROR").WithLocation(3, 46), - // (7,27): error CS8050: Only a property with a backing field and no setter, or a property with an auto-implemented setter, can have an initializer. + // (7,27): error CS8050: Only auto-implemented properties, or properties that use the 'field' keyword, can have initializers. // public partial string P2 { get => ""; set { } } = ERROR; Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "P2").WithLocation(7, 27), // (7,55): error CS0103: The name 'ERROR' does not exist in the current context // public partial string P2 { get => ""; set { } } = ERROR; Diagnostic(ErrorCode.ERR_NameNotInContext, "ERROR").WithArguments("ERROR").WithLocation(7, 55), - // (9,27): error CS8050: Only a property with a backing field and no setter, or a property with an auto-implemented setter, can have an initializer. + // (9,27): error CS8050: Only auto-implemented properties, or properties that use the 'field' keyword, can have initializers. // public partial string P3 { get; set; } = ERROR; Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "P3").WithLocation(9, 27), // (9,46): error CS0103: The name 'ERROR' does not exist in the current context // public partial string P3 { get; set; } = ERROR; Diagnostic(ErrorCode.ERR_NameNotInContext, "ERROR").WithArguments("ERROR").WithLocation(9, 46), - // (10,27): error CS8050: Only a property with a backing field and no setter, or a property with an auto-implemented setter, can have an initializer. + // (10,27): error CS8050: Only auto-implemented properties, or properties that use the 'field' keyword, can have initializers. // public partial string P3 { get => ""; set { } } = ERROR; Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "P3").WithLocation(10, 27), // (10,55): error CS0103: The name 'ERROR' does not exist in the current context @@ -3862,7 +3862,7 @@ partial class C // (6,6): warning CS0657: 'field' is not a valid attribute location for this declaration. Valid attribute locations for this declaration are 'property'. All attributes in this block will be ignored. // [field: Attr1] Diagnostic(ErrorCode.WRN_AttributeLocationOnBadDeclaration, "field").WithArguments("field", "property").WithLocation(6, 6), - // (7,27): error CS8050: Only a property with a backing field and no setter, or a property with an auto-implemented setter, can have an initializer. + // (7,27): error CS8050: Only auto-implemented properties, or properties that use the 'field' keyword, can have initializers. // public partial string P1 { get; set; } = "a"; Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "P1").WithLocation(7, 27), // (8,6): warning CS0657: 'field' is not a valid attribute location for this declaration. Valid attribute locations for this declaration are 'property'. All attributes in this block will be ignored. @@ -3874,19 +3874,19 @@ partial class C // (13,6): warning CS0657: 'field' is not a valid attribute location for this declaration. Valid attribute locations for this declaration are 'property'. All attributes in this block will be ignored. // [field: Attr2] Diagnostic(ErrorCode.WRN_AttributeLocationOnBadDeclaration, "field").WithArguments("field", "property").WithLocation(13, 6), - // (14,27): error CS8050: Only a property with a backing field and no setter, or a property with an auto-implemented setter, can have an initializer. + // (14,27): error CS8050: Only auto-implemented properties, or properties that use the 'field' keyword, can have initializers. // public partial string P2 { get => ""; set { } } = "b"; Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "P2").WithLocation(14, 27), // (16,6): warning CS0657: 'field' is not a valid attribute location for this declaration. Valid attribute locations for this declaration are 'property'. All attributes in this block will be ignored. // [field: Attr1] Diagnostic(ErrorCode.WRN_AttributeLocationOnBadDeclaration, "field").WithArguments("field", "property").WithLocation(16, 6), - // (17,27): error CS8050: Only a property with a backing field and no setter, or a property with an auto-implemented setter, can have an initializer. + // (17,27): error CS8050: Only auto-implemented properties, or properties that use the 'field' keyword, can have initializers. // public partial string P3 { get; set; } = "c"; Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "P3").WithLocation(17, 27), // (18,6): warning CS0657: 'field' is not a valid attribute location for this declaration. Valid attribute locations for this declaration are 'property'. All attributes in this block will be ignored. // [field: Attr2] Diagnostic(ErrorCode.WRN_AttributeLocationOnBadDeclaration, "field").WithArguments("field", "property").WithLocation(18, 6), - // (19,27): error CS8050: Only a property with a backing field and no setter, or a property with an auto-implemented setter, can have an initializer. + // (19,27): error CS8050: Only auto-implemented properties, or properties that use the 'field' keyword, can have initializers. // public partial string P3 { get => ""; set { } } = "d"; Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "P3").WithLocation(19, 27)); diff --git a/src/Compilers/CSharp/Test/Symbol/Symbols/SymbolErrorTests.cs b/src/Compilers/CSharp/Test/Symbol/Symbols/SymbolErrorTests.cs index 056577bc6c36f..d0b0be43ca294 100644 --- a/src/Compilers/CSharp/Test/Symbol/Symbols/SymbolErrorTests.cs +++ b/src/Compilers/CSharp/Test/Symbol/Symbols/SymbolErrorTests.cs @@ -16859,13 +16859,13 @@ public void CS8050ERR_InitializerOnNonAutoProperty() protected int P { get { throw null; } set { } } = 1; }"; CreateCompilation(source).VerifyDiagnostics( - // (5,9): error CS8050: Only a property with a backing field and no setter, or a property with an auto-implemented setter, can have an initializer. + // (5,9): error CS8050: Only auto-implemented properties, or properties that use the 'field' keyword, can have initializers. // int I { get { throw null; } set { } } = 1; Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "I").WithLocation(5, 9), - // (6,16): error CS8050: Only a property with a backing field and no setter, or a property with an auto-implemented setter, can have an initializer. + // (6,16): error CS8050: Only auto-implemented properties, or properties that use the 'field' keyword, can have initializers. // static int S { get { throw null; } set { } } = 1; Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "S").WithLocation(6, 16), - // (7,19): error CS8050: Only a property with a backing field and no setter, or a property with an auto-implemented setter, can have an initializer. + // (7,19): error CS8050: Only auto-implemented properties, or properties that use the 'field' keyword, can have initializers. // protected int P { get { throw null; } set { } } = 1; Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "P").WithLocation(7, 19) ); From d03acb2114bcca21748d5dddee4fe193cf857195 Mon Sep 17 00:00:00 2001 From: Charles Stoner <10732005+cston@users.noreply.github.com> Date: Sun, 25 Aug 2024 13:14:58 -0700 Subject: [PATCH 21/21] Default initialization tests --- .../Portable/Binder/Binder.ValueChecks.cs | 2 +- .../Portable/Binder/Binder_Statements.cs | 5 +- .../CSharp/Test/Emit3/FieldKeywordTests.cs | 508 +++++++++++++++++- 3 files changed, 492 insertions(+), 23 deletions(-) diff --git a/src/Compilers/CSharp/Portable/Binder/Binder.ValueChecks.cs b/src/Compilers/CSharp/Portable/Binder/Binder.ValueChecks.cs index a23da4551f2f3..f550f1c8f3f2f 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder.ValueChecks.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder.ValueChecks.cs @@ -1694,7 +1694,7 @@ private bool CheckPropertyValueKind(SyntaxNode node, BoundExpression expr, BindV if (setMethod is null) { var containing = this.ContainingMemberOrLambda; - if (!AccessingAutoPropertyFromConstructor(receiver, propertySymbol, containing) + if (!AccessingAutoPropertyFromConstructor(receiver, propertySymbol, containing, allowFieldKeyword: true) && !isAllowedDespiteReadonly(receiver)) { Error(diagnostics, ErrorCode.ERR_AssgReadonlyProp, node, propertySymbol); diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Statements.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Statements.cs index 64e79b538710c..65ec316dad808 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder_Statements.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder_Statements.cs @@ -1754,7 +1754,8 @@ internal static bool AccessingAutoPropertyFromConstructor(BoundPropertyAccess pr return AccessingAutoPropertyFromConstructor(propertyAccess.ReceiverOpt, propertyAccess.PropertySymbol, fromMember); } - private static bool AccessingAutoPropertyFromConstructor(BoundExpression receiver, PropertySymbol propertySymbol, Symbol fromMember) + // PROTOTYPE: Review all callers for allowFieldKeyword. + private static bool AccessingAutoPropertyFromConstructor(BoundExpression receiver, PropertySymbol propertySymbol, Symbol fromMember, bool allowFieldKeyword = false) { if (!propertySymbol.IsDefinition && propertySymbol.ContainingType.Equals(propertySymbol.ContainingType.OriginalDefinition, TypeCompareKind.IgnoreNullableModifiersForReferenceTypes)) { @@ -1765,7 +1766,7 @@ private static bool AccessingAutoPropertyFromConstructor(BoundExpression receive var propertyIsStatic = propertySymbol.IsStatic; return (object)sourceProperty != null && - sourceProperty.IsAutoPropertyOrUsesFieldKeyword && + (allowFieldKeyword ? sourceProperty.IsAutoPropertyOrUsesFieldKeyword : sourceProperty.IsAutoProperty) && TypeSymbol.Equals(sourceProperty.ContainingType, fromMember.ContainingType, TypeCompareKind.AllIgnoreOptions) && IsConstructorOrField(fromMember, isStatic: propertyIsStatic) && (propertyIsStatic || receiver.Kind == BoundKind.ThisReference); diff --git a/src/Compilers/CSharp/Test/Emit3/FieldKeywordTests.cs b/src/Compilers/CSharp/Test/Emit3/FieldKeywordTests.cs index 14918df86b0ef..92745d17f1cd2 100644 --- a/src/Compilers/CSharp/Test/Emit3/FieldKeywordTests.cs +++ b/src/Compilers/CSharp/Test/Emit3/FieldKeywordTests.cs @@ -1587,36 +1587,60 @@ .maxstack 2 { verifier.VerifyIL("C..ctor", $$""" { - // Code size 65 (0x41) + // Code size 121 (0x79) .maxstack 2 IL_0000: ldarg.0 - IL_0001: ldc.i4.1 - IL_0002: stfld "int C.k__BackingField" + IL_0001: ldc.i4.0 + IL_0002: stfld "int C.k__BackingField" IL_0007: ldarg.0 - IL_0008: ldc.i4.2 - IL_0009: stfld "int C.k__BackingField" + IL_0008: ldc.i4.0 + IL_0009: stfld "int C.k__BackingField" IL_000e: ldarg.0 - IL_000f: ldc.i4.3 - IL_0010: call "void C.P3.{{setter}}" + IL_000f: ldc.i4.0 + IL_0010: stfld "int C.k__BackingField" IL_0015: ldarg.0 - IL_0016: ldc.i4.4 - IL_0017: call "void C.P4.{{setter}}" + IL_0016: ldc.i4.0 + IL_0017: stfld "int C.k__BackingField" IL_001c: ldarg.0 - IL_001d: ldc.i4.5 - IL_001e: call "void C.P5.{{setter}}" + IL_001d: ldc.i4.0 + IL_001e: stfld "int C.k__BackingField" IL_0023: ldarg.0 - IL_0024: ldc.i4.6 - IL_0025: call "void C.P6.{{setter}}" + IL_0024: ldc.i4.0 + IL_0025: stfld "int C.k__BackingField" IL_002a: ldarg.0 - IL_002b: ldc.i4.7 - IL_002c: call "void C.P7.{{setter}}" + IL_002b: ldc.i4.0 + IL_002c: stfld "int C.k__BackingField" IL_0031: ldarg.0 - IL_0032: ldc.i4.8 - IL_0033: call "void C.P8.{{setter}}" + IL_0032: ldc.i4.0 + IL_0033: stfld "int C.k__BackingField" IL_0038: ldarg.0 - IL_0039: ldc.i4.s 9 - IL_003b: call "void C.P9.{{setter}}" - IL_0040: ret + IL_0039: ldc.i4.1 + IL_003a: stfld "int C.k__BackingField" + IL_003f: ldarg.0 + IL_0040: ldc.i4.2 + IL_0041: stfld "int C.k__BackingField" + IL_0046: ldarg.0 + IL_0047: ldc.i4.3 + IL_0048: call "void C.P3.{{setter}}" + IL_004d: ldarg.0 + IL_004e: ldc.i4.4 + IL_004f: call "void C.P4.{{setter}}" + IL_0054: ldarg.0 + IL_0055: ldc.i4.5 + IL_0056: call "void C.P5.{{setter}}" + IL_005b: ldarg.0 + IL_005c: ldc.i4.6 + IL_005d: call "void C.P6.{{setter}}" + IL_0062: ldarg.0 + IL_0063: ldc.i4.7 + IL_0064: call "void C.P7.{{setter}}" + IL_0069: ldarg.0 + IL_006a: ldc.i4.8 + IL_006b: call "void C.P8.{{setter}}" + IL_0070: ldarg.0 + IL_0071: ldc.i4.s 9 + IL_0073: call "void C.P9.{{setter}}" + IL_0078: ret } """); } @@ -1754,6 +1778,450 @@ public B() Diagnostic(ErrorCode.ERR_InaccessibleSetter, "P8").WithArguments("A.P8").WithLocation(24, 9)); } + [Fact] + public void ConstructorAssignment_06() + { + string source = $$""" + class A + { + public object P1 { get; } + public object P2 { get => field; } + public object P3 { get => field; init; } + public A() + { + this.P1 = 11; + this.P2 = 12; + this.P3 = 13; + } + A(A a) + { + a.P1 = 31; + a.P2 = 32; + a.P3 = 33; + } + } + class B : A + { + B() + { + base.P1 = 21; + base.P2 = 22; + base.P3 = 23; + } + } + """; + var comp = CreateCompilation(source, targetFramework: TargetFramework.Net80); + comp.VerifyEmitDiagnostics( + // (14,9): error CS0200: Property or indexer 'A.P1' cannot be assigned to -- it is read only + // a.P1 = 31; + Diagnostic(ErrorCode.ERR_AssgReadonlyProp, "a.P1").WithArguments("A.P1").WithLocation(14, 9), + // (15,9): error CS0200: Property or indexer 'A.P2' cannot be assigned to -- it is read only + // a.P2 = 32; + Diagnostic(ErrorCode.ERR_AssgReadonlyProp, "a.P2").WithArguments("A.P2").WithLocation(15, 9), + // (16,9): error CS8852: Init-only property or indexer 'A.P3' can only be assigned in an object initializer, or on 'this' or 'base' in an instance constructor or an 'init' accessor. + // a.P3 = 33; + Diagnostic(ErrorCode.ERR_AssignmentInitOnly, "a.P3").WithArguments("A.P3").WithLocation(16, 9), + // (23,9): error CS0200: Property or indexer 'A.P1' cannot be assigned to -- it is read only + // base.P1 = 21; + Diagnostic(ErrorCode.ERR_AssgReadonlyProp, "base.P1").WithArguments("A.P1").WithLocation(23, 9), + // (24,9): error CS0200: Property or indexer 'A.P2' cannot be assigned to -- it is read only + // base.P2 = 22; + Diagnostic(ErrorCode.ERR_AssgReadonlyProp, "base.P2").WithArguments("A.P2").WithLocation(24, 9)); + } + + [Fact] + public void ConstructorAssignment_07() + { + string source = $$""" + using System; + class C + { + public static int P1 { get; } + public static int P2 { get => field; } + public static int P3 { get => field; set; } + public static int P4 { get => field; set { } } + public static int P5 = F( + P1 = 1, + P2 = 2, + P3 = 3, + P4 = 4); + static int F(int x, int y, int z, int w) => x; + } + class Program + { + static void Main() + { + Console.WriteLine((C.P1, C.P2, C.P3, C.P4)); + } + } + """; + var verifier = CompileAndVerify(source, expectedOutput: "(1, 2, 3, 0)"); + verifier.VerifyDiagnostics(); + verifier.VerifyIL("C..cctor", """ + { + // Code size 39 (0x27) + .maxstack 5 + IL_0000: ldc.i4.1 + IL_0001: dup + IL_0002: stsfld "int C.k__BackingField" + IL_0007: ldc.i4.2 + IL_0008: dup + IL_0009: stsfld "int C.k__BackingField" + IL_000e: ldc.i4.3 + IL_000f: dup + IL_0010: call "void C.P3.set" + IL_0015: ldc.i4.4 + IL_0016: dup + IL_0017: call "void C.P4.set" + IL_001c: call "int C.F(int, int, int, int)" + IL_0021: stsfld "int C.P5" + IL_0026: ret + } + """); + } + + [Theory] + [CombinatorialData] + public void DefaultInitialization_01(bool useRefStruct, bool useInit, bool includeStructInitializationWarnings) + { + string typeKind = useRefStruct ? "ref struct" : " struct"; + string setter = useInit ? "init" : "set"; + string source = $$""" + using System; + {{typeKind}} S0 + { + public int F0; + public int P0 { get; {{setter}}; } + public S0(int unused) { _ = P0; } + } + {{typeKind}} S1 + { + public int F1; + public int P1 { get => field; } + public S1(int unused) { _ = P1; } + } + {{typeKind}} S2 + { + public int F2; + public int P2 { get => field; {{setter}}; } + public S2(int unused) { _ = P2; } + } + {{typeKind}} S3 + { + public int F3; + public int P3 { get => field; {{setter}} { field = value; } } + public S3(int unused) { _ = P3; } + } + class Program + { + static void Main() + { + var s0 = new S0(-1); + var s1 = new S1(1); + var s2 = new S2(2); + var s3 = new S3(3); + Console.WriteLine((s0.F0, s0.P0)); + Console.WriteLine((s1.F1, s1.P1)); + Console.WriteLine((s2.F2, s2.P2)); + Console.WriteLine((s3.F3, s3.P3)); + } + } + """; + var verifier = CompileAndVerify( + source, + options: includeStructInitializationWarnings ? TestOptions.ReleaseExe.WithSpecificDiagnosticOptions(ReportStructInitializationWarnings) : TestOptions.ReleaseExe, + targetFramework: TargetFramework.Net80, + verify: Verification.Skipped, + expectedOutput: IncludeExpectedOutput(""" + (0, 0) + (0, 0) + (0, 0) + (0, 0) + """)); + if (includeStructInitializationWarnings) + { + verifier.VerifyDiagnostics( + // (4,16): warning CS0649: Field 'S0.F0' is never assigned to, and will always have its default value 0 + // public int F0; + Diagnostic(ErrorCode.WRN_UnassignedInternalField, "F0").WithArguments("S0.F0", "0").WithLocation(4, 16), + // (6,12): warning CS9021: Control is returned to caller before auto-implemented property 'S0.P0' is explicitly assigned, causing a preceding implicit assignment of 'default'. + // public S0(int unused) { _ = P0; } + Diagnostic(ErrorCode.WRN_UnassignedThisAutoPropertySupportedVersion, "S0").WithArguments("S0.P0").WithLocation(6, 12), + // (6,12): warning CS9022: Control is returned to caller before field 'S0.F0' is explicitly assigned, causing a preceding implicit assignment of 'default'. + // public S0(int unused) { _ = P0; } + Diagnostic(ErrorCode.WRN_UnassignedThisSupportedVersion, "S0").WithArguments("S0.F0").WithLocation(6, 12), + // (6,33): warning CS9018: Auto-implemented property 'P0' is read before being explicitly assigned, causing a preceding implicit assignment of 'default'. + // public S0(int unused) { _ = P0; } + Diagnostic(ErrorCode.WRN_UseDefViolationPropertySupportedVersion, "P0").WithArguments("P0").WithLocation(6, 33), + // (10,16): warning CS0649: Field 'S1.F1' is never assigned to, and will always have its default value 0 + // public int F1; + Diagnostic(ErrorCode.WRN_UnassignedInternalField, "F1").WithArguments("S1.F1", "0").WithLocation(10, 16), + // (12,33): warning CS9020: The 'this' object is read before all of its fields have been assigned, causing preceding implicit assignments of 'default' to non-explicitly assigned fields. + // public S1(int unused) { _ = P1; } + Diagnostic(ErrorCode.WRN_UseDefViolationThisSupportedVersion, "P1").WithLocation(12, 33), + // (16,16): warning CS0649: Field 'S2.F2' is never assigned to, and will always have its default value 0 + // public int F2; + Diagnostic(ErrorCode.WRN_UnassignedInternalField, "F2").WithArguments("S2.F2", "0").WithLocation(16, 16), + // (18,12): warning CS9021: Control is returned to caller before auto-implemented property 'S2.P2' is explicitly assigned, causing a preceding implicit assignment of 'default'. + // public S2(int unused) { _ = P2; } + Diagnostic(ErrorCode.WRN_UnassignedThisAutoPropertySupportedVersion, "S2").WithArguments("S2.P2").WithLocation(18, 12), + // (18,12): warning CS9022: Control is returned to caller before field 'S2.F2' is explicitly assigned, causing a preceding implicit assignment of 'default'. + // public S2(int unused) { _ = P2; } + Diagnostic(ErrorCode.WRN_UnassignedThisSupportedVersion, "S2").WithArguments("S2.F2").WithLocation(18, 12), + // (18,33): warning CS9018: Auto-implemented property 'P2' is read before being explicitly assigned, causing a preceding implicit assignment of 'default'. + // public S2(int unused) { _ = P2; } + Diagnostic(ErrorCode.WRN_UseDefViolationPropertySupportedVersion, "P2").WithArguments("P2").WithLocation(18, 33), + // (22,16): warning CS0649: Field 'S3.F3' is never assigned to, and will always have its default value 0 + // public int F3; + Diagnostic(ErrorCode.WRN_UnassignedInternalField, "F3").WithArguments("S3.F3", "0").WithLocation(22, 16), + // (24,33): warning CS9020: The 'this' object is read before all of its fields have been assigned, causing preceding implicit assignments of 'default' to non-explicitly assigned fields. + // public S3(int unused) { _ = P3; } + Diagnostic(ErrorCode.WRN_UseDefViolationThisSupportedVersion, "P3").WithLocation(24, 33)); + } + else + { + verifier.VerifyDiagnostics( + // (4,16): warning CS0649: Field 'S0.F0' is never assigned to, and will always have its default value 0 + // public int F0; + Diagnostic(ErrorCode.WRN_UnassignedInternalField, "F0").WithArguments("S0.F0", "0").WithLocation(4, 16), + // (10,16): warning CS0649: Field 'S1.F1' is never assigned to, and will always have its default value 0 + // public int F1; + Diagnostic(ErrorCode.WRN_UnassignedInternalField, "F1").WithArguments("S1.F1", "0").WithLocation(10, 16), + // (16,16): warning CS0649: Field 'S2.F2' is never assigned to, and will always have its default value 0 + // public int F2; + Diagnostic(ErrorCode.WRN_UnassignedInternalField, "F2").WithArguments("S2.F2", "0").WithLocation(16, 16), + // (22,16): warning CS0649: Field 'S3.F3' is never assigned to, and will always have its default value 0 + // public int F3; + Diagnostic(ErrorCode.WRN_UnassignedInternalField, "F3").WithArguments("S3.F3", "0").WithLocation(22, 16)); + } + verifier.VerifyIL("S0..ctor", $$""" + { + // Code size 22 (0x16) + .maxstack 2 + IL_0000: ldarg.0 + IL_0001: ldc.i4.0 + IL_0002: stfld "int S0.F0" + IL_0007: ldarg.0 + IL_0008: ldc.i4.0 + IL_0009: stfld "int S0.k__BackingField" + IL_000e: ldarg.0 + IL_000f: call "readonly int S0.P0.get" + IL_0014: pop + IL_0015: ret + } + """); + verifier.VerifyIL("S1..ctor", $$""" + { + // Code size 22 (0x16) + .maxstack 2 + IL_0000: ldarg.0 + IL_0001: ldc.i4.0 + IL_0002: stfld "int S1.F1" + IL_0007: ldarg.0 + IL_0008: ldc.i4.0 + IL_0009: stfld "int S1.k__BackingField" + IL_000e: ldarg.0 + IL_000f: call "int S1.P1.get" + IL_0014: pop + IL_0015: ret + } + """); + verifier.VerifyIL("S2..ctor", $$""" + { + // Code size 22 (0x16) + .maxstack 2 + IL_0000: ldarg.0 + IL_0001: ldc.i4.0 + IL_0002: stfld "int S2.F2" + IL_0007: ldarg.0 + IL_0008: ldc.i4.0 + IL_0009: stfld "int S2.k__BackingField" + IL_000e: ldarg.0 + IL_000f: call "int S2.P2.get" + IL_0014: pop + IL_0015: ret + } + """); + verifier.VerifyIL("S3..ctor", $$""" + { + // Code size 22 (0x16) + .maxstack 2 + IL_0000: ldarg.0 + IL_0001: ldc.i4.0 + IL_0002: stfld "int S3.F3" + IL_0007: ldarg.0 + IL_0008: ldc.i4.0 + IL_0009: stfld "int S3.k__BackingField" + IL_000e: ldarg.0 + IL_000f: call "int S3.P3.get" + IL_0014: pop + IL_0015: ret + } + """); + } + + [Theory] + [CombinatorialData] + public void DefaultInitialization_02(bool useRefStruct, bool useInit, bool includeStructInitializationWarnings) + { + string typeKind = useRefStruct ? "ref struct" : " struct"; + string setter = useInit ? "init" : "set"; + string source = $$""" + using System; + {{typeKind}} S0 + { + public int F0; + public int P0 { get; {{setter}}; } + public S0(int i) { P0 = i; } + } + {{typeKind}} S1 + { + public int F1; + public int P1 { get => field; } + public S1(int i) { P1 = i; } + } + {{typeKind}} S2 + { + public int F2; + public int P2 { get => field; {{setter}}; } + public S2(int i) { P2 = i; } + } + {{typeKind}} S3 + { + public int F3; + public int P3 { get => field; {{setter}} { field = value; } } + public S3(int i) { P3 = i; } + } + class Program + { + static void Main() + { + var s0 = new S0(-1); + var s1 = new S1(1); + var s2 = new S2(2); + var s3 = new S3(3); + Console.WriteLine((s0.F0, s0.P0)); + Console.WriteLine((s1.F1, s1.P1)); + Console.WriteLine((s2.F2, s2.P2)); + Console.WriteLine((s3.F3, s3.P3)); + } + } + """; + var verifier = CompileAndVerify( + source, + options: includeStructInitializationWarnings ? TestOptions.ReleaseExe.WithSpecificDiagnosticOptions(ReportStructInitializationWarnings) : TestOptions.ReleaseExe, + targetFramework: TargetFramework.Net80, + verify: Verification.Skipped, + expectedOutput: IncludeExpectedOutput(""" + (0, -1) + (0, 1) + (0, 2) + (0, 3) + """)); + if (includeStructInitializationWarnings) + { + verifier.VerifyDiagnostics( + // (4,16): warning CS0649: Field 'S0.F0' is never assigned to, and will always have its default value 0 + // public int F0; + Diagnostic(ErrorCode.WRN_UnassignedInternalField, "F0").WithArguments("S0.F0", "0").WithLocation(4, 16), + // (6,12): warning CS9022: Control is returned to caller before field 'S0.F0' is explicitly assigned, causing a preceding implicit assignment of 'default'. + // public S0(int i) { P0 = i; } + Diagnostic(ErrorCode.WRN_UnassignedThisSupportedVersion, "S0").WithArguments("S0.F0").WithLocation(6, 12), + // (10,16): warning CS0649: Field 'S1.F1' is never assigned to, and will always have its default value 0 + // public int F1; + Diagnostic(ErrorCode.WRN_UnassignedInternalField, "F1").WithArguments("S1.F1", "0").WithLocation(10, 16), + // (12,24): warning CS9020: The 'this' object is read before all of its fields have been assigned, causing preceding implicit assignments of 'default' to non-explicitly assigned fields. + // public S1(int i) { P1 = i; } + Diagnostic(ErrorCode.WRN_UseDefViolationThisSupportedVersion, "P1").WithLocation(12, 24), + // (16,16): warning CS0649: Field 'S2.F2' is never assigned to, and will always have its default value 0 + // public int F2; + Diagnostic(ErrorCode.WRN_UnassignedInternalField, "F2").WithArguments("S2.F2", "0").WithLocation(16, 16), + // (18,12): warning CS9022: Control is returned to caller before field 'S2.F2' is explicitly assigned, causing a preceding implicit assignment of 'default'. + // public S2(int i) { P2 = i; } + Diagnostic(ErrorCode.WRN_UnassignedThisSupportedVersion, "S2").WithArguments("S2.F2").WithLocation(18, 12), + // (22,16): warning CS0649: Field 'S3.F3' is never assigned to, and will always have its default value 0 + // public int F3; + Diagnostic(ErrorCode.WRN_UnassignedInternalField, "F3").WithArguments("S3.F3", "0").WithLocation(22, 16), + // (24,24): warning CS9020: The 'this' object is read before all of its fields have been assigned, causing preceding implicit assignments of 'default' to non-explicitly assigned fields. + // public S3(int i) { P3 = i; } + Diagnostic(ErrorCode.WRN_UseDefViolationThisSupportedVersion, "P3").WithLocation(24, 24)); + } + else + { + verifier.VerifyDiagnostics( + // (4,16): warning CS0649: Field 'S0.F0' is never assigned to, and will always have its default value 0 + // public int F0; + Diagnostic(ErrorCode.WRN_UnassignedInternalField, "F0").WithArguments("S0.F0", "0").WithLocation(4, 16), + // (10,16): warning CS0649: Field 'S1.F1' is never assigned to, and will always have its default value 0 + // public int F1; + Diagnostic(ErrorCode.WRN_UnassignedInternalField, "F1").WithArguments("S1.F1", "0").WithLocation(10, 16), + // (16,16): warning CS0649: Field 'S2.F2' is never assigned to, and will always have its default value 0 + // public int F2; + Diagnostic(ErrorCode.WRN_UnassignedInternalField, "F2").WithArguments("S2.F2", "0").WithLocation(16, 16), + // (22,16): warning CS0649: Field 'S3.F3' is never assigned to, and will always have its default value 0 + // public int F3; + Diagnostic(ErrorCode.WRN_UnassignedInternalField, "F3").WithArguments("S3.F3", "0").WithLocation(22, 16)); + } + verifier.VerifyIL("S0..ctor", $$""" + { + // Code size 15 (0xf) + .maxstack 2 + IL_0000: ldarg.0 + IL_0001: ldc.i4.0 + IL_0002: stfld "int S0.F0" + IL_0007: ldarg.0 + IL_0008: ldarg.1 + IL_0009: call "void S0.P0.{{setter}}" + IL_000e: ret + } + """); + verifier.VerifyIL("S1..ctor", $$""" + { + // Code size 22 (0x16) + .maxstack 2 + IL_0000: ldarg.0 + IL_0001: ldc.i4.0 + IL_0002: stfld "int S1.F1" + IL_0007: ldarg.0 + IL_0008: ldc.i4.0 + IL_0009: stfld "int S1.k__BackingField" + IL_000e: ldarg.0 + IL_000f: ldarg.1 + IL_0010: stfld "int S1.k__BackingField" + IL_0015: ret + } + """); + verifier.VerifyIL("S2..ctor", $$""" + { + // Code size 15 (0xf) + .maxstack 2 + IL_0000: ldarg.0 + IL_0001: ldc.i4.0 + IL_0002: stfld "int S2.F2" + IL_0007: ldarg.0 + IL_0008: ldarg.1 + IL_0009: call "void S2.P2.{{setter}}" + IL_000e: ret + } + """); + verifier.VerifyIL("S3..ctor", $$""" + { + // Code size 22 (0x16) + .maxstack 2 + IL_0000: ldarg.0 + IL_0001: ldc.i4.0 + IL_0002: stfld "int S3.F3" + IL_0007: ldarg.0 + IL_0008: ldc.i4.0 + IL_0009: stfld "int S3.k__BackingField" + IL_000e: ldarg.0 + IL_000f: ldarg.1 + IL_0010: call "void S3.P3.{{setter}}" + IL_0015: ret + } + """); + } + [Theory] [CombinatorialData] public void ReadOnly_01(bool useReadOnlyType, bool useReadOnlyProperty, bool useInit)