|
// 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;
}
}
}
|