|
// 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.Collections.Immutable;
using System.Linq;
using System.Text;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.CSharp.Test.Utilities;
using Microsoft.CodeAnalysis.FlowAnalysis;
using Microsoft.CodeAnalysis.Operations;
using Roslyn.Test.Utilities;
using Xunit;
namespace Microsoft.CodeAnalysis.CSharp.UnitTests.CodeGen
{
public class CodeGenOperators : CSharpTestBase
{
[Fact]
public void TestIsNullPattern()
{
var source = @"
using System;
class C
{
public static void Main()
{
var c = new C();
Console.Write(c is null);
}
}
";
// Release
var compilation = CompileAndVerify(source, expectedOutput: "False", options: TestOptions.ReleaseExe);
compilation.VerifyIL("C.Main", @"{
// Code size 14 (0xe)
.maxstack 2
IL_0000: newobj ""C..ctor()""
IL_0005: ldnull
IL_0006: ceq
IL_0008: call ""void System.Console.Write(bool)""
IL_000d: ret
}");
// Debug
compilation = CompileAndVerify(source, expectedOutput: "False", options: TestOptions.DebugExe);
compilation.VerifyIL("C.Main", @"{
// Code size 18 (0x12)
.maxstack 2
.locals init (C V_0) //c
IL_0000: nop
IL_0001: newobj ""C..ctor()""
IL_0006: stloc.0
IL_0007: ldloc.0
IL_0008: ldnull
IL_0009: ceq
IL_000b: call ""void System.Console.Write(bool)""
IL_0010: nop
IL_0011: ret
}");
}
[Fact]
public void TestIsNullPatternGenericParam()
{
var source = @"
using System;
class C
{
public static void M<T>(T o)
{
Console.Write(o is null);
if (o is null)
{
Console.Write(""Branch taken"");
}
}
public static void Main()
{
M(new object());
}
}
";
var compilation = CompileAndVerify(source, expectedOutput: "False", options: TestOptions.ReleaseExe);
compilation.VerifyIL("C.M<T>(T)", @"{
// Code size 33 (0x21)
.maxstack 2
IL_0000: ldarg.0
IL_0001: box ""T""
IL_0006: ldnull
IL_0007: ceq
IL_0009: call ""void System.Console.Write(bool)""
IL_000e: ldarg.0
IL_000f: box ""T""
IL_0014: brtrue.s IL_0020
IL_0016: ldstr ""Branch taken""
IL_001b: call ""void System.Console.Write(string)""
IL_0020: ret
}");
// Debug
compilation = CompileAndVerify(source, expectedOutput: "False", options: TestOptions.DebugExe);
compilation.VerifyIL("C.M<T>(T)", @"{
// Code size 43 (0x2b)
.maxstack 2
.locals init (bool V_0)
IL_0000: nop
IL_0001: ldarg.0
IL_0002: box ""T""
IL_0007: ldnull
IL_0008: ceq
IL_000a: call ""void System.Console.Write(bool)""
IL_000f: nop
IL_0010: ldarg.0
IL_0011: box ""T""
IL_0016: ldnull
IL_0017: ceq
IL_0019: stloc.0
IL_001a: ldloc.0
IL_001b: brfalse.s IL_002a
IL_001d: nop
IL_001e: ldstr ""Branch taken""
IL_0023: call ""void System.Console.Write(string)""
IL_0028: nop
IL_0029: nop
IL_002a: ret
}");
}
[Fact]
public void TestIsNullPatternGenericParamClass()
{
var source = @"
using System;
class C
{
public static void M<T>(T o) where T: class
{
Console.Write(o is null);
if (o is null) {
Console.Write("" Branch taken"");
}
}
public static void Main()
{
M(new object());
}
}
";
// Release
var compilation = CompileAndVerify(source, expectedOutput: "False", options: TestOptions.ReleaseExe);
compilation.VerifyIL("C.M<T>(T)", @"{
// Code size 33 (0x21)
.maxstack 2
IL_0000: ldarg.0
IL_0001: box ""T""
IL_0006: ldnull
IL_0007: ceq
IL_0009: call ""void System.Console.Write(bool)""
IL_000e: ldarg.0
IL_000f: box ""T""
IL_0014: brtrue.s IL_0020
IL_0016: ldstr "" Branch taken""
IL_001b: call ""void System.Console.Write(string)""
IL_0020: ret
}");
// Debug
compilation = CompileAndVerify(source, expectedOutput: "False", options: TestOptions.DebugExe);
compilation.VerifyIL("C.M<T>(T)", @"{
// Code size 43 (0x2b)
.maxstack 2
.locals init (bool V_0)
IL_0000: nop
IL_0001: ldarg.0
IL_0002: box ""T""
IL_0007: ldnull
IL_0008: ceq
IL_000a: call ""void System.Console.Write(bool)""
IL_000f: nop
IL_0010: ldarg.0
IL_0011: box ""T""
IL_0016: ldnull
IL_0017: ceq
IL_0019: stloc.0
IL_001a: ldloc.0
IL_001b: brfalse.s IL_002a
IL_001d: nop
IL_001e: ldstr "" Branch taken""
IL_0023: call ""void System.Console.Write(string)""
IL_0028: nop
IL_0029: nop
IL_002a: ret
}");
}
[Fact]
public void TestIsNullPatternNullable()
{
var source = @"
using System;
class C
{
public static void M(Nullable<int> obj)
{
Console.Write(obj is null);
if (obj is null) {
Console.Write("" Branch taken"");
} else {
Console.Write("" Branch not taken"");
}
}
public static void Main()
{
M(5);
Console.Write(""-"");
M(null);
}
}
";
// Release
var compilation = CompileAndVerify(source, expectedOutput: "False Branch not taken-True Branch taken", options: TestOptions.ReleaseExe);
compilation.VerifyIL("C.M", @"{
// Code size 46 (0x2e)
.maxstack 2
IL_0000: ldarga.s V_0
IL_0002: call ""bool int?.HasValue.get""
IL_0007: ldc.i4.0
IL_0008: ceq
IL_000a: call ""void System.Console.Write(bool)""
IL_000f: ldarga.s V_0
IL_0011: call ""bool int?.HasValue.get""
IL_0016: brtrue.s IL_0023
IL_0018: ldstr "" Branch taken""
IL_001d: call ""void System.Console.Write(string)""
IL_0022: ret
IL_0023: ldstr "" Branch not taken""
IL_0028: call ""void System.Console.Write(string)""
IL_002d: ret
}");
// Debug
compilation = CompileAndVerify(source, expectedOutput: "False Branch not taken-True Branch taken", options: TestOptions.DebugExe);
compilation.VerifyIL("C.M", @"{
// Code size 60 (0x3c)
.maxstack 2
.locals init (bool V_0)
IL_0000: nop
IL_0001: ldarga.s V_0
IL_0003: call ""bool int?.HasValue.get""
IL_0008: ldc.i4.0
IL_0009: ceq
IL_000b: call ""void System.Console.Write(bool)""
IL_0010: nop
IL_0011: ldarga.s V_0
IL_0013: call ""bool int?.HasValue.get""
IL_0018: ldc.i4.0
IL_0019: ceq
IL_001b: stloc.0
IL_001c: ldloc.0
IL_001d: brfalse.s IL_002e
IL_001f: nop
IL_0020: ldstr "" Branch taken""
IL_0025: call ""void System.Console.Write(string)""
IL_002a: nop
IL_002b: nop
IL_002c: br.s IL_003b
IL_002e: nop
IL_002f: ldstr "" Branch not taken""
IL_0034: call ""void System.Console.Write(string)""
IL_0039: nop
IL_003a: nop
IL_003b: ret
}");
}
[Fact]
public void TestIsNullPatternObjectLiteral()
{
var source = @"
using System;
class C
{
public static void Main()
{
Console.Write(((object)null) is null);
if (((object) null) is null) {
Console.Write("" Branch taken"");
}
}
}
";
// Release
var compilation = CompileAndVerify(source, expectedOutput: "True Branch taken", options: TestOptions.ReleaseExe);
compilation.VerifyIL("C.Main", @"{
// Code size 17 (0x11)
.maxstack 1
IL_0000: ldc.i4.1
IL_0001: call ""void System.Console.Write(bool)""
IL_0006: ldstr "" Branch taken""
IL_000b: call ""void System.Console.Write(string)""
IL_0010: ret
}");
// Debug
compilation = CompileAndVerify(source, expectedOutput: "True Branch taken", options: TestOptions.DebugExe);
compilation.VerifyIL("C.Main", @"
{
// Code size 27 (0x1b)
.maxstack 1
.locals init (bool V_0)
IL_0000: nop
IL_0001: ldc.i4.1
IL_0002: call ""void System.Console.Write(bool)""
IL_0007: nop
IL_0008: ldc.i4.1
IL_0009: stloc.0
IL_000a: ldloc.0
IL_000b: brfalse.s IL_001a
IL_000d: nop
IL_000e: ldstr "" Branch taken""
IL_0013: call ""void System.Console.Write(string)""
IL_0018: nop
IL_0019: nop
IL_001a: ret
}");
}
[Fact]
public void TestIsNullPatternStringConstant()
{
var source = @"
using System;
class C
{
const String nullString = null;
public static void Main()
{
Console.Write(((string)null) is nullString);
if (((string) null) is nullString) {
Console.Write("" Branch taken"");
}
}
}
";
// Release
var compilation = CompileAndVerify(source, expectedOutput: "True Branch taken", options: TestOptions.ReleaseExe);
compilation.VerifyIL("C.Main", @"{
// Code size 17 (0x11)
.maxstack 1
IL_0000: ldc.i4.1
IL_0001: call ""void System.Console.Write(bool)""
IL_0006: ldstr "" Branch taken""
IL_000b: call ""void System.Console.Write(string)""
IL_0010: ret
}");
// Debug
compilation = CompileAndVerify(source, expectedOutput: "True Branch taken", options: TestOptions.DebugExe);
compilation.VerifyIL("C.Main", @"{
// Code size 27 (0x1b)
.maxstack 1
.locals init (bool V_0)
IL_0000: nop
IL_0001: ldc.i4.1
IL_0002: call ""void System.Console.Write(bool)""
IL_0007: nop
IL_0008: ldc.i4.1
IL_0009: stloc.0
IL_000a: ldloc.0
IL_000b: brfalse.s IL_001a
IL_000d: nop
IL_000e: ldstr "" Branch taken""
IL_0013: call ""void System.Console.Write(string)""
IL_0018: nop
IL_0019: nop
IL_001a: ret
}");
}
[Fact]
public void TestDelegateAndStringOperators()
{
var source = @"
using System;
class C
{
delegate void D();
public static void M123()
{
Console.WriteLine(123);
}
public static void M456()
{
Console.WriteLine(456);
}
public static void Main()
{
D d123 = M123;
D d456 = M456;
D d123456 = d123 + d456;
d123456();
Console.WriteLine(d123456 - d123 == d456);
Console.WriteLine(d123456 - d123 == d123);
string s123 = 123.ToString();
object s456 = 456.ToString();
Console.WriteLine(s123 + s456);
Console.WriteLine(s123 + s456 + s123);
}
}
";
string expectedOutput =
@"123
456
True
False
123456
123456123
";
var compilation = CompileAndVerify(source, expectedOutput: expectedOutput);
}
[Fact]
public void TestCompoundAssignmentOperators()
{
var source = @"
using System;
class C
{
delegate void D();
public static void M123()
{
Console.Write(123);
}
public static void M456()
{
Console.Write(456);
}
static C c;
static C GetC() { Console.Write(""GetC""); return c; }
byte f;
public static void Main()
{
C.c = new C();
D d123 = M123;
D d456 = M456;
D d = null;
d += d123;
d();
d += d456;
d();
d -= d123;
d();
Console.WriteLine();
short b = 100;
b -= 70;
Console.Write(b);
b *= 2;
Console.Write(b);
Console.WriteLine();
string s = string.Empty;
s += 789.ToString();
Console.Write(s);
s += 987.ToString();
Console.Write(s);
Console.WriteLine();
GetC().f += 100;
Console.Write(C.c.f);
Console.WriteLine();
int[] arr = { 10 };
arr[0] += 1;
Console.Write(arr[0]);
Console.WriteLine();
}
}
";
string expectedOutput =
@"123123456456
3060
789789987
GetC100
11";
var compilation = CompileAndVerify(source, expectedOutput: expectedOutput);
}
// TODO: Add VerifyIL for is and as Codegen tests
[Fact]
public void TestIsOperator()
{
var source = @"
namespace TestIsOperator
{
public interface MyInter { }
public class TestType : MyInter { }
public class AnotherType { }
public class MyBase { }
public class MyDerived : MyBase { }
public class C
{
static void Main()
{
string myStr = ""goo"";
object o = myStr;
bool b = o is string;
int myInt = 3;
b = myInt is int;
TestType tt = null;
o = tt;
b = o is TestType;
tt = new TestType();
o = tt;
b = o is AnotherType;
b = o is MyInter;
MyInter mi = new TestType();
o = mi;
b = o is MyInter;
MyBase mb = new MyBase();
o = mb;
b = o is MyDerived;
MyDerived md = new MyDerived();
o = md;
b = o is MyBase;
b = null is MyBase;
}
}
}
";
var compilation = CompileAndVerify(source);
}
// TODO: Add VerifyIL for is and as Codegen tests
[Fact]
public void TestIsOperatorGeneric()
{
var source = @"
namespace TestIsOperatorGeneric
{
public class C
{
public static void Main() { }
public static void M<T, U, W>(T t, U u, W w)
where T : class
where U : class
where W : class
{
bool test = t is int;
test = u is object;
test = t is U;
test = t is T;
test = u is U;
test = u is T;
test = w is int;
test = w is object;
test = w is U;
test = u is W;
test = t is W;
test = w is W;
}
}
}
";
var compilation = CompileAndVerify(source);
}
[Fact]
public void CS0184WRN_IsAlwaysFalse()
{
var text = @"
class MyClass
{
public static int Main()
{
int i = 0;
bool b = i is string; // CS0184
System.Console.WriteLine(b);
return 0;
}
}
";
var comp = CompileAndVerify(text, expectedOutput: "False");
comp.VerifyDiagnostics(
// (7,18): warning CS0184: The given expression is never of the provided ('string') type
// bool b = i is string; // CS0184
Diagnostic(ErrorCode.WRN_IsAlwaysFalse, "i is string").WithArguments("string"));
comp.VerifyIL("MyClass.Main", @"
{
// Code size 8 (0x8)
.maxstack 1
IL_0000: ldc.i4.0
IL_0001: call ""void System.Console.WriteLine(bool)""
IL_0006: ldc.i4.0
IL_0007: ret
}");
}
[WorkItem(542466, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/542466")]
[Fact]
public void CS0184WRN_IsAlwaysFalse_Enum()
{
var text = @"
class IsTest
{
static void Main()
{
var b = 1 is color;
System.Console.WriteLine(b);
}
}
enum @color
{ }
";
var comp = CompileAndVerify(text, expectedOutput: "False");
comp.VerifyDiagnostics(
// (6,17): warning CS0184: The given expression is never of the provided ('color') type
// var b = 1 is color;
Diagnostic(ErrorCode.WRN_IsAlwaysFalse, "1 is color").WithArguments("color"));
comp.VerifyIL("IsTest.Main", @"
{
// Code size 7 (0x7)
.maxstack 1
IL_0000: ldc.i4.0
IL_0001: call ""void System.Console.WriteLine(bool)""
IL_0006: ret
}");
}
[WorkItem(542466, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/542466")]
[Fact]
public void CS0184WRN_IsAlwaysFalse_ExplicitEnumeration()
{
var text = @"
class IsTest
{
static void Main()
{
var b = default(color) is int;
System.Console.WriteLine(b);
}
}
enum @color
{ }
";
var comp = CompileAndVerify(text, expectedOutput: "False");
comp.VerifyDiagnostics(
// (6,17): warning CS0184: The given expression is never of the provided ('int') type
// var b = default(color) is int;
Diagnostic(ErrorCode.WRN_IsAlwaysFalse, "default(color) is int").WithArguments("int"));
comp.VerifyIL("IsTest.Main", @"
{
// Code size 7 (0x7)
.maxstack 1
IL_0000: ldc.i4.0
IL_0001: call ""void System.Console.WriteLine(bool)""
IL_0006: ret
}");
}
[WorkItem(542466, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/542466")]
[Fact]
public void CS0184WRN_IsAlwaysFalse_ImplicitNumeric()
{
var text = @"
class IsTest
{
static void Main()
{
var b = 1 is double;
System.Console.WriteLine(b);
}
}
";
var comp = CompileAndVerify(text, expectedOutput: "False");
comp.VerifyDiagnostics(
// (6,17): warning CS0184: The given expression is never of the provided ('double') type
// var b = 1 is double;
Diagnostic(ErrorCode.WRN_IsAlwaysFalse, "1 is double").WithArguments("double"));
comp.VerifyIL("IsTest.Main", @"
{
// Code size 7 (0x7)
.maxstack 1
IL_0000: ldc.i4.0
IL_0001: call ""void System.Console.WriteLine(bool)""
IL_0006: ret
}");
}
[Fact, WorkItem(542466, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/542466")]
public void CS0184WRN_IsAlwaysFalse_ExplicitNumeric()
{
var text = @"
class IsTest
{
static void Main()
{
var b = 1.0 is int;
System.Console.WriteLine(b);
b = 1.0 is float;
System.Console.WriteLine(b);
b = 1 is byte;
System.Console.WriteLine(b);
}
}
";
var comp = CompileAndVerify(text, expectedOutput: @"False
False
False");
comp.VerifyDiagnostics(
// (6,17): warning CS0184: The given expression is never of the provided ('int') type
// var b = 1.0 is int;
Diagnostic(ErrorCode.WRN_IsAlwaysFalse, "1.0 is int").WithArguments("int"),
// (7,13): warning CS0184: The given expression is never of the provided ('float') type
// b = 1.0 is float;
Diagnostic(ErrorCode.WRN_IsAlwaysFalse, "1.0 is float").WithArguments("float"),
// (8,13): warning CS0184: The given expression is never of the provided ('byte') type
// b = 1 is byte;
Diagnostic(ErrorCode.WRN_IsAlwaysFalse, "1 is byte").WithArguments("byte"));
comp.VerifyIL("IsTest.Main", @"
{
// Code size 19 (0x13)
.maxstack 1
IL_0000: ldc.i4.0
IL_0001: call ""void System.Console.WriteLine(bool)""
IL_0006: ldc.i4.0
IL_0007: call ""void System.Console.WriteLine(bool)""
IL_000c: ldc.i4.0
IL_000d: call ""void System.Console.WriteLine(bool)""
IL_0012: ret
}");
}
[Fact, WorkItem(546371, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/546371")]
public void CS0184WRN_IsAlwaysFalse_NumericIsNullable()
{
#region src
var text = @"using System;
public class Test
{
const char v0 = default(char);
public static sbyte v1 = default(sbyte);
internal static byte v2 = 0;// default(byte);
protected static short v3 = 0; // default(short);
private static ushort v4 = default(ushort);
static void Main()
{
const int v5 = 0; // default(int);
uint v6 = 0; // default(uint);
long v7 = 0; // default(long);
const ulong v8 = default(ulong);
float v9 = default(float);
// char
if (v0 is ushort?)
Console.Write(0);
else
Console.Write(1);
// sbyte & byte
if (v1 is short? || v2 is short?)
Console.Write(0);
else
Console.Write(2);
// short & ushort
if (v3 is int? || v4 is int?)
Console.Write(0);
else
Console.Write(3);
// int & uint
if (v5 is long? || v6 is long?)
Console.Write(0);
else
Console.Write(4);
// long & ulong
if (v7 is float? || v8 is float?)
Console.Write(0);
else
Console.Write(5);
// float
if (v9 is int?)
Console.Write(0);
else
Console.Write(6);
}
}
";
#endregion
var comp = CompileAndVerify(text, expectedOutput: @"123456");
comp.VerifyDiagnostics(
Diagnostic(ErrorCode.WRN_IsAlwaysFalse, "v0 is ushort?").WithArguments("ushort?"),
Diagnostic(ErrorCode.WRN_IsAlwaysFalse, "v1 is short?").WithArguments("short?"),
Diagnostic(ErrorCode.WRN_IsAlwaysFalse, "v2 is short?").WithArguments("short?"),
Diagnostic(ErrorCode.WRN_IsAlwaysFalse, "v3 is int?").WithArguments("int?"),
Diagnostic(ErrorCode.WRN_IsAlwaysFalse, "v4 is int?").WithArguments("int?"),
Diagnostic(ErrorCode.WRN_IsAlwaysFalse, "v5 is long?").WithArguments("long?"),
Diagnostic(ErrorCode.WRN_IsAlwaysFalse, "v6 is long?").WithArguments("long?"),
Diagnostic(ErrorCode.WRN_IsAlwaysFalse, "v7 is float?").WithArguments("float?"),
Diagnostic(ErrorCode.WRN_IsAlwaysFalse, "v8 is float?").WithArguments("float?"),
Diagnostic(ErrorCode.WRN_IsAlwaysFalse, "v9 is int?").WithArguments("int?")
);
comp.VerifyIL("Test.Main", @"
{
// Code size 61 (0x3d)
.maxstack 1
IL_0000: ldc.i4.1
IL_0001: call ""void System.Console.Write(int)""
IL_0006: ldsfld ""sbyte Test.v1""
IL_000b: pop
IL_000c: ldsfld ""byte Test.v2""
IL_0011: pop
IL_0012: ldc.i4.2
IL_0013: call ""void System.Console.Write(int)""
IL_0018: ldsfld ""short Test.v3""
IL_001d: pop
IL_001e: ldsfld ""ushort Test.v4""
IL_0023: pop
IL_0024: ldc.i4.3
IL_0025: call ""void System.Console.Write(int)""
IL_002a: ldc.i4.4
IL_002b: call ""void System.Console.Write(int)""
IL_0030: ldc.i4.5
IL_0031: call ""void System.Console.Write(int)""
IL_0036: ldc.i4.6
IL_0037: call ""void System.Console.Write(int)""
IL_003c: ret
}
");
}
// TODO: Add VerifyIL for is and as Codegen tests
[Fact]
public void TestAsOperator()
{
var source = @"
namespace TestAsOperator
{
public interface MyInter {}
public class TestType : MyInter {}
public class AnotherType {}
public class MyBase {}
public class MyDerived : MyBase { }
public class C
{
static void Main()
{
string myStr = ""goo"";
object o = myStr;
object b = o as string;
TestType tt = null;
o = tt;
b = o as TestType;
tt = new TestType();
o = tt;
b = o as AnotherType;
b = o as MyInter;
MyInter mi = new TestType();
o = mi;
b = o as MyInter;
MyBase mb = new MyBase();
o = mb;
b = o as MyDerived;
MyDerived md = new MyDerived();
o = md;
b = o as MyBase;
b = null as MyBase;
}
}
}
";
var compilation = CompileAndVerify(source);
}
[Fact]
public void TestAsOperatorGeneric()
{
var source = @"
public class TestAsOperatorGeneric
{
public static void Main() { }
public static void M<T, U, W>(T t, U u, W w)
where T : class
where U : class
where W : class
{
object test2 = u as object;
System.Console.WriteLine(test2);
U test3 = t as U;
System.Console.WriteLine(test3);
T test4 = t as T;
System.Console.WriteLine(test4);
U test5 = u as U;
System.Console.WriteLine(test5);
T test12 = u as T;
System.Console.WriteLine(test12);
object test7 = w as object;
System.Console.WriteLine(test7);
U test8 = w as U;
System.Console.WriteLine(test8);
W test9 = u as W;
System.Console.WriteLine(test9);
W test10 = t as W;
System.Console.WriteLine(test10);
W test11 = w as W;
System.Console.WriteLine(test11);
}
}
";
var compilation = CompileAndVerify(source);
compilation.VerifyIL("TestAsOperatorGeneric.M<T, U, W>(T, U, W)",
@"{
// Code size 186 (0xba)
.maxstack 1
IL_0000: ldarg.1
IL_0001: box ""U""
IL_0006: call ""void System.Console.WriteLine(object)""
IL_000b: ldarg.0
IL_000c: box ""T""
IL_0011: isinst ""U""
IL_0016: unbox.any ""U""
IL_001b: box ""U""
IL_0020: call ""void System.Console.WriteLine(object)""
IL_0025: ldarg.0
IL_0026: box ""T""
IL_002b: call ""void System.Console.WriteLine(object)""
IL_0030: ldarg.1
IL_0031: box ""U""
IL_0036: call ""void System.Console.WriteLine(object)""
IL_003b: ldarg.1
IL_003c: box ""U""
IL_0041: isinst ""T""
IL_0046: unbox.any ""T""
IL_004b: box ""T""
IL_0050: call ""void System.Console.WriteLine(object)""
IL_0055: ldarg.2
IL_0056: box ""W""
IL_005b: call ""void System.Console.WriteLine(object)""
IL_0060: ldarg.2
IL_0061: box ""W""
IL_0066: isinst ""U""
IL_006b: unbox.any ""U""
IL_0070: box ""U""
IL_0075: call ""void System.Console.WriteLine(object)""
IL_007a: ldarg.1
IL_007b: box ""U""
IL_0080: isinst ""W""
IL_0085: unbox.any ""W""
IL_008a: box ""W""
IL_008f: call ""void System.Console.WriteLine(object)""
IL_0094: ldarg.0
IL_0095: box ""T""
IL_009a: isinst ""W""
IL_009f: unbox.any ""W""
IL_00a4: box ""W""
IL_00a9: call ""void System.Console.WriteLine(object)""
IL_00ae: ldarg.2
IL_00af: box ""W""
IL_00b4: call ""void System.Console.WriteLine(object)""
IL_00b9: ret
}");
}
[Fact, WorkItem(754408, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/754408")]
public void TestNullCoalesce_DynamicAndObject()
{
var source = @"using System;
public class A {}
public class C
{
public static dynamic Get()
{
object a = new A();
dynamic b = new A();
return a ?? b;
}
public static void Main()
{
var c = Get();
}
}";
var comp = CompileAndVerify(source,
references: new[] { CSharpRef },
expectedOutput: string.Empty);
comp.VerifyIL("C.Get",
@"{
// Code size 17 (0x11)
.maxstack 2
.locals init (object V_0) //b
IL_0000: newobj ""A..ctor()""
IL_0005: newobj ""A..ctor()""
IL_000a: stloc.0
IL_000b: dup
IL_000c: brtrue.s IL_0010
IL_000e: pop
IL_000f: ldloc.0
IL_0010: ret
}");
}
[Fact]
public void TestNullCoalesce_Implicit_b_To_a_nullable()
{
var source = @"
using System;
// a ?? b
public class E : D { }
public class D { }
public class C
{
public static int Main()
{
Nullable_a_Implicit_b_to_a0_null_a('a');
Nullable_a_Implicit_b_to_a0_constant_non_null_a('a');
Nullable_a_Implicit_b_to_a0_not_null_a('a', 10);
return 0;
}
public static int Nullable_a_Implicit_b_to_a0_null_a(char ch)
{
char b = ch;
int? a = null;
int z = a ?? b;
return z;
}
public static int Nullable_a_Implicit_b_to_a0_constant_non_null_a(char ch)
{
char b = ch;
int? a = 10;
int z = a ?? b;
return z;
}
public static int Nullable_a_Implicit_b_to_a0_not_null_a(char ch, int? i)
{
char b = ch;
int? a = i;
int z = a ?? b;
return z;
}
}
";
var compilation = CompileAndVerify(source, expectedOutput: string.Empty);
compilation.VerifyIL("C.Nullable_a_Implicit_b_to_a0_null_a", @"
{
// Code size 31 (0x1f)
.maxstack 1
.locals init (char V_0, //b
int? V_1)
IL_0000: ldarg.0
IL_0001: stloc.0
IL_0002: ldloca.s V_1
IL_0004: initobj ""int?""
IL_000a: ldloc.1
IL_000b: stloc.1
IL_000c: ldloca.s V_1
IL_000e: call ""bool int?.HasValue.get""
IL_0013: brtrue.s IL_0017
IL_0015: ldloc.0
IL_0016: ret
IL_0017: ldloca.s V_1
IL_0019: call ""int int?.GetValueOrDefault()""
IL_001e: ret
}
");
compilation.VerifyIL("C.Nullable_a_Implicit_b_to_a0_constant_non_null_a", @"
{
// Code size 29 (0x1d)
.maxstack 1
.locals init (char V_0, //b
int? V_1)
IL_0000: ldarg.0
IL_0001: stloc.0
IL_0002: ldc.i4.s 10
IL_0004: newobj ""int?..ctor(int)""
IL_0009: stloc.1
IL_000a: ldloca.s V_1
IL_000c: call ""bool int?.HasValue.get""
IL_0011: brtrue.s IL_0015
IL_0013: ldloc.0
IL_0014: ret
IL_0015: ldloca.s V_1
IL_0017: call ""int int?.GetValueOrDefault()""
IL_001c: ret
}");
compilation.VerifyIL("C.Nullable_a_Implicit_b_to_a0_not_null_a", @"
{
// Code size 23 (0x17)
.maxstack 1
.locals init (char V_0, //b
int? V_1)
IL_0000: ldarg.0
IL_0001: stloc.0
IL_0002: ldarg.1
IL_0003: stloc.1
IL_0004: ldloca.s V_1
IL_0006: call ""bool int?.HasValue.get""
IL_000b: brtrue.s IL_000f
IL_000d: ldloc.0
IL_000e: ret
IL_000f: ldloca.s V_1
IL_0011: call ""int int?.GetValueOrDefault()""
IL_0016: ret
}
");
}
[Fact]
public void TestNullCoalesce_Nullable_a_Implicit_b_to_a0()
{
var source = @"
using System;
// a ?? b
public class E : D { }
public class D { }
public class C
{
public static int Main()
{
Nullable_a_Implicit_b_to_a0_null_a('a');
Nullable_a_Implicit_b_to_a0_constant_non_null_a('a');
Nullable_a_Implicit_b_to_a0_not_null_a('a', 10);
Nullable_a_Implicit_b_to_a_null_a('a');
Nullable_a_Implicit_b_to_a_constant_non_null_a('a');
Nullable_a_Implicit_b_to_a_not_null_a('a', 10);
return 0;
}
public static int Nullable_a_Implicit_b_to_a0_null_a(char ch)
{
char b = ch;
int? a = null;
int z = a ?? b;
return z;
}
public static int Nullable_a_Implicit_b_to_a0_constant_non_null_a(char ch)
{
char b = ch;
int? a = 10;
int z = a ?? b;
return z;
}
public static int Nullable_a_Implicit_b_to_a0_not_null_a(char ch, int? i)
{
char b = ch;
int? a = i;
int z = a ?? b;
return z;
}
public static int? Nullable_a_Implicit_b_to_a_null_a(char? ch)
{
char? b = ch;
int? a = null;
int? z = a ?? b;
return z;
}
public static int? Nullable_a_Implicit_b_to_a_constant_non_null_a(char? ch)
{
char? b = ch;
int? a = 10;
int? z = a ?? b;
return z;
}
public static int? Nullable_a_Implicit_b_to_a_not_null_a(char ch, int? i)
{
char? b = ch;
int? a = i;
int? z = a ?? b;
return z;
}
}
";
var compilation = CompileAndVerify(source, expectedOutput: string.Empty);
compilation.VerifyIL("C.Nullable_a_Implicit_b_to_a0_null_a", @"
{
// Code size 31 (0x1f)
.maxstack 1
.locals init (char V_0, //b
int? V_1)
IL_0000: ldarg.0
IL_0001: stloc.0
IL_0002: ldloca.s V_1
IL_0004: initobj ""int?""
IL_000a: ldloc.1
IL_000b: stloc.1
IL_000c: ldloca.s V_1
IL_000e: call ""bool int?.HasValue.get""
IL_0013: brtrue.s IL_0017
IL_0015: ldloc.0
IL_0016: ret
IL_0017: ldloca.s V_1
IL_0019: call ""int int?.GetValueOrDefault()""
IL_001e: ret
}");
}
[Fact]
public void TestNullCoalesce_Nullable_a_ImplicitReference_a_to_b()
{
var source = @"
using System;
// a ?? b
public class E : D { }
public class D { }
public class C
{
public static int Main()
{
ImplicitReference_a_to_b_null_a_nullable(10);
ImplicitReference_a_to_b_constant_nonnull_a_nullable(10);
ImplicitReference_a_to_b_not_null_a_nullable(10, 'a');
Null_Literal_a('a');
return 0;
}
public static int? ImplicitReference_a_to_b_null_a_nullable(int? c)
{
int? b = c;
char? a = null;
int? z = a ?? b;
return z;
}
public static int? ImplicitReference_a_to_b_constant_nonnull_a_nullable(int? c)
{
int? b = c;
char? a = 'a';
int? z = a ?? b;
return z;
}
public static int? ImplicitReference_a_to_b_not_null_a_nullable(int? c, char? d)
{
int? b = c;
char? a = d;
int? z = a ?? b;
return z;
}
public static char? Null_Literal_a(char? ch)
{
char? b = ch;
char? z = null ?? b;
return z;
}
}
";
var compilation = CompileAndVerify(source, expectedOutput: string.Empty);
compilation.VerifyIL("C.ImplicitReference_a_to_b_null_a_nullable", @"
{
// Code size 36 (0x24)
.maxstack 1
.locals init (int? V_0, //b
char? V_1)
IL_0000: ldarg.0
IL_0001: stloc.0
IL_0002: ldloca.s V_1
IL_0004: initobj ""char?""
IL_000a: ldloc.1
IL_000b: stloc.1
IL_000c: ldloca.s V_1
IL_000e: call ""bool char?.HasValue.get""
IL_0013: brtrue.s IL_0017
IL_0015: ldloc.0
IL_0016: ret
IL_0017: ldloca.s V_1
IL_0019: call ""char char?.GetValueOrDefault()""
IL_001e: newobj ""int?..ctor(int)""
IL_0023: ret
}");
compilation.VerifyIL("C.Null_Literal_a", @"
{
// Code size 2 (0x2)
.maxstack 1
IL_0000: ldarg.0
IL_0001: ret
}");
}
[Fact]
public void TestNullCoalesce_ImplicitReference_a_to_b()
{
var source = @"
using System;
// a ?? b
public class E : D { }
public class D { }
public class C
{
public static int Main()
{
ImplicitReference_a_to_b_null_a();
ImplicitReference_a_to_b_not_null_a();
return 0;
}
public static D ImplicitReference_a_to_b_null_a()
{
D b = new D();
E a = null;
D z = a ?? b;
return z;
}
public static D ImplicitReference_a_to_b_not_null_a()
{
D b = new D();
E a = new E();
D z = a ?? b;
return z;
}
}
";
var compilation = CompileAndVerify(source, expectedOutput: string.Empty);
compilation.VerifyIL("C.ImplicitReference_a_to_b_null_a", @"
{
// Code size 13 (0xd)
.maxstack 2
.locals init (D V_0) //b
IL_0000: newobj ""D..ctor()""
IL_0005: stloc.0
IL_0006: ldnull
IL_0007: dup
IL_0008: brtrue.s IL_000c
IL_000a: pop
IL_000b: ldloc.0
IL_000c: ret
}
");
compilation.VerifyIL("C.ImplicitReference_a_to_b_not_null_a",
@"
{
// Code size 17 (0x11)
.maxstack 2
.locals init (D V_0) //b
IL_0000: newobj ""D..ctor()""
IL_0005: stloc.0
IL_0006: newobj ""E..ctor()""
IL_000b: dup
IL_000c: brtrue.s IL_0010
IL_000e: pop
IL_000f: ldloc.0
IL_0010: ret
}
");
}
[Fact]
public void TestNullCoalesce_TypeParameter()
{
var source = @"
using System;
static class Program
{
static void Main()
{
Goo(default, 1000);
Goo(1, 1000);
Goo(default, ""String parameter 1"");
Goo(""String parameter 2"", ""Should not print"");
Goo((int?)null, 4);
Goo((int?)5, 1000);
Goo2(6, 1000);
Goo2<int?, object>(null, 7);
Goo2<int?, object>(8, 1000);
Goo2<int?, int?>(9, 1000);
Goo2<int?, int?>(null, 10);
}
static void Goo<T>(T x1, T x2)
{
Console.WriteLine(x1 ?? x2);
}
static void Goo2<T1, T2>(T1 t1, T2 t2, dynamic d = null) where T1 : T2
{
// Verifying no type errors
Console.WriteLine(t1 ?? t2);
dynamic d2 = t1 ?? d;
}
}
";
var comp = CompileAndVerify(source, expectedOutput: @"
0
1
String parameter 1
String parameter 2
4
5
6
7
8
9
10
");
comp.VerifyIL("Program.Goo<T>(T, T)", expectedIL: @"
{
// Code size 25 (0x19)
.maxstack 1
.locals init (T V_0)
IL_0000: ldarg.0
IL_0001: stloc.0
IL_0002: ldloc.0
IL_0003: box ""T""
IL_0008: brtrue.s IL_000d
IL_000a: ldarg.1
IL_000b: br.s IL_000e
IL_000d: ldloc.0
IL_000e: box ""T""
IL_0013: call ""void System.Console.WriteLine(object)""
IL_0018: ret
}
");
comp.VerifyIL("Program.Goo2<T1, T2>(T1, T2, dynamic)", expectedIL: @"
{
// Code size 44 (0x2c)
.maxstack 1
.locals init (T1 V_0)
IL_0000: ldarg.0
IL_0001: stloc.0
IL_0002: ldloc.0
IL_0003: box ""T1""
IL_0008: brtrue.s IL_000d
IL_000a: ldarg.1
IL_000b: br.s IL_0018
IL_000d: ldloc.0
IL_000e: box ""T1""
IL_0013: unbox.any ""T2""
IL_0018: box ""T2""
IL_001d: call ""void System.Console.WriteLine(object)""
IL_0022: ldarg.0
IL_0023: stloc.0
IL_0024: ldloc.0
IL_0025: box ""T1""
IL_002a: pop
IL_002b: ret
}
");
}
[Fact]
public void TestNullCoalesce_TypeParameter_DefaultLHS()
{
var source = @"
using System;
static class Program
{
static void Main()
{
Goo(10);
Goo(""String parameter"");
Goo((int?)3);
}
static void Goo<T>(T x)
{
Console.WriteLine(default(T) ?? x);
}
}
";
var comp = CompileAndVerify(source, expectedOutput: @"
0
String parameter
3
");
comp.VerifyIL("Program.Goo<T>(T)", expectedIL: @"
{
// Code size 31 (0x1f)
.maxstack 1
.locals init (T V_0)
IL_0000: ldloca.s V_0
IL_0002: initobj ""T""
IL_0008: ldloc.0
IL_0009: box ""T""
IL_000e: brtrue.s IL_0013
IL_0010: ldarg.0
IL_0011: br.s IL_0014
IL_0013: ldloc.0
IL_0014: box ""T""
IL_0019: call ""void System.Console.WriteLine(object)""
IL_001e: ret
}
");
}
[Fact]
public void TestNullCoalesce_NoDuplicateCallsToGoo()
{
var source = @"
// a ?? b
public class Test
{
static void Main()
{
object o = Goo() ?? Bar();
}
static object Goo()
{
System.Console.Write(""Goo"");
return new object();
}
static object Bar()
{
System.Console.Write(""Bar"");
return new object();
}
}
";
var compilation = CompileAndVerify(source, expectedOutput: "Goo");
compilation.VerifyIL("Test.Main", @"
{
// Code size 14 (0xe)
.maxstack 1
IL_0000: call ""object Test.Goo()""
IL_0005: brtrue.s IL_000d
IL_0007: call ""object Test.Bar()""
IL_000c: pop
IL_000d: ret
}
");
}
[WorkItem(541232, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/541232")]
[Fact]
public void TestNullCoalesce_MethodGroups()
{
var source =
@"class C
{
static void M()
{
System.Action a = null;
a = a ?? M;
a = M ?? a;
}
}";
CreateCompilation(source).VerifyDiagnostics(
// (7,13): error CS0019: Operator '??' cannot be applied to operands of type 'method group' and 'System.Action'
Diagnostic(ErrorCode.ERR_BadBinaryOps, "M ?? a").WithArguments("??", "method group", "System.Action").WithLocation(7, 13));
}
/// <summary>
/// From orcas bug #42645. PEVerify fails.
/// </summary>
[Fact]
public void TestNullCoalesce_InterfaceRegression1()
{
var source = @"
using System.Collections.Generic;
using System.Security;
[assembly: SecurityTransparent()]
public class Test
{
static void Main()
{
int[] a = new int[] { };
List<int> b = new List<int>();
IEnumerable<int> c = a ?? (IEnumerable<int>)b;
Goo(c);
}
static void Goo<T>(T x)
{
System.Console.WriteLine(typeof(T));
}
}";
// Note the explicit casts, even though the conversions are
// implicit reference conversions.
var comp = CompileAndVerify(source, expectedOutput: "System.Collections.Generic.IEnumerable`1[System.Int32]");
comp.VerifyDiagnostics();
comp.VerifyIL("Test.Main", @"
{
// Code size 25 (0x19)
.maxstack 2
.locals init (System.Collections.Generic.List<int> V_0, //b
System.Collections.Generic.IEnumerable<int> V_1)
IL_0000: ldc.i4.0
IL_0001: newarr ""int""
IL_0006: newobj ""System.Collections.Generic.List<int>..ctor()""
IL_000b: stloc.0
IL_000c: stloc.1
IL_000d: ldloc.1
IL_000e: dup
IL_000f: brtrue.s IL_0013
IL_0011: pop
IL_0012: ldloc.0
IL_0013: call ""void Test.Goo<System.Collections.Generic.IEnumerable<int>>(System.Collections.Generic.IEnumerable<int>)""
IL_0018: ret
}
");
}
[Fact]
public void TestNullCoalesce_InterfaceRegression1a()
{
var source = @"
using System.Collections.Generic;
public class Test
{
static void Main()
{
int[] a = new int[] { };
IEnumerable<int> b = new List<int>();
IEnumerable<int> c = b ?? a;
Goo(c);
}
static void Goo<T>(T x)
{
System.Console.WriteLine(typeof(T));
}
}";
var comp = CompileAndVerify(source, expectedOutput: "System.Collections.Generic.IEnumerable`1[System.Int32]");
comp.VerifyDiagnostics();
comp.VerifyIL("Test.Main", @"
{
// Code size 25 (0x19)
.maxstack 2
.locals init (int[] V_0, //a
System.Collections.Generic.IEnumerable<int> V_1)
IL_0000: ldc.i4.0
IL_0001: newarr ""int""
IL_0006: stloc.0
IL_0007: newobj ""System.Collections.Generic.List<int>..ctor()""
IL_000c: stloc.1
IL_000d: ldloc.1
IL_000e: dup
IL_000f: brtrue.s IL_0013
IL_0011: pop
IL_0012: ldloc.0
IL_0013: call ""void Test.Goo<System.Collections.Generic.IEnumerable<int>>(System.Collections.Generic.IEnumerable<int>)""
IL_0018: ret
}");
}
[Fact]
public void TestNullCoalesce_InterfaceRegression1b()
{
var source = @"
using System.Collections.Generic;
public class Test
{
static void Main()
{
int[] a = new int[] { };
IEnumerable<int> b;
IEnumerable<int> c = (b = (IEnumerable<int>)new List<int>()) ?? a;
Goo(c);
Goo(b);
}
static void Goo<T>(T x)
{
System.Console.Write(typeof(T));
}
}";
var comp = CompileAndVerify(source, expectedOutput: "System.Collections.Generic.IEnumerable`1[System.Int32]System.Collections.Generic.IEnumerable`1[System.Int32]");
comp.VerifyDiagnostics();
comp.VerifyIL("Test.Main", @"
{
// Code size 31 (0x1f)
.maxstack 3
.locals init (int[] V_0, //a
System.Collections.Generic.IEnumerable<int> V_1)
IL_0000: ldc.i4.0
IL_0001: newarr ""int""
IL_0006: stloc.0
IL_0007: newobj ""System.Collections.Generic.List<int>..ctor()""
IL_000c: dup
IL_000d: stloc.1
IL_000e: ldloc.1
IL_000f: dup
IL_0010: brtrue.s IL_0014
IL_0012: pop
IL_0013: ldloc.0
IL_0014: call ""void Test.Goo<System.Collections.Generic.IEnumerable<int>>(System.Collections.Generic.IEnumerable<int>)""
IL_0019: call ""void Test.Goo<System.Collections.Generic.IEnumerable<int>>(System.Collections.Generic.IEnumerable<int>)""
IL_001e: ret
}");
}
[Fact]
public void TestNullCoalesce_InterfaceRegression1c()
{
var source = @"
using System.Collections.Generic;
public class Test
{
static void Main()
{
int[] a = new int[] { };
IEnumerable<int> b = new List<int>();
Goo(b, b ?? a);
}
static void Goo<T, U>(T x, U y)
{
System.Console.Write(typeof(T));
}
}";
var comp = CompileAndVerify(source, expectedOutput: "System.Collections.Generic.IEnumerable`1[System.Int32]");
comp.VerifyDiagnostics();
comp.VerifyIL("Test.Main", @"
{
// Code size 26 (0x1a)
.maxstack 3
.locals init (int[] V_0, //a
System.Collections.Generic.IEnumerable<int> V_1)
IL_0000: ldc.i4.0
IL_0001: newarr ""int""
IL_0006: stloc.0
IL_0007: newobj ""System.Collections.Generic.List<int>..ctor()""
IL_000c: dup
IL_000d: stloc.1
IL_000e: ldloc.1
IL_000f: dup
IL_0010: brtrue.s IL_0014
IL_0012: pop
IL_0013: ldloc.0
IL_0014: call ""void Test.Goo<System.Collections.Generic.IEnumerable<int>, System.Collections.Generic.IEnumerable<int>>(System.Collections.Generic.IEnumerable<int>, System.Collections.Generic.IEnumerable<int>)""
IL_0019: ret
}
");
}
/// <summary>
/// From whidbey bug #49619. PEVerify fails.
/// </summary>
/// <remarks>
/// Dev10 does not produce verifiable code for this example.
/// </remarks>
[Fact]
public void TestNullCoalesce_InterfaceRegression2()
{
var source = @"
public interface IA { }
public interface IB { int f(); }
public class AB1 : IA, IB { public int f() { return 42; } }
public class AB2 : IA, IB { public int f() { return 1; } }
class MainClass
{
public static void g(AB1 ab1)
{
((IB)ab1 ?? (IB)new AB2()).f();
}
}";
// Note the explicit casts, even though the conversions are
// implicit reference conversions.
var comp = CompileAndVerify(source);
comp.VerifyDiagnostics();
comp.VerifyIL("MainClass.g", @"
{
// Code size 19 (0x13)
.maxstack 2
.locals init (IB V_0)
IL_0000: ldarg.0
IL_0001: stloc.0
IL_0002: ldloc.0
IL_0003: dup
IL_0004: brtrue.s IL_000c
IL_0006: pop
IL_0007: newobj ""AB2..ctor()""
IL_000c: callvirt ""int IB.f()""
IL_0011: pop
IL_0012: ret
}");
}
[Fact, WorkItem(638289, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/638289")]
public void TestNullCoalesce_Nested()
{
var src =
@"interface I { void DoNothing(); }
class A : I { public void DoNothing() {} }
class B : I { public void DoNothing() {} }
class C : I
{
public void DoNothing() {}
static I Tester(A a, B b)
{
I i = a ?? (b ?? (I)new C());
i.DoNothing();
i = a ?? ((I)b ?? new C());
i.DoNothing();
i = ((I)a ?? b) ?? new C();
i.DoNothing();
return i;
}
static void Main()
{
System.Console.Write(Tester(null, null).GetType());
}
}";
var verify = CompileAndVerify(src,
options: TestOptions.DebugExe, expectedOutput: "C");
verify.VerifyIL("C.Tester", @"
{
// Code size 86 (0x56)
.maxstack 2
.locals init (I V_0, //i
I V_1,
I V_2)
IL_0000: nop
IL_0001: ldarg.0
IL_0002: stloc.1
IL_0003: ldloc.1
IL_0004: dup
IL_0005: brtrue.s IL_0014
IL_0007: pop
IL_0008: ldarg.1
IL_0009: stloc.1
IL_000a: ldloc.1
IL_000b: dup
IL_000c: brtrue.s IL_0014
IL_000e: pop
IL_000f: newobj ""C..ctor()""
IL_0014: stloc.0
IL_0015: ldloc.0
IL_0016: callvirt ""void I.DoNothing()""
IL_001b: nop
IL_001c: ldarg.0
IL_001d: stloc.1
IL_001e: ldloc.1
IL_001f: dup
IL_0020: brtrue.s IL_002f
IL_0022: pop
IL_0023: ldarg.1
IL_0024: stloc.1
IL_0025: ldloc.1
IL_0026: dup
IL_0027: brtrue.s IL_002f
IL_0029: pop
IL_002a: newobj ""C..ctor()""
IL_002f: stloc.0
IL_0030: ldloc.0
IL_0031: callvirt ""void I.DoNothing()""
IL_0036: nop
IL_0037: ldarg.0
IL_0038: stloc.1
IL_0039: ldloc.1
IL_003a: dup
IL_003b: brtrue.s IL_003f
IL_003d: pop
IL_003e: ldarg.1
IL_003f: dup
IL_0040: brtrue.s IL_0048
IL_0042: pop
IL_0043: newobj ""C..ctor()""
IL_0048: stloc.0
IL_0049: ldloc.0
IL_004a: callvirt ""void I.DoNothing()""
IL_004f: nop
IL_0050: ldloc.0
IL_0051: stloc.2
IL_0052: br.s IL_0054
IL_0054: ldloc.2
IL_0055: ret
}");
// Optimized
verify = CompileAndVerify(src, expectedOutput: "C");
verify.VerifyIL("C.Tester", @"
{
// Code size 72 (0x48)
.maxstack 2
.locals init (I V_0)
IL_0000: ldarg.0
IL_0001: stloc.0
IL_0002: ldloc.0
IL_0003: dup
IL_0004: brtrue.s IL_0013
IL_0006: pop
IL_0007: ldarg.1
IL_0008: stloc.0
IL_0009: ldloc.0
IL_000a: dup
IL_000b: brtrue.s IL_0013
IL_000d: pop
IL_000e: newobj ""C..ctor()""
IL_0013: callvirt ""void I.DoNothing()""
IL_0018: ldarg.0
IL_0019: stloc.0
IL_001a: ldloc.0
IL_001b: dup
IL_001c: brtrue.s IL_002b
IL_001e: pop
IL_001f: ldarg.1
IL_0020: stloc.0
IL_0021: ldloc.0
IL_0022: dup
IL_0023: brtrue.s IL_002b
IL_0025: pop
IL_0026: newobj ""C..ctor()""
IL_002b: callvirt ""void I.DoNothing()""
IL_0030: ldarg.0
IL_0031: stloc.0
IL_0032: ldloc.0
IL_0033: dup
IL_0034: brtrue.s IL_0038
IL_0036: pop
IL_0037: ldarg.1
IL_0038: dup
IL_0039: brtrue.s IL_0041
IL_003b: pop
IL_003c: newobj ""C..ctor()""
IL_0041: dup
IL_0042: callvirt ""void I.DoNothing()""
IL_0047: ret
}");
}
[Fact]
public void TestNullCoalesce_FuncVariance()
{
var source = @"
using System;
using System.Collections.Generic;
class Program
{
static void Main(string[] args)
{
Func<Exception[]> f1 = null;
Func<IEnumerable<object>> f2 = null;
var oo = f1 ?? f2;
Console.WriteLine(oo);
oo = f2 ?? f1;
Console.WriteLine(oo);
}
}
";
var comp = CompileAndVerify(source);
comp.VerifyDiagnostics();
comp.VerifyIL("Program.Main", @"
{
// Code size 31 (0x1f)
.maxstack 2
.locals init (System.Func<System.Exception[]> V_0, //f1
System.Func<System.Collections.Generic.IEnumerable<object>> V_1, //f2
System.Func<System.Collections.Generic.IEnumerable<object>> V_2)
IL_0000: ldnull
IL_0001: stloc.0
IL_0002: ldnull
IL_0003: stloc.1
IL_0004: ldloc.0
IL_0005: stloc.2
IL_0006: ldloc.2
IL_0007: dup
IL_0008: brtrue.s IL_000c
IL_000a: pop
IL_000b: ldloc.1
IL_000c: call ""void System.Console.WriteLine(object)""
IL_0011: ldloc.1
IL_0012: dup
IL_0013: brtrue.s IL_0019
IL_0015: pop
IL_0016: ldloc.0
IL_0017: stloc.2
IL_0018: ldloc.2
IL_0019: call ""void System.Console.WriteLine(object)""
IL_001e: ret
}
");
}
[Fact]
public void TestNullCoalesce_FuncVariance01()
{
var source = @"
using System;
using System.Collections;
using System.Collections.Generic;
class Program
{
static void Main(string[] args)
{
Func<Exception[]> f1 = null;
Func<IEnumerable<object>> f2 = null;
var oo = (Func<IEnumerable>)f1 ?? (Func<IEnumerable>)f2;
Console.WriteLine(oo);
oo = (Func<IEnumerable>)f2 ?? (Func<IEnumerable>)f1;
Console.WriteLine(oo);
}
}
";
var comp = CompileAndVerify(source);
comp.VerifyDiagnostics();
comp.VerifyIL("Program.Main", @"
{
// Code size 35 (0x23)
.maxstack 2
.locals init (System.Func<System.Exception[]> V_0, //f1
System.Func<System.Collections.Generic.IEnumerable<object>> V_1, //f2
System.Func<System.Collections.IEnumerable> V_2)
IL_0000: ldnull
IL_0001: stloc.0
IL_0002: ldnull
IL_0003: stloc.1
IL_0004: ldloc.0
IL_0005: stloc.2
IL_0006: ldloc.2
IL_0007: dup
IL_0008: brtrue.s IL_000e
IL_000a: pop
IL_000b: ldloc.1
IL_000c: stloc.2
IL_000d: ldloc.2
IL_000e: call ""void System.Console.WriteLine(object)""
IL_0013: ldloc.1
IL_0014: stloc.2
IL_0015: ldloc.2
IL_0016: dup
IL_0017: brtrue.s IL_001d
IL_0019: pop
IL_001a: ldloc.0
IL_001b: stloc.2
IL_001c: ldloc.2
IL_001d: call ""void System.Console.WriteLine(object)""
IL_0022: ret
}
");
}
[Fact]
public void TestNullCoalesce_InterfaceVariance()
{
var source = @"
using System;
using System.Collections.Generic;
class Program
{
interface CoInter<out T>
{
}
static void Main(string[] args)
{
CoInter<Exception[]> f1 = null;
CoInter<IEnumerable<object>> f2 = null;
var oo = f1 ?? f2;
Console.WriteLine(oo);
oo = f2 ?? f1;
Console.WriteLine(oo);
}
}
";
var comp = CompileAndVerify(source);
comp.VerifyDiagnostics();
comp.VerifyIL("Program.Main", @"
{
// Code size 31 (0x1f)
.maxstack 2
.locals init (Program.CoInter<System.Exception[]> V_0, //f1
Program.CoInter<System.Collections.Generic.IEnumerable<object>> V_1, //f2
Program.CoInter<System.Collections.Generic.IEnumerable<object>> V_2)
IL_0000: ldnull
IL_0001: stloc.0
IL_0002: ldnull
IL_0003: stloc.1
IL_0004: ldloc.0
IL_0005: stloc.2
IL_0006: ldloc.2
IL_0007: dup
IL_0008: brtrue.s IL_000c
IL_000a: pop
IL_000b: ldloc.1
IL_000c: call ""void System.Console.WriteLine(object)""
IL_0011: ldloc.1
IL_0012: dup
IL_0013: brtrue.s IL_0019
IL_0015: pop
IL_0016: ldloc.0
IL_0017: stloc.2
IL_0018: ldloc.2
IL_0019: call ""void System.Console.WriteLine(object)""
IL_001e: ret
}
");
}
[Fact]
public void TestNullCoalesce_InterfaceVariance01()
{
var source = @"
using System;
using System.Collections;
using System.Collections.Generic;
class Program
{
interface CoInter<out T>
{
}
static void Main(string[] args)
{
CoInter<Exception[]> f1 = null;
CoInter<IEnumerable<object>> f2 = null;
var oo = (CoInter<IEnumerable>)f1 ?? (CoInter<IEnumerable>)f2;
Console.WriteLine(oo);
oo = (CoInter<IEnumerable>)f2 ?? (CoInter<IEnumerable>)f1;
Console.WriteLine(oo);
}
}
";
var comp = CompileAndVerify(source);
comp.VerifyDiagnostics();
comp.VerifyIL("Program.Main", @"
{
// Code size 35 (0x23)
.maxstack 2
.locals init (Program.CoInter<System.Exception[]> V_0, //f1
Program.CoInter<System.Collections.Generic.IEnumerable<object>> V_1, //f2
Program.CoInter<System.Collections.IEnumerable> V_2)
IL_0000: ldnull
IL_0001: stloc.0
IL_0002: ldnull
IL_0003: stloc.1
IL_0004: ldloc.0
IL_0005: stloc.2
IL_0006: ldloc.2
IL_0007: dup
IL_0008: brtrue.s IL_000e
IL_000a: pop
IL_000b: ldloc.1
IL_000c: stloc.2
IL_000d: ldloc.2
IL_000e: call ""void System.Console.WriteLine(object)""
IL_0013: ldloc.1
IL_0014: stloc.2
IL_0015: ldloc.2
IL_0016: dup
IL_0017: brtrue.s IL_001d
IL_0019: pop
IL_001a: ldloc.0
IL_001b: stloc.2
IL_001c: ldloc.2
IL_001d: call ""void System.Console.WriteLine(object)""
IL_0022: ret
}
");
}
[WorkItem(543074, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/543074")]
[Fact]
public void TestEqualEqualOnNestedStructGuid()
{
var source = @"
using System;
public class Parent
{
public System.Guid Goo(int d = 0, System.Guid g = default(System.Guid)) { return g; }
}
public class Test
{
public static void Main()
{
var x = new Parent().Goo();
var ret = x == default(System.Guid);
Console.Write(ret);
}
}
";
CompileAndVerify(source, expectedOutput: "True");
}
[WorkItem(543092, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/543092")]
[Fact]
public void ShortCircuitConditionalOperator()
{
var source = @"
using System;
using System.Linq;
using System.Collections.Generic;
class X
{
public int selectCount = 0;
public bool Select<T>(Func<int, T> selector)
{
selectCount++;
return true;
}
}
class P
{
static int Main()
{
int errCount = 0;
var src = new X();
// QE is not 'executed'
var b = false && from x in src select x;
if (src.selectCount == 1)
errCount++;
Console.Write(errCount);
return (errCount > 0) ? 1 : 0;
}
}";
CompileAndVerify(source, expectedOutput: "0", options: TestOptions.ReleaseExe.WithWarningLevel(5)).VerifyDiagnostics(
// (3,1): hidden CS8019: Unnecessary using directive.
// using System.Linq;
Diagnostic(ErrorCode.HDN_UnusedUsingDirective, "using System.Linq;").WithLocation(3, 1),
// (4,1): hidden CS8019: Unnecessary using directive.
// using System.Collections.Generic;
Diagnostic(ErrorCode.HDN_UnusedUsingDirective, "using System.Collections.Generic;").WithLocation(4, 1),
// (23,26): warning CS8848: Operator 'from' cannot be used here due to precedence. Use parentheses to disambiguate.
// var b = false && from x in src select x;
Diagnostic(ErrorCode.WRN_PrecedenceInversion, "from x in src").WithArguments("from").WithLocation(23, 26)
);
}
[WorkItem(543109, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/543109")]
[Fact()]
public void ShortCircuitConditionalOperator02()
{
var source = @"
using System;
class P
{
static int Main()
{
int errCount = 0;
var f = false;
var b = f && (0 == errCount++);
Console.Write(errCount);
return (errCount > 0) ? 1 : 0;
}
}";
CompileAndVerify(source, expectedOutput: "0");
}
[WorkItem(543377, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/543377")]
[Fact]
public void DecimalComparison()
{
var source = @"
class Program
{
static void Main()
{
decimal d1 = 1.0201m;
if (d1 == 10201M)
{
}
}
}";
CompileAndVerify(source).
VerifyIL("Program.Main", @"
{
// Code size 31 (0x1f)
.maxstack 5
IL_0000: ldc.i4 0x27d9
IL_0005: ldc.i4.0
IL_0006: ldc.i4.0
IL_0007: ldc.i4.0
IL_0008: ldc.i4.4
IL_0009: newobj ""decimal..ctor(int, int, int, bool, byte)""
IL_000e: ldc.i4 0x27d9
IL_0013: newobj ""decimal..ctor(int)""
IL_0018: call ""bool decimal.op_Equality(decimal, decimal)""
IL_001d: pop
IL_001e: ret
}");
}
[WorkItem(543453, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/543453")]
[Fact]
public void TestIncrementDecrementOperator_Generic()
{
var source = @"
using System;
class BaseType<T> where T : BaseType<T>, new()
{
public static T operator ++(BaseType<T> x)
{
return null;
}
public static implicit operator T(BaseType<T> x)
{
return null;
}
}
class DrivedType : BaseType<DrivedType>
{
public static void Main()
{
BaseType<DrivedType> test = new BaseType<DrivedType>();
DrivedType test2 = test++;
}
}
";
CompileAndVerify(source);
}
[WorkItem(543474, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/543474")]
[Fact]
public void LogicalComplementOperator()
{
var source = @"
class Program
{
static void Main(string[] args)
{
checked
{
var b = false;
if (!b) {System.Console.Write(""1""); }
}
}
}";
CompileAndVerify(source,
expectedOutput: "1");
}
[WorkItem(543500, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/543500")]
[Fact]
public void BuiltInLeftShiftOperators()
{
var source = @"
using System;
class Program
{
static void Main(string[] args)
{
int i = 1;
uint ui = 1;
long l = 1;
ulong ul = 1;
Console.WriteLine(i << 31);
Console.WriteLine(i << 32);
Console.WriteLine(i << 33);
Console.WriteLine(i << -1);
Console.WriteLine();
Console.WriteLine(ui << 31);
Console.WriteLine(ui << 32);
Console.WriteLine(ui << 33);
Console.WriteLine(ui << -1);
Console.WriteLine();
Console.WriteLine(l << 63);
Console.WriteLine(l << 64);
Console.WriteLine(l << 65);
Console.WriteLine(l << -1);
Console.WriteLine();
Console.WriteLine(ul << 63);
Console.WriteLine(ul << 64);
Console.WriteLine(ul << 65);
Console.WriteLine(ul << -1);
Console.WriteLine();
}
}";
CompileAndVerify(source,
expectedOutput: @"
-2147483648
1
2
-2147483648
2147483648
1
2
2147483648
-9223372036854775808
1
2
-9223372036854775808
9223372036854775808
1
2
9223372036854775808
");
}
[WorkItem(543500, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/543500")]
[Fact]
public void BuiltInRightShiftOperators()
{
var source = @"
using System;
class Program
{
static void Main(string[] args)
{
int i = int.MaxValue;
uint ui = uint.MaxValue;
long l = long.MaxValue;
ulong ul = ulong.MaxValue;
Console.WriteLine(i >> 31);
Console.WriteLine(i >> 32);
Console.WriteLine(i >> 33);
Console.WriteLine(i >> -1);
Console.WriteLine();
Console.WriteLine(ui >> 31);
Console.WriteLine(ui >> 32);
Console.WriteLine(ui >> 33);
Console.WriteLine(ui >> -1);
Console.WriteLine();
Console.WriteLine(l >> 63);
Console.WriteLine(l >> 64);
Console.WriteLine(l >> 65);
Console.WriteLine(l >> -1);
Console.WriteLine();
Console.WriteLine(ul >> 63);
Console.WriteLine(ul >> 64);
Console.WriteLine(ul >> 65);
Console.WriteLine(ul >> -1);
Console.WriteLine();
}
}";
CompileAndVerify(source,
expectedOutput: @"
0
2147483647
1073741823
0
1
4294967295
2147483647
1
0
9223372036854775807
4611686018427387903
0
1
18446744073709551615
9223372036854775807
1
");
}
[WorkItem(543500, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/543500")]
[Fact]
public void BuiltInShiftOperators()
{
var source = @"
using System;
class Program
{
static void Main(string[] args)
{
int i = 1;
long l = long.MaxValue;
int amount = 1;
Console.WriteLine(i << 31); // 31
Console.WriteLine(i << 32); // no shift
Console.WriteLine(i << 33); // 1
Console.WriteLine(i << -1); // 31
Console.WriteLine(i >> amount); // & 31
Console.WriteLine();
Console.WriteLine(l >> 63); // 63
Console.WriteLine(l >> 64); // no shift
Console.WriteLine(l >> 65); // 1
Console.WriteLine(l >> -1); // 63
Console.WriteLine(l >> amount); // & 63
Console.WriteLine();
}
}";
var verifier = CompileAndVerify(source,
expectedOutput: @"
-2147483648
1
2
-2147483648
0
0
9223372036854775807
4611686018427387903
0
4611686018427387903
");
verifier.VerifyIL("Program.Main", @"
{
// Code size 109 (0x6d)
.maxstack 3
.locals init (long V_0, //l
int V_1) //amount
IL_0000: ldc.i4.1
IL_0001: ldc.i8 0x7fffffffffffffff
IL_000a: stloc.0
IL_000b: ldc.i4.1
IL_000c: stloc.1
IL_000d: dup
IL_000e: ldc.i4.s 31
IL_0010: shl
IL_0011: call ""void System.Console.WriteLine(int)""
IL_0016: dup
IL_0017: call ""void System.Console.WriteLine(int)""
IL_001c: dup
IL_001d: ldc.i4.1
IL_001e: shl
IL_001f: call ""void System.Console.WriteLine(int)""
IL_0024: dup
IL_0025: ldc.i4.s 31
IL_0027: shl
IL_0028: call ""void System.Console.WriteLine(int)""
IL_002d: ldloc.1
IL_002e: ldc.i4.s 31
IL_0030: and
IL_0031: shr
IL_0032: call ""void System.Console.WriteLine(int)""
IL_0037: call ""void System.Console.WriteLine()""
IL_003c: ldloc.0
IL_003d: ldc.i4.s 63
IL_003f: shr
IL_0040: call ""void System.Console.WriteLine(long)""
IL_0045: ldloc.0
IL_0046: call ""void System.Console.WriteLine(long)""
IL_004b: ldloc.0
IL_004c: ldc.i4.1
IL_004d: shr
IL_004e: call ""void System.Console.WriteLine(long)""
IL_0053: ldloc.0
IL_0054: ldc.i4.s 63
IL_0056: shr
IL_0057: call ""void System.Console.WriteLine(long)""
IL_005c: ldloc.0
IL_005d: ldloc.1
IL_005e: ldc.i4.s 63
IL_0060: and
IL_0061: shr
IL_0062: call ""void System.Console.WriteLine(long)""
IL_0067: call ""void System.Console.WriteLine()""
IL_006c: ret
}
");
}
[Fact, WorkItem(543993, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/543993")]
public void BuiltInShiftOperators01()
{
var source = @"
using System;
public class Test
{
public static void Main()
{
int n = 2;
int v1 = (1 << n) << 3;
int v2 = 1 << n << 3;
Console.Write(""{0}=={1} "", v1, v2);
v1 = (1 >> n) >> 3;
v2 = 1 >> n >> 3;
Console.Write(""{0}=={1}"", v1, v2);
}
}
";
var verifier = CompileAndVerify(source,
expectedOutput: @"32==32 0==0");
verifier.VerifyIL("Test.Main", @"
{
// Code size 83 (0x53)
.maxstack 3
.locals init (int V_0, //n
int V_1, //v1
int V_2) //v2
IL_0000: ldc.i4.2
IL_0001: stloc.0
IL_0002: ldc.i4.1
IL_0003: ldloc.0
IL_0004: ldc.i4.s 31
IL_0006: and
IL_0007: shl
IL_0008: ldc.i4.3
IL_0009: shl
IL_000a: stloc.1
IL_000b: ldc.i4.1
IL_000c: ldloc.0
IL_000d: ldc.i4.s 31
IL_000f: and
IL_0010: shl
IL_0011: ldc.i4.3
IL_0012: shl
IL_0013: stloc.2
IL_0014: ldstr ""{0}=={1} ""
IL_0019: ldloc.1
IL_001a: box ""int""
IL_001f: ldloc.2
IL_0020: box ""int""
IL_0025: call ""void System.Console.Write(string, object, object)""
IL_002a: ldc.i4.1
IL_002b: ldloc.0
IL_002c: ldc.i4.s 31
IL_002e: and
IL_002f: shr
IL_0030: ldc.i4.3
IL_0031: shr
IL_0032: stloc.1
IL_0033: ldc.i4.1
IL_0034: ldloc.0
IL_0035: ldc.i4.s 31
IL_0037: and
IL_0038: shr
IL_0039: ldc.i4.3
IL_003a: shr
IL_003b: stloc.2
IL_003c: ldstr ""{0}=={1}""
IL_0041: ldloc.1
IL_0042: box ""int""
IL_0047: ldloc.2
IL_0048: box ""int""
IL_004d: call ""void System.Console.Write(string, object, object)""
IL_0052: ret
}
");
}
[Fact, WorkItem(543993, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/543993")]
public void BuiltInShiftOperators02()
{
var source = @"
class Program
{
static void Main()
{
System.Console.WriteLine(1 << 2 << 3);
System.Console.WriteLine((1 << 2) << 3);
System.Console.WriteLine(1 << (2 << 3));
}
}
";
CompileAndVerify(source, expectedOutput: @"
32
32
65536");
}
[WorkItem(543568, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/543568")]
[Fact]
public void ImplicitConversionOperatorWithOptionalParam()
{
var source = @"
using System;
public class C
{
static public implicit operator int(C d = null) // warning CS1066
{
if (d != null) return 0;
return 1;
}
}
class TestFunction
{
public static void Main()
{
var tf = new C();
int result = tf;
Console.Write(result);
}
}
";
var verifier = CompileAndVerify(source, expectedOutput: @"0");
}
[WorkItem(543569, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/543569")]
[Fact()]
public void AssignmentInOperandOfIsAlwaysFalse()
{
var source = @"
using System;
public class Program
{
public static void Main()
{
int[] a = null;
bool result = (a = new[] { 4, 5, 6 }) is char[]; // warning CS0184
if (a == null)
{
Console.WriteLine(""FAIL"");
}
else
{
Console.WriteLine(""PASS"");
}
}
}
";
var verifier = CompileAndVerify(source, expectedOutput: @"PASS");
}
[WorkItem(543577, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/543577")]
[Fact()]
public void IsOperatorAlwaysFalseInLambda()
{
var source = @"
using System;
class C
{
static int counter = 0;
public static void Increment()
{
counter++;
}
public static void Main()
{
Func<bool> testExpr = () => Increment() is object; // warning CS0184
Console.WriteLine(counter);
}
}
";
var verifier = CompileAndVerify(source, expectedOutput: @"0");
}
[WorkItem(543446, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/543446"), WorkItem(543446, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/543446")]
[Fact]
public void ThrowExceptionByConversion()
{
var source = @"using System;
namespace Test
{
class DException : Exception
{
public static implicit operator DException(Action d)
{
return new DException();
}
}
class Program
{
static void M() { }
static void Main()
{
try
{
throw (DException) M;
}
catch (DException)
{
Console.Write(0);
}
Console.Write(1);
}
}
}
";
var verifier = CompileAndVerify(source, expectedOutput: @"01");
}
[WorkItem(543586, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/543586")]
[Fact]
public void ImplicitVsExplicitOverloadOperators()
{
var source = @"using System;
class Test
{
static void Main()
{
Str str = (Str)1;
Console.WriteLine(str.num);
}
}
struct Str
{
public int num;
public static explicit operator Str(int i)
{
Str temp;
temp.num = 10;
return temp;
}
public static implicit operator Str(double i)
{
Str temp;
temp.num = 100;
return temp;
}
}
";
var verifier = CompileAndVerify(source, expectedOutput: @"10");
}
[WorkItem(543602, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/543602")]
[WorkItem(543660, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/543660")]
[Fact]
public void SwitchExpressionWithImplicitConversion()
{
var source = @"using System;
public class Test
{
public static implicit operator int(Test val)
{
return 1;
}
public static implicit operator float(Test val)
{
return 2.1f;
}
public static int Main()
{
Test t = new Test();
switch (t)
{
case 1:
Console.WriteLine(0);
return 0;
default:
Console.WriteLine(1);
return 1;
}
}
}
";
var verifier = CompileAndVerify(source, expectedOutput: @"0");
}
[WorkItem(543498, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/543498")]
[Fact]
public void UserDefinedConversionAfterUserDefinedIncrement()
{
var source =
@"using System;
class A
{
public static C operator ++(A x)
{
Console.Write('3');
return new C();
}
}
class C : A
{
public static implicit operator B(C x)
{
Console.Write('4');
return new B();
}
}
class B : A
{
static void Main()
{
Console.Write('1');
B b = new B();
Console.Write('2');
b++;
Console.Write('5');
}
}";
CompileAndVerify(source, expectedOutput: "12345");
}
[Fact]
public void TestXor()
{
var source = @"
using System;
class Program
{
static bool t() { return true; }
static bool f() { return false; }
static void write(bool b) { Console.WriteLine(b); }
static void Main(string[] args)
{
write(t() ^ t());
write(t() ^ f());
write(f() ^ t());
write(f() ^ f());
Console.WriteLine(""---"");
write(!(t() ^ t()));
write(!(t() ^ f()));
write(!(f() ^ t()));
write(!(f() ^ f()));
Console.WriteLine(""---"");
write((t() ^ t()) || (t() ^ f()));
write((t() ^ f()) || (t() ^ t()));
write((f() ^ t()) || (f() ^ f()));
write((f() ^ f()) || (t() ^ t()));
Console.WriteLine(""---"");
write((t() ^ t()) && (t() ^ f()));
write((t() ^ f()) && (t() ^ t()));
write((f() ^ t()) && (f() ^ f()));
write((f() ^ f()) && (f() ^ t()));
Console.WriteLine(""---"");
write((t() ^ t()) || !(t() ^ f()));
write((t() ^ f()) || !(t() ^ t()));
write(!(f() ^ t()) || (f() ^ f()));
write(!(f() ^ f()) || (f() ^ t()));
Console.WriteLine(""---"");
write((t() ^ t()) && !(t() ^ f()));
write((t() ^ f()) && !(t() ^ t()));
write(!(f() ^ t()) && (f() ^ f()));
write(!(f() ^ f()) && (f() ^ t()));
}
}
";
string expectedOutput =
@"False
True
True
False
---
True
False
False
True
---
True
True
True
False
---
False
False
False
False
---
False
True
False
True
---
False
True
False
True
";
var compilation = CompileAndVerify(source, expectedOutput: expectedOutput);
}
[Fact]
public void TestXorInIf()
{
var source = @"
using System;
class Program
{
static bool t() { return true; }
static bool f() { return false; }
static void Main(string[] args)
{
if (t() ^ t())
{
Console.WriteLine(""1"");
}
if (!(t() ^ f()))
{
Console.WriteLine(""2"");
}
if (f() ^ t())
{
Console.WriteLine(""3"");
}
if (f() ^ f())
{
Console.WriteLine(""4"");
}
if ((t() ^ f()) && (f() ^ t()))
{
Console.WriteLine(""5"");
}
if ((t() ^ t()) || (t() ^ f()))
{
Console.WriteLine(""6"");
}
if ((t() ^ t()) || (f() ^ f()))
{
Console.WriteLine(""7"");
}
}
}
";
string expectedOutput =
@"3
5
6";
var compilation = CompileAndVerify(source, expectedOutput: expectedOutput);
}
[Fact]
public void XorIl()
{
var text = @"using System;
class MyClass
{
public static bool f = false, t = true;
public static bool r;
public static void Main()
{
r = f ^ t;
r = !(f ^ t);
}
}
";
var comp = CompileAndVerify(text, expectedOutput: "");
comp.VerifyIL("MyClass.Main", @"
{
// Code size 34 (0x22)
.maxstack 2
IL_0000: ldsfld ""bool MyClass.f""
IL_0005: ldsfld ""bool MyClass.t""
IL_000a: xor
IL_000b: stsfld ""bool MyClass.r""
IL_0010: ldsfld ""bool MyClass.f""
IL_0015: ldsfld ""bool MyClass.t""
IL_001a: ceq
IL_001c: stsfld ""bool MyClass.r""
IL_0021: ret
}");
}
[Fact, WorkItem(543446, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/543446")]
public void UserDefinedConversionAfterUserDefinedConvert()
{
var source =
@"using System;
delegate void D(int p1);
class DException : Exception
{
public D d;
public static implicit operator DException(D d)
{
DException e = new DException();
e.d = d;
return e;
}
}
class Program
{
static void PM(int p1)
{
}
static void Main()
{
throw (DException)PM;
}
}
";
CompileAndVerify(source);
}
[Fact]
public void UserDefinedOperatorAfterUserDefinedConversion()
{
var source =
@"using System;
class Program
{
public static void Main(string[] args)
{
var c = new C();
var trash = c + c; // which +?
}
}
class C
{
public static string operator +(C c, string s)
{
Console.WriteLine(""+(C,string)"");
return ""+s"";
}
public static string operator +(C c, object o)
{
Console.WriteLine(""+(C,object)"");
return ""+o"";
}
public static implicit operator string(C c)
{
Console.WriteLine(""C->string"");
return ""C->string"";
}
public override string ToString()
{
Console.WriteLine(""C.ToString()"");
return ""C2"";
}
}";
CompileAndVerify(source, expectedOutput:
@"C->string
+(C,string)
");
}
[Fact, WorkItem(529248, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/529248")]
public void TestNullCoalescingOperatorWithNullableConversions()
{
// Native compiler violates the language specification while binding the type for the null coalescing operator (??).
// The last bullet in section 7.13 of the specification for binding the type of ?? operator states that:
// SPEC: Otherwise, if b has a type B and an implicit conversion exists from a to B, the result type is B.
// SPEC: At run-time, a is first evaluated. If a is not null, a is unwrapped to type A0 (if A exists and is nullable)
// SPEC: and converted to type B, and this becomes the result. Otherwise, b is evaluated and becomes the result.
// Note that for this test there is no implicit conversion from 's' -> int (SnapshotPoint? -> int), but there is an implicit conversion
// from stripped type SnapshotPoint -> int.
// Native compiler instead implements this part based on whether A is a nullable type or not. We maintain compatibility with the native compiler:
// SPEC PROPOSAL: Otherwise, if A exists and is a nullable type and if b has a type B and an implicit conversion exists from A0 to B,
// SPEC PROPOSAL: the result type is B. At run-time, a is first evaluated. If a is not null, a is unwrapped to type A0 and converted to type B,
// SPEC PROPOSAL: and this becomes the result. Otherwise, b is evaluated and becomes the result.
//
// SPEC PROPOSAL: Otherwise, if A does not exist or is a non-nullable type and if b has a type B and an implicit conversion exists from a to B,
// SPEC PROPOSAL: the result type is B. At run-time, a is first evaluated. If a is not null, a is converted to type B, and this becomes the result.
// SPEC PROPOSAL: Otherwise, b is evaluated and becomes the result.
string source = @"
struct SnapshotPoint
{
public static implicit operator int(SnapshotPoint snapshotPoint)
{
System.Console.WriteLine(""Pass"");
return 0;
}
}
class Program
{
static void Main(string[] args)
{
SnapshotPoint? s = new SnapshotPoint();
var r = s ?? -1;
SnapshotPoint? s2 = null;
r = s2 ?? -1;
}
}
";
var verifier = CompileAndVerify(source: source, expectedOutput: "Pass");
verifier.VerifyIL("Program.Main", @"
{
// Code size 70 (0x46)
.maxstack 1
.locals init (SnapshotPoint V_0,
SnapshotPoint? V_1)
IL_0000: ldloca.s V_0
IL_0002: initobj ""SnapshotPoint""
IL_0008: ldloc.0
IL_0009: newobj ""SnapshotPoint?..ctor(SnapshotPoint)""
IL_000e: stloc.1
IL_000f: ldloca.s V_1
IL_0011: call ""bool SnapshotPoint?.HasValue.get""
IL_0016: brfalse.s IL_0025
IL_0018: ldloca.s V_1
IL_001a: call ""SnapshotPoint SnapshotPoint?.GetValueOrDefault()""
IL_001f: call ""int SnapshotPoint.op_Implicit(SnapshotPoint)""
IL_0024: pop
IL_0025: ldloca.s V_1
IL_0027: initobj ""SnapshotPoint?""
IL_002d: ldloc.1
IL_002e: stloc.1
IL_002f: ldloca.s V_1
IL_0031: call ""bool SnapshotPoint?.HasValue.get""
IL_0036: brfalse.s IL_0045
IL_0038: ldloca.s V_1
IL_003a: call ""SnapshotPoint SnapshotPoint?.GetValueOrDefault()""
IL_003f: call ""int SnapshotPoint.op_Implicit(SnapshotPoint)""
IL_0044: pop
IL_0045: ret
}");
}
[Fact, WorkItem(543980, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/543980")]
public void IsOperatorOnEnumAndTypeParameterConstraintToStruct()
{
string source = @"using System;
public enum E { One }
class Gen<T> where T : struct
{
public static void TestIsOperatorEnum(T t)
{
Console.WriteLine(t is Enum);
Console.WriteLine(t is E);
Console.WriteLine(t as Enum);
}
}
public class Test
{
public static void Main()
{
Gen<E>.TestIsOperatorEnum(new E());
}
}
";
string expectedOutput = @"True
True
One";
CompileAndVerify(source, expectedOutput: expectedOutput);
}
[Fact, WorkItem(543982, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/543982")]
public void OverloadAdditionOperatorOnGenericClass()
{
var source = @"
using System;
public class G<T>
{
public static G<T> operator ~(G<T> g)
{
Console.WriteLine(""G<{0}> unary negation"", typeof(T));
return new G<T>();
}
public static G<T> operator +(G<T> G1, G<T> G2)
{
Console.WriteLine(""G<{0}> binary addition"", typeof(T));
return new G<T>();
}
}
public class Gen<T, U> where T : G<U>
{
public static void TestLookupOnT(T obj, U val)
{
G<U> t = obj + ~obj;
}
}
public class Test
{
public static void Main()
{
Gen<G<int>, int>.TestLookupOnT(new G<int>(), 1);
}
}
";
string expected = @"G<System.Int32> unary negation
G<System.Int32> binary addition";
CompileAndVerify(
source: source,
expectedOutput: expected);
}
[Fact, WorkItem(544539, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/544539"), WorkItem(544540, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/544540")]
public void NonShortCircuitBoolean()
{
var source = @"using System;
struct Program
{
public static bool P()
{
Console.WriteLine(""P"");
return true;
}
public static void Main(string[] args)
{
bool x = true | P();
Console.WriteLine(P() & false);
}
}";
string expected = @"P
P
False";
CompileAndVerify(
source: source,
expectedOutput: expected);
}
[Fact]
public void EqualZero()
{
var text = @"
using System;
class MyClass
{
public enum E1
{
A,
B
}
public static void Main()
{
Test1((object)null, 0);
}
public static void Test1<T>(T x, E1 e) where T : class
{
if (x == null)
{
Console.WriteLine(!(x == null));
}
if (e == E1.A)
{
Console.WriteLine(!(e == E1.A));
}
}
}
";
var comp = CompileAndVerify(text, expectedOutput: @"False
False
");
comp.VerifyIL("MyClass.Test1<T>", @"
{
// Code size 35 (0x23)
.maxstack 2
IL_0000: ldarg.0
IL_0001: box ""T""
IL_0006: brtrue.s IL_0016
IL_0008: ldarg.0
IL_0009: box ""T""
IL_000e: ldnull
IL_000f: cgt.un
IL_0011: call ""void System.Console.WriteLine(bool)""
IL_0016: ldarg.1
IL_0017: brtrue.s IL_0022
IL_0019: ldarg.1
IL_001a: ldc.i4.0
IL_001b: cgt.un
IL_001d: call ""void System.Console.WriteLine(bool)""
IL_0022: ret
}
");
}
[Fact]
public void EqualZeroUnoptimized()
{
var text = @"
using System;
class MyClass
{
public enum E1
{
A,
B
}
public static void Main()
{
Test1((object)null, 0);
}
public static void Test1<T>(T x, E1 e) where T : class
{
if (x == null)
{
Console.WriteLine(x == null);
}
if (e == E1.A)
{
Console.WriteLine(e == E1.A);
}
}
}
";
var comp = CompileAndVerify(text, options: TestOptions.DebugExe, expectedOutput: @"True
True
");
comp.VerifyIL("MyClass.Test1<T>", @"
{
// Code size 52 (0x34)
.maxstack 2
.locals init (bool V_0,
bool V_1)
-IL_0000: nop
-IL_0001: ldarg.0
IL_0002: box ""T""
IL_0007: ldnull
IL_0008: ceq
IL_000a: stloc.0
~IL_000b: ldloc.0
IL_000c: brfalse.s IL_001f
-IL_000e: nop
-IL_000f: ldarg.0
IL_0010: box ""T""
IL_0015: ldnull
IL_0016: ceq
IL_0018: call ""void System.Console.WriteLine(bool)""
IL_001d: nop
-IL_001e: nop
-IL_001f: ldarg.1
IL_0020: ldc.i4.0
IL_0021: ceq
IL_0023: stloc.1
~IL_0024: ldloc.1
IL_0025: brfalse.s IL_0033
-IL_0027: nop
-IL_0028: ldarg.1
IL_0029: ldc.i4.0
IL_002a: ceq
IL_002c: call ""void System.Console.WriteLine(bool)""
IL_0031: nop
-IL_0032: nop
-IL_0033: ret
}
", sequencePoints: "MyClass.Test1");
}
[WorkItem(543893, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/543893")]
[Fact]
public void EnumBitwiseComplement()
{
var text = @"
public class A
{
enum E : ushort { one = 1, two = 2, four = 4 }
public static void Main()
{
checked {
E e = E.one;
e &= ~E.two;
System.Console.WriteLine(e);
}
}
}
";
var comp = CompileAndVerify(text, expectedOutput: @"one");
// Can't actually see an unchecked cast here since only constant values are emitted.
comp.VerifyIL("A.Main", @"
{
// Code size 18 (0x12)
.maxstack 2
IL_0000: ldc.i4.1
IL_0001: ldc.i4 0xfffd
IL_0006: and
IL_0007: box ""A.E""
IL_000c: call ""void System.Console.WriteLine(object)""
IL_0011: ret
}
");
text = @"
public class A
{
enum E : ushort { one = 1, two = 2, four = 4 }
public static void Main()
{
checked {
E e = E.one;
int i = 5 + (int)~e;
System.Console.WriteLine(i);
}
}
}
";
comp = CompileAndVerify(text, expectedOutput: @"65539");
// Can't actually see an unchecked cast here since only constant values are emitted.
comp.VerifyIL("A.Main", @"
{
// Code size 13 (0xd)
.maxstack 2
.locals init (A.E V_0) //e
IL_0000: ldc.i4.1
IL_0001: stloc.0
IL_0002: ldc.i4.5
IL_0003: ldloc.0
IL_0004: not
IL_0005: conv.u2
IL_0006: add.ovf
IL_0007: call ""void System.Console.WriteLine(int)""
IL_000c: ret
}
");
}
[Fact]
public void EnumXor()
{
var text = @"
using System;
enum e : sbyte
{
x = sbyte.MinValue,
y = sbyte.MaxValue,
z = 1
}
enum e1 : byte
{
x = byte.MinValue,
y = byte.MaxValue,
z = 1
}
public static class Test
{
public static void Main()
{
TestE();
TestE1();
}
private static void TestE()
{
var x = e.x;
var y = e.y;
var z = x ^ y;
System.Console.WriteLine((int)z);
x ^= e.z;
y ^= unchecked((e)(-1));
x ^= e.z;
y ^= unchecked((e)(-1));
z = x ^ y;
System.Console.WriteLine((int)z);
}
private static void TestE1()
{
var x = e1.x;
var y = e1.y;
var z = x ^ y;
System.Console.WriteLine((int)z);
x ^= e1.z;
y ^= unchecked((e1)(-1));
x ^= e1.z;
y ^= unchecked((e1)(-1));
z = x ^ y;
System.Console.WriteLine((int)z);
}
}
";
var comp = CompileAndVerify(text, expectedOutput: @"
-1
-1
255
255
");
comp.VerifyIL("Test.TestE()", @"
{
// Code size 33 (0x21)
.maxstack 3
.locals init (e V_0) //y
IL_0000: ldc.i4.s -128
IL_0002: ldc.i4.s 127
IL_0004: stloc.0
IL_0005: dup
IL_0006: ldloc.0
IL_0007: xor
IL_0008: call ""void System.Console.WriteLine(int)""
IL_000d: ldc.i4.1
IL_000e: xor
IL_000f: ldloc.0
IL_0010: ldc.i4.m1
IL_0011: xor
IL_0012: stloc.0
IL_0013: ldc.i4.1
IL_0014: xor
IL_0015: ldloc.0
IL_0016: ldc.i4.m1
IL_0017: xor
IL_0018: stloc.0
IL_0019: ldloc.0
IL_001a: xor
IL_001b: call ""void System.Console.WriteLine(int)""
IL_0020: ret
}
");
comp.VerifyIL("Test.TestE1()", @"
{
// Code size 43 (0x2b)
.maxstack 3
.locals init (e1 V_0) //y
IL_0000: ldc.i4.0
IL_0001: ldc.i4 0xff
IL_0006: stloc.0
IL_0007: dup
IL_0008: ldloc.0
IL_0009: xor
IL_000a: call ""void System.Console.WriteLine(int)""
IL_000f: ldc.i4.1
IL_0010: xor
IL_0011: ldloc.0
IL_0012: ldc.i4 0xff
IL_0017: xor
IL_0018: stloc.0
IL_0019: ldc.i4.1
IL_001a: xor
IL_001b: ldloc.0
IL_001c: ldc.i4 0xff
IL_0021: xor
IL_0022: stloc.0
IL_0023: ldloc.0
IL_0024: xor
IL_0025: call ""void System.Console.WriteLine(int)""
IL_002a: ret
}
");
}
[WorkItem(544452, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/544452")]
[Fact]
public void LiftedByteEnumAddition()
{
var text =
@"using System;
public class Program
{
private static bool ThrowsException(Action action)
{
try
{
action();
return false;
}
catch(Exception)
{
return true;
}
}
private static void Test(bool b)
{
Console.Write(b ? 't' : 'f');
}
enum Color : byte { Red, Green, Blue }
static void Main()
{
Color? c = Color.Blue;
byte? b = byte.MaxValue - 1;
Color? r = 0;
Test(ThrowsException(()=>{ r = checked(c + b); }));
Test(ThrowsException(()=>{ r = checked(c.Value + b.Value); }));
Test(ThrowsException(()=>{ r = unchecked(c + b); }));
Test(ThrowsException(()=>{ r = unchecked(c.Value + b.Value); }));
}
static void M(Color c, byte b)
{
Console.WriteLine(checked(c + b));
Console.WriteLine(unchecked(c + b));
}
}";
string il = @"{
// Code size 29 (0x1d)
.maxstack 2
IL_0000: ldarg.0
IL_0001: ldarg.1
IL_0002: add.ovf
IL_0003: conv.ovf.u1
IL_0004: box ""Program.Color""
IL_0009: call ""void System.Console.WriteLine(object)""
IL_000e: ldarg.0
IL_000f: ldarg.1
IL_0010: add
IL_0011: conv.u1
IL_0012: box ""Program.Color""
IL_0017: call ""void System.Console.WriteLine(object)""
IL_001c: ret
}";
var comp = CompileAndVerify(text, expectedOutput: @"ttff");
comp.VerifyIL("Program.M", il);
}
[WorkItem(7091, "https://github.com/dotnet/roslyn/issues/7091")]
[Fact]
public void LiftedBitwiseOr()
{
var text =
@"using System;
public class Program
{
static void Main()
{
var res = XX() | YY();
}
static bool XX()
{
Console.WriteLine (""XX"");
return true;
}
static bool? YY()
{
Console.WriteLine(""YY"");
return true;
}
}
";
var expectedOutput =
@"XX
YY";
var comp = CompileAndVerify(text, expectedOutput: expectedOutput);
string il = @"{
// Code size 13 (0xd)
.maxstack 2
.locals init (bool? V_0)
IL_0000: call ""bool Program.XX()""
IL_0005: call ""bool? Program.YY()""
IL_000a: stloc.0
IL_000b: pop
IL_000c: ret
}
";
comp.VerifyIL("Program.Main", il);
}
[WorkItem(544943, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/544943")]
[Fact]
public void OptimizedXor()
{
var text = @"
using System;
class C
{
void M(bool b)
{
Console.WriteLine(b ^ true);
Console.WriteLine(b ^ false);
Console.WriteLine(true ^ b);
Console.WriteLine(false ^ b);
}
}";
//NOTE: all xors optimized away
var comp = CompileAndVerify(text).VerifyIL("C.M", @"
{
// Code size 31 (0x1f)
.maxstack 2
IL_0000: ldarg.1
IL_0001: ldc.i4.0
IL_0002: ceq
IL_0004: call ""void System.Console.WriteLine(bool)""
IL_0009: ldarg.1
IL_000a: call ""void System.Console.WriteLine(bool)""
IL_000f: ldarg.1
IL_0010: ldc.i4.0
IL_0011: ceq
IL_0013: call ""void System.Console.WriteLine(bool)""
IL_0018: ldarg.1
IL_0019: call ""void System.Console.WriteLine(bool)""
IL_001e: ret
}");
}
[WorkItem(544943, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/544943")]
[Fact]
public void XorMalformedTrue()
{
var text = @"
using System;
class C
{
static void Main()
{
byte[] x = { 0xFF };
bool[] y = { true };
Buffer.BlockCopy(x, 0, y, 0, 1);
Console.WriteLine(y[0]);
Console.WriteLine(y[0] ^ true);
}
}";
var comp = CompileAndVerify(text, expectedOutput: @"True
False");
}
[WorkItem(539398, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/539398")]
[WorkItem(1043494, "DevDiv")]
[ConditionalFact(typeof(DesktopOnly))]
public void TestFloatNegativeZero()
{
var text = @"
using System;
using System.Globalization;
class C
{
static void Main()
{
WriteLine(+0f == -0f);
WriteLine(1f / 0f);
WriteLine(1f / -0f);
WriteLine(-1f / 0f);
WriteLine(-1f / -0f);
WriteLine(1f / (1f * 0f));
WriteLine(1f / (1f * -0f));
WriteLine(1f / (-1f * 0f));
WriteLine(1f / (-1f * -0f));
}
static void WriteLine(bool b) => Console.WriteLine(b);
static void WriteLine(float f) => Console.WriteLine(f.ToString(CultureInfo.InvariantCulture));
}";
var comp = CompileAndVerify(text, expectedOutput: @"
True
Infinity
-Infinity
-Infinity
Infinity
Infinity
-Infinity
-Infinity
Infinity");
}
[WorkItem(539398, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/539398")]
[WorkItem(1043494, "DevDiv")]
[ConditionalFact(typeof(DesktopOnly))]
public void TestDoubleNegativeZero()
{
var text = @"
using System;
using System.Globalization;
class C
{
static void Main()
{
WriteLine(+0d == -0d);
WriteLine(1d / 0d);
WriteLine(1d / -0d);
WriteLine(-1d / 0d);
WriteLine(-1d / -0d);
WriteLine(1d / (1d * 0d));
WriteLine(1d / (1d * -0d));
WriteLine(1d / (-1d * 0d));
WriteLine(1d / (-1d * -0d));
}
static void WriteLine(bool b) => Console.WriteLine(b);
static void WriteLine(double d) => Console.WriteLine(d.ToString(CultureInfo.InvariantCulture));
}";
var comp = CompileAndVerify(text, expectedOutput: @"
True
Infinity
-Infinity
-Infinity
Infinity
Infinity
-Infinity
-Infinity
Infinity");
}
// NOTE: decimal doesn't have infinity, so we convert to double.
[WorkItem(539398, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/539398")]
[WorkItem(1043494, "DevDiv")]
[ConditionalFact(typeof(DesktopOnly))]
public void TestDecimalNegativeZero()
{
var text = @"
using System;
using System.Globalization;
class C
{
static void Main()
{
WriteLine(+0m == -0m);
WriteLine(1d / (double)(0m));
WriteLine(1d / (double)(-0m));
WriteLine(-1d / (double)(0m));
WriteLine(-1d / (double)(-0m));
WriteLine(1d / (double)(1m * 0m));
WriteLine(1d / (double)(1m * -0m));
WriteLine(1d / (double)(-1m * 0m));
WriteLine(1d / (double)(-1m * -0m));
}
static void WriteLine(bool b) => Console.WriteLine(b);
static void WriteLine(double d) => Console.WriteLine(d.ToString(CultureInfo.InvariantCulture));
}";
var comp = CompileAndVerify(text, expectedOutput: @"
True
Infinity
-Infinity
-Infinity
Infinity
Infinity
-Infinity
-Infinity
Infinity");
}
[WorkItem(545239, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/545239")]
[Fact()]
public void IncrementPropertyOfTypeParameterReturnValue()
{
var text = @"
public interface I
{
int IntPropI { get; set; }
}
struct S1 : I
{
public int x;
public int IntPropI
{
get
{
x ++;
return x;
}
set
{
x ++;
System.Console.WriteLine(x);
}
}
}
public class Test
{
public static void Main()
{
S1 s = new S1();
TestINop(s);
}
public static T Nop<T>(T t) { return t; }
public static void TestINop<T>(T t) where T : I
{
Nop(t).IntPropI++;
Nop(t).IntPropI++;
}
}
";
CompileAndVerify(text, expectedOutput: @"
2
2").VerifyIL("Test.TestINop<T>", @"
{
// Code size 73 (0x49)
.maxstack 3
.locals init (int V_0,
T V_1)
IL_0000: ldarg.0
IL_0001: call ""T Test.Nop<T>(T)""
IL_0006: stloc.1
IL_0007: ldloca.s V_1
IL_0009: dup
IL_000a: constrained. ""T""
IL_0010: callvirt ""int I.IntPropI.get""
IL_0015: stloc.0
IL_0016: ldloc.0
IL_0017: ldc.i4.1
IL_0018: add
IL_0019: constrained. ""T""
IL_001f: callvirt ""void I.IntPropI.set""
IL_0024: ldarg.0
IL_0025: call ""T Test.Nop<T>(T)""
IL_002a: stloc.1
IL_002b: ldloca.s V_1
IL_002d: dup
IL_002e: constrained. ""T""
IL_0034: callvirt ""int I.IntPropI.get""
IL_0039: stloc.0
IL_003a: ldloc.0
IL_003b: ldc.i4.1
IL_003c: add
IL_003d: constrained. ""T""
IL_0043: callvirt ""void I.IntPropI.set""
IL_0048: ret
}
");
}
[WorkItem(546750, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/546750")]
[Fact()]
public void IncrementStructFieldWithReceiverThis()
{
var text = @"
struct S
{
int x;
void Test()
{
x++;
}
}
";
// NOTE: don't need a ref local in this case.
CompileAndVerify(text).VerifyIL("S.Test", @"
{
// Code size 15 (0xf)
.maxstack 3
IL_0000: ldarg.0
IL_0001: ldarg.0
IL_0002: ldfld ""int S.x""
IL_0007: ldc.i4.1
IL_0008: add
IL_0009: stfld ""int S.x""
IL_000e: ret
}
");
}
[Fact]
public void TestTernary_InterfaceRegression1a()
{
var source = @"
using System.Collections.Generic;
public class Test
{
private static bool C() { return true;}
static void Main()
{
int[] a = new int[] { };
IEnumerable<int> b = new List<int>();
IEnumerable<int> c = C()? b : a;
Goo(c);
}
static void Goo<T>(T x)
{
System.Console.WriteLine(typeof(T));
}
}";
var comp = CompileAndVerify(source, expectedOutput: "System.Collections.Generic.IEnumerable`1[System.Int32]");
comp.VerifyDiagnostics();
comp.VerifyIL("Test.Main", @"
{
// Code size 32 (0x20)
.maxstack 1
.locals init (int[] V_0, //a
System.Collections.Generic.IEnumerable<int> V_1, //b
System.Collections.Generic.IEnumerable<int> V_2)
IL_0000: ldc.i4.0
IL_0001: newarr ""int""
IL_0006: stloc.0
IL_0007: newobj ""System.Collections.Generic.List<int>..ctor()""
IL_000c: stloc.1
IL_000d: call ""bool Test.C()""
IL_0012: brtrue.s IL_0019
IL_0014: ldloc.0
IL_0015: stloc.2
IL_0016: ldloc.2
IL_0017: br.s IL_001a
IL_0019: ldloc.1
IL_001a: call ""void Test.Goo<System.Collections.Generic.IEnumerable<int>>(System.Collections.Generic.IEnumerable<int>)""
IL_001f: ret
}");
}
[Fact]
public void TestTernary_InterfaceRegression1b()
{
var source = @"
using System.Collections.Generic;
public class Test
{
private static bool C() { return true;}
static void Main()
{
int[] a = new int[] { };
IEnumerable<int> b = null;
IEnumerable<int> c = C()? (b = (IEnumerable<int>)new List<int>()) : a;
Goo(c);
Goo(b);
}
static void Goo<T>(T x)
{
System.Console.Write(typeof(T));
}
}";
var comp = CompileAndVerify(source, expectedOutput: "System.Collections.Generic.IEnumerable`1[System.Int32]System.Collections.Generic.IEnumerable`1[System.Int32]");
comp.VerifyDiagnostics();
comp.VerifyIL("Test.Main", @"
{
// Code size 42 (0x2a)
.maxstack 2
.locals init (int[] V_0, //a
System.Collections.Generic.IEnumerable<int> V_1, //b
System.Collections.Generic.IEnumerable<int> V_2)
IL_0000: ldc.i4.0
IL_0001: newarr ""int""
IL_0006: stloc.0
IL_0007: ldnull
IL_0008: stloc.1
IL_0009: call ""bool Test.C()""
IL_000e: brtrue.s IL_0015
IL_0010: ldloc.0
IL_0011: stloc.2
IL_0012: ldloc.2
IL_0013: br.s IL_001e
IL_0015: newobj ""System.Collections.Generic.List<int>..ctor()""
IL_001a: dup
IL_001b: stloc.1
IL_001c: stloc.2
IL_001d: ldloc.2
IL_001e: call ""void Test.Goo<System.Collections.Generic.IEnumerable<int>>(System.Collections.Generic.IEnumerable<int>)""
IL_0023: ldloc.1
IL_0024: call ""void Test.Goo<System.Collections.Generic.IEnumerable<int>>(System.Collections.Generic.IEnumerable<int>)""
IL_0029: ret
}");
}
[Fact]
public void TestTernary_InterfaceRegression1c()
{
var source = @"
using System.Collections.Generic;
public class Test
{
static void Main()
{
int[] a = new int[] { };
IEnumerable<int> b = new List<int>();
Goo(b, b != null ? b : a);
}
static void Goo<T, U>(T x, U y)
{
System.Console.Write(typeof(T));
}
}";
var comp = CompileAndVerify(source, expectedOutput: "System.Collections.Generic.IEnumerable`1[System.Int32]");
comp.VerifyDiagnostics();
comp.VerifyIL("Test.Main", @"
{
// Code size 29 (0x1d)
.maxstack 2
.locals init (int[] V_0, //a
System.Collections.Generic.IEnumerable<int> V_1, //b
System.Collections.Generic.IEnumerable<int> V_2)
IL_0000: ldc.i4.0
IL_0001: newarr ""int""
IL_0006: stloc.0
IL_0007: newobj ""System.Collections.Generic.List<int>..ctor()""
IL_000c: stloc.1
IL_000d: ldloc.1
IL_000e: ldloc.1
IL_000f: brtrue.s IL_0016
IL_0011: ldloc.0
IL_0012: stloc.2
IL_0013: ldloc.2
IL_0014: br.s IL_0017
IL_0016: ldloc.1
IL_0017: call ""void Test.Goo<System.Collections.Generic.IEnumerable<int>, System.Collections.Generic.IEnumerable<int>>(System.Collections.Generic.IEnumerable<int>, System.Collections.Generic.IEnumerable<int>)""
IL_001c: ret
}
");
}
[Fact]
public void TestTernary_InterfaceRegression2()
{
var source = @"
public interface IA { }
public interface IB { int f(); }
public class AB1 : IA, IB { public int f() { return 42; } }
public class AB2 : IA, IB { public int f() { return 1; } }
class MainClass
{
private static bool C() { return true;}
public static void g(AB1 ab1)
{
(C()? (IB)ab1 : (IB)new AB2()).f();
}
}";
var comp = CompileAndVerify(source);
comp.VerifyDiagnostics();
comp.VerifyIL("MainClass.g", @"
{
// Code size 26 (0x1a)
.maxstack 1
.locals init (IB V_0)
IL_0000: call ""bool MainClass.C()""
IL_0005: brtrue.s IL_0010
IL_0007: newobj ""AB2..ctor()""
IL_000c: stloc.0
IL_000d: ldloc.0
IL_000e: br.s IL_0013
IL_0010: ldarg.0
IL_0011: stloc.0
IL_0012: ldloc.0
IL_0013: callvirt ""int IB.f()""
IL_0018: pop
IL_0019: ret
}");
}
[Fact]
public void TestTernary_FuncVariance()
{
var source = @"
using System;
using System.Collections.Generic;
class Program
{
private static bool C() { return true;}
static void Main(string[] args)
{
Func<Exception[]> f1 = null;
Func<IEnumerable<object>> f2 = null;
var oo = C()? f1 : f2;
Console.WriteLine(oo);
oo = C()? f2 : f1;
Console.WriteLine(oo);
}
}
";
var comp = CompileAndVerify(source);
comp.VerifyDiagnostics();
comp.VerifyIL("Program.Main", @"
{
// Code size 41 (0x29)
.maxstack 1
.locals init (System.Func<System.Exception[]> V_0, //f1
System.Func<System.Collections.Generic.IEnumerable<object>> V_1, //f2
System.Func<System.Collections.Generic.IEnumerable<object>> V_2)
IL_0000: ldnull
IL_0001: stloc.0
IL_0002: ldnull
IL_0003: stloc.1
IL_0004: call ""bool Program.C()""
IL_0009: brtrue.s IL_000e
IL_000b: ldloc.1
IL_000c: br.s IL_0011
IL_000e: ldloc.0
IL_000f: stloc.2
IL_0010: ldloc.2
IL_0011: call ""void System.Console.WriteLine(object)""
IL_0016: call ""bool Program.C()""
IL_001b: brtrue.s IL_0022
IL_001d: ldloc.0
IL_001e: stloc.2
IL_001f: ldloc.2
IL_0020: br.s IL_0023
IL_0022: ldloc.1
IL_0023: call ""void System.Console.WriteLine(object)""
IL_0028: ret
}
");
}
[Fact]
public void TestTernary_FuncVariance01()
{
var source = @"
using System;
using System.Collections;
using System.Collections.Generic;
class Program
{
private static bool C() { return true;}
static void Main(string[] args)
{
Func<Exception[]> f1 = null;
Func<IEnumerable<object>> f2 = null;
var oo = C()? (Func<IEnumerable>)f1 : (Func<IEnumerable>)f2;
Console.WriteLine(oo);
oo = C()? (Func<IEnumerable>)f2 : (Func<IEnumerable>)f1;
Console.WriteLine(oo);
}
}
";
var comp = CompileAndVerify(source);
comp.VerifyDiagnostics();
comp.VerifyIL("Program.Main", @"
{
// Code size 45 (0x2d)
.maxstack 1
.locals init (System.Func<System.Exception[]> V_0, //f1
System.Func<System.Collections.Generic.IEnumerable<object>> V_1, //f2
System.Func<System.Collections.IEnumerable> V_2)
IL_0000: ldnull
IL_0001: stloc.0
IL_0002: ldnull
IL_0003: stloc.1
IL_0004: call ""bool Program.C()""
IL_0009: brtrue.s IL_0010
IL_000b: ldloc.1
IL_000c: stloc.2
IL_000d: ldloc.2
IL_000e: br.s IL_0013
IL_0010: ldloc.0
IL_0011: stloc.2
IL_0012: ldloc.2
IL_0013: call ""void System.Console.WriteLine(object)""
IL_0018: call ""bool Program.C()""
IL_001d: brtrue.s IL_0024
IL_001f: ldloc.0
IL_0020: stloc.2
IL_0021: ldloc.2
IL_0022: br.s IL_0027
IL_0024: ldloc.1
IL_0025: stloc.2
IL_0026: ldloc.2
IL_0027: call ""void System.Console.WriteLine(object)""
IL_002c: ret
}
");
}
[Fact]
public void TestTernary_InterfaceVariance()
{
var source = @"
using System;
using System.Collections.Generic;
using System.Security;
[assembly: SecurityTransparent()]
class Program
{
private static bool C() { return true;}
interface CoInter<out T>
{
}
static void Main(string[] args)
{
CoInter<Exception[]> f1 = null;
CoInter<IEnumerable<object>> f2 = null;
var oo = C()? f1 : f2;
Console.WriteLine(oo);
oo = C()? f2 : f1;
Console.WriteLine(oo);
}
}
";
var comp = CompileAndVerify(source);
comp.VerifyDiagnostics();
comp.VerifyIL("Program.Main", @"
{
// Code size 41 (0x29)
.maxstack 1
.locals init (Program.CoInter<System.Exception[]> V_0, //f1
Program.CoInter<System.Collections.Generic.IEnumerable<object>> V_1, //f2
Program.CoInter<System.Collections.Generic.IEnumerable<object>> V_2)
IL_0000: ldnull
IL_0001: stloc.0
IL_0002: ldnull
IL_0003: stloc.1
IL_0004: call ""bool Program.C()""
IL_0009: brtrue.s IL_000e
IL_000b: ldloc.1
IL_000c: br.s IL_0011
IL_000e: ldloc.0
IL_000f: stloc.2
IL_0010: ldloc.2
IL_0011: call ""void System.Console.WriteLine(object)""
IL_0016: call ""bool Program.C()""
IL_001b: brtrue.s IL_0022
IL_001d: ldloc.0
IL_001e: stloc.2
IL_001f: ldloc.2
IL_0020: br.s IL_0023
IL_0022: ldloc.1
IL_0023: call ""void System.Console.WriteLine(object)""
IL_0028: ret
}
");
}
[Fact]
public void TestTernary_InterfaceVarianceA()
{
var source = @"
using System;
using System.Security;
[assembly: SecurityTransparent()]
class Program
{
private static bool C() { return true;}
interface CoInter<out T>
{
}
static void Main(string[] args)
{
CoInter<Exception> f1 = null;
CoInter<object> f2 = null;
var oo = C()? f1 : f2;
Console.WriteLine(oo);
oo = C()? f2 : f1;
Console.WriteLine(oo);
}
}
";
var comp = CompileAndVerify(new string[] { source }, expectedOutput: @"");
// var comp = CompileAndVerify(source);
comp.VerifyDiagnostics();
comp.VerifyIL("Program.Main", @"
{
// Code size 41 (0x29)
.maxstack 1
.locals init (Program.CoInter<System.Exception> V_0, //f1
Program.CoInter<object> V_1, //f2
Program.CoInter<object> V_2)
IL_0000: ldnull
IL_0001: stloc.0
IL_0002: ldnull
IL_0003: stloc.1
IL_0004: call ""bool Program.C()""
IL_0009: brtrue.s IL_000e
IL_000b: ldloc.1
IL_000c: br.s IL_0011
IL_000e: ldloc.0
IL_000f: stloc.2
IL_0010: ldloc.2
IL_0011: call ""void System.Console.WriteLine(object)""
IL_0016: call ""bool Program.C()""
IL_001b: brtrue.s IL_0022
IL_001d: ldloc.0
IL_001e: stloc.2
IL_001f: ldloc.2
IL_0020: br.s IL_0023
IL_0022: ldloc.1
IL_0023: call ""void System.Console.WriteLine(object)""
IL_0028: ret
}
");
}
[Fact]
public void TestTernary_InterfaceVariance01()
{
var source = @"
using System;
using System.Collections;
using System.Collections.Generic;
using System.Security;
[assembly: SecurityTransparent()]
class Program
{
private static bool C() { return true;}
interface CoInter<out T>
{
}
static void Main(string[] args)
{
CoInter<Exception[]> f1 = null;
CoInter<IEnumerable<object>> f2 = null;
var oo = C()? (CoInter<IEnumerable>)f1 : (CoInter<IEnumerable>)f2;
Console.WriteLine(oo);
oo = C()? (CoInter<IEnumerable>)f2 : (CoInter<IEnumerable>)f1;
Console.WriteLine(oo);
}
}
";
var comp = CompileAndVerify(source);
comp.VerifyDiagnostics();
comp.VerifyIL("Program.Main", @"
{
// Code size 45 (0x2d)
.maxstack 1
.locals init (Program.CoInter<System.Exception[]> V_0, //f1
Program.CoInter<System.Collections.Generic.IEnumerable<object>> V_1, //f2
Program.CoInter<System.Collections.IEnumerable> V_2)
IL_0000: ldnull
IL_0001: stloc.0
IL_0002: ldnull
IL_0003: stloc.1
IL_0004: call ""bool Program.C()""
IL_0009: brtrue.s IL_0010
IL_000b: ldloc.1
IL_000c: stloc.2
IL_000d: ldloc.2
IL_000e: br.s IL_0013
IL_0010: ldloc.0
IL_0011: stloc.2
IL_0012: ldloc.2
IL_0013: call ""void System.Console.WriteLine(object)""
IL_0018: call ""bool Program.C()""
IL_001d: brtrue.s IL_0024
IL_001f: ldloc.0
IL_0020: stloc.2
IL_0021: ldloc.2
IL_0022: br.s IL_0027
IL_0024: ldloc.1
IL_0025: stloc.2
IL_0026: ldloc.2
IL_0027: call ""void System.Console.WriteLine(object)""
IL_002c: ret
}
");
}
[Fact]
public void TestTernary_ToBase()
{
var source = @"
using System;
using System.Collections.Generic;
using System.Security;
[assembly: SecurityTransparent()]
class Program
{
private static bool C() { return true;}
static void Main(string[] args)
{
Exception[] f1 = null;
IEnumerable<object> f2 = null;
var oo = C()? (object)f1 : (object)f2;
Console.WriteLine(oo);
oo = C()? (object)f2 : (object)f1;
Console.WriteLine(oo);
}
}
";
var comp = CompileAndVerify(source);
comp.VerifyDiagnostics();
comp.VerifyIL("Program.Main", @"
{
// Code size 37 (0x25)
.maxstack 1
.locals init (System.Exception[] V_0, //f1
System.Collections.Generic.IEnumerable<object> V_1) //f2
IL_0000: ldnull
IL_0001: stloc.0
IL_0002: ldnull
IL_0003: stloc.1
IL_0004: call ""bool Program.C()""
IL_0009: brtrue.s IL_000e
IL_000b: ldloc.1
IL_000c: br.s IL_000f
IL_000e: ldloc.0
IL_000f: call ""void System.Console.WriteLine(object)""
IL_0014: call ""bool Program.C()""
IL_0019: brtrue.s IL_001e
IL_001b: ldloc.0
IL_001c: br.s IL_001f
IL_001e: ldloc.1
IL_001f: call ""void System.Console.WriteLine(object)""
IL_0024: ret
}
");
}
[WorkItem(634407, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/634407")]
[Fact]
public void TestTernary_Null()
{
var source = @"
using System;
using System.Collections.Generic;
using System.Security;
[assembly: SecurityTransparent()]
class Program
{
private static bool C() { return true;}
static void Main(string[] args)
{
Exception[] f1 = null;
var oo = C()? f1 : null as IEnumerable<object>;
Console.WriteLine(oo);
var oo1 = C()? null as IEnumerable<object> : f1 as IEnumerable<Exception>;
Console.WriteLine(oo1);
}
}
";
var comp = CompileAndVerify(source);
comp.VerifyDiagnostics();
comp.VerifyIL("Program.Main", @"
{
// Code size 39 (0x27)
.maxstack 1
.locals init (System.Exception[] V_0, //f1
System.Collections.Generic.IEnumerable<object> V_1)
IL_0000: ldnull
IL_0001: stloc.0
IL_0002: call ""bool Program.C()""
IL_0007: brtrue.s IL_000c
IL_0009: ldnull
IL_000a: br.s IL_000f
IL_000c: ldloc.0
IL_000d: stloc.1
IL_000e: ldloc.1
IL_000f: call ""void System.Console.WriteLine(object)""
IL_0014: call ""bool Program.C()""
IL_0019: brtrue.s IL_0020
IL_001b: ldloc.0
IL_001c: stloc.1
IL_001d: ldloc.1
IL_001e: br.s IL_0021
IL_0020: ldnull
IL_0021: call ""void System.Console.WriteLine(object)""
IL_0026: ret
}");
}
[WorkItem(634406, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/634406")]
[Fact]
public void TestBinary_Implicit()
{
var source = @"
using System;
using System.Security;
[assembly: SecurityTransparent()]
class Program
{
private static bool C() { return true; }
class cls1
{
public static implicit operator int(cls1 from)
{
return 42;
}
}
static void Main(string[] args)
{
cls1 f1 = null;
var oo = f1 ?? 33;
Console.WriteLine(oo);
}
}
";
var comp = CompileAndVerify(source);
comp.VerifyDiagnostics();
comp.VerifyIL("Program.Main", @"
{
// Code size 21 (0x15)
.maxstack 1
.locals init (Program.cls1 V_0)
IL_0000: ldnull
IL_0001: stloc.0
IL_0002: ldloc.0
IL_0003: brtrue.s IL_0009
IL_0005: ldc.i4.s 33
IL_0007: br.s IL_000f
IL_0009: ldloc.0
IL_000a: call ""int Program.cls1.op_Implicit(Program.cls1)""
IL_000f: call ""void System.Console.WriteLine(int)""
IL_0014: ret
}
");
}
[WorkItem(656807, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/656807")]
[Fact]
public void DelegateEqualsNull()
{
var source = @"
public delegate int D(int x);
public class Program
{
public static D d1 = null;
public static int r1;
public static bool r2;
public static void Main(string[] args)
{
if (d1 == null) { r1 = 1; }
if (d1 != null) { r1 = 2; }
r2 = (d1 == null);
r2 = (d1 != null);
}
}
";
var comp = CompileAndVerify(source);
comp.VerifyDiagnostics();
comp.VerifyIL("Program.Main", @"
{
// Code size 53 (0x35)
.maxstack 2
IL_0000: ldsfld ""D Program.d1""
IL_0005: brtrue.s IL_000d
IL_0007: ldc.i4.1
IL_0008: stsfld ""int Program.r1""
IL_000d: ldsfld ""D Program.d1""
IL_0012: brfalse.s IL_001a
IL_0014: ldc.i4.2
IL_0015: stsfld ""int Program.r1""
IL_001a: ldsfld ""D Program.d1""
IL_001f: ldnull
IL_0020: ceq
IL_0022: stsfld ""bool Program.r2""
IL_0027: ldsfld ""D Program.d1""
IL_002c: ldnull
IL_002d: cgt.un
IL_002f: stsfld ""bool Program.r2""
IL_0034: ret
}");
}
[WorkItem(717072, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/717072")]
[Fact]
public void DecimalOperators()
{
var source = @"
class Program
{
static void Main()
{
decimal d1 = 1.0201m;
if (d1 == 10201M)
{
}
if (d1 != 10201M)
{
}
decimal d2 = d1 + d1;
decimal d3 = d1 - d1;
decimal d4 = d1 * d1;
decimal d5 = d1 / d1;
decimal d6 = d1 % d1;
decimal d7 = d1 ++;
decimal d8 = d1--;
decimal d9 = -d1;
decimal d10 = +d1;
}
}
";
var comp = CompileAndVerify(source);
comp.VerifyDiagnostics();
comp.VerifyIL("Program.Main", @"
{
// Code size 116 (0x74)
.maxstack 6
.locals init (decimal V_0) //d1
IL_0000: ldloca.s V_0
IL_0002: ldc.i4 0x27d9
IL_0007: ldc.i4.0
IL_0008: ldc.i4.0
IL_0009: ldc.i4.0
IL_000a: ldc.i4.4
IL_000b: call ""decimal..ctor(int, int, int, bool, byte)""
IL_0010: ldloc.0
IL_0011: ldc.i4 0x27d9
IL_0016: newobj ""decimal..ctor(int)""
IL_001b: call ""bool decimal.op_Equality(decimal, decimal)""
IL_0020: pop
IL_0021: ldloc.0
IL_0022: ldc.i4 0x27d9
IL_0027: newobj ""decimal..ctor(int)""
IL_002c: call ""bool decimal.op_Inequality(decimal, decimal)""
IL_0031: pop
IL_0032: ldloc.0
IL_0033: ldloc.0
IL_0034: call ""decimal decimal.op_Addition(decimal, decimal)""
IL_0039: pop
IL_003a: ldloc.0
IL_003b: ldloc.0
IL_003c: call ""decimal decimal.op_Subtraction(decimal, decimal)""
IL_0041: pop
IL_0042: ldloc.0
IL_0043: ldloc.0
IL_0044: call ""decimal decimal.op_Multiply(decimal, decimal)""
IL_0049: pop
IL_004a: ldloc.0
IL_004b: ldloc.0
IL_004c: call ""decimal decimal.op_Division(decimal, decimal)""
IL_0051: pop
IL_0052: ldloc.0
IL_0053: ldloc.0
IL_0054: call ""decimal decimal.op_Modulus(decimal, decimal)""
IL_0059: pop
IL_005a: ldloc.0
IL_005b: dup
IL_005c: call ""decimal decimal.op_Increment(decimal)""
IL_0061: stloc.0
IL_0062: pop
IL_0063: ldloc.0
IL_0064: dup
IL_0065: call ""decimal decimal.op_Decrement(decimal)""
IL_006a: stloc.0
IL_006b: pop
IL_006c: ldloc.0
IL_006d: call ""decimal decimal.op_UnaryNegation(decimal)""
IL_0072: pop
IL_0073: ret
}
");
}
[Fact]
[WorkItem(732269, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/732269")]
[WorkItem("https://github.com/dotnet/roslyn/issues/56007")]
public void NullCoalesce()
{
var source = """
class Program
{
static int Main(int? x, int y) { return x ?? y; }
}
""";
var comp = CompileAndVerify(source);
comp.VerifyDiagnostics();
comp.VerifyIL("Program.Main", """
{
// Code size 9 (0x9)
.maxstack 2
IL_0000: ldarga.s V_0
IL_0002: ldarg.1
IL_0003: call "int int?.GetValueOrDefault(int)"
IL_0008: ret
}
""");
}
[Theory, WorkItem("https://github.com/dotnet/roslyn/issues/56007")]
[InlineData("ref")]
[InlineData("in")]
[InlineData("ref readonly")]
public void NullCoalesce_RefParameter(string refKeyword)
{
var source = $$"""
class Program
{
static int Main(int? x, {{refKeyword}} int y) { return x ?? y; }
}
""";
var comp = CompileAndVerify(source);
comp.VerifyDiagnostics();
// Dereferencing might throw, so no `GetValueOrDefault(defaultValue)` optimization here
comp.VerifyIL("Program.Main", """
{
// Code size 22 (0x16)
.maxstack 1
.locals init (int? V_0)
IL_0000: ldarg.0
IL_0001: stloc.0
IL_0002: ldloca.s V_0
IL_0004: call "bool int?.HasValue.get"
IL_0009: brtrue.s IL_000e
IL_000b: ldarg.1
IL_000c: ldind.i4
IL_000d: ret
IL_000e: ldloca.s V_0
IL_0010: call "int int?.GetValueOrDefault()"
IL_0015: ret
}
""");
}
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/56007")]
public void NullCoalesce_OutParameter()
{
var source = """
class Program
{
static int Main(int? x, out int y)
{
y = 0;
return x ?? y;
}
}
""";
var comp = CompileAndVerify(source);
comp.VerifyDiagnostics();
// Dereferencing might throw, so no `GetValueOrDefault(defaultValue)` optimization here
comp.VerifyIL("Program.Main", """
{
// Code size 25 (0x19)
.maxstack 2
.locals init (int? V_0)
IL_0000: ldarg.1
IL_0001: ldc.i4.0
IL_0002: stind.i4
IL_0003: ldarg.0
IL_0004: stloc.0
IL_0005: ldloca.s V_0
IL_0007: call "bool int?.HasValue.get"
IL_000c: brtrue.s IL_0011
IL_000e: ldarg.1
IL_000f: ldind.i4
IL_0010: ret
IL_0011: ldloca.s V_0
IL_0013: call "int int?.GetValueOrDefault()"
IL_0018: ret
}
""");
}
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/56007")]
public void NullCoalesce_Local()
{
var source = """
class Program
{
static int Main(int? x)
{
var y = 3;
var z = x ?? y;
return y + z;
}
}
""";
var comp = CompileAndVerify(source);
comp.VerifyDiagnostics();
comp.VerifyIL("Program.Main", """
{
// Code size 15 (0xf)
.maxstack 2
.locals init (int V_0, //y
int V_1) //z
IL_0000: ldc.i4.3
IL_0001: stloc.0
IL_0002: ldarga.s V_0
IL_0004: ldloc.0
IL_0005: call "int int?.GetValueOrDefault(int)"
IL_000a: stloc.1
IL_000b: ldloc.0
IL_000c: ldloc.1
IL_000d: add
IL_000e: ret
}
""");
}
[Theory, WorkItem("https://github.com/dotnet/roslyn/issues/56007")]
[InlineData("ref")]
[InlineData("ref readonly")]
public void NullCoalesce_RefLocal(string refKeyword)
{
var source = $$"""
class Program
{
static int Main(int? x, ref int y)
{
{{refKeyword}} int z = ref y;
return x ?? z;
}
}
""";
var comp = CompileAndVerify(source);
comp.VerifyDiagnostics();
// Dereferencing might throw, so no `GetValueOrDefault(defaultValue)` optimization here
comp.VerifyIL("Program.Main", """
{
// Code size 24 (0x18)
.maxstack 1
.locals init (int& V_0, //z
int? V_1)
IL_0000: ldarg.1
IL_0001: stloc.0
IL_0002: ldarg.0
IL_0003: stloc.1
IL_0004: ldloca.s V_1
IL_0006: call "bool int?.HasValue.get"
IL_000b: brtrue.s IL_0010
IL_000d: ldloc.0
IL_000e: ldind.i4
IL_000f: ret
IL_0010: ldloca.s V_1
IL_0012: call "int int?.GetValueOrDefault()"
IL_0017: ret
}
""");
}
[Fact]
public void TestCompoundOnAFieldOfGeneric()
{
var source = @"
class Program
{
static void Main(string[] args)
{
var x = new c0();
test<c0>.Repro1(x);
System.Console.WriteLine(x.x);
test<c0>.Repro2(x);
System.Console.WriteLine(x.x);
}
}
class c0
{
public int x;
public int P1
{
get { return x; }
set { x = value; }
}
public int this[int i]
{
get { return x; }
set { x = value; }
}
public static int Goo(c0 arg)
{
return 1;
}
public int Goo()
{
return 1;
}
}
class test<T> where T : c0
{
public static void Repro1(T arg)
{
arg.x += 1;
arg.P1 += 1;
arg[1] += 1;
}
public static void Repro2(T arg)
{
arg.x = c0.Goo(arg);
arg.x = arg.Goo();
}
}
";
var compilation = CompileAndVerify(source, expectedOutput: @"3
1");
compilation.VerifyIL("test<T>.Repro1(T)", @"
{
// Code size 88 (0x58)
.maxstack 4
.locals init (T& V_0)
IL_0000: ldarg.0
IL_0001: box ""T""
IL_0006: dup
IL_0007: ldfld ""int c0.x""
IL_000c: ldc.i4.1
IL_000d: add
IL_000e: stfld ""int c0.x""
IL_0013: ldarga.s V_0
IL_0015: stloc.0
IL_0016: ldloc.0
IL_0017: ldobj ""T""
IL_001c: box ""T""
IL_0021: ldloc.0
IL_0022: constrained. ""T""
IL_0028: callvirt ""int c0.P1.get""
IL_002d: ldc.i4.1
IL_002e: add
IL_002f: callvirt ""void c0.P1.set""
IL_0034: ldarga.s V_0
IL_0036: stloc.0
IL_0037: ldloc.0
IL_0038: ldobj ""T""
IL_003d: box ""T""
IL_0042: ldc.i4.1
IL_0043: ldloc.0
IL_0044: ldc.i4.1
IL_0045: constrained. ""T""
IL_004b: callvirt ""int c0.this[int].get""
IL_0050: ldc.i4.1
IL_0051: add
IL_0052: callvirt ""void c0.this[int].set""
IL_0057: ret
}
").VerifyIL("test<T>.Repro2(T)", @"
{
// Code size 45 (0x2d)
.maxstack 2
IL_0000: ldarg.0
IL_0001: box ""T""
IL_0006: ldarg.0
IL_0007: box ""T""
IL_000c: call ""int c0.Goo(c0)""
IL_0011: stfld ""int c0.x""
IL_0016: ldarg.0
IL_0017: box ""T""
IL_001c: ldarg.0
IL_001d: box ""T""
IL_0022: callvirt ""int c0.Goo()""
IL_0027: stfld ""int c0.x""
IL_002c: ret
}
");
}
[Fact()]
[WorkItem(4828, "https://github.com/dotnet/roslyn/issues/4828")]
public void OptimizeOutLocals_01()
{
const string source = @"
class Program
{
static void Main(string[] args)
{
int a = 0;
int b = a + a / 1;
}
}";
var result = CompileAndVerify(source, options: TestOptions.ReleaseExe);
result.VerifyIL("Program.Main",
@"
{
// Code size 5 (0x5)
.maxstack 2
IL_0000: ldc.i4.0
IL_0001: ldc.i4.1
IL_0002: div
IL_0003: pop
IL_0004: ret
}
");
}
[ConditionalFact(typeof(NoIOperationValidation))]
[WorkItem(5395, "https://github.com/dotnet/roslyn/issues/5395")]
public void EmitSequenceOfBinaryExpressions_01()
{
var source =
@"
class Test
{
static void Main()
{
var f = new long[4096];
for (int i = 0; i < 4096 ; i++)
{
f[i] = 4096 - i;
}
System.Console.WriteLine((Calculate1(f) == Calculate2(f)) ? ""True"" : ""False"");
}
public static long Calculate1(long[] f)
{
" + $" return {BuildSequenceOfBinaryExpressions_01()};" + @"
}
public static long Calculate2(long[] f)
{
long result = 0;
int i;
for (i = 0; i < f.Length; i++)
{
result+=(i + 1)*f[i];
}
return result + (i + 1);
}
}
";
var result = CompileAndVerify(source, options: TestOptions.ReleaseExe, expectedOutput: "True");
}
private static string BuildSequenceOfBinaryExpressions_01(int count = 4096)
{
var builder = new System.Text.StringBuilder();
int i;
for (i = 0; i < count; i++)
{
builder.Append(i + 1);
builder.Append(" * ");
builder.Append("f[");
builder.Append(i);
builder.Append("] + ");
}
builder.Append(i + 1);
return builder.ToString();
}
[ConditionalFact(typeof(NoIOperationValidation))]
[WorkItem(5395, "https://github.com/dotnet/roslyn/issues/5395")]
[WorkItem(63689, "https://github.com/dotnet/roslyn/issues/63689")]
public void EmitSequenceOfBinaryExpressions_02()
{
var source =
@"
class Test
{
static void Main()
{
var f = new long[4096];
for (int i = 0; i < 4096 ; i++)
{
f[i] = 4096 - i;
}
System.Console.WriteLine(Calculate(f));
}
public static double Calculate(long[] f)
{
" + $" return checked({BuildSequenceOfBinaryExpressions_01()});" + @"
}
}
";
var result = CompileAndVerify(source, options: TestOptions.ReleaseExe, expectedOutput: "11461640193");
var tree = result.Compilation.SyntaxTrees.Single();
var model = result.Compilation.GetSemanticModel(tree);
ControlFlowGraph.Create((IMethodBodyOperation)model.GetOperation(tree.GetRoot().DescendantNodes().OfType<MethodDeclarationSyntax>().Where(m => m.Identifier.ValueText == "Calculate").Single()));
}
[ConditionalFact(typeof(ClrOnly), typeof(NoIOperationValidation), Reason = "https://github.com/dotnet/roslyn/issues/29428")]
[WorkItem(6077, "https://github.com/dotnet/roslyn/issues/6077")]
[WorkItem(5395, "https://github.com/dotnet/roslyn/issues/5395")]
public void EmitSequenceOfBinaryExpressions_03()
{
var diagnostics = ImmutableArray<Diagnostic>.Empty;
const int start = 8192;
const int step = 4096;
const int limit = start * 4;
for (int count = start; count <= limit && diagnostics.IsEmpty; count += step)
{
var source =
@"
class Test
{
static void Main()
{
}
public static bool Calculate(bool[] a, bool[] f)
{
" + $" return {BuildSequenceOfBinaryExpressions_03(count)};" + @"
}
}
";
var compilation = CreateCompilation(source, options: TestOptions.ReleaseExe);
diagnostics = compilation.GetEmitDiagnostics();
}
diagnostics.Verify(
// (10,16): error CS8078: An expression is too long or complex to compile
// return a[0] & f[0] | a[1] & f[1] | a[2] & f[2] | ...
Diagnostic(ErrorCode.ERR_InsufficientStack, "a").WithLocation(10, 16)
);
}
private static string BuildSequenceOfBinaryExpressions_03(int count = 8192)
{
var builder = new System.Text.StringBuilder();
int i;
for (i = 0; i < count; i++)
{
builder.Append("a[");
builder.Append(i);
builder.Append(']');
builder.Append(" & ");
builder.Append("f[");
builder.Append(i);
builder.Append("] | ");
}
builder.Append("a[");
builder.Append(i);
builder.Append(']');
return builder.ToString();
}
[ConditionalFact(typeof(ClrOnly), typeof(NoIOperationValidation), Reason = "https://github.com/dotnet/roslyn/issues/29428")]
[WorkItem(5395, "https://github.com/dotnet/roslyn/issues/5395")]
public void EmitSequenceOfBinaryExpressions_04()
{
var source =
@"
class Test
{
static void Main()
{
var f = new float?[4096];
for (int i = 0; i < 4096 ; i++)
{
f[i] = 4096 - i;
}
System.Console.WriteLine(Calculate(f));
}
public static double? Calculate(float?[] f)
{
" + $" return {BuildSequenceOfBinaryExpressions_01()};" + @"
}
}
";
var compilation = CreateCompilation(source, options: TestOptions.ReleaseExe);
compilation.VerifyEmitDiagnostics(
// (17,16): error CS8078: An expression is too long or complex to compile
// return 1 * f[0] + 2 * f[1] + 3 * f[2] + 4 * f[3] + ...
Diagnostic(ErrorCode.ERR_InsufficientStack, "1").WithLocation(17, 16)
);
}
[ConditionalFact(typeof(NoIOperationValidation))]
[WorkItem(5395, "https://github.com/dotnet/roslyn/issues/5395")]
public void EmitSequenceOfBinaryExpressions_05()
{
int count = 50;
var source =
@"
class Test
{
static void Main()
{
Test1();
Test2();
}
static void Test1()
{
var f = new double?[" + $"{count}" + @"];
for (int i = 0; i < " + $"{count}" + @" ; i++)
{
f[i] = 4096 - i;
}
System.Console.WriteLine(Calculate(f));
}
public static double? Calculate(double?[] f)
{
" + $" return {BuildSequenceOfBinaryExpressions_01(count)};" + @"
}
static void Test2()
{
var f = new double[" + $"{count}" + @"];
for (int i = 0; i < " + $"{count}" + @" ; i++)
{
f[i] = 4096 - i;
}
System.Console.WriteLine(Calculate(f));
}
public static double Calculate(double[] f)
{
" + $" return {BuildSequenceOfBinaryExpressions_01(count)};" + @"
}
}
";
var result = CompileAndVerify(source, options: TestOptions.ReleaseExe, expectedOutput: @"5180801
5180801");
}
[ConditionalFact(typeof(ClrOnly), typeof(NoIOperationValidation), Reason = "https://github.com/dotnet/roslyn/issues/29428", AlwaysSkip = "https://github.com/dotnet/roslyn/issues/46361")]
[WorkItem(5395, "https://github.com/dotnet/roslyn/issues/5395")]
public void EmitSequenceOfBinaryExpressions_06()
{
var source =
@"
class Test
{
static void Main()
{
}
public static bool Calculate(S1[] a, S1[] f)
{
" + $" return {BuildSequenceOfBinaryExpressions_06()};" + @"
}
}
struct S1
{
public static S1 operator & (S1 x, S1 y)
{
return new S1();
}
public static S1 operator |(S1 x, S1 y)
{
return new S1();
}
public static bool operator true(S1 x)
{
return true;
}
public static bool operator false(S1 x)
{
return true;
}
public static implicit operator bool (S1 x)
{
return true;
}
}
";
var compilation = CreateCompilation(source, options: TestOptions.ReleaseExe);
compilation.VerifyEmitDiagnostics(
// (10,16): error CS8078: An expression is too long or complex to compile
// return a[0] && f[0] || a[1] && f[1] || a[2] && f[2] || ...
Diagnostic(ErrorCode.ERR_InsufficientStack, "a").WithLocation(10, 16)
);
}
private static string BuildSequenceOfBinaryExpressions_06(int count = 8192)
{
var builder = new System.Text.StringBuilder();
int i;
for (i = 0; i < count; i++)
{
builder.Append("a[");
builder.Append(i);
builder.Append(']');
builder.Append(" && ");
builder.Append("f[");
builder.Append(i);
builder.Append("] || ");
}
builder.Append("a[");
builder.Append(i);
builder.Append(']');
return builder.ToString();
}
[ConditionalFact(typeof(ClrOnly), typeof(NoIOperationValidation), Reason = "https://github.com/dotnet/roslyn/issues/29428")]
[WorkItem(63689, "https://github.com/dotnet/roslyn/issues/63689")]
public void EmitSequenceOfBinaryExpressions_07()
{
const int start = 1024;
const int step = 1024;
const int limit = start * 8;
bool passed = false;
for (int count = start; count <= limit; count += step)
{
var source =
@"
class Test
{
static void Main()
{
}
public static bool Calculate(S1[] a, S1[] f)
{
" + $" return {BuildSequenceOfBinaryExpressions_06(count)};" + @"
}
}
struct S1
{
public static S1 operator & (S1 x, S1 y)
{
return new S1();
}
public static S1 operator |(S1 x, S1 y)
{
return new S1();
}
public static bool operator true(S1 x)
{
return true;
}
public static bool operator false(S1 x)
{
return true;
}
public static implicit operator bool (S1 x)
{
return true;
}
}
";
var compilation = CreateCompilation(source, options: TestOptions.ReleaseExe);
var tree = compilation.SyntaxTrees.Single();
var model = compilation.GetSemanticModel(tree);
try
{
ControlFlowGraph.Create((IMethodBodyOperation)model.GetOperation(tree.GetRoot().DescendantNodes().OfType<MethodDeclarationSyntax>().Where(m => m.Identifier.ValueText == "Calculate").Single()));
}
catch (System.InsufficientExecutionStackException)
{
passed = true;
break;
}
}
Assert.True(passed);
}
[ConditionalFact(typeof(ClrOnly), typeof(NoIOperationValidation), Reason = "https://github.com/dotnet/roslyn/issues/29428")]
[WorkItem(63689, "https://github.com/dotnet/roslyn/issues/63689")]
public void EmitSequenceOfBinaryExpressions_08()
{
var source =
@"
class Test
{
static void Main()
{
}
public static bool Calculate(bool[] a, bool[] f)
{
" + $" return {BuildSequenceOfBinaryExpressions_06(2048)};" + @"
}
}
";
var compilation = CreateCompilation(source, options: TestOptions.ReleaseExe);
var tree = compilation.SyntaxTrees.Single();
var model = compilation.GetSemanticModel(tree);
ControlFlowGraph.Create((IMethodBodyOperation)model.GetOperation(tree.GetRoot().DescendantNodes().OfType<MethodDeclarationSyntax>().Where(m => m.Identifier.ValueText == "Calculate").Single()));
}
[Fact, WorkItem(7262, "https://github.com/dotnet/roslyn/issues/7262")]
public void TruncatePrecisionOnCast()
{
var source =
@"
class Test
{
static void Main()
{
float temp1 = (float)(23334800f / 5.5f);
System.Console.WriteLine((int)temp1);
const float temp2 = (float)(23334800f / 5.5f);
System.Console.WriteLine((int)temp2);
System.Console.WriteLine((int)(23334800f / 5.5f));
}
}
";
var expectedOutput =
@"4242691
4242691
4242691";
var result = CompileAndVerify(source, options: TestOptions.ReleaseExe, expectedOutput: expectedOutput);
}
[Fact, WorkItem(17756, "https://github.com/dotnet/roslyn/issues/17756")]
public void TestCoalesceNotLvalue()
{
var source = @"
class Program
{
struct S1
{
public int field;
public int Increment() => field++;
}
static void Main()
{
S1 v = default(S1);
v.Increment();
((S1?)null ?? v).Increment();
System.Console.WriteLine(v.field);
}
}
";
string expectedOutput = @"1";
CompileAndVerify(source, expectedOutput: expectedOutput);
}
[Fact]
public void TestNullCoalesce_NullableWithDefault_Optimization()
{
var source = @"
class Program
{
struct S
{
int _a;
System.Guid _b;
public S(int a, System.Guid b)
{
_a = a;
_b = b;
}
public override string ToString() => (_a, _b).ToString();
}
static int CoalesceInt32(int? x)
{
return x ?? 0;
}
static T CoalesceGeneric<T>(T? x) where T : struct
{
return x ?? default(T);
}
static (bool a, System.Guid b) CoalesceTuple((bool a, System.Guid b)? x)
{
return x ?? default((bool a, System.Guid b));
}
static S CoalesceUserStruct(S? x)
{
return x ?? default(S);
}
static S CoalesceStructWithImplicitConstructor(S? x)
{
return x ?? new S();
}
static void Main()
{
System.Console.WriteLine(CoalesceInt32(42));
System.Console.WriteLine(CoalesceInt32(null));
System.Console.WriteLine(CoalesceGeneric<System.Guid>(new System.Guid(""44ed2f0b-c2fa-4791-81f6-97222fffa466"")));
System.Console.WriteLine(CoalesceGeneric<System.Guid>(null));
System.Console.WriteLine(CoalesceTuple((true, new System.Guid(""1c95cef0-1aae-4adb-a43c-54b2e7c083a0""))));
System.Console.WriteLine(CoalesceTuple(null));
System.Console.WriteLine(CoalesceUserStruct(new S(42, new System.Guid(""8683f371-81b4-45f6-aaed-1c665b371594""))));
System.Console.WriteLine(CoalesceUserStruct(null));
System.Console.WriteLine(CoalesceStructWithImplicitConstructor(new S()));
System.Console.WriteLine(CoalesceStructWithImplicitConstructor(null));
}
}";
var expectedOutput =
@"42
0
44ed2f0b-c2fa-4791-81f6-97222fffa466
00000000-0000-0000-0000-000000000000
(True, 1c95cef0-1aae-4adb-a43c-54b2e7c083a0)
(False, 00000000-0000-0000-0000-000000000000)
(42, 8683f371-81b4-45f6-aaed-1c665b371594)
(0, 00000000-0000-0000-0000-000000000000)
(0, 00000000-0000-0000-0000-000000000000)
(0, 00000000-0000-0000-0000-000000000000)";
var comp = CompileAndVerify(source, expectedOutput: expectedOutput);
comp.VerifyIL("Program.CoalesceInt32", @"{
// Code size 8 (0x8)
.maxstack 1
IL_0000: ldarga.s V_0
IL_0002: call ""int int?.GetValueOrDefault()""
IL_0007: ret
}");
comp.VerifyIL("Program.CoalesceGeneric<T>", @"{
// Code size 8 (0x8)
.maxstack 1
IL_0000: ldarga.s V_0
IL_0002: call ""T T?.GetValueOrDefault()""
IL_0007: ret
}");
comp.VerifyIL("Program.CoalesceTuple", @"{
// Code size 8 (0x8)
.maxstack 1
IL_0000: ldarga.s V_0
IL_0002: call ""System.ValueTuple<bool, System.Guid> System.ValueTuple<bool, System.Guid>?.GetValueOrDefault()""
IL_0007: ret
}");
comp.VerifyIL("Program.CoalesceUserStruct", @"{
// Code size 8 (0x8)
.maxstack 1
IL_0000: ldarga.s V_0
IL_0002: call ""Program.S Program.S?.GetValueOrDefault()""
IL_0007: ret
}");
comp.VerifyIL("Program.CoalesceStructWithImplicitConstructor", @"{
// Code size 8 (0x8)
.maxstack 1
IL_0000: ldarga.s V_0
IL_0002: call ""Program.S Program.S?.GetValueOrDefault()""
IL_0007: ret
}");
}
[Fact]
public void TestNullCoalesce_NullableWithConvertedDefault_Optimization()
{
var source = @"
class Program
{
static (bool a, System.Guid b, string c) CoalesceDifferentTupleNames((bool a, System.Guid b, string c)? x)
{
return x ?? default((bool c, System.Guid d, string e));
}
static void Main()
{
System.Console.WriteLine(CoalesceDifferentTupleNames((true, new System.Guid(""533d4d3b-5013-461e-ae9e-b98eb593d761""), ""value"")));
System.Console.WriteLine(CoalesceDifferentTupleNames(null));
}
}";
var expectedOutput =
@"(True, 533d4d3b-5013-461e-ae9e-b98eb593d761, value)
(False, 00000000-0000-0000-0000-000000000000, )";
var comp = CompileAndVerify(source, expectedOutput: expectedOutput);
comp.VerifyIL("Program.CoalesceDifferentTupleNames", @"{
// Code size 8 (0x8)
.maxstack 1
IL_0000: ldarga.s V_0
IL_0002: call ""System.ValueTuple<bool, System.Guid, string> System.ValueTuple<bool, System.Guid, string>?.GetValueOrDefault()""
IL_0007: ret
}");
}
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/56007")]
public void TestNullCoalesce_NullableWithNonDefault()
{
var source = @"
class Program
{
static int CoalesceWithNonDefault1(int? x)
{
return x ?? 2;
}
static int CoalesceWithNonDefault2(int? x, int y)
{
return x ?? y;
}
static int? CoalesceWithNonDefault3(int? x, int? y)
{
return x ?? y;
}
static int? CoalesceWithNonDefault4(int? x)
{
return x ?? default(int?);
}
static void Main()
{
void WriteLine(object value) => System.Console.WriteLine(value?.ToString() ?? ""*null*"");
WriteLine(CoalesceWithNonDefault1(42));
WriteLine(CoalesceWithNonDefault1(null));
WriteLine(CoalesceWithNonDefault2(12, 34));
WriteLine(CoalesceWithNonDefault2(null, 34));
WriteLine(CoalesceWithNonDefault3(123, 456));
WriteLine(CoalesceWithNonDefault3(123, null));
WriteLine(CoalesceWithNonDefault3(null, 456));
WriteLine(CoalesceWithNonDefault3(null, null));
WriteLine(CoalesceWithNonDefault4(42));
WriteLine(CoalesceWithNonDefault4(null));
}
}";
var expectedOutput =
@"42
2
12
34
123
123
456
*null*
42
*null*";
var comp = CompileAndVerify(source, expectedOutput: expectedOutput);
comp.VerifyIL("Program.CoalesceWithNonDefault1", @"{
// Code size 9 (0x9)
.maxstack 2
IL_0000: ldarga.s V_0
IL_0002: ldc.i4.2
IL_0003: call ""int int?.GetValueOrDefault(int)""
IL_0008: ret
}");
comp.VerifyIL("Program.CoalesceWithNonDefault2", @"{
// Code size 9 (0x9)
.maxstack 2
IL_0000: ldarga.s V_0
IL_0002: ldarg.1
IL_0003: call ""int int?.GetValueOrDefault(int)""
IL_0008: ret
}");
comp.VerifyIL("Program.CoalesceWithNonDefault3", @"{
// Code size 15 (0xf)
.maxstack 1
.locals init (int? V_0)
IL_0000: ldarg.0
IL_0001: stloc.0
IL_0002: ldloca.s V_0
IL_0004: call ""bool int?.HasValue.get""
IL_0009: brtrue.s IL_000d
IL_000b: ldarg.1
IL_000c: ret
IL_000d: ldloc.0
IL_000e: ret
}");
comp.VerifyIL("Program.CoalesceWithNonDefault4", @"{
// Code size 23 (0x17)
.maxstack 1
.locals init (int? V_0,
int? V_1)
IL_0000: ldarg.0
IL_0001: stloc.0
IL_0002: ldloca.s V_0
IL_0004: call ""bool int?.HasValue.get""
IL_0009: brtrue.s IL_0015
IL_000b: ldloca.s V_1
IL_000d: initobj ""int?""
IL_0013: ldloc.1
IL_0014: ret
IL_0015: ldloc.0
IL_0016: ret
}");
}
[Fact]
public void TestNullCoalesce_NonNullableWithDefault_NoOptimization()
{
var source = @"
class Program
{
static string CoalesceNonNullableWithDefault(string x)
{
return x ?? default(string);
}
static void Main()
{
void WriteLine(object value) => System.Console.WriteLine(value?.ToString() ?? ""*null*"");
WriteLine(CoalesceNonNullableWithDefault(""value""));
WriteLine(CoalesceNonNullableWithDefault(null));
}
}";
var expectedOutput =
@"value
*null*";
var comp = CompileAndVerify(source, expectedOutput: expectedOutput);
comp.VerifyIL("Program.CoalesceNonNullableWithDefault", @"{
// Code size 7 (0x7)
.maxstack 2
IL_0000: ldarg.0
IL_0001: dup
IL_0002: brtrue.s IL_0006
IL_0004: pop
IL_0005: ldnull
IL_0006: ret
}");
}
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/56007")]
public void TestNullCoalesce_NullableDefault_MissingGetValueOrDefault()
{
var source = """
class Program
{
static int Coalesce(int? x)
{
return x ?? 0;
}
}
""";
var comp = CreateCompilation(source);
comp.MakeMemberMissing(SpecialMember.System_Nullable_T_GetValueOrDefault);
// We gracefully fallback to calling `GetValueOrDefault(defaultValue)` member
comp.VerifyEmitDiagnostics();
var verifier = CompileAndVerify(comp);
verifier.VerifyIL("Program.Coalesce", """
{
// Code size 9 (0x9)
.maxstack 2
IL_0000: ldarga.s V_0
IL_0002: ldc.i4.0
IL_0003: call "int int?.GetValueOrDefault(int)"
IL_0008: ret
}
""");
}
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/56007")]
public void TestNullCoalesce_NullableDefault_MissingGetValueOrDefaultAndGetValueOrDefaultWithADefaultValueParameter()
{
var source = """
class Program
{
static int Coalesce(int? x)
{
return x ?? 0;
}
}
""";
var comp = CreateCompilation(source);
comp.MakeMemberMissing(SpecialMember.System_Nullable_T_GetValueOrDefault);
comp.MakeMemberMissing(SpecialMember.System_Nullable_T_GetValueOrDefaultDefaultValue);
comp.VerifyEmitDiagnostics(
// (5,16): error CS0656: Missing compiler required member 'System.Nullable`1.GetValueOrDefault'
// return x ?? 0;
Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "x").WithArguments("System.Nullable`1", "GetValueOrDefault").WithLocation(5, 16)
);
}
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/56007")]
public void TestNullCoalesce_NullableNonDefaultConstant_MissingGetValueOrDefaultWithDefaultValue()
{
var source = """
class Program
{
static int Coalesce(int? x)
{
return x ?? 1;
}
}
""";
var comp = CreateCompilation(source);
comp.MakeMemberMissing(SpecialMember.System_Nullable_T_GetValueOrDefaultDefaultValue);
// We gracefully fallback to less efficient implementation with branching
comp.VerifyEmitDiagnostics();
var verifier = CompileAndVerify(comp);
verifier.VerifyIL("Program.Coalesce", """
{
// Code size 21 (0x15)
.maxstack 1
.locals init (int? V_0)
IL_0000: ldarg.0
IL_0001: stloc.0
IL_0002: ldloca.s V_0
IL_0004: call "bool int?.HasValue.get"
IL_0009: brtrue.s IL_000d
IL_000b: ldc.i4.1
IL_000c: ret
IL_000d: ldloca.s V_0
IL_000f: call "int int?.GetValueOrDefault()"
IL_0014: ret
}
""");
}
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/56007")]
public void TestNullCoalesce_NullableNonDefaultConstant_MissingGetValueOrDefaultAndGetValueOrDefaultWithADefaultValueParameter()
{
var source = """
class Program
{
static int Coalesce(int? x)
{
return x ?? 1;
}
}
""";
var comp = CreateCompilation(source);
comp.MakeMemberMissing(SpecialMember.System_Nullable_T_GetValueOrDefault);
comp.MakeMemberMissing(SpecialMember.System_Nullable_T_GetValueOrDefaultDefaultValue);
comp.VerifyEmitDiagnostics(
// (5,16): error CS0656: Missing compiler required member 'System.Nullable`1.GetValueOrDefault'
// return x ?? 1;
Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "x").WithArguments("System.Nullable`1", "GetValueOrDefault").WithLocation(5, 16)
);
}
[Fact]
public void TestNullCoalesce_UnconstrainedTypeParameter_OldLanguageVersion()
{
var source = @"
class C
{
void M<T>(T t1, T t2)
{
t1 = t1 ?? t2;
}
}";
var comp = CreateCompilation(source, parseOptions: TestOptions.Regular7_3);
comp.VerifyDiagnostics(
// (6,14): error CS8652: The feature 'unconstrained type parameters in null coalescing operator' is not available in C# 7.3. Please use language version 8.0 or greater.
// t1 = t1 ?? t2;
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7_3, "t1 ?? t2").WithArguments("unconstrained type parameters in null coalescing operator", "8.0").WithLocation(6, 14));
}
[Fact, WorkItem(41760, "https://github.com/dotnet/roslyn/issues/41760")]
public void NullableBoolOperatorSemantics_01()
{
// The C# specification has a section outlining the behavior of the bool operators `|` and `&`
// on operands of type `bool?`. We check that these are the semantics obeyed by the compiler.
var sourceStart = @"
using System;
public class C
{
bool T => true;
bool F => false;
static bool? True => true;
static bool? False => false;
static bool? Null => null;
static void Main()
{
C n = null;
C c = new C();
bool t = true;
bool f = false;
bool? nt = true;
bool? nf = false;
bool? nn = null;
";
var sourceEnd =
@" Console.WriteLine(""Done."");
}
static bool? And(bool? x, bool? y)
{
if (x == false || y == false)
return false;
if (x == null || y == null)
return null;
return true;
}
static bool? Or(bool? x, bool? y)
{
if (x == true || y == true)
return true;
if (x == null || y == null)
return null;
return false;
}
static bool? Xor(bool? x, bool? y)
{
if (x == null || y == null)
return null;
return x.Value != y.Value;
}
}
static class Assert
{
public static void Equal<T>(T expected, T actual, string message)
{
if (!object.Equals(expected, actual))
Console.WriteLine($""Wrong for {message,-15} Expected: {expected?.ToString() ?? ""null"",-5} Actual: {actual?.ToString() ?? ""null""}"");
}
}
";
var builder = new StringBuilder();
var forms = new string[]
{
"null",
"nn",
"true",
"t",
"nt",
"false",
"f",
"nf",
"c?.T",
"c?.F",
"n?.T",
"Null",
"True",
"False",
};
foreach (var left in forms)
{
foreach (var right in forms)
{
if (left == "null" && right == "null")
continue;
builder.AppendLine(@$" Assert.Equal<bool?>(Or({left}, {right}), {left} | {right}, ""{left} | {right}"");");
builder.AppendLine(@$" Assert.Equal<bool?>(And({left}, {right}), {left} & {right}, ""{left} & {right}"");");
if (left != "null" && right != "null")
builder.AppendLine(@$" Assert.Equal<bool?>(Xor({left}, {right}), {left} ^ {right}, ""{left} ^ {right}"");");
}
}
var source = sourceStart + builder.ToString() + sourceEnd;
var comp = CreateCompilation(source, options: TestOptions.ReleaseExe);
comp.VerifyDiagnostics(
);
CompileAndVerify(comp, expectedOutput: @"Done.");
}
[Fact, WorkItem(41760, "https://github.com/dotnet/roslyn/issues/41760")]
public void NullableBoolOperatorSemantics_02()
{
var source = @"
using System;
public class C
{
public bool BoolValue;
static void Main()
{
C obj = null;
Console.Write(obj?.BoolValue | true);
Console.Write(obj?.BoolValue & false);
}
}
";
var comp = CreateCompilation(source, options: TestOptions.ReleaseExe);
comp.VerifyDiagnostics(
);
var cv = CompileAndVerify(comp, expectedOutput: @"TrueFalse");
cv.VerifyIL("C.Main", @"
{
// Code size 99 (0x63)
.maxstack 3
.locals init (bool? V_0,
bool? V_1)
IL_0000: ldnull
IL_0001: dup
IL_0002: dup
IL_0003: brtrue.s IL_0011
IL_0005: pop
IL_0006: ldloca.s V_1
IL_0008: initobj ""bool?""
IL_000e: ldloc.1
IL_000f: br.s IL_001b
IL_0011: ldfld ""bool C.BoolValue""
IL_0016: newobj ""bool?..ctor(bool)""
IL_001b: stloc.0
IL_001c: ldc.i4.1
IL_001d: brtrue.s IL_0022
IL_001f: ldloc.0
IL_0020: br.s IL_0028
IL_0022: ldc.i4.1
IL_0023: newobj ""bool?..ctor(bool)""
IL_0028: box ""bool?""
IL_002d: call ""void System.Console.Write(object)""
IL_0032: dup
IL_0033: brtrue.s IL_0041
IL_0035: pop
IL_0036: ldloca.s V_1
IL_0038: initobj ""bool?""
IL_003e: ldloc.1
IL_003f: br.s IL_004b
IL_0041: ldfld ""bool C.BoolValue""
IL_0046: newobj ""bool?..ctor(bool)""
IL_004b: stloc.0
IL_004c: ldc.i4.0
IL_004d: brtrue.s IL_0057
IL_004f: ldc.i4.0
IL_0050: newobj ""bool?..ctor(bool)""
IL_0055: br.s IL_0058
IL_0057: ldloc.0
IL_0058: box ""bool?""
IL_005d: call ""void System.Console.Write(object)""
IL_0062: ret
}
");
}
[Fact, WorkItem(56376, "https://github.com/dotnet/roslyn/issues/56376")]
public void UserDefinedOperatorInGenericExpressionTree_01()
{
var code = @"
using System;
using System.Linq.Expressions;
namespace BadImageFormatExceptionRepro
{
class Program
{
private readonly struct Wrapper<T>
{
public static bool operator ==(T t, Wrapper<T> wrapper)
{
Console.WriteLine(t.ToString());
return true;
}
public static bool operator !=(T t, Wrapper<T> wrapper) => false;
}
static void Main()
{
GenericMethod(""Run"");
}
private static void GenericMethod<T>(T t) where T : class
{
Func<Expression<Func<T, Wrapper<T>, bool>>> func = () => (x, y) => x == y;
func().Compile()(t, default);
}
}
}";
var verifier = CompileAndVerify(code, expectedOutput: "Run");
verifier.VerifyDiagnostics(
// (9,33): warning CS0660: 'Program.Wrapper<T>' defines operator == or operator != but does not override Object.Equals(object o)
// private readonly struct Wrapper<T>
Diagnostic(ErrorCode.WRN_EqualityOpWithoutEquals, "Wrapper").WithArguments("BadImageFormatExceptionRepro.Program.Wrapper<T>").WithLocation(9, 33),
// (9,33): warning CS0661: 'Program.Wrapper<T>' defines operator == or operator != but does not override Object.GetHashCode()
// private readonly struct Wrapper<T>
Diagnostic(ErrorCode.WRN_EqualityOpWithoutGetHashCode, "Wrapper").WithArguments("BadImageFormatExceptionRepro.Program.Wrapper<T>").WithLocation(9, 33)
);
verifier.VerifyIL("BadImageFormatExceptionRepro.Program.<>c__2<T>.<GenericMethod>b__2_0()", @"
{
// Code size 90 (0x5a)
.maxstack 5
.locals init (System.Linq.Expressions.ParameterExpression V_0,
System.Linq.Expressions.ParameterExpression V_1)
IL_0000: ldtoken ""T""
IL_0005: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)""
IL_000a: ldstr ""x""
IL_000f: call ""System.Linq.Expressions.ParameterExpression System.Linq.Expressions.Expression.Parameter(System.Type, string)""
IL_0014: stloc.0
IL_0015: ldtoken ""BadImageFormatExceptionRepro.Program.Wrapper<T>""
IL_001a: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)""
IL_001f: ldstr ""y""
IL_0024: call ""System.Linq.Expressions.ParameterExpression System.Linq.Expressions.Expression.Parameter(System.Type, string)""
IL_0029: stloc.1
IL_002a: ldloc.0
IL_002b: ldloc.1
IL_002c: ldc.i4.0
IL_002d: ldtoken ""bool BadImageFormatExceptionRepro.Program.Wrapper<T>.op_Equality(T, BadImageFormatExceptionRepro.Program.Wrapper<T>)""
IL_0032: ldtoken ""BadImageFormatExceptionRepro.Program.Wrapper<T>""
IL_0037: call ""System.Reflection.MethodBase System.Reflection.MethodBase.GetMethodFromHandle(System.RuntimeMethodHandle, System.RuntimeTypeHandle)""
IL_003c: castclass ""System.Reflection.MethodInfo""
IL_0041: call ""System.Linq.Expressions.BinaryExpression System.Linq.Expressions.Expression.Equal(System.Linq.Expressions.Expression, System.Linq.Expressions.Expression, bool, System.Reflection.MethodInfo)""
IL_0046: ldc.i4.2
IL_0047: newarr ""System.Linq.Expressions.ParameterExpression""
IL_004c: dup
IL_004d: ldc.i4.0
IL_004e: ldloc.0
IL_004f: stelem.ref
IL_0050: dup
IL_0051: ldc.i4.1
IL_0052: ldloc.1
IL_0053: stelem.ref
IL_0054: call ""System.Linq.Expressions.Expression<System.Func<T, BadImageFormatExceptionRepro.Program.Wrapper<T>, bool>> System.Linq.Expressions.Expression.Lambda<System.Func<T, BadImageFormatExceptionRepro.Program.Wrapper<T>, bool>>(System.Linq.Expressions.Expression, params System.Linq.Expressions.ParameterExpression[])""
IL_0059: ret
}");
}
[Fact, WorkItem(56376, "https://github.com/dotnet/roslyn/issues/56376")]
public void UserDefinedOperatorInGenericExpressionTree_02()
{
var code = @"
using System;
using System.Linq.Expressions;
namespace BadImageFormatExceptionRepro
{
class Program
{
private readonly struct Wrapper<T>
{
public static Wrapper<T> operator +(Wrapper<T> wrapper)
{
Console.WriteLine(""Run"");
return wrapper;
}
}
static void Main()
{
GenericMethod<string>();
}
private static void GenericMethod<T>() where T : class
{
Func<Expression<Func<Wrapper<T>, Wrapper<T>>>> func = () => (x) => +x;
func().Compile()(default);
}
}
}";
var verifier = CompileAndVerify(code, expectedOutput: "Run");
verifier.VerifyDiagnostics();
verifier.VerifyIL("BadImageFormatExceptionRepro.Program.<>c__2<T>.<GenericMethod>b__2_0()", @"
{
// Code size 63 (0x3f)
.maxstack 5
.locals init (System.Linq.Expressions.ParameterExpression V_0)
IL_0000: ldtoken ""BadImageFormatExceptionRepro.Program.Wrapper<T>""
IL_0005: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)""
IL_000a: ldstr ""x""
IL_000f: call ""System.Linq.Expressions.ParameterExpression System.Linq.Expressions.Expression.Parameter(System.Type, string)""
IL_0014: stloc.0
IL_0015: ldloc.0
IL_0016: ldtoken ""BadImageFormatExceptionRepro.Program.Wrapper<T> BadImageFormatExceptionRepro.Program.Wrapper<T>.op_UnaryPlus(BadImageFormatExceptionRepro.Program.Wrapper<T>)""
IL_001b: ldtoken ""BadImageFormatExceptionRepro.Program.Wrapper<T>""
IL_0020: call ""System.Reflection.MethodBase System.Reflection.MethodBase.GetMethodFromHandle(System.RuntimeMethodHandle, System.RuntimeTypeHandle)""
IL_0025: castclass ""System.Reflection.MethodInfo""
IL_002a: call ""System.Linq.Expressions.UnaryExpression System.Linq.Expressions.Expression.UnaryPlus(System.Linq.Expressions.Expression, System.Reflection.MethodInfo)""
IL_002f: ldc.i4.1
IL_0030: newarr ""System.Linq.Expressions.ParameterExpression""
IL_0035: dup
IL_0036: ldc.i4.0
IL_0037: ldloc.0
IL_0038: stelem.ref
IL_0039: call ""System.Linq.Expressions.Expression<System.Func<BadImageFormatExceptionRepro.Program.Wrapper<T>, BadImageFormatExceptionRepro.Program.Wrapper<T>>> System.Linq.Expressions.Expression.Lambda<System.Func<BadImageFormatExceptionRepro.Program.Wrapper<T>, BadImageFormatExceptionRepro.Program.Wrapper<T>>>(System.Linq.Expressions.Expression, params System.Linq.Expressions.ParameterExpression[])""
IL_003e: ret
}");
}
[Fact, WorkItem(56376, "https://github.com/dotnet/roslyn/issues/56376")]
public void UserDefinedOperatorInGenericExpressionTree_03()
{
var code = @"
using System;
using System.Linq.Expressions;
namespace BadImageFormatExceptionRepro
{
class Program
{
static void Main()
{
GenericMethod<C>();
}
private static void GenericMethod<T>() where T : I<T>
{
Func<Expression<Func<T, T, bool>>> func = () => (x, y) => x == y;
func();
Console.WriteLine(""Run"");
}
}
interface I<T> where T : I<T>
{
public static abstract bool operator==(T t1, T t2);
public static abstract bool operator!=(T t1, T t2);
}
class C : I<C>
{
public static bool operator ==(C c1, C c2) => true;
public static bool operator !=(C c1, C c2) => false;
}
}";
var comp = CreateCompilation(code, parseOptions: TestOptions.RegularPreview, targetFramework: TargetFramework.Net60);
comp.VerifyDiagnostics(
// (16,71): error CS8927: An expression tree may not contain an access of static virtual or abstract interface member
// Func<Expression<Func<T, T, bool>>> func = () => (x, y) => x == y;
Diagnostic(ErrorCode.ERR_ExpressionTreeContainsAbstractStaticMemberAccess, "x == y").WithLocation(16, 71),
// (29,11): warning CS0660: 'C' defines operator == or operator != but does not override Object.Equals(object o)
// class C : I<C>
Diagnostic(ErrorCode.WRN_EqualityOpWithoutEquals, "C").WithArguments("BadImageFormatExceptionRepro.C").WithLocation(29, 11),
// (29,11): warning CS0661: 'C' defines operator == or operator != but does not override Object.GetHashCode()
// class C : I<C>
Diagnostic(ErrorCode.WRN_EqualityOpWithoutGetHashCode, "C").WithArguments("BadImageFormatExceptionRepro.C").WithLocation(29, 11)
);
}
[Fact, WorkItem(56376, "https://github.com/dotnet/roslyn/issues/56376")]
public void UserDefinedOperatorInGenericExpressionTree_04()
{
var code = @"
using System;
using System.Linq.Expressions;
namespace BadImageFormatExceptionRepro
{
class Program
{
static void Main()
{
GenericMethod<C>();
}
private static void GenericMethod<T>() where T : I<T>
{
Func<Expression<Func<T, T>>> func = () => (x) => +x;
func();
Console.WriteLine(""Run"");
}
}
interface I<T> where T : I<T>
{
public static abstract T operator+(T t);
}
class C : I<C>
{
public static C operator +(C c) => c;
}
}";
var comp = CreateCompilation(code, parseOptions: TestOptions.RegularPreview, targetFramework: TargetFramework.Net60);
comp.VerifyDiagnostics(
// (16,62): error CS8927: An expression tree may not contain an access of static virtual or abstract interface member
// Func<Expression<Func<T, T>>> func = () => (x) => +x;
Diagnostic(ErrorCode.ERR_ExpressionTreeContainsAbstractStaticMemberAccess, "+x").WithLocation(16, 62)
);
}
[Fact, WorkItem(56376, "https://github.com/dotnet/roslyn/issues/56376")]
public void UserDefinedOperatorInGenericExpressionTree_05()
{
var code = @"
using System;
using System.Linq.Expressions;
namespace BadImageFormatExceptionRepro
{
class Program
{
static void Main()
{
GenericMethod(""Run"");
}
private static void GenericMethod<T>(T t)
{
Func<Expression<Func<T, C<T>>>> func = () => x => x;
func().Compile()(t);
}
}
class C<T>
{
public static implicit operator C<T>(T t)
{
Console.WriteLine(t);
return default;
}
}
}
";
var verifier = CompileAndVerify(code, expectedOutput: "Run");
verifier.VerifyDiagnostics();
verifier.VerifyIL("BadImageFormatExceptionRepro.Program.<>c__1<T>.<GenericMethod>b__1_0()", @"
{
// Code size 73 (0x49)
.maxstack 5
.locals init (System.Linq.Expressions.ParameterExpression V_0)
IL_0000: ldtoken ""T""
IL_0005: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)""
IL_000a: ldstr ""x""
IL_000f: call ""System.Linq.Expressions.ParameterExpression System.Linq.Expressions.Expression.Parameter(System.Type, string)""
IL_0014: stloc.0
IL_0015: ldloc.0
IL_0016: ldtoken ""BadImageFormatExceptionRepro.C<T>""
IL_001b: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)""
IL_0020: ldtoken ""BadImageFormatExceptionRepro.C<T> BadImageFormatExceptionRepro.C<T>.op_Implicit(T)""
IL_0025: ldtoken ""BadImageFormatExceptionRepro.C<T>""
IL_002a: call ""System.Reflection.MethodBase System.Reflection.MethodBase.GetMethodFromHandle(System.RuntimeMethodHandle, System.RuntimeTypeHandle)""
IL_002f: castclass ""System.Reflection.MethodInfo""
IL_0034: call ""System.Linq.Expressions.UnaryExpression System.Linq.Expressions.Expression.Convert(System.Linq.Expressions.Expression, System.Type, System.Reflection.MethodInfo)""
IL_0039: ldc.i4.1
IL_003a: newarr ""System.Linq.Expressions.ParameterExpression""
IL_003f: dup
IL_0040: ldc.i4.0
IL_0041: ldloc.0
IL_0042: stelem.ref
IL_0043: call ""System.Linq.Expressions.Expression<System.Func<T, BadImageFormatExceptionRepro.C<T>>> System.Linq.Expressions.Expression.Lambda<System.Func<T, BadImageFormatExceptionRepro.C<T>>>(System.Linq.Expressions.Expression, params System.Linq.Expressions.ParameterExpression[])""
IL_0048: ret
}
");
}
[Fact, WorkItem(56376, "https://github.com/dotnet/roslyn/issues/56376")]
public void UserDefinedOperatorInGenericExpressionTree_06()
{
var code = @"
using System;
using System.Linq.Expressions;
namespace BadImageFormatExceptionRepro
{
class Program
{
static void Main()
{
GenericMethod(""Run"");
}
private static void GenericMethod<T>(T t)
{
Func<Expression<Func<T, C<T>>>> func = () => x => (C<T>)x;
func().Compile()(t);
}
}
class C<T>
{
public static explicit operator C<T>(T t)
{
Console.WriteLine(t);
return default;
}
}
}
";
var verifier = CompileAndVerify(code, expectedOutput: "Run");
verifier.VerifyDiagnostics();
verifier.VerifyIL("BadImageFormatExceptionRepro.Program.<>c__1<T>.<GenericMethod>b__1_0()", @"
{
// Code size 73 (0x49)
.maxstack 5
.locals init (System.Linq.Expressions.ParameterExpression V_0)
IL_0000: ldtoken ""T""
IL_0005: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)""
IL_000a: ldstr ""x""
IL_000f: call ""System.Linq.Expressions.ParameterExpression System.Linq.Expressions.Expression.Parameter(System.Type, string)""
IL_0014: stloc.0
IL_0015: ldloc.0
IL_0016: ldtoken ""BadImageFormatExceptionRepro.C<T>""
IL_001b: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)""
IL_0020: ldtoken ""BadImageFormatExceptionRepro.C<T> BadImageFormatExceptionRepro.C<T>.op_Explicit(T)""
IL_0025: ldtoken ""BadImageFormatExceptionRepro.C<T>""
IL_002a: call ""System.Reflection.MethodBase System.Reflection.MethodBase.GetMethodFromHandle(System.RuntimeMethodHandle, System.RuntimeTypeHandle)""
IL_002f: castclass ""System.Reflection.MethodInfo""
IL_0034: call ""System.Linq.Expressions.UnaryExpression System.Linq.Expressions.Expression.Convert(System.Linq.Expressions.Expression, System.Type, System.Reflection.MethodInfo)""
IL_0039: ldc.i4.1
IL_003a: newarr ""System.Linq.Expressions.ParameterExpression""
IL_003f: dup
IL_0040: ldc.i4.0
IL_0041: ldloc.0
IL_0042: stelem.ref
IL_0043: call ""System.Linq.Expressions.Expression<System.Func<T, BadImageFormatExceptionRepro.C<T>>> System.Linq.Expressions.Expression.Lambda<System.Func<T, BadImageFormatExceptionRepro.C<T>>>(System.Linq.Expressions.Expression, params System.Linq.Expressions.ParameterExpression[])""
IL_0048: ret
}
");
}
[Fact, WorkItem(56376, "https://github.com/dotnet/roslyn/issues/56376")]
public void UserDefinedOperatorInGenericExpressionTree_07()
{
var code = @"
using System;
using System.Linq.Expressions;
namespace BadImageFormatExceptionRepro
{
class Program
{
static void Main()
{
GenericMethod<string>();
}
private static void GenericMethod<T>()
{
Func<Expression<Func<C<T>, C<T>, C<T>>>> func = () => (x, y) => x && y;
func().Compile()(default, default);
}
}
class C<T>
{
public static bool operator false(C<T> c)
{
Console.Write(""1"");
return false;
}
public static bool operator true(C<T> c) => false;
public static C<T> operator &(C<T> c1, C<T> c2)
{
Console.Write(""2"");
return c1;
}
}
}
";
var verifier = CompileAndVerify(code, expectedOutput: "12");
verifier.VerifyDiagnostics();
verifier.VerifyIL("BadImageFormatExceptionRepro.Program.<>c__1<T>.<GenericMethod>b__1_0()", @"
{
// Code size 89 (0x59)
.maxstack 5
.locals init (System.Linq.Expressions.ParameterExpression V_0,
System.Linq.Expressions.ParameterExpression V_1)
IL_0000: ldtoken ""BadImageFormatExceptionRepro.C<T>""
IL_0005: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)""
IL_000a: ldstr ""x""
IL_000f: call ""System.Linq.Expressions.ParameterExpression System.Linq.Expressions.Expression.Parameter(System.Type, string)""
IL_0014: stloc.0
IL_0015: ldtoken ""BadImageFormatExceptionRepro.C<T>""
IL_001a: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)""
IL_001f: ldstr ""y""
IL_0024: call ""System.Linq.Expressions.ParameterExpression System.Linq.Expressions.Expression.Parameter(System.Type, string)""
IL_0029: stloc.1
IL_002a: ldloc.0
IL_002b: ldloc.1
IL_002c: ldtoken ""BadImageFormatExceptionRepro.C<T> BadImageFormatExceptionRepro.C<T>.op_BitwiseAnd(BadImageFormatExceptionRepro.C<T>, BadImageFormatExceptionRepro.C<T>)""
IL_0031: ldtoken ""BadImageFormatExceptionRepro.C<T>""
IL_0036: call ""System.Reflection.MethodBase System.Reflection.MethodBase.GetMethodFromHandle(System.RuntimeMethodHandle, System.RuntimeTypeHandle)""
IL_003b: castclass ""System.Reflection.MethodInfo""
IL_0040: call ""System.Linq.Expressions.BinaryExpression System.Linq.Expressions.Expression.AndAlso(System.Linq.Expressions.Expression, System.Linq.Expressions.Expression, System.Reflection.MethodInfo)""
IL_0045: ldc.i4.2
IL_0046: newarr ""System.Linq.Expressions.ParameterExpression""
IL_004b: dup
IL_004c: ldc.i4.0
IL_004d: ldloc.0
IL_004e: stelem.ref
IL_004f: dup
IL_0050: ldc.i4.1
IL_0051: ldloc.1
IL_0052: stelem.ref
IL_0053: call ""System.Linq.Expressions.Expression<System.Func<BadImageFormatExceptionRepro.C<T>, BadImageFormatExceptionRepro.C<T>, BadImageFormatExceptionRepro.C<T>>> System.Linq.Expressions.Expression.Lambda<System.Func<BadImageFormatExceptionRepro.C<T>, BadImageFormatExceptionRepro.C<T>, BadImageFormatExceptionRepro.C<T>>>(System.Linq.Expressions.Expression, params System.Linq.Expressions.ParameterExpression[])""
IL_0058: ret
}
");
}
[Fact, WorkItem(56376, "https://github.com/dotnet/roslyn/issues/56376")]
public void UserDefinedOperatorInGenericExpressionTree_08()
{
var code = @"
using System;
using System.Linq.Expressions;
namespace BadImageFormatExceptionRepro
{
class Program
{
static void Main()
{
GenericMethod<string>();
}
private static void GenericMethod<T>()
{
Func<Expression<Func<C<T>, C<T>, C<T>>>> func = () => (x, y) => x || y;
func().Compile()(default, default);
}
}
class C<T>
{
public static bool operator true(C<T> c)
{
Console.Write(""1"");
return false;
}
public static bool operator false(C<T> c) => false;
public static C<T> operator |(C<T> c1, C<T> c2)
{
Console.Write(""2"");
return c1;
}
}
}
";
var verifier = CompileAndVerify(code, expectedOutput: "12");
verifier.VerifyDiagnostics();
verifier.VerifyIL("BadImageFormatExceptionRepro.Program.<>c__1<T>.<GenericMethod>b__1_0()", @"
{
// Code size 89 (0x59)
.maxstack 5
.locals init (System.Linq.Expressions.ParameterExpression V_0,
System.Linq.Expressions.ParameterExpression V_1)
IL_0000: ldtoken ""BadImageFormatExceptionRepro.C<T>""
IL_0005: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)""
IL_000a: ldstr ""x""
IL_000f: call ""System.Linq.Expressions.ParameterExpression System.Linq.Expressions.Expression.Parameter(System.Type, string)""
IL_0014: stloc.0
IL_0015: ldtoken ""BadImageFormatExceptionRepro.C<T>""
IL_001a: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)""
IL_001f: ldstr ""y""
IL_0024: call ""System.Linq.Expressions.ParameterExpression System.Linq.Expressions.Expression.Parameter(System.Type, string)""
IL_0029: stloc.1
IL_002a: ldloc.0
IL_002b: ldloc.1
IL_002c: ldtoken ""BadImageFormatExceptionRepro.C<T> BadImageFormatExceptionRepro.C<T>.op_BitwiseOr(BadImageFormatExceptionRepro.C<T>, BadImageFormatExceptionRepro.C<T>)""
IL_0031: ldtoken ""BadImageFormatExceptionRepro.C<T>""
IL_0036: call ""System.Reflection.MethodBase System.Reflection.MethodBase.GetMethodFromHandle(System.RuntimeMethodHandle, System.RuntimeTypeHandle)""
IL_003b: castclass ""System.Reflection.MethodInfo""
IL_0040: call ""System.Linq.Expressions.BinaryExpression System.Linq.Expressions.Expression.OrElse(System.Linq.Expressions.Expression, System.Linq.Expressions.Expression, System.Reflection.MethodInfo)""
IL_0045: ldc.i4.2
IL_0046: newarr ""System.Linq.Expressions.ParameterExpression""
IL_004b: dup
IL_004c: ldc.i4.0
IL_004d: ldloc.0
IL_004e: stelem.ref
IL_004f: dup
IL_0050: ldc.i4.1
IL_0051: ldloc.1
IL_0052: stelem.ref
IL_0053: call ""System.Linq.Expressions.Expression<System.Func<BadImageFormatExceptionRepro.C<T>, BadImageFormatExceptionRepro.C<T>, BadImageFormatExceptionRepro.C<T>>> System.Linq.Expressions.Expression.Lambda<System.Func<BadImageFormatExceptionRepro.C<T>, BadImageFormatExceptionRepro.C<T>, BadImageFormatExceptionRepro.C<T>>>(System.Linq.Expressions.Expression, params System.Linq.Expressions.ParameterExpression[])""
IL_0058: ret
}
");
}
[Fact, WorkItem(56376, "https://github.com/dotnet/roslyn/issues/56376")]
public void UserDefinedOperatorInGenericExpressionTree_09()
{
var code = @"
using System;
using System.Linq.Expressions;
namespace BadImageFormatExceptionRepro
{
class Program
{
static void Main()
{
GenericMethod<C>();
}
private static void GenericMethod<T>() where T : I<T>
{
Func<Expression<Func<T, T, T>>> func = () => (x, y) => x && y;
func().Compile()(default, default);
}
}
public interface I<T> where T : I<T>
{
public static abstract bool operator true(T t);
public static abstract bool operator false(T t);
public static abstract T operator &(T t1, T t2);
}
class C : I<C>
{
public static bool operator false(C c)
{
Console.Write(""1"");
return false;
}
public static bool operator true(C c) => false;
public static C operator &(C c1, C c2)
{
Console.Write(""2"");
return c1;
}
}
}
";
var comp = CreateCompilation(code, parseOptions: TestOptions.RegularPreview, targetFramework: TargetFramework.Net60);
comp.VerifyDiagnostics(
// (16,68): error CS8927: An expression tree may not contain an access of static virtual or abstract interface member
// Func<Expression<Func<T, T, T>>> func = () => (x, y) => x && y;
Diagnostic(ErrorCode.ERR_ExpressionTreeContainsAbstractStaticMemberAccess, "x && y").WithLocation(16, 68)
);
}
[Fact, WorkItem(56376, "https://github.com/dotnet/roslyn/issues/56376")]
public void UserDefinedOperatorInGenericExpressionTree_10()
{
var code = @"
using System;
using System.Linq.Expressions;
namespace BadImageFormatExceptionRepro
{
class Program
{
static void Main()
{
GenericMethod<C>();
}
private static void GenericMethod<T>() where T : I<T>
{
Func<Expression<Func<T, T, T>>> func = () => (x, y) => x || y;
func().Compile()(default, default);
}
}
public interface I<T> where T : I<T>
{
public static abstract bool operator true(T t);
public static abstract bool operator false(T t);
public static abstract T operator |(T t1, T t2);
}
class C : I<C>
{
public static bool operator true(C c)
{
Console.Write(""1"");
return false;
}
public static bool operator false(C c) => false;
public static C operator |(C c1, C c2)
{
Console.Write(""2"");
return c1;
}
}
}
";
var comp = CreateCompilation(code, parseOptions: TestOptions.RegularPreview, targetFramework: TargetFramework.Net60);
comp.VerifyDiagnostics(
// (16,68): error CS8927: An expression tree may not contain an access of static virtual or abstract interface member
// Func<Expression<Func<T, T, T>>> func = () => (x, y) => x || y;
Diagnostic(ErrorCode.ERR_ExpressionTreeContainsAbstractStaticMemberAccess, "x || y").WithLocation(16, 68)
);
}
}
}
|