|
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
#nullable disable
using System;
using System.Linq;
using Microsoft.CodeAnalysis.CSharp.Symbols;
using Microsoft.CodeAnalysis.CSharp.Test.Utilities;
using Microsoft.CodeAnalysis.Test.Utilities;
using Roslyn.Test.Utilities;
using Xunit;
namespace Microsoft.CodeAnalysis.CSharp.UnitTests.CodeGen
{
public class CodeGenClosureLambdaTests : CSharpTestBase
{
[Fact]
public void LambdaInIndexerAndBinaryOperator()
{
var verifier = CompileAndVerify(@"
using System;
class C
{
private static Func<int> _f1;
private static Func<int> _f2;
public static void Main() {
var c = new C();
c[() => 0] += 1;
Console.WriteLine(object.ReferenceEquals(_f1, _f2));
}
int this[Func<int> f] {
get { _f1 = f; return 0; }
set { _f2 = f; }
}
}", expectedOutput: "True");
}
[Fact]
public void MethodGroupInIndexerAndBinaryOperator()
{
CompileAndVerify(@"
using System;
class C
{
private static Func<int> _f1;
private static Func<int> _f2;
public static void Main() {
var c = new C();
c[F] += 1;
Console.WriteLine(object.ReferenceEquals(_f1, _f2));
}
static int F() => 0;
public int this[Func<int> f] {
get { _f1 = f; return 0; }
set { _f2 = f; }
}
}", expectedOutput: "True");
}
[Fact]
public void EnvironmentChainContainsUnusedEnvironment()
{
CompileAndVerify(@"
using System;
class C
{
void M(int x)
{
{
int y = 10;
Action f1 = () => Console.WriteLine(y);
{
int z = 5;
Action f2 = () => Console.WriteLine(z + x);
f2();
}
f1();
}
}
public static void Main() => new C().M(3);
}", expectedOutput: @"8
10");
}
[Fact]
public void CaptureThisAsFramePointer()
{
var comp = @"
using System;
using System.Collections.Generic;
class C
{
int _z = 0;
void M(IEnumerable<int> xs)
{
foreach (var x in xs)
{
Func<int, int> captureFunc = k => x + _z;
}
}
}";
CompileAndVerify(comp);
}
[Fact]
public void StaticClosure01()
{
string source = @"using System;
delegate void D();
class C
{
public static void Main(string[] args)
{
D d1 = new D(() => Console.Write(1));
d1();
D d2 = () => Console.WriteLine(2);
d2();
}
}";
var compilation = CompileAndVerify(source, expectedOutput: @"12");
compilation.VerifyIL("C.Main",
@"
{
// Code size 73 (0x49)
.maxstack 2
IL_0000: ldsfld ""D C.<>c.<>9__0_0""
IL_0005: dup
IL_0006: brtrue.s IL_001f
IL_0008: pop
IL_0009: ldsfld ""C.<>c C.<>c.<>9""
IL_000e: ldftn ""void C.<>c.<Main>b__0_0()""
IL_0014: newobj ""D..ctor(object, System.IntPtr)""
IL_0019: dup
IL_001a: stsfld ""D C.<>c.<>9__0_0""
IL_001f: callvirt ""void D.Invoke()""
IL_0024: ldsfld ""D C.<>c.<>9__0_1""
IL_0029: dup
IL_002a: brtrue.s IL_0043
IL_002c: pop
IL_002d: ldsfld ""C.<>c C.<>c.<>9""
IL_0032: ldftn ""void C.<>c.<Main>b__0_1()""
IL_0038: newobj ""D..ctor(object, System.IntPtr)""
IL_003d: dup
IL_003e: stsfld ""D C.<>c.<>9__0_1""
IL_0043: callvirt ""void D.Invoke()""
IL_0048: ret
}
");
}
[Fact]
public void ThisOnlyClosure()
{
string source = @"using System;
delegate void D();
class C
{
public static void Main(string[] args)
{
new C().M();
}
int n = 1;
int m = 2;
public void M()
{
for (int i = 0; i < 2; i++)
{
D d1 = new D(() => Console.Write(n));
d1();
D d2 = () => Console.WriteLine(m);
d2();
}
}
}";
var compilation = CompileAndVerify(source, expectedOutput: @"12
12");
compilation.VerifyIL("C.M",
@"{
// Code size 47 (0x2f)
.maxstack 2
.locals init (int V_0) //i
IL_0000: ldc.i4.0
IL_0001: stloc.0
IL_0002: br.s IL_002a
IL_0004: ldarg.0
IL_0005: ldftn ""void C.<M>b__3_0()""
IL_000b: newobj ""D..ctor(object, System.IntPtr)""
IL_0010: callvirt ""void D.Invoke()""
IL_0015: ldarg.0
IL_0016: ldftn ""void C.<M>b__3_1()""
IL_001c: newobj ""D..ctor(object, System.IntPtr)""
IL_0021: callvirt ""void D.Invoke()""
IL_0026: ldloc.0
IL_0027: ldc.i4.1
IL_0028: add
IL_0029: stloc.0
IL_002a: ldloc.0
IL_002b: ldc.i4.2
IL_002c: blt.s IL_0004
IL_002e: ret
}");
}
[Fact]
public void StaticClosure02()
{
string source = @"using System;
delegate void D();
class C
{
public static void Main(string[] args)
{
new C().F();
}
void F()
{
D d1 = () => Console.WriteLine(1);
d1();
}
}";
CompileAndVerify(source, expectedOutput: "1");
}
[Fact]
public void StaticClosure03()
{
string source = @"using System;
delegate int D(int x);
class Program
{
static void Main(string[] args)
{
int @string = 10;
D d = delegate (int @class)
{
return @class + @string;
};
Console.WriteLine(d(2));
}
} ";
var compilation = CompileAndVerify(source, expectedOutput: @"12");
}
[Fact]
public void InstanceClosure01()
{
string source = @"using System;
delegate void D();
class C
{
int X;
C(int x)
{
this.X = x;
}
public static void Main(string[] args)
{
new C(12).F();
}
void F()
{
D d1 = () => Console.WriteLine(X);
d1();
}
}";
CompileAndVerify(source, expectedOutput: "12");
}
[Fact]
public void InstanceClosure02()
{
string source = @"using System;
delegate void D();
class C
{
int X;
C(int x)
{
this.X = x;
}
public static void Main(string[] args)
{
new C(12).F();
}
void F()
{
D d1 = () => {
C c = this;
Console.WriteLine(c.X);
};
d1();
}
}";
CompileAndVerify(source, expectedOutput: "12");
}
[Fact]
public void InstanceClosure03()
{
string source = @"using System;
delegate void D();
class C
{
int X;
C(int x)
{
this.X = x;
}
public static void Main(string[] args)
{
new C(12).F();
}
void F()
{
C c = this;
D d1 = () => {
Console.WriteLine(c.X);
};
d1();
}
}";
CompileAndVerify(source, expectedOutput: "12");
}
[Fact]
public void InstanceClosure04()
{
string source = @"using System;
delegate void D();
class C
{
int X;
C(int x)
{
this.X = x;
}
public static void Main(string[] args)
{
F(new C(12));
}
static void F(C c)
{
D d1 = () =>
{
Console.WriteLine(c.X);
};
d1();
}
}";
CompileAndVerify(source, expectedOutput: "12");
}
[Fact]
public void InstanceClosure05()
{
string source = @"using System;
delegate void D();
class C
{
int X;
C(int x)
{
this.X = x;
}
public static void Main(string[] args)
{
{
C c = new C(12);
D d = () => {
Console.WriteLine(c.X);
};
d();
}
{
C c = new C(13);
D d = () => {
Console.WriteLine(c.X);
};
d();
}
}
}";
CompileAndVerify(source, expectedOutput: @"
12
13
");
}
[Fact]
public void InstanceClosure06()
{
string source = @"using System;
delegate void D();
class C
{
int K = 11;
public static void Main(string[] args)
{
new C().F();
}
void F()
{
int i = 12;
D d1 = () =>
{
Console.WriteLine(K);
Console.WriteLine(i);
};
d1();
}
}";
CompileAndVerify(source, expectedOutput: @"
11
12
");
}
[Fact]
public void LoopClosure01()
{
string source = @"using System;
delegate void D();
class C
{
public static void Main(string[] args)
{
D d1 = null, d2 = null;
int i = 0;
while (i < 10)
{
int j = i;
if (i == 5)
{
d1 = () => Console.WriteLine(j);
d2 = () => Console.WriteLine(i);
}
i = i + 1;
}
d1();
d2();
}
}";
CompileAndVerify(source, expectedOutput: @"
5
10
");
}
[Fact]
public void NestedClosure01()
{
string source = @"using System;
delegate void D();
class C
{
public static void Main(string[] args)
{
int i = 12;
D d1 = () =>
{
D d2 = () =>
{
Console.WriteLine(i);
};
d2();
};
d1();
}
}";
CompileAndVerify(source, expectedOutput: @"12");
}
[Fact]
public void NestedClosure02()
{
string source = @"using System;
delegate void D();
class C
{
int K = 11;
public static void Main(string[] args)
{
new C().F();
}
void F()
{
int i = 12;
D d1 = () =>
{
D d2 = () =>
{
Console.WriteLine(K);
Console.WriteLine(i);
};
d2();
};
d1();
}
}";
CompileAndVerify(source, expectedOutput: @"
11
12
");
}
[Fact]
public void NestedClosure10()
{
string source = @"using System;
delegate void D();
class C
{
public static void Main(string[] args)
{
int i = 12;
D d1 = () =>
{
int j = 13;
D d2 = () =>
{
Console.WriteLine(i);
Console.WriteLine(j);
};
d2();
};
d1();
}
}";
CompileAndVerify(source, expectedOutput: @"
12
13
");
}
[Fact]
public void NestedClosure11()
{
string source = @"using System;
delegate void D();
class C
{
int K = 11;
public static void Main(string[] args)
{
new C().F();
}
void F()
{
int i = 12;
D d1 = () =>
{
int j = 13;
D d2 = () =>
{
Console.WriteLine(K);
Console.WriteLine(i);
Console.WriteLine(j);
};
d2();
};
d1();
}
}";
CompileAndVerify(source, expectedOutput: @"
11
12
13
");
}
[Fact]
public void NestedClosure20()
{
string source = @"using System;
delegate void D();
class C
{
public static void Main(string[] args)
{
int i = 12;
D d1 = () =>
{
int j = i + 1;
D d2 = () =>
{
Console.WriteLine(i);
Console.WriteLine(j);
};
d2();
};
d1();
}
}";
CompileAndVerify(source, expectedOutput: @"
12
13
");
}
[Fact]
public void NestedClosure21()
{
string source = @"using System;
delegate void D();
class C
{
int K = 11;
public static void Main(string[] args)
{
new C().F();
}
void F()
{
int i = 12;
D d1 = () =>
{
int j = i + 1;
D d2 = () =>
{
Console.WriteLine(K);
Console.WriteLine(i);
Console.WriteLine(j);
};
d2();
};
d1();
}
}";
CompileAndVerify(source, expectedOutput: @"
11
12
13
");
}
[WorkItem(540146, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/540146")]
[Fact]
public void NestedClosureThisConstructorInitializer()
{
string source = @"using System;
delegate void D();
delegate void D1(int i);
class C
{
public int l = 15;
public C():this((int i) =>
{
int k = 14;
D d15 = () =>
{
int j = 13;
D d2 = () =>
{
Console.WriteLine(i);
Console.WriteLine(j);
Console.WriteLine(k);
};
d2();
};
d15();
})
{func((int i) =>
{
int k = 14;
D d15 = () =>
{
int j = 13;
D d2 = () =>
{
Console.WriteLine(i);
Console.WriteLine(j);
Console.WriteLine(k);
Console.WriteLine(l);
};
d2();
};
d15();
});
}
public C(D1 d1){int i=12; d1(i);}
public void func(D1 d1)
{
int i=12;d1(i);
}
public static void Main(string[] args)
{
new C();
}
}";
CompileAndVerify(source, expectedOutput: @"
12
13
14
12
13
14
15
");
}
[Fact]
public void FilterParameterClosure01()
{
string source = @"
using System;
class Program
{
static void Main()
{
string s = ""xxx"";
try
{
throw new Exception(""xxx"");
}
catch (Exception e) when (new Func<Exception, bool>(x => x.Message == s)(e))
{
Console.Write(""pass"");
}
}
}";
CompileAndVerify(source, expectedOutput: "pass");
}
[Fact]
public void FilterParameterClosure02()
{
string source = @"
using System;
class Program
{
static void Main()
{
string s = ""xxx"";
try
{
throw new Exception(""xxx"");
}
catch (Exception e) when (new Func<Exception, bool>(x => x.Message == s)(e))
{
Console.Write(s + ""pass"");
}
}
}";
CompileAndVerify(source, expectedOutput: "xxxpass");
}
[WorkItem(541258, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/541258")]
[Fact]
public void CatchVarLifted1()
{
string source = @"using System;
class Program
{
static void Main()
{
Action a = null;
try
{
throw new Exception(""pass"");
}
catch (Exception e)
{
a = () => Console.Write(e.Message);
}
a();
}
}";
var verifier = CompileAndVerify(source, expectedOutput: "pass");
verifier.VerifyIL("Program.Main", @"
{
// Code size 49 (0x31)
.maxstack 2
.locals init (System.Action V_0, //a
Program.<>c__DisplayClass0_0 V_1, //CS$<>8__locals0
System.Exception V_2)
IL_0000: ldnull
IL_0001: stloc.0
.try
{
IL_0002: ldstr ""pass""
IL_0007: newobj ""System.Exception..ctor(string)""
IL_000c: throw
}
catch System.Exception
{
IL_000d: newobj ""Program.<>c__DisplayClass0_0..ctor()""
IL_0012: stloc.1
IL_0013: stloc.2
IL_0014: ldloc.1
IL_0015: ldloc.2
IL_0016: stfld ""System.Exception Program.<>c__DisplayClass0_0.e""
IL_001b: ldloc.1
IL_001c: ldftn ""void Program.<>c__DisplayClass0_0.<Main>b__0()""
IL_0022: newobj ""System.Action..ctor(object, System.IntPtr)""
IL_0027: stloc.0
IL_0028: leave.s IL_002a
}
IL_002a: ldloc.0
IL_002b: callvirt ""void System.Action.Invoke()""
IL_0030: ret
}
");
}
[Fact]
public void CatchVarLifted2()
{
var source = @"
using System;
class Program
{
static bool Goo(Action x)
{
x();
return true;
}
static void Main()
{
try
{
throw new Exception(""fail"");
}
catch (Exception ex) when (Goo(() => { ex = new Exception(""pass""); }))
{
Console.Write(ex.Message);
}
}
}";
var verifier = CompileAndVerify(source, expectedOutput: "pass");
verifier.VerifyIL("Program.Main", @"
{
// Code size 79 (0x4f)
.maxstack 2
.locals init (Program.<>c__DisplayClass1_0 V_0, //CS$<>8__locals0
System.Exception V_1)
.try
{
IL_0000: ldstr ""fail""
IL_0005: newobj ""System.Exception..ctor(string)""
IL_000a: throw
}
filter
{
IL_000b: isinst ""System.Exception""
IL_0010: dup
IL_0011: brtrue.s IL_0017
IL_0013: pop
IL_0014: ldc.i4.0
IL_0015: br.s IL_0039
IL_0017: newobj ""Program.<>c__DisplayClass1_0..ctor()""
IL_001c: stloc.0
IL_001d: stloc.1
IL_001e: ldloc.0
IL_001f: ldloc.1
IL_0020: stfld ""System.Exception Program.<>c__DisplayClass1_0.ex""
IL_0025: ldloc.0
IL_0026: ldftn ""void Program.<>c__DisplayClass1_0.<Main>b__0()""
IL_002c: newobj ""System.Action..ctor(object, System.IntPtr)""
IL_0031: call ""bool Program.Goo(System.Action)""
IL_0036: ldc.i4.0
IL_0037: cgt.un
IL_0039: endfilter
} // end filter
{ // handler
IL_003b: pop
IL_003c: ldloc.0
IL_003d: ldfld ""System.Exception Program.<>c__DisplayClass1_0.ex""
IL_0042: callvirt ""string System.Exception.Message.get""
IL_0047: call ""void System.Console.Write(string)""
IL_004c: leave.s IL_004e
}
IL_004e: ret
}
");
}
[Fact]
public void CatchVarLifted2a()
{
var source = @"
using System;
class Program
{
static bool Goo(Action x)
{
x();
return true;
}
static void Main()
{
try
{
throw new Exception(""fail"");
}
catch (ArgumentException ex) when (Goo(() => { ex = new ArgumentException(""fail""); }))
{
Console.Write(ex.Message);
}
catch (Exception ex) when (Goo(() => { ex = new Exception(""pass""); }))
{
Console.Write(ex.Message);
}
}
}";
var verifier = CompileAndVerify(source, expectedOutput: "pass");
}
[Fact]
public void CatchVarLifted3()
{
string source = @"
using System;
class Program
{
static void Main()
{
try
{
throw new Exception(""xxx"");
}
catch (Exception e) when (new Func<bool>(() => e.Message == ""xxx"")())
{
Console.Write(""pass"");
}
}
}";
var verifier = CompileAndVerify(source, expectedOutput: "pass");
verifier.VerifyIL("Program.Main", @"
{
// Code size 73 (0x49)
.maxstack 2
.locals init (Program.<>c__DisplayClass0_0 V_0, //CS$<>8__locals0
System.Exception V_1)
.try
{
IL_0000: ldstr ""xxx""
IL_0005: newobj ""System.Exception..ctor(string)""
IL_000a: throw
}
filter
{
IL_000b: isinst ""System.Exception""
IL_0010: dup
IL_0011: brtrue.s IL_0017
IL_0013: pop
IL_0014: ldc.i4.0
IL_0015: br.s IL_0039
IL_0017: newobj ""Program.<>c__DisplayClass0_0..ctor()""
IL_001c: stloc.0
IL_001d: stloc.1
IL_001e: ldloc.0
IL_001f: ldloc.1
IL_0020: stfld ""System.Exception Program.<>c__DisplayClass0_0.e""
IL_0025: ldloc.0
IL_0026: ldftn ""bool Program.<>c__DisplayClass0_0.<Main>b__0()""
IL_002c: newobj ""System.Func<bool>..ctor(object, System.IntPtr)""
IL_0031: callvirt ""bool System.Func<bool>.Invoke()""
IL_0036: ldc.i4.0
IL_0037: cgt.un
IL_0039: endfilter
} // end filter
{ // handler
IL_003b: pop
IL_003c: ldstr ""pass""
IL_0041: call ""void System.Console.Write(string)""
IL_0046: leave.s IL_0048
}
IL_0048: ret
}
");
}
[Fact]
public void CatchVarLifted_Generic1()
{
string source = @"
using System;
using System.IO;
class Program
{
static void Main()
{
F<IOException>();
}
static void F<T>() where T : Exception
{
new Action(() =>
{
try
{
throw new IOException(""xxx"");
}
catch (T e) when (e.Message == ""xxx"")
{
Console.Write(""pass"");
}
})();
}
}";
var verifier = CompileAndVerify(source, expectedOutput: "pass");
verifier.VerifyIL("Program.<>c__1<T>.<F>b__1_0", @"
{
// Code size 67 (0x43)
.maxstack 2
.try
{
IL_0000: ldstr ""xxx""
IL_0005: newobj ""System.IO.IOException..ctor(string)""
IL_000a: throw
}
filter
{
IL_000b: isinst ""T""
IL_0010: dup
IL_0011: brtrue.s IL_0017
IL_0013: pop
IL_0014: ldc.i4.0
IL_0015: br.s IL_0033
IL_0017: unbox.any ""T""
IL_001c: box ""T""
IL_0021: callvirt ""string System.Exception.Message.get""
IL_0026: ldstr ""xxx""
IL_002b: call ""bool string.op_Equality(string, string)""
IL_0030: ldc.i4.0
IL_0031: cgt.un
IL_0033: endfilter
} // end filter
{ // handler
IL_0035: pop
IL_0036: ldstr ""pass""
IL_003b: call ""void System.Console.Write(string)""
IL_0040: leave.s IL_0042
}
IL_0042: ret
}
");
}
[Fact]
public void CatchVarLifted_Generic2()
{
string source = @"
using System;
using System.IO;
class Program
{
static void Main()
{
F<IOException>();
}
static void F<T>() where T : Exception
{
string x = ""x"";
new Action(() =>
{
string y = ""y"";
try
{
throw new IOException(""xy"");
}
catch (T e) when (new Func<bool>(() => e.Message == x + y)())
{
Console.Write(""pass_"" + x + y);
}
})();
}
}";
var verifier = CompileAndVerify(source, expectedOutput: "pass_xy");
verifier.VerifyIL("Program.<>c__DisplayClass1_0<T>.<F>b__0", @"
{
// Code size 113 (0x71)
.maxstack 3
.locals init (Program.<>c__DisplayClass1_1<T> V_0, //CS$<>8__locals0
T V_1)
IL_0000: newobj ""Program.<>c__DisplayClass1_1<T>..ctor()""
IL_0005: stloc.0
IL_0006: ldloc.0
IL_0007: ldarg.0
IL_0008: stfld ""Program.<>c__DisplayClass1_0<T> Program.<>c__DisplayClass1_1<T>.CS$<>8__locals1""
IL_000d: ldloc.0
IL_000e: ldstr ""y""
IL_0013: stfld ""string Program.<>c__DisplayClass1_1<T>.y""
.try
{
IL_0018: ldstr ""xy""
IL_001d: newobj ""System.IO.IOException..ctor(string)""
IL_0022: throw
}
filter
{
IL_0023: isinst ""T""
IL_0028: dup
IL_0029: brtrue.s IL_002f
IL_002b: pop
IL_002c: ldc.i4.0
IL_002d: br.s IL_0050
IL_002f: unbox.any ""T""
IL_0034: stloc.1
IL_0035: ldloc.0
IL_0036: ldloc.1
IL_0037: stfld ""T Program.<>c__DisplayClass1_1<T>.e""
IL_003c: ldloc.0
IL_003d: ldftn ""bool Program.<>c__DisplayClass1_1<T>.<F>b__1()""
IL_0043: newobj ""System.Func<bool>..ctor(object, System.IntPtr)""
IL_0048: callvirt ""bool System.Func<bool>.Invoke()""
IL_004d: ldc.i4.0
IL_004e: cgt.un
IL_0050: endfilter
} // end filter
{ // handler
IL_0052: pop
IL_0053: ldstr ""pass_""
IL_0058: ldarg.0
IL_0059: ldfld ""string Program.<>c__DisplayClass1_0<T>.x""
IL_005e: ldloc.0
IL_005f: ldfld ""string Program.<>c__DisplayClass1_1<T>.y""
IL_0064: call ""string string.Concat(string, string, string)""
IL_0069: call ""void System.Console.Write(string)""
IL_006e: leave.s IL_0070
}
IL_0070: ret
}
");
}
[Fact]
public void CatchVarLifted_Generic3()
{
string source = @"
using System;
using System.IO;
class Program
{
static void Main()
{
F<IOException>();
}
static void F<T>() where T : Exception
{
string x = ""x"";
new Action(() =>
{
string y = ""y"";
try
{
throw new IOException(""a"");
}
catch (T e1) when (new Func<bool>(() =>
{
string z = ""z"";
try
{
throw new IOException(""xyz"");
}
catch (T e2) when (e2.Message == x + y + z)
{
return true;
}
})())
{
Console.Write(""pass_"" + x + y);
}
})();
}
}";
var verifier = CompileAndVerify(source, expectedOutput: "pass_xy");
}
[Fact]
public void ForeachParameterClosure01()
{
string source = @"using System;
using System.Collections.Generic;
delegate void D();
class C
{
public static void Main(string[] args)
{
List<string> list = new List<string>(new string[] {""A"", ""B""});
D d = null;
foreach (string s in list)
{
if (s == ""A"")
{
d = () =>
{
Console.WriteLine(s);
};
}
}
d();
}
}";
// Dev10 prints B, but we have intentionally changed the scope
// of the loop variable.
CompileAndVerify(source, expectedOutput: "A");
}
[Fact]
public void LambdaParameterClosure01()
{
string source = @"using System;
delegate void D0();
delegate void D1(string s);
class C
{
public static void Main(string[] args)
{
D0 d0 = null;
D1 d1 = (string s) =>
{
d0 = () =>
{
Console.WriteLine(s);
};
};
d1(""goo"");
d0();
}
}";
CompileAndVerify(source, expectedOutput: "goo");
}
[Fact]
public void BaseInvocation01()
{
string source = @"using System;
class B
{
public virtual void F()
{
Console.WriteLine(""base"");
}
}
class C : B
{
public override void F()
{
Console.WriteLine(""derived"");
}
void Main()
{
base.F();
}
public static void Main(string[] args)
{
new C().Main();
}
}";
CompileAndVerify(source, expectedOutput: "base");
}
[Fact]
public void BaseInvocationClosure01()
{
string source = @"using System;
delegate void D();
class B
{
public virtual void F()
{
Console.WriteLine(""base"");
}
}
class C : B
{
public override void F()
{
Console.WriteLine(""derived"");
}
void Main()
{
D d = () =>
{
base.F();
};
d();
}
public static void Main(string[] args)
{
new C().Main();
}
}";
CompileAndVerify(source, expectedOutput: "base");
}
[Fact]
public void BaseInvocationClosure02()
{
string source = @"using System;
delegate void D();
class B
{
public virtual void F()
{
Console.WriteLine(""base"");
}
}
class C : B
{
public override void F()
{
Console.WriteLine(""derived"");
}
void Main(int x)
{
D d = () =>
{
x = x + 1;
base.F();
};
d();
}
public static void Main(string[] args)
{
new C().Main(3);
}
}";
CompileAndVerify(source, expectedOutput: "base");
}
[Fact]
public void BaseInvocationClosure03()
{
string source = @"using System;
delegate void D();
class B
{
public virtual void F()
{
Console.WriteLine(""base"");
}
}
class C : B
{
public override void F()
{
Console.WriteLine(""derived"");
}
void Main(int x)
{
D d = base.F;
d();
}
public static void Main(string[] args)
{
new C().Main(3);
}
}";
CompileAndVerify(source, expectedOutput: "base");
}
[Fact]
public void BaseAccessInClosure_01()
{
string source = @"using System;
static class M1
{
class B1
{
public virtual string F()
{
return ""B1::F"";
}
}
class B2 : B1
{
public override string F()
{
return ""B2::F"";
}
public void TestThis()
{
var s = ""this: "";
Func<string> f = () => s + this.F();
Console.WriteLine(f());
}
public void TestBase()
{
var s = ""base: "";
Func<string> f = () => s + base.F();
Console.WriteLine(f());
}
}
class D : B2
{
public override string F()
{
return ""D::F"";
}
}
static void Main()
{
(new D()).TestThis();
(new D()).TestBase();
}
}
";
CompileAndVerify(source, expectedOutput: $"this: D::F{Environment.NewLine}base: B1::F");
}
[Fact]
public void BaseAccessInClosure_02()
{
string source = @"using System;
static class M1
{
class B1
{
public virtual string F()
{
return ""B1::F"";
}
}
class B1a : B1
{
}
class B2 : B1a
{
public override string F()
{
return ""B2::F"";
}
public void TestThis()
{
var s = ""this: "";
Func<string> f = () => s + this.F();
Console.WriteLine(f());
}
public void TestBase()
{
var s = ""base: "";
Func<string> f = () => s + base.F();
Console.WriteLine(f());
}
}
class D : B2
{
public override string F()
{
return ""D::F"";
}
}
static void Main()
{
(new D()).TestThis();
(new D()).TestBase();
}
}
";
CompileAndVerify(source, expectedOutput: $"this: D::F{Environment.NewLine}base: B1::F");
}
[Fact]
public void BaseAccessInClosure_03_WithILCheck()
{
string source = @"using System;
static class M1
{
class B1
{
public virtual string F()
{
return ""B1::F"";
}
}
class B1a : B1
{
}
class B2 : B1a
{
public override string F()
{
return ""B2::F"";
}
public void TestBase()
{
Func<string> f = () => base.F();
Console.WriteLine(f());
}
}
class D : B2
{
public override string F()
{
return ""D::F"";
}
}
static void Main()
{
(new D()).TestBase();
}
}
";
CompileAndVerify(source, expectedOutput: "B1::F").
VerifyIL("M1.B2.<TestBase>b__1_0",
@"{
// Code size 7 (0x7)
.maxstack 1
IL_0000: ldarg.0
IL_0001: call ""string M1.B1.F()""
IL_0006: ret
}");
}
[Fact]
public void BaseAccessInClosure_03a_WithILCheck()
{
string source = @"using System;
static class M1
{
class B1
{
public virtual string F()
{
return ""B1::F"";
}
}
class B1a : B1
{
public override string F()
{
return ""B1a::F"";
}
}
class B2 : B1a
{
public override string F()
{
return ""B2::F"";
}
public void TestBase()
{
Func<string> f = () => base.F();
Console.WriteLine(f());
}
}
class D : B2
{
public override string F()
{
return ""D::F"";
}
}
static void Main()
{
(new D()).TestBase();
}
}
";
CompileAndVerify(source, expectedOutput: "B1a::F").
VerifyIL("M1.B2.<TestBase>b__1_0",
@"{
// Code size 7 (0x7)
.maxstack 1
IL_0000: ldarg.0
IL_0001: call ""string M1.B1a.F()""
IL_0006: ret
}");
}
[Fact]
public void BaseAccessInClosure_04()
{
string source = @"using System;
static class M1
{
class B1
{
public virtual string F()
{
return ""B1::F"";
}
}
class B2 : B1
{
public override string F()
{
return ""B2::F"";
}
public void TestThis()
{
Func<string> f = this.F;
Console.WriteLine(f());
}
public void TestBase()
{
Func<string> f = base.F;
Console.WriteLine(f());
}
}
class D : B2
{
public override string F()
{
return ""D::F"";
}
}
static void Main()
{
(new D()).TestThis();
(new D()).TestBase();
}
}
";
CompileAndVerify(source, expectedOutput: $"D::F{Environment.NewLine}B1::F");
}
[Fact]
public void BaseAccessInClosure_05()
{
string source = @"using System;
static class M1
{
class B1
{
public virtual string F()
{
return ""B1::F"";
}
}
class B2 : B1
{
public override string F()
{
return ""B2::F"";
}
public void TestThis()
{
Func<Func<string>> f = () => this.F;
Console.WriteLine(f()());
}
public void TestBase()
{
Func<Func<string>> f = () => base.F;
Console.WriteLine(f()());
}
}
class D : B2
{
public override string F()
{
return ""D::F"";
}
}
static void Main()
{
(new D()).TestThis();
(new D()).TestBase();
}
}
";
CompileAndVerify(source, expectedOutput: $"D::F{Environment.NewLine}B1::F");
}
[Fact]
public void BaseAccessInClosure_06()
{
string source = @"using System;
static class M1
{
class B1
{
public virtual string F()
{
return ""B1::F"";
}
}
class B2 : B1
{
public override string F()
{
return ""B2::F"";
}
public void TestThis()
{
int s = 0;
Func<Func<string>> f = () => { s++; return this.F; };
Console.WriteLine(f()());
}
public void TestBase()
{
int s = 0;
Func<Func<string>> f = () => { s++; return base.F; };
Console.WriteLine(f()());
}
}
class D : B2
{
public override string F()
{
return ""D::F"";
}
}
static void Main()
{
(new D()).TestThis();
(new D()).TestBase();
}
}
";
CompileAndVerify(source, expectedOutput: $"D::F{Environment.NewLine}B1::F");
}
[Fact]
public void BaseAccessInClosure_07()
{
string source = @"using System;
static class M1
{
class B1
{
public virtual string F
{
get { Console.Write(""B1::F.Get;""); return null; }
set { Console.Write(""B1::F.Set;""); }
}
}
class B2 : B1
{
public override string F
{
get { Console.Write(""B2::F.Get;""); return null; }
set { Console.Write(""B2::F.Set;""); }
}
public void Test()
{
int s = 0;
Action f = () => { s++; this.F = base.F; base.F = this.F; };
f();
}
}
class D : B2
{
public override string F
{
get { Console.Write(""D::F.Get;""); return null; }
set { Console.Write(""F::F.Set;""); }
}
}
static void Main()
{
(new D()).Test();
}
}";
CompileAndVerify(source, expectedOutput: "B1::F.Get;F::F.Set;D::F.Get;B1::F.Set;");
}
[Fact]
public void BaseAccessInClosure_08()
{
string source = @"using System;
static class M1
{
class B1
{
public virtual void F<T>(T t)
{
Console.Write(""B1::F;"");
}
}
class B2 : B1
{
public override void F<T>(T t)
{
Console.Write(""B2::F;"");
}
public void Test()
{
int s = 0;
Action f = () => { s++; this.F<int>(0); base.F<string>(""""); };
f();
}
}
class D : B2
{
public override void F<T>(T t)
{
Console.Write(""D::F;"");
}
}
static void Main()
{
(new D()).Test();
}
}";
CompileAndVerify(source, expectedOutput: "D::F;B1::F;");
}
[Fact]
public void BaseAccessInClosure_09()
{
string source = @"using System;
static class M1
{
class B1
{
public virtual void F<T>(T t)
{
Console.Write(""B1::F;"");
}
}
class B2 : B1
{
public override void F<T>(T t)
{
Console.Write(""B2::F;"");
}
public void Test()
{
int s = 0;
Func<Action<int>> f1 = () => { s++; return base.F<int>; };
f1()(0);
Func<Action<string>> f2 = () => { s++; return this.F<string>; };
f2()(null);
}
}
class D : B2
{
public override void F<T>(T t)
{
Console.Write(""D::F;"");
}
}
static void Main()
{
(new D()).Test();
}
}";
CompileAndVerify(source, expectedOutput: "B1::F;D::F;");
}
[Fact]
public void BaseAccessInClosure_10()
{
string source = @"using System;
static class M1
{
class B1<T>
{
public virtual void F<U>(T t, U u)
{
Console.Write(""B1::F;"");
}
}
class B2<T> : B1<T>
{
public override void F<U>(T t, U u)
{
Console.Write(""B2::F;"");
}
public void Test()
{
int s = 0;
Func<Action<T, int>> f1 = () => { s++; return base.F<int>; };
f1()(default(T), 0);
Func<Action<T, string>> f2 = () => { s++; return this.F<string>; };
f2()(default(T), null);
}
}
class D<T> : B2<T>
{
public override void F<U>(T t, U u)
{
Console.Write(""D::F;"");
}
}
static void Main()
{
(new D<int>()).Test();
}
}";
CompileAndVerify(source, expectedOutput: "B1::F;D::F;");
}
[Fact]
public void BaseAccessInClosure_11()
{
string source = @"using System;
static class M1
{
class B1<T>
{
public virtual void F<U>(T t, U u)
{
Console.Write(""B1::F;"");
}
}
class Outer<V>
{
public class B2 : B1<V>
{
public override void F<U>(V t, U u)
{
Console.Write(""B2::F;"");
}
public void Test()
{
int s = 0;
Func<Action<V, int>> f1 = () => { s++; return base.F<int>; };
f1()(default(V), 0);
Func<Action<V, string>> f2 = () => { s++; return this.F<string>; };
f2()(default(V), null);
}
}
}
class D<X> : Outer<X>.B2
{
public override void F<U>(X t, U u)
{
Console.Write(""D::F;"");
}
}
static void Main()
{
(new D<int>()).Test();
}
}";
CompileAndVerify(source, expectedOutput: "B1::F;D::F;");
}
[Fact]
public void BaseAccessInClosure_12()
{
string source = @"using System;
static class M1
{
public class Outer<T>
{
public class B1
{
public virtual string F1(T t)
{
return ""B1::F1;"";
}
public virtual string F2(T t)
{
return ""B1::F2;"";
}
}
}
public class B2 : Outer<int>.B1
{
public override string F1(int t)
{
return ""B2::F2;"";
}
public void Test()
{
int s = 0;
Func<string> f1 = () => new Func<int, string>(this.F1)(s) + new Func<int, string>(base.F1)(s);
Func<string> f2 = () => new Func<int, string>(this.F2)(s) + new Func<int, string>(base.F2)(s);
Console.WriteLine(f1() + f2());
}
}
class D : B2
{
public override string F1(int t)
{
return ""D::F2;"";
}
public override string F2(int t)
{
return ""D::F2;"";
}
}
static void Main()
{
(new D()).Test();
}
}
";
CompileAndVerify(source, expectedOutput: "D::F2;B1::F1;D::F2;B1::F2;");
}
[Fact]
public void BaseAccessInClosure_13()
{
string source = @"using System;
static class M1
{
interface I{}
class B1<T>
where T : I
{
public virtual void F<U>(T t, U u) where U : struct, T
{
Console.Write(""B1::F;"");
}
}
class Outer<V>
where V : struct, I
{
public class B2 : B1<V>
{
public override void F<U>(V t, U u)
{
Console.Write(""B2::F;"");
}
public void Test()
{
int s = 0;
Func<Action<V, V>> f1 = () => { s++; return base.F<V>; };
f1()(default(V), default(V));
Func<Action<V, V>> f2 = () => { s++; return this.F<V>; };
f2()(default(V), default(V));
}
}
}
class D<X> : Outer<X>.B2
where X : struct, I
{
public override void F<U>(X t, U u)
{
Console.Write(""D::F;"");
}
}
struct C : I { }
static void Main()
{
(new D<C>()).Test();
}
}";
CompileAndVerify(source, expectedOutput: "B1::F;D::F;");
}
[Fact]
public void BaseAccessInClosure_14_WithILCheck()
{
string source = @"using System;
static class M1
{
public class Outer<T>
{
public class B1
{
public virtual string F<U>(T t, U u)
{
return ""B1:F"";
}
}
}
public class B2 : Outer<int>.B1
{
public override string F<U>(int t, U u)
{
return ""B2:F"";
}
public void Test()
{
int s = 0;
Func<string> f1 = () => new Func<int, int, string>(base.F<int>)(s, s);
Console.WriteLine(f1());
}
}
static void Main()
{
(new B2()).Test();
}
}";
CompileAndVerify(source,
expectedOutput: @"B1:F"
).
VerifyIL("M1.B2.<>n__0<U>",
@"{
// Code size 9 (0x9)
.maxstack 3
IL_0000: ldarg.0
IL_0001: ldarg.1
IL_0002: ldarg.2
IL_0003: call ""string M1.Outer<int>.B1.F<U>(int, U)""
IL_0008: ret
}");
}
[Fact]
public void BaseAccessInClosure_15_WithILCheck()
{
string source = @"using System;
static class M1
{
public interface I { }
public interface II : I { }
public class C : II { public C() { } }
public class Outer<T>
where T : I, new()
{
public class B1
{
public virtual string F<U>(T t, U u)
where U : T, new()
{
return ""B1::F;"";
}
}
}
public class B2 : Outer<C>.B1
{
public override string F<U>(C t, U u)
{
return ""B2::F;"";
}
public void Test()
{
C s = new C();
Func<string> f1 = () => new Func<C, C, string>(base.F)(s, s);
Console.WriteLine(f1());
}
}
static void Main()
{
(new B2()).Test();
}
}";
CompileAndVerify(source,
expectedOutput: @"B1::F;"
).
VerifyIL("M1.B2.<>c__DisplayClass1_0.<Test>b__0",
@"{
// Code size 35 (0x23)
.maxstack 3
IL_0000: ldarg.0
IL_0001: ldfld ""M1.B2 M1.B2.<>c__DisplayClass1_0.<>4__this""
IL_0006: ldftn ""string M1.B2.<>n__0<M1.C>(M1.C, M1.C)""
IL_000c: newobj ""System.Func<M1.C, M1.C, string>..ctor(object, System.IntPtr)""
IL_0011: ldarg.0
IL_0012: ldfld ""M1.C M1.B2.<>c__DisplayClass1_0.s""
IL_0017: ldarg.0
IL_0018: ldfld ""M1.C M1.B2.<>c__DisplayClass1_0.s""
IL_001d: callvirt ""string System.Func<M1.C, M1.C, string>.Invoke(M1.C, M1.C)""
IL_0022: ret
}").
VerifyIL("M1.B2.<>n__0<U>",
@"{
// Code size 9 (0x9)
.maxstack 3
IL_0000: ldarg.0
IL_0001: ldarg.1
IL_0002: ldarg.2
IL_0003: call ""string M1.Outer<M1.C>.B1.F<U>(M1.C, U)""
IL_0008: ret
}");
}
[Fact]
public void BaseAccessInClosure_16()
{
string source = @"using System;
using System.Runtime.InteropServices;
using System.Reflection;
using System.Runtime.CompilerServices;
static class M1
{
public interface I { }
public interface II : I { }
public class C : II { public C() { } }
public class Outer<T>
where T : I, new()
{
public class B1
{
public virtual string F<U>(T t, U u)
where U : I, T, new()
{
return ""B1::F;"";
}
}
}
public class B2 : Outer<C>.B1
{
public override string F<U>(C t, U u)
{
return ""B2::F;"";
}
public void Test()
{
C s = new C();
Func<string> f1 = () => new Func<C, C, string>(base.F)(s, s);
Console.WriteLine(f1());
}
}
static void Main()
{
var type = (new B2()).GetType();
var method = type.GetMethod(""<>n__0"", BindingFlags.NonPublic | BindingFlags.Instance);
Console.WriteLine(Attribute.IsDefined(method, typeof(CompilerGeneratedAttribute)));
Console.WriteLine(method.IsPrivate);
Console.WriteLine(method.IsVirtual);
Console.WriteLine(method.IsGenericMethod);
var genericDef = method.GetGenericMethodDefinition();
var arguments = genericDef.GetGenericArguments();
Console.WriteLine(arguments.Length);
var arg0 = arguments[0];
GenericParameterAttributes attributes = arg0.GenericParameterAttributes;
Console.WriteLine(attributes.ToString());
var arg0constraints = arg0.GetGenericParameterConstraints();
Console.WriteLine(arg0constraints.Length);
Console.WriteLine(arg0constraints[0]);
Console.WriteLine(arg0constraints[1]);
}
}";
CompileAndVerify(source,
expectedOutput: @"
True
True
False
True
1
DefaultConstructorConstraint
2
M1+I
M1+C"
);
}
[Fact]
public void BaseAccessInClosure_17_WithILCheck()
{
string source = @"using System;
class Base<T>
{
public virtual void Func<U>(T t, U u)
{
Console.Write(typeof (T));
Console.Write("" "");
Console.Write(typeof (U));
}
public class Derived : Base<int>
{
public void Test()
{
int i = 0;
T t = default(T);
Action d = () => { base.Func<T>(i, t); };
d();
}
}
}
class Program
{
static void Main()
{
new Base<string>.Derived().Test();
}
}
";
CompileAndVerify(source,
expectedOutput: "System.Int32 System.String"
).
VerifyIL("Base<T>.Derived.<>n__0<U>",
@"{
// Code size 9 (0x9)
.maxstack 3
IL_0000: ldarg.0
IL_0001: ldarg.1
IL_0002: ldarg.2
IL_0003: call ""void Base<int>.Func<U>(int, U)""
IL_0008: ret
}");
}
[Fact]
public void BaseAccessInClosure_18_WithILCheck()
{
string source = @"using System;
class Base
{
public void F(int i) { Console.Write(""Base::F;""); }
}
class Derived : Base
{
public new void F(int i) { Console.Write(""Derived::F;""); }
public void Test()
{
int j = 0;
Action a = () => { base.F(j); this.F(j); };
a();
}
static void Main(string[] args)
{
new Derived().Test();
}
}
";
CompileAndVerify(source,
expectedOutput: "Base::F;Derived::F;"
).
VerifyIL("Derived.<>c__DisplayClass1_0.<Test>b__0",
@"
{
// Code size 35 (0x23)
.maxstack 2
IL_0000: ldarg.0
IL_0001: ldfld ""Derived Derived.<>c__DisplayClass1_0.<>4__this""
IL_0006: ldarg.0
IL_0007: ldfld ""int Derived.<>c__DisplayClass1_0.j""
IL_000c: call ""void Base.F(int)""
IL_0011: ldarg.0
IL_0012: ldfld ""Derived Derived.<>c__DisplayClass1_0.<>4__this""
IL_0017: ldarg.0
IL_0018: ldfld ""int Derived.<>c__DisplayClass1_0.j""
IL_001d: call ""void Derived.F(int)""
IL_0022: ret
}");
}
[Fact]
public void BaseAccessInClosure_19_WithILCheck()
{
string source = @"using System;
class Base
{
public void F(int i) { Console.Write(""Base::F;""); }
}
class Derived : Base
{
public new void F(int i) { Console.Write(""Derived::F;""); }
public void Test()
{
int j = 0;
Action a = () => { Action<int> b = base.F; b(j); };
a();
}
static void Main(string[] args)
{
new Derived().Test();
}
}
";
CompileAndVerify(source,
expectedOutput: "Base::F;"
).
VerifyIL("Derived.<>c__DisplayClass1_0.<Test>b__0",
@"{
// Code size 29 (0x1d)
.maxstack 2
IL_0000: ldarg.0
IL_0001: ldfld ""Derived Derived.<>c__DisplayClass1_0.<>4__this""
IL_0006: ldftn ""void Base.F(int)""
IL_000c: newobj ""System.Action<int>..ctor(object, System.IntPtr)""
IL_0011: ldarg.0
IL_0012: ldfld ""int Derived.<>c__DisplayClass1_0.j""
IL_0017: callvirt ""void System.Action<int>.Invoke(int)""
IL_001c: ret
}");
}
[Fact]
public void BaseAccessInClosure_20_WithILCheck()
{
string source = @"using System;
class Base
{
public void F(int i) { Console.Write(""Base::F;""); }
}
class Derived : Base
{
public new void F(int i) { Console.Write(""Derived::F;""); }
public void Test()
{
int j = 0;
Action a = () => { Action<int> b = new Action<int>(base.F); b(j); };
a();
}
static void Main(string[] args)
{
new Derived().Test();
}
}
";
CompileAndVerify(source,
expectedOutput: "Base::F;"
).
VerifyIL("Derived.<>c__DisplayClass1_0.<Test>b__0",
@"{
// Code size 29 (0x1d)
.maxstack 2
IL_0000: ldarg.0
IL_0001: ldfld ""Derived Derived.<>c__DisplayClass1_0.<>4__this""
IL_0006: ldftn ""void Base.F(int)""
IL_000c: newobj ""System.Action<int>..ctor(object, System.IntPtr)""
IL_0011: ldarg.0
IL_0012: ldfld ""int Derived.<>c__DisplayClass1_0.j""
IL_0017: callvirt ""void System.Action<int>.Invoke(int)""
IL_001c: ret
}");
}
[Fact]
public void UnsafeInvocationClosure01()
{
string source = @"using System;
delegate void D();
class C
{
static unsafe void F()
{
D d = () =>
{
Console.WriteLine(""F"");
};
d();
}
public static void Main(string[] args)
{
D d = () =>
{
F();
};
d();
}
}";
CompileAndVerify(source, options: TestOptions.UnsafeReleaseExe, expectedOutput: "F", verify: Verification.Passes);
}
[Fact]
public void LambdaWithParameters01()
{
var source = @"
delegate void D(int x);
class LWP
{
public static void Main(string[] args)
{
D d1 = x => {
System.Console.Write(x);
};
d1(123);
}
}
";
CompileAndVerify(source, expectedOutput: "123");
}
[Fact]
public void LambdaWithParameters02()
{
var source = @"
delegate void D(int x);
class LWP
{
public static void Main(string[] args)
{
int local;
D d1 = x => {
local = 12;
System.Console.Write(x);
};
d1(123);
}
}
";
CompileAndVerify(source, expectedOutput: "123");
}
[Fact]
public void LambdaWithParameters03()
{
var source = @"
delegate void D(int x);
class LWP
{
void M()
{
D d1 = x => {
System.Console.Write(x);
};
d1(123);
}
public static void Main(string[] args)
{
new LWP().M();
}
}
";
CompileAndVerify(source, expectedOutput: "123");
}
[Fact]
public void LambdaWithParameters04()
{
var source = @"
delegate void D(int x);
class LWP
{
void M()
{
int local;
D d1 = x => {
local = 2;
System.Console.Write(x);
};
d1(123);
}
public static void Main(string[] args)
{
new LWP().M();
}
}
";
CompileAndVerify(source, expectedOutput: "123");
}
[Fact]
public void CapturedLambdaParameter01()
{
var source = @"
delegate D D(int x);
class CLP
{
public static void Main(string[] args)
{
D d1 = x => y => z => {
System.Console.Write(x + y + z);
return null;
};
d1(100)(20)(3);
}
}
";
CompileAndVerify(source, expectedOutput: "123");
}
[Fact]
public void CapturedLambdaParameter02()
{
var source = @"
delegate D D(int x);
class CLP
{
void M()
{
D d1 = x => y => z => {
System.Console.Write(x + y + z);
return null;
};
d1(100)(20)(3);
}
public static void Main(string[] args)
{
new CLP().M();
}
}
";
CompileAndVerify(source, expectedOutput: "123");
}
[Fact]
public void CapturedLambdaParameter03()
{
var source = @"
delegate D D(int x);
class CLP
{
public static void Main(string[] args)
{
int K = 4000;
D d1 = x => y => z => {
System.Console.Write(x + y + z + K);
return null;
};
d1(100)(20)(3);
}
}
";
CompileAndVerify(source, expectedOutput: "4123");
}
[Fact]
public void CapturedLambdaParameter04()
{
var source = @"
delegate D D(int x);
class CLP
{
void M()
{
int K = 4000;
D d1 = x => y => z => {
System.Console.Write(x + y + z + K);
return null;
};
d1(100)(20)(3);
}
public static void Main(string[] args)
{
new CLP().M();
}
}
";
CompileAndVerify(source, expectedOutput: "4123");
}
[Fact]
public void GenericClosure01()
{
string source = @"using System;
delegate void D();
class G<T>
{
public static void F(T t)
{
D d = () =>
{
Console.WriteLine(t);
};
d();
}
}
class C
{
public static void Main(string[] args)
{
G<int>.F(12);
G<string>.F(""goo"");
}
}";
CompileAndVerify(source, expectedOutput: @"
12
goo
");
}
[Fact]
public void GenericClosure02()
{
string source = @"using System;
delegate void D();
class G
{
public static void F<T>(T t)
{
D d = () =>
{
Console.WriteLine(t);
};
d();
}
}
class C
{
public static void Main(string[] args)
{
G.F<int>(12);
G.F<string>(""goo"");
}
}";
CompileAndVerify(source, expectedOutput: @"
12
goo
");
}
[Fact]
public void GenericClosure03()
{
var source = @"using System;
delegate U D<U>();
class GenericClosure
{
static D<T> Default<T>(T value)
{
return () => value;
}
public static void Main(string[] args)
{
D<string> dHello = Default(""Hello"");
Console.WriteLine(dHello());
D<int> d1234 = Default(1234);
Console.WriteLine(d1234());
}
}
";
var expectedOutput = @"Hello
1234";
CompileAndVerify(source, expectedOutput: expectedOutput);
}
[Fact]
public void GenericClosure04()
{
var source = @"using System;
delegate T D<T>();
class GenericClosure
{
static D<T> Default<T>(T value)
{
return () => default(T);
}
public static void Main(string[] args)
{
D<string> dHello = Default(""Hello"");
Console.WriteLine(dHello());
D<int> d1234 = Default(1234);
Console.WriteLine(d1234());
}
}
";
var expectedOutput = @"
0";
CompileAndVerify(source, expectedOutput: expectedOutput);
}
[Fact]
public void GenericCapturedLambdaParameter01()
{
var source = @"
delegate D D(int x);
class CLP
{
void M<T>()
{
D d1 = x => y => z => {
System.Console.Write(x + y + z);
return null;
};
d1(100)(20)(3);
}
public static void Main(string[] args)
{
new CLP().M<int>();
new CLP().M<string>();
}
}
";
CompileAndVerify(source, expectedOutput: "123123");
}
[Fact]
public void GenericCapturedLambdaParameter02()
{
var source = @"
delegate D D(int x);
class CLP
{
static void M<T>()
{
D d1 = x => y => z => {
System.Console.Write(x + y + z);
return null;
};
d1(100)(20)(3);
}
public static void Main(string[] args)
{
CLP.M<int>();
CLP.M<string>();
}
}
";
CompileAndVerify(source, expectedOutput: "123123");
}
[Fact]
public void GenericCapturedLambdaParameter03()
{
var source = @"
delegate D D(int x);
class CLP
{
void M<T>()
{
int K = 4000;
D d1 = x => y => z => {
System.Console.Write(x + y + z + K);
return null;
};
d1(100)(20)(3);
}
public static void Main(string[] args)
{
new CLP().M<int>();
new CLP().M<string>();
}
}
";
CompileAndVerify(source, expectedOutput: "41234123");
}
[Fact]
public void GenericCapturedLambdaParameter04()
{
var source = @"
delegate D D(int x);
class CLP
{
static void M<T>()
{
int K = 4000;
D d1 = x => y => z => {
System.Console.Write(x + y + z + K);
return null;
};
d1(100)(20)(3);
}
public static void Main(string[] args)
{
CLP.M<int>();
CLP.M<string>();
}
}
";
CompileAndVerify(source, expectedOutput: "41234123");
}
[Fact]
public void GenericCapturedTypeParameterLocal()
{
var source = @"
delegate void D();
class CLP
{
static void M<T>(T t0)
{
T t1 = t0;
D d = () => {
T t2 = t1;
System.Console.Write("""" + t0 + t1 + t2);
};
d();
}
public static void Main(string[] args)
{
CLP.M<int>(0);
CLP.M<string>(""h"");
}
}
";
CompileAndVerify(source, expectedOutput: "000hhh");
}
[Fact]
public void CaptureConstructedMethodInvolvingTypeParameter()
{
var source = @"
delegate void D();
class CLP
{
static void P<T>(T t0, T t1, T t2)
{
System.Console.Write(string.Concat(t0, t1, t2));
}
static void M<T>(T t0)
{
T t1 = t0;
D d = () => {
T t2 = t1;
P(t0, t1, t2);
};
d();
}
public static void Main(string[] args)
{
CLP.M<int>(0);
CLP.M<string>(""h"");
}
}
";
CompileAndVerify(source, expectedOutput: "000hhh");
}
[Fact]
public void CaptureConstructionInvolvingTypeParameter()
{
var source = @"
delegate void D();
class CLP
{
class P<T>
{
public P(T t0, T t1, T t2)
{
System.Console.Write(string.Concat(t0, t1, t2));
}
}
static void M<T>(T t0)
{
T t1 = t0;
D d = () =>
{
T t2 = t1;
new P<T>(t0, t1, t2);
};
d();
}
public static void Main(string[] args)
{
CLP.M<int>(0);
CLP.M<string>(""h"");
}
}
";
CompileAndVerify(source, expectedOutput: "000hhh");
}
[Fact]
public void CaptureDelegateConversionInvolvingTypeParameter()
{
var source = @"
delegate void D();
class CLP
{
delegate void D3<T>(T t0, T t1, T t2);
public static void P<T>(T t0, T t1, T t2)
{
System.Console.Write(string.Concat(t0, t1, t2));
}
static void M<T>(T t0)
{
T t1 = t0;
D d = () =>
{
T t2 = t1;
D3<T> d3 = P;
d3(t0, t1, t2);
};
d();
}
public static void Main(string[] args)
{
CLP.M<int>(0);
CLP.M<string>(""h"");
}
}
";
CompileAndVerify(source, expectedOutput: "000hhh");
}
[Fact]
public void CaptureFieldInvolvingTypeParameter()
{
var source = @"
delegate void D();
class CLP
{
class HolderClass<T>
{
public static T t;
}
delegate void D3<T>(T t0, T t1, T t2);
static void M<T>()
{
D d = () =>
{
System.Console.Write(string.Concat(HolderClass<T>.t));
};
d();
}
public static void Main(string[] args)
{
HolderClass<int>.t = 12;
HolderClass<string>.t = ""he"";
CLP.M<int>();
CLP.M<string>();
}
}
";
CompileAndVerify(source, expectedOutput: "12he");
}
[Fact]
public void CaptureReadonly01()
{
var source = @"
using System;
class Program
{
private static readonly int v = 5;
delegate int del(int i);
static void Main(string[] args)
{
del myDelegate = (int x) => x * v;
Console.Write(string.Concat(myDelegate(3), ""he""));
}
}";
CompileAndVerify(source, expectedOutput: "15he");
}
[Fact]
public void CaptureReadonly02()
{
var source = @"
using System;
class Program
{
private readonly int v = 5;
delegate int del(int i);
void M()
{
del myDelegate = (int x) => x * v;
Console.Write(string.Concat(myDelegate(3), ""he""));
}
static void Main(string[] args)
{
new Program().M();
}
}";
CompileAndVerify(source, expectedOutput: "15he");
}
[Fact]
public void CaptureLoopIndex()
{
var source = @"
using System;
delegate void D();
class Program
{
static void Main(string[] args)
{
D d0 = null;
for (int i = 0; i < 4; i++)
{
D d = d0 = () =>
{
Console.Write(i);
};
d();
}
d0();
}
}";
CompileAndVerify(source, expectedOutput: "01234");
}
// see Roslyn bug 5956
[Fact]
public void CapturedIncrement()
{
var source = @"
class Program
{
delegate int Func();
static void Main(string[] args)
{
int i = 0;
Func query;
if (true)
{
query = () =>
{
i = 6;
Goo(i++);
return i;
};
}
i = 3;
System.Console.WriteLine(query.Invoke());
}
public static int Goo(int i)
{
i = 4;
return i;
}
}
";
CompileAndVerify(source, expectedOutput: "7");
}
[Fact]
public void StructDelegate()
{
var source = @"
using System;
class Program
{
static void Main()
{
int x = 42;
Func<string> f = x.ToString;
Console.Write(f.Invoke());
}
}";
// See tracking issue https://github.com/dotnet/runtime/issues/96695
var verifier = CompileAndVerify(source, expectedOutput: "42",
verify: Verification.FailsILVerify with { ILVerifyMessage = "[Main]: Unrecognized arguments for delegate .ctor. { Offset = 0xe }" });
verifier.VerifyIL("Program.Main", """
{
// Code size 30 (0x1e)
.maxstack 2
IL_0000: ldc.i4.s 42
IL_0002: box "int"
IL_0007: dup
IL_0008: ldvirtftn "string object.ToString()"
IL_000e: newobj "System.Func<string>..ctor(object, System.IntPtr)"
IL_0013: callvirt "string System.Func<string>.Invoke()"
IL_0018: call "void System.Console.Write(string)"
IL_001d: ret
}
""");
}
[Fact]
public void StructDelegate1()
{
var source = @"
using System;
class Program
{
public static void Goo<T>(T x)
{
Func<string> f = x.ToString;
Console.Write(f.Invoke());
}
static void Main()
{
string s = ""Hi"";
Goo(s);
int x = 42;
Goo(x);
}
}"
;
CompileAndVerify(source, expectedOutput: "Hi42");
}
[Fact]
public void StaticDelegateFromMethodGroupInLambda()
{
var source = @"using System;
class Program
{
static void M()
{
Console.WriteLine(12);
}
public static void Main(string[] args)
{
Action a = () => {
Action b = new Action(M);
b();
};
a();
}
}";
CompileAndVerify(source, expectedOutput: "12");
}
[Fact]
public void StaticDelegateFromMethodGroupInLambda2()
{
var source = @"using System;
class Program
{
static void M()
{
Console.WriteLine(12);
}
void G()
{
Action a = () => {
Action b = new Action(M);
b();
};
a();
}
public static void Main(string[] args)
{
new Program().G();
}
}";
CompileAndVerify(source, expectedOutput: "12");
}
[WorkItem(539346, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/539346")]
[Fact]
public void CachedLambdas()
{
var source = @"using System;
public class Program
{
private static void Assert(bool b)
{
if (!b) throw new Exception();
}
public static void Test1()
{
Action a0 = null;
for (int i = 0; i < 2; i++)
{
Action a = () => { };
if (i == 0)
{
a0 = a;
}
else
{
Assert(ReferenceEquals(a, a0));
}
}
}
public void Test2()
{
Action a0 = null;
for (int i = 0; i < 2; i++)
{
Action a = () => { };
if (i == 0)
{
a0 = a;
}
else
{
Assert(ReferenceEquals(a, a0));
}
}
}
public static void Test3()
{
int inEnclosing = 12;
Func<int> a0 = null;
for (int i = 0; i < 2; i++)
{
Func<int> a = () => inEnclosing;
if (i == 0)
{
a0 = a;
}
else
{
Assert(ReferenceEquals(a, a0));
}
}
}
public void Test4()
{
Func<Program> a0 = null;
for (int i = 0; i < 2; i++)
{
Func<Program> a = () => this;
if (i == 0)
{
a0 = a;
}
else
{
Assert(ReferenceEquals(a, a0)); // Roslyn misses this
}
}
}
public static void Test5()
{
int i = 12;
Func<Action> D = () => () => Console.WriteLine(i);
Action a1 = D();
Action a2 = D();
Assert(ReferenceEquals(a1, a2)); // native compiler misses this
}
public static void Test6()
{
Func<int> a1 = Goo<int>.Bar<int>();
Func<int> a2 = Goo<int>.Bar<int>();
Assert(ReferenceEquals(a1, a2)); // both native compiler and Roslyn miss this
}
public static void Main(string[] args)
{
Test1();
new Program().Test2();
Test3();
// new Program().Test4();
Test5();
// Test6();
}
}
class Goo<T>
{
static T t;
public static Func<U> Bar<U>()
{
return () => Goo<U>.t;
}
}";
CompileAndVerify(source, expectedOutput: "");
}
[Fact]
public void ParentFrame01()
{
//IMPORTANT: the parent frame field in Program.c1.<>c__DisplayClass1 should be named CS$<>8__locals, not <>4__this.
string source = @"
using System;
class Program
{
static void Main(string[] args)
{
var t = new c1();
t.Test();
}
class c1
{
int x = 1;
public void Test()
{
int y = 2;
Func<Func<Func<int, Func<int, int>>>> ff = null;
if (2.ToString() != null)
{
int a = 4;
ff = () => () => (z) => (zz) => x + y + z + a + zz;
}
Console.WriteLine(ff()()(3)(3));
}
}
}";
CompileAndVerify(source, expectedOutput: "13").
VerifyIL("Program.c1.<>c__DisplayClass1_0.<Test>b__2",
@"{
// Code size 31 (0x1f)
.maxstack 3
IL_0000: newobj ""Program.c1.<>c__DisplayClass1_1..ctor()""
IL_0005: dup
IL_0006: ldarg.0
IL_0007: stfld ""Program.c1.<>c__DisplayClass1_0 Program.c1.<>c__DisplayClass1_1.CS$<>8__locals1""
IL_000c: dup
IL_000d: ldarg.1
IL_000e: stfld ""int Program.c1.<>c__DisplayClass1_1.z""
IL_0013: ldftn ""int Program.c1.<>c__DisplayClass1_1.<Test>b__3(int)""
IL_0019: newobj ""System.Func<int, int>..ctor(object, System.IntPtr)""
IL_001e: ret
}");
}
[Fact]
public void ParentFrame02()
{
string source = @"
using System;
class Program
{
static void Main(string[] args)
{
var t = new c1();
t.Test();
}
class c1
{
int x = 1;
public void Test()
{
int y = 2;
Func<Func<Func<int, Func<int>>>> ff = null;
if (2.ToString() != null)
{
int a = 4;
ff = () => () => (z) => () => x + y + z + a;
}
if (2.ToString() != null)
{
int a = 4;
ff = () => () => (z) => () => x + y + z + a;
}
Console.WriteLine(ff()()(3)());
}
}
}
";
CompileAndVerify(source, expectedOutput: "10").
VerifyIL("Program.c1.Test",
@"{
// Code size 134 (0x86)
.maxstack 3
.locals init (Program.c1.<>c__DisplayClass1_0 V_0, //CS$<>8__locals0
System.Func<System.Func<System.Func<int, System.Func<int>>>> V_1, //ff
int V_2)
IL_0000: newobj ""Program.c1.<>c__DisplayClass1_0..ctor()""
IL_0005: stloc.0
IL_0006: ldloc.0
IL_0007: ldarg.0
IL_0008: stfld ""Program.c1 Program.c1.<>c__DisplayClass1_0.<>4__this""
IL_000d: ldloc.0
IL_000e: ldc.i4.2
IL_000f: stfld ""int Program.c1.<>c__DisplayClass1_0.y""
IL_0014: ldnull
IL_0015: stloc.1
IL_0016: ldc.i4.2
IL_0017: stloc.2
IL_0018: ldloca.s V_2
IL_001a: call ""string int.ToString()""
IL_001f: brfalse.s IL_0040
IL_0021: newobj ""Program.c1.<>c__DisplayClass1_1..ctor()""
IL_0026: dup
IL_0027: ldloc.0
IL_0028: stfld ""Program.c1.<>c__DisplayClass1_0 Program.c1.<>c__DisplayClass1_1.CS$<>8__locals1""
IL_002d: dup
IL_002e: ldc.i4.4
IL_002f: stfld ""int Program.c1.<>c__DisplayClass1_1.a""
IL_0034: ldftn ""System.Func<System.Func<int, System.Func<int>>> Program.c1.<>c__DisplayClass1_1.<Test>b__0()""
IL_003a: newobj ""System.Func<System.Func<System.Func<int, System.Func<int>>>>..ctor(object, System.IntPtr)""
IL_003f: stloc.1
IL_0040: ldc.i4.2
IL_0041: stloc.2
IL_0042: ldloca.s V_2
IL_0044: call ""string int.ToString()""
IL_0049: brfalse.s IL_006a
IL_004b: newobj ""Program.c1.<>c__DisplayClass1_3..ctor()""
IL_0050: dup
IL_0051: ldloc.0
IL_0052: stfld ""Program.c1.<>c__DisplayClass1_0 Program.c1.<>c__DisplayClass1_3.CS$<>8__locals3""
IL_0057: dup
IL_0058: ldc.i4.4
IL_0059: stfld ""int Program.c1.<>c__DisplayClass1_3.a""
IL_005e: ldftn ""System.Func<System.Func<int, System.Func<int>>> Program.c1.<>c__DisplayClass1_3.<Test>b__4()""
IL_0064: newobj ""System.Func<System.Func<System.Func<int, System.Func<int>>>>..ctor(object, System.IntPtr)""
IL_0069: stloc.1
IL_006a: ldloc.1
IL_006b: callvirt ""System.Func<System.Func<int, System.Func<int>>> System.Func<System.Func<System.Func<int, System.Func<int>>>>.Invoke()""
IL_0070: callvirt ""System.Func<int, System.Func<int>> System.Func<System.Func<int, System.Func<int>>>.Invoke()""
IL_0075: ldc.i4.3
IL_0076: callvirt ""System.Func<int> System.Func<int, System.Func<int>>.Invoke(int)""
IL_007b: callvirt ""int System.Func<int>.Invoke()""
IL_0080: call ""void System.Console.WriteLine(int)""
IL_0085: ret
}");
}
[Fact]
public void ParentFrame03()
{
string source = @"
using System;
class Program
{
static void Main(string[] args)
{
var t = new c1();
t.Test();
}
class c1
{
int x = 1;
public void Test()
{
int y = 2;
Func<Func<Func<Func<int>>>> ff = null;
if (2.ToString() != null)
{
int z = 3;
ff = () => () => () => () => x + y + z;
}
if (2.ToString() != null)
{
int z = 3;
ff = () => () => () => () => x + y + z;
}
Console.WriteLine(ff()()()());
}
}
}
";
CompileAndVerify(source, expectedOutput: "6").
VerifyIL("Program.c1.Test",
@"{
// Code size 133 (0x85)
.maxstack 3
.locals init (Program.c1.<>c__DisplayClass1_0 V_0, //CS$<>8__locals0
System.Func<System.Func<System.Func<System.Func<int>>>> V_1, //ff
int V_2)
IL_0000: newobj ""Program.c1.<>c__DisplayClass1_0..ctor()""
IL_0005: stloc.0
IL_0006: ldloc.0
IL_0007: ldarg.0
IL_0008: stfld ""Program.c1 Program.c1.<>c__DisplayClass1_0.<>4__this""
IL_000d: ldloc.0
IL_000e: ldc.i4.2
IL_000f: stfld ""int Program.c1.<>c__DisplayClass1_0.y""
IL_0014: ldnull
IL_0015: stloc.1
IL_0016: ldc.i4.2
IL_0017: stloc.2
IL_0018: ldloca.s V_2
IL_001a: call ""string int.ToString()""
IL_001f: brfalse.s IL_0040
IL_0021: newobj ""Program.c1.<>c__DisplayClass1_1..ctor()""
IL_0026: dup
IL_0027: ldloc.0
IL_0028: stfld ""Program.c1.<>c__DisplayClass1_0 Program.c1.<>c__DisplayClass1_1.CS$<>8__locals1""
IL_002d: dup
IL_002e: ldc.i4.3
IL_002f: stfld ""int Program.c1.<>c__DisplayClass1_1.z""
IL_0034: ldftn ""System.Func<System.Func<System.Func<int>>> Program.c1.<>c__DisplayClass1_1.<Test>b__0()""
IL_003a: newobj ""System.Func<System.Func<System.Func<System.Func<int>>>>..ctor(object, System.IntPtr)""
IL_003f: stloc.1
IL_0040: ldc.i4.2
IL_0041: stloc.2
IL_0042: ldloca.s V_2
IL_0044: call ""string int.ToString()""
IL_0049: brfalse.s IL_006a
IL_004b: newobj ""Program.c1.<>c__DisplayClass1_2..ctor()""
IL_0050: dup
IL_0051: ldloc.0
IL_0052: stfld ""Program.c1.<>c__DisplayClass1_0 Program.c1.<>c__DisplayClass1_2.CS$<>8__locals2""
IL_0057: dup
IL_0058: ldc.i4.3
IL_0059: stfld ""int Program.c1.<>c__DisplayClass1_2.z""
IL_005e: ldftn ""System.Func<System.Func<System.Func<int>>> Program.c1.<>c__DisplayClass1_2.<Test>b__4()""
IL_0064: newobj ""System.Func<System.Func<System.Func<System.Func<int>>>>..ctor(object, System.IntPtr)""
IL_0069: stloc.1
IL_006a: ldloc.1
IL_006b: callvirt ""System.Func<System.Func<System.Func<int>>> System.Func<System.Func<System.Func<System.Func<int>>>>.Invoke()""
IL_0070: callvirt ""System.Func<System.Func<int>> System.Func<System.Func<System.Func<int>>>.Invoke()""
IL_0075: callvirt ""System.Func<int> System.Func<System.Func<int>>.Invoke()""
IL_007a: callvirt ""int System.Func<int>.Invoke()""
IL_007f: call ""void System.Console.WriteLine(int)""
IL_0084: ret
}
");
}
[Fact]
public void ParentFrame04()
{
string source = @"
using System;
public static class Program
{
public static void Main()
{
var c = new c1();
System.Console.WriteLine(c.Test());
}
class c1
{
public int goo = 42;
public object Test()
{
if (T())
{
Func<int, Boolean> a = (s) => s == goo && ((Func<bool>)(() => s == goo)).Invoke();
return a.Invoke(42);
}
int aaa = 42;
if (T())
{
Func<int, bool> a = (s) => aaa == goo;
return a.Invoke(42);
}
return null;
}
private bool T()
{
return true;
}
}
}
";
CompileAndVerify(source, expectedOutput: "True").
VerifyIL("Program.c1.Test",
@"
{
// Code size 89 (0x59)
.maxstack 2
.locals init (Program.c1.<>c__DisplayClass1_0 V_0) //CS$<>8__locals0
IL_0000: newobj ""Program.c1.<>c__DisplayClass1_0..ctor()""
IL_0005: stloc.0
IL_0006: ldloc.0
IL_0007: ldarg.0
IL_0008: stfld ""Program.c1 Program.c1.<>c__DisplayClass1_0.<>4__this""
IL_000d: ldarg.0
IL_000e: call ""bool Program.c1.T()""
IL_0013: brfalse.s IL_002e
IL_0015: ldloc.0
IL_0016: ldftn ""bool Program.c1.<>c__DisplayClass1_0.<Test>b__0(int)""
IL_001c: newobj ""System.Func<int, bool>..ctor(object, System.IntPtr)""
IL_0021: ldc.i4.s 42
IL_0023: callvirt ""bool System.Func<int, bool>.Invoke(int)""
IL_0028: box ""bool""
IL_002d: ret
IL_002e: ldloc.0
IL_002f: ldc.i4.s 42
IL_0031: stfld ""int Program.c1.<>c__DisplayClass1_0.aaa""
IL_0036: ldarg.0
IL_0037: call ""bool Program.c1.T()""
IL_003c: brfalse.s IL_0057
IL_003e: ldloc.0
IL_003f: ldftn ""bool Program.c1.<>c__DisplayClass1_0.<Test>b__2(int)""
IL_0045: newobj ""System.Func<int, bool>..ctor(object, System.IntPtr)""
IL_004a: ldc.i4.s 42
IL_004c: callvirt ""bool System.Func<int, bool>.Invoke(int)""
IL_0051: box ""bool""
IL_0056: ret
IL_0057: ldnull
IL_0058: ret
}
");
}
[Fact]
public void ParentFrame05()
{
// IMPORTANT: Program.c1.<>c__DisplayClass1_0 should not capture any frame pointers.
string source = @"
using System;
class Program
{
static void Main(string[] args)
{
var t = new c1();
t.Test();
}
class c1
{
int x = 1;
public void Test()
{
Func<int> ff = null;
Func<int> aa = null;
if (T())
{
int a = 1;
if (T())
{
int b = 4;
ff = () => a + b;
aa = () => x;
}
}
Console.WriteLine(ff() + aa());
}
private bool T()
{
return true;
}
}
}
";
CompileAndVerify(source, expectedOutput: "6").
VerifyIL("Program.c1.Test",
@"{
// Code size 85 (0x55)
.maxstack 2
.locals init (System.Func<int> V_0, //ff
System.Func<int> V_1, //aa
Program.c1.<>c__DisplayClass1_0 V_2) //CS$<>8__locals0
IL_0000: ldnull
IL_0001: stloc.0
IL_0002: ldnull
IL_0003: stloc.1
IL_0004: ldarg.0
IL_0005: call ""bool Program.c1.T()""
IL_000a: brfalse.s IL_0042
IL_000c: newobj ""Program.c1.<>c__DisplayClass1_0..ctor()""
IL_0011: stloc.2
IL_0012: ldloc.2
IL_0013: ldc.i4.1
IL_0014: stfld ""int Program.c1.<>c__DisplayClass1_0.a""
IL_0019: ldarg.0
IL_001a: call ""bool Program.c1.T()""
IL_001f: brfalse.s IL_0042
IL_0021: ldloc.2
IL_0022: ldc.i4.4
IL_0023: stfld ""int Program.c1.<>c__DisplayClass1_0.b""
IL_0028: ldloc.2
IL_0029: ldftn ""int Program.c1.<>c__DisplayClass1_0.<Test>b__0()""
IL_002f: newobj ""System.Func<int>..ctor(object, System.IntPtr)""
IL_0034: stloc.0
IL_0035: ldarg.0
IL_0036: ldftn ""int Program.c1.<Test>b__1_1()""
IL_003c: newobj ""System.Func<int>..ctor(object, System.IntPtr)""
IL_0041: stloc.1
IL_0042: ldloc.0
IL_0043: callvirt ""int System.Func<int>.Invoke()""
IL_0048: ldloc.1
IL_0049: callvirt ""int System.Func<int>.Invoke()""
IL_004e: add
IL_004f: call ""void System.Console.WriteLine(int)""
IL_0054: ret
}");
}
[Fact]
public void ClosuresInConstructorAndInitializers1()
{
string source = @"
using System;
class C
{
int f1 = new Func<int, int>(x => 1)(1);
int f2 = new Func<int, int>(x => 2)(1);
C()
{
int l = new Func<int, int>(x => 3)(1);
}
}";
CompileAndVerify(source);
}
[Fact]
public void ClosuresInConstructorAndInitializers2()
{
string source = @"
using System;
class C
{
int f1 = ((Func<int, int>)(x => ((Func<int>)(() => x + 2))() + x))(1);
int f2 = ((Func<int, int>)(x => ((Func<int>)(() => x + 2))() + x))(1);
C()
{
int l = ((Func<int, int>)(x => ((Func<int>)(() => x + 4))() + x))(1);
}
}";
CompileAndVerify(source);
}
[Fact]
public void ClosuresInConstructorAndInitializers3()
{
string source = @"
using System;
class C
{
static int f1 = ((Func<int, int>)(x => ((Func<int>)(() => x + 2))() + x))(1);
static int f2 = ((Func<int, int>)(x => ((Func<int>)(() => x + 2))() + x))(1);
static C()
{
int l = ((Func<int, int>)(x => ((Func<int>)(() => x + 4))() + x))(1);
}
}";
CompileAndVerify(source);
}
[Fact]
public void GenericStaticFrames()
{
string source = @"
using System;
public class C
{
public static void F<TF>()
{
var f = new Func<TF>(() => default(TF));
}
public static void G<TG>()
{
var f = new Func<TG>(() => default(TG));
}
public static void F<TF1, TF2>()
{
var f = new Func<TF1, TF2>(a => default(TF2));
}
public static void G<TG1, TG2>()
{
var f = new Func<TG1, TG2>(a => default(TG2));
}
}";
CompileAndVerify(source, options: TestOptions.DebugDll.WithMetadataImportOptions(MetadataImportOptions.All), symbolValidator: m =>
{
var c = m.GlobalNamespace.GetMember<NamedTypeSymbol>("C");
AssertEx.Equal(new[]
{
"C.<>c__0<TF>",
"C.<>c__1<TG>",
"C.<>c__2<TF1, TF2>",
"C.<>c__3<TG1, TG2>"
}, c.GetMembers().Where(member => member.Kind == SymbolKind.NamedType).Select(member => member.ToString()));
var c0 = c.GetMember<NamedTypeSymbol>("<>c__0");
AssertEx.SetEqual(new[]
{
"C.<>c__0<TF>.<>9",
"C.<>c__0<TF>.<>9__0_0",
"C.<>c__0<TF>.<>c__0()",
"C.<>c__0<TF>.<>c__0()",
"C.<>c__0<TF>.<F>b__0_0()",
}, c0.GetMembers().Select(member => member.ToString()));
var c1 = c.GetMember<NamedTypeSymbol>("<>c__1");
AssertEx.SetEqual(new[]
{
"C.<>c__1<TG>.<>9",
"C.<>c__1<TG>.<>9__1_0",
"C.<>c__1<TG>.<>c__1()",
"C.<>c__1<TG>.<>c__1()",
"C.<>c__1<TG>.<G>b__1_0()",
}, c1.GetMembers().Select(member => member.ToString()));
var c2 = c.GetMember<NamedTypeSymbol>("<>c__2");
AssertEx.SetEqual(new[]
{
"C.<>c__2<TF1, TF2>.<>9",
"C.<>c__2<TF1, TF2>.<>9__2_0",
"C.<>c__2<TF1, TF2>.<>c__2()",
"C.<>c__2<TF1, TF2>.<>c__2()",
"C.<>c__2<TF1, TF2>.<F>b__2_0(TF1)",
}, c2.GetMembers().Select(member => member.ToString()));
var c3 = c.GetMember<NamedTypeSymbol>("<>c__3");
AssertEx.SetEqual(new[]
{
"C.<>c__3<TG1, TG2>.<>9",
"C.<>c__3<TG1, TG2>.<>9__3_0",
"C.<>c__3<TG1, TG2>.<>c__3()",
"C.<>c__3<TG1, TG2>.<>c__3()",
"C.<>c__3<TG1, TG2>.<G>b__3_0(TG1)",
}, c3.GetMembers().Select(member => member.ToString()));
});
}
[Fact]
public void GenericStaticFramesWithConstraints()
{
string source = @"
using System;
public class C
{
public static void F<TF>() where TF : class
{
var f = new Func<TF>(() => default(TF));
}
public static void G<TG>() where TG : struct
{
var f = new Func<TG>(() => default(TG));
}
}";
CompileAndVerify(source, options: TestOptions.DebugDll.WithMetadataImportOptions(MetadataImportOptions.All), symbolValidator: m =>
{
var c = m.GlobalNamespace.GetMember<NamedTypeSymbol>("C");
AssertEx.Equal(new[]
{
"C.<>c__0<TF>",
"C.<>c__1<TG>",
}, c.GetMembers().Where(member => member.Kind == SymbolKind.NamedType).Select(member => member.ToString()));
});
}
[Fact]
public void GenericInstance()
{
string source = @"
using System;
public class C
{
public void F<TF>()
{
var f = new Func<TF>(() => { this.F(); return default(TF); });
}
public void G<TG>()
{
var f = new Func<TG>(() => { this.F(); return default(TG); });
}
public void F<TF1, TF2>()
{
var f = new Func<TF1, TF2>(a => { this.F(); return default(TF2); });
}
public void G<TG1, TG2>()
{
var f = new Func<TG1, TG2>(a => { this.F(); return default(TG2); });
}
private void F() {}
}";
CompileAndVerify(source, options: TestOptions.DebugDll.WithMetadataImportOptions(MetadataImportOptions.All), symbolValidator: m =>
{
var c = m.GlobalNamespace.GetMember<NamedTypeSymbol>("C");
AssertEx.SetEqual(new[]
{
"C.F<TF>()",
"C.G<TG>()",
"C.F<TF1, TF2>()",
"C.G<TG1, TG2>()",
"C.F()",
"C.C()",
"C.<F>b__0_0<TF>()",
"C.<G>b__1_0<TG>()",
"C.<F>b__2_0<TF1, TF2>(TF1)",
"C.<G>b__3_0<TG1, TG2>(TG1)",
}, c.GetMembers().Select(member => member.ToString()));
});
}
#region "Regressions"
[WorkItem(539439, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/539439")]
[Fact]
public void LambdaWithReturn()
{
string source = @"
using System;
class Program
{
delegate int Func(int i, int r);
static void Main(string[] args)
{
Func fnc = (arg, arg2) => { return 1 + 2; };
Console.Write(fnc(3, 4));
}
}";
CompileAndVerify(source, expectedOutput: @"3");
}
/// <remarks>
/// Based on MadsT blog post:
/// http://blogs.msdn.com/b/madst/archive/2007/05/11/recursive-lambda-expressions.aspx
/// </remarks>
[WorkItem(540034, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/540034")]
[Fact]
public void YCombinatorTest()
{
var source = @"
using System;
using System.Linq;
public class Program
{
delegate T SelfApplicable<T>(SelfApplicable<T> self);
static void Main()
{
// The Y combinator
SelfApplicable<
Func<Func<Func<int, int>, Func<int, int>>, Func<int, int>>
> Y = y => f => x => f(y(y)(f))(x);
// The fixed point generator
Func<Func<Func<int, int>, Func<int, int>>, Func<int, int>> Fix =
Y(Y);
// The higher order function describing factorial
Func<Func<int, int>, Func<int, int>> F =
fac => x => { if (x == 0) { return 1; } else { return x * fac(x - 1); }
};
// The factorial function itself
Func<int, int> factorial = Fix(F);
Console.WriteLine(string.Join(
Environment.NewLine,
Enumerable.Select(Enumerable.Range(0, 12), factorial)));
}
}
";
CompileAndVerify(
source,
expectedOutput:
@"1
1
2
6
24
120
720
5040
40320
362880
3628800
39916800"
);
}
[WorkItem(540035, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/540035")]
[Fact]
public void LongNameTest()
{
var source = @"
using System;
namespace Lambda.Bugs
{
public interface I<T>
{
void Goo(int x);
}
public class OuterGenericClass<T, S>
{
public class NestedClass : OuterGenericClass<NestedClass, NestedClass> { }
public class C : I<NestedClass.NestedClass.NestedClass.NestedClass.NestedClass>
{
void I<NestedClass.NestedClass.NestedClass.NestedClass.NestedClass>.Goo(int x)
{
Func<int> f = () => x;
Console.WriteLine(f());
}
}
}
public class Program
{
public static void Main()
{
I<OuterGenericClass<int, int>.NestedClass.NestedClass.NestedClass.NestedClass.NestedClass> x =
new OuterGenericClass<int, int>.C();
x.Goo(1);
}
}
}
";
CreateCompilation(source).VerifyEmitDiagnostics(
// (17,81): error CS7013: Name 'Lambda.Bugs.I<Lambda.Bugs.OuterGenericClass<Lambda.Bugs.OuterGenericClass<Lambda.Bugs.OuterGenericClass<Lambda.Bugs.OuterGenericClass<Lambda.Bugs.OuterGenericClass<T,S>.NestedClass,Lambda.Bugs.OuterGenericClass<T,S>.NestedClass>.NestedClass,Lambda.Bugs.OuterGenericClass<Lambda.Bugs.OuterGenericClass<T,S>.NestedClass,Lambda.Bugs.OuterGenericClass<T,S>.NestedClass>.NestedClass>.NestedClass,Lambda.Bugs.OuterGenericClass<Lambda.Bugs.OuterGenericClass<Lambda.Bugs.OuterGenericClass<T,S>.NestedClass,Lambda.Bugs.OuterGenericClass<T,S>.NestedClass>.NestedClass,Lambda.Bugs.OuterGenericClass<Lambda.Bugs.OuterGenericClass<T,S>.NestedClass,Lambda.Bugs.OuterGenericClass<T,S>.NestedClass>.NestedClass>.NestedClass>.NestedClass,Lambda.Bugs.OuterGenericClass<Lambda.Bugs.OuterGenericClass<Lambda.Bugs.OuterGenericClass<Lambda.Bugs.OuterGenericClass<T,S>.NestedClass,Lambda.Bugs.OuterGenericClass<T,S>.NestedClass>.NestedClass,Lambda.Bugs.OuterGenericClass<Lambda.Bugs.OuterGenericClass<T,S>.NestedClass,Lambda.Bugs.OuterGenericClass<T,S>.NestedClass>.NestedClass>.NestedClass,Lambda.Bugs.OuterGenericClass<Lambda.Bugs.OuterGenericClass<Lambda.Bugs.OuterGenericClass<T,S>.NestedClass,Lambda.Bugs.OuterGenericClass<T,S>.NestedClass>.NestedClass,Lambda.Bugs.OuterGenericClass<Lambda.Bugs.OuterGenericClass<T,S>.NestedClass,Lambda.Bugs.OuterGenericClass<T,S>.NestedClass>.NestedClass>.NestedClass>.NestedClass>.NestedClass>.Goo' exceeds the maximum length allowed in metadata.
// void I<NestedClass.NestedClass.NestedClass.NestedClass.NestedClass>.Goo(int x)
Diagnostic(ErrorCode.ERR_MetadataNameTooLong, "Goo").WithArguments("Lambda.Bugs.I<Lambda.Bugs.OuterGenericClass<Lambda.Bugs.OuterGenericClass<Lambda.Bugs.OuterGenericClass<Lambda.Bugs.OuterGenericClass<Lambda.Bugs.OuterGenericClass<T,S>.NestedClass,Lambda.Bugs.OuterGenericClass<T,S>.NestedClass>.NestedClass,Lambda.Bugs.OuterGenericClass<Lambda.Bugs.OuterGenericClass<T,S>.NestedClass,Lambda.Bugs.OuterGenericClass<T,S>.NestedClass>.NestedClass>.NestedClass,Lambda.Bugs.OuterGenericClass<Lambda.Bugs.OuterGenericClass<Lambda.Bugs.OuterGenericClass<T,S>.NestedClass,Lambda.Bugs.OuterGenericClass<T,S>.NestedClass>.NestedClass,Lambda.Bugs.OuterGenericClass<Lambda.Bugs.OuterGenericClass<T,S>.NestedClass,Lambda.Bugs.OuterGenericClass<T,S>.NestedClass>.NestedClass>.NestedClass>.NestedClass,Lambda.Bugs.OuterGenericClass<Lambda.Bugs.OuterGenericClass<Lambda.Bugs.OuterGenericClass<Lambda.Bugs.OuterGenericClass<T,S>.NestedClass,Lambda.Bugs.OuterGenericClass<T,S>.NestedClass>.NestedClass,Lambda.Bugs.OuterGenericClass<Lambda.Bugs.OuterGenericClass<T,S>.NestedClass,Lambda.Bugs.OuterGenericClass<T,S>.NestedClass>.NestedClass>.NestedClass,Lambda.Bugs.OuterGenericClass<Lambda.Bugs.OuterGenericClass<Lambda.Bugs.OuterGenericClass<T,S>.NestedClass,Lambda.Bugs.OuterGenericClass<T,S>.NestedClass>.NestedClass,Lambda.Bugs.OuterGenericClass<Lambda.Bugs.OuterGenericClass<T,S>.NestedClass,Lambda.Bugs.OuterGenericClass<T,S>.NestedClass>.NestedClass>.NestedClass>.NestedClass>.NestedClass>.Goo").WithLocation(17, 81),
// (19,31): error CS7013: Name '<Lambda.Bugs.I<Lambda.Bugs.OuterGenericClass<Lambda.Bugs.OuterGenericClass<Lambda.Bugs.OuterGenericClass<Lambda.Bugs.OuterGenericClass<Lambda.Bugs.OuterGenericClass<T,S>.NestedClass,Lambda.Bugs.OuterGenericClass<T,S>.NestedClass>.NestedClass,Lambda.Bugs.OuterGenericClass<Lambda.Bugs.OuterGenericClass<T,S>.NestedClass,Lambda.Bugs.OuterGenericClass<T,S>.NestedClass>.NestedClass>.NestedClass,Lambda.Bugs.OuterGenericClass<Lambda.Bugs.OuterGenericClass<Lambda.Bugs.OuterGenericClass<T,S>.NestedClass,Lambda.Bugs.OuterGenericClass<T,S>.NestedClass>.NestedClass,Lambda.Bugs.OuterGenericClass<Lambda.Bugs.OuterGenericClass<T,S>.NestedClass,Lambda.Bugs.OuterGenericClass<T,S>.NestedClass>.NestedClass>.NestedClass>.NestedClass,Lambda.Bugs.OuterGenericClass<Lambda.Bugs.OuterGenericClass<Lambda.Bugs.OuterGenericClass<Lambda.Bugs.OuterGenericClass<T,S>.NestedClass,Lambda.Bugs.OuterGenericClass<T,S>.NestedClass>.NestedClass,Lambda.Bugs.OuterGenericClass<Lambda.Bugs.OuterGenericClass<T,S>.NestedClass,Lambda.Bugs.OuterGenericClass<T,S>.NestedClass>.NestedClass>.NestedClass,Lambda.Bugs.OuterGenericClass<Lambda.Bugs.OuterGenericClass<Lambda.Bugs.OuterGenericClass<T,S>.NestedClass,Lambda.Bugs.OuterGenericClass<T,S>.NestedClass>.NestedClass,Lambda.Bugs.OuterGenericClass<Lambda.Bugs.OuterGenericClass<T,S>.NestedClass,Lambda.Bugs.OuterGenericClass<T,S>.NestedClass>.NestedClass>.NestedClass>.NestedClass>.NestedClass>.Goo>b__0' exceeds the maximum length allowed in metadata.
// Func<int> f = () => x;
Diagnostic(ErrorCode.ERR_MetadataNameTooLong, "() => x").WithArguments("<Lambda.Bugs.I<Lambda.Bugs.OuterGenericClass<Lambda.Bugs.OuterGenericClass<Lambda.Bugs.OuterGenericClass<Lambda.Bugs.OuterGenericClass<Lambda.Bugs.OuterGenericClass<T,S>.NestedClass,Lambda.Bugs.OuterGenericClass<T,S>.NestedClass>.NestedClass,Lambda.Bugs.OuterGenericClass<Lambda.Bugs.OuterGenericClass<T,S>.NestedClass,Lambda.Bugs.OuterGenericClass<T,S>.NestedClass>.NestedClass>.NestedClass,Lambda.Bugs.OuterGenericClass<Lambda.Bugs.OuterGenericClass<Lambda.Bugs.OuterGenericClass<T,S>.NestedClass,Lambda.Bugs.OuterGenericClass<T,S>.NestedClass>.NestedClass,Lambda.Bugs.OuterGenericClass<Lambda.Bugs.OuterGenericClass<T,S>.NestedClass,Lambda.Bugs.OuterGenericClass<T,S>.NestedClass>.NestedClass>.NestedClass>.NestedClass,Lambda.Bugs.OuterGenericClass<Lambda.Bugs.OuterGenericClass<Lambda.Bugs.OuterGenericClass<Lambda.Bugs.OuterGenericClass<T,S>.NestedClass,Lambda.Bugs.OuterGenericClass<T,S>.NestedClass>.NestedClass,Lambda.Bugs.OuterGenericClass<Lambda.Bugs.OuterGenericClass<T,S>.NestedClass,Lambda.Bugs.OuterGenericClass<T,S>.NestedClass>.NestedClass>.NestedClass,Lambda.Bugs.OuterGenericClass<Lambda.Bugs.OuterGenericClass<Lambda.Bugs.OuterGenericClass<T,S>.NestedClass,Lambda.Bugs.OuterGenericClass<T,S>.NestedClass>.NestedClass,Lambda.Bugs.OuterGenericClass<Lambda.Bugs.OuterGenericClass<T,S>.NestedClass,Lambda.Bugs.OuterGenericClass<T,S>.NestedClass>.NestedClass>.NestedClass>.NestedClass>.NestedClass>.Goo>b__0").WithLocation(19, 31),
// (19,31): error CS7013: Name '<Lambda.Bugs.I<Lambda.Bugs.OuterGenericClass<Lambda.Bugs.OuterGenericClass<Lambda.Bugs.OuterGenericClass<Lambda.Bugs.OuterGenericClass<Lambda.Bugs.OuterGenericClass<T,S>.NestedClass,Lambda.Bugs.OuterGenericClass<T,S>.NestedClass>.NestedClass,Lambda.Bugs.OuterGenericClass<Lambda.Bugs.OuterGenericClass<T,S>.NestedClass,Lambda.Bugs.OuterGenericClass<T,S>.NestedClass>.NestedClass>.NestedClass,Lambda.Bugs.OuterGenericClass<Lambda.Bugs.OuterGenericClass<Lambda.Bugs.OuterGenericClass<T,S>.NestedClass,Lambda.Bugs.OuterGenericClass<T,S>.NestedClass>.NestedClass,Lambda.Bugs.OuterGenericClass<Lambda.Bugs.OuterGenericClass<T,S>.NestedClass,Lambda.Bugs.OuterGenericClass<T,S>.NestedClass>.NestedClass>.NestedClass>.NestedClass,Lambda.Bugs.OuterGenericClass<Lambda.Bugs.OuterGenericClass<Lambda.Bugs.OuterGenericClass<Lambda.Bugs.OuterGenericClass<T,S>.NestedClass,Lambda.Bugs.OuterGenericClass<T,S>.NestedClass>.NestedClass,Lambda.Bugs.OuterGenericClass<Lambda.Bugs.OuterGenericClass<T,S>.NestedClass,Lambda.Bugs.OuterGenericClass<T,S>.NestedClass>.NestedClass>.NestedClass,Lambda.Bugs.OuterGenericClass<Lambda.Bugs.OuterGenericClass<Lambda.Bugs.OuterGenericClass<T,S>.NestedClass,Lambda.Bugs.OuterGenericClass<T,S>.NestedClass>.NestedClass,Lambda.Bugs.OuterGenericClass<Lambda.Bugs.OuterGenericClass<T,S>.NestedClass,Lambda.Bugs.OuterGenericClass<T,S>.NestedClass>.NestedClass>.NestedClass>.NestedClass>.NestedClass>.Goo>b__0' exceeds the maximum length allowed in metadata.
// Func<int> f = () => x;
Diagnostic(ErrorCode.ERR_MetadataNameTooLong, "() => x").WithArguments("<Lambda.Bugs.I<Lambda.Bugs.OuterGenericClass<Lambda.Bugs.OuterGenericClass<Lambda.Bugs.OuterGenericClass<Lambda.Bugs.OuterGenericClass<Lambda.Bugs.OuterGenericClass<T,S>.NestedClass,Lambda.Bugs.OuterGenericClass<T,S>.NestedClass>.NestedClass,Lambda.Bugs.OuterGenericClass<Lambda.Bugs.OuterGenericClass<T,S>.NestedClass,Lambda.Bugs.OuterGenericClass<T,S>.NestedClass>.NestedClass>.NestedClass,Lambda.Bugs.OuterGenericClass<Lambda.Bugs.OuterGenericClass<Lambda.Bugs.OuterGenericClass<T,S>.NestedClass,Lambda.Bugs.OuterGenericClass<T,S>.NestedClass>.NestedClass,Lambda.Bugs.OuterGenericClass<Lambda.Bugs.OuterGenericClass<T,S>.NestedClass,Lambda.Bugs.OuterGenericClass<T,S>.NestedClass>.NestedClass>.NestedClass>.NestedClass,Lambda.Bugs.OuterGenericClass<Lambda.Bugs.OuterGenericClass<Lambda.Bugs.OuterGenericClass<Lambda.Bugs.OuterGenericClass<T,S>.NestedClass,Lambda.Bugs.OuterGenericClass<T,S>.NestedClass>.NestedClass,Lambda.Bugs.OuterGenericClass<Lambda.Bugs.OuterGenericClass<T,S>.NestedClass,Lambda.Bugs.OuterGenericClass<T,S>.NestedClass>.NestedClass>.NestedClass,Lambda.Bugs.OuterGenericClass<Lambda.Bugs.OuterGenericClass<Lambda.Bugs.OuterGenericClass<T,S>.NestedClass,Lambda.Bugs.OuterGenericClass<T,S>.NestedClass>.NestedClass,Lambda.Bugs.OuterGenericClass<Lambda.Bugs.OuterGenericClass<T,S>.NestedClass,Lambda.Bugs.OuterGenericClass<T,S>.NestedClass>.NestedClass>.NestedClass>.NestedClass>.NestedClass>.Goo>b__0").WithLocation(19, 31)
);
}
[WorkItem(540049, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/540049")]
[Fact]
public void LambdaWithUnreachableCode()
{
var source = @"
using System;
class Program
{
static void Main()
{
int x = 7;
Action f = () => { int y; Console.Write(x); return; int z = y; };
f();
}
}
";
CompileAndVerify(source, expectedOutput: "7");
}
[Fact]
[WorkItem(1019237, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/1019237")]
[WorkItem(10838, "https://github.com/mono/mono/issues/10838")]
public void OrderOfDelegateMembers()
{
var source = @"
using System.Linq;
class Program
{
delegate int D1();
static void Main()
{
foreach (var member in typeof(D1).GetMembers(
System.Reflection.BindingFlags.DeclaredOnly |
System.Reflection.BindingFlags.Public |
System.Reflection.BindingFlags.Instance).OrderBy(m=>m.MetadataToken))
{
System.Console.WriteLine(member.ToString());
}
}
}
";
// ref emit would just have different metadata tokens
// we are not interested in testing that
CompileAndVerify(source,
expectedOutput: @"
Void .ctor(System.Object, IntPtr)
Int32 Invoke()
System.IAsyncResult BeginInvoke(System.AsyncCallback, System.Object)
Int32 EndInvoke(System.IAsyncResult)
");
}
[WorkItem(540092, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/540092")]
[Fact]
public void NestedAnonymousMethodsUsingLocalAndField()
{
string source = @"
using System;
delegate void MyDel(int i);
class Test
{
int j = 1;
static int Main()
{
Test t = new Test();
t.goo();
return 0;
}
void goo()
{
int l = 0;
MyDel d = delegate
{
Console.WriteLine(l++);
};
d = delegate(int i)
{
MyDel dd = delegate(int k)
{
Console.WriteLine(i + j + k);
};
dd(10);
};
d(100);
}
}
";
CompileAndVerify(source, expectedOutput: "111");
}
[WorkItem(540129, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/540129")]
[Fact]
public void CacheStaticAnonymousMethodInField()
{
string source = @"
using System;
delegate void D();
public delegate void E<T, U>(T t, U u);
public class Gen<T>
{
public static void Goo<U>(T t, U u)
{
((D)delegate
{
((E<T, U>)delegate(T t2, U u2)
{
// do nothing in order to allow this anonymous method to be cached in a static field
})(t, u);
})();
}
}
public class Test
{
public static void Main()
{
Gen<int>.Goo<string>(1, ""2"");
Console.WriteLine(""PASS"");
}
}
";
CompileAndVerify(source, expectedOutput: "PASS");
}
[WorkItem(540147, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/540147")]
[Fact]
public void CapturedVariableNamedThis()
{
var source =
@"
using System;
class A
{
public int N;
public A(int n)
{
this.N = n;
}
public void Goo(A @this)
{
Action a = () => Bar(@this);
a.Invoke();
}
public void Bar(A other)
{
Console.Write(this.N);
Console.Write(other.N);
}
static void Main()
{
A a = new A(1);
A b = new A(2);
a.Goo(b);
}
}
";
var verifier = CompileAndVerify(
source,
expectedOutput: "12");
}
[Fact]
public void StaticClosureSerialize()
{
string source = @"
using System;
class Program
{
static void Main(string[] args)
{
Func<int> x = () => 42;
System.Console.WriteLine(x.Target.GetType().IsSerializable);
Func<int> y = () => x();
System.Console.WriteLine(y.Target.GetType().IsSerializable);
}
}
";
var compilation = CompileAndVerify(source, options: TestOptions.ReleaseExe, expectedOutput: @"True
False");
}
[Fact]
public void StaticClosureSerializeD()
{
string source = @"
using System;
class Program
{
static void Main(string[] args)
{
Func<int> x = () => 42;
System.Console.WriteLine(x.Target.GetType().IsSerializable);
Func<int> y = () => x();
System.Console.WriteLine(y.Target.GetType().IsSerializable);
}
}
";
var compilation = CompileAndVerify(source, options: TestOptions.DebugExe, expectedOutput: @"True
False");
}
[WorkItem(540178, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/540178")]
[Fact]
public void NestedGenericLambda()
{
var source =
@"
using System;
class Program
{
static void Main()
{
Goo<int>()()();
}
static Func<Func<T>> Goo<T>()
{
T[] x = new T[1];
return () => () => x[0];
}
}
";
var verifier = CompileAndVerify(
source,
expectedOutput: "");
}
[WorkItem(540768, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/540768")]
[Fact]
public void TestClosureMethodAccessibility()
{
var source = @"
using System;
class Test
{
static void Main()
{
}
Func<int, int> f = (x) => 0;
Func<string, string> Goo()
{
string s = """"; Console.WriteLine(s);
return (a) => s;
}
}";
// Dev11 emits "public", we emit "internal" visibility for <Goo>b__1:
CompileAndVerify(source, expectedSignatures: new[]
{
Signature("Test+<>c__DisplayClass2_0", "<Goo>b__0",
".method assembly hidebysig instance System.String <Goo>b__0(System.String a) cil managed"),
});
}
[WorkItem(541008, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/541008")]
[Fact]
public void TooEarlyForThis()
{
// this tests for the C# analogue of VB bug 7520
var source =
@"using System;
class Program
{
int x;
Program(int x) : this(z => x + 10)
{
this.x = x + 100;
F(z => z + x + this.x + 1000);
}
Program(Func<int, int> func)
{}
void F(Func<int, int> func)
{
Console.Write(func(10000));
}
public static void Main(string[] args)
{
new Program(1);
}
}";
var verifier = CompileAndVerify(
source,
expectedOutput: "11102");
}
[WorkItem(542062, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/542062")]
[Fact]
public void TestLambdaNoClosureClass()
{
var source = @"
using System;
delegate int D();
class Test
{
static D field = () => field2;
static short field2 = -1;
public static void Main()
{
D myd = delegate() { return 1; };
Console.WriteLine(""({0},{1})"", myd(), field());
}
}
";
//IMPORTANT!!! we should not be caching static lambda in static initializer.
CompileAndVerify(source, expectedOutput: "(1,-1)").VerifyIL("Test..cctor", @"
{
// Code size 28 (0x1c)
.maxstack 2
IL_0000: ldsfld ""Test.<>c Test.<>c.<>9""
IL_0005: ldftn ""int Test.<>c.<.cctor>b__4_0()""
IL_000b: newobj ""D..ctor(object, System.IntPtr)""
IL_0010: stsfld ""D Test.field""
IL_0015: ldc.i4.m1
IL_0016: stsfld ""short Test.field2""
IL_001b: ret
}
");
}
[WorkItem(543087, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/543087")]
[Fact]
public void LambdaInGenericMethod()
{
var source = @"
using System;
delegate bool D();
class G<T> where T : class
{
public T Fld = default(T);
public static bool RunTest<U>(U u) where U : class
{
G<U> g = new G<U>();
g.Fld = u;
return ((D)(() => Test.Eval(g.Fld == u, true)))();
}
}
class Test
{
public static bool Eval(object obj1, object obj2)
{
return obj1.Equals(obj2);
}
static void Main()
{
var ret = G<string>.RunTest((string)null);
Console.Write(ret);
}
}
";
var verifier = CompileAndVerify(
source,
expectedOutput: "True");
}
[WorkItem(543344, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/543344")]
[Fact]
public void AnonymousMethodOmitParameterList()
{
var source = @"
using System;
class C
{
public int M()
{
Func<C, int> f = delegate { return 9; } ;
return f(new C());
}
static void Main()
{
int r = new C().M();
Console.WriteLine((r == 9) ? 0 : 1);
}
}
";
var verifier = CompileAndVerify(
source,
expectedOutput: "0");
}
[WorkItem(543345, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/543345")]
[Fact()]
public void ExtraCompilerGeneratedAttribute()
{
string source = @"using System;
using System.Reflection;
using System.Runtime.CompilerServices;
class Test
{
static public System.Collections.IEnumerable myIterator(int start, int end)
{
for (int i = start; i <= end; i++)
{
yield return (Func<int,int>)((x) => { return i + x; });
}
yield break;
}
static void Main()
{
var type = typeof(Test);
var nested = type.GetNestedTypes(BindingFlags.NonPublic | BindingFlags.Instance);
var total = 0;
if (nested.Length > 0 && nested[0].Name.StartsWith(""<>c__DisplayClass"", StringComparison.Ordinal))
{
foreach (MemberInfo mi in nested[0].GetMembers(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance))
{
var ca = mi.GetCustomAttributes(typeof(CompilerGeneratedAttribute), false);
foreach (var a in ca) Console.WriteLine(mi + "": "" + a);
total += ca.Length;
}
}
Console.WriteLine(total);
}
}
";
var compilation = CompileAndVerify(source, expectedOutput: "0");
}
[WorkItem(545430, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/545430")]
[Fact]
public void CacheNonStaticLambdaInGenericMethod()
{
var source = @"
using System.Collections.Generic;
using System.Linq;
class C
{
static void M<T>(List<T> dd, int p) where T : D
{
do{
if (dd != null)
{
var last = dd.LastOrDefault(m => m.P <= p);
if (dd.Count() > 1)
{
dd.Reverse();
}
}
} while(false);
}
}
class D
{
public int P { get; set; }
}
";
var comp = CreateCompilationWithMscorlib40AndSystemCore(source, options: TestOptions.ReleaseDll);
var verifier = CompileAndVerify(comp, expectedSignatures: new[]
{
Signature("C+<>c__DisplayClass0_0`1", "<>9__0",
".field public instance System.Func`2[T,System.Boolean] <>9__0")
});
verifier.VerifyIL("C.M<T>", @"
{
// Code size 70 (0x46)
.maxstack 4
.locals init (C.<>c__DisplayClass0_0<T> V_0, //CS$<>8__locals0
System.Func<T, bool> V_1)
IL_0000: newobj ""C.<>c__DisplayClass0_0<T>..ctor()""
IL_0005: stloc.0
IL_0006: ldloc.0
IL_0007: ldarg.1
IL_0008: stfld ""int C.<>c__DisplayClass0_0<T>.p""
IL_000d: ldarg.0
IL_000e: brfalse.s IL_0045
IL_0010: ldarg.0
IL_0011: ldloc.0
IL_0012: ldfld ""System.Func<T, bool> C.<>c__DisplayClass0_0<T>.<>9__0""
IL_0017: dup
IL_0018: brtrue.s IL_0030
IL_001a: pop
IL_001b: ldloc.0
IL_001c: ldloc.0
IL_001d: ldftn ""bool C.<>c__DisplayClass0_0<T>.<M>b__0(T)""
IL_0023: newobj ""System.Func<T, bool>..ctor(object, System.IntPtr)""
IL_0028: dup
IL_0029: stloc.1
IL_002a: stfld ""System.Func<T, bool> C.<>c__DisplayClass0_0<T>.<>9__0""
IL_002f: ldloc.1
IL_0030: call ""T System.Linq.Enumerable.LastOrDefault<T>(System.Collections.Generic.IEnumerable<T>, System.Func<T, bool>)""
IL_0035: pop
IL_0036: ldarg.0
IL_0037: call ""int System.Linq.Enumerable.Count<T>(System.Collections.Generic.IEnumerable<T>)""
IL_003c: ldc.i4.1
IL_003d: ble.s IL_0045
IL_003f: ldarg.0
IL_0040: callvirt ""void System.Collections.Generic.List<T>.Reverse()""
IL_0045: ret
}
");
}
[Fact]
public void CacheNonStaticLambda001()
{
var source = @"
using System;
class Program
{
static void Main(string[] args)
{
}
class Executor
{
public void Execute(Func<int, int> f)
{
f(42);
}
}
Executor[] arr = new Executor[] { new Executor() };
void Test()
{
int x = 123;
for (int i = 1; i < 10; i++)
{
if (i < 2)
{
arr[i].Execute(arg => arg + x); // delegate should be cached
}
}
for (int i = 1; i < 10; i++)
{
var val = i;
if (i < 2)
{
int y = i + i;
System.Console.WriteLine(y);
arr[i].Execute(arg => arg + val); // delegate should NOT be cached (closure created inside the loop)
}
}
}
}
";
var comp = CreateCompilationWithMscorlib40AndSystemCore(source, options: TestOptions.ReleaseDll);
var verifier = CompileAndVerify(comp);
verifier.VerifyIL("Program.Test", @"
{
// Code size 142 (0x8e)
.maxstack 4
.locals init (Program.<>c__DisplayClass3_0 V_0, //CS$<>8__locals0
int V_1, //i
System.Func<int, int> V_2,
int V_3, //i
Program.<>c__DisplayClass3_1 V_4) //CS$<>8__locals1
IL_0000: newobj ""Program.<>c__DisplayClass3_0..ctor()""
IL_0005: stloc.0
IL_0006: ldloc.0
IL_0007: ldc.i4.s 123
IL_0009: stfld ""int Program.<>c__DisplayClass3_0.x""
IL_000e: ldc.i4.1
IL_000f: stloc.1
IL_0010: br.s IL_0046
IL_0012: ldloc.1
IL_0013: ldc.i4.2
IL_0014: bge.s IL_0042
IL_0016: ldarg.0
IL_0017: ldfld ""Program.Executor[] Program.arr""
IL_001c: ldloc.1
IL_001d: ldelem.ref
IL_001e: ldloc.0
IL_001f: ldfld ""System.Func<int, int> Program.<>c__DisplayClass3_0.<>9__0""
IL_0024: dup
IL_0025: brtrue.s IL_003d
IL_0027: pop
IL_0028: ldloc.0
IL_0029: ldloc.0
IL_002a: ldftn ""int Program.<>c__DisplayClass3_0.<Test>b__0(int)""
IL_0030: newobj ""System.Func<int, int>..ctor(object, System.IntPtr)""
IL_0035: dup
IL_0036: stloc.2
IL_0037: stfld ""System.Func<int, int> Program.<>c__DisplayClass3_0.<>9__0""
IL_003c: ldloc.2
IL_003d: callvirt ""void Program.Executor.Execute(System.Func<int, int>)""
IL_0042: ldloc.1
IL_0043: ldc.i4.1
IL_0044: add
IL_0045: stloc.1
IL_0046: ldloc.1
IL_0047: ldc.i4.s 10
IL_0049: blt.s IL_0012
IL_004b: ldc.i4.1
IL_004c: stloc.3
IL_004d: br.s IL_0088
IL_004f: newobj ""Program.<>c__DisplayClass3_1..ctor()""
IL_0054: stloc.s V_4
IL_0056: ldloc.s V_4
IL_0058: ldloc.3
IL_0059: stfld ""int Program.<>c__DisplayClass3_1.val""
IL_005e: ldloc.3
IL_005f: ldc.i4.2
IL_0060: bge.s IL_0084
IL_0062: ldloc.3
IL_0063: ldloc.3
IL_0064: add
IL_0065: call ""void System.Console.WriteLine(int)""
IL_006a: ldarg.0
IL_006b: ldfld ""Program.Executor[] Program.arr""
IL_0070: ldloc.3
IL_0071: ldelem.ref
IL_0072: ldloc.s V_4
IL_0074: ldftn ""int Program.<>c__DisplayClass3_1.<Test>b__1(int)""
IL_007a: newobj ""System.Func<int, int>..ctor(object, System.IntPtr)""
IL_007f: callvirt ""void Program.Executor.Execute(System.Func<int, int>)""
IL_0084: ldloc.3
IL_0085: ldc.i4.1
IL_0086: add
IL_0087: stloc.3
IL_0088: ldloc.3
IL_0089: ldc.i4.s 10
IL_008b: blt.s IL_004f
IL_008d: ret
}
");
}
[Fact]
public void CacheNonStaticLambda002()
{
var source = @"
using System;
class Program
{
static void Main(string[] args)
{
}
void Test()
{
int y = 123;
Func<int, Func<int>> f1 =
// should be cached
(x) =>
{
if (x > 0)
{
int z = 123;
System.Console.WriteLine(z);
return () => y;
}
return null;
};
f1(1);
Func<int, Func<int>> f2 =
// should NOT be cached
(x) =>
{
if (x > 0)
{
int z = 123;
System.Console.WriteLine(z);
return () => x;
}
return null;
};
f2(1);
}
}
";
var comp = CreateCompilationWithMscorlib40AndSystemCore(source, options: TestOptions.ReleaseDll);
var verifier = CompileAndVerify(comp);
verifier.VerifyIL("Program.Test", @"
{
// Code size 70 (0x46)
.maxstack 3
IL_0000: newobj ""Program.<>c__DisplayClass1_0..ctor()""
IL_0005: dup
IL_0006: ldc.i4.s 123
IL_0008: stfld ""int Program.<>c__DisplayClass1_0.y""
IL_000d: ldftn ""System.Func<int> Program.<>c__DisplayClass1_0.<Test>b__0(int)""
IL_0013: newobj ""System.Func<int, System.Func<int>>..ctor(object, System.IntPtr)""
IL_0018: ldc.i4.1
IL_0019: callvirt ""System.Func<int> System.Func<int, System.Func<int>>.Invoke(int)""
IL_001e: pop
IL_001f: ldsfld ""System.Func<int, System.Func<int>> Program.<>c.<>9__1_1""
IL_0024: dup
IL_0025: brtrue.s IL_003e
IL_0027: pop
IL_0028: ldsfld ""Program.<>c Program.<>c.<>9""
IL_002d: ldftn ""System.Func<int> Program.<>c.<Test>b__1_1(int)""
IL_0033: newobj ""System.Func<int, System.Func<int>>..ctor(object, System.IntPtr)""
IL_0038: dup
IL_0039: stsfld ""System.Func<int, System.Func<int>> Program.<>c.<>9__1_1""
IL_003e: ldc.i4.1
IL_003f: callvirt ""System.Func<int> System.Func<int, System.Func<int>>.Invoke(int)""
IL_0044: pop
IL_0045: ret
}
");
verifier.VerifyIL("Program.<>c.<Test>b__1_1(int)",
@"
{
// Code size 44 (0x2c)
.maxstack 2
.locals init (Program.<>c__DisplayClass1_1 V_0) //CS$<>8__locals0
IL_0000: newobj ""Program.<>c__DisplayClass1_1..ctor()""
IL_0005: stloc.0
IL_0006: ldloc.0
IL_0007: ldarg.1
IL_0008: stfld ""int Program.<>c__DisplayClass1_1.x""
IL_000d: ldloc.0
IL_000e: ldfld ""int Program.<>c__DisplayClass1_1.x""
IL_0013: ldc.i4.0
IL_0014: ble.s IL_002a
IL_0016: ldc.i4.s 123
IL_0018: call ""void System.Console.WriteLine(int)""
IL_001d: ldloc.0
IL_001e: ldftn ""int Program.<>c__DisplayClass1_1.<Test>b__3()""
IL_0024: newobj ""System.Func<int>..ctor(object, System.IntPtr)""
IL_0029: ret
IL_002a: ldnull
IL_002b: ret
}
"
);
verifier.VerifyIL("Program.<>c__DisplayClass1_0.<Test>b__0(int)",
@"
{
// Code size 45 (0x2d)
.maxstack 3
.locals init (System.Func<int> V_0)
IL_0000: ldarg.1
IL_0001: ldc.i4.0
IL_0002: ble.s IL_002b
IL_0004: ldc.i4.s 123
IL_0006: call ""void System.Console.WriteLine(int)""
IL_000b: ldarg.0
IL_000c: ldfld ""System.Func<int> Program.<>c__DisplayClass1_0.<>9__2""
IL_0011: dup
IL_0012: brtrue.s IL_002a
IL_0014: pop
IL_0015: ldarg.0
IL_0016: ldarg.0
IL_0017: ldftn ""int Program.<>c__DisplayClass1_0.<Test>b__2()""
IL_001d: newobj ""System.Func<int>..ctor(object, System.IntPtr)""
IL_0022: dup
IL_0023: stloc.0
IL_0024: stfld ""System.Func<int> Program.<>c__DisplayClass1_0.<>9__2""
IL_0029: ldloc.0
IL_002a: ret
IL_002b: ldnull
IL_002c: ret
}
"
);
}
[WorkItem(546211, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/546211")]
[Fact]
public void LambdaInCatchInLambdaInInstance()
{
var source =
@"using System;
static class Utilities
{
internal static void ReportException(object _componentModelHost, Exception e, string p) { }
internal static void BeginInvoke(Action a) { }
}
class VsCatalogProvider
{
private object _componentModelHost = null;
static void Main()
{
Console.WriteLine(""success"");
}
private void TryIsolatedOperation()
{
Action action = new Action(() =>
{
try
{
}
catch (Exception ex)
{
Utilities.BeginInvoke(new Action(() =>
{
Utilities.ReportException(_componentModelHost, ex, string.Empty);
}));
}
});
}
}";
var compilation = CompileAndVerify(source, expectedOutput: "success");
}
[WorkItem(546748, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/546748")]
[Fact]
public void LambdaWithCatchTypeParameter()
{
var source =
@"using System;
class Program
{
static void Main() { }
public static void Sleep<TException>(Func<bool> sleepDelegate) where TException : Exception
{
Func<bool> x = delegate
{
try
{
return sleepDelegate();
}
catch (TException e)
{
}
return false;
};
}
}";
CompileAndVerify(source);
}
[WorkItem(546748, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/546748")]
[Fact]
public void LambdaWithCapturedCatchTypeParameter()
{
var source =
@"using System;
class Program
{
static void Main() { }
public static void Sleep<TException>(Func<bool> sleepDelegate) where TException : Exception
{
Func<bool> x = delegate
{
try
{
return sleepDelegate();
}
catch (TException e)
{
Func<bool> x2 = delegate {
return e == null;
};
}
return false;
};
}
}";
var compilation = CompileAndVerify(source);
}
[WorkItem(530911, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/530911")]
[Fact]
public void LambdaWithOutParameter()
{
var source =
@"
using System;
delegate D D(out D d);
class Program
{
static void Main()
{
D tmpD = delegate (out D d)
{
throw new System.Exception();
};
D d01 = delegate (out D d)
{
tmpD(out d);
d(out d);
return d;
};
}
}
";
var compilation = CompileAndVerify(source);
}
[WorkItem(691006, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/691006")]
[Fact]
public void LambdaWithSwitch()
{
var source =
@"
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using System.Threading;
namespace ConsoleApplication16
{
class Program
{
public static Task<IEnumerable<TResult>> Iterate<TResult>(IEnumerable<Task> asyncIterator, CancellationToken cancellationToken = default(CancellationToken))
{
var results = new List<TResult>();
var tcs = new TaskCompletionSource<IEnumerable<TResult>>();
IEnumerator<Task> enumerator = asyncIterator.GetEnumerator();
Action recursiveBody = null;
recursiveBody = () =>
{
try
{
if (cancellationToken.IsCancellationRequested)
{
tcs.TrySetCanceled();
}
else if (enumerator.MoveNext())
{
enumerator.Current.ContinueWith(previous =>
{
switch (previous.Status)
{
case TaskStatus.Faulted:
case TaskStatus.Canceled:
tcs.SetResult((previous as Task<IEnumerable<TResult>>).Result);
break;
default:
var previousWithResult = previous as Task<TResult>;
if (previousWithResult != null)
{
results.Add(previousWithResult.Result);
}
else
{
results.Add(default(TResult));
}
recursiveBody();
break;
}
});
}
else
{
tcs.TrySetResult(results);
}
}
catch (Exception e)
{
tcs.TrySetException(e);
}
};
recursiveBody();
return tcs.Task;
}
static void Main(string[] args)
{
}
}
}
";
CompileAndVerify(source);
}
#endregion
[Fact]
public void LambdaInQuery_Let()
{
var source = @"
using System;
using System.Linq;
class C
{
public void F(int[] array)
{
var f = from item in array
let a = new Func<int>(() => item)
select a() + new Func<int>(() => item)();
}
}";
CompileAndVerify(source);
}
[Fact]
public void LambdaInQuery_From()
{
var source = @"
using System;
using System.Linq;
class C
{
public void F(int[] array)
{
var f = from item1 in new Func<int[]>(() => array)()
from item2 in new Func<int[]>(() => array)()
select item1 + item2;
}
}";
CompileAndVerify(source);
}
[Fact]
public void EmbeddedStatementClosures1()
{
var source = @"
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
class C
{
public void G<T>(Func<T> f) {}
public void F()
{
for (int x = 1, y = 2; x < 10; x++) G(() => x + y);
for (int x = 1, y = 2; x < 10; x++) { G(() => x + y); }
foreach (var x in new[] { 1, 2, 3 }) G(() => x);
foreach (var x in new[] { 1, 2, 3 }) { G(() => x); }
foreach (var x in new[,] { {1}, {2}, {3} }) G(() => x);
foreach (var x in new[,] { {1}, {2}, {3} }) { G(() => x); }
foreach (var x in ""123"") G(() => x);
foreach (var x in ""123"") { G(() => x); }
foreach (var x in new List<string>()) G(() => x);
foreach (var x in new List<string>()) { G(() => x); }
using (var x = new MemoryStream()) G(() => x);
using (var x = new MemoryStream()) G(() => x);
}
}";
CompileAndVerify(source);
}
[Fact, WorkItem(2549, "https://github.com/dotnet/roslyn/issues/2549")]
public void NestedLambdaWithExtensionMethodsInGeneric()
{
var source =
@"using System;
using System.Collections.Generic;
using System.Linq;
public class BadBaby
{
IEnumerable<object> Children;
public object Goo<T>()
{
return from child in Children select from T ch in Children select false;
}
}";
CompileAndVerify(source);
}
[WorkItem(9131, "https://github.com/dotnet/roslyn/issues/9131")]
[Fact]
public void ClosureInSwitchStatementWithNullableExpression()
{
string source =
@"using System;
class C
{
static void Main()
{
int? i = null;
switch (i)
{
default:
object o = null;
Func<object> f = () => o;
Console.Write(""{0}"", f() == null);
break;
case 0:
o = 1;
break;
}
}
}";
var compilation = CompileAndVerify(source, expectedOutput: @"True");
compilation.VerifyIL("C.Main",
@"{
// Code size 90 (0x5a)
.maxstack 3
.locals init (int? V_0, //i
C.<>c__DisplayClass0_0 V_1, //CS$<>8__locals0
System.Func<object> V_2) //f
IL_0000: ldloca.s V_0
IL_0002: initobj ""int?""
IL_0008: newobj ""C.<>c__DisplayClass0_0..ctor()""
IL_000d: stloc.1
IL_000e: ldloca.s V_0
IL_0010: call ""bool int?.HasValue.get""
IL_0015: brfalse.s IL_0020
IL_0017: ldloca.s V_0
IL_0019: call ""int int?.GetValueOrDefault()""
IL_001e: brfalse.s IL_004d
IL_0020: ldloc.1
IL_0021: ldnull
IL_0022: stfld ""object C.<>c__DisplayClass0_0.o""
IL_0027: ldloc.1
IL_0028: ldftn ""object C.<>c__DisplayClass0_0.<Main>b__0()""
IL_002e: newobj ""System.Func<object>..ctor(object, System.IntPtr)""
IL_0033: stloc.2
IL_0034: ldstr ""{0}""
IL_0039: ldloc.2
IL_003a: callvirt ""object System.Func<object>.Invoke()""
IL_003f: ldnull
IL_0040: ceq
IL_0042: box ""bool""
IL_0047: call ""void System.Console.Write(string, object)""
IL_004c: ret
IL_004d: ldloc.1
IL_004e: ldc.i4.1
IL_004f: box ""int""
IL_0054: stfld ""object C.<>c__DisplayClass0_0.o""
IL_0059: ret
}");
}
[WorkItem(44720, "https://github.com/dotnet/roslyn/issues/44720")]
[Fact]
public void LambdaDependentOnEnclosingLocalFunctionTypeParameter1_CompilesCorrectly()
{
// The lambda passed into StaticMethod depends on TLocal type argument of LocalMethod
// so if the delegate is cached outside the method the type argument reference is broken
// and code throws BadImageFormatException. Such a broken code will looks like:
// class DisplayClass
// {
// Func<TLocal, string> _cachedDelegate;
//
// void LocalMethod<TLocal>()
// {
// ...
// }
//
// The test checks that it is not the issue.
string source =
@"using System;
using System.Collections.Generic;
static class Program
{
private static void Main()
{
TestMethod(string.Empty);
}
private static void TestMethod<T>(T param)
{
var message = string.Empty;
for (int i = 0; i < 1; i++)
{
void LocalFunction<TLocal>(TLocal value)
{
StaticMethod(value, param, (_, __) => message);
StaticMethod(new List<TLocal> { value }, param, (_, __) => message);
StaticMethod(new TLocal[] { value }, param, (_, __) => message);
}
message = i.ToString();
LocalFunction<string>(string.Empty);
}
}
static void StaticMethod<TFirst, TSecond, TOut>(TFirst first, TSecond second, Func<TFirst, TSecond, TOut> func)
{
Console.Write($""{func(first, second)}-{typeof(TFirst)};"");
}
}";
CompileAndVerify(source, expectedOutput: @"0-System.String;0-System.Collections.Generic.List`1[System.String];0-System.String[];");
}
/// <summary>
/// Check <see cref="LambdaDependentOnEnclosingLocalFunctionTypeParameter1_CompilesCorrectly"/> summary
/// for the test case description
/// </summary>
[WorkItem(44720, "https://github.com/dotnet/roslyn/issues/44720")]
[Fact]
public void LambdaDependentOnEnclosingLocalFunctionTypeParameter2_CompilesCorrectly()
{
string source =
@"using System;
using System.Collections.Generic;
static class Program
{
private static void Main()
{
TestMethod(string.Empty);
}
private static void TestMethod<T>(T param)
{
var message = string.Empty;
for (int i = 0; i < 1; i++)
{
void LocalFunction<TLocal>(TLocal value)
{
InnerLocalFunction();
void InnerLocalFunction()
{
StaticMethod(value, param, (_, __) => message);
StaticMethod(new List<TLocal> { value }, param, (_, __) => message);
StaticMethod(new TLocal[] { value }, param, (_, __) => message);
}
}
message = i.ToString();
LocalFunction<string>(string.Empty);
}
}
static void StaticMethod<TFirst, TSecond, TOut>(TFirst first, TSecond second, Func<TFirst, TSecond, TOut> func)
{
Console.Write($""{func(first, second)}-{typeof(TFirst)};"");
}
}";
CompileAndVerify(source, expectedOutput: @"0-System.String;0-System.Collections.Generic.List`1[System.String];0-System.String[];");
}
/// <summary>
/// Check <see cref="LambdaDependentOnEnclosingLocalFunctionTypeParameter1_CompilesCorrectly"/> summary
/// for the test case description
/// </summary>
[WorkItem(44720, "https://github.com/dotnet/roslyn/issues/44720")]
[Fact]
public void LambdaDependentOnEnclosingLocalFunctionTypeParameter3_CompilesCorrectly()
{
string source =
@"using System;
using System.Collections.Generic;
static class Program
{
private static void Main()
{
TestMethod(string.Empty);
}
private static void TestMethod<T>(T param)
{
var message = string.Empty;
OuterLocalFunction();
void OuterLocalFunction()
{
for (int i = 0; i < 1; i++)
{
void LocalFunction<TLocal>(TLocal value)
{
StaticMethod(value, param, (_, __) => message);
StaticMethod(new List<TLocal> { value }, param, (_, __) => message);
StaticMethod(new TLocal[] { value }, param, (_, __) => message);
}
message = i.ToString();
LocalFunction<string>(string.Empty);
}
}
}
static void StaticMethod<TFirst, TSecond, TOut>(TFirst first, TSecond second, Func<TFirst, TSecond, TOut> func)
{
Console.Write($""{func(first, second)}-{typeof(TFirst)};"");
}
}";
CompileAndVerify(source, expectedOutput: @"0-System.String;0-System.Collections.Generic.List`1[System.String];0-System.String[];");
}
[WorkItem(44720, "https://github.com/dotnet/roslyn/issues/44720")]
[Fact]
public void LambdaInsideLocalFunctionInsideLoop_IsCached()
{
string source =
@"using System;
using System.Collections.Generic;
static class Program
{
private static void Main()
{
var message = string.Empty;
for (int i = 0; i < 1; i++)
{
void LocalMethod()
{
StaticMethod(message, _ => message);
}
message = i.ToString();
LocalMethod();
}
}
static void StaticMethod<TIn, TOut>(TIn value, Func<TIn, TOut> func)
{
Console.Write($""{func(value)}-{typeof(TIn)};"");
}
}";
var compilation = CompileAndVerify(source, expectedOutput: @"0-System.String;");
compilation.VerifyIL("Program.<>c__DisplayClass0_0.<Main>g__LocalMethod|0()",
@"{
// Code size 43 (0x2b)
.maxstack 4
.locals init (System.Func<string, string> V_0)
IL_0000: ldarg.0
IL_0001: ldfld ""string Program.<>c__DisplayClass0_0.message""
IL_0006: ldarg.0
IL_0007: ldfld ""System.Func<string, string> Program.<>c__DisplayClass0_0.<>9__1""
IL_000c: dup
IL_000d: brtrue.s IL_0025
IL_000f: pop
IL_0010: ldarg.0
IL_0011: ldarg.0
IL_0012: ldftn ""string Program.<>c__DisplayClass0_0.<Main>b__1(string)""
IL_0018: newobj ""System.Func<string, string>..ctor(object, System.IntPtr)""
IL_001d: dup
IL_001e: stloc.0
IL_001f: stfld ""System.Func<string, string> Program.<>c__DisplayClass0_0.<>9__1""
IL_0024: ldloc.0
IL_0025: call ""void Program.StaticMethod<string, string>(string, System.Func<string, string>)""
IL_002a: ret
}");
}
[WorkItem(44720, "https://github.com/dotnet/roslyn/issues/44720")]
[Fact]
public void LambdaDependentOnEnclosingMethodTypeParameter_IsCached()
{
string source =
@"using System;
using System.Collections.Generic;
static class Program
{
private static void Main()
{
TestMethod(string.Empty);
}
private static void TestMethod<T>(T param)
{
var message = string.Empty;
for (int i = 0; i < 1; i++)
{
message = i.ToString();
StaticMethod(param, _ => message);
}
}
static void StaticMethod<TIn, TOut>(TIn value, Func<TIn, TOut> func)
{
Console.Write($""{func(value)}-{typeof(TIn)};"");
}
}";
var compilation = CompileAndVerify(source, expectedOutput: @"0-System.String;");
compilation.VerifyIL("Program.TestMethod<T>(T)",
@"{
// Code size 80 (0x50)
.maxstack 4
.locals init (Program.<>c__DisplayClass1_0<T> V_0, //CS$<>8__locals0
int V_1, //i
System.Func<T, string> V_2)
IL_0000: newobj ""Program.<>c__DisplayClass1_0<T>..ctor()""
IL_0005: stloc.0
IL_0006: ldloc.0
IL_0007: ldsfld ""string string.Empty""
IL_000c: stfld ""string Program.<>c__DisplayClass1_0<T>.message""
IL_0011: ldc.i4.0
IL_0012: stloc.1
IL_0013: br.s IL_004b
IL_0015: ldloc.0
IL_0016: ldloca.s V_1
IL_0018: call ""string int.ToString()""
IL_001d: stfld ""string Program.<>c__DisplayClass1_0<T>.message""
IL_0022: ldarg.0
IL_0023: ldloc.0
IL_0024: ldfld ""System.Func<T, string> Program.<>c__DisplayClass1_0<T>.<>9__0""
IL_0029: dup
IL_002a: brtrue.s IL_0042
IL_002c: pop
IL_002d: ldloc.0
IL_002e: ldloc.0
IL_002f: ldftn ""string Program.<>c__DisplayClass1_0<T>.<TestMethod>b__0(T)""
IL_0035: newobj ""System.Func<T, string>..ctor(object, System.IntPtr)""
IL_003a: dup
IL_003b: stloc.2
IL_003c: stfld ""System.Func<T, string> Program.<>c__DisplayClass1_0<T>.<>9__0""
IL_0041: ldloc.2
IL_0042: call ""void Program.StaticMethod<T, string>(T, System.Func<T, string>)""
IL_0047: ldloc.1
IL_0048: ldc.i4.1
IL_0049: add
IL_004a: stloc.1
IL_004b: ldloc.1
IL_004c: ldc.i4.1
IL_004d: blt.s IL_0015
IL_004f: ret
}");
}
[WorkItem(44720, "https://github.com/dotnet/roslyn/issues/44720")]
[Fact]
public void LambdaInsideGenericLocalFunction_IsCached()
{
string source =
@"using System;
using System.Collections.Generic;
static class Program
{
private static void Main()
{
TestMethod(string.Empty);
}
private static void TestMethod<T>(T param)
{
var message = string.Empty;
for (int i = 0; i < 1; i++)
{
void LocalFunction<TLocal>(TLocal value)
{
StaticMethod(param, _ => message);
}
message = i.ToString();
LocalFunction<string>(string.Empty);
}
}
static void StaticMethod<TIn, TOut>(TIn value, Func<TIn, TOut> func)
{
Console.Write($""{func(value)}-{typeof(TIn)};"");
}
}";
var compilation = CompileAndVerify(source, expectedOutput: @"0-System.String;");
compilation.VerifyIL("Program.<>c__DisplayClass1_0<T>.<TestMethod>g__LocalFunction|0<TLocal>(TLocal)",
@"{
// Code size 43 (0x2b)
.maxstack 4
.locals init (System.Func<T, string> V_0)
IL_0000: ldarg.0
IL_0001: ldfld ""T Program.<>c__DisplayClass1_0<T>.param""
IL_0006: ldarg.0
IL_0007: ldfld ""System.Func<T, string> Program.<>c__DisplayClass1_0<T>.<>9__1""
IL_000c: dup
IL_000d: brtrue.s IL_0025
IL_000f: pop
IL_0010: ldarg.0
IL_0011: ldarg.0
IL_0012: ldftn ""string Program.<>c__DisplayClass1_0<T>.<TestMethod>b__1<TLocal>(T)""
IL_0018: newobj ""System.Func<T, string>..ctor(object, System.IntPtr)""
IL_001d: dup
IL_001e: stloc.0
IL_001f: stfld ""System.Func<T, string> Program.<>c__DisplayClass1_0<T>.<>9__1""
IL_0024: ldloc.0
IL_0025: call ""void Program.StaticMethod<T, string>(T, System.Func<T, string>)""
IL_002a: ret
}");
}
[WorkItem(44720, "https://github.com/dotnet/roslyn/issues/44720")]
[Fact]
public void LambdaInsideGenericMethod_IsCached()
{
string source =
@"using System;
using System.Collections.Generic;
static class Program
{
private static void Main()
{
TestMethod(string.Empty);
}
private static void TestMethod<T>(T param)
{
var message = string.Empty;
for (int i = 0; i < 1; i++)
{
message = i.ToString();
StaticMethod(param, _ => message);
}
}
static void StaticMethod<TIn, TOut>(TIn value, Func<TIn, TOut> func)
{
Console.Write($""{func(value)}-{typeof(TIn)};"");
}
}";
var compilation = CompileAndVerify(source, expectedOutput: @"0-System.String;");
compilation.VerifyIL("Program.TestMethod<T>(T)",
@"{
// Code size 80 (0x50)
.maxstack 4
.locals init (Program.<>c__DisplayClass1_0<T> V_0, //CS$<>8__locals0
int V_1, //i
System.Func<T, string> V_2)
IL_0000: newobj ""Program.<>c__DisplayClass1_0<T>..ctor()""
IL_0005: stloc.0
IL_0006: ldloc.0
IL_0007: ldsfld ""string string.Empty""
IL_000c: stfld ""string Program.<>c__DisplayClass1_0<T>.message""
IL_0011: ldc.i4.0
IL_0012: stloc.1
IL_0013: br.s IL_004b
IL_0015: ldloc.0
IL_0016: ldloca.s V_1
IL_0018: call ""string int.ToString()""
IL_001d: stfld ""string Program.<>c__DisplayClass1_0<T>.message""
IL_0022: ldarg.0
IL_0023: ldloc.0
IL_0024: ldfld ""System.Func<T, string> Program.<>c__DisplayClass1_0<T>.<>9__0""
IL_0029: dup
IL_002a: brtrue.s IL_0042
IL_002c: pop
IL_002d: ldloc.0
IL_002e: ldloc.0
IL_002f: ldftn ""string Program.<>c__DisplayClass1_0<T>.<TestMethod>b__0(T)""
IL_0035: newobj ""System.Func<T, string>..ctor(object, System.IntPtr)""
IL_003a: dup
IL_003b: stloc.2
IL_003c: stfld ""System.Func<T, string> Program.<>c__DisplayClass1_0<T>.<>9__0""
IL_0041: ldloc.2
IL_0042: call ""void Program.StaticMethod<T, string>(T, System.Func<T, string>)""
IL_0047: ldloc.1
IL_0048: ldc.i4.1
IL_0049: add
IL_004a: stloc.1
IL_004b: ldloc.1
IL_004c: ldc.i4.1
IL_004d: blt.s IL_0015
IL_004f: ret
}");
}
}
}
|