/
githubmirror
/
roslyn
Обзор
Документация
Войти
/
githubmirror
/
roslyn
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
src/Compilers/CSharp/Test/Semantic/Semantics/StructConstructorTests.cs
4 900 строк
178 KB
Fred Silberberg
Simplify sequence point display (#81104)
10 ноя 2025, 20:11
Не верифицирован
10 ноя 2025, 20:11
0544ad5
Код
Авторство
О чём код?
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. #nullable disable using System.Linq; using Microsoft.CodeAnalysis.CSharp.Symbols; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.CSharp.Test.Utilities; using Microsoft.CodeAnalysis.Test.Utilities; using Roslyn.Test.Utilities; using Xunit; namespace Microsoft.CodeAnalysis.CSharp.UnitTests.Semantics { public class StructConstructorTests : CSharpTestBase { [CombinatorialData] [Theory] public void PublicParameterlessConstructor(bool useCompilationReference) { var sourceA = @"public struct S<T> { public readonly bool Initialized; public S() { Initialized = true; } }"; var comp = CreateCompilation(sourceA, parseOptions: TestOptions.Regular9); comp.VerifyDiagnostics( // (4,12): error CS8773: Feature 'parameterless struct constructors' is not available in C# 9.0. Please use language version 10.0 or greater. // public S() { Initialized = true; } Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion9, "S").WithArguments("parameterless struct constructors", "10.0").WithLocation(4, 12)); comp = CreateCompilation(sourceA); comp.VerifyDiagnostics(); var refA = AsReference(comp, useCompilationReference); var sourceB = @"using System; class Program { static T CreateNew<T>() where T : new() => new T(); static T CreateStruct<T>() where T : struct => new T(); static void Main() { Console.WriteLine(new S<int>().Initialized); Console.WriteLine(CreateNew<S<int>>().Initialized); Console.WriteLine(CreateStruct<S<int>>().Initialized); Console.WriteLine(CreateStruct<S<string>>().Initialized); Console.WriteLine(CreateNew<S<string>>().Initialized); Console.WriteLine(new S<string>().Initialized); } }"; bool secondCall = ExecutionConditionUtil.IsCoreClr; // .NET Framework ignores constructor in second call to Activator.CreateInstance<T>(). CompileAndVerify(sourceB, references: new[] { refA }, expectedOutput: $@"True True {secondCall} True {secondCall} True"); } [Fact] public void NonPublicParameterlessConstructor_01() { var source = @"public struct A0 { public A0() { } } public struct A1 { internal A1() { } } public struct A2 { private A2() { } } public struct A3 { A3() { } } internal struct B0 { public B0() { } } internal struct B1 { internal B1() { } } internal struct B2 { private B2() { } } internal struct B3 { B3() { } } public class C { internal protected struct C0 { public C0() { } } internal protected struct C1 { internal C1() { } } internal protected struct C2 { private C2() { } } internal protected struct C3 { C3() { } } protected struct D0 { public D0() { } } protected struct D1 { internal D1() { } } protected struct D2 { private D2() { } } protected struct D3 { D3() { } } private protected struct E0 { public E0() { } } private protected struct E1 { internal E1() { } } private protected struct E2 { private E2() { } } private protected struct E3 { E3() { } } private struct F0 { public F0() { } } private struct F1 { internal F1() { } } private struct F2 { private F2() { } } private struct F3 { F3() { } } }"; var comp = CreateCompilation(source); comp.VerifyDiagnostics( // (2,29): error CS8938: The parameterless struct constructor must be 'public'. // public struct A1 { internal A1() { } } Diagnostic(ErrorCode.ERR_NonPublicParameterlessStructConstructor, "A1").WithLocation(2, 29), // (3,28): error CS8938: The parameterless struct constructor must be 'public'. // public struct A2 { private A2() { } } Diagnostic(ErrorCode.ERR_NonPublicParameterlessStructConstructor, "A2").WithLocation(3, 28), // (4,20): error CS8938: The parameterless struct constructor must be 'public'. // public struct A3 { A3() { } } Diagnostic(ErrorCode.ERR_NonPublicParameterlessStructConstructor, "A3").WithLocation(4, 20), // (7,31): error CS8938: The parameterless struct constructor must be 'public'. // internal struct B1 { internal B1() { } } Diagnostic(ErrorCode.ERR_NonPublicParameterlessStructConstructor, "B1").WithLocation(7, 31), // (8,30): error CS8938: The parameterless struct constructor must be 'public'. // internal struct B2 { private B2() { } } Diagnostic(ErrorCode.ERR_NonPublicParameterlessStructConstructor, "B2").WithLocation(8, 30), // (9,22): error CS8938: The parameterless struct constructor must be 'public'. // internal struct B3 { B3() { } } Diagnostic(ErrorCode.ERR_NonPublicParameterlessStructConstructor, "B3").WithLocation(9, 22), // (14,45): error CS8938: The parameterless struct constructor must be 'public'. // internal protected struct C1 { internal C1() { } } Diagnostic(ErrorCode.ERR_NonPublicParameterlessStructConstructor, "C1").WithLocation(14, 45), // (15,44): error CS8938: The parameterless struct constructor must be 'public'. // internal protected struct C2 { private C2() { } } Diagnostic(ErrorCode.ERR_NonPublicParameterlessStructConstructor, "C2").WithLocation(15, 44), // (16,36): error CS8938: The parameterless struct constructor must be 'public'. // internal protected struct C3 { C3() { } } Diagnostic(ErrorCode.ERR_NonPublicParameterlessStructConstructor, "C3").WithLocation(16, 36), // (19,36): error CS8938: The parameterless struct constructor must be 'public'. // protected struct D1 { internal D1() { } } Diagnostic(ErrorCode.ERR_NonPublicParameterlessStructConstructor, "D1").WithLocation(19, 36), // (20,35): error CS8938: The parameterless struct constructor must be 'public'. // protected struct D2 { private D2() { } } Diagnostic(ErrorCode.ERR_NonPublicParameterlessStructConstructor, "D2").WithLocation(20, 35), // (21,27): error CS8938: The parameterless struct constructor must be 'public'. // protected struct D3 { D3() { } } Diagnostic(ErrorCode.ERR_NonPublicParameterlessStructConstructor, "D3").WithLocation(21, 27), // (24,44): error CS8938: The parameterless struct constructor must be 'public'. // private protected struct E1 { internal E1() { } } Diagnostic(ErrorCode.ERR_NonPublicParameterlessStructConstructor, "E1").WithLocation(24, 44), // (25,43): error CS8938: The parameterless struct constructor must be 'public'. // private protected struct E2 { private E2() { } } Diagnostic(ErrorCode.ERR_NonPublicParameterlessStructConstructor, "E2").WithLocation(25, 43), // (26,35): error CS8938: The parameterless struct constructor must be 'public'. // private protected struct E3 { E3() { } } Diagnostic(ErrorCode.ERR_NonPublicParameterlessStructConstructor, "E3").WithLocation(26, 35), // (29,34): error CS8938: The parameterless struct constructor must be 'public'. // private struct F1 { internal F1() { } } Diagnostic(ErrorCode.ERR_NonPublicParameterlessStructConstructor, "F1").WithLocation(29, 34), // (30,33): error CS8938: The parameterless struct constructor must be 'public'. // private struct F2 { private F2() { } } Diagnostic(ErrorCode.ERR_NonPublicParameterlessStructConstructor, "F2").WithLocation(30, 33), // (31,25): error CS8938: The parameterless struct constructor must be 'public'. // private struct F3 { F3() { } } Diagnostic(ErrorCode.ERR_NonPublicParameterlessStructConstructor, "F3").WithLocation(31, 25)); } [InlineData("assembly")] [InlineData("private")] [Theory] public void NonPublicParameterlessConstructor_02(string accessibility) { var sourceA = $@".class public sealed S extends [mscorlib]System.ValueType {{ .method {accessibility} hidebysig specialname rtspecialname instance void .ctor() cil managed {{ ret }} }}"; var refA = CompileIL(sourceA); var sourceB = @"using System; class Program { static T CreateNew<T>() where T : new() => new T(); static T CreateStruct1<T>() where T : struct => new T(); static T CreateStruct2<T>() where T : struct => CreateNew<T>(); static string Invoke(Func<object> f) { object obj; try { obj = f(); } catch (Exception e) { obj = e; } return obj.GetType().FullName; } static void Main() { Console.WriteLine(Invoke(() => new S())); Console.WriteLine(Invoke(() => CreateNew<S>())); Console.WriteLine(Invoke(() => CreateStruct1<S>())); Console.WriteLine(Invoke(() => CreateStruct2<S>())); } }"; CompileAndVerify(sourceB, references: new[] { refA }, expectedOutput: @"S System.MissingMethodException System.MissingMethodException System.MissingMethodException"); } [InlineData("internal")] [InlineData("private")] [Theory] public void NonPublicParameterlessConstructor_03(string accessibility) { var sourceA = $@"public struct S {{ {accessibility} S() {{ }} }}"; var comp = CreateCompilation(sourceA); comp.VerifyDiagnostics( // (4,5): error CS8938: The parameterless struct constructor must be 'public'. // S() { } Diagnostic(ErrorCode.ERR_NonPublicParameterlessStructConstructor, "S").WithLocation(4, 5)); var refA = comp.ToMetadataReference(); var sourceB = @"class Program { static T CreateNew<T>() where T : new() => new T(); static T CreateStruct<T>() where T : struct => new T(); static void Main() { _ = new S(); _ = CreateNew<S>(); _ = CreateStruct<S>(); } }"; var expectedDiagnostics = new[] { // (7,17): error CS0122: 'S.S()' is inaccessible due to its protection level // _ = new S(); Diagnostic(ErrorCode.ERR_BadAccess, "S").WithArguments("S.S()").WithLocation(7, 17), // (8,13): error CS0310: 'S' must be a non-abstract type with a public parameterless constructor in order to use it as parameter 'T' in the generic type or method 'Program.CreateNew<T>()' // _ = CreateNew<S>(); Diagnostic(ErrorCode.ERR_NewConstraintNotSatisfied, "CreateNew<S>").WithArguments("Program.CreateNew<T>()", "T", "S").WithLocation(8, 13), }; comp = CreateCompilation(sourceB, references: new[] { refA }, parseOptions: TestOptions.Regular9); comp.VerifyDiagnostics(expectedDiagnostics); comp = CreateCompilation(sourceB, references: new[] { refA }); comp.VerifyDiagnostics(expectedDiagnostics); } [InlineData("internal")] [InlineData("protected")] [InlineData("protected internal")] [InlineData("private")] [InlineData("private protected")] [Theory] public void PublicConstructorPrivateStruct_NewConstraint(string accessibility) { var sourceA = $@"partial class Program {{ {accessibility} struct S {{ public readonly bool Initialized; public S() {{ Initialized = true; }} }} }}"; var sourceB = @"using System; partial class Program { static T CreateNew<T>() where T : new() => new T(); static void Main() { Console.WriteLine(CreateNew<S>().Initialized); } }"; CompileAndVerify(new[] { sourceA, sourceB }, expectedOutput: "True"); } [Fact] public void ThisInitializer_01() { var source = @"using static System.Console; using static Program; struct S1 { internal int Value; public S1() { Value = Two(); } internal S1(object obj) : this() { } } struct S2 { internal int Value; public S2() : this(null) { } S2(object obj) { Value = Three(); } } class Program { internal static int Two() { WriteLine(""Two()""); return 2; } internal static int Three() { WriteLine(""Three()""); return 3; } static void Main() { WriteLine($""new S1().Value: {new S1().Value}""); WriteLine($""new S1(null).Value: {new S1(null).Value}""); WriteLine($""new S2().Value: {new S2().Value}""); } }"; var verifier = CompileAndVerify(source, expectedOutput: @"Two() new S1().Value: 2 Two() new S1(null).Value: 2 Three() new S2().Value: 3 "); verifier.VerifyIL("S1..ctor()", @"{ // Code size 12 (0xc) .maxstack 2 IL_0000: ldarg.0 IL_0001: call ""int Program.Two()"" IL_0006: stfld ""int S1.Value"" IL_000b: ret }"); verifier.VerifyIL("S1..ctor(object)", @"{ // Code size 7 (0x7) .maxstack 1 IL_0000: ldarg.0 IL_0001: call ""S1..ctor()"" IL_0006: ret }"); verifier.VerifyIL("S2..ctor()", @"{ // Code size 8 (0x8) .maxstack 2 IL_0000: ldarg.0 IL_0001: ldnull IL_0002: call ""S2..ctor(object)"" IL_0007: ret }"); verifier.VerifyIL("S2..ctor(object)", @"{ // Code size 12 (0xc) .maxstack 2 IL_0000: ldarg.0 IL_0001: call ""int Program.Three()"" IL_0006: stfld ""int S2.Value"" IL_000b: ret }"); } [Fact] public void ThisInitializer_02() { var source = @"using static System.Console; using static Program; struct S1 { internal int Value; public S1() { Value = Two(); } internal S1(object obj) : this() { Value = Three(); } } struct S2 { internal int Value; public S2() : this(null) { Value = Two(); } S2(object obj) { Value = Three(); } } class Program { internal static int Two() { WriteLine(""Two()""); return 2; } internal static int Three() { WriteLine(""Three()""); return 3; } static void Main() { WriteLine($""new S1().Value: {new S1().Value}""); WriteLine($""new S1(null).Value: {new S1(null).Value}""); WriteLine($""new S2().Value: {new S2().Value}""); } }"; var verifier = CompileAndVerify(source, expectedOutput: @"Two() new S1().Value: 2 Two() Three() new S1(null).Value: 3 Three() Two() new S2().Value: 2 "); verifier.VerifyIL("S1..ctor()", @"{ // Code size 12 (0xc) .maxstack 2 IL_0000: ldarg.0 IL_0001: call ""int Program.Two()"" IL_0006: stfld ""int S1.Value"" IL_000b: ret }"); verifier.VerifyIL("S1..ctor(object)", @"{ // Code size 18 (0x12) .maxstack 2 IL_0000: ldarg.0 IL_0001: call ""S1..ctor()"" IL_0006: ldarg.0 IL_0007: call ""int Program.Three()"" IL_000c: stfld ""int S1.Value"" IL_0011: ret }"); verifier.VerifyIL("S2..ctor()", @"{ // Code size 19 (0x13) .maxstack 2 IL_0000: ldarg.0 IL_0001: ldnull IL_0002: call ""S2..ctor(object)"" IL_0007: ldarg.0 IL_0008: call ""int Program.Two()"" IL_000d: stfld ""int S2.Value"" IL_0012: ret }"); verifier.VerifyIL("S2..ctor(object)", @"{ // Code size 12 (0xc) .maxstack 2 IL_0000: ldarg.0 IL_0001: call ""int Program.Three()"" IL_0006: stfld ""int S2.Value"" IL_000b: ret }"); } [Fact] public void ThisInitializer_03() { var source = @"using static System.Console; using static Program; struct S0 { internal int Value = One(); internal S0(object obj) : this() { } } struct S1 { internal int Value = One(); public S1() { } internal S1(object obj) : this() { } } struct S2 { internal int Value = One(); public S2() : this(null) { } S2(object obj) { } } class Program { internal static int One() { WriteLine(""One()""); return 1; } static void Main() { WriteLine($""new S0().Value: {new S0().Value}""); WriteLine($""new S0(null).Value: {new S0(null).Value}""); WriteLine($""new S1().Value: {new S1().Value}""); WriteLine($""new S1(null).Value: {new S1(null).Value}""); WriteLine($""new S2().Value: {new S2().Value}""); } }"; var verifier = CompileAndVerify(source, expectedOutput: @" new S0().Value: 0 One() new S0(null).Value: 1 One() new S1().Value: 1 One() new S1(null).Value: 1 One() new S2().Value: 1 "); verifier.VerifyMissing("S0..ctor()"); verifier.VerifyIL("S0..ctor(object)", @"{ // Code size 19 (0x13) .maxstack 2 IL_0000: ldarg.0 IL_0001: initobj ""S0"" IL_0007: ldarg.0 IL_0008: call ""int Program.One()"" IL_000d: stfld ""int S0.Value"" IL_0012: ret }"); verifier.VerifyIL("S1..ctor()", @"{ // Code size 12 (0xc) .maxstack 2 IL_0000: ldarg.0 IL_0001: call ""int Program.One()"" IL_0006: stfld ""int S1.Value"" IL_000b: ret }"); verifier.VerifyIL("S1..ctor(object)", @"{ // Code size 7 (0x7) .maxstack 1 IL_0000: ldarg.0 IL_0001: call ""S1..ctor()"" IL_0006: ret }"); verifier.VerifyIL("S2..ctor()", @"{ // Code size 8 (0x8) .maxstack 2 IL_0000: ldarg.0 IL_0001: ldnull IL_0002: call ""S2..ctor(object)"" IL_0007: ret }"); verifier.VerifyIL("S2..ctor(object)", @"{ // Code size 12 (0xc) .maxstack 2 IL_0000: ldarg.0 IL_0001: call ""int Program.One()"" IL_0006: stfld ""int S2.Value"" IL_000b: ret }"); } [Fact] public void ThisInitializer_04() { var source = @"using static System.Console; using static Program; struct S0 { internal int Value = One(); internal S0(object obj) : this() { Value = Two(); } } struct S1 { internal int Value = One(); public S1() { Value = Two(); } internal S1(object obj) : this() { Value = Three(); } } struct S2 { internal int Value = One(); public S2() : this(null) { Value = Two(); } S2(object obj) { Value = Three(); } } class Program { internal static int One() { WriteLine(""One()""); return 1; } internal static int Two() { WriteLine(""Two()""); return 2; } internal static int Three() { WriteLine(""Three()""); return 3; } static void Main() { WriteLine($""new S0().Value: {new S0().Value}""); WriteLine($""new S0(null).Value: {new S0(null).Value}""); WriteLine($""new S1().Value: {new S1().Value}""); WriteLine($""new S1(null).Value: {new S1(null).Value}""); WriteLine($""new S2().Value: {new S2().Value}""); } }"; var verifier = CompileAndVerify(source, expectedOutput: @"new S0().Value: 0 One() Two() new S0(null).Value: 2 One() Two() new S1().Value: 2 One() Two() Three() new S1(null).Value: 3 One() Three() Two() new S2().Value: 2 "); verifier.VerifyMissing("S0..ctor()"); verifier.VerifyIL("S0..ctor(object)", @"{ // Code size 30 (0x1e) .maxstack 2 IL_0000: ldarg.0 IL_0001: initobj ""S0"" IL_0007: ldarg.0 IL_0008: call ""int Program.One()"" IL_000d: stfld ""int S0.Value"" IL_0012: ldarg.0 IL_0013: call ""int Program.Two()"" IL_0018: stfld ""int S0.Value"" IL_001d: ret }"); verifier.VerifyIL("S1..ctor()", @"{ // Code size 23 (0x17) .maxstack 2 IL_0000: ldarg.0 IL_0001: call ""int Program.One()"" IL_0006: stfld ""int S1.Value"" IL_000b: ldarg.0 IL_000c: call ""int Program.Two()"" IL_0011: stfld ""int S1.Value"" IL_0016: ret }"); verifier.VerifyIL("S1..ctor(object)", @"{ // Code size 18 (0x12) .maxstack 2 IL_0000: ldarg.0 IL_0001: call ""S1..ctor()"" IL_0006: ldarg.0 IL_0007: call ""int Program.Three()"" IL_000c: stfld ""int S1.Value"" IL_0011: ret }"); verifier.VerifyIL("S2..ctor()", @"{ // Code size 19 (0x13) .maxstack 2 IL_0000: ldarg.0 IL_0001: ldnull IL_0002: call ""S2..ctor(object)"" IL_0007: ldarg.0 IL_0008: call ""int Program.Two()"" IL_000d: stfld ""int S2.Value"" IL_0012: ret }"); verifier.VerifyIL("S2..ctor(object)", @"{ // Code size 23 (0x17) .maxstack 2 IL_0000: ldarg.0 IL_0001: call ""int Program.One()"" IL_0006: stfld ""int S2.Value"" IL_000b: ldarg.0 IL_000c: call ""int Program.Three()"" IL_0011: stfld ""int S2.Value"" IL_0016: ret }"); } /// <summary> /// Initializers with default values to verify that the decision whether /// to execute an initializer is independent of the initializer value. /// </summary> [Fact] public void ThisInitializer_05() { var source = @"using static System.Console; using static Program; struct S0 { internal int Value = 0; internal S0(object obj) : this() { Value = Two(); } } struct S1 { internal int Value = 0; public S1() { Value = Two(); } internal S1(object obj) : this() { Value = Three(); } } struct S2 { internal int Value = 0; public S2() : this(null) { Value = Two(); } S2(object obj) { Value = Three(); } } class Program { internal static int Two() { WriteLine(""Two()""); return 2; } internal static int Three() { WriteLine(""Three()""); return 3; } static void Main() { WriteLine($""new S0().Value: {new S0().Value}""); WriteLine($""new S0(null).Value: {new S0(null).Value}""); WriteLine($""new S1().Value: {new S1().Value}""); WriteLine($""new S1(null).Value: {new S1(null).Value}""); WriteLine($""new S2().Value: {new S2().Value}""); } }"; var verifier = CompileAndVerify(source, expectedOutput: @"new S0().Value: 0 Two() new S0(null).Value: 2 Two() new S1().Value: 2 Two() Three() new S1(null).Value: 3 Three() Two() new S2().Value: 2 "); verifier.VerifyMissing("S0..ctor()"); verifier.VerifyIL("S0..ctor(object)", @"{ // Code size 26 (0x1a) .maxstack 2 IL_0000: ldarg.0 IL_0001: initobj ""S0"" IL_0007: ldarg.0 IL_0008: ldc.i4.0 IL_0009: stfld ""int S0.Value"" IL_000e: ldarg.0 IL_000f: call ""int Program.Two()"" IL_0014: stfld ""int S0.Value"" IL_0019: ret }"); verifier.VerifyIL("S1..ctor()", @"{ // Code size 19 (0x13) .maxstack 2 IL_0000: ldarg.0 IL_0001: ldc.i4.0 IL_0002: stfld ""int S1.Value"" IL_0007: ldarg.0 IL_0008: call ""int Program.Two()"" IL_000d: stfld ""int S1.Value"" IL_0012: ret }"); verifier.VerifyIL("S1..ctor(object)", @"{ // Code size 18 (0x12) .maxstack 2 IL_0000: ldarg.0 IL_0001: call ""S1..ctor()"" IL_0006: ldarg.0 IL_0007: call ""int Program.Three()"" IL_000c: stfld ""int S1.Value"" IL_0011: ret }"); verifier.VerifyIL("S2..ctor()", @"{ // Code size 19 (0x13) .maxstack 2 IL_0000: ldarg.0 IL_0001: ldnull IL_0002: call ""S2..ctor(object)"" IL_0007: ldarg.0 IL_0008: call ""int Program.Two()"" IL_000d: stfld ""int S2.Value"" IL_0012: ret }"); verifier.VerifyIL("S2..ctor(object)", @"{ // Code size 19 (0x13) .maxstack 2 IL_0000: ldarg.0 IL_0001: ldc.i4.0 IL_0002: stfld ""int S2.Value"" IL_0007: ldarg.0 IL_0008: call ""int Program.Three()"" IL_000d: stfld ""int S2.Value"" IL_0012: ret }"); } [Fact] public void ThisInitializer_06() { var source = @"using static System.Console; using static Program; struct S0 { internal int Value; public S0(params object[] args) { Value = Two(); } public S0(int i) : this() { } } struct S1 { internal int Value; public S1(object obj = null) { Value = Two(); } public S1(int i) : this() { } } class Program { internal static int Two() { WriteLine(""Two()""); return 2; } static void Main() { WriteLine($""new S0().Value: {new S0().Value}""); WriteLine($""new S0(0).Value: {new S0(0).Value}""); WriteLine($""new S0((object)0).Value: {new S0((object)0).Value}""); WriteLine($""new S1().Value: {new S1().Value}""); WriteLine($""new S1(1).Value: {new S1(1).Value}""); WriteLine($""new S1((object)1).Value: {new S1((object)1).Value}""); } }"; var verifier = CompileAndVerify(source, expectedOutput: @"new S0().Value: 0 new S0(0).Value: 0 Two() new S0((object)0).Value: 2 new S1().Value: 0 new S1(1).Value: 0 Two() new S1((object)1).Value: 2 "); verifier.VerifyMissing("S0..ctor()"); verifier.VerifyIL("S0..ctor(int)", @"{ // Code size 8 (0x8) .maxstack 1 IL_0000: ldarg.0 IL_0001: initobj ""S0"" IL_0007: ret }"); verifier.VerifyMissing("S1..ctor()"); verifier.VerifyIL("S1..ctor(int)", @"{ // Code size 8 (0x8) .maxstack 1 IL_0000: ldarg.0 IL_0001: initobj ""S1"" IL_0007: ret }"); } private static CSharpParseOptions GetParseOptions(LanguageVersion? languageVersion) { return languageVersion is null ? null : TestOptions.Regular.WithLanguageVersion(languageVersion.Value); } [Theory] [InlineData(LanguageVersion.CSharp10)] [InlineData(null)] public void DefaultThisInitializer_01(LanguageVersion? languageVersion) { var source = @"using System; struct S { int x; int y; public S(int y) : this() { } public override string ToString() => (x, y).ToString(); } record struct R { int x; int y; public R(int y) : this() { } public override string ToString() => (x, y).ToString(); } class Program { static void Main() { Console.WriteLine(new S(2)); Console.WriteLine(new S()); Console.WriteLine(new R(2)); Console.WriteLine(new R()); } }"; var verifier = CompileAndVerify(source, parseOptions: GetParseOptions(languageVersion), expectedOutput: @"(0, 0) (0, 0) (0, 0) (0, 0) "); verifier.VerifyIL("S..ctor(int)", @"{ // Code size 8 (0x8) .maxstack 1 IL_0000: ldarg.0 IL_0001: initobj ""S"" IL_0007: ret }"); verifier.VerifyIL("R..ctor(int)", @"{ // Code size 8 (0x8) .maxstack 1 IL_0000: ldarg.0 IL_0001: initobj ""R"" IL_0007: ret }"); } [Theory] [InlineData(LanguageVersion.CSharp10)] [InlineData(null)] public void DefaultThisInitializer_02(LanguageVersion? languageVersion) { var source = @"using System; struct S { int x; int y; public S(int y) : this() { this.y = y; } public override string ToString() => (x, y).ToString(); } record struct R { int x; int y; public R(int y) : this() { this.y = y; } public override string ToString() => (x, y).ToString(); } class Program { static void Main() { Console.WriteLine(new S(2)); Console.WriteLine(new S()); Console.WriteLine(new R(2)); Console.WriteLine(new R()); } }"; var verifier = CompileAndVerify(source, parseOptions: GetParseOptions(languageVersion), expectedOutput: @"(0, 2) (0, 0) (0, 2) (0, 0) "); verifier.VerifyIL("S..ctor(int)", @"{ // Code size 15 (0xf) .maxstack 2 IL_0000: ldarg.0 IL_0001: initobj ""S"" IL_0007: ldarg.0 IL_0008: ldarg.1 IL_0009: stfld ""int S.y"" IL_000e: ret }"); verifier.VerifyIL("R..ctor(int)", @"{ // Code size 15 (0xf) .maxstack 2 IL_0000: ldarg.0 IL_0001: initobj ""R"" IL_0007: ldarg.0 IL_0008: ldarg.1 IL_0009: stfld ""int R.y"" IL_000e: ret }"); } [WorkItem(58790, "https://github.com/dotnet/roslyn/issues/58790")] [Theory] [InlineData(LanguageVersion.CSharp10)] [InlineData(null)] public void DefaultThisInitializer_03(LanguageVersion? languageVersion) { var source = @"using System; struct S { int x = 1; int y; public S(int y) : this() { } public override string ToString() => (x, y).ToString(); } record struct R { int x = 1; int y; public R(int y) : this() { } public override string ToString() => (x, y).ToString(); } class Program { static void Main() { Console.WriteLine(new S(2)); Console.WriteLine(new S()); Console.WriteLine(new R(2)); Console.WriteLine(new R()); } }"; var verifier = CompileAndVerify(source, parseOptions: GetParseOptions(languageVersion), expectedOutput: @"(1, 0) (0, 0) (1, 0) (0, 0) "); verifier.VerifyIL("S..ctor(int)", @"{ // Code size 15 (0xf) .maxstack 2 IL_0000: ldarg.0 IL_0001: initobj ""S"" IL_0007: ldarg.0 IL_0008: ldc.i4.1 IL_0009: stfld ""int S.x"" IL_000e: ret }"); verifier.VerifyIL("R..ctor(int)", @"{ // Code size 15 (0xf) .maxstack 2 IL_0000: ldarg.0 IL_0001: initobj ""R"" IL_0007: ldarg.0 IL_0008: ldc.i4.1 IL_0009: stfld ""int R.x"" IL_000e: ret }"); var comp = (CSharpCompilation)verifier.Compilation; var tree = comp.SyntaxTrees.Single(); var model = comp.GetSemanticModel(tree); var syntax = tree.GetRoot().DescendantNodes().OfType<ConstructorDeclarationSyntax>().First(); var operation = model.GetOperation(syntax); var actualText = OperationTreeVerifier.GetOperationTree(comp, operation); OperationTreeVerifier.Verify( @"IConstructorBodyOperation (OperationKind.ConstructorBody, Type: null) (Syntax: 'public S(in ... }') Initializer: IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null, IsImplicit) (Syntax: ': this()') Expression: IInvocationOperation ( S..ctor()) (OperationKind.Invocation, Type: System.Void) (Syntax: ': this()') Instance Receiver: IInstanceReferenceOperation (ReferenceKind: ContainingTypeInstance) (OperationKind.InstanceReference, Type: S, IsImplicit) (Syntax: ': this()') Arguments(0) BlockBody: IBlockOperation (0 statements) (OperationKind.Block, Type: null) (Syntax: '{ ... }') ExpressionBody: null ", actualText); } [WorkItem(58790, "https://github.com/dotnet/roslyn/issues/58790")] [Theory] [InlineData(LanguageVersion.CSharp10)] [InlineData(null)] public void DefaultThisInitializer_04(LanguageVersion? languageVersion) { var source = @"using System; struct S { int x = 1; int y = 2; public S(int y) : this() { } public override string ToString() => (x, y).ToString(); } record struct R { int x = 1; int y = 2; public R(int y) : this() { } public override string ToString() => (x, y).ToString(); } class Program { static void Main() { Console.WriteLine(new S(2)); Console.WriteLine(new S()); Console.WriteLine(new R(2)); Console.WriteLine(new R()); } }"; var verifier = CompileAndVerify(source, parseOptions: GetParseOptions(languageVersion), expectedOutput: @"(1, 2) (0, 0) (1, 2) (0, 0) "); verifier.VerifyIL("S..ctor(int)", @"{ // Code size 22 (0x16) .maxstack 2 IL_0000: ldarg.0 IL_0001: initobj ""S"" IL_0007: ldarg.0 IL_0008: ldc.i4.1 IL_0009: stfld ""int S.x"" IL_000e: ldarg.0 IL_000f: ldc.i4.2 IL_0010: stfld ""int S.y"" IL_0015: ret }"); verifier.VerifyIL("R..ctor(int)", @"{ // Code size 22 (0x16) .maxstack 2 IL_0000: ldarg.0 IL_0001: initobj ""R"" IL_0007: ldarg.0 IL_0008: ldc.i4.1 IL_0009: stfld ""int R.x"" IL_000e: ldarg.0 IL_000f: ldc.i4.2 IL_0010: stfld ""int R.y"" IL_0015: ret }"); var comp = (CSharpCompilation)verifier.Compilation; var tree = comp.SyntaxTrees.Single(); var model = comp.GetSemanticModel(tree); var syntax = tree.GetRoot().DescendantNodes().OfType<ConstructorDeclarationSyntax>().First(); var operation = model.GetOperation(syntax); var actualText = OperationTreeVerifier.GetOperationTree(comp, operation); OperationTreeVerifier.Verify( @"IConstructorBodyOperation (OperationKind.ConstructorBody, Type: null) (Syntax: 'public S(in ... }') Initializer: IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null, IsImplicit) (Syntax: ': this()') Expression: IInvocationOperation ( S..ctor()) (OperationKind.Invocation, Type: System.Void) (Syntax: ': this()') Instance Receiver: IInstanceReferenceOperation (ReferenceKind: ContainingTypeInstance) (OperationKind.InstanceReference, Type: S, IsImplicit) (Syntax: ': this()') Arguments(0) BlockBody: IBlockOperation (0 statements) (OperationKind.Block, Type: null) (Syntax: '{ ... }') ExpressionBody: null ", actualText); } [WorkItem(58790, "https://github.com/dotnet/roslyn/issues/58790")] [Theory] [InlineData(LanguageVersion.CSharp10)] [InlineData(null)] public void DefaultThisInitializer_05(LanguageVersion? languageVersion) { var source = @"using System; struct S { int x = 1; int y; public S(int y) : this() { this.y = y; } public override string ToString() => (x, y).ToString(); } record struct R { int x = 1; int y; public R(int y) : this() { this.y = y; } public override string ToString() => (x, y).ToString(); } class Program { static void Main() { Console.WriteLine(new S(2)); Console.WriteLine(new S()); Console.WriteLine(new R(2)); Console.WriteLine(new R()); } }"; var verifier = CompileAndVerify(source, parseOptions: GetParseOptions(languageVersion), expectedOutput: @"(1, 2) (0, 0) (1, 2) (0, 0) "); verifier.VerifyIL("S..ctor(int)", @"{ // Code size 22 (0x16) .maxstack 2 IL_0000: ldarg.0 IL_0001: initobj ""S"" IL_0007: ldarg.0 IL_0008: ldc.i4.1 IL_0009: stfld ""int S.x"" IL_000e: ldarg.0 IL_000f: ldarg.1 IL_0010: stfld ""int S.y"" IL_0015: ret }"); verifier.VerifyIL("R..ctor(int)", @"{ // Code size 22 (0x16) .maxstack 2 IL_0000: ldarg.0 IL_0001: initobj ""R"" IL_0007: ldarg.0 IL_0008: ldc.i4.1 IL_0009: stfld ""int R.x"" IL_000e: ldarg.0 IL_000f: ldarg.1 IL_0010: stfld ""int R.y"" IL_0015: ret }"); var comp = (CSharpCompilation)verifier.Compilation; var tree = comp.SyntaxTrees.Single(); var model = comp.GetSemanticModel(tree); var syntax = tree.GetRoot().DescendantNodes().OfType<ConstructorDeclarationSyntax>().First(); var operation = model.GetOperation(syntax); var actualText = OperationTreeVerifier.GetOperationTree(comp, operation); OperationTreeVerifier.Verify( @"IConstructorBodyOperation (OperationKind.ConstructorBody, Type: null) (Syntax: 'public S(in ... }') Initializer: IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null, IsImplicit) (Syntax: ': this()') Expression: IInvocationOperation ( S..ctor()) (OperationKind.Invocation, Type: System.Void) (Syntax: ': this()') Instance Receiver: IInstanceReferenceOperation (ReferenceKind: ContainingTypeInstance) (OperationKind.InstanceReference, Type: S, IsImplicit) (Syntax: ': this()') Arguments(0) BlockBody: IBlockOperation (1 statements) (OperationKind.Block, Type: null) (Syntax: '{ ... }') IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'this.y = y;') Expression: ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: System.Int32) (Syntax: 'this.y = y') Left: IFieldReferenceOperation: System.Int32 S.y (OperationKind.FieldReference, Type: System.Int32) (Syntax: 'this.y') Instance Receiver: IInstanceReferenceOperation (ReferenceKind: ContainingTypeInstance) (OperationKind.InstanceReference, Type: S) (Syntax: 'this') Right: IParameterReferenceOperation: y (OperationKind.ParameterReference, Type: System.Int32) (Syntax: 'y') ExpressionBody: null ", actualText); } [Fact] public void DefaultThisInitializer_06() { var source = @"#pragma warning disable 169 #pragma warning disable 414 using System; struct S1 { int x; int y; public S1(int y) : this() { } public S1() { } public override string ToString() => (x, y).ToString(); } struct S2 { int x; int y; public S2(int y) : this() { this.y = y; } public S2() { } public override string ToString() => (x, y).ToString(); } struct S3 { int x; int y; public S3(int y) : this() { } public S3() { this.y = -3; } public override string ToString() => (x, y).ToString(); } class Program { static void Main() { Console.WriteLine(new S1(1)); Console.WriteLine(new S1()); Console.WriteLine(new S2(2)); Console.WriteLine(new S2()); Console.WriteLine(new S3(3)); Console.WriteLine(new S3()); } }"; var comp = CreateCompilation(source, parseOptions: TestOptions.Regular10); comp.VerifyDiagnostics( // (11,12): error CS0171: Field 'S1.y' must be fully assigned before control is returned to the caller. Consider updating to language version '11.0' to auto-default the field. // public S1() { } Diagnostic(ErrorCode.ERR_UnassignedThisUnsupportedVersion, "S1").WithArguments("S1.y", "11.0").WithLocation(11, 12), // (11,12): error CS0171: Field 'S1.x' must be fully assigned before control is returned to the caller. Consider updating to language version '11.0' to auto-default the field. // public S1() { } Diagnostic(ErrorCode.ERR_UnassignedThisUnsupportedVersion, "S1").WithArguments("S1.x", "11.0").WithLocation(11, 12), // (22,12): error CS0171: Field 'S2.y' must be fully assigned before control is returned to the caller. Consider updating to language version '11.0' to auto-default the field. // public S2() { } Diagnostic(ErrorCode.ERR_UnassignedThisUnsupportedVersion, "S2").WithArguments("S2.y", "11.0").WithLocation(22, 12), // (22,12): error CS0171: Field 'S2.x' must be fully assigned before control is returned to the caller. Consider updating to language version '11.0' to auto-default the field. // public S2() { } Diagnostic(ErrorCode.ERR_UnassignedThisUnsupportedVersion, "S2").WithArguments("S2.x", "11.0").WithLocation(22, 12), // (32,12): error CS0171: Field 'S3.x' must be fully assigned before control is returned to the caller. Consider updating to language version '11.0' to auto-default the field. // public S3() Diagnostic(ErrorCode.ERR_UnassignedThisUnsupportedVersion, "S3").WithArguments("S3.x", "11.0").WithLocation(32, 12)); var verifier = CompileAndVerify(source, expectedOutput: @"(0, 0) (0, 0) (0, 2) (0, 0) (0, -3) (0, -3) "); verifier.VerifyIL("S1..ctor(int)", @"{ // Code size 7 (0x7) .maxstack 1 IL_0000: ldarg.0 IL_0001: call ""S1..ctor()"" IL_0006: ret }"); verifier.VerifyIL("S1..ctor()", @"{ // Code size 15 (0xf) .maxstack 2 IL_0000: ldarg.0 IL_0001: ldc.i4.0 IL_0002: stfld ""int S1.x"" IL_0007: ldarg.0 IL_0008: ldc.i4.0 IL_0009: stfld ""int S1.y"" IL_000e: ret }"); verifier.VerifyIL("S2..ctor(int)", @"{ // Code size 14 (0xe) .maxstack 2 IL_0000: ldarg.0 IL_0001: call ""S2..ctor()"" IL_0006: ldarg.0 IL_0007: ldarg.1 IL_0008: stfld ""int S2.y"" IL_000d: 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.x"" IL_0007: ldarg.0 IL_0008: ldc.i4.0 IL_0009: stfld ""int S2.y"" IL_000e: ret }"); verifier.VerifyIL("S3..ctor(int)", @"{ // Code size 7 (0x7) .maxstack 1 IL_0000: ldarg.0 IL_0001: call ""S3..ctor()"" IL_0006: ret }"); verifier.VerifyIL("S3..ctor()", @"{ // Code size 16 (0x10) .maxstack 2 IL_0000: ldarg.0 IL_0001: ldc.i4.0 IL_0002: stfld ""int S3.x"" IL_0007: ldarg.0 IL_0008: ldc.i4.s -3 IL_000a: stfld ""int S3.y"" IL_000f: ret }"); } [Fact] public void DefaultThisInitializer_07() { var source = @"#pragma warning disable 169 #pragma warning disable 414 using System; struct S1 { int x = 1; int y; public S1(int y) : this() { } public S1() { } public override string ToString() => (x, y).ToString(); } struct S2 { int x = 2; int y; public S2(int y) : this() { this.y = y; } public S2() { } public override string ToString() => (x, y).ToString(); } struct S3 { int x = 3; int y; public S3(int y) : this() { } public S3() { this.y = -3; } public override string ToString() => (x, y).ToString(); } class Program { static void Main() { Console.WriteLine(new S1(1)); Console.WriteLine(new S1()); Console.WriteLine(new S2(2)); Console.WriteLine(new S2()); Console.WriteLine(new S3(3)); Console.WriteLine(new S3()); } }"; var comp = CreateCompilation(source, parseOptions: TestOptions.Regular10); comp.VerifyDiagnostics( // (11,12): error CS0171: Field 'S1.y' must be fully assigned before control is returned to the caller. Consider updating to language version '11.0' to auto-default the field. // public S1() { } Diagnostic(ErrorCode.ERR_UnassignedThisUnsupportedVersion, "S1").WithArguments("S1.y", "11.0").WithLocation(11, 12), // (22,12): error CS0171: Field 'S2.y' must be fully assigned before control is returned to the caller. Consider updating to language version '11.0' to auto-default the field. // public S2() { } Diagnostic(ErrorCode.ERR_UnassignedThisUnsupportedVersion, "S2").WithArguments("S2.y", "11.0").WithLocation(22, 12)); var verifier = CompileAndVerify(source, expectedOutput: @"(1, 0) (1, 0) (2, 2) (2, 0) (3, -3) (3, -3) "); verifier.VerifyIL("S1..ctor(int)", @"{ // Code size 7 (0x7) .maxstack 1 IL_0000: ldarg.0 IL_0001: call ""S1..ctor()"" IL_0006: ret }"); verifier.VerifyIL("S1..ctor()", @"{ // Code size 15 (0xf) .maxstack 2 IL_0000: ldarg.0 IL_0001: ldc.i4.0 IL_0002: stfld ""int S1.y"" IL_0007: ldarg.0 IL_0008: ldc.i4.1 IL_0009: stfld ""int S1.x"" IL_000e: ret }"); verifier.VerifyIL("S2..ctor(int)", @"{ // Code size 14 (0xe) .maxstack 2 IL_0000: ldarg.0 IL_0001: call ""S2..ctor()"" IL_0006: ldarg.0 IL_0007: ldarg.1 IL_0008: stfld ""int S2.y"" IL_000d: 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.y"" IL_0007: ldarg.0 IL_0008: ldc.i4.2 IL_0009: stfld ""int S2.x"" IL_000e: ret }"); verifier.VerifyIL("S3..ctor(int)", @"{ // Code size 7 (0x7) .maxstack 1 IL_0000: ldarg.0 IL_0001: call ""S3..ctor()"" IL_0006: ret }"); verifier.VerifyIL("S3..ctor()", @"{ // Code size 16 (0x10) .maxstack 2 IL_0000: ldarg.0 IL_0001: ldc.i4.3 IL_0002: stfld ""int S3.x"" IL_0007: ldarg.0 IL_0008: ldc.i4.s -3 IL_000a: stfld ""int S3.y"" IL_000f: ret }"); } [Fact] public void DefaultThisInitializer_08() { var source = @"struct S1 { int x1 = y1 + 1; int y1; public S1(int y) { this.y1 = y; } } record struct R1 { int x1 = y1 + 1; int y1; public R1(int y) { this.y1 = y; } }"; var comp = CreateCompilation(source, parseOptions: TestOptions.Regular10); comp.VerifyDiagnostics( // (3,14): error CS0236: A field initializer cannot reference the non-static field, method, or property 'S1.y1' // int x1 = y1 + 1; Diagnostic(ErrorCode.ERR_FieldInitRefNonstatic, "y1").WithArguments("S1.y1").WithLocation(3, 14), // (3,14): error CS9015: Use of possibly unassigned field 'y1'. Consider updating to language version '11.0' to auto-default the field. // int x1 = y1 + 1; Diagnostic(ErrorCode.ERR_UseDefViolationFieldUnsupportedVersion, "y1").WithArguments("y1", "11.0").WithLocation(3, 14), // (12,14): error CS0236: A field initializer cannot reference the non-static field, method, or property 'R1.y1' // int x1 = y1 + 1; Diagnostic(ErrorCode.ERR_FieldInitRefNonstatic, "y1").WithArguments("R1.y1").WithLocation(12, 14), // (12,14): error CS9015: Use of possibly unassigned field 'y1'. Consider updating to language version '11.0' to auto-default the field. // int x1 = y1 + 1; Diagnostic(ErrorCode.ERR_UseDefViolationFieldUnsupportedVersion, "y1").WithArguments("y1", "11.0").WithLocation(12, 14)); comp = CreateCompilation(source); comp.VerifyDiagnostics( // (3,14): error CS0236: A field initializer cannot reference the non-static field, method, or property 'S1.y1' // int x1 = y1 + 1; Diagnostic(ErrorCode.ERR_FieldInitRefNonstatic, "y1").WithArguments("S1.y1").WithLocation(3, 14), // (12,14): error CS0236: A field initializer cannot reference the non-static field, method, or property 'R1.y1' // int x1 = y1 + 1; Diagnostic(ErrorCode.ERR_FieldInitRefNonstatic, "y1").WithArguments("R1.y1").WithLocation(12, 14)); } [WorkItem(58790, "https://github.com/dotnet/roslyn/issues/58790")] [Theory] [InlineData(LanguageVersion.CSharp10)] [InlineData(null)] public void DefaultThisInitializer_09(LanguageVersion? languageVersion) { var source = @"struct S2 { int x2 = y2 + 1; int y2; public S2(int y) : this() { this.y2 = y; } } record struct R2 { int x2 = y2 + 1; int y2; public R2(int y) : this() { this.y2 = y; } }"; var comp = CreateCompilation(source, parseOptions: GetParseOptions(languageVersion)); comp.VerifyDiagnostics( // (3,14): error CS0236: A field initializer cannot reference the non-static field, method, or property 'S2.y2' // int x2 = y2 + 1; Diagnostic(ErrorCode.ERR_FieldInitRefNonstatic, "y2").WithArguments("S2.y2").WithLocation(3, 14), // (12,14): error CS0236: A field initializer cannot reference the non-static field, method, or property 'R2.y2' // int x2 = y2 + 1; Diagnostic(ErrorCode.ERR_FieldInitRefNonstatic, "y2").WithArguments("R2.y2").WithLocation(12, 14)); } [Fact] public void DefaultThisInitializer_10() { var source = @"struct S3 { int x3 = y3 + 1; int y3; public S3(int y) { this = default; this.y3 = y; } } record struct R3 { int x3 = y3 + 1; int y3; public R3(int y) { this = default; this.y3 = y; } }"; var comp = CreateCompilation(source, parseOptions: TestOptions.Regular10); comp.VerifyDiagnostics( // (3,14): error CS0236: A field initializer cannot reference the non-static field, method, or property 'S3.y3' // int x3 = y3 + 1; Diagnostic(ErrorCode.ERR_FieldInitRefNonstatic, "y3").WithArguments("S3.y3").WithLocation(3, 14), // (3,14): error CS9015: Use of possibly unassigned field 'y3'. Consider updating to language version '11.0' to auto-default the field. // int x3 = y3 + 1; Diagnostic(ErrorCode.ERR_UseDefViolationFieldUnsupportedVersion, "y3").WithArguments("y3", "11.0").WithLocation(3, 14), // (13,14): error CS0236: A field initializer cannot reference the non-static field, method, or property 'R3.y3' // int x3 = y3 + 1; Diagnostic(ErrorCode.ERR_FieldInitRefNonstatic, "y3").WithArguments("R3.y3").WithLocation(13, 14), // (13,14): error CS9015: Use of possibly unassigned field 'y3'. Consider updating to language version '11.0' to auto-default the field. // int x3 = y3 + 1; Diagnostic(ErrorCode.ERR_UseDefViolationFieldUnsupportedVersion, "y3").WithArguments("y3", "11.0").WithLocation(13, 14)); comp = CreateCompilation(source); comp.VerifyDiagnostics( // (3,14): error CS0236: A field initializer cannot reference the non-static field, method, or property 'S3.y3' // int x3 = y3 + 1; Diagnostic(ErrorCode.ERR_FieldInitRefNonstatic, "y3").WithArguments("S3.y3").WithLocation(3, 14), // (13,14): error CS0236: A field initializer cannot reference the non-static field, method, or property 'R3.y3' // int x3 = y3 + 1; Diagnostic(ErrorCode.ERR_FieldInitRefNonstatic, "y3").WithArguments("R3.y3").WithLocation(13, 14)); } [WorkItem(58790, "https://github.com/dotnet/roslyn/issues/58790")] [Fact] public void DefaultThisInitializer_11() { var source = @"#pragma warning disable 169 #pragma warning disable 414 using System; struct S { int x1; int y1 = 1; public S(int unused) { } public S(string unused) : this() { } public override string ToString() => (x1, y1).ToString(); } record struct R { int x2; int y2 = -1; public R(int unused) { } public R(string unused) : this() { } public override string ToString() => (x2, y2).ToString(); } class Program { static void Main() { Console.WriteLine(new S(0)); Console.WriteLine(new S(string.Empty)); Console.WriteLine(new R(0)); Console.WriteLine(new R(string.Empty)); } }"; var comp = CreateCompilation(source, parseOptions: TestOptions.Regular10); comp.VerifyDiagnostics( // (8,12): error CS0171: Field 'S.x1' must be fully assigned before control is returned to the caller. Consider updating to language version '11.0' to auto-default the field. // public S(int unused) { } Diagnostic(ErrorCode.ERR_UnassignedThisUnsupportedVersion, "S").WithArguments("S.x1", "11.0").WithLocation(8, 12), // (16,12): error CS0171: Field 'R.x2' must be fully assigned before control is returned to the caller. Consider updating to language version '11.0' to auto-default the field. // public R(int unused) { } Diagnostic(ErrorCode.ERR_UnassignedThisUnsupportedVersion, "R").WithArguments("R.x2", "11.0").WithLocation(16, 12)); var verifier = CompileAndVerify(source, expectedOutput: @"(0, 1) (0, 1) (0, -1) (0, -1) "); verifier.VerifyIL("S..ctor(int)", @"{ // Code size 15 (0xf) .maxstack 2 IL_0000: ldarg.0 IL_0001: ldc.i4.0 IL_0002: stfld ""int S.x1"" IL_0007: ldarg.0 IL_0008: ldc.i4.1 IL_0009: stfld ""int S.y1"" IL_000e: ret }"); verifier.VerifyIL("S..ctor(string)", @"{ // Code size 15 (0xf) .maxstack 2 IL_0000: ldarg.0 IL_0001: initobj ""S"" IL_0007: ldarg.0 IL_0008: ldc.i4.1 IL_0009: stfld ""int S.y1"" IL_000e: ret }"); verifier.VerifyIL("R..ctor(int)", @"{ // Code size 15 (0xf) .maxstack 2 IL_0000: ldarg.0 IL_0001: ldc.i4.0 IL_0002: stfld ""int R.x2"" IL_0007: ldarg.0 IL_0008: ldc.i4.m1 IL_0009: stfld ""int R.y2"" IL_000e: ret }"); verifier.VerifyIL("R..ctor(string)", @"{ // Code size 15 (0xf) .maxstack 2 IL_0000: ldarg.0 IL_0001: initobj ""R"" IL_0007: ldarg.0 IL_0008: ldc.i4.m1 IL_0009: stfld ""int R.y2"" IL_000e: ret }"); } [WorkItem(58790, "https://github.com/dotnet/roslyn/issues/58790")] [Theory] [InlineData(LanguageVersion.CSharp10)] [InlineData(null)] public void DefaultThisInitializer_12(LanguageVersion? languageVersion) { var source = @"using System; struct S { int x1; int y1 = 1; public S(int unused) { x1 = 2; } public S(string unused) : this() { x1 = 3; } public override string ToString() => (x1, y1).ToString(); } record struct R { int x2; int y2 = -1; public R(int unused) { x2 = -2; } public R(string unused) : this() { x2 = -3; } public override string ToString() => (x2, y2).ToString(); } class Program { static void Main() { Console.WriteLine(new S(0)); Console.WriteLine(new S(string.Empty)); Console.WriteLine(new R(0)); Console.WriteLine(new R(string.Empty)); } }"; var verifier = CompileAndVerify(source, parseOptions: GetParseOptions(languageVersion), expectedOutput: @"(2, 1) (3, 1) (-2, -1) (-3, -1) "); verifier.VerifyIL("S..ctor(int)", @"{ // Code size 15 (0xf) .maxstack 2 IL_0000: ldarg.0 IL_0001: ldc.i4.1 IL_0002: stfld ""int S.y1"" IL_0007: ldarg.0 IL_0008: ldc.i4.2 IL_0009: stfld ""int S.x1"" IL_000e: ret }"); verifier.VerifyIL("S..ctor(string)", @"{ // Code size 22 (0x16) .maxstack 2 IL_0000: ldarg.0 IL_0001: initobj ""S"" IL_0007: ldarg.0 IL_0008: ldc.i4.1 IL_0009: stfld ""int S.y1"" IL_000e: ldarg.0 IL_000f: ldc.i4.3 IL_0010: stfld ""int S.x1"" IL_0015: ret }"); verifier.VerifyIL("R..ctor(int)", @"{ // Code size 16 (0x10) .maxstack 2 IL_0000: ldarg.0 IL_0001: ldc.i4.m1 IL_0002: stfld ""int R.y2"" IL_0007: ldarg.0 IL_0008: ldc.i4.s -2 IL_000a: stfld ""int R.x2"" IL_000f: ret }"); verifier.VerifyIL("R..ctor(string)", @"{ // Code size 23 (0x17) .maxstack 2 IL_0000: ldarg.0 IL_0001: initobj ""R"" IL_0007: ldarg.0 IL_0008: ldc.i4.m1 IL_0009: stfld ""int R.y2"" IL_000e: ldarg.0 IL_000f: ldc.i4.s -3 IL_0011: stfld ""int R.x2"" IL_0016: ret }"); } [Theory] [InlineData(LanguageVersion.CSharp10)] [InlineData(null)] public void DefaultThisInitializer_13(LanguageVersion? languageVersion) { var source = @"#pragma warning disable 169 struct S { int x1; int y1; public S() : this() { } } record struct R { int x2; int y2; public R() : this() { } }"; var comp = CreateCompilation(source, parseOptions: GetParseOptions(languageVersion)); comp.VerifyDiagnostics( // (6,18): error CS0516: Constructor 'S.S()' cannot call itself // public S() : this() { } Diagnostic(ErrorCode.ERR_RecursiveConstructorCall, "this").WithArguments("S.S()").WithLocation(6, 18), // (12,18): error CS0516: Constructor 'R.R()' cannot call itself // public R() : this() { } Diagnostic(ErrorCode.ERR_RecursiveConstructorCall, "this").WithArguments("R.R()").WithLocation(12, 18)); } [Theory] [InlineData(LanguageVersion.CSharp10)] [InlineData(null)] public void DefaultThisInitializer_14(LanguageVersion? languageVersion) { var source = @"#pragma warning disable 169 struct S { int x1; int y1 = 1; public S() : this() { } } record struct R { int x2; int y2 = 2; public R() : this() { } }"; var comp = CreateCompilation(source, parseOptions: GetParseOptions(languageVersion)); comp.VerifyDiagnostics( // (6,18): error CS0516: Constructor 'S.S()' cannot call itself // public S() : this() { } Diagnostic(ErrorCode.ERR_RecursiveConstructorCall, "this").WithArguments("S.S()").WithLocation(6, 18), // (12,18): error CS0516: Constructor 'R.R()' cannot call itself // public R() : this() { } Diagnostic(ErrorCode.ERR_RecursiveConstructorCall, "this").WithArguments("R.R()").WithLocation(12, 18)); } [Fact] public void FieldInitializers_None() { var source = @"#pragma warning disable 649 using System; struct S0 { object X; object Y; public override string ToString() => (X, Y).ToString(); } struct S1 { object X; object Y; public S1() { Y = 1; } public override string ToString() => (X, Y).ToString(); } struct S2 { object X; object Y; public S2(object y) { Y = y; } public override string ToString() => (X, Y).ToString(); } class Program { static void Main() { Console.WriteLine(new S0()); Console.WriteLine(new S1()); Console.WriteLine(new S2()); } }"; var comp = CreateCompilation(source, parseOptions: TestOptions.Regular9); comp.VerifyDiagnostics( // (13,12): error CS8773: Feature 'parameterless struct constructors' is not available in C# 9.0. Please use language version 10.0 or greater. // public S1() { Y = 1; } Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion9, "S1").WithArguments("parameterless struct constructors", "10.0").WithLocation(13, 12), // (13,12): error CS0171: Field 'S1.X' must be fully assigned before control is returned to the caller. Consider updating to language version '11.0' to auto-default the field. // public S1() { Y = 1; } Diagnostic(ErrorCode.ERR_UnassignedThisUnsupportedVersion, "S1").WithArguments("S1.X", "11.0").WithLocation(13, 12), // (20,12): error CS0171: Field 'S2.X' must be fully assigned before control is returned to the caller. Consider updating to language version '11.0' to auto-default the field. // public S2(object y) { Y = y; } Diagnostic(ErrorCode.ERR_UnassignedThisUnsupportedVersion, "S2").WithArguments("S2.X", "11.0").WithLocation(20, 12)); var verifier = CompileAndVerify(source, parseOptions: TestOptions.Regular11, expectedOutput: @"(, ) (, 1) (, )"); verifier.VerifyDiagnostics(); } [Fact] public void FieldInitializers_None_WithEmptyParameterlessConstructor() { var source = @"#pragma warning disable 649 using System; struct S0 { object X; object Y; public S0() { } public override string ToString() => (X, Y).ToString(); } class Program { static void Main() { Console.WriteLine(new S0()); } }"; var comp = CreateCompilation(source, parseOptions: TestOptions.Regular9); comp.VerifyDiagnostics( // (7,12): error CS8773: Feature 'parameterless struct constructors' is not available in C# 9.0. Please use language version 10.0 or greater. // public S0() { } Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion9, "S0").WithArguments("parameterless struct constructors", "10.0").WithLocation(7, 12), // (7,12): error CS0171: Field 'S0.Y' must be fully assigned before control is returned to the caller. Consider updating to language version '11.0' to auto-default the field. // public S0() { } Diagnostic(ErrorCode.ERR_UnassignedThisUnsupportedVersion, "S0").WithArguments("S0.Y", "11.0").WithLocation(7, 12), // (7,12): error CS0171: Field 'S0.X' must be fully assigned before control is returned to the caller. Consider updating to language version '11.0' to auto-default the field. // public S0() { } Diagnostic(ErrorCode.ERR_UnassignedThisUnsupportedVersion, "S0").WithArguments("S0.X", "11.0").WithLocation(7, 12)); var verifier = CompileAndVerify(source, parseOptions: TestOptions.Regular11, expectedOutput: "(, )"); verifier.VerifyDiagnostics(); verifier.VerifyIL("S0..ctor", @" { // Code size 15 (0xf) .maxstack 2 // sequence point: <hidden> IL_0000: ldarg.0 IL_0001: ldnull IL_0002: stfld ""object S0.X"" IL_0007: ldarg.0 IL_0008: ldnull IL_0009: stfld ""object S0.Y"" // sequence point: } IL_000e: ret } ", sequencePointDisplay: SequencePointDisplayMode.Enhanced); } [Fact] public void FieldInitializers_01() { var source = @"#pragma warning disable 649 using System; struct S2 { object X = null; object Y; public S2() { Y = 1; } public override string ToString() => (X, Y).ToString(); } struct S3 { object X; object Y = null; public S3(object x) { X = x; } public override string ToString() => (X, Y).ToString(); } class Program { static void Main() { Console.WriteLine(new S2()); Console.WriteLine(new S3()); } }"; var comp = CreateCompilation(source, parseOptions: TestOptions.Regular9); comp.VerifyDiagnostics( // (5,12): error CS8773: Feature 'struct field initializers' is not available in C# 9.0. Please use language version 10.0 or greater. // object X = null; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion9, "X").WithArguments("struct field initializers", "10.0").WithLocation(5, 12), // (7,12): error CS8773: Feature 'parameterless struct constructors' is not available in C# 9.0. Please use language version 10.0 or greater. // public S2() { Y = 1; } Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion9, "S2").WithArguments("parameterless struct constructors", "10.0").WithLocation(7, 12), // (13,12): error CS8773: Feature 'struct field initializers' is not available in C# 9.0. Please use language version 10.0 or greater. // object Y = null; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion9, "Y").WithArguments("struct field initializers", "10.0").WithLocation(13, 12)); comp = CreateCompilation(source, options: TestOptions.ReleaseExe); comp.VerifyDiagnostics(); var verifier = CompileAndVerify(comp, expectedOutput: @"(, 1) (, )"); verifier.VerifyIL("Program.Main", @"{ // Code size 35 (0x23) .maxstack 1 .locals init (S3 V_0) IL_0000: newobj ""S2..ctor()"" IL_0005: box ""S2"" IL_000a: call ""void System.Console.WriteLine(object)"" IL_000f: ldloca.s V_0 IL_0011: initobj ""S3"" IL_0017: ldloc.0 IL_0018: box ""S3"" IL_001d: call ""void System.Console.WriteLine(object)"" IL_0022: ret }"); verifier.VerifyIL("S2..ctor()", @"{ // Code size 20 (0x14) .maxstack 2 IL_0000: ldarg.0 IL_0001: ldnull IL_0002: stfld ""object S2.X"" IL_0007: ldarg.0 IL_0008: ldc.i4.1 IL_0009: box ""int"" IL_000e: stfld ""object S2.Y"" IL_0013: ret }"); verifier.VerifyMissing("S3..ctor()"); verifier.VerifyIL("S3..ctor(object)", @"{ // Code size 15 (0xf) .maxstack 2 IL_0000: ldarg.0 IL_0001: ldnull IL_0002: stfld ""object S3.Y"" IL_0007: ldarg.0 IL_0008: ldarg.1 IL_0009: stfld ""object S3.X"" IL_000e: ret }"); } [Fact] public void FieldInitializers_02() { var source = @"#pragma warning disable 649 using System; struct S2 { internal object X = 2; internal object Y; public S2() { Y = 2; } public override string ToString() => (X, Y).ToString(); } struct S3 { internal object X = 3; internal object Y; public S3(object _) { Y = 3; } public override string ToString() => (X, Y).ToString(); } class Program { static void Main() { Console.WriteLine(new S2()); Console.WriteLine(new S3()); Console.WriteLine(new S2 { }); Console.WriteLine(new S3 { }); Console.WriteLine(new S2 { Y = 4 }); Console.WriteLine(new S3 { Y = 6 }); } }"; var verifier = CompileAndVerify(source, options: TestOptions.ReleaseExe, expectedOutput: @"(2, 2) (, ) (2, 2) (, ) (2, 4) (, 6)"); verifier.VerifyIL("Program.Main", @"{ // Code size 132 (0x84) .maxstack 2 .locals init (S3 V_0, S2 V_1) IL_0000: newobj ""S2..ctor()"" IL_0005: box ""S2"" IL_000a: call ""void System.Console.WriteLine(object)"" IL_000f: ldloca.s V_0 IL_0011: initobj ""S3"" IL_0017: ldloc.0 IL_0018: box ""S3"" IL_001d: call ""void System.Console.WriteLine(object)"" IL_0022: newobj ""S2..ctor()"" IL_0027: box ""S2"" IL_002c: call ""void System.Console.WriteLine(object)"" IL_0031: ldloca.s V_0 IL_0033: initobj ""S3"" IL_0039: ldloc.0 IL_003a: box ""S3"" IL_003f: call ""void System.Console.WriteLine(object)"" IL_0044: ldloca.s V_1 IL_0046: call ""S2..ctor()"" IL_004b: ldloca.s V_1 IL_004d: ldc.i4.4 IL_004e: box ""int"" IL_0053: stfld ""object S2.Y"" IL_0058: ldloc.1 IL_0059: box ""S2"" IL_005e: call ""void System.Console.WriteLine(object)"" IL_0063: ldloca.s V_0 IL_0065: initobj ""S3"" IL_006b: ldloca.s V_0 IL_006d: ldc.i4.6 IL_006e: box ""int"" IL_0073: stfld ""object S3.Y"" IL_0078: ldloc.0 IL_0079: box ""S3"" IL_007e: call ""void System.Console.WriteLine(object)"" IL_0083: ret }"); verifier.VerifyIL("S2..ctor()", @"{ // Code size 25 (0x19) .maxstack 2 IL_0000: ldarg.0 IL_0001: ldc.i4.2 IL_0002: box ""int"" IL_0007: stfld ""object S2.X"" IL_000c: ldarg.0 IL_000d: ldc.i4.2 IL_000e: box ""int"" IL_0013: stfld ""object S2.Y"" IL_0018: ret }"); verifier.VerifyMissing("S3..ctor()"); verifier.VerifyIL("S3..ctor(object)", @"{ // Code size 25 (0x19) .maxstack 2 IL_0000: ldarg.0 IL_0001: ldc.i4.3 IL_0002: box ""int"" IL_0007: stfld ""object S3.X"" IL_000c: ldarg.0 IL_000d: ldc.i4.3 IL_000e: box ""int"" IL_0013: stfld ""object S3.Y"" IL_0018: ret }"); } // As above but with auto-properties. [Fact] public void FieldInitializers_03() { var source = @"#pragma warning disable 649 using System; struct S2 { internal object X { get; init; } = 2; internal object Y { get; init; } public S2() { Y = 2; } public override string ToString() => (X, Y).ToString(); } struct S3 { internal object X { get; private set; } = 3; internal object Y { get; set; } public S3(object _) { Y = 3; } public override string ToString() => (X, Y).ToString(); } class Program { static void Main() { Console.WriteLine(new S2()); Console.WriteLine(new S3()); Console.WriteLine(new S2 { }); Console.WriteLine(new S3 { }); Console.WriteLine(new S2 { Y = 4 }); Console.WriteLine(new S3 { Y = 6 }); } }"; var verifier = CompileAndVerify(new[] { source, IsExternalInitTypeDefinition }, options: TestOptions.ReleaseExe, verify: Verification.Skipped, expectedOutput: @"(2, 2) (, ) (2, 2) (, ) (2, 4) (, 6)"); verifier.VerifyIL("Program.Main", @"{ // Code size 132 (0x84) .maxstack 2 .locals init (S3 V_0, S2 V_1) IL_0000: newobj ""S2..ctor()"" IL_0005: box ""S2"" IL_000a: call ""void System.Console.WriteLine(object)"" IL_000f: ldloca.s V_0 IL_0011: initobj ""S3"" IL_0017: ldloc.0 IL_0018: box ""S3"" IL_001d: call ""void System.Console.WriteLine(object)"" IL_0022: newobj ""S2..ctor()"" IL_0027: box ""S2"" IL_002c: call ""void System.Console.WriteLine(object)"" IL_0031: ldloca.s V_0 IL_0033: initobj ""S3"" IL_0039: ldloc.0 IL_003a: box ""S3"" IL_003f: call ""void System.Console.WriteLine(object)"" IL_0044: ldloca.s V_1 IL_0046: call ""S2..ctor()"" IL_004b: ldloca.s V_1 IL_004d: ldc.i4.4 IL_004e: box ""int"" IL_0053: call ""void S2.Y.init"" IL_0058: ldloc.1 IL_0059: box ""S2"" IL_005e: call ""void System.Console.WriteLine(object)"" IL_0063: ldloca.s V_0 IL_0065: initobj ""S3"" IL_006b: ldloca.s V_0 IL_006d: ldc.i4.6 IL_006e: box ""int"" IL_0073: call ""void S3.Y.set"" IL_0078: ldloc.0 IL_0079: box ""S3"" IL_007e: call ""void System.Console.WriteLine(object)"" IL_0083: ret }"); verifier.VerifyIL("S2..ctor()", @"{ // Code size 25 (0x19) .maxstack 2 IL_0000: ldarg.0 IL_0001: ldc.i4.2 IL_0002: box ""int"" IL_0007: stfld ""object S2.<X>k__BackingField"" IL_000c: ldarg.0 IL_000d: ldc.i4.2 IL_000e: box ""int"" IL_0013: call ""void S2.Y.init"" IL_0018: ret }"); verifier.VerifyMissing("S3..ctor()"); verifier.VerifyIL("S3..ctor(object)", @"{ // Code size 25 (0x19) .maxstack 2 IL_0000: ldarg.0 IL_0001: ldc.i4.3 IL_0002: box ""int"" IL_0007: stfld ""object S3.<X>k__BackingField"" IL_000c: ldarg.0 IL_000d: ldc.i4.3 IL_000e: box ""int"" IL_0013: call ""void S3.Y.set"" IL_0018: ret }"); } [Fact] public void FieldInitializers_04A() { var source = @"#pragma warning disable 649 using System; struct S1<T> { internal int X = 1; } class Program { static void Main() { Console.WriteLine(new S1<object>().X); } }"; var comp = CreateCompilation(source); comp.VerifyDiagnostics( // (3,8): error CS8983: A 'struct' with field initializers must include an explicitly declared constructor. // struct S1<T> { internal int X = 1; } Diagnostic(ErrorCode.ERR_StructHasInitializersAndNoDeclaredConstructor, "S1").WithLocation(3, 8)); } [Fact] public void FieldInitializers_04B() { var source = @"#pragma warning disable 649 using System; struct S2<T> { internal int X = 2; public S2() { } } struct S3<T> { internal int X = 3; public S3(int _) { } } class Program { static void Main() { Console.WriteLine(new S2<object>().X); Console.WriteLine(new S3<object>().X); } }"; var verifier = CompileAndVerify(source, options: TestOptions.ReleaseExe, expectedOutput: @"2 0"); verifier.VerifyIL("Program.Main", @"{ // Code size 35 (0x23) .maxstack 1 .locals init (S3<object> V_0) IL_0000: newobj ""S2<object>..ctor()"" IL_0005: ldfld ""int S2<object>.X"" IL_000a: call ""void System.Console.WriteLine(int)"" IL_000f: ldloca.s V_0 IL_0011: initobj ""S3<object>"" IL_0017: ldloc.0 IL_0018: ldfld ""int S3<object>.X"" IL_001d: call ""void System.Console.WriteLine(int)"" IL_0022: ret }"); } [Fact] public void FieldInitializers_05A() { var source = @"#pragma warning disable 649 using System; class A<T> { internal struct S1 { internal int X { get; } = 1; } } class Program { static void Main() { Console.WriteLine(new A<object>.S1().X); } }"; var comp = CreateCompilation(source); comp.VerifyDiagnostics( // (5,21): error CS8983: A 'struct' with field initializers must include an explicitly declared constructor. // internal struct S1 { internal int X { get; } = 1; } Diagnostic(ErrorCode.ERR_StructHasInitializersAndNoDeclaredConstructor, "S1").WithLocation(5, 21)); } [Fact] public void FieldInitializers_05B() { var source = @"#pragma warning disable 649 using System; class A<T> { internal struct S2 { internal int X { get; init; } = 2; public S2() { } } internal struct S3 { internal int X { get; set; } = 3; public S3(int _) { } } } class Program { static void Main() { Console.WriteLine(new A<object>.S2().X); Console.WriteLine(new A<object>.S3().X); } }"; var verifier = CompileAndVerify(new[] { source, IsExternalInitTypeDefinition }, options: TestOptions.ReleaseExe, verify: Verification.Skipped, expectedOutput: @"2 0"); verifier.VerifyIL("Program.Main", @"{ // Code size 38 (0x26) .maxstack 2 .locals init (A<object>.S2 V_0, A<object>.S3 V_1) IL_0000: newobj ""A<object>.S2..ctor()"" IL_0005: stloc.0 IL_0006: ldloca.s V_0 IL_0008: call ""readonly int A<object>.S2.X.get"" IL_000d: call ""void System.Console.WriteLine(int)"" IL_0012: ldloca.s V_1 IL_0014: dup IL_0015: initobj ""A<object>.S3"" IL_001b: call ""readonly int A<object>.S3.X.get"" IL_0020: call ""void System.Console.WriteLine(int)"" IL_0025: ret }"); verifier.VerifyIL("A<T>.S2..ctor()", @"{ // Code size 8 (0x8) .maxstack 2 IL_0000: ldarg.0 IL_0001: ldc.i4.2 IL_0002: stfld ""int A<T>.S2.<X>k__BackingField"" IL_0007: ret }"); verifier.VerifyIL("A<T>.S3..ctor(int)", @"{ // Code size 8 (0x8) .maxstack 2 IL_0000: ldarg.0 IL_0001: ldc.i4.3 IL_0002: stfld ""int A<T>.S3.<X>k__BackingField"" IL_0007: ret }"); } [WorkItem(57870, "https://github.com/dotnet/roslyn/issues/57870")] [Fact] public void FieldInitializers_06() { var source = @"#pragma warning disable 649 struct S1 { internal object X = null; internal object Y; } struct S2 { internal object X = 2; internal object Y; public S2() { } } struct S3 { internal object X; internal object Y = 3; public S3() { Y = 3; } } struct S4 { internal object X; internal object Y = 4; public S4() { X = 4; } }"; var comp = CreateCompilation(source, parseOptions: TestOptions.Regular9); comp.VerifyDiagnostics( // (2,8): error CS8983: A 'struct' with field initializers must include an explicitly declared constructor. // struct S1 Diagnostic(ErrorCode.ERR_StructHasInitializersAndNoDeclaredConstructor, "S1").WithLocation(2, 8), // (4,21): error CS8773: Feature 'struct field initializers' is not available in C# 9.0. Please use language version 10.0 or greater. // internal object X = null; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion9, "X").WithArguments("struct field initializers", "10.0").WithLocation(4, 21), // (9,21): error CS8773: Feature 'struct field initializers' is not available in C# 9.0. Please use language version 10.0 or greater. // internal object X = 2; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion9, "X").WithArguments("struct field initializers", "10.0").WithLocation(9, 21), // (11,12): error CS8773: Feature 'parameterless struct constructors' is not available in C# 9.0. Please use language version 10.0 or greater. // public S2() { } Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion9, "S2").WithArguments("parameterless struct constructors", "10.0").WithLocation(11, 12), // (11,12): error CS0171: Field 'S2.Y' must be fully assigned before control is returned to the caller. Consider updating to language version '11.0' to auto-default the field. // public S2() { } Diagnostic(ErrorCode.ERR_UnassignedThisUnsupportedVersion, "S2").WithArguments("S2.Y", "11.0").WithLocation(11, 12), // (16,21): error CS8773: Feature 'struct field initializers' is not available in C# 9.0. Please use language version 10.0 or greater. // internal object Y = 3; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion9, "Y").WithArguments("struct field initializers", "10.0").WithLocation(16, 21), // (17,12): error CS8773: Feature 'parameterless struct constructors' is not available in C# 9.0. Please use language version 10.0 or greater. // public S3() { Y = 3; } Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion9, "S3").WithArguments("parameterless struct constructors", "10.0").WithLocation(17, 12), // (17,12): error CS0171: Field 'S3.X' must be fully assigned before control is returned to the caller. Consider updating to language version '11.0' to auto-default the field. // public S3() { Y = 3; } Diagnostic(ErrorCode.ERR_UnassignedThisUnsupportedVersion, "S3").WithArguments("S3.X", "11.0").WithLocation(17, 12), // (22,21): error CS8773: Feature 'struct field initializers' is not available in C# 9.0. Please use language version 10.0 or greater. // internal object Y = 4; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion9, "Y").WithArguments("struct field initializers", "10.0").WithLocation(22, 21), // (23,12): error CS8773: Feature 'parameterless struct constructors' is not available in C# 9.0. Please use language version 10.0 or greater. // public S4() { X = 4; } Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion9, "S4").WithArguments("parameterless struct constructors", "10.0").WithLocation(23, 12)); comp = CreateCompilation(source, parseOptions: TestOptions.Regular10); comp.VerifyDiagnostics( // (2,8): error CS8983: A 'struct' with field initializers must include an explicitly declared constructor. // struct S1 Diagnostic(ErrorCode.ERR_StructHasInitializersAndNoDeclaredConstructor, "S1").WithLocation(2, 8), // (11,12): error CS0171: Field 'S2.Y' must be fully assigned before control is returned to the caller. Consider updating to language version '11.0' to auto-default the field. // public S2() { } Diagnostic(ErrorCode.ERR_UnassignedThisUnsupportedVersion, "S2").WithArguments("S2.Y", "11.0").WithLocation(11, 12), // (17,12): error CS0171: Field 'S3.X' must be fully assigned before control is returned to the caller. Consider updating to language version '11.0' to auto-default the field. // public S3() { Y = 3; } Diagnostic(ErrorCode.ERR_UnassignedThisUnsupportedVersion, "S3").WithArguments("S3.X", "11.0").WithLocation(17, 12)); comp = CreateCompilation(source, parseOptions: TestOptions.Regular11); comp.VerifyDiagnostics( // (2,8): error CS8983: A 'struct' with field initializers must include an explicitly declared constructor. // struct S1 Diagnostic(ErrorCode.ERR_StructHasInitializersAndNoDeclaredConstructor, "S1").WithLocation(2, 8)); } [WorkItem(57870, "https://github.com/dotnet/roslyn/issues/57870")] [Fact] public void FieldInitializers_07() { var source = @"#pragma warning disable 649 struct S1 { internal object X { get; } = null; internal object Y { get; } } struct S2 { internal object X { get; } = 2; internal object Y { get; } public S2() { } } struct S3 { internal object X { get; } internal object Y { get; } = 3; public S3() { Y = 3; } } struct S4 { internal object X { get; } internal object Y { get; } = 4; public S4() { X = 4; } }"; var comp = CreateCompilation(source, parseOptions: TestOptions.Regular9); comp.VerifyDiagnostics( // (2,8): error CS8983: A 'struct' with field initializers must include an explicitly declared constructor. // struct S1 Diagnostic(ErrorCode.ERR_StructHasInitializersAndNoDeclaredConstructor, "S1").WithLocation(2, 8), // (4,21): error CS8773: Feature 'struct field initializers' is not available in C# 9.0. Please use language version 10.0 or greater. // internal object X { get; } = null; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion9, "X").WithArguments("struct field initializers", "10.0").WithLocation(4, 21), // (9,21): error CS8773: Feature 'struct field initializers' is not available in C# 9.0. Please use language version 10.0 or greater. // internal object X { get; } = 2; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion9, "X").WithArguments("struct field initializers", "10.0").WithLocation(9, 21), // (11,12): error CS8773: Feature 'parameterless struct constructors' is not available in C# 9.0. Please use language version 10.0 or greater. // public S2() { } Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion9, "S2").WithArguments("parameterless struct constructors", "10.0").WithLocation(11, 12), // (11,12): error CS0843: Auto-implemented property 'S2.Y' must be fully assigned before control is returned to the caller. Consider updating to language version '11.0' to auto-default the property. // public S2() { } Diagnostic(ErrorCode.ERR_UnassignedThisAutoPropertyUnsupportedVersion, "S2").WithArguments("S2.Y", "11.0").WithLocation(11, 12), // (16,21): error CS8773: Feature 'struct field initializers' is not available in C# 9.0. Please use language version 10.0 or greater. // internal object Y { get; } = 3; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion9, "Y").WithArguments("struct field initializers", "10.0").WithLocation(16, 21), // (17,12): error CS8773: Feature 'parameterless struct constructors' is not available in C# 9.0. Please use language version 10.0 or greater. // public S3() { Y = 3; } Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion9, "S3").WithArguments("parameterless struct constructors", "10.0").WithLocation(17, 12), // (17,12): error CS0843: Auto-implemented property 'S3.X' must be fully assigned before control is returned to the caller. Consider updating to language version '11.0' to auto-default the property. // public S3() { Y = 3; } Diagnostic(ErrorCode.ERR_UnassignedThisAutoPropertyUnsupportedVersion, "S3").WithArguments("S3.X", "11.0").WithLocation(17, 12), // (22,21): error CS8773: Feature 'struct field initializers' is not available in C# 9.0. Please use language version 10.0 or greater. // internal object Y { get; } = 4; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion9, "Y").WithArguments("struct field initializers", "10.0").WithLocation(22, 21), // (23,12): error CS8773: Feature 'parameterless struct constructors' is not available in C# 9.0. Please use language version 10.0 or greater. // public S4() { X = 4; } Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion9, "S4").WithArguments("parameterless struct constructors", "10.0").WithLocation(23, 12)); comp = CreateCompilation(source, parseOptions: TestOptions.Regular10); comp.VerifyDiagnostics( // (2,8): error CS8983: A 'struct' with field initializers must include an explicitly declared constructor. // struct S1 Diagnostic(ErrorCode.ERR_StructHasInitializersAndNoDeclaredConstructor, "S1").WithLocation(2, 8), // (11,12): error CS0843: Auto-implemented property 'S2.Y' must be fully assigned before control is returned to the caller. Consider updating to language version '11.0' to auto-default the property. // public S2() { } Diagnostic(ErrorCode.ERR_UnassignedThisAutoPropertyUnsupportedVersion, "S2").WithArguments("S2.Y", "11.0").WithLocation(11, 12), // (17,12): error CS0843: Auto-implemented property 'S3.X' must be fully assigned before control is returned to the caller. Consider updating to language version '11.0' to auto-default the property. // public S3() { Y = 3; } Diagnostic(ErrorCode.ERR_UnassignedThisAutoPropertyUnsupportedVersion, "S3").WithArguments("S3.X", "11.0").WithLocation(17, 12)); comp = CreateCompilation(source, parseOptions: TestOptions.Regular11); comp.VerifyDiagnostics( // (2,8): error CS8983: A 'struct' with field initializers must include an explicitly declared constructor. // struct S1 Diagnostic(ErrorCode.ERR_StructHasInitializersAndNoDeclaredConstructor, "S1").WithLocation(2, 8)); } [WorkItem(57870, "https://github.com/dotnet/roslyn/issues/57870")] [Fact] public void FieldInitializers_08() { var source = @"#pragma warning disable 649 record struct S1 { internal object X = 1; internal object Y; } record struct S2 { internal object X { get; } = 2; internal object Y { get; } public S2() { } } record struct S3 { internal object X { get; init; } internal object Y { get; init; } = 3; public S3() { Y = 3; } } record struct S4 { internal object X { get; init; } internal object Y { get; init; } = 4; public S4() { X = 4; } } "; var comp = CreateCompilation(new[] { source, IsExternalInitTypeDefinition }, parseOptions: TestOptions.Regular10); comp.VerifyDiagnostics( // (2,15): error CS8983: A 'struct' with field initializers must include an explicitly declared constructor. // record struct S1 Diagnostic(ErrorCode.ERR_StructHasInitializersAndNoDeclaredConstructor, "S1").WithLocation(2, 15), // (11,12): error CS0843: Auto-implemented property 'S2.Y' must be fully assigned before control is returned to the caller. Consider updating to language version '11.0' to auto-default the property. // public S2() { } Diagnostic(ErrorCode.ERR_UnassignedThisAutoPropertyUnsupportedVersion, "S2").WithArguments("S2.Y", "11.0").WithLocation(11, 12), // (17,12): error CS0843: Auto-implemented property 'S3.X' must be fully assigned before control is returned to the caller. Consider updating to language version '11.0' to auto-default the property. // public S3() { Y = 3; } Diagnostic(ErrorCode.ERR_UnassignedThisAutoPropertyUnsupportedVersion, "S3").WithArguments("S3.X", "11.0").WithLocation(17, 12)); comp = CreateCompilation(new[] { source, IsExternalInitTypeDefinition }, parseOptions: TestOptions.Regular11); comp.VerifyDiagnostics( // (2,15): error CS8983: A 'struct' with field initializers must include an explicitly declared constructor. // record struct S1 Diagnostic(ErrorCode.ERR_StructHasInitializersAndNoDeclaredConstructor, "S1").WithLocation(2, 15)); } [Fact] public void FieldInitializers_09() { var source = @" using System; #pragma warning disable 649 record struct S1() { public object X = 1; public object Y; } record struct S2() { public object X { get; } = 2; public object Y { get; } } record struct S3() { public object X { get; init; } public object Y { get; init; } = 3; } class Program { static void Main() { Console.WriteLine(new S1()); Console.WriteLine(new S2()); Console.WriteLine(new S3()); } } "; var comp = CreateCompilation(new[] { source, IsExternalInitTypeDefinition }, parseOptions: TestOptions.Regular10); comp.VerifyDiagnostics( // (5,15): error CS0171: Field 'S1.Y' 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 S1() Diagnostic(ErrorCode.ERR_UnassignedThisUnsupportedVersion, "S1").WithArguments("S1.Y", "11.0").WithLocation(5, 15), // (10,15): error CS0843: Auto-implemented property 'S2.Y' must be fully assigned before control is returned to the caller. Consider updating to language version '11.0' to auto-default the property. // record struct S2() Diagnostic(ErrorCode.ERR_UnassignedThisAutoPropertyUnsupportedVersion, "S2").WithArguments("S2.Y", "11.0").WithLocation(10, 15), // (15,15): error CS0843: Auto-implemented property 'S3.X' must be fully assigned before control is returned to the caller. Consider updating to language version '11.0' to auto-default the property. // record struct S3() Diagnostic(ErrorCode.ERR_UnassignedThisAutoPropertyUnsupportedVersion, "S3").WithArguments("S3.X", "11.0").WithLocation(15, 15)); var verifier = CompileAndVerify(new[] { source, IsExternalInitTypeDefinition }, parseOptions: TestOptions.Regular11, expectedOutput: @" S1 { X = 1, Y = } S2 { X = 2, Y = } S3 { X = , Y = 3 } ", verify: Verification.Skipped); verifier.VerifyDiagnostics(); verifier.VerifyIL("S1..ctor", @" { // Code size 20 (0x14) .maxstack 2 // sequence point: <hidden> IL_0000: ldarg.0 IL_0001: ldnull IL_0002: stfld ""object S1.Y"" // sequence point: public object X = 1; IL_0007: ldarg.0 IL_0008: ldc.i4.1 IL_0009: box ""int"" IL_000e: stfld ""object S1.X"" IL_0013: ret }", sequencePointDisplay: SequencePointDisplayMode.Enhanced); verifier.VerifyIL("S2..ctor", @" { // Code size 20 (0x14) .maxstack 2 // sequence point: <hidden> IL_0000: ldarg.0 IL_0001: ldnull IL_0002: stfld ""object S2.<Y>k__BackingField"" // sequence point: 2 IL_0007: ldarg.0 IL_0008: ldc.i4.2 IL_0009: box ""int"" IL_000e: stfld ""object S2.<X>k__BackingField"" IL_0013: ret }", sequencePointDisplay: SequencePointDisplayMode.Enhanced); verifier.VerifyIL("S3..ctor", @" { // Code size 20 (0x14) .maxstack 2 // sequence point: <hidden> IL_0000: ldarg.0 IL_0001: ldnull IL_0002: stfld ""object S3.<X>k__BackingField"" // sequence point: 3 IL_0007: ldarg.0 IL_0008: ldc.i4.3 IL_0009: box ""int"" IL_000e: stfld ""object S3.<Y>k__BackingField"" IL_0013: ret }", sequencePointDisplay: SequencePointDisplayMode.Enhanced); } [Fact] public void FieldInitializers_10() { var source = @" using System; #pragma warning disable 649 record struct S1(object X) { public object X = 1; public object Y; } record struct S2(object X) { public object X { get; } = 2; public object Y { get; } } record struct S3(object Y) { public object X { get; init; } public object Y { get; init; } = 3; } class Program { static void Main() { Console.WriteLine(new S1(""a"")); Console.WriteLine(new S2(""b"")); Console.WriteLine(new S3(""c"")); } } "; var comp = CreateCompilation(new[] { source, IsExternalInitTypeDefinition }, parseOptions: TestOptions.Regular10); comp.VerifyDiagnostics( // (5,15): error CS0171: Field 'S1.Y' 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 S1(object X) Diagnostic(ErrorCode.ERR_UnassignedThisUnsupportedVersion, "S1").WithArguments("S1.Y", "11.0").WithLocation(5, 15), // (5,25): warning CS8907: Parameter 'X' is unread. Did you forget to use it to initialize the property with that name? // record struct S1(object X) Diagnostic(ErrorCode.WRN_UnreadRecordParameter, "X").WithArguments("X").WithLocation(5, 25), // (10,15): error CS0843: Auto-implemented property 'S2.Y' must be fully assigned before control is returned to the caller. Consider updating to language version '11.0' to auto-default the property. // record struct S2(object X) Diagnostic(ErrorCode.ERR_UnassignedThisAutoPropertyUnsupportedVersion, "S2").WithArguments("S2.Y", "11.0").WithLocation(10, 15), // (10,25): warning CS8907: Parameter 'X' is unread. Did you forget to use it to initialize the property with that name? // record struct S2(object X) Diagnostic(ErrorCode.WRN_UnreadRecordParameter, "X").WithArguments("X").WithLocation(10, 25), // (15,15): error CS0843: Auto-implemented property 'S3.X' must be fully assigned before control is returned to the caller. Consider updating to language version '11.0' to auto-default the property. // record struct S3(object Y) Diagnostic(ErrorCode.ERR_UnassignedThisAutoPropertyUnsupportedVersion, "S3").WithArguments("S3.X", "11.0").WithLocation(15, 15), // (15,25): warning CS8907: Parameter 'Y' is unread. Did you forget to use it to initialize the property with that name? // record struct S3(object Y) Diagnostic(ErrorCode.WRN_UnreadRecordParameter, "Y").WithArguments("Y").WithLocation(15, 25)); var verifier = CompileAndVerify(new[] { source, IsExternalInitTypeDefinition }, parseOptions: TestOptions.Regular11, expectedOutput: @"S1 { X = 1, Y = } S2 { X = 2, Y = } S3 { X = , Y = 3 } ", verify: Verification.Skipped); verifier.VerifyDiagnostics( // (5,25): warning CS8907: Parameter 'X' is unread. Did you forget to use it to initialize the property with that name? // record struct S1(object X) Diagnostic(ErrorCode.WRN_UnreadRecordParameter, "X").WithArguments("X").WithLocation(5, 25), // (10,25): warning CS8907: Parameter 'X' is unread. Did you forget to use it to initialize the property with that name? // record struct S2(object X) Diagnostic(ErrorCode.WRN_UnreadRecordParameter, "X").WithArguments("X").WithLocation(10, 25), // (15,25): warning CS8907: Parameter 'Y' is unread. Did you forget to use it to initialize the property with that name? // record struct S3(object Y) Diagnostic(ErrorCode.WRN_UnreadRecordParameter, "Y").WithArguments("Y").WithLocation(15, 25)); } [Fact] public void FieldInitializers_11() { var source = @" using System; #pragma warning disable 649 record struct S1(object X) { public object X; public object Y = 1; } record struct S2(object X) { public object X { get; } public object Y { get; } = 2; } record struct S3(object Y) { public object X { get; init; } = 3; public object Y { get; init; } } class Program { static void Main() { Console.WriteLine(new S1(""a"")); Console.WriteLine(new S2(""b"")); Console.WriteLine(new S3(""c"")); } } "; var comp = CreateCompilation(new[] { source, IsExternalInitTypeDefinition }, parseOptions: TestOptions.Regular10); comp.VerifyDiagnostics( // (5,15): error CS0171: Field 'S1.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 S1(object X) Diagnostic(ErrorCode.ERR_UnassignedThisUnsupportedVersion, "S1").WithArguments("S1.X", "11.0").WithLocation(5, 15), // (5,25): warning CS8907: Parameter 'X' is unread. Did you forget to use it to initialize the property with that name? // record struct S1(object X) Diagnostic(ErrorCode.WRN_UnreadRecordParameter, "X").WithArguments("X").WithLocation(5, 25), // (10,15): error CS0843: Auto-implemented property 'S2.X' must be fully assigned before control is returned to the caller. Consider updating to language version '11.0' to auto-default the property. // record struct S2(object X) Diagnostic(ErrorCode.ERR_UnassignedThisAutoPropertyUnsupportedVersion, "S2").WithArguments("S2.X", "11.0").WithLocation(10, 15), // (10,25): warning CS8907: Parameter 'X' is unread. Did you forget to use it to initialize the property with that name? // record struct S2(object X) Diagnostic(ErrorCode.WRN_UnreadRecordParameter, "X").WithArguments("X").WithLocation(10, 25), // (15,15): error CS0843: Auto-implemented property 'S3.Y' must be fully assigned before control is returned to the caller. Consider updating to language version '11.0' to auto-default the property. // record struct S3(object Y) Diagnostic(ErrorCode.ERR_UnassignedThisAutoPropertyUnsupportedVersion, "S3").WithArguments("S3.Y", "11.0").WithLocation(15, 15), // (15,25): warning CS8907: Parameter 'Y' is unread. Did you forget to use it to initialize the property with that name? // record struct S3(object Y) Diagnostic(ErrorCode.WRN_UnreadRecordParameter, "Y").WithArguments("Y").WithLocation(15, 25)); var verifier = CompileAndVerify(new[] { source, IsExternalInitTypeDefinition }, parseOptions: TestOptions.Regular11, expectedOutput: @"S1 { X = , Y = 1 } S2 { X = , Y = 2 } S3 { X = 3, Y = }", verify: Verification.Skipped); verifier.VerifyDiagnostics( // (5,25): warning CS8907: Parameter 'X' is unread. Did you forget to use it to initialize the property with that name? // record struct S1(object X) Diagnostic(ErrorCode.WRN_UnreadRecordParameter, "X").WithArguments("X").WithLocation(5, 25), // (10,25): warning CS8907: Parameter 'X' is unread. Did you forget to use it to initialize the property with that name? // record struct S2(object X) Diagnostic(ErrorCode.WRN_UnreadRecordParameter, "X").WithArguments("X").WithLocation(10, 25), // (15,25): warning CS8907: Parameter 'Y' is unread. Did you forget to use it to initialize the property with that name? // record struct S3(object Y) Diagnostic(ErrorCode.WRN_UnreadRecordParameter, "Y").WithArguments("Y").WithLocation(15, 25)); } [Fact] public void FieldInitializers_12() { var source = @"#pragma warning disable 649 using System; record struct S1(object X) { internal object Y = 1; } record struct S2(object X) { internal object Y { get; } = 2; } record struct S3(object X) { internal object Y { get; init; } = 3; } class Program { static void Main() { Console.WriteLine(new S1()); Console.WriteLine(new S1(10)); Console.WriteLine(new S2()); Console.WriteLine(new S2(20)); Console.WriteLine(new S3()); Console.WriteLine(new S3(30)); } } "; var expectedOutput = @"S1 { X = } S1 { X = 10 } S2 { X = } S2 { X = 20 } S3 { X = } S3 { X = 30 } "; CompileAndVerify(new[] { source, IsExternalInitTypeDefinition }, parseOptions: TestOptions.Regular10, verify: Verification.Skipped, expectedOutput: expectedOutput); CompileAndVerify(new[] { source, IsExternalInitTypeDefinition }, verify: Verification.Skipped, expectedOutput: expectedOutput); } [WorkItem(57870, "https://github.com/dotnet/roslyn/issues/57870")] [Fact] public void FieldInitializers_13() { var source = @"#nullable enable using System; var x = new S { P1 = ""x1"", P2 = ""x2"" }; var y = new S { P2 = ""y2"" }; Console.WriteLine(y.P1); record struct S { public string? P1 { get; init; } public string? P2 { get; init; } = """"; }"; var expectedDiagnostics = new[] { // (10,15): error CS8983: A 'struct' with field initializers must include an explicitly declared constructor. // record struct S Diagnostic(ErrorCode.ERR_StructHasInitializersAndNoDeclaredConstructor, "S").WithLocation(10, 15) }; var comp = CreateCompilation(new[] { source, IsExternalInitTypeDefinition }, parseOptions: TestOptions.Regular10); comp.VerifyDiagnostics(expectedDiagnostics); comp = CreateCompilation(new[] { source, IsExternalInitTypeDefinition }); comp.VerifyDiagnostics(expectedDiagnostics); } /// <summary> /// Should still report binding errors in field initializers /// even if there is no explicit constructor. /// </summary> [Fact] public void FieldInitializers_14() { var source = @"struct S { private object F = Unknown(); }"; var comp = CreateCompilation(source); comp.VerifyDiagnostics( // (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,20): warning CS0169: The field 'S.F' is never used // private object F = Unknown(); Diagnostic(ErrorCode.WRN_UnreferencedField, "F").WithArguments("S.F").WithLocation(3, 20), // (3,24): error CS0103: The name 'Unknown' does not exist in the current context // private object F = Unknown(); Diagnostic(ErrorCode.ERR_NameNotInContext, "Unknown").WithArguments("Unknown").WithLocation(3, 24)); } [Fact] public void FieldInitializers_15() { var source = @"struct S0 { static S0() { } public int F = 1; }"; var comp = CreateCompilation(source); comp.VerifyDiagnostics( // (1,8): error CS8983: A 'struct' with field initializers must include an explicitly declared constructor. // struct S0 Diagnostic(ErrorCode.ERR_StructHasInitializersAndNoDeclaredConstructor, "S0").WithLocation(1, 8), // (4,16): warning CS0649: Field 'S0.F' is never assigned to, and will always have its default value 0 // public int F = 1; Diagnostic(ErrorCode.WRN_UnassignedInternalField, "F").WithArguments("S0.F", "0").WithLocation(4, 16)); } [Fact] public void FieldInitializers_16() { var source = @"using System; struct S1 { static S1() { } public S1() { } public int F = 1; } struct S2 { static S2() { } public S2(object o) { } public int F = 2; } class Program { static void Main() { Console.WriteLine(new S1().F); Console.WriteLine(new S2().F); } }"; CompileAndVerify(source, options: TestOptions.ReleaseExe, verify: Verification.Skipped, expectedOutput: @"1 0"); } [Fact] public void ExpressionTrees_01() { var source = @"#pragma warning disable 649 using System; using System.Linq.Expressions; struct S1 { int X = 1; public override string ToString() => X.ToString(); } class Program { static void Main() { Report(() => new S1()); } static void Report<T>(Expression<Func<T>> e) { var t = e.Compile().Invoke(); Console.WriteLine(t); } }"; var comp = CreateCompilation(source); comp.VerifyDiagnostics( // (4,8): error CS8983: A 'struct' with field initializers must include an explicitly declared constructor. // struct S1 Diagnostic(ErrorCode.ERR_StructHasInitializersAndNoDeclaredConstructor, "S1").WithLocation(4, 8)); } [Fact] public void ExpressionTrees_02() { var source = @"#pragma warning disable 649 using System; using System.Linq.Expressions; struct S0 { int X; public override string ToString() => X.ToString(); } struct S2 { int X = 2; public S2() { } public override string ToString() => X.ToString(); } class Program { static void Main() { Report(() => new S0()); Report(() => new S2()); } static void Report<T>(Expression<Func<T>> e) { var t = e.Compile().Invoke(); Console.WriteLine(t); } }"; var verifier = CompileAndVerify(source, options: TestOptions.ReleaseExe, expectedOutput: @"0 2"); verifier.VerifyIL("Program.Main", @"{ // Code size 71 (0x47) .maxstack 2 IL_0000: ldtoken ""S0"" IL_0005: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" IL_000a: call ""System.Linq.Expressions.NewExpression System.Linq.Expressions.Expression.New(System.Type)"" IL_000f: call ""System.Linq.Expressions.ParameterExpression[] System.Array.Empty<System.Linq.Expressions.ParameterExpression>()"" IL_0014: call ""System.Linq.Expressions.Expression<System.Func<S0>> System.Linq.Expressions.Expression.Lambda<System.Func<S0>>(System.Linq.Expressions.Expression, params System.Linq.Expressions.ParameterExpression[])"" IL_0019: call ""void Program.Report<S0>(System.Linq.Expressions.Expression<System.Func<S0>>)"" IL_001e: ldtoken ""S2..ctor()"" IL_0023: call ""System.Reflection.MethodBase System.Reflection.MethodBase.GetMethodFromHandle(System.RuntimeMethodHandle)"" IL_0028: castclass ""System.Reflection.ConstructorInfo"" IL_002d: call ""System.Linq.Expressions.Expression[] System.Array.Empty<System.Linq.Expressions.Expression>()"" IL_0032: call ""System.Linq.Expressions.NewExpression System.Linq.Expressions.Expression.New(System.Reflection.ConstructorInfo, System.Collections.Generic.IEnumerable<System.Linq.Expressions.Expression>)"" IL_0037: call ""System.Linq.Expressions.ParameterExpression[] System.Array.Empty<System.Linq.Expressions.ParameterExpression>()"" IL_003c: call ""System.Linq.Expressions.Expression<System.Func<S2>> System.Linq.Expressions.Expression.Lambda<System.Func<S2>>(System.Linq.Expressions.Expression, params System.Linq.Expressions.ParameterExpression[])"" IL_0041: call ""void Program.Report<S2>(System.Linq.Expressions.Expression<System.Func<S2>>)"" IL_0046: ret }"); } [Fact] public void Retargeting_01() { var sourceA = @"public struct S2 { public int X = 2; public S2() { } } public struct S3 { public int X = 3; public S3(object _) { } }"; var comp = CreateCompilation(sourceA, targetFramework: TargetFramework.Mscorlib40); var refA = comp.ToMetadataReference(); var typeA = comp.GetMember<FieldSymbol>("S2.X").Type; var corLibA = comp.Assembly.CorLibrary; Assert.Equal(corLibA, typeA.ContainingAssembly); var sourceB = @"using System; class Program { static void Main() { Console.WriteLine(new S2().X); Console.WriteLine(new S3().X); } }"; comp = CreateCompilation(sourceB, references: new[] { refA }, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular9, targetFramework: TargetFramework.Mscorlib461); CompileAndVerify(comp, expectedOutput: @"2 0"); var corLibB = comp.Assembly.CorLibrary; Assert.NotEqual(corLibA, corLibB); var field = comp.GetMember<FieldSymbol>("S2.X"); Assert.IsType<Microsoft.CodeAnalysis.CSharp.Symbols.Retargeting.RetargetingFieldSymbol>(field); var typeB = (NamedTypeSymbol)field.Type; Assert.Equal(corLibB, typeB.ContainingAssembly); } [Fact] public void NullableAnalysis_01() { var source = @"#pragma warning disable 169 #nullable enable struct S0 { object F0; } struct S1 { object F1; public S1() { } } struct S2 { object F2; public S2() : this(null) { } S2(object? obj) { } } struct S3 { object F3; public S3() { F3 = GetValue(); } static object? GetValue() => null; }"; var comp = CreateCompilation(source, parseOptions: TestOptions.Regular10); comp.VerifyDiagnostics( // (10,12): warning CS8618: Non-nullable field 'F1' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the field as nullable. // public S1() { } Diagnostic(ErrorCode.WRN_UninitializedNonNullableField, "S1").WithArguments("field", "F1").WithLocation(10, 12), // (10,12): error CS0171: Field 'S1.F1' must be fully assigned before control is returned to the caller. Consider updating to language version '11.0' to auto-default the field. // public S1() { } Diagnostic(ErrorCode.ERR_UnassignedThisUnsupportedVersion, "S1").WithArguments("S1.F1", "11.0").WithLocation(10, 12), // (16,5): warning CS8618: Non-nullable field 'F2' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the field as nullable. // S2(object? obj) { } Diagnostic(ErrorCode.WRN_UninitializedNonNullableField, "S2").WithArguments("field", "F2").WithLocation(16, 5), // (16,5): error CS0171: Field 'S2.F2' must be fully assigned before control is returned to the caller. Consider updating to language version '11.0' to auto-default the field. // S2(object? obj) { } Diagnostic(ErrorCode.ERR_UnassignedThisUnsupportedVersion, "S2").WithArguments("S2.F2", "11.0").WithLocation(16, 5), // (21,12): warning CS8618: Non-nullable field 'F3' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the field as nullable. // public S3() { F3 = GetValue(); } Diagnostic(ErrorCode.WRN_UninitializedNonNullableField, "S3").WithArguments("field", "F3").WithLocation(21, 12), // (21,24): warning CS8601: Possible null reference assignment. // public S3() { F3 = GetValue(); } Diagnostic(ErrorCode.WRN_NullReferenceAssignment, "GetValue()").WithLocation(21, 24)); comp = CreateCompilation(source, parseOptions: TestOptions.Regular11); comp.VerifyDiagnostics( // (10,12): warning CS8618: Non-nullable field 'F1' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the field as nullable. // public S1() { } Diagnostic(ErrorCode.WRN_UninitializedNonNullableField, "S1").WithArguments("field", "F1").WithLocation(10, 12), // (16,5): warning CS8618: Non-nullable field 'F2' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the field as nullable. // S2(object? obj) { } Diagnostic(ErrorCode.WRN_UninitializedNonNullableField, "S2").WithArguments("field", "F2").WithLocation(16, 5), // (21,12): warning CS8618: Non-nullable field 'F3' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the field as nullable. // public S3() { F3 = GetValue(); } Diagnostic(ErrorCode.WRN_UninitializedNonNullableField, "S3").WithArguments("field", "F3").WithLocation(21, 12), // (21,24): warning CS8601: Possible null reference assignment. // public S3() { F3 = GetValue(); } Diagnostic(ErrorCode.WRN_NullReferenceAssignment, "GetValue()").WithLocation(21, 24)); } [Fact] public void NullableAnalysis_02() { var source = @"#nullable enable struct S0 { object F0 = Utils.GetValue(); } static class Utils { internal static object? GetValue() => null; }"; var comp = CreateCompilation(source); comp.VerifyDiagnostics( // (2,8): error CS8983: A 'struct' with field initializers must include an explicitly declared constructor. // struct S0 Diagnostic(ErrorCode.ERR_StructHasInitializersAndNoDeclaredConstructor, "S0").WithLocation(2, 8), // (4,12): warning CS0169: The field 'S0.F0' is never used // object F0 = Utils.GetValue(); Diagnostic(ErrorCode.WRN_UnreferencedField, "F0").WithArguments("S0.F0").WithLocation(4, 12)); } [Fact] public void NullableAnalysis_03() { var source = @"#nullable enable struct S1 { object F1 = Utils.GetValue(); public S1() { } } struct S2 { object F2 = Utils.GetValue(); public S2() : this(null) { } S2(object obj) { } } static class Utils { internal static object? GetValue() => null; }"; var comp = CreateCompilation(source); comp.VerifyDiagnostics( // (4,17): warning CS8601: Possible null reference assignment. // object F1 = Utils.GetValue(); Diagnostic(ErrorCode.WRN_NullReferenceAssignment, "Utils.GetValue()").WithLocation(4, 17), // (9,17): warning CS8601: Possible null reference assignment. // object F2 = Utils.GetValue(); Diagnostic(ErrorCode.WRN_NullReferenceAssignment, "Utils.GetValue()").WithLocation(9, 17), // (10,24): warning CS8625: Cannot convert null literal to non-nullable reference type. // public S2() : this(null) { } Diagnostic(ErrorCode.WRN_NullAsNonNullable, "null").WithLocation(10, 24)); } [Fact] public void DefiniteAssignment() { var source = @"#pragma warning disable 169 unsafe struct S0 { fixed int Y[1]; } unsafe struct S1 { fixed int Y[1]; public S1() { } } unsafe struct S2 { int X; fixed int Y[1]; } unsafe struct S3 { int X; fixed int Y[1]; public S3() { } } unsafe struct S4 { int X = 4; fixed int Y[1]; } unsafe struct S5 { int X; fixed int Y[1]; public S5() { X = 5; } }"; var comp = CreateCompilation(source, options: TestOptions.UnsafeReleaseDll, parseOptions: TestOptions.Regular10); comp.VerifyDiagnostics( // (20,12): error CS0171: Field 'S3.X' must be fully assigned before control is returned to the caller. Consider updating to language version '11.0' to auto-default the field. // public S3() { } Diagnostic(ErrorCode.ERR_UnassignedThisUnsupportedVersion, "S3").WithArguments("S3.X", "11.0").WithLocation(20, 12), // (22,15): error CS8983: A 'struct' with field initializers must include an explicitly declared constructor. // unsafe struct S4 Diagnostic(ErrorCode.ERR_StructHasInitializersAndNoDeclaredConstructor, "S4").WithLocation(22, 15), // (29,9): warning CS0414: The field 'S5.X' is assigned but its value is never used // int X; Diagnostic(ErrorCode.WRN_UnreferencedFieldAssg, "X").WithArguments("S5.X").WithLocation(29, 9)); comp = CreateCompilation(source, options: TestOptions.UnsafeReleaseDll, parseOptions: TestOptions.Regular11); comp.VerifyDiagnostics( // (22,15): error CS8983: A 'struct' with field initializers must include an explicitly declared constructor. // unsafe struct S4 Diagnostic(ErrorCode.ERR_StructHasInitializersAndNoDeclaredConstructor, "S4").WithLocation(22, 15), // (29,9): warning CS0414: The field 'S5.X' is assigned but its value is never used // int X; Diagnostic(ErrorCode.WRN_UnreferencedFieldAssg, "X").WithArguments("S5.X").WithLocation(29, 9) ); } [Fact] public void ParameterDefaultValues_01() { var source = @"struct S1 { } struct S2 { public S2() { } } struct S3 { internal S3() { } } struct S4 { private S4() { } } class Program { static void F1(S1 s = default) { } static void F2(S2 s = default) { } static void F3(S3 s = default) { } static void F4(S4 s = default) { } static void G1(S1 s = new()) { } static void G2(S2 s = new()) { } static void G3(S3 s = new()) { } static void G4(S4 s = new()) { } static void G5(S1? s = new()) { } static void G6(S1? s = new S1()) { } static void G7(decimal s = new(1)) { } static void G8(decimal s = new decimal(1)) { } static void G9(decimal? s = new(1)) { } static void G10(decimal? s = new decimal(1)) { } static void G11(decimal s = (decimal)1) { } static void G12(decimal? s = (decimal)2) { } }"; var comp = CreateCompilation(source); comp.VerifyDiagnostics( // (3,22): error CS8938: The parameterless struct constructor must be 'public'. // struct S3 { internal S3() { } } Diagnostic(ErrorCode.ERR_NonPublicParameterlessStructConstructor, "S3").WithLocation(3, 22), // (4,21): error CS8938: The parameterless struct constructor must be 'public'. // struct S4 { private S4() { } } Diagnostic(ErrorCode.ERR_NonPublicParameterlessStructConstructor, "S4").WithLocation(4, 21), // (12,27): error CS1736: Default parameter value for 's' must be a compile-time constant // static void G2(S2 s = new()) { } Diagnostic(ErrorCode.ERR_DefaultValueMustBeConstant, "new()").WithArguments("s").WithLocation(12, 27), // (13,27): error CS1736: Default parameter value for 's' must be a compile-time constant // static void G3(S3 s = new()) { } Diagnostic(ErrorCode.ERR_DefaultValueMustBeConstant, "new()").WithArguments("s").WithLocation(13, 27), // (14,27): error CS0122: 'S4.S4()' is inaccessible due to its protection level // static void G4(S4 s = new()) { } Diagnostic(ErrorCode.ERR_BadAccess, "new()").WithArguments("S4.S4()").WithLocation(14, 27), // (14,27): error CS1736: Default parameter value for 's' must be a compile-time constant // static void G4(S4 s = new()) { } Diagnostic(ErrorCode.ERR_DefaultValueMustBeConstant, "new()").WithArguments("s").WithLocation(14, 27), // (15,24): error CS1770: A value of type 'S1' cannot be used as default parameter for nullable parameter 's' because 'S1' is not a simple type // static void G5(S1? s = new()) { } Diagnostic(ErrorCode.ERR_NoConversionForNubDefaultParam, "s").WithArguments("S1", "s").WithLocation(15, 24), // (16,24): error CS1770: A value of type 'S1' cannot be used as default parameter for nullable parameter 's' because 'S1' is not a simple type // static void G6(S1? s = new S1()) { } Diagnostic(ErrorCode.ERR_NoConversionForNubDefaultParam, "s").WithArguments("S1", "s").WithLocation(16, 24), // (17,32): error CS1736: Default parameter value for 's' must be a compile-time constant // static void G7(decimal s = new(1)) { } Diagnostic(ErrorCode.ERR_DefaultValueMustBeConstant, "new(1)").WithArguments("s").WithLocation(17, 32), // (18,32): error CS1736: Default parameter value for 's' must be a compile-time constant // static void G8(decimal s = new decimal(1)) { } Diagnostic(ErrorCode.ERR_DefaultValueMustBeConstant, "new decimal(1)").WithArguments("s").WithLocation(18, 32), // (19,33): error CS1736: Default parameter value for 's' must be a compile-time constant // static void G9(decimal? s = new(1)) { } Diagnostic(ErrorCode.ERR_DefaultValueMustBeConstant, "new(1)").WithArguments("s").WithLocation(19, 33), // (20,34): error CS1736: Default parameter value for 's' must be a compile-time constant // static void G10(decimal? s = new decimal(1)) { } Diagnostic(ErrorCode.ERR_DefaultValueMustBeConstant, "new decimal(1)").WithArguments("s").WithLocation(20, 34) ); } [Fact] public void ParameterDefaultValues_02() { var source = @"struct S1 { object X = 1; } struct S2 { object X = 2; public S2() { } } struct S3 { object X = 3; public S3(object x) { X = x; } } class Program { static void F1(S1 s = default) { } static void F2(S2 s = default) { } static void F3(S3 s = default) { } static void G1(S1 s = new()) { } static void G2(S2 s = new()) { } static void G3(S3 s = new()) { } }"; var comp = CreateCompilation(source); comp.VerifyDiagnostics( // (1,8): error CS8983: A 'struct' with field initializers must include an explicitly declared constructor. // struct S1 Diagnostic(ErrorCode.ERR_StructHasInitializersAndNoDeclaredConstructor, "S1").WithLocation(1, 8), // (3,12): warning CS0169: The field 'S1.X' is never used // object X = 1; Diagnostic(ErrorCode.WRN_UnreferencedField, "X").WithArguments("S1.X").WithLocation(3, 12), // (21,27): error CS1736: Default parameter value for 's' must be a compile-time constant // static void G2(S2 s = new()) { } Diagnostic(ErrorCode.ERR_DefaultValueMustBeConstant, "new()").WithArguments("s").WithLocation(21, 27)); } [Fact] public void ParameterDefaultValues_03() { var source = @"public struct S1 { } public class Program { public static void G1(S1 s = new()) { } public static void G2(S1 s = new S1()) { } }"; var comp = CreateCompilation(source); CompileAndVerify(comp, symbolValidator: validate, sourceSymbolValidator: validate).VerifyDiagnostics(); void validate(ModuleSymbol m) { var g1 = m.GlobalNamespace.GetMember<MethodSymbol>("Program.G1"); Assert.True(g1.Parameters[0].HasExplicitDefaultValue); Assert.Null(g1.Parameters[0].ExplicitDefaultValue); Assert.True(g1.Parameters[0].ExplicitDefaultConstantValue.IsNull); var g2 = m.GlobalNamespace.GetMember<MethodSymbol>("Program.G2"); Assert.True(g2.Parameters[0].HasExplicitDefaultValue); Assert.Null(g2.Parameters[0].ExplicitDefaultValue); Assert.True(g2.Parameters[0].ExplicitDefaultConstantValue.IsNull); } } [Fact] public void ParameterDefaultValues_04() { var source = @" public class Program { public static void G1(bool? s = new()) { } public static void G2(bool? s = new bool()) { } }"; var comp = CreateCompilation(source); CompileAndVerify(comp, symbolValidator: validate, sourceSymbolValidator: validate).VerifyDiagnostics(); void validate(ModuleSymbol m) { var g1 = m.GlobalNamespace.GetMember<MethodSymbol>("Program.G1"); Assert.True(g1.Parameters[0].HasExplicitDefaultValue); Assert.False((bool)g1.Parameters[0].ExplicitDefaultValue); Assert.False(g1.Parameters[0].ExplicitDefaultConstantValue.IsNull); var g2 = m.GlobalNamespace.GetMember<MethodSymbol>("Program.G2"); Assert.True(g2.Parameters[0].HasExplicitDefaultValue); Assert.False((bool)g2.Parameters[0].ExplicitDefaultValue); Assert.False(g2.Parameters[0].ExplicitDefaultConstantValue.BooleanValue); } } [Fact] public void Constants() { var source = @"struct S0 { } struct S1 { object X = 1; } struct S2 { public S2() { } } class Program { const object d0 = default(S0); const object d1 = default(S1); const object d2 = default(S2); const object s0 = new S0(); const object s1 = new S1(); const object s2 = new S2(); }"; var comp = CreateCompilation(source); comp.VerifyDiagnostics( // (4,8): error CS8983: A 'struct' with field initializers must include an explicitly declared constructor. // struct S1 Diagnostic(ErrorCode.ERR_StructHasInitializersAndNoDeclaredConstructor, "S1").WithLocation(4, 8), // (6,12): warning CS0169: The field 'S1.X' is never used // object X = 1; Diagnostic(ErrorCode.WRN_UnreferencedField, "X").WithArguments("S1.X").WithLocation(6, 12), // (14,23): error CS0133: The expression being assigned to 'Program.d0' must be constant // const object d0 = default(S0); Diagnostic(ErrorCode.ERR_NotConstantExpression, "default(S0)").WithArguments("Program.d0").WithLocation(14, 23), // (15,23): error CS0133: The expression being assigned to 'Program.d1' must be constant // const object d1 = default(S1); Diagnostic(ErrorCode.ERR_NotConstantExpression, "default(S1)").WithArguments("Program.d1").WithLocation(15, 23), // (16,23): error CS0133: The expression being assigned to 'Program.d2' must be constant // const object d2 = default(S2); Diagnostic(ErrorCode.ERR_NotConstantExpression, "default(S2)").WithArguments("Program.d2").WithLocation(16, 23), // (17,23): error CS0133: The expression being assigned to 'Program.s0' must be constant // const object s0 = new S0(); Diagnostic(ErrorCode.ERR_NotConstantExpression, "new S0()").WithArguments("Program.s0").WithLocation(17, 23), // (18,23): error CS0133: The expression being assigned to 'Program.s1' must be constant // const object s1 = new S1(); Diagnostic(ErrorCode.ERR_NotConstantExpression, "new S1()").WithArguments("Program.s1").WithLocation(18, 23), // (19,23): error CS0133: The expression being assigned to 'Program.s2' must be constant // const object s2 = new S2(); Diagnostic(ErrorCode.ERR_NotConstantExpression, "new S2()").WithArguments("Program.s2").WithLocation(19, 23)); } [Fact] public void NoPIA() { var sourceA = @"using System.Runtime.InteropServices; [assembly: ImportedFromTypeLib(""_.dll"")] [assembly: Guid(""9758B46C-5297-4832-BB58-F2B5B78B0D01"")] [ComImport()] [Guid(""6D947BE5-75B1-4D97-B444-2720624761D7"")] public interface I { S0 F0(); S1 F1(); } public struct S0 { } public struct S1 { public S1() { } }"; var comp = CreateCompilationWithMscorlib40(sourceA); var refA = comp.EmitToImageReference(embedInteropTypes: true); var sourceB = @"class Program { static void M(I i) { var s0 = i.F0(); var s1 = i.F1(); } }"; comp = CreateCompilationWithMscorlib40(sourceB, references: new[] { refA }); comp.VerifyEmitDiagnostics( // (6,18): error CS1757: Embedded interop struct 'S1' can contain only public instance fields. // var s1 = i.F1(); Diagnostic(ErrorCode.ERR_InteropStructContainsMethods, "i.F1()").WithArguments("S1").WithLocation(6, 18)); } [WorkItem(60568, "https://github.com/dotnet/roslyn/issues/60568")] [Fact] public void FieldInitializer_EscapeAnalysis_01() { var source = @"using System; ref struct Example { public Span<byte> Field = stackalloc byte[512]; public Span<byte> Property { get; } = stackalloc byte[512]; public Example() {} }"; var comp = CreateCompilationWithSpan(source); comp.VerifyDiagnostics( // (5,31): error CS8353: A result of a stackalloc expression of type 'Span<byte>' cannot be used in this context because it may be exposed outside of the containing method // public Span<byte> Field = stackalloc byte[512]; Diagnostic(ErrorCode.ERR_EscapeStackAlloc, "stackalloc byte[512]").WithArguments("System.Span<byte>").WithLocation(5, 31), // (6,43): error CS8353: A result of a stackalloc expression of type 'Span<byte>' cannot be used in this context because it may be exposed outside of the containing method // public Span<byte> Property { get; } = stackalloc byte[512]; Diagnostic(ErrorCode.ERR_EscapeStackAlloc, "stackalloc byte[512]").WithArguments("System.Span<byte>").WithLocation(6, 43)); } [WorkItem(60568, "https://github.com/dotnet/roslyn/issues/60568")] [ConditionalFact(typeof(CoreClrOnly))] // For conversion from Span<T> to ReadOnlySpan<T>. public void FieldInitializer_EscapeAnalysis_02() { var source = @"using System; ref struct Example { public ReadOnlySpan<int> Field = stackalloc int[512]; public ReadOnlySpan<int> Property { get; } = stackalloc int[512]; public Example() {} }"; var comp = CreateCompilation(source, targetFramework: TargetFramework.NetCoreApp); comp.VerifyDiagnostics( // (5,38): error CS8353: A result of a stackalloc expression of type 'Span<int>' cannot be used in this context because it may be exposed outside of the containing method // public ReadOnlySpan<int> Field = stackalloc int[512]; Diagnostic(ErrorCode.ERR_EscapeStackAlloc, "stackalloc int[512]").WithArguments("System.Span<int>").WithLocation(5, 38), // (6,50): error CS8353: A result of a stackalloc expression of type 'Span<int>' cannot be used in this context because it may be exposed outside of the containing method // public ReadOnlySpan<int> Property { get; } = stackalloc int[512]; Diagnostic(ErrorCode.ERR_EscapeStackAlloc, "stackalloc int[512]").WithArguments("System.Span<int>").WithLocation(6, 50)); } [WorkItem(60568, "https://github.com/dotnet/roslyn/issues/60568")] [Fact] public void FieldInitializer_EscapeAnalysis_03() { var source = @"using System; ref struct Example { public Span<byte> Field; } ref struct E2 { public Span<byte> Field = new Example { Field = stackalloc byte[512] }.Field; public Span<byte> Property { get; } = new Example { Field = stackalloc byte[512] }.Field; public E2() { } }"; var comp = CreateCompilationWithSpan(source); comp.VerifyDiagnostics( // (8,43): error CS8352: Cannot use variable 'Field = stackalloc byte[512]' in this context because it may expose referenced variables outside of their declaration scope // public Span<byte> Field = new Example { Field = stackalloc byte[512] }.Field; Diagnostic(ErrorCode.ERR_EscapeVariable, "{ Field = stackalloc byte[512] }").WithArguments("Field = stackalloc byte[512]").WithLocation(8, 43), // (9,55): error CS8352: Cannot use variable 'Field = stackalloc byte[512]' in this context because it may expose referenced variables outside of their declaration scope // public Span<byte> Property { get; } = new Example { Field = stackalloc byte[512] }.Field; Diagnostic(ErrorCode.ERR_EscapeVariable, "{ Field = stackalloc byte[512] }").WithArguments("Field = stackalloc byte[512]").WithLocation(9, 55)); } [Theory] [InlineData(LanguageVersion.CSharp10)] [InlineData(LanguageVersion.Latest)] public void FieldInitializer_EscapeAnalysis_04(LanguageVersion languageVersion) { var source = @"using System; delegate Span<T> D<T>(); ref struct Example { public Span<byte> Field = F(() => stackalloc byte[512]); public Span<byte> Property { get; } = F(() => stackalloc byte[512]); public Example() {} static Span<T> F<T>(D<T> d) => d(); }"; var comp = CreateCompilationWithSpan(source, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion)); comp.VerifyDiagnostics( // (5,39): error CS8353: A result of a stackalloc expression of type 'Span<byte>' cannot be used in this context because it may be exposed outside of the containing method // public Span<byte> Field = F(() => stackalloc byte[512]); Diagnostic(ErrorCode.ERR_EscapeStackAlloc, "stackalloc byte[512]").WithArguments("System.Span<byte>").WithLocation(5, 39), // (6,51): error CS8353: A result of a stackalloc expression of type 'Span<byte>' cannot be used in this context because it may be exposed outside of the containing method // public Span<byte> Property { get; } = F(() => stackalloc byte[512]); Diagnostic(ErrorCode.ERR_EscapeStackAlloc, "stackalloc byte[512]").WithArguments("System.Span<byte>").WithLocation(6, 51)); } [WorkItem(60568, "https://github.com/dotnet/roslyn/issues/60568")] [ConditionalFact(typeof(CoreClrOnly))] // For conversion from Span<T> to ReadOnlySpan<T>. public void FieldInitializer_EscapeAnalysis_05() { var source = @"using System; struct Example { public Span<byte> Field = stackalloc byte[512]; public ReadOnlySpan<int> Property { get; } = stackalloc int[512]; public Example() {} }"; var comp = CreateCompilation(source, targetFramework: TargetFramework.NetCoreApp); comp.VerifyDiagnostics( // (4,12): error CS8345: Field or auto-implemented property cannot be of type 'Span<byte>' unless it is an instance member of a ref struct. // public Span<byte> Field = stackalloc byte[512]; Diagnostic(ErrorCode.ERR_FieldAutoPropCantBeByRefLike, "Span<byte>").WithArguments("System.Span<byte>").WithLocation(4, 12), // (4,31): error CS8353: A result of a stackalloc expression of type 'Span<byte>' cannot be used in this context because it may be exposed outside of the containing method // public Span<byte> Field = stackalloc byte[512]; Diagnostic(ErrorCode.ERR_EscapeStackAlloc, "stackalloc byte[512]").WithArguments("System.Span<byte>").WithLocation(4, 31), // (5,12): error CS8345: Field or auto-implemented property cannot be of type 'ReadOnlySpan<int>' unless it is an instance member of a ref struct. // public ReadOnlySpan<int> Property { get; } = stackalloc int[512]; Diagnostic(ErrorCode.ERR_FieldAutoPropCantBeByRefLike, "ReadOnlySpan<int>").WithArguments("System.ReadOnlySpan<int>").WithLocation(5, 12), // (5,50): error CS8353: A result of a stackalloc expression of type 'Span<int>' cannot be used in this context because it may be exposed outside of the containing method // public ReadOnlySpan<int> Property { get; } = stackalloc int[512]; Diagnostic(ErrorCode.ERR_EscapeStackAlloc, "stackalloc int[512]").WithArguments("System.Span<int>").WithLocation(5, 50)); } [WorkItem(60568, "https://github.com/dotnet/roslyn/issues/60568")] [ConditionalFact(typeof(CoreClrOnly))] // For conversion from Span<T> to ReadOnlySpan<T>. public void FieldInitializer_EscapeAnalysis_06() { var source = @"using System; record struct Example() { public Span<byte> Field = stackalloc byte[512]; public ReadOnlySpan<int> Property { get; } = stackalloc int[512]; }"; var comp = CreateCompilation(source, targetFramework: TargetFramework.NetCoreApp); comp.VerifyDiagnostics( // (4,12): error CS8345: Field or auto-implemented property cannot be of type 'Span<byte>' unless it is an instance member of a ref struct. // public Span<byte> Field = stackalloc byte[512]; Diagnostic(ErrorCode.ERR_FieldAutoPropCantBeByRefLike, "Span<byte>").WithArguments("System.Span<byte>").WithLocation(4, 12), // (4,31): error CS8353: A result of a stackalloc expression of type 'Span<byte>' cannot be used in this context because it may be exposed outside of the containing method // public Span<byte> Field = stackalloc byte[512]; Diagnostic(ErrorCode.ERR_EscapeStackAlloc, "stackalloc byte[512]").WithArguments("System.Span<byte>").WithLocation(4, 31), // (5,12): error CS8345: Field or auto-implemented property cannot be of type 'ReadOnlySpan<int>' unless it is an instance member of a ref struct. // public ReadOnlySpan<int> Property { get; } = stackalloc int[512]; Diagnostic(ErrorCode.ERR_FieldAutoPropCantBeByRefLike, "ReadOnlySpan<int>").WithArguments("System.ReadOnlySpan<int>").WithLocation(5, 12), // (5,50): error CS8353: A result of a stackalloc expression of type 'Span<int>' cannot be used in this context because it may be exposed outside of the containing method // public ReadOnlySpan<int> Property { get; } = stackalloc int[512]; Diagnostic(ErrorCode.ERR_EscapeStackAlloc, "stackalloc int[512]").WithArguments("System.Span<int>").WithLocation(5, 50)); } [WorkItem(60568, "https://github.com/dotnet/roslyn/issues/60568")] [ConditionalFact(typeof(CoreClrOnly))] // For conversion from Span<T> to ReadOnlySpan<T>. public void FieldInitializer_EscapeAnalysis_07() { var source = @"using System; class Example { public Span<byte> Field = stackalloc byte[512]; public ReadOnlySpan<int> Property { get; } = stackalloc int[512]; }"; var comp = CreateCompilation(source, targetFramework: TargetFramework.NetCoreApp); comp.VerifyDiagnostics( // (4,12): error CS8345: Field or auto-implemented property cannot be of type 'Span<byte>' unless it is an instance member of a ref struct. // public Span<byte> Field = stackalloc byte[512]; Diagnostic(ErrorCode.ERR_FieldAutoPropCantBeByRefLike, "Span<byte>").WithArguments("System.Span<byte>").WithLocation(4, 12), // (4,31): error CS8353: A result of a stackalloc expression of type 'Span<byte>' cannot be used in this context because it may be exposed outside of the containing method // public Span<byte> Field = stackalloc byte[512]; Diagnostic(ErrorCode.ERR_EscapeStackAlloc, "stackalloc byte[512]").WithArguments("System.Span<byte>").WithLocation(4, 31), // (5,12): error CS8345: Field or auto-implemented property cannot be of type 'ReadOnlySpan<int>' unless it is an instance member of a ref struct. // public ReadOnlySpan<int> Property { get; } = stackalloc int[512]; Diagnostic(ErrorCode.ERR_FieldAutoPropCantBeByRefLike, "ReadOnlySpan<int>").WithArguments("System.ReadOnlySpan<int>").WithLocation(5, 12), // (5,50): error CS8353: A result of a stackalloc expression of type 'Span<int>' cannot be used in this context because it may be exposed outside of the containing method // public ReadOnlySpan<int> Property { get; } = stackalloc int[512]; Diagnostic(ErrorCode.ERR_EscapeStackAlloc, "stackalloc int[512]").WithArguments("System.Span<int>").WithLocation(5, 50)); } [ConditionalFact(typeof(CoreClrOnly))] // For conversion from Span<T> to ReadOnlySpan<T>. public void FieldInitializer_EscapeAnalysis_Script() { var source = @"using System; Span<byte> s = stackalloc byte[512]; ReadOnlySpan<int> r = stackalloc int[512]; "; var comp = CreateCompilation(source, parseOptions: TestOptions.Script, targetFramework: TargetFramework.NetCoreApp); comp.VerifyDiagnostics( // (2,1): error CS8345: Field or auto-implemented property cannot be of type 'Span<byte>' unless it is an instance member of a ref struct. // Span<byte> s = stackalloc byte[512]; Diagnostic(ErrorCode.ERR_FieldAutoPropCantBeByRefLike, "Span<byte>").WithArguments("System.Span<byte>").WithLocation(2, 1), // (3,1): error CS8345: Field or auto-implemented property cannot be of type 'ReadOnlySpan<int>' unless it is an instance member of a ref struct. // ReadOnlySpan<int> r = stackalloc int[512]; Diagnostic(ErrorCode.ERR_FieldAutoPropCantBeByRefLike, "ReadOnlySpan<int>").WithArguments("System.ReadOnlySpan<int>").WithLocation(3, 1)); } [Fact] public void ImplicitlyInitializedField_Simple() { var source = @" public struct S { public int x; public S() { } }"; CreateCompilation(source, parseOptions: TestOptions.Regular10) .VerifyDiagnostics( // (5,12): error CS0171: Field 'S.x' must be fully assigned before control is returned to the caller. Consider updating to language version '11.0' to auto-default the field. // public S() { } Diagnostic(ErrorCode.ERR_UnassignedThisUnsupportedVersion, "S").WithArguments("S.x", "11.0").WithLocation(5, 12)); CreateCompilation(source, options: TestOptions.DebugDll.WithSpecificDiagnosticOptions(ReportStructInitializationWarnings), parseOptions: TestOptions.Regular11) .VerifyDiagnostics( // (5,12): warning CS9021: Control is returned to caller before field 'S.x' is explicitly assigned, causing a preceding implicit assignment of 'default'. // public S() { } Diagnostic(ErrorCode.WRN_UnassignedThisSupportedVersion, "S").WithArguments("S.x").WithLocation(5, 12)); CreateCompilation(source, options: TestOptions.DebugDll.WithSpecificDiagnosticOptions(GetIdForErrorCode(ErrorCode.WRN_UnassignedThisSupportedVersion), ReportDiagnostic.Error), parseOptions: TestOptions.Regular11) .VerifyDiagnostics( // (5,12): error CS9021: Control is returned to caller before field 'S.x' is explicitly assigned, causing a preceding implicit assignment of 'default'. // public S() { } Diagnostic(ErrorCode.WRN_UnassignedThisSupportedVersion, "S").WithArguments("S.x").WithLocation(5, 12).WithWarningAsError(true)); var verifier = CompileAndVerify(source, parseOptions: TestOptions.Regular11); verifier.VerifyDiagnostics(); verifier.VerifyIL("S..ctor()", @" { // Code size 8 (0x8) .maxstack 2 IL_0000: ldarg.0 IL_0001: ldc.i4.0 IL_0002: stfld ""int S.x"" IL_0007: ret } "); } [Fact] public void ImplicitlyInitializedField_Pointer() { var source = """ using System; _ = new R(); unsafe struct R { public int* field; public R() { Console.WriteLine("explicit ctor"); } } """; var comp = CreateCompilation(source, options: TestOptions.UnsafeDebugExe); comp.VerifyDiagnostics( // (7,17): warning CS0649: Field 'R.field' is never assigned to, and will always have its default value // public int* field; Diagnostic(ErrorCode.WRN_UnassignedInternalField, "field").WithArguments("R.field", "").WithLocation(7, 17) ); var verifier = CompileAndVerify(comp, verify: Verification.Skipped, expectedOutput: "explicit ctor"); verifier.VerifyIL("R..ctor()", @" { // Code size 25 (0x19) .maxstack 1 IL_0000: nop IL_0001: ldarg.0 IL_0002: ldflda ""int* R.field"" IL_0007: initobj ""int*"" IL_000d: ldstr ""explicit ctor"" IL_0012: call ""void System.Console.WriteLine(string)"" IL_0017: nop IL_0018: ret }"); } [Fact] public void ImplicitlyInitializedField_NotOtherStruct() { var source = @" public struct S { public int x; public S() // 1 { S other; other.x.ToString(); // 2 S other2; other2.ToString(); // 3 } }"; CreateCompilation(source, parseOptions: TestOptions.Regular10) .VerifyDiagnostics( // (5,12): error CS0171: Field 'S.x' must be fully assigned before control is returned to the caller. Consider updating to language version '11.0' to auto-default the field. // public S() // 1 Diagnostic(ErrorCode.ERR_UnassignedThisUnsupportedVersion, "S").WithArguments("S.x", "11.0").WithLocation(5, 12), // (8,9): error CS0170: Use of possibly unassigned field 'x' // other.x.ToString(); // 2 Diagnostic(ErrorCode.ERR_UseDefViolationField, "other.x").WithArguments("x").WithLocation(8, 9), // (11,9): error CS0165: Use of unassigned local variable 'other2' // other2.ToString(); // 3 Diagnostic(ErrorCode.ERR_UseDefViolation, "other2").WithArguments("other2").WithLocation(11, 9)); CreateCompilation(source, options: TestOptions.DebugDll.WithSpecificDiagnosticOptions(ReportStructInitializationWarnings), parseOptions: TestOptions.Regular11) .VerifyDiagnostics( // (5,12): warning CS9021: Control is returned to caller before field 'S.x' is explicitly assigned, causing a preceding implicit assignment of 'default'. // public S() // 1 Diagnostic(ErrorCode.WRN_UnassignedThisSupportedVersion, "S").WithArguments("S.x").WithLocation(5, 12), // (8,9): error CS0170: Use of possibly unassigned field 'x' // other.x.ToString(); // 2 Diagnostic(ErrorCode.ERR_UseDefViolationField, "other.x").WithArguments("x").WithLocation(8, 9), // (11,9): error CS0165: Use of unassigned local variable 'other2' // other2.ToString(); // 3 Diagnostic(ErrorCode.ERR_UseDefViolation, "other2").WithArguments("other2").WithLocation(11, 9)); } [Fact] public void ImplicitlyInitializedField_ExplicitReturn() { var source = @" public struct S { public int x; public S() { return; } }"; var comp = CreateCompilation(source, parseOptions: TestOptions.Regular10); comp.VerifyDiagnostics( // (7,9): error CS0171: Field 'S.x' must be fully assigned before control is returned to the caller. Consider updating to language version '11.0' to auto-default the field. // return; Diagnostic(ErrorCode.ERR_UnassignedThisUnsupportedVersion, "return;").WithArguments("S.x", "11.0").WithLocation(7, 9)); var verifier = CompileAndVerify(source, options: TestOptions.DebugDll.WithSpecificDiagnosticOptions(ReportStructInitializationWarnings), parseOptions: TestOptions.Regular11); verifier.VerifyDiagnostics( // (7,9): warning CS9021: Control is returned to caller before field 'S.x' is explicitly assigned, causing a preceding implicit assignment of 'default'. // return; Diagnostic(ErrorCode.WRN_UnassignedThisSupportedVersion, "return;").WithArguments("S.x").WithLocation(7, 9)); verifier.VerifyIL("S..ctor", @" { // Code size 11 (0xb) .maxstack 2 IL_0000: nop IL_0001: ldarg.0 IL_0002: ldc.i4.0 IL_0003: stfld ""int S.x"" IL_0008: br.s IL_000a IL_000a: ret } "); } [Fact] public void ImplicitlyInitializedField_FieldLikeEvent() { var source = @" using System; public struct S { public event Action E; public S() { E?.Invoke(); } }"; var comp = CreateCompilation(source, parseOptions: TestOptions.Regular10); comp.VerifyDiagnostics( // (7,12): error CS0171: Field 'S.E' must be fully assigned before control is returned to the caller. Consider updating to language version '11.0' to auto-default the field. // public S() Diagnostic(ErrorCode.ERR_UnassignedThisUnsupportedVersion, "S").WithArguments("S.E", "11.0").WithLocation(7, 12), // (9,9): error CS9015: Use of possibly unassigned field 'E'. Consider updating to language version '11.0' to auto-default the field. // E?.Invoke(); Diagnostic(ErrorCode.ERR_UseDefViolationFieldUnsupportedVersion, "E").WithArguments("E", "11.0").WithLocation(9, 9)); var verifier = CompileAndVerify(source, options: TestOptions.DebugDll.WithSpecificDiagnosticOptions(ReportStructInitializationWarnings), parseOptions: TestOptions.Regular11); verifier.VerifyDiagnostics( // (7,12): warning CS9021: Control is returned to caller before field 'S.E' is explicitly assigned, causing a preceding implicit assignment of 'default'. // public S() Diagnostic(ErrorCode.WRN_UnassignedThisSupportedVersion, "S").WithArguments("S.E").WithLocation(7, 12), // (9,9): warning CS9018: Field 'E' is read before being explicitly assigned, causing a preceding implicit assignment of 'default'. // E?.Invoke(); Diagnostic(ErrorCode.WRN_UseDefViolationFieldSupportedVersion, "E").WithArguments("E").WithLocation(9, 9)); verifier.VerifyIL("S..ctor", @" { // Code size 27 (0x1b) .maxstack 2 IL_0000: nop IL_0001: ldarg.0 IL_0002: ldnull IL_0003: stfld ""System.Action S.E"" IL_0008: ldarg.0 IL_0009: ldfld ""System.Action S.E"" IL_000e: dup IL_000f: brtrue.s IL_0014 IL_0011: pop IL_0012: br.s IL_001a IL_0014: callvirt ""void System.Action.Invoke()"" IL_0019: nop IL_001a: ret } "); } [Fact, WorkItem(66046, "https://github.com/dotnet/roslyn/issues/66046")] public void ImplicitlyInitializedField_ConstructorInitializer_01() { var source = """ public struct S1 { public int F; S1(int x) {} public S1() : this(F) {} } """; var comp = CreateCompilation(source); comp.VerifyDiagnostics( // (7,24): error CS0120: An object reference is required for the non-static field, method, or property 'S1.F' // public S1() : this(F) {} Diagnostic(ErrorCode.ERR_ObjectRequired, "F").WithArguments("S1.F").WithLocation(7, 24)); } [Fact, WorkItem(66046, "https://github.com/dotnet/roslyn/issues/66046")] public void ImplicitlyInitializedField_ConstructorInitializer_02() { var source = """ public struct S1 { public int F; S1(int x) {} public static int M(int y) => y; public S1() : this(M(F)) {} } """; var comp = CreateCompilation(source); comp.VerifyDiagnostics( // (9,26): error CS0120: An object reference is required for the non-static field, method, or property 'S1.F' // public S1() : this(M(F)) {} Diagnostic(ErrorCode.ERR_ObjectRequired, "F").WithArguments("S1.F").WithLocation(9, 26)); } [Fact, WorkItem(66046, "https://github.com/dotnet/roslyn/issues/66046")] public void ImplicitlyInitializedField_ConstructorInitializer_03() { var source = """ public struct S1 { public int F; S1(int x) {} public S1() : base(F) {} } """; var comp = CreateCompilation(source); comp.VerifyDiagnostics( // (7,12): error CS0522: 'S1': structs cannot call base class constructors // public S1() : base(F) {} Diagnostic(ErrorCode.ERR_StructWithBaseConstructorCall, "S1").WithArguments("S1").WithLocation(7, 12), // (7,24): error CS0120: An object reference is required for the non-static field, method, or property 'S1.F' // public S1() : base(F) {} Diagnostic(ErrorCode.ERR_ObjectRequired, "F").WithArguments("S1.F").WithLocation(7, 24)); } [Theory] [InlineData(LanguageVersion.CSharp10)] [InlineData(LanguageVersion.CSharp11)] public void ImplicitlyInitializedFields_EmptyStruct(LanguageVersion languageVersion) { var source = @" public struct S { public S() { } }"; var verifier = CompileAndVerify(source, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion)); verifier.VerifyDiagnostics(); verifier.VerifyIL("S..ctor", @" { // Code size 1 (0x1) .maxstack 0 IL_0000: ret } "); } [Fact] public void ImplicitlyInitializedFields_Nested_FullyInitialized_01() { var source = @" public struct S1 { public int X, Y; } public struct S2 { public S1 S1; public S2() { S1.X = 42; S1.Y = 43; } }"; var verifier = CompileAndVerify(source, options: TestOptions.DebugDll.WithSpecificDiagnosticOptions(ReportStructInitializationWarnings)); verifier.VerifyDiagnostics(); verifier.VerifyIL("S2..ctor", @" { // Code size 28 (0x1c) .maxstack 2 IL_0000: nop IL_0001: ldarg.0 IL_0002: ldflda ""S1 S2.S1"" IL_0007: ldc.i4.s 42 IL_0009: stfld ""int S1.X"" IL_000e: ldarg.0 IL_000f: ldflda ""S1 S2.S1"" IL_0014: ldc.i4.s 43 IL_0016: stfld ""int S1.Y"" IL_001b: ret } "); } [Fact] public void ImplicitlyInitializedFields_Nested_FullyInitialized_02() { var source = @" public struct S1 { public int X, Y; } public struct S2 { public S1 S1; public S2() { this = default; } }"; var verifier = CompileAndVerify(source, options: TestOptions.DebugDll.WithSpecificDiagnosticOptions(ReportStructInitializationWarnings)); verifier.VerifyDiagnostics(); verifier.VerifyIL("S2..ctor", @" { // Code size 9 (0x9) .maxstack 1 IL_0000: nop IL_0001: ldarg.0 IL_0002: initobj ""S2"" IL_0008: ret } "); } [Fact] public void ImplicitlyInitializedFields_Nested_FullyInitialized_03() { var source = @" public struct S1 { public int X, Y; } public struct S2 { public S1 S1; public S2() { S1 = default; } }"; var verifier = CompileAndVerify(source, options: TestOptions.DebugDll.WithSpecificDiagnosticOptions(ReportStructInitializationWarnings)); verifier.VerifyDiagnostics(); verifier.VerifyIL("S2..ctor", @" { // Code size 14 (0xe) .maxstack 1 IL_0000: nop IL_0001: ldarg.0 IL_0002: ldflda ""S1 S2.S1"" IL_0007: initobj ""S1"" IL_000d: ret } "); } [Fact] [WorkItem(59890, "https://github.com/dotnet/roslyn/issues/59890")] public void ImplicitlyInitializedFields_Nested_PartiallyInitialized() { var source = @" public struct S1 { public int X, Y; } public struct S2 { public S1 S1; public S2() { S1.X = 42; } }"; var verifier = CompileAndVerify(source, options: TestOptions.DebugDll.WithSpecificDiagnosticOptions(ReportStructInitializationWarnings)); verifier.VerifyDiagnostics( // (11,12): warning CS9022: Control is returned to caller before field 'S2.S1' is explicitly assigned, causing a preceding implicit assignment of 'default'. // public S2() Diagnostic(ErrorCode.WRN_UnassignedThisSupportedVersion, "S2").WithArguments("S2.S1").WithLocation(11, 12)); verifier.VerifyIL("S2..ctor", @" { // Code size 27 (0x1b) .maxstack 2 IL_0000: nop IL_0001: ldarg.0 IL_0002: ldflda ""S1 S2.S1"" IL_0007: initobj ""S1"" IL_000d: ldarg.0 IL_000e: ldflda ""S1 S2.S1"" IL_0013: ldc.i4.s 42 IL_0015: stfld ""int S1.X"" IL_001a: ret } "); } [Fact] [WorkItem(59890, "https://github.com/dotnet/roslyn/issues/59890")] public void ImplicitlyInitializedFields_Conditional_01() { var source = @" public struct S { public int X; public S(bool b) { if (b) { X = 42; } } }"; var verifier = CompileAndVerify(source, options: TestOptions.DebugDll.WithSpecificDiagnosticOptions(ReportStructInitializationWarnings)); verifier.VerifyDiagnostics( // (6,12): warning CS9022: Control is returned to caller before field 'S.X' is explicitly assigned, causing a preceding implicit assignment of 'default'. // public S(bool b) Diagnostic(ErrorCode.WRN_UnassignedThisSupportedVersion, "S").WithArguments("S.X").WithLocation(6, 12)); verifier.VerifyIL("S..ctor", @" { // Code size 24 (0x18) .maxstack 2 .locals init (bool V_0) IL_0000: nop IL_0001: ldarg.0 IL_0002: ldc.i4.0 IL_0003: stfld ""int S.X"" IL_0008: ldarg.1 IL_0009: stloc.0 IL_000a: ldloc.0 IL_000b: brfalse.s IL_0017 IL_000d: nop IL_000e: ldarg.0 IL_000f: ldc.i4.s 42 IL_0011: stfld ""int S.X"" IL_0016: nop IL_0017: ret } "); } [Fact] public void ImplicitlyInitializedFields_Conditional_02() { var source = @" public struct S1 { public int X, Y; } public struct S2 { public S1 S1; public S2(bool b) { if (b) { this = default; } } }"; var verifier = CompileAndVerify(source, options: TestOptions.DebugDll.WithSpecificDiagnosticOptions(ReportStructInitializationWarnings)); verifier.VerifyDiagnostics( // (11,12): warning CS9022: Control is returned to caller before field 'S2.S1' is explicitly assigned, causing a preceding implicit assignment of 'default'. // public S2(bool b) Diagnostic(ErrorCode.WRN_UnassignedThisSupportedVersion, "S2").WithArguments("S2.S1").WithLocation(11, 12)); verifier.VerifyIL("S2..ctor", @" { // Code size 28 (0x1c) .maxstack 1 .locals init (bool V_0) IL_0000: nop IL_0001: ldarg.0 IL_0002: ldflda ""S1 S2.S1"" IL_0007: initobj ""S1"" IL_000d: ldarg.1 IL_000e: stloc.0 IL_000f: ldloc.0 IL_0010: brfalse.s IL_001b IL_0012: nop IL_0013: ldarg.0 IL_0014: initobj ""S2"" IL_001a: nop IL_001b: ret } "); } [Fact] public void ImplicitlyInitializedFields_SequencePoints() { // note: our testing is relatively limited here because: // - there are no iterator constructors or async constructors // - the implicit initializations can only occur on constructors which lack constructor initializers var source = @" public struct S { public int X; public S() { X.ToString(); } }"; var verifier = CompileAndVerify(source, options: TestOptions.DebugDll.WithSpecificDiagnosticOptions(ReportStructInitializationWarnings)); verifier.VerifyDiagnostics( // (6,12): warning CS9022: Control is returned to caller before field 'S.X' is explicitly assigned, causing a preceding implicit assignment of 'default'. // public S(string s!!) Diagnostic(ErrorCode.WRN_UnassignedThisSupportedVersion, "S").WithArguments("S.X").WithLocation(6, 12), // (8,9): warning CS9019: Field 'X' is read before being explicitly assigned, causing a preceding implicit assignment of 'default'. // X.ToString(); Diagnostic(ErrorCode.WRN_UseDefViolationFieldSupportedVersion, "X").WithArguments("X").WithLocation(8, 9)); verifier.VerifyIL("S..ctor", @" { // Code size 21 (0x15) .maxstack 2 // sequence point: { IL_0000: nop // sequence point: <hidden> IL_0001: ldarg.0 IL_0002: ldc.i4.0 IL_0003: stfld ""int S.X"" // sequence point: X.ToString(); IL_0008: ldarg.0 IL_0009: ldflda ""int S.X"" IL_000e: call ""string int.ToString()"" IL_0013: pop // sequence point: } IL_0014: ret } ", sequencePointDisplay: SequencePointDisplayMode.Enhanced); } [Fact] public void ImplicitlyInitializedFields_SequencePoints_ExpressionBody() { var source = @" public struct S { public int X; public S() => X.ToString(); }"; var verifier = CompileAndVerify(source, options: TestOptions.DebugDll.WithSpecificDiagnosticOptions(ReportStructInitializationWarnings)); verifier.VerifyDiagnostics( // (6,12): warning CS9022: Control is returned to caller before field 'S.X' is explicitly assigned, causing a preceding implicit assignment of 'default'. // public S() Diagnostic(ErrorCode.WRN_UnassignedThisSupportedVersion, "S").WithArguments("S.X").WithLocation(6, 12), // (7,12): warning CS9019: Field 'X' is read before being explicitly assigned, causing a preceding implicit assignment of 'default'. // => X.ToString(); Diagnostic(ErrorCode.WRN_UseDefViolationFieldSupportedVersion, "X").WithArguments("X").WithLocation(7, 12)); verifier.VerifyIL("S..ctor", @" { // Code size 20 (0x14) .maxstack 2 // sequence point: <hidden> IL_0000: ldarg.0 IL_0001: ldc.i4.0 IL_0002: stfld ""int S.X"" // sequence point: X.ToString() IL_0007: ldarg.0 IL_0008: ldflda ""int S.X"" IL_000d: call ""string int.ToString()"" IL_0012: pop IL_0013: ret } ", sequencePointDisplay: SequencePointDisplayMode.Enhanced); } [Fact] public void ImplicitlyInitializedFields_PragmaRestore() { var source = @" public struct S { public int X; #pragma warning restore CS9022 public S() { } }"; var comp = CreateCompilation(source, options: TestOptions.DebugDll.WithSpecificDiagnosticOptions(ReportStructInitializationWarnings)); comp.VerifyDiagnostics( // (6,12): warning CS9022: Control is returned to caller before field 'S.X' is explicitly assigned, causing a preceding implicit assignment of 'default'. // public S() Diagnostic(ErrorCode.WRN_UnassignedThisSupportedVersion, "S").WithArguments("S.X").WithLocation(6, 12)); comp = CreateCompilation(source); comp.VerifyDiagnostics(); } [Fact] public void ImplicitlyInitializedFields_PragmaDisable() { var source = @" public struct S { public int X; #pragma warning disable CS9022 public S() { } }"; var comp = CreateCompilation(source, options: TestOptions.DebugDll.WithSpecificDiagnosticOptions(ReportStructInitializationWarnings)); comp.VerifyDiagnostics(); comp = CreateCompilation(source); comp.VerifyDiagnostics(); } [Fact] public void ImplicitlyInitializedFields_AssignDefault() { var source = @" #nullable enable public struct SParameterless { public string Field; public SParameterless() { Field = ""a""; } } public struct SEmpty { } public struct S<T> { public string AutoProp { get; set; } public T TField; public SParameterless Parameterless; public SEmpty Empty; public S() { AutoProp = default; TField = default; Parameterless = default; Empty = default; } public S(bool unused) { } }"; var verifier = CompileAndVerify(source, options: TestOptions.DebugDll.WithSpecificDiagnosticOptions(ReportStructInitializationWarnings)); verifier.VerifyDiagnostics( // (21,12): warning CS8618: Non-nullable field 'TField' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the field as nullable. // public S() Diagnostic(ErrorCode.WRN_UninitializedNonNullableField, "S").WithArguments("field", "TField").WithLocation(21, 12), // (21,12): warning CS8618: Non-nullable property 'AutoProp' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the property as nullable. // public S() Diagnostic(ErrorCode.WRN_UninitializedNonNullableField, "S").WithArguments("property", "AutoProp").WithLocation(21, 12), // (23,20): warning CS8625: Cannot convert null literal to non-nullable reference type. // AutoProp = default; Diagnostic(ErrorCode.WRN_NullAsNonNullable, "default").WithLocation(23, 20), // (24,18): warning CS8601: Possible null reference assignment. // TField = default; Diagnostic(ErrorCode.WRN_NullReferenceAssignment, "default").WithLocation(24, 18), // (29,12): warning CS8618: Non-nullable field 'TField' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the field as nullable. // public S(bool unused) Diagnostic(ErrorCode.WRN_UninitializedNonNullableField, "S").WithArguments("field", "TField").WithLocation(29, 12), // (29,12): warning CS8618: Non-nullable property 'AutoProp' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the property as nullable. // public S(bool unused) Diagnostic(ErrorCode.WRN_UninitializedNonNullableField, "S").WithArguments("property", "AutoProp").WithLocation(29, 12), // (29,12): warning CS9022: Control is returned to caller before field 'S<T>.TField' is explicitly assigned, causing a preceding implicit assignment of 'default'. // public S(bool unused) Diagnostic(ErrorCode.WRN_UnassignedThisSupportedVersion, "S").WithArguments("S<T>.TField").WithLocation(29, 12), // (29,12): warning CS9022: Control is returned to caller before field 'S<T>.Parameterless' is explicitly assigned, causing a preceding implicit assignment of 'default'. // public S(bool unused) Diagnostic(ErrorCode.WRN_UnassignedThisSupportedVersion, "S").WithArguments("S<T>.Parameterless").WithLocation(29, 12), // (29,12): warning CS9021: Control is returned to caller before auto-implemented property 'S<T>.AutoProp' is explicitly assigned, causing a preceding implicit assignment of 'default'. // public S(bool unused) Diagnostic(ErrorCode.WRN_UnassignedThisAutoPropertySupportedVersion, "S").WithArguments("S<T>.AutoProp").WithLocation(29, 12)); verifyIL(); verifier = CompileAndVerify(source, options: TestOptions.DebugDll); verifier.VerifyDiagnostics( // (21,12): warning CS8618: Non-nullable field 'TField' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the field as nullable. // public S() Diagnostic(ErrorCode.WRN_UninitializedNonNullableField, "S").WithArguments("field", "TField").WithLocation(21, 12), // (21,12): warning CS8618: Non-nullable property 'AutoProp' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the property as nullable. // public S() Diagnostic(ErrorCode.WRN_UninitializedNonNullableField, "S").WithArguments("property", "AutoProp").WithLocation(21, 12), // (23,20): warning CS8625: Cannot convert null literal to non-nullable reference type. // AutoProp = default; Diagnostic(ErrorCode.WRN_NullAsNonNullable, "default").WithLocation(23, 20), // (24,18): warning CS8601: Possible null reference assignment. // TField = default; Diagnostic(ErrorCode.WRN_NullReferenceAssignment, "default").WithLocation(24, 18), // (29,12): warning CS8618: Non-nullable field 'TField' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the field as nullable. // public S(bool unused) Diagnostic(ErrorCode.WRN_UninitializedNonNullableField, "S").WithArguments("field", "TField").WithLocation(29, 12), // (29,12): warning CS8618: Non-nullable property 'AutoProp' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the property as nullable. // public S(bool unused) Diagnostic(ErrorCode.WRN_UninitializedNonNullableField, "S").WithArguments("property", "AutoProp").WithLocation(29, 12)); verifyIL(); void verifyIL() { verifier.VerifyIL("S<T>..ctor()", @" { // Code size 46 (0x2e) .maxstack 2 IL_0000: nop IL_0001: ldarg.0 IL_0002: ldnull IL_0003: call ""void S<T>.AutoProp.set"" IL_0008: nop IL_0009: ldarg.0 IL_000a: ldflda ""T S<T>.TField"" IL_000f: initobj ""T"" IL_0015: ldarg.0 IL_0016: ldflda ""SParameterless S<T>.Parameterless"" IL_001b: initobj ""SParameterless"" IL_0021: ldarg.0 IL_0022: ldflda ""SEmpty S<T>.Empty"" IL_0027: initobj ""SEmpty"" IL_002d: ret } "); verifier.VerifyIL("S<T>..ctor(bool)", @" { // Code size 33 (0x21) .maxstack 2 IL_0000: nop IL_0001: ldarg.0 IL_0002: ldnull IL_0003: stfld ""string S<T>.<AutoProp>k__BackingField"" IL_0008: ldarg.0 IL_0009: ldflda ""T S<T>.TField"" IL_000e: initobj ""T"" IL_0014: ldarg.0 IL_0015: ldflda ""SParameterless S<T>.Parameterless"" IL_001a: initobj ""SParameterless"" IL_0020: ret } "); } } [Fact] public void NonNullableReferenceTypeField() { var source = @"public struct S { public string Item; public S(bool unused) { } }"; var comp = CreateCompilation(new[] { source }, options: WithNullableEnable(), parseOptions: TestOptions.Regular10); comp.VerifyDiagnostics( // (4,12): warning CS8618: Non-nullable field 'Item' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the field as nullable. // public S(bool unused) Diagnostic(ErrorCode.WRN_UninitializedNonNullableField, "S").WithArguments("field", "Item").WithLocation(4, 12), // (4,12): error CS0171: Field 'S.Item' must be fully assigned before control is returned to the caller. Consider updating to language version '11.0' to auto-default the field. // public S(bool unused) Diagnostic(ErrorCode.ERR_UnassignedThisUnsupportedVersion, "S").WithArguments("S.Item", "11.0").WithLocation(4, 12) ); var verifier = CompileAndVerify(new[] { source }, options: WithNullableEnable(), parseOptions: TestOptions.Regular11); verifier.VerifyDiagnostics( // (4,12): warning CS8618: Non-nullable field 'Item' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the field as nullable. // public S(bool unused) Diagnostic(ErrorCode.WRN_UninitializedNonNullableField, "S").WithArguments("field", "Item").WithLocation(4, 12)); verifier.VerifyIL("S..ctor", @" { // Code size 8 (0x8) .maxstack 2 IL_0000: ldarg.0 IL_0001: ldnull IL_0002: stfld ""string S.Item"" IL_0007: ret } "); } [Theory] [InlineData(LanguageVersion.CSharp10)] [InlineData(LanguageVersion.CSharp11)] public void Struct_ExplicitThisConstructorInitializer_01(LanguageVersion languageVersion) { var source = @"public struct S { public string Item; public S(bool unused) : this() { } }"; var verifier = CompileAndVerify(new[] { source }, options: WithNullableEnable(), parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion)); verifier.VerifyDiagnostics( // (4,12): warning CS8618: Non-nullable field 'Item' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the field as nullable. // public S(bool unused) Diagnostic(ErrorCode.WRN_UninitializedNonNullableField, "S").WithArguments("field", "Item").WithLocation(4, 12) ); verifier.VerifyIL("S..ctor", @" { // Code size 8 (0x8) .maxstack 1 IL_0000: ldarg.0 IL_0001: initobj ""S"" IL_0007: ret } "); } [Theory] [InlineData(LanguageVersion.CSharp10)] [InlineData(LanguageVersion.CSharp11)] public void Struct_ExplicitThisConstructorInitializer_02(LanguageVersion languageVersion) { var source = @"public struct S { public string Item; public S(bool unused) : this() { } public S() { Item = ""a""; } }"; var verifier = CompileAndVerify(new[] { source }, options: WithNullableEnable(), parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion)); verifier.VerifyDiagnostics(); verifier.VerifyIL("S..ctor(bool)", @" { // Code size 7 (0x7) .maxstack 1 IL_0000: ldarg.0 IL_0001: call ""S..ctor()"" IL_0006: ret } "); verifier.VerifyIL("S..ctor()", @" { // Code size 12 (0xc) .maxstack 2 IL_0000: ldarg.0 IL_0001: ldstr ""a"" IL_0006: stfld ""string S.Item"" IL_000b: ret } "); } [Theory] [InlineData("class")] [InlineData("struct")] [WorkItem("https://devdiv.visualstudio.com/DevDiv/_workitems/edit/1598252")] public void StaticAndInstanceConstructors_01(string type) { string source = $$""" using System; {{type}} S { static S() { Console.WriteLine("static constructor"); } public S(int p) { Console.WriteLine("instance constructor: {0}", p); } public S() : this(0) { } } class Program { static void Main() { _ = new S(); } } """; var comp = CreateCompilation(source, options: TestOptions.ReleaseExe); VerifyExplicitlyDeclaredInstanceConstructors( comp.GlobalNamespace.GetTypeMember("S"), "S..ctor(System.Int32 p)", "S..ctor()"); VerifyExplicitlyDeclaredInstanceConstructors( ((Compilation)comp).GlobalNamespace.GetTypeMember("S"), "S..ctor(System.Int32 p)", "S..ctor()"); CompileAndVerify(comp, expectedOutput: """ static constructor instance constructor: 0 """); } [Theory] [InlineData("class")] [InlineData("struct")] public void StaticAndInstanceConstructors_02(string type) { string source = $$""" using System; {{type}} S { static S() { Console.WriteLine("static constructor"); } public S() { Console.WriteLine("instance constructor"); } } class Program { static void Main() { _ = new S(); } } """; var comp = CreateCompilation(source, options: TestOptions.ReleaseExe); VerifyExplicitlyDeclaredInstanceConstructors( comp.GlobalNamespace.GetTypeMember("S"), "S..ctor()"); VerifyExplicitlyDeclaredInstanceConstructors( ((Compilation)comp).GlobalNamespace.GetTypeMember("S"), "S..ctor()"); CompileAndVerify(comp, expectedOutput: """ static constructor instance constructor """); } private static void VerifyExplicitlyDeclaredInstanceConstructors(NamedTypeSymbol type, params string[] expectedConstructors) { var constructors = type.InstanceConstructors; var members = type.GetMembers(".ctor"); Assert.True(members.SequenceEqual(constructors)); Assert.True(constructors.All(c => c is { IsStatic: false, IsImplicitConstructor: false })); Assert.Equal(expectedConstructors, constructors.ToTestDisplayStrings()); } private static void VerifyExplicitlyDeclaredInstanceConstructors(INamedTypeSymbol type, params string[] expectedConstructors) { var constructors = type.InstanceConstructors; var members = type.GetMembers(".ctor"); Assert.True(members.SequenceEqual(constructors)); Assert.True(constructors.All(c => c is { IsStatic: false, IsImplicitlyDeclared: false })); Assert.Equal(expectedConstructors, constructors.ToTestDisplayStrings()); } } }