/
githubmirror
/
roslyn
Обзор
Документация
Войти
/
githubmirror
/
roslyn
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
src/Compilers/CSharp/Test/Semantic/Semantics/ConstantTests.cs
4 252 строки
171 KB
Julien Couvreur
Fix circularity issue with binding const local (#75371)
11 окт 2024, 20:16
Не верифицирован
11 окт 2024, 20:16
d1afb2f
Код
Авторство
О чём код?
// 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; using System.Collections.Generic; using System.Globalization; using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.CSharp.Symbols; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.CSharp.Test.Utilities; using Roslyn.Test.Utilities; using Xunit; namespace Microsoft.CodeAnalysis.CSharp.UnitTests { public class ConstantTests : CompilingTestBase { [Fact] public void TestConstantFolding() { // TODO: explicit conversions // TODO: constants from metadata // TODO: char, byte, sbyte, short, ushort, long, ulong var source = @"using System; class C { void M() { const int x = ((1 + 2 * 3) / (4 >> 1) ) << (5 % 3); const double y = (1.0 + (11.0 % (2.0 * 3.0))) / 4.0; const bool z = (1 < 2) & (3 > 2) & (10.0 < 11.0) & (120m >= 13m) & (3 != 4) & (""hello"" == ""hello""); const char c = (char)('a' + 2); const long lng1 = -2147483648U; const long lng2 = -2147483648u; const long lng3 = -2147483648L; const long lng4 = -2147483648l; const int minint = -2147483648 + 0; const long minlong = -9223372036854775808 + 0; const string s1 = ""hello"" + ""goodbye""; string s2 = ""abc"" + 123; // This is NOT a constant because it involves a boxing conversion. const string s3 = ""not null"" + null; const bool b = (null == null) & (null != null); const bool b2 = b & !b; const string s4 = s1 + s3; // According to the spec these are not constants but according to the native compiler // they are; we preserve this bug in Roslyn. const byte zero1 = new byte(); const ushort zero2 = new ushort(); const uint zero3 = new uint(); const ulong zero4 = new ulong(); const sbyte zero5 = new sbyte(); const short zero6 = new short(); const int zero7 = new int(); const long zero8 = new long(); const decimal zero9 = new decimal(); const double zero10 = new double(); const float zero11 = new float(); const char zero12 = new char(); const DayOfWeek zero13 = new DayOfWeek(); const long negUnsigned = -2u; const decimal dec1 = 100.0m % 3m; const decimal dec2 = 100.0m / 3m; const decimal dec3 = 100.0m - 50.00m; const double unplus1 = +123.4d; const float unplus2 = +123.4f; const decimal unplus3 = +123.4m; } "; var actual = ParseAndGetConstantFoldingSteps(source); var expected = @"((1 + 2 * 3) / (4 >> 1) ) << (5 % 3) --> 12 (1 + 2 * 3) / (4 >> 1) --> 3 1 + 2 * 3 --> 7 2 * 3 --> 6 4 >> 1 --> 2 5 % 3 --> 2 (1.0 + (11.0 % (2.0 * 3.0))) / 4.0 --> 1.5 1.0 + (11.0 % (2.0 * 3.0)) --> 6 11.0 % (2.0 * 3.0) --> 5 2.0 * 3.0 --> 6 (1 < 2) & (3 > 2) & (10.0 < 11.0) & (120m >= 13m) & (3 != 4) & (""hello"" == ""hello"") --> True (1 < 2) & (3 > 2) & (10.0 < 11.0) & (120m >= 13m) & (3 != 4) --> True (1 < 2) & (3 > 2) & (10.0 < 11.0) & (120m >= 13m) --> True (1 < 2) & (3 > 2) & (10.0 < 11.0) --> True (1 < 2) & (3 > 2) --> True 1 < 2 --> True 3 > 2 --> True 10.0 < 11.0 --> True 120m >= 13m --> True 3 != 4 --> True ""hello"" == ""hello"" --> True (char)('a' + 2) --> c 'a' + 2 --> 99 'a' --> 97 -2147483648U --> -2147483648 2147483648U --> 2147483648 -2147483648u --> -2147483648 2147483648u --> 2147483648 -2147483648L --> -2147483648 -2147483648l --> -2147483648 -2147483648 + 0 --> -2147483648 -9223372036854775808 + 0 --> -9223372036854775808 0 --> 0 ""hello"" + ""goodbye"" --> hellogoodbye ""not null"" + null --> not null null --> null (null == null) & (null != null) --> False b & !b --> False !b --> True s1 + s3 --> hellogoodbyenot null new byte() --> 0 new ushort() --> 0 new uint() --> 0 new ulong() --> 0 new sbyte() --> 0 new short() --> 0 new int() --> 0 new long() --> 0 new decimal() --> 0 new double() --> 0 new float() --> 0 new char() --> control character new DayOfWeek() --> 0 -2u --> -2 2u --> 2 100.0m % 3m --> 1.0 100.0m / 3m --> 33.333333333333333333333333333 100.0m - 50.00m --> 50.00 +123.4d --> 123.4 +123.4f --> 123.4 +123.4m --> 123.4"; Assert.Equal(expected, actual); } [Fact] public void ParameterlessCtorsInStructs() { var source = @" struct S1 { } struct S2 { public S2() { } } class Program { static void Main(string[] args) { } static void Goo(S1 s = new S1()) { } static void Goo(S2 s = new S2()) { } } "; var comp = CreateCompilation(source, parseOptions: TestOptions.Regular9); comp.VerifyDiagnostics( // (10,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(10, 12), // (26,28): error CS1736: Default parameter value for 's' must be a compile-time constant // static void Goo(S2 s = new S2()) Diagnostic(ErrorCode.ERR_DefaultValueMustBeConstant, "new S2()").WithArguments("s").WithLocation(26, 28)); } [Fact] public void TestConstantInt32Comparisons() { var source = @"class C { void M() { const bool comp1 = 1 < 2; const bool comp2 = 1 <= 2; const bool comp3 = 1 > 2; const bool comp4 = 1 >= 2; const bool comp5 = 1 == 2; const bool comp6 = 1 != 2; } "; var actual = ParseAndGetConstantFoldingSteps(source); var expected = @"1 < 2 --> True 1 <= 2 --> True 1 > 2 --> False 1 >= 2 --> False 1 == 2 --> False 1 != 2 --> True"; Assert.Equal(expected, actual); } [Fact] public void TestConstantUInt32Comparisons() { var source = @"class C { void M() { const bool comp1 = 1u < 2u; const bool comp2 = 1u <= 2u; const bool comp3 = 1u > 2u; const bool comp4 = 1u >= 2u; const bool comp5 = 1u == 2u; const bool comp6 = 1u != 2u; } "; var actual = ParseAndGetConstantFoldingSteps(source); var expected = @"1u < 2u --> True 1u <= 2u --> True 1u > 2u --> False 1u >= 2u --> False 1u == 2u --> False 1u != 2u --> True"; Assert.Equal(expected, actual); } [Fact] public void TestConstantInt64Comparisons() { var source = @"class C { void M() { const bool comp1 = 1L < 2L; const bool comp2 = 1L <= 2L; const bool comp3 = 1L > 2L; const bool comp4 = 1L >= 2L; const bool comp5 = 1L == 2L; const bool comp6 = 1L != 2L; } "; var actual = ParseAndGetConstantFoldingSteps(source); var expected = @"1L < 2L --> True 1L <= 2L --> True 1L > 2L --> False 1L >= 2L --> False 1L == 2L --> False 1L != 2L --> True"; Assert.Equal(expected, actual); } [Fact] public void TestConstantUInt64Comparisons() { var source = @"class C { void M() { const bool comp1 = 1UL < 2UL; const bool comp2 = 1UL <= 2UL; const bool comp3 = 1UL > 2UL; const bool comp4 = 1UL >= 2UL; const bool comp5 = 1UL == 2UL; const bool comp6 = 1UL != 2UL; } "; var actual = ParseAndGetConstantFoldingSteps(source); var expected = @"1UL < 2UL --> True 1UL <= 2UL --> True 1UL > 2UL --> False 1UL >= 2UL --> False 1UL == 2UL --> False 1UL != 2UL --> True"; Assert.Equal(expected, actual); } [Fact] public void TestConstantFloatComparisons() { var source = @"class C { void M() { const bool comp1 = 1f < 2f; const bool comp2 = 1f <= 2f; const bool comp3 = 1f > 2f; const bool comp4 = 1f >= 2f; const bool comp5 = 1f == 2f; const bool comp6 = 1f != 2f; } "; var actual = ParseAndGetConstantFoldingSteps(source); var expected = @"1f < 2f --> True 1f <= 2f --> True 1f > 2f --> False 1f >= 2f --> False 1f == 2f --> False 1f != 2f --> True"; Assert.Equal(expected, actual); } [Fact] public void TestConstantDecimalComparisons01() { var source = @"class C { void M() { const bool comp1 = 1m < 2m; const bool comp2 = 1m <= 2m; const bool comp3 = 1m > 2m; const bool comp4 = 1m >= 2m; const bool comp5 = 1m == 2m; const bool comp6 = 1m != 2m; } }"; var actual = ParseAndGetConstantFoldingSteps(source); var expected = @"1m < 2m --> True 1m <= 2m --> True 1m > 2m --> False 1m >= 2m --> False 1m == 2m --> False 1m != 2m --> True"; Assert.Equal(expected, actual); } [Fact(Skip = "https://github.com/dotnet/roslyn/issues/7803")] public void TestConstantDecimalComparisons02() { var source = @"class C { void M() { const bool comp1 = 0m < -0m; const bool comp2 = 0m <= -0m; const bool comp3 = 0m > -0m; const bool comp4 = 0m >= -0m; const bool comp5 = 0m == -0m; const bool comp6 = 0m != -0m; } }"; var actual = ParseAndGetConstantFoldingSteps(source); var expected = @"0m < -0m --> False -0m --> 0 0m <= -0m --> True -0m --> 0 0m > -0m --> False -0m --> 0 0m >= -0m --> True -0m --> 0 0m == -0m --> True -0m --> 0 0m != -0m --> False -0m --> 0"; Assert.Equal(expected, actual); } [Fact] public void TestConstantDoubleComparisons() { var source = @"class C { void M() { const bool comp1 = 1d < 2d; const bool comp2 = 1d <= 2d; const bool comp3 = 1d > 2d; const bool comp4 = 1d >= 2d; const bool comp5 = 1d == 2d; const bool comp6 = 1d != 2d; } "; var actual = ParseAndGetConstantFoldingSteps(source); var expected = @"1d < 2d --> True 1d <= 2d --> True 1d > 2d --> False 1d >= 2d --> False 1d == 2d --> False 1d != 2d --> True"; Assert.Equal(expected, actual); } private static readonly string[] s_enumTypeQualifiers = { "", " : sbyte", " : byte", " : short", " : ushort", " : int", " : uint", " : long", " : ulong", }; [Fact] public void TestExplicitEnumIntConversions() { foreach (var typeQualifier in s_enumTypeQualifiers) { var source = @"enum E" + typeQualifier + @" { A, B = 64, C } class C { static void F(E e) { } static void M() { const E e = E.C; const sbyte s8 = (sbyte)e; const byte u8 = (byte)e; const short s16 = (short)e; const ushort u16 = (ushort)e; const int s32 = (int)e; const uint u32 = (uint)e; const long s64 = (long)e; const ulong u64 = (ulong)e; const char c = (char)e; const float f = (float)e; const double d = (double)e; const decimal dec = (decimal)e; F((E)s8); F((E)u8); F((E)s16); F((E)u16); F((E)s32); F((E)u32); F((E)s64); F((E)u64); F((E)c); F((E)f); F((E)d); F((E)dec); } }"; var actual = ParseAndGetConstantFoldingSteps(source); var expected = @"E.C --> 65 (sbyte)e --> 65 (byte)e --> 65 (short)e --> 65 (ushort)e --> 65 (int)e --> 65 (uint)e --> 65 (long)e --> 65 (ulong)e --> 65 (char)e --> A (float)e --> 65 (double)e --> 65 (decimal)e --> 65 (E)s8 --> 65 (E)u8 --> 65 (E)s16 --> 65 (E)u16 --> 65 (E)s32 --> 65 (E)u32 --> 65 (E)s64 --> 65 (E)u64 --> 65 (E)c --> 65 (E)f --> 65 (E)d --> 65 (E)dec --> 65"; Assert.Equal(expected, actual); } } [Fact] public void TestExplicitEnumEnumConversions() { foreach (var typeQualifier in s_enumTypeQualifiers) { var source = @"enum E" + typeQualifier + @" { A, B = 3, C } enum S8 : sbyte { A, B, C } enum U8 : byte { A, B, C } enum S16 : short { A, B, C } enum U16 : ushort { A, B, C } enum S32 : int { A, B, C } enum U32 : uint { A, B, C } enum S64 : long { A, B, C } enum U64 : ulong { A, B, C } class C { static void M() { const E e = E.C; S8 s8 = (S8)e; U8 u8 = (U8)e; S16 s16 = (S16)e; U16 u16 = (U16)e; S32 s32 = (S32)e; U32 u32 = (U32)e; S64 s64 = (S64)e; U64 u64 = (U64)e; } }"; var actual = ParseAndGetConstantFoldingSteps(source); var expected = @"E.C --> 4 (S8)e --> 4 (U8)e --> 4 (S16)e --> 4 (U16)e --> 4 (S32)e --> 4 (U32)e --> 4 (S64)e --> 4 (U64)e --> 4"; Assert.Equal(expected, actual); } } [Fact] public void TestConstantEnumOperations() { foreach (var typeQualifier in s_enumTypeQualifiers) { var source = @"enum E" + typeQualifier + @" { A, B, C } class C { static void M() { E add1 = E.B + 1; E add2 = 2 + E.C; var sub1 = E.C - E.B; E sub2 = E.C - 2; bool comp1 = E.A == E.B; bool comp2 = E.A != E.B; bool comp3 = E.A == 0; bool comp4 = 0 != E.B; bool comp5 = E.A < E.A; bool comp6 = E.B > E.A; bool comp7 = E.A <= E.A; bool comp8 = E.B >= E.A; bool comp9 = 0 <= E.A; bool comp10 = E.B >= 0; E logical1 = E.B & E.C; E logical2 = E.B | E.C; E logical3 = E.B ^ E.C; } }"; var actual = ParseAndGetConstantFoldingSteps(source, node => node.Kind == BoundKind.BinaryOperator); var expected = @"E.B + 1 --> 2 2 + E.C --> 4 E.C - E.B --> 1 E.C - 2 --> 0 E.A == E.B --> False E.A != E.B --> True E.A == 0 --> True 0 != E.B --> True E.A < E.A --> False E.B > E.A --> True E.A <= E.A --> True E.B >= E.A --> True 0 <= E.A --> True E.B >= 0 --> True E.B & E.C --> 0 E.B | E.C --> 3 E.B ^ E.C --> 3"; Assert.Equal(expected, actual); } } [Fact] public void TestConstantEnumBitwiseComplement() { var source = @"enum S8 : sbyte { A, B, C } enum U8 : byte { A, B, C } enum S16 : short { A, B, C } enum U16 : ushort { A, B, C } enum S32 : int { A, B, C } enum U32 : uint { A, B, C } enum S64 : long { A, B, C } enum U64 : ulong { A, B, C } class C { static void M() { const S8 s8 = ~S8.A; const U8 u8 = ~U8.B; const S16 s16 = ~S16.A; const U16 u16 = ~U16.B; const S32 s32 = ~S32.B; const U32 u32 = ~U32.C; const S64 s64 = ~S64.B; const U64 u64 = ~U64.C; } }"; var actual = ParseAndGetConstantFoldingSteps(source, node => node.Kind == BoundKind.UnaryOperator); var expected = @"~S8.A --> -1 ~U8.B --> 254 ~S16.A --> -1 ~U16.B --> 65534 ~S32.B --> -2 ~U32.C --> 4294967293 ~S64.B --> -2 ~U64.C --> 18446744073709551613"; Assert.Equal(expected, actual); } [Fact] public void TestConstantBooleanOperations() { var source = @"class C { void M() { const bool op1 = !true; const bool op2 = true && false; const bool op3 = true || false; const bool op4 = true & false; const bool op5 = true | false; const bool op6 = true == false; const bool op7 = true != false; } "; var actual = ParseAndGetConstantFoldingSteps(source); var expected = @"!true --> False true && false --> False true || false --> True true & false --> False true | false --> True true == false --> False true != false --> True"; Assert.Equal(expected, actual); } [Fact] public void TestEnumOverflowErrors() { string source = @"enum S8 : sbyte { Min = sbyte.MinValue, MinPlusOne, Max = sbyte.MaxValue } enum U8 : byte { Min = byte.MinValue, MinPlusOne, Max = byte.MaxValue } enum S16 : short { Min = short.MinValue, MinPlusOne, Max = short.MaxValue } enum U16 : ushort { Min = ushort.MinValue, MinPlusOne, Max = ushort.MaxValue } enum S32 : int { Min = int.MinValue, MinPlusOne, Max = int.MaxValue } enum U32 : uint { Min = uint.MinValue, MinPlusOne, Max = uint.MaxValue } enum S64 : long { Min = long.MinValue, MinPlusOne, Max = long.MaxValue } enum U64 : ulong { Min = ulong.MinValue, MinPlusOne, Max = ulong.MaxValue } class C { static void F(S8 x) { } static void F(U8 x) { } static void F(S16 x) { } static void F(U16 x) { } static void F(S32 x) { } static void F(U32 x) { } static void F(S64 x) { } static void F(U64 x) { } static void F(sbyte x) { } static void F(byte x) { } static void F(short x) { } static void F(ushort x) { } static void F(int x) { } static void F(uint x) { } static void F(long x) { } static void F(ulong x) { } static void M() { // E + U F(S8.Max + 1); // 128 cannot be converted to ... F(U8.Max + 1); // 256 cannot be converted to ... F(S16.Max + 1); // 32768 cannot be converted to ... F(U16.Max + 1); // 65536 cannot be converted to ... F(S32.Max + 1); // overflows at compile time in checked mode F(U32.Max + 1); // overflows at compile time in checked mode F(S64.Max + 1); // overflows at compile time in checked mode F(U64.Max + 1); // overflows at compile time in checked mode // U + E F(2 + S8.Max); // 129 cannot be converted to ... F(2 + U8.Max); // 257 cannot be converted to ... F(2 + S16.Max); // 32769 cannot be converted to ... F(2 + U16.Max); // 65537 cannot be converted to ... F(2 + S32.Max); // overflows at compile time in checked mode F(2 + U32.Max); // overflows at compile time in checked mode F(2 + S64.Max); // overflows at compile time in checked mode F(2 + U64.Max); // overflows at compile time in checked mode // E - E F(S8.Min - S8.MinPlusOne); // no error F(U8.Min - U8.MinPlusOne); // -1 cannot be converted to ... F(S16.Min - S16.MinPlusOne); // no error F(U16.Min - U16.MinPlusOne); // -1 cannot be converted to ... F(S32.Min - S32.MinPlusOne); // no error F(U32.Min - U32.MinPlusOne); // overflows at compile time in checked mode F(S64.Min - S64.MinPlusOne); // no error F(U64.Min - U64.MinPlusOne); // overflows at compile time in checked mode // E - E F(S8.Min - S8.Max); // -255 cannot be converted to ... F(U8.Min - U8.Max); // -255 cannot be converted to ... F(S16.Min - S16.Max); // -65535 cannot be converted to ... F(U16.Min - U16.Max); // -65535 cannot be converted to ... F(S32.Min - S32.Max); // overflows at compile time in checked mode F(U32.Min - U32.Max); // overflows at compile time in checked mode F(S64.Min - S64.Max); // overflows at compile time in checked mode F(U64.Min - U64.Max); // overflows at compile time in checked mode // E - E F(S8.Max - S8.Min); // 255 cannot be converted to ... F(U8.Max - U8.Min); // no error F(S16.Max - S16.Min); // 65535 cannot be converted to ... F(U16.Max - U16.Min); // no error F(S32.Max - S32.Min); // overflows at compile time in checked mode F(U32.Max - U32.Min); // no error F(S64.Max - S64.Min); // overflows at compile time in checked mode F(U64.Max - U64.Min); // no error // E - U F(S8.Min - 2); // -130 cannot be converted to ... F(U8.Min - 2); // -2 cannot be converted to ... F(S16.Min - 2); // -32770 cannot be converted to ... F(U16.Min - 2); // -2 cannot be converted to ... F(S32.Min - 2); // overflows at compile time in checked mode F(U32.Min - 2); // overflows at compile time in checked mode F(S64.Min - 2); // overflows at compile time in checked mode F(U64.Min - 2); // overflows at compile time in checked mode } }"; CreateCompilation(source).VerifyDiagnostics( // (32,11): error CS0221: Constant value '128' cannot be converted to a 'S8' (use 'unchecked' syntax to override) // F(S8.Max + 1); // 128 cannot be converted to ... Diagnostic(ErrorCode.ERR_ConstOutOfRangeChecked, "S8.Max + 1").WithArguments("128", "S8").WithLocation(32, 11), // (33,11): error CS0221: Constant value '256' cannot be converted to a 'U8' (use 'unchecked' syntax to override) // F(U8.Max + 1); // 256 cannot be converted to ... Diagnostic(ErrorCode.ERR_ConstOutOfRangeChecked, "U8.Max + 1").WithArguments("256", "U8").WithLocation(33, 11), // (34,11): error CS0221: Constant value '32768' cannot be converted to a 'S16' (use 'unchecked' syntax to override) // F(S16.Max + 1); // 32768 cannot be converted to ... Diagnostic(ErrorCode.ERR_ConstOutOfRangeChecked, "S16.Max + 1").WithArguments("32768", "S16").WithLocation(34, 11), // (35,11): error CS0221: Constant value '65536' cannot be converted to a 'U16' (use 'unchecked' syntax to override) // F(U16.Max + 1); // 65536 cannot be converted to ... Diagnostic(ErrorCode.ERR_ConstOutOfRangeChecked, "U16.Max + 1").WithArguments("65536", "U16").WithLocation(35, 11), // (36,11): error CS0220: The operation overflows at compile time in checked mode // F(S32.Max + 1); // overflows at compile time in checked mode Diagnostic(ErrorCode.ERR_CheckedOverflow, "S32.Max + 1").WithLocation(36, 11), // (37,11): error CS0220: The operation overflows at compile time in checked mode // F(U32.Max + 1); // overflows at compile time in checked mode Diagnostic(ErrorCode.ERR_CheckedOverflow, "U32.Max + 1").WithLocation(37, 11), // (38,11): error CS0220: The operation overflows at compile time in checked mode // F(S64.Max + 1); // overflows at compile time in checked mode Diagnostic(ErrorCode.ERR_CheckedOverflow, "S64.Max + 1").WithLocation(38, 11), // (39,11): error CS0220: The operation overflows at compile time in checked mode // F(U64.Max + 1); // overflows at compile time in checked mode Diagnostic(ErrorCode.ERR_CheckedOverflow, "U64.Max + 1").WithLocation(39, 11), // (42,11): error CS0221: Constant value '129' cannot be converted to a 'S8' (use 'unchecked' syntax to override) // F(2 + S8.Max); // 129 cannot be converted to ... Diagnostic(ErrorCode.ERR_ConstOutOfRangeChecked, "2 + S8.Max").WithArguments("129", "S8").WithLocation(42, 11), // (43,11): error CS0221: Constant value '257' cannot be converted to a 'U8' (use 'unchecked' syntax to override) // F(2 + U8.Max); // 257 cannot be converted to ... Diagnostic(ErrorCode.ERR_ConstOutOfRangeChecked, "2 + U8.Max").WithArguments("257", "U8").WithLocation(43, 11), // (44,11): error CS0221: Constant value '32769' cannot be converted to a 'S16' (use 'unchecked' syntax to override) // F(2 + S16.Max); // 32769 cannot be converted to ... Diagnostic(ErrorCode.ERR_ConstOutOfRangeChecked, "2 + S16.Max").WithArguments("32769", "S16").WithLocation(44, 11), // (45,11): error CS0221: Constant value '65537' cannot be converted to a 'U16' (use 'unchecked' syntax to override) // F(2 + U16.Max); // 65537 cannot be converted to ... Diagnostic(ErrorCode.ERR_ConstOutOfRangeChecked, "2 + U16.Max").WithArguments("65537", "U16").WithLocation(45, 11), // (46,11): error CS0220: The operation overflows at compile time in checked mode // F(2 + S32.Max); // overflows at compile time in checked mode Diagnostic(ErrorCode.ERR_CheckedOverflow, "2 + S32.Max").WithLocation(46, 11), // (47,11): error CS0220: The operation overflows at compile time in checked mode // F(2 + U32.Max); // overflows at compile time in checked mode Diagnostic(ErrorCode.ERR_CheckedOverflow, "2 + U32.Max").WithLocation(47, 11), // (48,11): error CS0220: The operation overflows at compile time in checked mode // F(2 + S64.Max); // overflows at compile time in checked mode Diagnostic(ErrorCode.ERR_CheckedOverflow, "2 + S64.Max").WithLocation(48, 11), // (49,11): error CS0220: The operation overflows at compile time in checked mode // F(2 + U64.Max); // overflows at compile time in checked mode Diagnostic(ErrorCode.ERR_CheckedOverflow, "2 + U64.Max").WithLocation(49, 11), // (53,11): error CS0221: Constant value '-1' cannot be converted to a 'byte' (use 'unchecked' syntax to override) // F(U8.Min - U8.MinPlusOne); // -1 cannot be converted to ... Diagnostic(ErrorCode.ERR_ConstOutOfRangeChecked, "U8.Min - U8.MinPlusOne").WithArguments("-1", "byte").WithLocation(53, 11), // (55,11): error CS0221: Constant value '-1' cannot be converted to a 'ushort' (use 'unchecked' syntax to override) // F(U16.Min - U16.MinPlusOne); // -1 cannot be converted to ... Diagnostic(ErrorCode.ERR_ConstOutOfRangeChecked, "U16.Min - U16.MinPlusOne").WithArguments("-1", "ushort").WithLocation(55, 11), // (57,11): error CS0220: The operation overflows at compile time in checked mode // F(U32.Min - U32.MinPlusOne); // overflows at compile time in checked mode Diagnostic(ErrorCode.ERR_CheckedOverflow, "U32.Min - U32.MinPlusOne").WithLocation(57, 11), // (59,11): error CS0220: The operation overflows at compile time in checked mode // F(U64.Min - U64.MinPlusOne); // overflows at compile time in checked mode Diagnostic(ErrorCode.ERR_CheckedOverflow, "U64.Min - U64.MinPlusOne").WithLocation(59, 11), // (62,11): error CS0221: Constant value '-255' cannot be converted to a 'sbyte' (use 'unchecked' syntax to override) // F(S8.Min - S8.Max); // -255 cannot be converted to ... Diagnostic(ErrorCode.ERR_ConstOutOfRangeChecked, "S8.Min - S8.Max").WithArguments("-255", "sbyte").WithLocation(62, 11), // (63,11): error CS0221: Constant value '-255' cannot be converted to a 'byte' (use 'unchecked' syntax to override) // F(U8.Min - U8.Max); // -255 cannot be converted to ... Diagnostic(ErrorCode.ERR_ConstOutOfRangeChecked, "U8.Min - U8.Max").WithArguments("-255", "byte").WithLocation(63, 11), // (64,11): error CS0221: Constant value '-65535' cannot be converted to a 'short' (use 'unchecked' syntax to override) // F(S16.Min - S16.Max); // -65535 cannot be converted to ... Diagnostic(ErrorCode.ERR_ConstOutOfRangeChecked, "S16.Min - S16.Max").WithArguments("-65535", "short").WithLocation(64, 11), // (65,11): error CS0221: Constant value '-65535' cannot be converted to a 'ushort' (use 'unchecked' syntax to override) // F(U16.Min - U16.Max); // -65535 cannot be converted to ... Diagnostic(ErrorCode.ERR_ConstOutOfRangeChecked, "U16.Min - U16.Max").WithArguments("-65535", "ushort").WithLocation(65, 11), // (66,11): error CS0220: The operation overflows at compile time in checked mode // F(S32.Min - S32.Max); // overflows at compile time in checked mode Diagnostic(ErrorCode.ERR_CheckedOverflow, "S32.Min - S32.Max").WithLocation(66, 11), // (67,11): error CS0220: The operation overflows at compile time in checked mode // F(U32.Min - U32.Max); // overflows at compile time in checked mode Diagnostic(ErrorCode.ERR_CheckedOverflow, "U32.Min - U32.Max").WithLocation(67, 11), // (68,11): error CS0220: The operation overflows at compile time in checked mode // F(S64.Min - S64.Max); // overflows at compile time in checked mode Diagnostic(ErrorCode.ERR_CheckedOverflow, "S64.Min - S64.Max").WithLocation(68, 11), // (69,11): error CS0220: The operation overflows at compile time in checked mode // F(U64.Min - U64.Max); // overflows at compile time in checked mode Diagnostic(ErrorCode.ERR_CheckedOverflow, "U64.Min - U64.Max").WithLocation(69, 11), // (72,11): error CS0221: Constant value '255' cannot be converted to a 'sbyte' (use 'unchecked' syntax to override) // F(S8.Max - S8.Min); // 255 cannot be converted to ... Diagnostic(ErrorCode.ERR_ConstOutOfRangeChecked, "S8.Max - S8.Min").WithArguments("255", "sbyte").WithLocation(72, 11), // (74,11): error CS0221: Constant value '65535' cannot be converted to a 'short' (use 'unchecked' syntax to override) // F(S16.Max - S16.Min); // 65535 cannot be converted to ... Diagnostic(ErrorCode.ERR_ConstOutOfRangeChecked, "S16.Max - S16.Min").WithArguments("65535", "short").WithLocation(74, 11), // (76,11): error CS0220: The operation overflows at compile time in checked mode // F(S32.Max - S32.Min); // overflows at compile time in checked mode Diagnostic(ErrorCode.ERR_CheckedOverflow, "S32.Max - S32.Min").WithLocation(76, 11), // (78,11): error CS0220: The operation overflows at compile time in checked mode // F(S64.Max - S64.Min); // overflows at compile time in checked mode Diagnostic(ErrorCode.ERR_CheckedOverflow, "S64.Max - S64.Min").WithLocation(78, 11), // (82,11): error CS0221: Constant value '-130' cannot be converted to a 'S8' (use 'unchecked' syntax to override) // F(S8.Min - 2); // -130 cannot be converted to ... Diagnostic(ErrorCode.ERR_ConstOutOfRangeChecked, "S8.Min - 2").WithArguments("-130", "S8").WithLocation(82, 11), // (83,11): error CS0221: Constant value '-2' cannot be converted to a 'U8' (use 'unchecked' syntax to override) // F(U8.Min - 2); // -2 cannot be converted to ... Diagnostic(ErrorCode.ERR_ConstOutOfRangeChecked, "U8.Min - 2").WithArguments("-2", "U8").WithLocation(83, 11), // (84,11): error CS0221: Constant value '-32770' cannot be converted to a 'S16' (use 'unchecked' syntax to override) // F(S16.Min - 2); // -32770 cannot be converted to ... Diagnostic(ErrorCode.ERR_ConstOutOfRangeChecked, "S16.Min - 2").WithArguments("-32770", "S16").WithLocation(84, 11), // (85,11): error CS0221: Constant value '-2' cannot be converted to a 'U16' (use 'unchecked' syntax to override) // F(U16.Min - 2); // -2 cannot be converted to ... Diagnostic(ErrorCode.ERR_ConstOutOfRangeChecked, "U16.Min - 2").WithArguments("-2", "U16").WithLocation(85, 11), // (86,11): error CS0220: The operation overflows at compile time in checked mode // F(S32.Min - 2); // overflows at compile time in checked mode Diagnostic(ErrorCode.ERR_CheckedOverflow, "S32.Min - 2").WithLocation(86, 11), // (87,11): error CS0220: The operation overflows at compile time in checked mode // F(U32.Min - 2); // overflows at compile time in checked mode Diagnostic(ErrorCode.ERR_CheckedOverflow, "U32.Min - 2").WithLocation(87, 11), // (88,11): error CS0220: The operation overflows at compile time in checked mode // F(S64.Min - 2); // overflows at compile time in checked mode Diagnostic(ErrorCode.ERR_CheckedOverflow, "S64.Min - 2").WithLocation(88, 11), // (89,11): error CS0220: The operation overflows at compile time in checked mode // F(U64.Min - 2); // overflows at compile time in checked mode Diagnostic(ErrorCode.ERR_CheckedOverflow, "U64.Min - 2").WithLocation(89, 11)); } [Fact] [WorkItem(33564, "https://github.com/dotnet/roslyn/issues/33564")] [WorkItem(528727, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/528727")] public void TestConstantNumericConversionsNotOverflow() { var source = @" using System; class C { void M() // Test helper requires Method 'M' (default) { const sbyte S8_Max = (sbyte)(sbyte.MaxValue + 0.1); const byte U8_Max = (byte)(byte.MaxValue + 0.1); const short S16_Max = (short)(short.MaxValue + 0.1); const ushort U16_Max = (ushort)(ushort.MaxValue + 0.1); const int S32_Max = (int)(int.MaxValue + 0.1); const uint U32_Max = (uint)(uint.MaxValue + 0.1); const sbyte S8_Min = (sbyte)(sbyte.MinValue - 0.1); const byte U8_Min = (byte)(byte.MinValue - 0.1); const short S16_Min = (short)(short.MinValue - 0.1); const ushort U16_Min = (ushort)(ushort.MinValue - 0.1); const int S32_Min = (int)(int.MinValue - 0.1); const uint U32_Min = (uint)(uint.MinValue - 0.1); const long S64_Min = (long)(long.MinValue - 0.1); const ulong U64_Min = (ulong)(ulong.MinValue - 0.1); } }"; var actual = ParseAndGetConstantFoldingSteps(source); #if NET472 var longValue = "-9.22337203685478E+18"; #else var longValue = "-9.223372036854776E+18"; #endif var expected = $@"(sbyte)(sbyte.MaxValue + 0.1) --> 127 sbyte.MaxValue + 0.1 --> 127.1 sbyte.MaxValue --> 127 sbyte.MaxValue --> 127 (byte)(byte.MaxValue + 0.1) --> 255 byte.MaxValue + 0.1 --> 255.1 byte.MaxValue --> 255 byte.MaxValue --> 255 (short)(short.MaxValue + 0.1) --> 32767 short.MaxValue + 0.1 --> 32767.1 short.MaxValue --> 32767 short.MaxValue --> 32767 (ushort)(ushort.MaxValue + 0.1) --> 65535 ushort.MaxValue + 0.1 --> 65535.1 ushort.MaxValue --> 65535 ushort.MaxValue --> 65535 (int)(int.MaxValue + 0.1) --> 2147483647 int.MaxValue + 0.1 --> 2147483647.1 int.MaxValue --> 2147483647 int.MaxValue --> 2147483647 (uint)(uint.MaxValue + 0.1) --> 4294967295 uint.MaxValue + 0.1 --> 4294967295.1 uint.MaxValue --> 4294967295 uint.MaxValue --> 4294967295 (sbyte)(sbyte.MinValue - 0.1) --> -128 sbyte.MinValue - 0.1 --> -128.1 sbyte.MinValue --> -128 sbyte.MinValue --> -128 (byte)(byte.MinValue - 0.1) --> 0 byte.MinValue - 0.1 --> -0.1 byte.MinValue --> 0 byte.MinValue --> 0 (short)(short.MinValue - 0.1) --> -32768 short.MinValue - 0.1 --> -32768.1 short.MinValue --> -32768 short.MinValue --> -32768 (ushort)(ushort.MinValue - 0.1) --> 0 ushort.MinValue - 0.1 --> -0.1 ushort.MinValue --> 0 ushort.MinValue --> 0 (int)(int.MinValue - 0.1) --> -2147483648 int.MinValue - 0.1 --> -2147483648.1 int.MinValue --> -2147483648 int.MinValue --> -2147483648 (uint)(uint.MinValue - 0.1) --> 0 uint.MinValue - 0.1 --> -0.1 uint.MinValue --> 0 uint.MinValue --> 0 (long)(long.MinValue - 0.1) --> -9223372036854775808 long.MinValue - 0.1 --> {longValue} long.MinValue --> {longValue} long.MinValue --> -9223372036854775808 (ulong)(ulong.MinValue - 0.1) --> 0 ulong.MinValue - 0.1 --> -0.1 ulong.MinValue --> 0 ulong.MinValue --> 0"; Assert.Equal(expected, actual); } [Fact] public void TestConstantNumericConversions() { var source = @"class C { void M() { const int i = 65; const uint u = 65U; const long l = 65L; const ulong ul = 65UL; const float f = 65F; const decimal m = 65M; const double d = 65D; const byte b = (byte)65; const sbyte sb = (sbyte)65; const short s = (short)65; const ushort us = (ushort)65; const char c = 'A'; const int int01 = (int)i; const int int02 = (int)u; const int int03 = (int)l; const int int04 = (int)ul; const int int05 = (int)f; const int int06 = (int)m; const int int07 = (int)d; const int int08 = (int)b; const int int09 = (int)sb; const int int10 = (int)s; const int int11 = (int)us; const int int12 = (int)c; const uint uint01 = (uint)i; const uint uint02 = (uint)u; const uint uint03 = (uint)l; const uint uint04 = (uint)ul; const uint uint05 = (uint)f; const uint uint06 = (uint)m; const uint uint07 = (uint)d; const uint uint08 = (uint)b; const uint uint09 = (uint)sb; const uint uint10 = (uint)s; const uint uint11 = (uint)us; const uint uint12 = (uint)c; const long long01 = (long)i; const long long02 = (long)u; const long long03 = (long)l; const long long04 = (long)ul; const long long05 = (long)f; const long long06 = (long)m; const long long07 = (long)d; const long long08 = (long)b; const long long09 = (long)sb; const long long10 = (long)s; const long long11 = (long)us; const long long12 = (long)c; const ulong ulong01 = (ulong)i; const ulong ulong02 = (ulong)u; const ulong ulong03 = (ulong)l; const ulong ulong04 = (ulong)ul; const ulong ulong05 = (ulong)f; const ulong ulong06 = (ulong)m; const ulong ulong07 = (ulong)d; const ulong ulong08 = (ulong)b; const ulong ulong09 = (ulong)sb; const ulong ulong10 = (ulong)s; const ulong ulong11 = (ulong)us; const ulong ulong12 = (ulong)c; const float float01 = (float)i; const float float02 = (float)u; const float float03 = (float)l; const float float04 = (float)ul; const float float05 = (float)f; const float float06 = (float)m; const float float07 = (float)d; const float float08 = (float)b; const float float09 = (float)sb; const float float10 = (float)s; const float float11 = (float)us; const float float12 = (float)c; const decimal decimal01 = (decimal)i; const decimal decimal02 = (decimal)u; const decimal decimal03 = (decimal)l; const decimal decimal04 = (decimal)ul; const decimal decimal05 = (decimal)f; const decimal decimal06 = (decimal)m; const decimal decimal07 = (decimal)d; const decimal decimal08 = (decimal)b; const decimal decimal09 = (decimal)sb; const decimal decimal10 = (decimal)s; const decimal decimal11 = (decimal)us; const decimal decimal12 = (decimal)c; const double double01 = (double)i; const double double02 = (double)u; const double double03 = (double)l; const double double04 = (double)ul; const double double05 = (double)f; const double double06 = (double)m; const double double07 = (double)d; const double double08 = (double)b; const double double09 = (double)sb; const double double10 = (double)s; const double double11 = (double)us; const double double12 = (double)c; const byte byte01 = (byte)i; const byte byte02 = (byte)u; const byte byte03 = (byte)l; const byte byte04 = (byte)ul; const byte byte05 = (byte)f; const byte byte06 = (byte)m; const byte byte07 = (byte)d; const byte byte08 = (byte)b; const byte byte09 = (byte)sb; const byte byte10 = (byte)s; const byte byte11 = (byte)us; const byte byte12 = (byte)c; const sbyte sbyte01 = (sbyte)i; const sbyte sbyte02 = (sbyte)u; const sbyte sbyte03 = (sbyte)l; const sbyte sbyte04 = (sbyte)ul; const sbyte sbyte05 = (sbyte)f; const sbyte sbyte06 = (sbyte)m; const sbyte sbyte07 = (sbyte)d; const sbyte sbyte08 = (sbyte)b; const sbyte sbyte09 = (sbyte)sb; const sbyte sbyte10 = (sbyte)s; const sbyte sbyte11 = (sbyte)us; const sbyte sbyte12 = (sbyte)c; const short short01 = (short)i; const short short02 = (short)u; const short short03 = (short)l; const short short04 = (short)ul; const short short05 = (short)f; const short short06 = (short)m; const short short07 = (short)d; const short short08 = (short)b; const short short09 = (short)sb; const short short10 = (short)s; const short short11 = (short)us; const short short12 = (short)c; const ushort ushort01 = (ushort)i; const ushort ushort02 = (ushort)u; const ushort ushort03 = (ushort)l; const ushort ushort04 = (ushort)ul; const ushort ushort05 = (ushort)f; const ushort ushort06 = (ushort)m; const ushort ushort07 = (ushort)d; const ushort ushort08 = (ushort)b; const ushort ushort09 = (ushort)sb; const ushort ushort10 = (ushort)s; const ushort ushort11 = (ushort)us; const ushort ushort12 = (ushort)c; const char char01 = (char)i; const char char02 = (char)u; const char char03 = (char)l; const char char04 = (char)ul; const char char05 = (char)f; const char char06 = (char)m; const char char07 = (char)d; const char char08 = (char)b; const char char09 = (char)sb; const char char10 = (char)s; const char char11 = (char)us; const char char12 = (char)c; } "; var actual = ParseAndGetConstantFoldingSteps(source); //the first four are for the constants //no entries for identity conversions var expected = @"(byte)65 --> 65 (sbyte)65 --> 65 (short)65 --> 65 (ushort)65 --> 65 (int)i --> 65 (int)u --> 65 (int)l --> 65 (int)ul --> 65 (int)f --> 65 (int)m --> 65 (int)d --> 65 (int)b --> 65 (int)sb --> 65 (int)s --> 65 (int)us --> 65 (int)c --> 65 (uint)i --> 65 (uint)u --> 65 (uint)l --> 65 (uint)ul --> 65 (uint)f --> 65 (uint)m --> 65 (uint)d --> 65 (uint)b --> 65 (uint)sb --> 65 (uint)s --> 65 (uint)us --> 65 (uint)c --> 65 (long)i --> 65 (long)u --> 65 (long)l --> 65 (long)ul --> 65 (long)f --> 65 (long)m --> 65 (long)d --> 65 (long)b --> 65 (long)sb --> 65 (long)s --> 65 (long)us --> 65 (long)c --> 65 (ulong)i --> 65 (ulong)u --> 65 (ulong)l --> 65 (ulong)ul --> 65 (ulong)f --> 65 (ulong)m --> 65 (ulong)d --> 65 (ulong)b --> 65 (ulong)sb --> 65 (ulong)s --> 65 (ulong)us --> 65 (ulong)c --> 65 (float)i --> 65 (float)u --> 65 (float)l --> 65 (float)ul --> 65 (float)f --> 65 (float)m --> 65 (float)d --> 65 (float)b --> 65 (float)sb --> 65 (float)s --> 65 (float)us --> 65 (float)c --> 65 (decimal)i --> 65 (decimal)u --> 65 (decimal)l --> 65 (decimal)ul --> 65 (decimal)f --> 65 (decimal)m --> 65 (decimal)d --> 65 (decimal)b --> 65 (decimal)sb --> 65 (decimal)s --> 65 (decimal)us --> 65 (decimal)c --> 65 (double)i --> 65 (double)u --> 65 (double)l --> 65 (double)ul --> 65 (double)f --> 65 (double)m --> 65 (double)d --> 65 (double)b --> 65 (double)sb --> 65 (double)s --> 65 (double)us --> 65 (double)c --> 65 (byte)i --> 65 (byte)u --> 65 (byte)l --> 65 (byte)ul --> 65 (byte)f --> 65 (byte)m --> 65 (byte)d --> 65 (byte)b --> 65 (byte)sb --> 65 (byte)s --> 65 (byte)us --> 65 (byte)c --> 65 (sbyte)i --> 65 (sbyte)u --> 65 (sbyte)l --> 65 (sbyte)ul --> 65 (sbyte)f --> 65 (sbyte)m --> 65 (sbyte)d --> 65 (sbyte)b --> 65 (sbyte)sb --> 65 (sbyte)s --> 65 (sbyte)us --> 65 (sbyte)c --> 65 (short)i --> 65 (short)u --> 65 (short)l --> 65 (short)ul --> 65 (short)f --> 65 (short)m --> 65 (short)d --> 65 (short)b --> 65 (short)sb --> 65 (short)s --> 65 (short)us --> 65 (short)c --> 65 (ushort)i --> 65 (ushort)u --> 65 (ushort)l --> 65 (ushort)ul --> 65 (ushort)f --> 65 (ushort)m --> 65 (ushort)d --> 65 (ushort)b --> 65 (ushort)sb --> 65 (ushort)s --> 65 (ushort)us --> 65 (ushort)c --> 65 (char)i --> A (char)u --> A (char)l --> A (char)ul --> A (char)f --> A (char)m --> A (char)d --> A (char)b --> A (char)sb --> A (char)s --> A (char)us --> A (char)c --> A"; Assert.Equal(expected, actual); } [Fact] public void TestConstantFoldingOperations() { // TODO: char, byte, sbyte, short, ushort var source = @"class C { void M() { const int intOps = (1 - 2) + (3 / 4) + (5 % 6) + (7 * 8) + (9 << 10) + (11 >> 12) + (13 ^ 14) + (15 | 16) + (17 & 18) + (~19) + (-20) + (+21); const long longOps = (1L - 2L) + (3L / 4L) + (5L % 6L) + (7L * 8L) + (9L << 10) + (11L >> 12) + (13L ^ 14L) + (15L | 16L) + (17L & 18L) + (~19L) + (-20L) + (+21L); const uint uintOps = (20U - 19U) + (18U / 17U) + (16U % 15U) + (14U * 13U) + (12U << 11) + (10U >> 9) + (8U ^ 7U) + (6U | 5U) + (4U & 3U) + (+2U) & (~1U); const ulong ulongOps = (20UL - 19UL) + (18UL / 17UL) + (16UL % 15UL) + (14UL * 13UL) + (12UL << 11) + (10UL >> 9) + (8UL ^ 7UL) + (6UL | 5UL) + (4UL & 3UL) + (+2UL) & (~1UL); } "; var actual = ParseAndGetConstantFoldingSteps(source); var expected = @"(1 - 2) + (3 / 4) + (5 % 6) + (7 * 8) + (9 << 10) + (11 >> 12) + (13 ^ 14) + (15 | 16) + (17 & 18) + (~19) + (-20) + (+21) --> 9307 (1 - 2) + (3 / 4) + (5 % 6) + (7 * 8) + (9 << 10) + (11 >> 12) + (13 ^ 14) + (15 | 16) + (17 & 18) + (~19) + (-20) --> 9286 (1 - 2) + (3 / 4) + (5 % 6) + (7 * 8) + (9 << 10) + (11 >> 12) + (13 ^ 14) + (15 | 16) + (17 & 18) + (~19) --> 9306 (1 - 2) + (3 / 4) + (5 % 6) + (7 * 8) + (9 << 10) + (11 >> 12) + (13 ^ 14) + (15 | 16) + (17 & 18) --> 9326 (1 - 2) + (3 / 4) + (5 % 6) + (7 * 8) + (9 << 10) + (11 >> 12) + (13 ^ 14) + (15 | 16) --> 9310 (1 - 2) + (3 / 4) + (5 % 6) + (7 * 8) + (9 << 10) + (11 >> 12) + (13 ^ 14) --> 9279 (1 - 2) + (3 / 4) + (5 % 6) + (7 * 8) + (9 << 10) + (11 >> 12) --> 9276 (1 - 2) + (3 / 4) + (5 % 6) + (7 * 8) + (9 << 10) --> 9276 (1 - 2) + (3 / 4) + (5 % 6) + (7 * 8) --> 60 (1 - 2) + (3 / 4) + (5 % 6) --> 4 (1 - 2) + (3 / 4) --> -1 1 - 2 --> -1 3 / 4 --> 0 5 % 6 --> 5 7 * 8 --> 56 9 << 10 --> 9216 11 >> 12 --> 0 13 ^ 14 --> 3 15 | 16 --> 31 17 & 18 --> 16 ~19 --> -20 -20 --> -20 +21 --> 21 (1L - 2L) + (3L / 4L) + (5L % 6L) + (7L * 8L) + (9L << 10) + (11L >> 12) + (13L ^ 14L) + (15L | 16L) + (17L & 18L) + (~19L) + (-20L) + (+21L) --> 9307 (1L - 2L) + (3L / 4L) + (5L % 6L) + (7L * 8L) + (9L << 10) + (11L >> 12) + (13L ^ 14L) + (15L | 16L) + (17L & 18L) + (~19L) + (-20L) --> 9286 (1L - 2L) + (3L / 4L) + (5L % 6L) + (7L * 8L) + (9L << 10) + (11L >> 12) + (13L ^ 14L) + (15L | 16L) + (17L & 18L) + (~19L) --> 9306 (1L - 2L) + (3L / 4L) + (5L % 6L) + (7L * 8L) + (9L << 10) + (11L >> 12) + (13L ^ 14L) + (15L | 16L) + (17L & 18L) --> 9326 (1L - 2L) + (3L / 4L) + (5L % 6L) + (7L * 8L) + (9L << 10) + (11L >> 12) + (13L ^ 14L) + (15L | 16L) --> 9310 (1L - 2L) + (3L / 4L) + (5L % 6L) + (7L * 8L) + (9L << 10) + (11L >> 12) + (13L ^ 14L) --> 9279 (1L - 2L) + (3L / 4L) + (5L % 6L) + (7L * 8L) + (9L << 10) + (11L >> 12) --> 9276 (1L - 2L) + (3L / 4L) + (5L % 6L) + (7L * 8L) + (9L << 10) --> 9276 (1L - 2L) + (3L / 4L) + (5L % 6L) + (7L * 8L) --> 60 (1L - 2L) + (3L / 4L) + (5L % 6L) --> 4 (1L - 2L) + (3L / 4L) --> -1 1L - 2L --> -1 3L / 4L --> 0 5L % 6L --> 5 7L * 8L --> 56 9L << 10 --> 9216 11L >> 12 --> 0 13L ^ 14L --> 3 15L | 16L --> 31 17L & 18L --> 16 ~19L --> -20 -20L --> -20 +21L --> 21 (20U - 19U) + (18U / 17U) + (16U % 15U) + (14U * 13U) + (12U << 11) + (10U >> 9) + (8U ^ 7U) + (6U | 5U) + (4U & 3U) + (+2U) & (~1U) --> 24784 (20U - 19U) + (18U / 17U) + (16U % 15U) + (14U * 13U) + (12U << 11) + (10U >> 9) + (8U ^ 7U) + (6U | 5U) + (4U & 3U) + (+2U) --> 24785 (20U - 19U) + (18U / 17U) + (16U % 15U) + (14U * 13U) + (12U << 11) + (10U >> 9) + (8U ^ 7U) + (6U | 5U) + (4U & 3U) --> 24783 (20U - 19U) + (18U / 17U) + (16U % 15U) + (14U * 13U) + (12U << 11) + (10U >> 9) + (8U ^ 7U) + (6U | 5U) --> 24783 (20U - 19U) + (18U / 17U) + (16U % 15U) + (14U * 13U) + (12U << 11) + (10U >> 9) + (8U ^ 7U) --> 24776 (20U - 19U) + (18U / 17U) + (16U % 15U) + (14U * 13U) + (12U << 11) + (10U >> 9) --> 24761 (20U - 19U) + (18U / 17U) + (16U % 15U) + (14U * 13U) + (12U << 11) --> 24761 (20U - 19U) + (18U / 17U) + (16U % 15U) + (14U * 13U) --> 185 (20U - 19U) + (18U / 17U) + (16U % 15U) --> 3 (20U - 19U) + (18U / 17U) --> 2 20U - 19U --> 1 18U / 17U --> 1 16U % 15U --> 1 14U * 13U --> 182 12U << 11 --> 24576 10U >> 9 --> 0 8U ^ 7U --> 15 6U | 5U --> 7 4U & 3U --> 0 +2U --> 2 ~1U --> 4294967294 (20UL - 19UL) + (18UL / 17UL) + (16UL % 15UL) + (14UL * 13UL) + (12UL << 11) + (10UL >> 9) + (8UL ^ 7UL) + (6UL | 5UL) + (4UL & 3UL) + (+2UL) & (~1UL) --> 24784 (20UL - 19UL) + (18UL / 17UL) + (16UL % 15UL) + (14UL * 13UL) + (12UL << 11) + (10UL >> 9) + (8UL ^ 7UL) + (6UL | 5UL) + (4UL & 3UL) + (+2UL) --> 24785 (20UL - 19UL) + (18UL / 17UL) + (16UL % 15UL) + (14UL * 13UL) + (12UL << 11) + (10UL >> 9) + (8UL ^ 7UL) + (6UL | 5UL) + (4UL & 3UL) --> 24783 (20UL - 19UL) + (18UL / 17UL) + (16UL % 15UL) + (14UL * 13UL) + (12UL << 11) + (10UL >> 9) + (8UL ^ 7UL) + (6UL | 5UL) --> 24783 (20UL - 19UL) + (18UL / 17UL) + (16UL % 15UL) + (14UL * 13UL) + (12UL << 11) + (10UL >> 9) + (8UL ^ 7UL) --> 24776 (20UL - 19UL) + (18UL / 17UL) + (16UL % 15UL) + (14UL * 13UL) + (12UL << 11) + (10UL >> 9) --> 24761 (20UL - 19UL) + (18UL / 17UL) + (16UL % 15UL) + (14UL * 13UL) + (12UL << 11) --> 24761 (20UL - 19UL) + (18UL / 17UL) + (16UL % 15UL) + (14UL * 13UL) --> 185 (20UL - 19UL) + (18UL / 17UL) + (16UL % 15UL) --> 3 (20UL - 19UL) + (18UL / 17UL) --> 2 20UL - 19UL --> 1 18UL / 17UL --> 1 16UL % 15UL --> 1 14UL * 13UL --> 182 12UL << 11 --> 24576 10UL >> 9 --> 0 8UL ^ 7UL --> 15 6UL | 5UL --> 7 4UL & 3UL --> 0 +2UL --> 2 ~1UL --> 18446744073709551614"; Assert.Equal(expected, actual); } private static string ParseAndGetConstantFoldingSteps(string source) { return ParseAndGetConstantFoldingSteps(source, node => node.Kind != BoundKind.Literal && node.Kind != BoundKind.Local); } private static string ParseAndGetConstantFoldingSteps(string source, Func<BoundNode, bool> predicate) { var block = ParseAndBindMethodBody(source); var constants = BoundTreeSequencer.GetNodes(block). Where(predicate). OfType<BoundExpression>(). Where(node => node.ConstantValueOpt != null). Select(node => node.Syntax.ToFullString().Trim() + " --> " + ExtractValue(node.ConstantValueOpt)); var result = string.Join(Environment.NewLine, constants); return result; } private static object ExtractValue(ConstantValue constantValue) { if (constantValue.IsBad) { return "BAD"; } if (constantValue.IsChar && char.IsControl(constantValue.CharValue)) { return "control character"; } // return constantValue.Value ?? "null"; if (constantValue.Value == null) return "null"; return TestHelpers.GetCultureInvariantString(constantValue.Value); } /// <summary> /// Breaking change from the native compiler for /// certain constant expressions involving +0m and -0m. /// </summary> [WorkItem(529730, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/529730")] [WorkItem(1043494, "DevDiv")] [Fact(Skip = "1043494")] public void TestConstantFoldingDecimalOperations01() { var source = @"using System; using System.Globalization; class C { static void Main() { // + Console.WriteLine(""1 / (double)(0m + 0m) = {0}"", (1 / (double)(0m + 0m)).ToString(CultureInfo.InvariantCulture)); // Dev11: Infinity Console.WriteLine(""1 / (double)(0m + -0m) = {0}"", (1 / (double)(0m + -0m)).ToString(CultureInfo.InvariantCulture)); // Dev11: -Infinity Console.WriteLine(""1 / (double)(-0m + 0m) = {0}"", (1 / (double)(-0m + 0m)).ToString(CultureInfo.InvariantCulture)); // Dev11: Infinity Console.WriteLine(""1 / (double)(-0m + -0m) = {0}"", (1 / (double)(-0m + -0m)).ToString(CultureInfo.InvariantCulture)); // Dev11: -Infinity Console.WriteLine(); // - Console.WriteLine(""1 / (double)(0m - 0m) = {0}"", (1 / (double)(0m - 0m)).ToString(CultureInfo.InvariantCulture)); // Dev11: -Infinity Console.WriteLine(""1 / (double)(0m - -0m) = {0}"", (1 / (double)(0m - -0m)).ToString(CultureInfo.InvariantCulture)); // Dev11: Infinity Console.WriteLine(""1 / (double)(-0m - 0m) = {0}"", (1 / (double)(-0m - 0m)).ToString(CultureInfo.InvariantCulture)); // Dev11: -Infinity Console.WriteLine(""1 / (double)(-0m - -0m) = {0}"", (1 / (double)(-0m - -0m)).ToString(CultureInfo.InvariantCulture)); // Dev11: Infinity Console.WriteLine(); // * Console.WriteLine(""1 / (double)(0m * 1m) = {0}"", (1 / (double)(0m * 1m)).ToString(CultureInfo.InvariantCulture)); // Dev11: Infinity Console.WriteLine(""1 / (double)(1m * 0m) = {0}"", (1 / (double)(1m * 0m)).ToString(CultureInfo.InvariantCulture)); // Dev11: Infinity Console.WriteLine(""1 / (double)(0m * -1m) = {0}"", (1 / (double)(0m * -1m)).ToString(CultureInfo.InvariantCulture)); // Dev11: -Infinity Console.WriteLine(""1 / (double)(-1m * 0m) = {0}"", (1 / (double)(-1m * 0m)).ToString(CultureInfo.InvariantCulture)); // Dev11: -Infinity Console.WriteLine(""1 / (double)(0m * 1m) = {0}"", (1 / (double)(-0m * 1m)).ToString(CultureInfo.InvariantCulture)); // Dev11: -Infinity Console.WriteLine(""1 / (double)(1m * -0m) = {0}"", (1 / (double)(1m * -0m)).ToString(CultureInfo.InvariantCulture)); // Dev11: -Infinity Console.WriteLine(""1 / (double)(0m * -1m) = {0}"", (1 / (double)(-0m * -1m)).ToString(CultureInfo.InvariantCulture)); // Dev11: Infinity Console.WriteLine(""1 / (double)(-1m * -0m) = {0}"", (1 / (double)(-1m * -0m)).ToString(CultureInfo.InvariantCulture)); // Dev11: Infinity } }"; CompileAndVerify(source, expectedOutput: @"1 / (double)(0m + 0m) = Infinity 1 / (double)(0m + -0m) = Infinity 1 / (double)(-0m + 0m) = -Infinity 1 / (double)(-0m + -0m) = -Infinity 1 / (double)(0m - 0m) = Infinity 1 / (double)(0m - -0m) = Infinity 1 / (double)(-0m - 0m) = -Infinity 1 / (double)(-0m - -0m) = -Infinity 1 / (double)(0m * 1m) = Infinity 1 / (double)(1m * 0m) = Infinity 1 / (double)(0m * -1m) = -Infinity 1 / (double)(-1m * 0m) = -Infinity 1 / (double)(0m * 1m) = -Infinity 1 / (double)(1m * -0m) = -Infinity 1 / (double)(0m * -1m) = Infinity 1 / (double)(-1m * -0m) = Infinity"); } /// <summary> /// Breaking change from the native compiler for /// certain constant expressions involving +0m and -0m. /// </summary> [WorkItem(529730, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/529730")] [Fact] public void TestConstantFoldingDecimalOperations02() { var source = @"using System; using System.Linq; class C { static void Main() { var positiveZero = 0e-1m; var negativeZero = -0e-1m; Console.WriteLine(ToHexString(0e-1m)); Console.WriteLine(ToHexString(-0e-1m)); Console.WriteLine(); Console.WriteLine(ToHexString(0e-1m + 0e-1m)); // Dev11: 0e-1m, Roslyn: same Console.WriteLine(ToHexString(0e-1m + -0e-1m)); // Dev11: -0e-1m, Roslyn: 0e-1m Console.WriteLine(ToHexString(-0e-1m + 0e-1m)); // Dev11: 0e-1m, Roslyn: -0e-1m Console.WriteLine(ToHexString(-0e-1m + -0e-1m)); // Dev11: -0e-1m, Roslyn: same Console.WriteLine(); Console.WriteLine(ToHexString(0e-1m - 0e-1m)); // Dev11: -0e-1m, Roslyn: 0e-1m Console.WriteLine(ToHexString(0e-1m - -0e-1m)); // Dev11: 0e-1m, Roslyn: same Console.WriteLine(ToHexString(-0e-1m - 0e-1m)); // Dev11: -0e-1m, Roslyn: same Console.WriteLine(ToHexString(-0e-1m - -0e-1m)); // Dev11: 0e-1m, Roslyn: -0e-1m Console.WriteLine(); Console.WriteLine(ToHexString(positiveZero + negativeZero)); // Dev11: 0e-1m, Roslyn: same Console.WriteLine(ToHexString(negativeZero + positiveZero)); // Dev11: -0e-1m, Roslyn: same Console.WriteLine(ToHexString(positiveZero - positiveZero)); // Dev11: 0e-1m, Roslyn: same Console.WriteLine(ToHexString(negativeZero - negativeZero)); // Dev11: -0e-1m, Roslyn: same } static string ToHexString(decimal d) { return string.Join("""", decimal.GetBits(d).Select(word => string.Format(""{0:x8}"", word))); } }"; var compilation = CreateCompilationWithMscorlib40AndSystemCore(source, options: TestOptions.ReleaseExe); CompileAndVerify(compilation, expectedOutput: @"00000000000000000000000000010000 00000000000000000000000080010000 00000000000000000000000000010000 00000000000000000000000000010000 00000000000000000000000080010000 00000000000000000000000080010000 00000000000000000000000000010000 00000000000000000000000000010000 00000000000000000000000080010000 00000000000000000000000080010000 00000000000000000000000000010000 00000000000000000000000080010000 00000000000000000000000000010000 00000000000000000000000080010000"); } [Fact] public void TestConstantFoldingOperationBoundaries() { var source = @"class C { void M() { const int intOpBoundary1 = 2147483647 & -2147483648; const int intOpBoundary2 = 2147483647 | -2147483648; const int intOpBoundary3 = 2147483647 ^ -2147483648; const int intOpBoundary4 = 2147483647 + -2147483648; const int intOpBoundary5 = 2147483647 / -2147483648; const int intOpBoundary6 = 2147483647 % -2147483648; const int intOpBoundary7 = 2147483647 << -2147483648; const int intOpBoundary8 = 2147483647 >> -2147483648; const int intOpBoundary9 = -2147483648 / 2147483647; const int intOpBoundary10 = -2147483648 % 2147483647; const int intOpBoundary11 = -2147483648 << 2147483647; const int intOpBoundary12 = -2147483648 >> 2147483647; const long longOpBoundary1 = 9223372036854775807 & -9223372036854775808; const long longOpBoundary2 = 9223372036854775807 | -9223372036854775808; const long longOpBoundary3 = 9223372036854775807 ^ -9223372036854775808; const long longOpBoundary4 = 9223372036854775807 + -9223372036854775808; const long longOpBoundary5 = 9223372036854775807 / -9223372036854775808; const long longOpBoundary6 = 9223372036854775807 % -9223372036854775808; const long longOpBoundary7 = 9223372036854775807 << -2147483648; const long longOpBoundary8 = 9223372036854775807 >> -2147483648; const long longOpBoundary9 = -9223372036854775808 / 9223372036854775807; const long longOpBoundary10 = -9223372036854775808 % 9223372036854775807; const long longOpBoundary11 = -9223372036854775808 << 2147483647; const long longOpBoundary12 = -9223372036854775808 >> 2147483647; } "; var actual = ParseAndGetConstantFoldingSteps(source); var expected = @"2147483647 & -2147483648 --> 0 2147483647 | -2147483648 --> -1 2147483647 ^ -2147483648 --> -1 2147483647 + -2147483648 --> -1 2147483647 / -2147483648 --> 0 2147483647 % -2147483648 --> 2147483647 2147483647 << -2147483648 --> 2147483647 2147483647 >> -2147483648 --> 2147483647 -2147483648 / 2147483647 --> -1 -2147483648 % 2147483647 --> -1 -2147483648 << 2147483647 --> 0 -2147483648 >> 2147483647 --> -1 9223372036854775807 & -9223372036854775808 --> 0 9223372036854775807 | -9223372036854775808 --> -1 9223372036854775807 ^ -9223372036854775808 --> -1 9223372036854775807 + -9223372036854775808 --> -1 9223372036854775807 / -9223372036854775808 --> 0 9223372036854775807 % -9223372036854775808 --> 9223372036854775807 9223372036854775807 << -2147483648 --> 9223372036854775807 9223372036854775807 >> -2147483648 --> 9223372036854775807 -9223372036854775808 / 9223372036854775807 --> -1 -9223372036854775808 % 9223372036854775807 --> -1 -9223372036854775808 << 2147483647 --> 0 -9223372036854775808 >> 2147483647 --> -1"; Assert.Equal(expected, actual); } [WorkItem(538179, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/538179")] [Fact] public void TestConstantErrors() { // UNDONE: Extend this to test all the constant out-of-bounds errors // UNDONE: Test unchecked contexts var source = @" class C { struct S {} void M() { const S s = new S(); const double ul1 = -9223372036854775808UL + 0; const double ul2 = -9223372036854775808ul + 0; string s1 = null; const string s2 = s1; // Not a constant const object o1 = ""hello""; // Constants of ref type other than string must be null. int y = (1 / 0) + (1L/0L) + (1UL/0UL) + (1M/0M) + (-79228162514264337593543950335m - 1m); const int z = 1 + (z + 1); int intConversion = (int)0x8888888888888888; uint uintConversion = (uint)0x8888888888888888; long longConversion = (long)0x8888888888888888; ulong ulongConversion = (ulong)1E50; int intOverflow = int.MaxValue + 1; uint uintOverflow = uint.MaxValue + 1; long longOverflow = long.MaxValue + 1; ulong ulongOverflow = ulong.MaxValue + 1; int intUnderflow = int.MinValue - 1; uint uintUnderflow = uint.MinValue - 1; long longUnderflow = long.MinValue - 1; ulong ulongUnderflow = ulong.MinValue - 1; } }"; CreateCompilation(source).VerifyDiagnostics( // (7,15): error CS0283: The type 'C.S' cannot be declared const // const S s = new S(); Diagnostic(ErrorCode.ERR_BadConstType, "S").WithArguments("C.S").WithLocation(7, 15), // (8,28): error CS0023: Operator '-' cannot be applied to operand of type 'ulong' // const double ul1 = -9223372036854775808UL + 0; Diagnostic(ErrorCode.ERR_BadUnaryOp, "-9223372036854775808UL").WithArguments("-", "ulong").WithLocation(8, 28), // (9,28): error CS0023: Operator '-' cannot be applied to operand of type 'ulong' // const double ul2 = -9223372036854775808ul + 0; Diagnostic(ErrorCode.ERR_BadUnaryOp, "-9223372036854775808ul").WithArguments("-", "ulong").WithLocation(9, 28), // (12,27): error CS0133: The expression being assigned to 's2' must be constant // const string s2 = s1; // Not a constant Diagnostic(ErrorCode.ERR_NotConstantExpression, "s1").WithArguments("s2").WithLocation(12, 27), // (14,27): error CS0134: 'o1' is of type 'object'. A const field of a reference type other than string can only be initialized with null. // const object o1 = "hello"; // Constants of ref type other than string must be null. Diagnostic(ErrorCode.ERR_NotNullConstRefField, @"""hello""").WithArguments("o1", "object").WithLocation(14, 27), // (16,18): error CS0020: Division by constant zero // int y = (1 / 0) + (1L/0L) + (1UL/0UL) + (1M/0M) + (-79228162514264337593543950335m - 1m); Diagnostic(ErrorCode.ERR_IntDivByZero, "1 / 0").WithLocation(16, 18), // (16,28): error CS0020: Division by constant zero // int y = (1 / 0) + (1L/0L) + (1UL/0UL) + (1M/0M) + (-79228162514264337593543950335m - 1m); Diagnostic(ErrorCode.ERR_IntDivByZero, "1L/0L").WithLocation(16, 28), // (16,38): error CS0020: Division by constant zero // int y = (1 / 0) + (1L/0L) + (1UL/0UL) + (1M/0M) + (-79228162514264337593543950335m - 1m); Diagnostic(ErrorCode.ERR_IntDivByZero, "1UL/0UL").WithLocation(16, 38), // (16,50): error CS0020: Division by constant zero // int y = (1 / 0) + (1L/0L) + (1UL/0UL) + (1M/0M) + (-79228162514264337593543950335m - 1m); Diagnostic(ErrorCode.ERR_IntDivByZero, "1M/0M").WithLocation(16, 50), // (16,60): error CS0463: Evaluation of the decimal constant expression failed // int y = (1 / 0) + (1L/0L) + (1UL/0UL) + (1M/0M) + (-79228162514264337593543950335m - 1m); Diagnostic(ErrorCode.ERR_DecConstError, "-79228162514264337593543950335m - 1m").WithLocation(16, 60), // (18,28): error CS0110: The evaluation of the constant value for 'z' involves a circular definition // const int z = 1 + (z + 1); Diagnostic(ErrorCode.ERR_CircConstValue, "z").WithArguments("z").WithLocation(18, 28), // (20,29): error CS0221: Constant value '9838263505978427528' cannot be converted to a 'int' (use 'unchecked' syntax to override) // int intConversion = (int)0x8888888888888888; Diagnostic(ErrorCode.ERR_ConstOutOfRangeChecked, "(int)0x8888888888888888").WithArguments("9838263505978427528", "int").WithLocation(20, 29), // (21,31): error CS0221: Constant value '9838263505978427528' cannot be converted to a 'uint' (use 'unchecked' syntax to override) // uint uintConversion = (uint)0x8888888888888888; Diagnostic(ErrorCode.ERR_ConstOutOfRangeChecked, "(uint)0x8888888888888888").WithArguments("9838263505978427528", "uint").WithLocation(21, 31), // (22,31): error CS0221: Constant value '9838263505978427528' cannot be converted to a 'long' (use 'unchecked' syntax to override) // long longConversion = (long)0x8888888888888888; Diagnostic(ErrorCode.ERR_ConstOutOfRangeChecked, "(long)0x8888888888888888").WithArguments("9838263505978427528", "long").WithLocation(22, 31), // (23,33): error CS0221: Constant value '1E+50' cannot be converted to a 'ulong' (use 'unchecked' syntax to override) // ulong ulongConversion = (ulong)1E50; Diagnostic(ErrorCode.ERR_ConstOutOfRangeChecked, "(ulong)1E50").WithArguments("1E+50", "ulong").WithLocation(23, 33), // (25,27): error CS0220: The operation overflows at compile time in checked mode // int intOverflow = int.MaxValue + 1; Diagnostic(ErrorCode.ERR_CheckedOverflow, "int.MaxValue + 1").WithLocation(25, 27), // (26,29): error CS0220: The operation overflows at compile time in checked mode // uint uintOverflow = uint.MaxValue + 1; Diagnostic(ErrorCode.ERR_CheckedOverflow, "uint.MaxValue + 1").WithLocation(26, 29), // (27,29): error CS0220: The operation overflows at compile time in checked mode // long longOverflow = long.MaxValue + 1; Diagnostic(ErrorCode.ERR_CheckedOverflow, "long.MaxValue + 1").WithLocation(27, 29), // (28,31): error CS0220: The operation overflows at compile time in checked mode // ulong ulongOverflow = ulong.MaxValue + 1; Diagnostic(ErrorCode.ERR_CheckedOverflow, "ulong.MaxValue + 1").WithLocation(28, 31), // (30,28): error CS0220: The operation overflows at compile time in checked mode // int intUnderflow = int.MinValue - 1; Diagnostic(ErrorCode.ERR_CheckedOverflow, "int.MinValue - 1").WithLocation(30, 28), // (31,30): error CS0220: The operation overflows at compile time in checked mode // uint uintUnderflow = uint.MinValue - 1; Diagnostic(ErrorCode.ERR_CheckedOverflow, "uint.MinValue - 1").WithLocation(31, 30), // (32,30): error CS0220: The operation overflows at compile time in checked mode // long longUnderflow = long.MinValue - 1; Diagnostic(ErrorCode.ERR_CheckedOverflow, "long.MinValue - 1").WithLocation(32, 30), // (33,32): error CS0220: The operation overflows at compile time in checked mode // ulong ulongUnderflow = ulong.MinValue - 1; Diagnostic(ErrorCode.ERR_CheckedOverflow, "ulong.MinValue - 1").WithLocation(33, 32), // (7,17): warning CS0219: The variable 's' is assigned but its value is never used // const S s = new S(); Diagnostic(ErrorCode.WRN_UnreferencedVarAssg, "s").WithArguments("s").WithLocation(7, 17), // (20,13): warning CS0219: The variable 'intConversion' is assigned but its value is never used // int intConversion = (int)0x8888888888888888; Diagnostic(ErrorCode.WRN_UnreferencedVarAssg, "intConversion").WithArguments("intConversion").WithLocation(20, 13), // (21,14): warning CS0219: The variable 'uintConversion' is assigned but its value is never used // uint uintConversion = (uint)0x8888888888888888; Diagnostic(ErrorCode.WRN_UnreferencedVarAssg, "uintConversion").WithArguments("uintConversion").WithLocation(21, 14), // (22,14): warning CS0219: The variable 'longConversion' is assigned but its value is never used // long longConversion = (long)0x8888888888888888; Diagnostic(ErrorCode.WRN_UnreferencedVarAssg, "longConversion").WithArguments("longConversion").WithLocation(22, 14), // (23,15): warning CS0219: The variable 'ulongConversion' is assigned but its value is never used // ulong ulongConversion = (ulong)1E50; Diagnostic(ErrorCode.WRN_UnreferencedVarAssg, "ulongConversion").WithArguments("ulongConversion").WithLocation(23, 15)); } [Fact] public void TestDynamicConstantError() { var source = @" class C { const int d0 = default(dynamic); const int d1 = (dynamic)1; const int d2 = (int)(dynamic)1; const int d3 = 1 + (int)(dynamic)1; }"; CreateCompilation(source).VerifyDiagnostics( // (4,20): error CS0133: The expression being assigned to 'C.d0' must be constant Diagnostic(ErrorCode.ERR_NotConstantExpression, "default(dynamic)").WithArguments("C.d0"), // (5,20): error CS0133: The expression being assigned to 'C.d1' must be constant Diagnostic(ErrorCode.ERR_NotConstantExpression, "(dynamic)1").WithArguments("C.d1"), // (6,20): error CS0133: The expression being assigned to 'C.d2' must be constant Diagnostic(ErrorCode.ERR_NotConstantExpression, "(int)(dynamic)1").WithArguments("C.d2"), // (7,20): error CS0133: The expression being assigned to 'C.d3' must be constant Diagnostic(ErrorCode.ERR_NotConstantExpression, "1 + (int)(dynamic)1").WithArguments("C.d3")); } [Fact] public void FoldingUnaryOperators() { var source = @" using System; class C { const int implicit_int = -Int32.MinValue; const long implicit_long = -Int64.MinValue; const int checked_int = checked(-Int32.MinValue); const long checked_long = checked(-Int64.MinValue); const int unchecked_int = unchecked(-Int32.MinValue); const long unchecked_long = unchecked(-Int64.MinValue); } "; CreateCompilation(source).VerifyDiagnostics( // (6,30): error CS0220: The operation overflows at compile time in checked mode Diagnostic(ErrorCode.ERR_CheckedOverflow, "-Int32.MinValue"), // (7,32): error CS0220: The operation overflows at compile time in checked mode Diagnostic(ErrorCode.ERR_CheckedOverflow, "-Int64.MinValue"), // (9,37): error CS0220: The operation overflows at compile time in checked mode Diagnostic(ErrorCode.ERR_CheckedOverflow, "-Int32.MinValue"), // (10,39): error CS0220: The operation overflows at compile time in checked mode Diagnostic(ErrorCode.ERR_CheckedOverflow, "-Int64.MinValue")); } [ClrOnlyFact] public void FoldingRemDivOperators() { var source = @" class C { void M() { const int crem = checked(int.MinValue % (-1)); const int urem = unchecked(int.MinValue % (-1)); const long creml = checked(long.MinValue % (-1)); const long ureml = unchecked(long.MinValue % (-1)); const int cdiv = checked(int.MinValue / (-1)); const int udiv = unchecked(int.MinValue / (-1)); const long cdivl = checked(long.MinValue / (-1)); const long udivl = unchecked(long.MinValue / (-1)); System.Console.WriteLine(null, crem, urem, creml, ureml, cdiv, udiv, cdivl, udivl); } } "; CreateCompilation(source).VerifyDiagnostics( // (12,34): error CS0220: The operation overflows at compile time in checked mode Diagnostic(ErrorCode.ERR_CheckedOverflow, "int.MinValue / (-1)"), // (15,36): error CS0220: The operation overflows at compile time in checked mode Diagnostic(ErrorCode.ERR_CheckedOverflow, "long.MinValue / (-1)")); var actual = ParseAndGetConstantFoldingSteps(source); var expected = @"int.MinValue % (-1) --> 0 int.MinValue --> -2147483648 -1 --> -1 int.MinValue % (-1) --> 0 int.MinValue --> -2147483648 -1 --> -1 long.MinValue % (-1) --> 0 long.MinValue --> -9223372036854775808 -1 --> -1 -1 --> -1 long.MinValue % (-1) --> 0 long.MinValue --> -9223372036854775808 -1 --> -1 -1 --> -1 int.MinValue / (-1) --> BAD int.MinValue --> -2147483648 -1 --> -1 int.MinValue / (-1) --> -2147483648 int.MinValue --> -2147483648 -1 --> -1 long.MinValue / (-1) --> BAD long.MinValue --> -9223372036854775808 -1 --> -1 -1 --> -1 long.MinValue / (-1) --> -9223372036854775808 long.MinValue --> -9223372036854775808 -1 --> -1 -1 --> -1 null --> null cdiv --> BAD cdivl --> BAD"; Assert.Equal(expected, actual); } [Fact] public void CS0220ERR_CheckedOverflow01() { var text = @"class TestClass { const int x = 1000000; const int y = 1000000; public int MethodCh() { int z = (x * y); // CS0220 return z; } public int MethodUnCh() { unchecked { int z = (x * y); return z; } } } "; CreateCompilation(text).VerifyDiagnostics( // (8,18): error CS0220: The operation overflows at compile time in checked mode Diagnostic(ErrorCode.ERR_CheckedOverflow, "x * y")); } [Fact] public void CS0220ERR_CheckedOverflow02() { string text = @"enum E : uint { A, B = A - 1 } "; CreateCompilation(text).VerifyDiagnostics( // (1,24): error CS0220: The operation overflows at compile time in checked mode Diagnostic(ErrorCode.ERR_CheckedOverflow, "A - 1")); } [Fact] public void CS0220ERR_CheckedOverflow_Enums() { string text = @"enum E : uint { A = uint.MaxValue } class C { const uint F = (uint)(E.A + 1); // CS0220 const uint G = unchecked((uint)(E.A + 2)); const uint H = checked((uint)(E.A + 3)); // CS0220 } "; CreateCompilation(text).VerifyDiagnostics( // (4,27): error CS0220: The operation overflows at compile time in checked mode Diagnostic(ErrorCode.ERR_CheckedOverflow, "E.A + 1"), // (6,35): error CS0220: The operation overflows at compile time in checked mode Diagnostic(ErrorCode.ERR_CheckedOverflow, "E.A + 3")); } [Fact] public void MultiplyingConstantsInCheckedStatement() { // multiplying constants in checked statement that causes overflow behaves like unchecked var source = @" public class @goo { const int i = 1000000; const int j = 1000000; public static void Main() { checked { int k = i * j; } } } "; var comp = CreateCompilation(source); comp.VerifyDiagnostics( // (11,21): error CS0220: The operation overflows at compile time in checked mode // int k = i * j; Diagnostic(ErrorCode.ERR_CheckedOverflow, "i * j").WithLocation(11, 21)); } [Fact] public void ExpressionsInDefaultCheckedContext() { // Expressions which are in unchecked statement are in explicitly unchecked context. // Expressions which are out of unchecked statement are in default checked context. var source = @" class Program { static void Main() { int r = 0; r = int.MaxValue + 1; unchecked { r = int.MaxValue + 1; }; } } "; var comp = CreateCompilation(source); comp.VerifyDiagnostics( // (8,13): error CS0220: The operation overflows at compile time in checked mode // r = int.MaxValue + 1; Diagnostic(ErrorCode.ERR_CheckedOverflow, "int.MaxValue + 1")); } [Fact] public void MethodInvocationExpressionInCheckedOrUncheckedStatement() { // Overflow checking context with use method invocation expression in checked/unchecked statement var source = @" class Program { static int M1(int i) { int r = int.MaxValue + 1; checked { r = int.MaxValue + 1; } return r; } static void Main() { int r = 0; r = int.MaxValue + 1; unchecked { r = M1(int.MaxValue + 1); } checked { r = M1(int.MaxValue + 1); } } } "; var comp = CreateCompilation(source); comp.VerifyDiagnostics( // (6,17): error CS0220: The operation overflows at compile time in checked mode // int r = int.MaxValue + 1; Diagnostic(ErrorCode.ERR_CheckedOverflow, "int.MaxValue + 1"), // (9,17): error CS0220: The operation overflows at compile time in checked mode // r = int.MaxValue + 1; Diagnostic(ErrorCode.ERR_CheckedOverflow, "int.MaxValue + 1"), // (17,13): error CS0220: The operation overflows at compile time in checked mode // r = int.MaxValue + 1; Diagnostic(ErrorCode.ERR_CheckedOverflow, "int.MaxValue + 1"), // (25,20): error CS0220: The operation overflows at compile time in checked mode // r = M1(int.MaxValue + 1); Diagnostic(ErrorCode.ERR_CheckedOverflow, "int.MaxValue + 1")); } [Fact] public void AnonymousFunctionAndLambdaExpressionInUncheckedStatement() { // Overflow checking context with use anonymous function expression in unchecked statement var source = @" class Program { delegate int D1(int i); static void Main() { int r = 0; D1 d1; r = int.MaxValue + 1; unchecked { r = int.MaxValue + 1; d1 = delegate (int i) { int r1 = int.MaxValue + 1; checked { r1 = int.MaxValue + 1; } return r1; }; } unchecked { r = int.MaxValue + 1; d1 = i => int.MaxValue + 1 + checked(0 + 0); } unchecked { r = int.MaxValue + 1; d1 = i => 0 + 0 + checked(int.MaxValue + 1); } unchecked { r = int.MaxValue + 1; d1 = new D1(delegate (int i) { int r1 = int.MaxValue + 1; checked { r1 = int.MaxValue + 1; } return r1; }); } unchecked { r = int.MaxValue + 1; d1 = new D1(i => int.MaxValue + 1 + checked(0 + 0)); } unchecked { r = int.MaxValue + 1; d1 = new D1(i => 0 + 0 + checked(int.MaxValue + 1)); } } } "; var comp = CreateCompilation(source); comp.VerifyDiagnostics( // (9,13): error CS0220: The operation overflows at compile time in checked mode // r = int.MaxValue + 1; Diagnostic(ErrorCode.ERR_CheckedOverflow, "int.MaxValue + 1"), // (16,32): error CS0220: The operation overflows at compile time in checked mode // checked { r1 = int.MaxValue + 1; } Diagnostic(ErrorCode.ERR_CheckedOverflow, "int.MaxValue + 1"), // (28,39): error CS0220: The operation overflows at compile time in checked mode // d1 = i => 0 + 0 + checked(int.MaxValue + 1); Diagnostic(ErrorCode.ERR_CheckedOverflow, "int.MaxValue + 1"), // (37,32): error CS0220: The operation overflows at compile time in checked mode // checked { r1 = int.MaxValue + 1; } Diagnostic(ErrorCode.ERR_CheckedOverflow, "int.MaxValue + 1"), // (49,46): error CS0220: The operation overflows at compile time in checked mode // d1 = new D1(i => 0 + 0 + checked(int.MaxValue + 1)); Diagnostic(ErrorCode.ERR_CheckedOverflow, "int.MaxValue + 1")); } [Fact] public void AnonymousFunctionAndLambdaExpressionInCheckedStatement() { // Overflow checking context with use anonymous function expression in checked statement var source = @" class Program { delegate int D1(int i); static void Main() { int r = 0; D1 d1; checked { r = int.MaxValue + 1; d1 = i => int.MaxValue + 1 + unchecked(0 + 0); } checked { r = int.MaxValue + 1; d1 = i => 0 + 0 + unchecked(int.MaxValue + 1); } checked { r = int.MaxValue + 1; d1 = new D1(i => int.MaxValue + 1 + unchecked(0 + 0)); } checked { r = int.MaxValue + 1; d1 = new D1(i => 0 + 0 + unchecked(int.MaxValue + 1)); } } } "; var comp = CreateCompilation(source); comp.VerifyDiagnostics( // (11,17): error CS0220: The operation overflows at compile time in checked mode // r = int.MaxValue + 1; Diagnostic(ErrorCode.ERR_CheckedOverflow, "int.MaxValue + 1"), // (12,23): error CS0220: The operation overflows at compile time in checked mode // d1 = i => int.MaxValue + 1 + unchecked(0 + 0); Diagnostic(ErrorCode.ERR_CheckedOverflow, "int.MaxValue + 1"), // (16,17): error CS0220: The operation overflows at compile time in checked mode // r = int.MaxValue + 1; Diagnostic(ErrorCode.ERR_CheckedOverflow, "int.MaxValue + 1"), // (21,17): error CS0220: The operation overflows at compile time in checked mode // r = int.MaxValue + 1; Diagnostic(ErrorCode.ERR_CheckedOverflow, "int.MaxValue + 1"), // (22,30): error CS0220: The operation overflows at compile time in checked mode // d1 = new D1(i => int.MaxValue + 1 + unchecked(0 + 0)); Diagnostic(ErrorCode.ERR_CheckedOverflow, "int.MaxValue + 1"), // (26,17): error CS0220: The operation overflows at compile time in checked mode // r = int.MaxValue + 1; Diagnostic(ErrorCode.ERR_CheckedOverflow, "int.MaxValue + 1")); } [Fact] public void TestConstantFields() { var source = @"class C { const int x = 1; const int y = x + 1; void M() { const int z = x + y; } "; var actual = ParseAndGetConstantFoldingSteps(source); var expected = @"x + y --> 3 x --> 1 y --> 2"; Assert.Equal(expected, actual); } [Fact] public void TestBadConstantValue() { var source = @"class C { const int x = x; void M() { const int z = ((short)(+x)) + 1; } "; var actual = ParseAndGetConstantFoldingSteps(source); //the cast line is duplicated because there's also an implicit conversions var expected = @"((short)(+x)) + 1 --> BAD (short)(+x) --> BAD (short)(+x) --> BAD +x --> BAD x --> BAD"; Assert.Equal(expected, actual); } // Technically, these are binary operators, but it's clearer to test them separately. [Fact] public void TestLiftedEquality() { var source = @"class C { void M() { const bool a = 1 == null; const bool b = 1 != null; const bool c = null == (1 == null); const bool d = null != (1 != null); } }"; var actual = ParseAndGetConstantFoldingSteps(source); //the identity lines are implicit conversions var expected = @"1 == null --> False null --> null 1 != null --> True null --> null null == (1 == null) --> False null --> null 1 == null --> False null --> null null != (1 != null) --> True null --> null 1 != null --> True null --> null"; Assert.Equal(expected, actual); } [Fact] public void ConstantEquals1() { ConstantValue nonNullValue = ConstantValue.Create(10); ConstantValue nullValue = null; ConstantEquals(nullValue, nullValue); ConstantEquals(nullValue, nonNullValue); ConstantEquals(nonNullValue, nullValue); ConstantEquals(nonNullValue, nonNullValue); } private static void ConstantEquals(ConstantValue a, ConstantValue b) { var same = object.ReferenceEquals(a, b); Assert.Equal(a == b, same); Assert.Equal(a != b, !same); } [Fact] public void TestConstantConditional() { var source = @"class C { const bool b = true ? false : true; void M() { const int z = b ? 1 + 2 : (int)4u; } "; var actual = ParseAndGetConstantFoldingSteps(source); var expected = @"b ? 1 + 2 : (int)4u --> 4 b --> False 1 + 2 --> 3 (int)4u --> 4"; Assert.Equal(expected, actual); } [Fact] public void TestConstantConditionalBadValue() { var source = @"class C { const int i = i; const bool b = b; void M() { const int z = true ? 1 + i : (int)4u; const int z = b ? (uint)1 : (byte)2; } "; var actual = ParseAndGetConstantFoldingSteps(source); // Confirm that both branches are evaluated, even if the value is Bad // Duplicate "(byte)2" is because there's an implicit conversion to uint. // Duplicate "b ? (uint)1 : (byte)2" is because there's an implicit conversion to int. var expected = @"1 + i --> BAD i --> BAD (int)4u --> 4 b ? (uint)1 : (byte)2 --> BAD b ? (uint)1 : (byte)2 --> BAD b --> BAD (uint)1 --> 1 (byte)2 --> 2 (byte)2 --> 2"; Assert.Equal(expected, actual); } [Fact] public void TestUnspecifiedUncheckedConversions() { var source = @"class C { void M() { unchecked { _ = (ulong)double.NaN; _ = (uint)double.NaN; _ = (ulong)float.NaN; _ = (uint)float.NaN; _ = (ulong)double.NegativeInfinity; _ = (uint)double.NegativeInfinity; _ = (ulong)float.NegativeInfinity; _ = (uint)float.NegativeInfinity; _ = (ulong)double.PositiveInfinity; _ = (uint)double.PositiveInfinity; _ = (ulong)float.PositiveInfinity; _ = (uint)float.PositiveInfinity; _ = (ulong)1e100; _ = (uint)1e100; _ = (ulong)1e38f; _ = (uint)1e38f; _ = (ulong)-1e100; _ = (uint)-1e100; _ = (ulong)-1e38f; _ = (uint)-1e38f; _ = (short)65535.17567; } } }"; var actual = ParseAndGetConstantFoldingSteps(source); var expected = @"(ulong)double.NaN --> 0 double.NaN --> NaN (uint)double.NaN --> 0 double.NaN --> NaN (ulong)float.NaN --> 0 float.NaN --> NaN (uint)float.NaN --> 0 float.NaN --> NaN (ulong)double.NegativeInfinity --> 0 double.NegativeInfinity --> -Infinity (uint)double.NegativeInfinity --> 0 double.NegativeInfinity --> -Infinity (ulong)float.NegativeInfinity --> 0 float.NegativeInfinity --> -Infinity (uint)float.NegativeInfinity --> 0 float.NegativeInfinity --> -Infinity (ulong)double.PositiveInfinity --> 0 double.PositiveInfinity --> Infinity (uint)double.PositiveInfinity --> 0 double.PositiveInfinity --> Infinity (ulong)float.PositiveInfinity --> 0 float.PositiveInfinity --> Infinity (uint)float.PositiveInfinity --> 0 float.PositiveInfinity --> Infinity (ulong)1e100 --> 0 (uint)1e100 --> 0 (ulong)1e38f --> 0 (uint)1e38f --> 0 (ulong)-1e100 --> 0 -1e100 --> -1E+100 (uint)-1e100 --> 0 -1e100 --> -1E+100 (ulong)-1e38f --> 0 -1e38f --> -1E+38 (uint)-1e38f --> 0 -1e38f --> -1E+38 (short)65535.17567 --> 0"; Assert.Equal(expected, actual); } [Fact] public void TestUnspecifiedShifts() { var source = @"class C { void M() { _ = 1487023104 == (-40490869 << 1176494346); _ = 3405660160U == (385007504U << 1176494346); _ = -5519616229445825536L == (2480596744084445603L << 1176494346); _ = 12553477852066636800UL == (1183195158831237785UL << 1176494346); _ = -39542 == (-40490869 >> 1176494346); _ = 375983U == (385007504U >> 1176494346); _ = 2422457757894966L == (2480596744084445603L >> 1176494346); _ = 1155464022296130UL == (1183195158831237785UL >> 1176494346); _ = 1026730496 == (1142856021 << 52258473); _ = 3405730304U == (4167401385U << 52258473); _ = 949749347979886592L == (-99642203025533160L << 52258473); _ = 3870362293631975424UL == (5277240384921721637UL << 52258473); _ = 2232140 == (1142856021 >> 52258473); _ = 8139455U == (4167401385U >> 52258473); _ = -45313L == (-99642203025533160L >> 52258473); _ = 2399811UL == (5277240384921721637UL >> 52258473); _ = 2146190848 == (1765799459 << -847584439); _ = 746002432U == (1956002700U << -847584439); _ = 8330086530681716224L == (-2649861279148095905L << -847584439); _ = 11021680305799133184UL == (4633212737774651836UL << -847584439); _ = 3448827 == (1765799459 >> -847584439); _ = 3820317U == (1956002700U >> -847584439); _ = -5175510310836125L == (-2649861279148095905L >> -847584439); _ = 9049243628466116UL == (4633212737774651836UL >> -847584439); _ = -147839246 == (-73919623 << -261666143); _ = 434667096U == (2364817196U << -261666143); _ = 5379847945883484160L == (8600028236070815642L << -261666143); _ = 18250411927379378176UL == (9754066888939486842UL << -261666143); _ = -36959812 == (-73919623 >> -261666143); _ = 1182408598U == (2364817196U >> -261666143); _ = 1001175054L == (8600028236070815642L >> -261666143); _ = 1135522835UL == (9754066888939486842UL >> -261666143); _ = -642990336 == (-575448706 << 1251164583); _ = 101734912U == (2651594932U << 1251164583); _ = -2477956711135051776L == (4397665286211975439L << 1251164583); _ = 17177975275221155840UL == (3677188853080049883UL << 1251164583); _ = -4495694 == (-575448706 >> 1251164583); _ = 20715585U == (2651594932U >> 1251164583); _ = 7999306L == (4397665286211975439L >> 1251164583); _ = 6688767UL == (3677188853080049883UL >> 1251164583); _ = -2147483648 == (1680903167 << -1931469441); _ = 2147483648U == (1696031835U << -1931469441); _ = 0L == (-5154426740587151092L << -1931469441); _ = 9223372036854775808UL == (11340274989429123451UL << -1931469441); _ = 0 == (1680903167 >> -1931469441); _ = 0U == (1696031835U >> -1931469441); _ = -1L == (-5154426740587151092L >> -1931469441); _ = 1UL == (11340274989429123451UL >> -1931469441); _ = -1073741824 == (466088311 << 664633406); _ = 0U == (3367565272U << 664633406); _ = 0L == (-9002257244105090536L << 664633406); _ = 13835058055282163712UL == (16369162113479203207UL << 664633406); _ = 0 == (466088311 >> 664633406); _ = 3U == (3367565272U >> 664633406); _ = -2L == (-9002257244105090536L >> 664633406); _ = 3UL == (16369162113479203207UL >> 664633406); _ = 1016170002 == (508085001 << 84049121); _ = 3845222538U == (1922611269U << 84049121); _ = -3053627404204376064L == (1789288808291740423L << 84049121); _ = 9069021830043402240UL == (3140594490787352999UL << 84049121); _ = 254042500 == (508085001 >> 84049121); _ = 961305634U == (1922611269U >> 84049121); _ = 208300632L == (1789288808291740423L >> 84049121); _ = 365613318UL == (3140594490787352999UL >> 84049121); _ = 1610612736 == (1704288204 << -639239173); _ = 3758096384U == (2570458748U << -639239173); _ = -1152921504606846976L == (7131876568822188702L << -639239173); _ = 9799832789158199296UL == (5759179746966546129UL << -639239173); _ = 12 == (1704288204 >> -639239173); _ = 19U == (2570458748U >> -639239173); _ = 12L == (7131876568822188702L >> -639239173); _ = 9UL == (5759179746966546129UL >> -639239173); _ = 1493172224 == (-177594791 << 232270776); _ = 671088640U == (3656907048U << 232270776); _ = 144115188075855872L == (5226244767915300354L << 232270776); _ = 17005592192950992896UL == (16201604657234886124UL << 232270776); _ = -11 == (-177594791 >> 232270776); _ = 217U == (3656907048U >> 232270776); _ = 72L == (5226244767915300354L >> 232270776); _ = 224UL == (16201604657234886124UL >> 232270776); } }"; var actual = ParseAndGetConstantFoldingSteps(source); var expected = @"1487023104 == (-40490869 << 1176494346) --> True -40490869 << 1176494346 --> 1487023104 -40490869 --> -40490869 3405660160U == (385007504U << 1176494346) --> True 385007504U << 1176494346 --> 3405660160 -5519616229445825536L == (2480596744084445603L << 1176494346) --> True -5519616229445825536L --> -5519616229445825536 2480596744084445603L << 1176494346 --> -5519616229445825536 12553477852066636800UL == (1183195158831237785UL << 1176494346) --> True 1183195158831237785UL << 1176494346 --> 12553477852066636800 -39542 == (-40490869 >> 1176494346) --> True -39542 --> -39542 -40490869 >> 1176494346 --> -39542 -40490869 --> -40490869 375983U == (385007504U >> 1176494346) --> True 385007504U >> 1176494346 --> 375983 2422457757894966L == (2480596744084445603L >> 1176494346) --> True 2480596744084445603L >> 1176494346 --> 2422457757894966 1155464022296130UL == (1183195158831237785UL >> 1176494346) --> True 1183195158831237785UL >> 1176494346 --> 1155464022296130 1026730496 == (1142856021 << 52258473) --> True 1142856021 << 52258473 --> 1026730496 3405730304U == (4167401385U << 52258473) --> True 4167401385U << 52258473 --> 3405730304 949749347979886592L == (-99642203025533160L << 52258473) --> True -99642203025533160L << 52258473 --> 949749347979886592 -99642203025533160L --> -99642203025533160 3870362293631975424UL == (5277240384921721637UL << 52258473) --> True 5277240384921721637UL << 52258473 --> 3870362293631975424 2232140 == (1142856021 >> 52258473) --> True 1142856021 >> 52258473 --> 2232140 8139455U == (4167401385U >> 52258473) --> True 4167401385U >> 52258473 --> 8139455 -45313L == (-99642203025533160L >> 52258473) --> True -45313L --> -45313 -99642203025533160L >> 52258473 --> -45313 -99642203025533160L --> -99642203025533160 2399811UL == (5277240384921721637UL >> 52258473) --> True 5277240384921721637UL >> 52258473 --> 2399811 2146190848 == (1765799459 << -847584439) --> True 1765799459 << -847584439 --> 2146190848 -847584439 --> -847584439 746002432U == (1956002700U << -847584439) --> True 1956002700U << -847584439 --> 746002432 -847584439 --> -847584439 8330086530681716224L == (-2649861279148095905L << -847584439) --> True -2649861279148095905L << -847584439 --> 8330086530681716224 -2649861279148095905L --> -2649861279148095905 -847584439 --> -847584439 11021680305799133184UL == (4633212737774651836UL << -847584439) --> True 4633212737774651836UL << -847584439 --> 11021680305799133184 -847584439 --> -847584439 3448827 == (1765799459 >> -847584439) --> True 1765799459 >> -847584439 --> 3448827 -847584439 --> -847584439 3820317U == (1956002700U >> -847584439) --> True 1956002700U >> -847584439 --> 3820317 -847584439 --> -847584439 -5175510310836125L == (-2649861279148095905L >> -847584439) --> True -5175510310836125L --> -5175510310836125 -2649861279148095905L >> -847584439 --> -5175510310836125 -2649861279148095905L --> -2649861279148095905 -847584439 --> -847584439 9049243628466116UL == (4633212737774651836UL >> -847584439) --> True 4633212737774651836UL >> -847584439 --> 9049243628466116 -847584439 --> -847584439 -147839246 == (-73919623 << -261666143) --> True -147839246 --> -147839246 -73919623 << -261666143 --> -147839246 -73919623 --> -73919623 -261666143 --> -261666143 434667096U == (2364817196U << -261666143) --> True 2364817196U << -261666143 --> 434667096 -261666143 --> -261666143 5379847945883484160L == (8600028236070815642L << -261666143) --> True 8600028236070815642L << -261666143 --> 5379847945883484160 -261666143 --> -261666143 18250411927379378176UL == (9754066888939486842UL << -261666143) --> True 9754066888939486842UL << -261666143 --> 18250411927379378176 -261666143 --> -261666143 -36959812 == (-73919623 >> -261666143) --> True -36959812 --> -36959812 -73919623 >> -261666143 --> -36959812 -73919623 --> -73919623 -261666143 --> -261666143 1182408598U == (2364817196U >> -261666143) --> True 2364817196U >> -261666143 --> 1182408598 -261666143 --> -261666143 1001175054L == (8600028236070815642L >> -261666143) --> True 8600028236070815642L >> -261666143 --> 1001175054 -261666143 --> -261666143 1135522835UL == (9754066888939486842UL >> -261666143) --> True 9754066888939486842UL >> -261666143 --> 1135522835 -261666143 --> -261666143 -642990336 == (-575448706 << 1251164583) --> True -642990336 --> -642990336 -575448706 << 1251164583 --> -642990336 -575448706 --> -575448706 101734912U == (2651594932U << 1251164583) --> True 2651594932U << 1251164583 --> 101734912 -2477956711135051776L == (4397665286211975439L << 1251164583) --> True -2477956711135051776L --> -2477956711135051776 4397665286211975439L << 1251164583 --> -2477956711135051776 17177975275221155840UL == (3677188853080049883UL << 1251164583) --> True 3677188853080049883UL << 1251164583 --> 17177975275221155840 -4495694 == (-575448706 >> 1251164583) --> True -4495694 --> -4495694 -575448706 >> 1251164583 --> -4495694 -575448706 --> -575448706 20715585U == (2651594932U >> 1251164583) --> True 2651594932U >> 1251164583 --> 20715585 7999306L == (4397665286211975439L >> 1251164583) --> True 4397665286211975439L >> 1251164583 --> 7999306 6688767UL == (3677188853080049883UL >> 1251164583) --> True 3677188853080049883UL >> 1251164583 --> 6688767 -2147483648 == (1680903167 << -1931469441) --> True 1680903167 << -1931469441 --> -2147483648 -1931469441 --> -1931469441 2147483648U == (1696031835U << -1931469441) --> True 1696031835U << -1931469441 --> 2147483648 -1931469441 --> -1931469441 0L == (-5154426740587151092L << -1931469441) --> True -5154426740587151092L << -1931469441 --> 0 -5154426740587151092L --> -5154426740587151092 -1931469441 --> -1931469441 9223372036854775808UL == (11340274989429123451UL << -1931469441) --> True 11340274989429123451UL << -1931469441 --> 9223372036854775808 -1931469441 --> -1931469441 0 == (1680903167 >> -1931469441) --> True 1680903167 >> -1931469441 --> 0 -1931469441 --> -1931469441 0U == (1696031835U >> -1931469441) --> True 1696031835U >> -1931469441 --> 0 -1931469441 --> -1931469441 -1L == (-5154426740587151092L >> -1931469441) --> True -1L --> -1 -5154426740587151092L >> -1931469441 --> -1 -5154426740587151092L --> -5154426740587151092 -1931469441 --> -1931469441 1UL == (11340274989429123451UL >> -1931469441) --> True 11340274989429123451UL >> -1931469441 --> 1 -1931469441 --> -1931469441 -1073741824 == (466088311 << 664633406) --> True -1073741824 --> -1073741824 466088311 << 664633406 --> -1073741824 0U == (3367565272U << 664633406) --> True 3367565272U << 664633406 --> 0 0L == (-9002257244105090536L << 664633406) --> True -9002257244105090536L << 664633406 --> 0 -9002257244105090536L --> -9002257244105090536 13835058055282163712UL == (16369162113479203207UL << 664633406) --> True 16369162113479203207UL << 664633406 --> 13835058055282163712 0 == (466088311 >> 664633406) --> True 466088311 >> 664633406 --> 0 3U == (3367565272U >> 664633406) --> True 3367565272U >> 664633406 --> 3 -2L == (-9002257244105090536L >> 664633406) --> True -2L --> -2 -9002257244105090536L >> 664633406 --> -2 -9002257244105090536L --> -9002257244105090536 3UL == (16369162113479203207UL >> 664633406) --> True 16369162113479203207UL >> 664633406 --> 3 1016170002 == (508085001 << 84049121) --> True 508085001 << 84049121 --> 1016170002 3845222538U == (1922611269U << 84049121) --> True 1922611269U << 84049121 --> 3845222538 -3053627404204376064L == (1789288808291740423L << 84049121) --> True -3053627404204376064L --> -3053627404204376064 1789288808291740423L << 84049121 --> -3053627404204376064 9069021830043402240UL == (3140594490787352999UL << 84049121) --> True 3140594490787352999UL << 84049121 --> 9069021830043402240 254042500 == (508085001 >> 84049121) --> True 508085001 >> 84049121 --> 254042500 961305634U == (1922611269U >> 84049121) --> True 1922611269U >> 84049121 --> 961305634 208300632L == (1789288808291740423L >> 84049121) --> True 1789288808291740423L >> 84049121 --> 208300632 365613318UL == (3140594490787352999UL >> 84049121) --> True 3140594490787352999UL >> 84049121 --> 365613318 1610612736 == (1704288204 << -639239173) --> True 1704288204 << -639239173 --> 1610612736 -639239173 --> -639239173 3758096384U == (2570458748U << -639239173) --> True 2570458748U << -639239173 --> 3758096384 -639239173 --> -639239173 -1152921504606846976L == (7131876568822188702L << -639239173) --> True -1152921504606846976L --> -1152921504606846976 7131876568822188702L << -639239173 --> -1152921504606846976 -639239173 --> -639239173 9799832789158199296UL == (5759179746966546129UL << -639239173) --> True 5759179746966546129UL << -639239173 --> 9799832789158199296 -639239173 --> -639239173 12 == (1704288204 >> -639239173) --> True 1704288204 >> -639239173 --> 12 -639239173 --> -639239173 19U == (2570458748U >> -639239173) --> True 2570458748U >> -639239173 --> 19 -639239173 --> -639239173 12L == (7131876568822188702L >> -639239173) --> True 7131876568822188702L >> -639239173 --> 12 -639239173 --> -639239173 9UL == (5759179746966546129UL >> -639239173) --> True 5759179746966546129UL >> -639239173 --> 9 -639239173 --> -639239173 1493172224 == (-177594791 << 232270776) --> True -177594791 << 232270776 --> 1493172224 -177594791 --> -177594791 671088640U == (3656907048U << 232270776) --> True 3656907048U << 232270776 --> 671088640 144115188075855872L == (5226244767915300354L << 232270776) --> True 5226244767915300354L << 232270776 --> 144115188075855872 17005592192950992896UL == (16201604657234886124UL << 232270776) --> True 16201604657234886124UL << 232270776 --> 17005592192950992896 -11 == (-177594791 >> 232270776) --> True -11 --> -11 -177594791 >> 232270776 --> -11 -177594791 --> -177594791 217U == (3656907048U >> 232270776) --> True 3656907048U >> 232270776 --> 217 72L == (5226244767915300354L >> 232270776) --> True 5226244767915300354L >> 232270776 --> 72 224UL == (16201604657234886124UL >> 232270776) --> True 16201604657234886124UL >> 232270776 --> 224"; Assert.Equal(expected, actual); } // Constant fields should be bound in the declaration phase. [Fact] public void TestConstantEvalAtDeclarationPhase() { var source = @"class C { const string F = F; }"; var compilation = CreateCompilation(source); compilation.GetDeclarationDiagnostics().Verify( // (3,18): error CS0110: The evaluation of the constant value for 'C.F' involves a circular definition Diagnostic(CSharp.ErrorCode.ERR_CircConstValue, "F").WithArguments("C.F").WithLocation(3, 18)); } [Fact] [WorkItem(50127, "https://github.com/dotnet/roslyn/issues/50127")] public void DeterministicCycleReporting() { var source = @"enum C { A = F, B = A + C + D + E, C = E, D = B, E = B, F = G, G = F, }"; var expected = new[] { // (4,5): error CS0110: The evaluation of the constant value for 'C.B' involves a circular definition // B = A + C + D + E, Diagnostic(ErrorCode.ERR_CircConstValue, "B").WithArguments("C.B").WithLocation(4, 5), // (8,5): error CS0110: The evaluation of the constant value for 'C.F' involves a circular definition // F = G, Diagnostic(ErrorCode.ERR_CircConstValue, "F").WithArguments("C.F").WithLocation(8, 5) }; for (int i = 0; i < 100; i++) { var compilation = CreateCompilation(source); compilation.GetDeclarationDiagnostics().Verify(expected); } } [Fact] public void TestConstantEvalAcrossCompilations() { var source1 = @"public class A { public const string A1 = null; } public class B { public const string B1 = A.A1; } public class C { public const string C1 = B.B1; }"; var source2 = @"public class D { public const string D1 = E.E1; } public class E { public const string E1 = C.C1; }"; var compilation1 = CreateCompilation(source1); var compilation2 = CreateCompilation(source2, new MetadataReference[] { new CSharpCompilationReference(compilation1) }); compilation2.VerifyDiagnostics(); compilation1.VerifyDiagnostics(); } [Fact] public void TestCyclicConstantEvalAcrossCompilations() { var source1 = @"public class A { public const string A1 = B.B1; } public class B { public const string B1 = A.A1; } public class C { public const string C1 = B.B1; }"; var source2 = @"public class D { public const string D1 = D1; }"; var source3 = @"public class E { public const string E1 = F.F1; } public class F { public const string F1 = C.C1; }"; var source4 = @"public class G { public const string G1 = F.F1 + D.D1; }"; var compilation1 = CreateCompilation(source1); var reference1 = new CSharpCompilationReference(compilation1); var compilation2 = CreateCompilation(source2); var reference2 = new CSharpCompilationReference(compilation2); var compilation3 = CreateCompilation(source3, new MetadataReference[] { reference1 }); var reference3 = new CSharpCompilationReference(compilation3); var compilation4 = CreateCompilation(source4, new MetadataReference[] { reference2, reference3 }); compilation4.VerifyDiagnostics(); compilation3.VerifyDiagnostics(); compilation2.VerifyDiagnostics( // (3,25): error CS0110: The evaluation of the constant value for 'D.D1' involves a circular definition // public const string D1 = D1; Diagnostic(ErrorCode.ERR_CircConstValue, "D1").WithArguments("D.D1").WithLocation(3, 25)); compilation1.VerifyDiagnostics( // (3,25): error CS0110: The evaluation of the constant value for 'A.A1' involves a circular definition // public const string A1 = B.B1; Diagnostic(ErrorCode.ERR_CircConstValue, "A1").WithArguments("A.A1").WithLocation(3, 25)); } [Fact] public void TestConstantValueInsideAttributes() { var tree = SyntaxFactory.ParseSyntaxTree(@" class c1 { const int A = 1; const int B = 2; class MyAttribute : Attribute { MyAttribute(int i) { } } [MyAttribute(A + B + 3)] void Goo() { } }"); var expr = tree.GetCompilationUnitRoot().DescendantNodes().OfType<BinaryExpressionSyntax>().First(); var comp = CreateCompilation(tree); var constantValue = comp.GetSemanticModel(tree).GetConstantValue(expr); Assert.True(constantValue.HasValue); Assert.Equal(6, constantValue.Value); } [WorkItem(544620, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/544620")] [Fact] public void NoConstantValueForOverflows() { var tree = SyntaxFactory.ParseSyntaxTree(@" class c1 { const byte Z1 = 300; const byte Z2 = (byte)300; }"); var compilation = CreateCompilation(tree); compilation.VerifyDiagnostics( // (4,21): error CS0031: Constant value '300' cannot be converted to a 'byte' // const byte Z1 = 300; Diagnostic(ErrorCode.ERR_ConstOutOfRange, "300").WithArguments("300", "byte"), // (5,21): error CS0221: Constant value '300' cannot be converted to a 'byte' (use 'unchecked' syntax to override) // const byte Z2 = (byte)300; Diagnostic(ErrorCode.ERR_ConstOutOfRangeChecked, "(byte)300").WithArguments("300", "byte") ); var symbol = compilation.GlobalNamespace.GetTypeMembers("c1").First().GetMembers("Z1").First(); Assert.False(((FieldSymbol)symbol).HasConstantValue); symbol = compilation.GlobalNamespace.GetTypeMembers("c1").First().GetMembers("Z2").First(); Assert.False(((FieldSymbol)symbol).HasConstantValue); } [WorkItem(544620, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/544620")] [Fact] public void NoConstantValueForOverflows_02() { var tree = SyntaxFactory.ParseSyntaxTree(@" class c1 { void M() { _ = checked((decimal)1e100); _ = unchecked((decimal)1e100); } }"); var compilation = CreateCompilation(tree); compilation.VerifyDiagnostics( // (6,21): error CS0031: Constant value '1E+100' cannot be converted to a 'decimal' // _ = checked((decimal)1e100); Diagnostic(ErrorCode.ERR_ConstOutOfRange, "(decimal)1e100").WithArguments("1E+100", "decimal").WithLocation(6, 21), // (7,23): error CS0031: Constant value '1E+100' cannot be converted to a 'decimal' // _ = unchecked((decimal)1e100); Diagnostic(ErrorCode.ERR_ConstOutOfRange, "(decimal)1e100").WithArguments("1E+100", "decimal").WithLocation(7, 23)); } [WorkItem(545965, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/545965")] [Fact] public void CircularConstantReportingRace() { const int numConstants = 5; var template = @" class C{0} {{ public const int X = C{1}.X; }}"; var range = Enumerable.Range(0, numConstants); var source = string.Join(Environment.NewLine, range.Select(i => string.Format(template, i, (i + 1) % numConstants))); var compilation = CreateCompilation(source); var global = compilation.GlobalNamespace; var types = range.Select(i => global.GetMember<NamedTypeSymbol>("C" + i)); // Complete all the types at the same time. Parallel.ForEach(types, t => t.ForceComplete(null, filter: null, default(CancellationToken))); compilation.VerifyDiagnostics( // (4,22): error CS0110: The evaluation of the constant value for 'C0.X' involves a circular definition // public const int X = C1.X; Diagnostic(ErrorCode.ERR_CircConstValue, "X").WithArguments("C0.X")); } [WorkItem(545965, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/545965")] [Fact] public void MultiCircularConstantReportingRace() { const int numConstants = 10; var template = @" class C{0} {{ public const int X = C{1}.X + C{2}.X; }}"; var range = Enumerable.Range(0, numConstants); var source = string.Join(Environment.NewLine, range.Select(i => i == 0 ? string.Format(template, i, i + 1, i + 1) : i == (numConstants - 1) ? string.Format(template, i, i - 1, i - 1) : string.Format(template, i, i - 1, i + 1))); var compilation = CreateCompilation(source); var global = compilation.GlobalNamespace; var types = range.Select(i => global.GetMember<NamedTypeSymbol>("C" + i)); // Complete all the types at the same time. Parallel.ForEach(types, t => t.ForceComplete(null, filter: null, default(CancellationToken))); // All but C9.X, which is not (lexically) first in any cycle. compilation.VerifyDiagnostics( // (4,22): error CS0110: The evaluation of the constant value for 'C0.X' involves a circular definition // public const int X = C1.X + C1.X; Diagnostic(ErrorCode.ERR_CircConstValue, "X").WithArguments("C0.X"), // (9,22): error CS0110: The evaluation of the constant value for 'C1.X' involves a circular definition // public const int X = C0.X + C2.X; Diagnostic(ErrorCode.ERR_CircConstValue, "X").WithArguments("C1.X"), // (14,22): error CS0110: The evaluation of the constant value for 'C2.X' involves a circular definition // public const int X = C1.X + C3.X; Diagnostic(ErrorCode.ERR_CircConstValue, "X").WithArguments("C2.X"), // (19,22): error CS0110: The evaluation of the constant value for 'C3.X' involves a circular definition // public const int X = C2.X + C4.X; Diagnostic(ErrorCode.ERR_CircConstValue, "X").WithArguments("C3.X"), // (24,22): error CS0110: The evaluation of the constant value for 'C4.X' involves a circular definition // public const int X = C3.X + C5.X; Diagnostic(ErrorCode.ERR_CircConstValue, "X").WithArguments("C4.X"), // (29,22): error CS0110: The evaluation of the constant value for 'C5.X' involves a circular definition // public const int X = C4.X + C6.X; Diagnostic(ErrorCode.ERR_CircConstValue, "X").WithArguments("C5.X"), // (34,22): error CS0110: The evaluation of the constant value for 'C6.X' involves a circular definition // public const int X = C5.X + C7.X; Diagnostic(ErrorCode.ERR_CircConstValue, "X").WithArguments("C6.X"), // (39,22): error CS0110: The evaluation of the constant value for 'C7.X' involves a circular definition // public const int X = C6.X + C8.X; Diagnostic(ErrorCode.ERR_CircConstValue, "X").WithArguments("C7.X"), // (44,22): error CS0110: The evaluation of the constant value for 'C8.X' involves a circular definition // public const int X = C7.X + C9.X; Diagnostic(ErrorCode.ERR_CircConstValue, "X").WithArguments("C8.X")); } [WorkItem(545965, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/545965")] [Fact] public void CircularEnumReportingRace() { const int numConstants = 5; var template = @" enum E{0} {{ X = E{1}.X }}"; var range = Enumerable.Range(0, numConstants); var source = string.Join(Environment.NewLine, range.Select(i => string.Format(template, i, (i + 1) % numConstants))); var compilation = CreateCompilation(source); var global = compilation.GlobalNamespace; var types = range.Select(i => global.GetMember<NamedTypeSymbol>("E" + i)); // Complete all the types at the same time. Parallel.ForEach(types, t => t.ForceComplete(null, filter: null, default(CancellationToken))); compilation.VerifyDiagnostics( // (4,5): error CS0110: The evaluation of the constant value for 'E0.X' involves a circular definition // X = E1.X Diagnostic(ErrorCode.ERR_CircConstValue, "X").WithArguments("E0.X")); } [WorkItem(545965, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/545965")] [Fact] public void MultiCircularEnumReportingRace() { const int numConstants = 10; var template = @" enum E{0} {{ X = E{1}.X | E{2}.X }}"; var range = Enumerable.Range(0, numConstants); var source = string.Join(Environment.NewLine, range.Select(i => i == 0 ? string.Format(template, i, i + 1, i + 1) : i == (numConstants - 1) ? string.Format(template, i, i - 1, i - 1) : string.Format(template, i, i - 1, i + 1))); var compilation = CreateCompilation(source); var global = compilation.GlobalNamespace; var types = range.Select(i => global.GetMember<NamedTypeSymbol>("E" + i)); // Complete all the types at the same time. Parallel.ForEach(types, t => t.ForceComplete(null, filter: null, default(CancellationToken))); // All but E9.X, which is not (lexically) first in any cycle. compilation.VerifyDiagnostics( // (4,5): error CS0110: The evaluation of the constant value for 'E0.X' involves a circular definition // X = E1.X | E1.X Diagnostic(ErrorCode.ERR_CircConstValue, "X").WithArguments("E0.X").WithLocation(4, 5), // (9,5): error CS0110: The evaluation of the constant value for 'E1.X' involves a circular definition // X = E0.X | E2.X Diagnostic(ErrorCode.ERR_CircConstValue, "X").WithArguments("E1.X").WithLocation(9, 5), // (14,5): error CS0110: The evaluation of the constant value for 'E2.X' involves a circular definition // X = E1.X | E3.X Diagnostic(ErrorCode.ERR_CircConstValue, "X").WithArguments("E2.X").WithLocation(14, 5), // (19,5): error CS0110: The evaluation of the constant value for 'E3.X' involves a circular definition // X = E2.X | E4.X Diagnostic(ErrorCode.ERR_CircConstValue, "X").WithArguments("E3.X").WithLocation(19, 5), // (24,5): error CS0110: The evaluation of the constant value for 'E4.X' involves a circular definition // X = E3.X | E5.X Diagnostic(ErrorCode.ERR_CircConstValue, "X").WithArguments("E4.X").WithLocation(24, 5), // (29,5): error CS0110: The evaluation of the constant value for 'E5.X' involves a circular definition // X = E4.X | E6.X Diagnostic(ErrorCode.ERR_CircConstValue, "X").WithArguments("E5.X").WithLocation(29, 5), // (34,5): error CS0110: The evaluation of the constant value for 'E6.X' involves a circular definition // X = E5.X | E7.X Diagnostic(ErrorCode.ERR_CircConstValue, "X").WithArguments("E6.X").WithLocation(34, 5), // (39,5): error CS0110: The evaluation of the constant value for 'E7.X' involves a circular definition // X = E6.X | E8.X Diagnostic(ErrorCode.ERR_CircConstValue, "X").WithArguments("E7.X").WithLocation(39, 5), // (44,5): error CS0110: The evaluation of the constant value for 'E8.X' involves a circular definition // X = E7.X | E9.X Diagnostic(ErrorCode.ERR_CircConstValue, "X").WithArguments("E8.X").WithLocation(44, 5)); } [WorkItem(545965, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/545965")] [Fact] public void CircularImplicitEnumReportingRace() { const int numEnums = 5; var template = @" enum E{0} {{ A = E{1}.D, B, C, D, }}"; var range = Enumerable.Range(0, numEnums); var source = string.Join(Environment.NewLine, range.Select(i => string.Format(template, i, (i + 1) % numEnums))); var compilation = CreateCompilation(source); var global = compilation.GlobalNamespace; var types = range.Select(i => global.GetMember<NamedTypeSymbol>("E" + i)); // Complete all the types at the same time. Parallel.ForEach(types, t => t.ForceComplete(null, filter: null, default(CancellationToken))); compilation.VerifyDiagnostics( // (4,5): error CS0110: The evaluation of the constant value for 'E0.A' involves a circular definition // A = E1.D, Diagnostic(ErrorCode.ERR_CircConstValue, "A").WithArguments("E0.A")); } [WorkItem(545965, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/545965")] [Fact] public void MultiCircularImplicitEnumReportingRace() { const int numEnums = 10; var template = @" enum E{0} {{ A = E{1}.D | E{2}.D, B, C, D, }}"; var range = Enumerable.Range(0, numEnums); var source = string.Join(Environment.NewLine, range.Select(i => i == 0 ? string.Format(template, i, i + 1, i + 1) : i == (numEnums - 1) ? string.Format(template, i, i - 1, i - 1) : string.Format(template, i, i - 1, i + 1))); var compilation = CreateCompilation(source); var global = compilation.GlobalNamespace; var types = range.Select(i => global.GetMember<NamedTypeSymbol>("E" + i)); // Complete all the types at the same time. Parallel.ForEach(types, t => t.ForceComplete(null, filter: null, default(CancellationToken))); // All but E9.X, which is not (lexically) first in any cycle. compilation.VerifyDiagnostics( // (4,5): error CS0110: The evaluation of the constant value for 'E0.A' involves a circular definition // A = E1.D | E1.D, Diagnostic(ErrorCode.ERR_CircConstValue, "A").WithArguments("E0.A"), // (12,5): error CS0110: The evaluation of the constant value for 'E1.A' involves a circular definition // A = E0.D | E2.D, Diagnostic(ErrorCode.ERR_CircConstValue, "A").WithArguments("E1.A"), // (20,5): error CS0110: The evaluation of the constant value for 'E2.A' involves a circular definition // A = E1.D | E3.D, Diagnostic(ErrorCode.ERR_CircConstValue, "A").WithArguments("E2.A"), // (28,5): error CS0110: The evaluation of the constant value for 'E3.A' involves a circular definition // A = E2.D | E4.D, Diagnostic(ErrorCode.ERR_CircConstValue, "A").WithArguments("E3.A"), // (36,5): error CS0110: The evaluation of the constant value for 'E4.A' involves a circular definition // A = E3.D | E5.D, Diagnostic(ErrorCode.ERR_CircConstValue, "A").WithArguments("E4.A"), // (44,5): error CS0110: The evaluation of the constant value for 'E5.A' involves a circular definition // A = E4.D | E6.D, Diagnostic(ErrorCode.ERR_CircConstValue, "A").WithArguments("E5.A"), // (52,5): error CS0110: The evaluation of the constant value for 'E6.A' involves a circular definition // A = E5.D | E7.D, Diagnostic(ErrorCode.ERR_CircConstValue, "A").WithArguments("E6.A"), // (60,5): error CS0110: The evaluation of the constant value for 'E7.A' involves a circular definition // A = E6.D | E8.D, Diagnostic(ErrorCode.ERR_CircConstValue, "A").WithArguments("E7.A"), // (68,5): error CS0110: The evaluation of the constant value for 'E8.A' involves a circular definition // A = E7.D | E9.D, Diagnostic(ErrorCode.ERR_CircConstValue, "A").WithArguments("E8.A")); } [Fact, WorkItem(544941, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/544941")] public static void ConstantNullNotObject() { var source = @"class MyTest { } class MyClass { const MyTest test = null; const bool b = test == null; public static int Main() { const bool bb = test != null; return bb ? 1 : 0; } }"; CreateCompilation(source).VerifyDiagnostics(); } [Fact, WorkItem(1098197, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/1098197")] public static void Bug1098197_01_WithCSharp6() { var source = @" class Program { static void Main(string[] args) { void f() { if () const int i = 0; } } } "; CreateCompilation(source, parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp6)).VerifyDiagnostics( // (6,14): error CS8059: Feature 'local functions' is not available in C# 6. Please use language version 7.0 or greater. // void f() { if () const int i = 0; } Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion6, "f").WithArguments("local functions", "7.0").WithLocation(6, 14), // (6,24): error CS1525: Invalid expression term ')' // void f() { if () const int i = 0; } Diagnostic(ErrorCode.ERR_InvalidExprTerm, ")").WithArguments(")").WithLocation(6, 24), // (6,26): error CS1023: Embedded statement cannot be a declaration or labeled statement // void f() { if () const int i = 0; } Diagnostic(ErrorCode.ERR_BadEmbeddedStmt, "const int i = 0;").WithLocation(6, 26), // (6,36): warning CS0219: The variable 'i' is assigned but its value is never used // void f() { if () const int i = 0; } Diagnostic(ErrorCode.WRN_UnreferencedVarAssg, "i").WithArguments("i").WithLocation(6, 36), // (6,14): warning CS8321: The local function 'f' is declared but never used // void f() { if () const int i = 0; } Diagnostic(ErrorCode.WRN_UnreferencedLocalFunction, "f").WithArguments("f").WithLocation(6, 14) ); } [Fact] public static void DoubleRecursiveConst() { var source = @"using System; class C { public static void Main() { const Func<int> a = () => { const int b = a(); return 1; }; } }"; CreateCompilation(source).VerifyDiagnostics( // (6,51): error CS0133: The expression being assigned to 'b' must be constant // const Func<int> a = () => { const int b = a(); return 1; }; Diagnostic(ErrorCode.ERR_NotConstantExpression, "a()").WithArguments("b").WithLocation(6, 51) ); } [Fact] public static void DoubleRecursiveConst_NotInvoked() { var source = @"using System; class C { public static void Main() { const Func<int> a = () => { const Func<int> b = a; return 1; }; } }"; CreateCompilation(source).VerifyDiagnostics( // (6,57): error CS0134: 'b' is of type 'Func<int>'. A const field of a reference type other than string can only be initialized with null. // const Func<int> a = () => { const Func<int> b = a; return 1; }; Diagnostic(ErrorCode.ERR_NotNullConstRefField, "a").WithArguments("b", "System.Func<int>").WithLocation(6, 57) ); } [Fact] public static void RecursiveConst() { var source = @"class C { public static void Main() { const int z = 1 + z + 1; } }"; CreateCompilation(source).VerifyDiagnostics( // (5,27): error CS0110: The evaluation of the constant value for 'z' involves a circular definition // const int z = 1 + z + 1; Diagnostic(ErrorCode.ERR_CircConstValue, "z").WithArguments("z").WithLocation(5, 27) ); } [Fact, WorkItem(1098197, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/1098197")] public static void Bug1098197_02() { var source = @" void f() { if () const int i = 0; } "; CreateCompilation(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular9).VerifyDiagnostics( // (2,6): warning CS8321: The local function 'f' is declared but never used // void f() { if () const int i = 0; } Diagnostic(ErrorCode.WRN_UnreferencedLocalFunction, "f").WithArguments("f").WithLocation(2, 6), // (2,16): error CS1525: Invalid expression term ')' // void f() { if () const int i = 0; } Diagnostic(ErrorCode.ERR_InvalidExprTerm, ")").WithArguments(")").WithLocation(2, 16), // (2,18): error CS1023: Embedded statement cannot be a declaration or labeled statement // void f() { if () const int i = 0; } Diagnostic(ErrorCode.ERR_BadEmbeddedStmt, "const int i = 0;").WithLocation(2, 18), // (2,28): warning CS0219: The variable 'i' is assigned but its value is never used // void f() { if () const int i = 0; } Diagnostic(ErrorCode.WRN_UnreferencedVarAssg, "i").WithArguments("i").WithLocation(2, 28) ); } [Fact, WorkItem(1098605, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/1098605")] public static void Bug1098605_01() { var source = @" class C { static void Main(string[] args) { const string x1 = (string)(object)null; const string y1 = (string)(object)""y""; const string x2 = (object)null; const string y2 = (object)""y""; const object x3 = (string)null; const object y3 = ""y""; switch (args[0]) { case (string)(object)null: break; case (string)(object)""b"": break; case (object)null: break; case (object)""b"": break; } System.Console.WriteLine("""", x1, x2, x3, y1, y2, y3); } } "; CreateCompilation(source).VerifyDiagnostics( // (7,27): error CS0133: The expression being assigned to 'y1' must be constant // const string y1 = (string)(object)"y"; Diagnostic(ErrorCode.ERR_NotConstantExpression, @"(string)(object)""y""").WithArguments("y1").WithLocation(7, 27), // (9,27): error CS0266: Cannot implicitly convert type 'object' to 'string'. An explicit conversion exists (are you missing a cast?) // const string x2 = (object)null; Diagnostic(ErrorCode.ERR_NoImplicitConvCast, "(object)null").WithArguments("object", "string").WithLocation(9, 27), // (10,27): error CS0266: Cannot implicitly convert type 'object' to 'string'. An explicit conversion exists (are you missing a cast?) // const string y2 = (object)"y"; Diagnostic(ErrorCode.ERR_NoImplicitConvCast, @"(object)""y""").WithArguments("object", "string").WithLocation(10, 27), // (13,27): error CS0134: 'y3' is of type 'object'. A const field of a reference type other than string can only be initialized with null. // const object y3 = "y"; Diagnostic(ErrorCode.ERR_NotNullConstRefField, @"""y""").WithArguments("y3", "object").WithLocation(13, 27), // (19,18): error CS9135: A constant value of type 'string' is expected // case (string)(object)"b": Diagnostic(ErrorCode.ERR_ConstantValueOfTypeExpected, @"(string)(object)""b""").WithArguments("string").WithLocation(19, 18), // (21,18): error CS0266: Cannot implicitly convert type 'object' to 'string'. An explicit conversion exists (are you missing a cast?) // case (object)null: Diagnostic(ErrorCode.ERR_NoImplicitConvCast, "(object)null").WithArguments("object", "string").WithLocation(21, 18), // (23,18): error CS0266: Cannot implicitly convert type 'object' to 'string'. An explicit conversion exists (are you missing a cast?) // case (object)"b": Diagnostic(ErrorCode.ERR_NoImplicitConvCast, @"(object)""b""").WithArguments("object", "string").WithLocation(23, 18), // (23,18): error CS9135: A constant value of type 'string' is expected // case (object)"b": Diagnostic(ErrorCode.ERR_ConstantValueOfTypeExpected, @"(object)""b""").WithArguments("string").WithLocation(23, 18), // (21,13): error CS0152: The switch statement contains multiple cases with the label value 'null' // case (object)null: Diagnostic(ErrorCode.ERR_DuplicateCaseLabel, "case (object)null:").WithArguments("null").WithLocation(21, 13)); } [Fact] [WorkItem(24869, "https://github.com/dotnet/roslyn/issues/24869")] public void TestSelfReferencingViaLambda() { string source = @" using System.Collections.Generic; using System.Linq; class C { static void F(IEnumerable<C> c) { const int F = c.Select(o => new { E = F }); } }"; var comp = CreateCompilationWithMscorlib40(source, references: new[] { LinqAssemblyRef }); comp.VerifyDiagnostics( // (9,9): error CS0029: Cannot implicitly convert type 'System.Collections.Generic.IEnumerable<<anonymous type: int E>>' to 'int' // c.Select(o => new { E = F }); Diagnostic(ErrorCode.ERR_NoImplicitConv, "c.Select(o => new { E = F })").WithArguments("System.Collections.Generic.IEnumerable<<anonymous type: int E>>", "int").WithLocation(9, 9) ); } [Fact] [WorkItem(24869, "https://github.com/dotnet/roslyn/issues/24869")] public void TestSelfReferencingViaLambda2() { string source = @" using System.Collections.Generic; using System.Linq; class C { static void F(IEnumerable<C> c) { const int F = c.Sum(o => F); } }"; var comp = CreateCompilationWithMscorlib40(source, references: new[] { LinqAssemblyRef }); comp.VerifyDiagnostics( // (8,34): error CS0110: The evaluation of the constant value for 'F' involves a circular definition // const int F = c.Sum(o => F); Diagnostic(ErrorCode.ERR_CircConstValue, "F").WithArguments("F").WithLocation(8, 34) ); } // Attempting to call `ConstantValue` on every constituent string component times out the IOperation runner. // Instead, we manually validate just the top level [ConditionalFact(typeof(NoIOperationValidation)), WorkItem(43019, "https://github.com/dotnet/roslyn/issues/43019")] public void TestLargeStringConcatenation() { // When the compiler folds string concatenations using an O(n^2) algorithm, this program cannot be // compiled within ordinary memory bounds. However, when the compiler uses an O(n) algorithm, it can. string source0 = @" class C { static void Main() { string s = ""BEGIN "" + "; string source1 = @" ""END""; System.Console.WriteLine(System.Linq.Enumerable.Sum(s, c => (int)c)); } } "; StringBuilder source = new StringBuilder(); source.Append(source0); const int NumIterations = 5000; for (int i = 0; i < NumIterations; i++) { source.Append(@"""Lorem ipsum dolor sit amet"" + "", consectetur adipiscing elit, sed"" + "" do eiusmod tempor incididunt"" + "" ut labore et dolore magna aliqua. "" +" + "\n"); } source.Append(source1); var comp = CreateCompilation(source.ToString(), options: TestOptions.ReleaseExe); CompileAndVerify(comp, expectedOutput: "58430604"); var tree = comp.SyntaxTrees[0]; var model = comp.GetSemanticModel(tree); var initializer = tree.GetRoot().DescendantNodes().OfType<VariableDeclaratorSyntax>().Single().Initializer.Value; var literalOperation = model.GetOperation(initializer); var stringTextBuilder = new StringBuilder(); stringTextBuilder.Append("BEGIN "); for (int i = 0; i < NumIterations; i++) { stringTextBuilder.Append("Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. "); } stringTextBuilder.Append("END"); Assert.Equal(stringTextBuilder.ToString(), literalOperation.ConstantValue); } [Fact] public void ConstantInterpolatedStringsSimple() { string source = @" class C { void M() { const string S1 = $""Testing""; const string S2 = $""{""Level 5""} {""Number 3""}""; const string S3 = $""{$""{""Spinning Top""}""}""; const string F1 = $""{S1}""; const string F2 = $""{F1} the {S2}""; } }"; var actual = ParseAndGetConstantFoldingSteps(source); var expected = @"$""Testing"" --> Testing $""{""Level 5""} {""Number 3""}"" --> Level 5 Number 3 $""{$""{""Spinning Top""}""}"" --> Spinning Top $""{""Spinning Top""}"" --> Spinning Top $""{S1}"" --> Testing $""{F1} the {S2}"" --> Testing the Level 5 Number 3"; Assert.Equal(expected, actual); } [Fact] public void ConstantRawInterpolatedStringsSimple() { string source = @" class C { void M() { const string S1 = $""""""Testing""""""; const string S2 = $""""""{""Level 5""} {""Number 3""}""""""; const string S3 = $""""""{$""{""Spinning Top""}""}""""""; const string F1 = $""""""{S1}""""""; const string F2 = $""""""{F1} the {S2}""""""; } }"; var actual = ParseAndGetConstantFoldingSteps(source); var expected = @"$""""""Testing"""""" --> Testing $""""""{""Level 5""} {""Number 3""}"""""" --> Level 5 Number 3 $""""""{$""{""Spinning Top""}""}"""""" --> Spinning Top $""{""Spinning Top""}"" --> Spinning Top $""""""{S1}"""""" --> Testing $""""""{F1} the {S2}"""""" --> Testing the Level 5 Number 3"; Assert.Equal(expected, actual); } [Fact] public void ConstantInterpolatedStringsContinued() { string source = @" public class A : System.Attribute { private string name; public A(string name) { this.name = name; } } [A($""ITEM"")] class C { const string S0 = $""Faaaaaaaaaaaaaaaaaaaaaaaaall""; class Namae { public string X { get; } } void M(string S1 = $""Testing"", Namae n = null) { if (n is Namae { X : $""ConstantInterpolatedString""}){ switch(S1){ case $""Level 5"": break; case $""Radio Noise"": goto case $""Level 5""; } } S1 = S0; } }"; var comp = CreateCompilation(source, parseOptions: TestOptions.RegularPreview); comp.VerifyDiagnostics(); } [Fact] public void ConstantRawInterpolatedStringsContinued() { string source = @" public class A : System.Attribute { private string name; public A(string name) { this.name = name; } } [A($""ITEM"")] class C { const string S0 = $""""""Faaaaaaaaaaaaaaaaaaaaaaaaall""""""; class Namae { public string X { get; } } void M(string S1 = $""""""Testing"""""", Namae n = null) { if (n is Namae { X : $""""""ConstantInterpolatedString""""""}){ switch(S1){ case $""""""Level 5"""""": break; case $""""""Radio Noise"""""": goto case $""""""Level 5""""""; } } S1 = S0; } }"; var comp = CreateCompilation(source, parseOptions: TestOptions.RegularPreview); comp.VerifyDiagnostics(); } [Fact] public void ConstantInterpolatedStringsError() { string source = @" class C { void M(string ParamDefault = ""Academy City"") { const string S1 = $""Testing""; const string S2 = $""{""Level 5""} {3}""; const string S3 = $""{$""{""Spinning Top"", 10}""}""; const string S4 = $""{ParamDefault}""; const int I1 = 0; const string F1 = $""{I1}""; const string F2 = $""{I1} the {S1}""; } }"; var comp = CreateCompilation(source, parseOptions: TestOptions.RegularPreview); comp.VerifyDiagnostics( // (7,27): error CS0133: The expression being assigned to 'S2' must be constant // const string S2 = $"{"Level 5"} {3}"; Diagnostic(ErrorCode.ERR_NotConstantExpression, @"$""{""Level 5""} {3}""").WithArguments("S2").WithLocation(7, 27), // (8,27): error CS0133: The expression being assigned to 'S3' must be constant // const string S3 = $"{$"{"Spinning Top", 10}"}"; Diagnostic(ErrorCode.ERR_NotConstantExpression, @"$""{$""{""Spinning Top"", 10}""}""").WithArguments("S3").WithLocation(8, 27), // (9,27): error CS0133: The expression being assigned to 'S4' must be constant // const string S4 = $"{ParamDefault}"; Diagnostic(ErrorCode.ERR_NotConstantExpression, @"$""{ParamDefault}""").WithArguments("S4").WithLocation(9, 27), // (11,27): error CS0133: The expression being assigned to 'F1' must be constant // const string F1 = $"{I1}"; Diagnostic(ErrorCode.ERR_NotConstantExpression, @"$""{I1}""").WithArguments("F1").WithLocation(11, 27), // (12,27): error CS0133: The expression being assigned to 'F2' must be constant // const string F2 = $"{I1} the {S1}"; Diagnostic(ErrorCode.ERR_NotConstantExpression, @"$""{I1} the {S1}""").WithArguments("F2").WithLocation(12, 27)); } [Fact] public void ConstantRawInterpolatedStringsError() { string source = @" class C { void M(string ParamDefault = """"""Academy City"""""") { const string S1 = $""""""Testing""""""; const string S2 = $""""""{""Level 5""} {3}""""""; const string S3 = $""""""{$""{""Spinning Top"", 10}""}""""""; const string S4 = $""""""{ParamDefault}""""""; const int I1 = 0; const string F1 = $""""""{I1}""""""; const string F2 = $""""""{I1} the {S1}""""""; } }"; var comp = CreateCompilation(source, parseOptions: TestOptions.RegularPreview); comp.VerifyDiagnostics( // (7,27): error CS0133: The expression being assigned to 'S2' must be constant // const string S2 = $"""{"Level 5"} {3}"""; Diagnostic(ErrorCode.ERR_NotConstantExpression, @"$""""""{""Level 5""} {3}""""""").WithArguments("S2").WithLocation(7, 27), // (8,27): error CS0133: The expression being assigned to 'S3' must be constant // const string S3 = $"""{$"{"Spinning Top", 10}"}"""; Diagnostic(ErrorCode.ERR_NotConstantExpression, @"$""""""{$""{""Spinning Top"", 10}""}""""""").WithArguments("S3").WithLocation(8, 27), // (9,27): error CS0133: The expression being assigned to 'S4' must be constant // const string S4 = $"""{ParamDefault}"""; Diagnostic(ErrorCode.ERR_NotConstantExpression, @"$""""""{ParamDefault}""""""").WithArguments("S4").WithLocation(9, 27), // (11,27): error CS0133: The expression being assigned to 'F1' must be constant // const string F1 = $"""{I1}"""; Diagnostic(ErrorCode.ERR_NotConstantExpression, @"$""""""{I1}""""""").WithArguments("F1").WithLocation(11, 27), // (12,27): error CS0133: The expression being assigned to 'F2' must be constant // const string F2 = $"""{I1} the {S1}"""; Diagnostic(ErrorCode.ERR_NotConstantExpression, @"$""""""{I1} the {S1}""""""").WithArguments("F2").WithLocation(12, 27)); } [Fact] public void ConstantInterpolatedStringsHybrid() { string source = @" class C { void M() { const string S1 = $""Number "" + ""3""; const string S2 = $""{""Level 5""} "" + S1; const string F1 = $""{S1}""; } }"; var actual = ParseAndGetConstantFoldingSteps(source); var expected = @"$""Number "" + ""3"" --> Number 3 $""Number "" --> Number $""{""Level 5""} "" + S1 --> Level 5 Number 3 $""{""Level 5""} "" --> Level 5 $""{S1}"" --> Number 3"; Assert.Equal(expected, actual); } [Fact] public void ConstantRawInterpolatedStringsHybrid() { string source = @" class C { void M() { const string S1 = $""""""Number """""" + ""3""; const string S2 = $""""""{""Level 5""} """""" + S1; const string F1 = $""""""{S1}""""""; } }"; var actual = ParseAndGetConstantFoldingSteps(source); var expected = @"$""""""Number """""" + ""3"" --> Number 3 $""""""Number """""" --> Number $""""""{""Level 5""} """""" + S1 --> Level 5 Number 3 $""""""{""Level 5""} """""" --> Level 5 $""""""{S1}"""""" --> Number 3"; Assert.Equal(expected, actual); } [Fact] public void ConstantInterpolatedStringsHybridError() { string source = @" class C { void M() { string NC1 = ""Teleporter""; const string S1 = ""The"" + $""Number {3}"" + ""Level 5""; const string S2 = $""Level 4 "" + NC1; const string F1 = $""{S1}""; } }"; var comp = CreateCompilation(source, parseOptions: TestOptions.RegularPreview); comp.VerifyDiagnostics( // (8,27): error CS0133: The expression being assigned to 'S1' must be constant // const string S1 = "The" + $"Number {3}" + "Level 5"; Diagnostic(ErrorCode.ERR_NotConstantExpression, @"""The"" + $""Number {3}"" + ""Level 5""").WithArguments("S1").WithLocation(8, 27), // (9,27): error CS0133: The expression being assigned to 'S2' must be constant // const string S2 = $"Level 4 " + NC1; Diagnostic(ErrorCode.ERR_NotConstantExpression, @"$""Level 4 "" + NC1").WithArguments("S2").WithLocation(9, 27), // (10,27): error CS0133: The expression being assigned to 'F1' must be constant // const string F1 = $"{S1}"; Diagnostic(ErrorCode.ERR_NotConstantExpression, @"$""{S1}""").WithArguments("F1").WithLocation(10, 27)); } [Fact] public void ConstantRawInterpolatedStringsHybridError() { string source = @" class C { void M() { string NC1 = """"""Teleporter""""""; const string S1 = ""The"" + $""""""Number {3}"""""" + ""Level 5""; const string S2 = $""""""Level 4 """""" + NC1; const string F1 = $""""""{S1}""""""; } }"; var comp = CreateCompilation(source, parseOptions: TestOptions.RegularPreview); comp.VerifyDiagnostics( // (8,27): error CS0133: The expression being assigned to 'S1' must be constant // const string S1 = "The" + $"""Number {3}""" + "Level 5"; Diagnostic(ErrorCode.ERR_NotConstantExpression, @"""The"" + $""""""Number {3}"""""" + ""Level 5""").WithArguments("S1").WithLocation(8, 27), // (9,27): error CS0133: The expression being assigned to 'S2' must be constant // const string S2 = $"""Level 4 """ + NC1; Diagnostic(ErrorCode.ERR_NotConstantExpression, @"$""""""Level 4 """""" + NC1").WithArguments("S2").WithLocation(9, 27), // (10,27): error CS0133: The expression being assigned to 'F1' must be constant // const string F1 = $"""{S1}"""; Diagnostic(ErrorCode.ERR_NotConstantExpression, @"$""""""{S1}""""""").WithArguments("F1").WithLocation(10, 27)); } [Fact] public void ConstantInterpolatedStringsVersionError() { string source = @" public class A : System.Attribute { private string name; public A(string name) { this.name = name; } } [A($""ITEM"")] class C { const string S0 = $""Post""; class Namae { public string X { get; } } #pragma warning disable CS0219 // unused locals void M1() { const string S1 = $""Testing""; const string S2 = $""{""Level 5""} {""Number 3""}""; const string S3 = $""{$""{""Spinning Top""}""}""; const string S4 = $""Hybrid"" + ""Testing"" + ""123""; const string S5 = ""Hybrid"" + ""Testing"" + $""321""; const string F1 = $""{S1}""; const string F2 = F1 + $"" the {S2}""; string VS = ""Change""; const string S6 = $""Failed to {VS}""; } void M2(string S1 = $""Testing"", object O = null, Namae N = null) { switch(S1){ case $""Level 5"": break; } if (N is Namae { X : $""ConstantInterpolatedString""}){ switch(O){ case $""Number 3"": break; case $""Radio Noise"": goto case $""Number 3""; } } } }"; var comp = CreateCompilation(source, parseOptions: TestOptions.Regular10); comp.VerifyDiagnostics( // (32,27): error CS0133: The expression being assigned to 'S6' must be constant // const string S6 = $"Failed to {VS}"; Diagnostic(ErrorCode.ERR_NotConstantExpression, @"$""Failed to {VS}""").WithArguments("S6").WithLocation(34, 27)); comp = CreateCompilation(source, parseOptions: TestOptions.Regular9); comp.VerifyDiagnostics( // (12,4): error CS8773: Feature 'constant interpolated strings' is not available in C# 9.0. Please use language version 10.0 or greater. // [A($"ITEM")] Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion9, @"$""ITEM""").WithArguments("constant interpolated strings", "10.0").WithLocation(12, 4), // (15,23): error CS8773: Feature 'constant interpolated strings' is not available in C# 9.0. Please use language version 10.0 or greater. // const string S0 = $"Post"; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion9, @"$""Post""").WithArguments("constant interpolated strings", "10.0").WithLocation(15, 23), // (25,27): error CS8773: Feature 'constant interpolated strings' is not available in C# 9.0. Please use language version 10.0 or greater. // const string S1 = $"Testing"; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion9, @"$""Testing""").WithArguments("constant interpolated strings", "10.0").WithLocation(25, 27), // (26,27): error CS8773: Feature 'constant interpolated strings' is not available in C# 9.0. Please use language version 10.0 or greater. // const string S2 = $"{"Level 5"} {"Number 3"}"; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion9, @"$""{""Level 5""} {""Number 3""}""").WithArguments("constant interpolated strings", "10.0").WithLocation(26, 27), // (27,27): error CS8773: Feature 'constant interpolated strings' is not available in C# 9.0. Please use language version 10.0 or greater. // const string S3 = $"{$"{"Spinning Top"}"}"; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion9, @"$""{$""{""Spinning Top""}""}""").WithArguments("constant interpolated strings", "10.0").WithLocation(27, 27), // (28,27): error CS8773: Feature 'constant interpolated strings' is not available in C# 9.0. Please use language version 10.0 or greater. // const string S4 = $"Hybrid" + "Testing" + "123"; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion9, @"$""Hybrid""").WithArguments("constant interpolated strings", "10.0").WithLocation(28, 27), // (29,50): error CS8773: Feature 'constant interpolated strings' is not available in C# 9.0. Please use language version 10.0 or greater. // const string S5 = "Hybrid" + "Testing" + $"321"; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion9, @"$""321""").WithArguments("constant interpolated strings", "10.0").WithLocation(29, 50), // (30,27): error CS8773: Feature 'constant interpolated strings' is not available in C# 9.0. Please use language version 10.0 or greater. // const string F1 = $"{S1}"; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion9, @"$""{S1}""").WithArguments("constant interpolated strings", "10.0").WithLocation(30, 27), // (31,32): error CS8773: Feature 'constant interpolated strings' is not available in C# 9.0. Please use language version 10.0 or greater. // const string F2 = F1 + $" the {S2}"; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion9, @"$"" the {S2}""").WithArguments("constant interpolated strings", "10.0").WithLocation(31, 32), // (34,27): error CS8773: Feature 'constant interpolated strings' is not available in C# 9.0. Please use language version 10.0 or greater. // const string S6 = $"Failed to {VS}"; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion9, @"$""Failed to {VS}""").WithArguments("constant interpolated strings", "10.0").WithLocation(34, 27), // (34,27): error CS0133: The expression being assigned to 'S6' must be constant // const string S6 = $"Failed to {VS}"; Diagnostic(ErrorCode.ERR_NotConstantExpression, @"$""Failed to {VS}""").WithArguments("S6").WithLocation(34, 27), // (37,25): error CS8773: Feature 'constant interpolated strings' is not available in C# 9.0. Please use language version 10.0 or greater. // void M2(string S1 = $"Testing", object O = null, Namae N = null) Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion9, @"$""Testing""").WithArguments("constant interpolated strings", "10.0").WithLocation(37, 25), // (40,18): error CS8773: Feature 'constant interpolated strings' is not available in C# 9.0. Please use language version 10.0 or greater. // case $"Level 5": Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion9, @"$""Level 5""").WithArguments("constant interpolated strings", "10.0").WithLocation(40, 18), // (44,30): error CS8773: Feature 'constant interpolated strings' is not available in C# 9.0. Please use language version 10.0 or greater. // if (N is Namae { X : $"ConstantInterpolatedString"}){ Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion9, @"$""ConstantInterpolatedString""").WithArguments("constant interpolated strings", "10.0").WithLocation(44, 30), // (46,22): error CS8773: Feature 'constant interpolated strings' is not available in C# 9.0. Please use language version 10.0 or greater. // case $"Number 3": Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion9, @"$""Number 3""").WithArguments("constant interpolated strings", "10.0").WithLocation(46, 22), // (48,22): error CS8773: Feature 'constant interpolated strings' is not available in C# 9.0. Please use language version 10.0 or greater. // case $"Radio Noise": Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion9, @"$""Radio Noise""").WithArguments("constant interpolated strings", "10.0").WithLocation(48, 22), // (49,31): error CS8773: Feature 'constant interpolated strings' is not available in C# 9.0. Please use language version 10.0 or greater. // goto case $"Number 3"; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion9, @"$""Number 3""").WithArguments("constant interpolated strings", "10.0").WithLocation(49, 31)); } [Fact] public void EmptyConstInterpolatedString() { CompileAndVerify(@" public class C { public const string s = $""""; static void Main() { System.Console.WriteLine(s); } } ", parseOptions: TestOptions.RegularPreview, expectedOutput: "", symbolValidator: module => { Assert.Equal(string.Empty, module.GlobalNamespace.GetTypeMember("C").GetField("s").ConstantValue); }); } [Fact] public void EmptyConstRawInterpolatedString() { CompileAndVerify(@" public class C { public const string s = $"""""" """"""; static void Main() { System.Console.WriteLine(s); } } ", parseOptions: TestOptions.RegularPreview, expectedOutput: "", symbolValidator: module => { Assert.Equal(string.Empty, module.GlobalNamespace.GetTypeMember("C").GetField("s").ConstantValue); }); } [Fact] public void ConstantValueFormatting() { ConstantValue charConstant = ConstantValue.Create('c'), byteConst = ConstantValue.Create(0x4), sbyteConst = ConstantValue.Create(unchecked((sbyte)byte.MaxValue)), shortConst = ConstantValue.Create(unchecked((short)ushort.MaxValue)), ushortConst = ConstantValue.Create(ushort.MaxValue), int32Const = ConstantValue.Create(unchecked((int)uint.MaxValue)), uint32Const = ConstantValue.Create(uint.MaxValue), nintConst = ConstantValue.CreateNativeInt(unchecked((int)uint.MaxValue)), nuintConst = ConstantValue.CreateNativeUInt(uint.MaxValue), int64Const = ConstantValue.Create(unchecked((long)ulong.MaxValue)), uint64Const = ConstantValue.Create(ulong.MaxValue), decimalConst = ConstantValue.Create(1m / 3m), floatConst = ConstantValue.Create(Math.Round(1f / 3f, 5)), doubleConst = ConstantValue.Create(Math.Round((double)1 / 3, 8)), stringConst = ConstantValue.Create("abcdefghijklmnopqrstuvwxyz"), dateTimeConst = ConstantValue.Create(DateTime.MaxValue), boolConst = ConstantValue.Create(true), badConst = ConstantValue.Bad, nullConst = ConstantValue.Null; Assert.Equal("c", charConstant.ToString(null, CultureInfo.InvariantCulture)); Assert.Equal("4", byteConst.ToString(null, CultureInfo.InvariantCulture)); Assert.Equal("-1", sbyteConst.ToString(null, CultureInfo.InvariantCulture)); Assert.Equal("-1", shortConst.ToString(null, CultureInfo.InvariantCulture)); Assert.Equal("65535", ushortConst.ToString(null, CultureInfo.InvariantCulture)); Assert.Equal("-1", int32Const.ToString(null, CultureInfo.InvariantCulture)); Assert.Equal("4294967295", uint32Const.ToString(null, CultureInfo.InvariantCulture)); Assert.Equal("-1", nintConst.ToString(null, CultureInfo.InvariantCulture)); Assert.Equal("4294967295", nuintConst.ToString(null, CultureInfo.InvariantCulture)); Assert.Equal("-1", int64Const.ToString(null, CultureInfo.InvariantCulture)); Assert.Equal("18446744073709551615", uint64Const.ToString(null, CultureInfo.InvariantCulture)); Assert.Equal("0.3333333333333333333333333333", decimalConst.ToString(null, CultureInfo.InvariantCulture)); Assert.Equal("0.33333", floatConst.ToString(null, CultureInfo.InvariantCulture)); Assert.Equal("0.33333333", doubleConst.ToString(null, CultureInfo.InvariantCulture)); Assert.Equal(@"""abcdefghijklmnopqrstuvwxyz""", stringConst.ToString(null, CultureInfo.InvariantCulture)); Assert.Equal(@"""abcdefghijklmnopqrstuvwxyz""", stringConst.ToString("26", CultureInfo.InvariantCulture)); Assert.Equal(@"""abcdefghijklmnopqrstuvwxyz""", stringConst.ToString("27", CultureInfo.InvariantCulture)); Assert.Equal(@"""...""", stringConst.ToString("-1", CultureInfo.InvariantCulture)); Assert.Equal(@"""...""", stringConst.ToString("2", CultureInfo.InvariantCulture)); Assert.Equal(@"""...""", stringConst.ToString("3", CultureInfo.InvariantCulture)); Assert.Equal(@"""abcd...""", stringConst.ToString("7", CultureInfo.InvariantCulture)); Assert.Equal("12/31/9999 23:59:59", dateTimeConst.ToString(null, CultureInfo.InvariantCulture)); Assert.Equal("True", boolConst.ToString(null, CultureInfo.InvariantCulture)); Assert.Equal("bad", badConst.ToString(null, CultureInfo.InvariantCulture)); Assert.Equal("null", nullConst.ToString(null, CultureInfo.InvariantCulture)); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/75353")] public void ConstLocalCircularity_SwitchOperand() { var source = """ const string x = x switch { _ => "" }; """; var comp = CreateCompilation(source); comp.VerifyDiagnostics( // (1,18): error CS0110: The evaluation of the constant value for 'x' involves a circular definition // const string x = x switch { _ => "" }; Diagnostic(ErrorCode.ERR_CircConstValue, "x").WithArguments("x").WithLocation(1, 18), // (1,18): error CS0133: The expression being assigned to 'x' must be constant // const string x = x switch { _ => "" }; Diagnostic(ErrorCode.ERR_NotConstantExpression, @"x switch { _ => """" }").WithArguments("x").WithLocation(1, 18)); var tree = comp.SyntaxTrees.Single(); var model = comp.GetSemanticModel(tree); var xDeclarator = GetSyntax<VariableDeclaratorSyntax>(tree, """x = x switch { _ => "" }"""); Assert.Equal("System.String x", model.GetDeclaredSymbol(xDeclarator).ToTestDisplayString(includeNonNullable: false)); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/75353")] public void ConstLocalCircularity_SwitchOperand_Var() { var source = """ const var x = x switch { _ => "" }; """; var comp = CreateCompilation(source); comp.VerifyDiagnostics( // (1,7): error CS0822: Implicitly-typed variables cannot be constant // const var x = x switch { _ => "" }; Diagnostic(ErrorCode.ERR_ImplicitlyTypedVariableCannotBeConst, @"var x = x switch { _ => """" }").WithLocation(1, 7), // (1,15): error CS0841: Cannot use local variable 'x' before it is declared // const var x = x switch { _ => "" }; Diagnostic(ErrorCode.ERR_VariableUsedBeforeDeclaration, "x").WithArguments("x").WithLocation(1, 15)); var tree = comp.SyntaxTrees.Single(); var model = comp.GetSemanticModel(tree); var xDeclarator = GetSyntax<VariableDeclaratorSyntax>(tree, """x = x switch { _ => "" }"""); Assert.Equal("System.String x", model.GetDeclaredSymbol(xDeclarator).ToTestDisplayString(includeNonNullable: false)); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/75353")] public void ConstLocalCircularity_SwitchArm() { var source = """ const string x = 42 switch { _ => x }; """; var comp = CreateCompilation(source); comp.VerifyDiagnostics( // (1,18): error CS0133: The expression being assigned to 'x' must be constant // const string x = 42 switch { _ => x }; Diagnostic(ErrorCode.ERR_NotConstantExpression, "42 switch { _ => x }").WithArguments("x").WithLocation(1, 18), // (1,35): error CS0110: The evaluation of the constant value for 'x' involves a circular definition // const string x = 42 switch { _ => x }; Diagnostic(ErrorCode.ERR_CircConstValue, "x").WithArguments("x").WithLocation(1, 35)); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/75353")] public void ConstLocalCircularity_Nameof() { var source = """ const string x = nameof(x); """; var comp = CreateCompilation(source); comp.VerifyDiagnostics(); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/75353")] public void ConstLocalCircularity_Checked() { var source = """ const int x = checked(x); """; var comp = CreateCompilation(source); comp.VerifyDiagnostics( // (1,23): error CS0110: The evaluation of the constant value for 'x' involves a circular definition // const int x = checked(x); Diagnostic(ErrorCode.ERR_CircConstValue, "x").WithArguments("x").WithLocation(1, 23)); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/75353")] public void ConstLocalCircularity_Checked_TwoConstDeclarations() { var source = """ const int x = checked(y); const int y = checked(x); """; var comp = CreateCompilation(source); comp.VerifyDiagnostics( // (1,23): error CS0841: Cannot use local variable 'y' before it is declared // const int x = checked(y); Diagnostic(ErrorCode.ERR_VariableUsedBeforeDeclaration, "y").WithArguments("y").WithLocation(1, 23)); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/75353")] public void ConstLocalCircularity_Checked_TwoConstDeclarators() { var source = """ const int x = y switch { _ => 42 }, y = x switch { _ => 42 }; """; var comp = CreateCompilation(source); comp.VerifyDiagnostics( // (1,15): error CS0841: Cannot use local variable 'y' before it is declared // const int x = y switch { _ => 42 }, y = x switch { _ => 42 }; Diagnostic(ErrorCode.ERR_VariableUsedBeforeDeclaration, "y").WithArguments("y").WithLocation(1, 15), // (1,41): error CS0133: The expression being assigned to 'y' must be constant // const int x = y switch { _ => 42 }, y = x switch { _ => 42 }; Diagnostic(ErrorCode.ERR_NotConstantExpression, "x switch { _ => 42 }").WithArguments("y").WithLocation(1, 41)); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/75353")] public void ConstLocalCircularity_CollectionExpression_IEnumerable_Struct() { var source = """ const S x = [x]; public struct S : System.Collections.Generic.IEnumerable<S> { public S() => throw null; public void Add(S s) => throw null; System.Collections.Generic.IEnumerator<S> System.Collections.Generic.IEnumerable<S>.GetEnumerator() => throw null; System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() => throw null; } """; var comp = CreateCompilation(source); comp.VerifyDiagnostics( // (1,7): error CS0283: The type 'S' cannot be declared const // const S x = [x]; Diagnostic(ErrorCode.ERR_BadConstType, "S").WithArguments("S").WithLocation(1, 7)); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/75353")] public void ConstLocalCircularity_CollectionExpression_IEnumerable_Class() { var source = """ const S x = [x]; public class S : System.Collections.Generic.IEnumerable<S> { public S() => throw null; public void Add(S s) => throw null; System.Collections.Generic.IEnumerator<S> System.Collections.Generic.IEnumerable<S>.GetEnumerator() => throw null; System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() => throw null; } """; var comp = CreateCompilation(source); comp.VerifyDiagnostics( // (1,13): error CS0133: The expression being assigned to 'x' must be constant // const S x = [x]; Diagnostic(ErrorCode.ERR_NotConstantExpression, "[x]").WithArguments("x").WithLocation(1, 13), // (1,14): error CS0110: The evaluation of the constant value for 'x' involves a circular definition // const S x = [x]; Diagnostic(ErrorCode.ERR_CircConstValue, "x").WithArguments("x").WithLocation(1, 14)); } } internal sealed class BoundTreeSequencer : BoundTreeWalkerWithStackGuard { public static IEnumerable<BoundNode> GetNodes(BoundNode root) { var s = new BoundTreeSequencer(); s.Visit(root); foreach (var node in s._list) yield return node; } private readonly List<BoundNode> _list; private BoundTreeSequencer() { _list = new List<BoundNode>(); } public override BoundNode Visit(BoundNode node) { if (node != null) //e.g. static method invocations have null receivers { _list.Add(node); } return base.Visit(node); } protected override bool ConvertInsufficientExecutionStackExceptionToCancelledByStackGuardException() { return false; } } }