|
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
#nullable disable
using System;
using System.Collections.Generic;
using System.Linq;
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 CodeGenAsyncSpillTests : EmitMetadataTestBase
{
public CodeGenAsyncSpillTests()
{
}
private CompilationVerifier CompileAndVerify(string source, string expectedOutput = null, IEnumerable<MetadataReference> references = null, CSharpCompilationOptions options = null)
{
return base.CompileAndVerify(source, expectedOutput: expectedOutput, references: references, options: options);
}
[Fact]
public void AsyncWithTernary()
{
var source = @"
using System;
using System.Threading.Tasks;
class Test
{
public static Task<T> F<T>(T x)
{
Console.WriteLine(""F("" + x + "")"");
return Task.Factory.StartNew(() => { return x; });
}
public static async Task<int> G(bool b1, bool b2)
{
int c = 0;
c = c + (b1 ? 1 : await F(2));
c = c + (b2 ? await F(4) : 8);
return await F(c);
}
public static int H(bool b1, bool b2)
{
Task<int> t = G(b1, b2);
t.Wait(1000 * 60);
return t.Result;
}
public static void Main()
{
Console.WriteLine(H(false, false));
Console.WriteLine(H(false, true));
Console.WriteLine(H(true, false));
Console.WriteLine(H(true, true));
}
}";
var expectedOutput = @"
F(2)
F(10)
10
F(2)
F(4)
F(6)
6
F(9)
9
F(4)
F(5)
5
";
CompileAndVerify(source, expectedOutput: expectedOutput);
var comp = CreateRuntimeAsyncCompilation(source);
var verifier = CompileAndVerify(comp, expectedOutput: CodeGenAsyncTests.ExpectedOutput(expectedOutput, isRuntimeAsync: true), verify: Verification.Fails with
{
ILVerifyMessage = """
[G]: Unexpected type on the stack. { Offset = 0x35, Found = Int32, Expected = ref '[System.Runtime]System.Threading.Tasks.Task`1<int32>' }
"""
});
verifier.VerifyDiagnostics();
verifier.VerifyIL("Test.G(bool, bool)", """
{
// Code size 54 (0x36)
.maxstack 2
.locals init (int V_0)
IL_0000: ldc.i4.0
IL_0001: ldarg.0
IL_0002: brfalse.s IL_0008
IL_0004: ldc.i4.1
IL_0005: stloc.0
IL_0006: br.s IL_0014
IL_0008: ldc.i4.2
IL_0009: call "System.Threading.Tasks.Task<int> Test.F<int>(int)"
IL_000e: call "int System.Runtime.CompilerServices.AsyncHelpers.Await<int>(System.Threading.Tasks.Task<int>)"
IL_0013: stloc.0
IL_0014: ldloc.0
IL_0015: add
IL_0016: ldarg.1
IL_0017: brfalse.s IL_0027
IL_0019: ldc.i4.4
IL_001a: call "System.Threading.Tasks.Task<int> Test.F<int>(int)"
IL_001f: call "int System.Runtime.CompilerServices.AsyncHelpers.Await<int>(System.Threading.Tasks.Task<int>)"
IL_0024: stloc.0
IL_0025: br.s IL_0029
IL_0027: ldc.i4.8
IL_0028: stloc.0
IL_0029: ldloc.0
IL_002a: add
IL_002b: call "System.Threading.Tasks.Task<int> Test.F<int>(int)"
IL_0030: call "int System.Runtime.CompilerServices.AsyncHelpers.Await<int>(System.Threading.Tasks.Task<int>)"
IL_0035: ret
}
""");
}
[Fact]
public void AsyncWithAnd()
{
var source = @"
using System;
using System.Threading.Tasks;
class Test
{
public static Task<T> F<T>(T x)
{
Console.WriteLine(""F("" + x + "")"");
return Task.Factory.StartNew(() => { return x; });
}
public static async Task<int> G(bool b1, bool b2)
{
bool x1 = b1 && await F(true);
bool x2 = b1 && await F(false);
bool x3 = b2 && await F(true);
bool x4 = b2 && await F(false);
int c = 0;
if (x1) c += 1;
if (x2) c += 2;
if (x3) c += 4;
if (x4) c += 8;
return await F(c);
}
public static int H(bool b1, bool b2)
{
Task<int> t = G(b1, b2);
t.Wait(1000 * 60);
return t.Result;
}
public static void Main()
{
Console.WriteLine(H(false, true));
}
}";
var expectedOutput = @"
F(True)
F(False)
F(4)
4
";
CompileAndVerify(source, expectedOutput: expectedOutput);
var comp = CreateRuntimeAsyncCompilation(source);
var verifier = CompileAndVerify(comp, expectedOutput: CodeGenAsyncTests.ExpectedOutput(expectedOutput, isRuntimeAsync: true), verify: Verification.Fails with
{
ILVerifyMessage = """
[G]: Unexpected type on the stack. { Offset = 0x83, Found = Int32, Expected = ref '[System.Runtime]System.Threading.Tasks.Task`1<int32>' }
"""
});
verifier.VerifyDiagnostics();
verifier.VerifyIL("Test.G(bool, bool)", """
{
// Code size 132 (0x84)
.maxstack 3
.locals init (bool V_0, //x1
bool V_1, //x2
bool V_2, //x3
int V_3, //c
bool V_4)
IL_0000: ldarg.0
IL_0001: stloc.s V_4
IL_0003: ldloc.s V_4
IL_0005: brfalse.s IL_0014
IL_0007: ldc.i4.1
IL_0008: call "System.Threading.Tasks.Task<bool> Test.F<bool>(bool)"
IL_000d: call "bool System.Runtime.CompilerServices.AsyncHelpers.Await<bool>(System.Threading.Tasks.Task<bool>)"
IL_0012: stloc.s V_4
IL_0014: ldloc.s V_4
IL_0016: stloc.0
IL_0017: ldarg.0
IL_0018: stloc.s V_4
IL_001a: ldloc.s V_4
IL_001c: brfalse.s IL_002b
IL_001e: ldc.i4.0
IL_001f: call "System.Threading.Tasks.Task<bool> Test.F<bool>(bool)"
IL_0024: call "bool System.Runtime.CompilerServices.AsyncHelpers.Await<bool>(System.Threading.Tasks.Task<bool>)"
IL_0029: stloc.s V_4
IL_002b: ldloc.s V_4
IL_002d: stloc.1
IL_002e: ldarg.1
IL_002f: stloc.s V_4
IL_0031: ldloc.s V_4
IL_0033: brfalse.s IL_0042
IL_0035: ldc.i4.1
IL_0036: call "System.Threading.Tasks.Task<bool> Test.F<bool>(bool)"
IL_003b: call "bool System.Runtime.CompilerServices.AsyncHelpers.Await<bool>(System.Threading.Tasks.Task<bool>)"
IL_0040: stloc.s V_4
IL_0042: ldloc.s V_4
IL_0044: stloc.2
IL_0045: ldarg.1
IL_0046: stloc.s V_4
IL_0048: ldloc.s V_4
IL_004a: brfalse.s IL_0059
IL_004c: ldc.i4.0
IL_004d: call "System.Threading.Tasks.Task<bool> Test.F<bool>(bool)"
IL_0052: call "bool System.Runtime.CompilerServices.AsyncHelpers.Await<bool>(System.Threading.Tasks.Task<bool>)"
IL_0057: stloc.s V_4
IL_0059: ldloc.s V_4
IL_005b: ldc.i4.0
IL_005c: stloc.3
IL_005d: ldloc.0
IL_005e: brfalse.s IL_0064
IL_0060: ldloc.3
IL_0061: ldc.i4.1
IL_0062: add
IL_0063: stloc.3
IL_0064: ldloc.1
IL_0065: brfalse.s IL_006b
IL_0067: ldloc.3
IL_0068: ldc.i4.2
IL_0069: add
IL_006a: stloc.3
IL_006b: ldloc.2
IL_006c: brfalse.s IL_0072
IL_006e: ldloc.3
IL_006f: ldc.i4.4
IL_0070: add
IL_0071: stloc.3
IL_0072: brfalse.s IL_0078
IL_0074: ldloc.3
IL_0075: ldc.i4.8
IL_0076: add
IL_0077: stloc.3
IL_0078: ldloc.3
IL_0079: call "System.Threading.Tasks.Task<int> Test.F<int>(int)"
IL_007e: call "int System.Runtime.CompilerServices.AsyncHelpers.Await<int>(System.Threading.Tasks.Task<int>)"
IL_0083: ret
}
""");
}
[Fact]
public void AsyncWithOr()
{
var source = @"
using System;
using System.Threading.Tasks;
class Test
{
public static Task<T> F<T>(T x)
{
Console.WriteLine(""F("" + x + "")"");
return Task.Factory.StartNew(() => { return x; });
}
public static async Task<int> G(bool b1, bool b2)
{
bool x1 = b1 || await F(true);
bool x2 = b1 || await F(false);
bool x3 = b2 || await F(true);
bool x4 = b2 || await F(false);
int c = 0;
if (x1) c += 1;
if (x2) c += 2;
if (x3) c += 4;
if (x4) c += 8;
return await F(c);
}
public static int H(bool b1, bool b2)
{
Task<int> t = G(b1, b2);
t.Wait(1000 * 60);
return t.Result;
}
public static void Main()
{
Console.WriteLine(H(false, true));
}
}";
var expectedOutput = @"
F(True)
F(False)
F(13)
13
";
CompileAndVerify(source, expectedOutput: expectedOutput);
var comp = CreateRuntimeAsyncCompilation(source);
var verifier = CompileAndVerify(comp, expectedOutput: CodeGenAsyncTests.ExpectedOutput(expectedOutput, isRuntimeAsync: true), verify: Verification.Fails with
{
ILVerifyMessage = """
[G]: Unexpected type on the stack. { Offset = 0x83, Found = Int32, Expected = ref '[System.Runtime]System.Threading.Tasks.Task`1<int32>' }
"""
});
verifier.VerifyDiagnostics();
verifier.VerifyIL("Test.G(bool, bool)", """
{
// Code size 132 (0x84)
.maxstack 3
.locals init (bool V_0, //x1
bool V_1, //x2
bool V_2, //x3
int V_3, //c
bool V_4)
IL_0000: ldarg.0
IL_0001: stloc.s V_4
IL_0003: ldloc.s V_4
IL_0005: brtrue.s IL_0014
IL_0007: ldc.i4.1
IL_0008: call "System.Threading.Tasks.Task<bool> Test.F<bool>(bool)"
IL_000d: call "bool System.Runtime.CompilerServices.AsyncHelpers.Await<bool>(System.Threading.Tasks.Task<bool>)"
IL_0012: stloc.s V_4
IL_0014: ldloc.s V_4
IL_0016: stloc.0
IL_0017: ldarg.0
IL_0018: stloc.s V_4
IL_001a: ldloc.s V_4
IL_001c: brtrue.s IL_002b
IL_001e: ldc.i4.0
IL_001f: call "System.Threading.Tasks.Task<bool> Test.F<bool>(bool)"
IL_0024: call "bool System.Runtime.CompilerServices.AsyncHelpers.Await<bool>(System.Threading.Tasks.Task<bool>)"
IL_0029: stloc.s V_4
IL_002b: ldloc.s V_4
IL_002d: stloc.1
IL_002e: ldarg.1
IL_002f: stloc.s V_4
IL_0031: ldloc.s V_4
IL_0033: brtrue.s IL_0042
IL_0035: ldc.i4.1
IL_0036: call "System.Threading.Tasks.Task<bool> Test.F<bool>(bool)"
IL_003b: call "bool System.Runtime.CompilerServices.AsyncHelpers.Await<bool>(System.Threading.Tasks.Task<bool>)"
IL_0040: stloc.s V_4
IL_0042: ldloc.s V_4
IL_0044: stloc.2
IL_0045: ldarg.1
IL_0046: stloc.s V_4
IL_0048: ldloc.s V_4
IL_004a: brtrue.s IL_0059
IL_004c: ldc.i4.0
IL_004d: call "System.Threading.Tasks.Task<bool> Test.F<bool>(bool)"
IL_0052: call "bool System.Runtime.CompilerServices.AsyncHelpers.Await<bool>(System.Threading.Tasks.Task<bool>)"
IL_0057: stloc.s V_4
IL_0059: ldloc.s V_4
IL_005b: ldc.i4.0
IL_005c: stloc.3
IL_005d: ldloc.0
IL_005e: brfalse.s IL_0064
IL_0060: ldloc.3
IL_0061: ldc.i4.1
IL_0062: add
IL_0063: stloc.3
IL_0064: ldloc.1
IL_0065: brfalse.s IL_006b
IL_0067: ldloc.3
IL_0068: ldc.i4.2
IL_0069: add
IL_006a: stloc.3
IL_006b: ldloc.2
IL_006c: brfalse.s IL_0072
IL_006e: ldloc.3
IL_006f: ldc.i4.4
IL_0070: add
IL_0071: stloc.3
IL_0072: brfalse.s IL_0078
IL_0074: ldloc.3
IL_0075: ldc.i4.8
IL_0076: add
IL_0077: stloc.3
IL_0078: ldloc.3
IL_0079: call "System.Threading.Tasks.Task<int> Test.F<int>(int)"
IL_007e: call "int System.Runtime.CompilerServices.AsyncHelpers.Await<int>(System.Threading.Tasks.Task<int>)"
IL_0083: ret
}
""");
}
[Fact]
public void AsyncWithCoalesce()
{
var source = @"
using System;
using System.Threading.Tasks;
class Test
{
public static Task<string> F(string x)
{
Console.WriteLine(""F("" + (x ?? ""null"") + "")"");
return Task.Factory.StartNew(() => { return x; });
}
public static async Task<string> G(string s1, string s2)
{
var result = await F(s1) ?? await F(s2);
Console.WriteLine("" "" + (result ?? ""null""));
return result;
}
public static string H(string s1, string s2)
{
Task<string> t = G(s1, s2);
t.Wait(1000 * 60);
return t.Result;
}
public static void Main()
{
H(null, null);
H(null, ""a"");
H(""b"", null);
H(""c"", ""d"");
}
}";
var expectedOutput = @"
F(null)
F(null)
null
F(null)
F(a)
a
F(b)
b
F(c)
c
";
CompileAndVerify(source, expectedOutput: expectedOutput);
var comp = CreateRuntimeAsyncCompilation(source);
var verifier = CompileAndVerify(comp, expectedOutput: CodeGenAsyncTests.ExpectedOutput(expectedOutput, isRuntimeAsync: true), verify: Verification.Fails with
{
ILVerifyMessage = """
[G]: Unexpected type on the stack. { Offset = 0x37, Found = ref 'string', Expected = ref '[System.Runtime]System.Threading.Tasks.Task`1<string>' }
"""
});
verifier.VerifyDiagnostics();
verifier.VerifyIL("Test.G(string, string)", """
{
// Code size 56 (0x38)
.maxstack 3
.locals init (string V_0, //result
string V_1)
IL_0000: ldarg.0
IL_0001: call "System.Threading.Tasks.Task<string> Test.F(string)"
IL_0006: call "string System.Runtime.CompilerServices.AsyncHelpers.Await<string>(System.Threading.Tasks.Task<string>)"
IL_000b: stloc.1
IL_000c: ldloc.1
IL_000d: brtrue.s IL_001b
IL_000f: ldarg.1
IL_0010: call "System.Threading.Tasks.Task<string> Test.F(string)"
IL_0015: call "string System.Runtime.CompilerServices.AsyncHelpers.Await<string>(System.Threading.Tasks.Task<string>)"
IL_001a: stloc.1
IL_001b: ldloc.1
IL_001c: stloc.0
IL_001d: ldstr " "
IL_0022: ldloc.0
IL_0023: dup
IL_0024: brtrue.s IL_002c
IL_0026: pop
IL_0027: ldstr "null"
IL_002c: call "string string.Concat(string, string)"
IL_0031: call "void System.Console.WriteLine(string)"
IL_0036: ldloc.0
IL_0037: ret
}
""");
}
[Fact]
public void AwaitInExpr()
{
var source = @"
using System;
using System.Threading.Tasks;
class Test
{
public static async Task<int> F()
{
return await Task.Factory.StartNew(() => 21);
}
public static async Task<int> G()
{
int c = 0;
c = (await F()) + 21;
return c;
}
public static void Main()
{
Task<int> t = G();
t.Wait(1000 * 60);
Console.WriteLine(t.Result);
}
}";
var expectedOutput = @"
42
";
CompileAndVerify(source, expectedOutput: expectedOutput);
var comp = CreateRuntimeAsyncCompilation(source);
var verifier = CompileAndVerify(comp, expectedOutput: CodeGenAsyncTests.ExpectedOutput(expectedOutput, isRuntimeAsync: true), verify: Verification.Fails with
{
ILVerifyMessage = """
[F]: Unexpected type on the stack. { Offset = 0x2e, Found = Int32, Expected = ref '[System.Runtime]System.Threading.Tasks.Task`1<int32>' }
[G]: Unexpected type on the stack. { Offset = 0xd, Found = Int32, Expected = ref '[System.Runtime]System.Threading.Tasks.Task`1<int32>' }
"""
});
verifier.VerifyDiagnostics();
verifier.VerifyIL("Test.G()", """
{
// Code size 14 (0xe)
.maxstack 2
IL_0000: call "System.Threading.Tasks.Task<int> Test.F()"
IL_0005: call "int System.Runtime.CompilerServices.AsyncHelpers.Await<int>(System.Threading.Tasks.Task<int>)"
IL_000a: ldc.i4.s 21
IL_000c: add
IL_000d: ret
}
""");
}
[Fact]
public void SpillNestedUnary()
{
var source = @"
#pragma warning disable CS1998 // Async method lacks 'await' operators and will run synchronously
using System;
using System.Threading.Tasks;
class Test
{
public static async Task<int> F()
{
return 1;
}
public static async Task<int> G1()
{
return -(await F());
}
public static async Task<int> G2()
{
return -(-(await F()));
}
public static async Task<int> G3()
{
return -(-(-(await F())));
}
public static void WaitAndPrint(Task<int> t)
{
t.Wait();
Console.WriteLine(t.Result);
}
public static void Main()
{
WaitAndPrint(G1());
WaitAndPrint(G2());
WaitAndPrint(G3());
}
}";
var expectedOutput = @"
-1
1
-1
";
CompileAndVerify(source, expectedOutput);
var comp = CreateRuntimeAsyncCompilation(source);
var verifier = CompileAndVerify(comp, expectedOutput: CodeGenAsyncTests.ExpectedOutput(expectedOutput, isRuntimeAsync: true), verify: Verification.Fails with
{
ILVerifyMessage = """
[F]: Unexpected type on the stack. { Offset = 0x1, Found = Int32, Expected = ref '[System.Runtime]System.Threading.Tasks.Task`1<int32>' }
[G1]: Unexpected type on the stack. { Offset = 0xb, Found = Int32, Expected = ref '[System.Runtime]System.Threading.Tasks.Task`1<int32>' }
[G2]: Unexpected type on the stack. { Offset = 0xc, Found = Int32, Expected = ref '[System.Runtime]System.Threading.Tasks.Task`1<int32>' }
[G3]: Unexpected type on the stack. { Offset = 0xd, Found = Int32, Expected = ref '[System.Runtime]System.Threading.Tasks.Task`1<int32>' }
"""
});
verifier.VerifyDiagnostics();
verifier.VerifyIL("Test.G1()", """
{
// Code size 12 (0xc)
.maxstack 1
IL_0000: call "System.Threading.Tasks.Task<int> Test.F()"
IL_0005: call "int System.Runtime.CompilerServices.AsyncHelpers.Await<int>(System.Threading.Tasks.Task<int>)"
IL_000a: neg
IL_000b: ret
}
""");
verifier.VerifyDiagnostics();
verifier.VerifyIL("Test.G2()", """
{
// Code size 13 (0xd)
.maxstack 1
IL_0000: call "System.Threading.Tasks.Task<int> Test.F()"
IL_0005: call "int System.Runtime.CompilerServices.AsyncHelpers.Await<int>(System.Threading.Tasks.Task<int>)"
IL_000a: neg
IL_000b: neg
IL_000c: ret
}
""");
verifier.VerifyDiagnostics();
verifier.VerifyIL("Test.G3()", """
{
// Code size 14 (0xe)
.maxstack 1
IL_0000: call "System.Threading.Tasks.Task<int> Test.F()"
IL_0005: call "int System.Runtime.CompilerServices.AsyncHelpers.Await<int>(System.Threading.Tasks.Task<int>)"
IL_000a: neg
IL_000b: neg
IL_000c: neg
IL_000d: ret
}
""");
}
[Fact]
public void AsyncWithParamsAndLocals_DoubleAwait_Spilling()
{
var source = @"
using System;
using System.Threading.Tasks;
class Test
{
public static async Task<int> F(int x)
{
return await Task.Factory.StartNew(() => { return x; });
}
public static async Task<int> G(int x)
{
int c = 0;
c = (await F(x)) + c;
c = (await F(x)) + c;
return c;
}
public static void Main()
{
Task<int> t = G(21);
t.Wait(1000 * 60);
Console.WriteLine(t.Result);
}
}";
var expectedOutput = @"
42
";
// When the local 'c' gets hoisted, the statement:
// c = (await F(x)) + c;
// Gets rewritten to:
// this.c_field = (await F(x)) + this.c_field;
//
// The code-gen for the assignment is something like this:
// ldarg0 // load the 'this' reference to the stack
// <emitted await expression>
// stfld
//
// What we really want is to evaluate any parts of the lvalue that have side-effects (which is this case is
// nothing), and then defer loading the address for the field reference until after the await expression:
// <emitted await expression>
// <store to tmp>
// ldarg0
// <load tmp>
// stfld
//
// So this case actually requires stack spilling, which is not yet implemented. This has the unfortunate
// consequence of preventing await expressions from being assigned to hoisted locals.
//
CompileAndVerify(source, expectedOutput: expectedOutput);
var comp = CreateRuntimeAsyncCompilation(source);
var verifier = CompileAndVerify(comp, expectedOutput: CodeGenAsyncTests.ExpectedOutput(expectedOutput, isRuntimeAsync: true), verify: Verification.Fails with
{
ILVerifyMessage = """
[F]: Unexpected type on the stack. { Offset = 0x28, Found = Int32, Expected = ref '[System.Runtime]System.Threading.Tasks.Task`1<int32>' }
[G]: Unexpected type on the stack. { Offset = 0x1f, Found = Int32, Expected = ref '[System.Runtime]System.Threading.Tasks.Task`1<int32>' }
"""
});
verifier.VerifyDiagnostics();
verifier.VerifyIL("Test.G(int)", """
{
// Code size 32 (0x20)
.maxstack 2
.locals init (int V_0) //c
IL_0000: ldc.i4.0
IL_0001: stloc.0
IL_0002: ldarg.0
IL_0003: call "System.Threading.Tasks.Task<int> Test.F(int)"
IL_0008: call "int System.Runtime.CompilerServices.AsyncHelpers.Await<int>(System.Threading.Tasks.Task<int>)"
IL_000d: ldloc.0
IL_000e: add
IL_000f: stloc.0
IL_0010: ldarg.0
IL_0011: call "System.Threading.Tasks.Task<int> Test.F(int)"
IL_0016: call "int System.Runtime.CompilerServices.AsyncHelpers.Await<int>(System.Threading.Tasks.Task<int>)"
IL_001b: ldloc.0
IL_001c: add
IL_001d: stloc.0
IL_001e: ldloc.0
IL_001f: ret
}
""");
}
[Fact]
public void SpillCall()
{
var source = @"
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
class Test
{
public static void Printer(int a, int b, int c, int d, int e)
{
foreach (var x in new List<int>() { a, b, c, d, e })
{
Console.WriteLine(x);
}
}
public static int Get(int x)
{
Console.WriteLine(""> "" + x);
return x;
}
public static async Task<int> F(int x)
{
return await Task.Factory.StartNew(() => x);
}
public static async Task G()
{
Printer(Get(111), Get(222), Get(333), await F(Get(444)), Get(555));
}
public static void Main()
{
Task t = G();
t.Wait();
}
}";
var expectedOutput = @"
> 111
> 222
> 333
> 444
> 555
111
222
333
444
555
";
CompileAndVerify(source, expectedOutput);
var comp = CreateRuntimeAsyncCompilation(source);
var verifier = CompileAndVerify(comp, expectedOutput: CodeGenAsyncTests.ExpectedOutput(expectedOutput, isRuntimeAsync: true), verify: Verification.Fails with
{
ILVerifyMessage = """
[F]: Unexpected type on the stack. { Offset = 0x28, Found = Int32, Expected = ref '[System.Runtime]System.Threading.Tasks.Task`1<int32>' }
[G]: Return value missing on the stack. { Offset = 0x44 }
"""
});
verifier.VerifyDiagnostics();
verifier.VerifyIL("Test.G()", """
{
// Code size 69 (0x45)
.maxstack 5
.locals init (int V_0,
int V_1,
int V_2)
IL_0000: ldc.i4.s 111
IL_0002: call "int Test.Get(int)"
IL_0007: ldc.i4 0xde
IL_000c: call "int Test.Get(int)"
IL_0011: stloc.0
IL_0012: ldc.i4 0x14d
IL_0017: call "int Test.Get(int)"
IL_001c: stloc.1
IL_001d: ldc.i4 0x1bc
IL_0022: call "int Test.Get(int)"
IL_0027: call "System.Threading.Tasks.Task<int> Test.F(int)"
IL_002c: call "int System.Runtime.CompilerServices.AsyncHelpers.Await<int>(System.Threading.Tasks.Task<int>)"
IL_0031: stloc.2
IL_0032: ldloc.0
IL_0033: ldloc.1
IL_0034: ldloc.2
IL_0035: ldc.i4 0x22b
IL_003a: call "int Test.Get(int)"
IL_003f: call "void Test.Printer(int, int, int, int, int)"
IL_0044: ret
}
""");
}
[Fact]
public void SpillCall2()
{
var source = @"
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
class Test
{
public static void Printer(int a, int b, int c, int d, int e)
{
foreach (var x in new List<int>() { a, b, c, d, e })
{
Console.WriteLine(x);
}
}
public static int Get(int x)
{
Console.WriteLine(""> "" + x);
return x;
}
public static async Task<int> F(int x)
{
return await Task.Factory.StartNew(() => x);
}
public static async Task G()
{
Printer(Get(111), await F(Get(222)), Get(333), await F(Get(444)), Get(555));
}
public static void Main()
{
Task t = G();
t.Wait();
}
}";
var expectedOutput = @"
> 111
> 222
> 333
> 444
> 555
111
222
333
444
555
";
CompileAndVerify(source, expectedOutput);
var comp = CreateRuntimeAsyncCompilation(source);
var verifier = CompileAndVerify(comp, expectedOutput: CodeGenAsyncTests.ExpectedOutput(expectedOutput, isRuntimeAsync: true), verify: Verification.Fails with
{
ILVerifyMessage = """
[F]: Unexpected type on the stack. { Offset = 0x28, Found = Int32, Expected = ref '[System.Runtime]System.Threading.Tasks.Task`1<int32>' }
[G]: Return value missing on the stack. { Offset = 0x4e }
"""
});
verifier.VerifyDiagnostics();
verifier.VerifyIL("Test.G()", """
{
// Code size 79 (0x4f)
.maxstack 5
.locals init (int V_0,
int V_1,
int V_2)
IL_0000: ldc.i4.s 111
IL_0002: call "int Test.Get(int)"
IL_0007: ldc.i4 0xde
IL_000c: call "int Test.Get(int)"
IL_0011: call "System.Threading.Tasks.Task<int> Test.F(int)"
IL_0016: call "int System.Runtime.CompilerServices.AsyncHelpers.Await<int>(System.Threading.Tasks.Task<int>)"
IL_001b: stloc.0
IL_001c: ldc.i4 0x14d
IL_0021: call "int Test.Get(int)"
IL_0026: stloc.1
IL_0027: ldc.i4 0x1bc
IL_002c: call "int Test.Get(int)"
IL_0031: call "System.Threading.Tasks.Task<int> Test.F(int)"
IL_0036: call "int System.Runtime.CompilerServices.AsyncHelpers.Await<int>(System.Threading.Tasks.Task<int>)"
IL_003b: stloc.2
IL_003c: ldloc.0
IL_003d: ldloc.1
IL_003e: ldloc.2
IL_003f: ldc.i4 0x22b
IL_0044: call "int Test.Get(int)"
IL_0049: call "void Test.Printer(int, int, int, int, int)"
IL_004e: ret
}
""");
}
[Fact]
public void SpillCall3()
{
var source = @"
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
class Test
{
public static void Printer(int a, int b, int c, int d, int e, int f)
{
foreach (var x in new List<int>(){a, b, c, d, e, f})
{
Console.WriteLine(x);
}
}
public static async Task<int> F(int x)
{
return await Task.Factory.StartNew(() => x);
}
public static async Task G()
{
Printer(1, await F(2), 3, await F(await F(await F(await F(4)))), await F(5), 6);
}
public static void Main()
{
Task t = G();
t.Wait();
}
}";
var expectedOutput = @"
1
2
3
4
5
6
";
CompileAndVerify(source, expectedOutput);
var comp = CreateRuntimeAsyncCompilation(source);
var verifier = CompileAndVerify(comp, expectedOutput: CodeGenAsyncTests.ExpectedOutput(expectedOutput, isRuntimeAsync: true), verify: Verification.Fails with
{
ILVerifyMessage = """
[F]: Unexpected type on the stack. { Offset = 0x28, Found = Int32, Expected = ref '[System.Runtime]System.Threading.Tasks.Task`1<int32>' }
[G]: Return value missing on the stack. { Offset = 0x4d }
"""
});
verifier.VerifyDiagnostics();
verifier.VerifyIL("Test.G()", """
{
// Code size 78 (0x4e)
.maxstack 6
.locals init (int V_0,
int V_1,
int V_2)
IL_0000: ldc.i4.2
IL_0001: call "System.Threading.Tasks.Task<int> Test.F(int)"
IL_0006: call "int System.Runtime.CompilerServices.AsyncHelpers.Await<int>(System.Threading.Tasks.Task<int>)"
IL_000b: stloc.0
IL_000c: ldc.i4.4
IL_000d: call "System.Threading.Tasks.Task<int> Test.F(int)"
IL_0012: call "int System.Runtime.CompilerServices.AsyncHelpers.Await<int>(System.Threading.Tasks.Task<int>)"
IL_0017: call "System.Threading.Tasks.Task<int> Test.F(int)"
IL_001c: call "int System.Runtime.CompilerServices.AsyncHelpers.Await<int>(System.Threading.Tasks.Task<int>)"
IL_0021: call "System.Threading.Tasks.Task<int> Test.F(int)"
IL_0026: call "int System.Runtime.CompilerServices.AsyncHelpers.Await<int>(System.Threading.Tasks.Task<int>)"
IL_002b: call "System.Threading.Tasks.Task<int> Test.F(int)"
IL_0030: call "int System.Runtime.CompilerServices.AsyncHelpers.Await<int>(System.Threading.Tasks.Task<int>)"
IL_0035: stloc.1
IL_0036: ldc.i4.5
IL_0037: call "System.Threading.Tasks.Task<int> Test.F(int)"
IL_003c: call "int System.Runtime.CompilerServices.AsyncHelpers.Await<int>(System.Threading.Tasks.Task<int>)"
IL_0041: stloc.2
IL_0042: ldc.i4.1
IL_0043: ldloc.0
IL_0044: ldc.i4.3
IL_0045: ldloc.1
IL_0046: ldloc.2
IL_0047: ldc.i4.6
IL_0048: call "void Test.Printer(int, int, int, int, int, int)"
IL_004d: ret
}
""");
}
[Fact]
public void SpillCall4()
{
var source = @"
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
class Test
{
public static void Printer(int a, int b)
{
foreach (var x in new List<int>(){a, b})
{
Console.WriteLine(x);
}
}
public static async Task<int> F(int x)
{
return await Task.Factory.StartNew(() => x);
}
public static async Task G()
{
Printer(1, await F(await F(2)));
}
public static void Main()
{
Task t = G();
t.Wait();
}
}";
var expectedOutput = @"
1
2
";
CompileAndVerify(source, expectedOutput);
var comp = CreateRuntimeAsyncCompilation(source);
var verifier = CompileAndVerify(comp, expectedOutput: CodeGenAsyncTests.ExpectedOutput(expectedOutput, isRuntimeAsync: true), verify: Verification.Fails with
{
ILVerifyMessage = """
[F]: Unexpected type on the stack. { Offset = 0x28, Found = Int32, Expected = ref '[System.Runtime]System.Threading.Tasks.Task`1<int32>' }
[G]: Return value missing on the stack. { Offset = 0x1d }
"""
});
verifier.VerifyDiagnostics();
verifier.VerifyIL("Test.G()", """
{
// Code size 30 (0x1e)
.maxstack 2
.locals init (int V_0)
IL_0000: ldc.i4.2
IL_0001: call "System.Threading.Tasks.Task<int> Test.F(int)"
IL_0006: call "int System.Runtime.CompilerServices.AsyncHelpers.Await<int>(System.Threading.Tasks.Task<int>)"
IL_000b: call "System.Threading.Tasks.Task<int> Test.F(int)"
IL_0010: call "int System.Runtime.CompilerServices.AsyncHelpers.Await<int>(System.Threading.Tasks.Task<int>)"
IL_0015: stloc.0
IL_0016: ldc.i4.1
IL_0017: ldloc.0
IL_0018: call "void Test.Printer(int, int)"
IL_001d: ret
}
""");
}
[Fact]
public void SpillSequences1()
{
var source = @"
using System.Threading.Tasks;
public class Test
{
public static int H(int a, int b, int c)
{
return a;
}
public static Task<int> G()
{
return null;
}
public static async Task<int> F(int[] array)
{
H(array[1] += 2, array[3] += await G(), 4);
return 1;
}
}
";
var v = CompileAndVerify(source, options: TestOptions.DebugDll);
v.VerifyIL("Test.<F>d__2.System.Runtime.CompilerServices.IAsyncStateMachine.MoveNext",
@"{
// Code size 273 (0x111)
.maxstack 5
.locals init (int V_0,
int V_1,
int V_2,
System.Runtime.CompilerServices.TaskAwaiter<int> V_3,
Test.<F>d__2 V_4,
System.Exception V_5)
~IL_0000: ldarg.0
IL_0001: ldfld ""int Test.<F>d__2.<>1__state""
IL_0006: stloc.0
.try
{
~IL_0007: ldloc.0
IL_0008: brfalse.s IL_000c
IL_000a: br.s IL_000e
IL_000c: br.s IL_0088
-IL_000e: nop
-IL_000f: ldarg.0
IL_0010: ldarg.0
IL_0011: ldfld ""int[] Test.<F>d__2.array""
IL_0016: ldc.i4.1
IL_0017: ldelema ""int""
IL_001c: dup
IL_001d: ldind.i4
IL_001e: ldc.i4.2
IL_001f: add
IL_0020: dup
IL_0021: stloc.2
IL_0022: stind.i4
IL_0023: ldloc.2
IL_0024: stfld ""int Test.<F>d__2.<>s__1""
IL_0029: ldarg.0
IL_002a: ldarg.0
IL_002b: ldfld ""int[] Test.<F>d__2.array""
IL_0030: stfld ""int[] Test.<F>d__2.<>s__4""
IL_0035: ldarg.0
IL_0036: ldfld ""int[] Test.<F>d__2.<>s__4""
IL_003b: ldc.i4.3
IL_003c: ldelem.i4
IL_003d: pop
IL_003e: ldarg.0
IL_003f: ldarg.0
IL_0040: ldfld ""int[] Test.<F>d__2.<>s__4""
IL_0045: ldc.i4.3
IL_0046: ldelem.i4
IL_0047: stfld ""int Test.<F>d__2.<>s__2""
IL_004c: call ""System.Threading.Tasks.Task<int> Test.G()""
IL_0051: callvirt ""System.Runtime.CompilerServices.TaskAwaiter<int> System.Threading.Tasks.Task<int>.GetAwaiter()""
IL_0056: stloc.3
~IL_0057: ldloca.s V_3
IL_0059: call ""bool System.Runtime.CompilerServices.TaskAwaiter<int>.IsCompleted.get""
IL_005e: brtrue.s IL_00a4
IL_0060: ldarg.0
IL_0061: ldc.i4.0
IL_0062: dup
IL_0063: stloc.0
IL_0064: stfld ""int Test.<F>d__2.<>1__state""
<IL_0069: ldarg.0
IL_006a: ldloc.3
IL_006b: stfld ""System.Runtime.CompilerServices.TaskAwaiter<int> Test.<F>d__2.<>u__1""
IL_0070: ldarg.0
IL_0071: stloc.s V_4
IL_0073: ldarg.0
IL_0074: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder<int> Test.<F>d__2.<>t__builder""
IL_0079: ldloca.s V_3
IL_007b: ldloca.s V_4
IL_007d: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder<int>.AwaitUnsafeOnCompleted<System.Runtime.CompilerServices.TaskAwaiter<int>, Test.<F>d__2>(ref System.Runtime.CompilerServices.TaskAwaiter<int>, ref Test.<F>d__2)""
IL_0082: nop
IL_0083: leave IL_0110
>IL_0088: ldarg.0
IL_0089: ldfld ""System.Runtime.CompilerServices.TaskAwaiter<int> Test.<F>d__2.<>u__1""
IL_008e: stloc.3
IL_008f: ldarg.0
IL_0090: ldflda ""System.Runtime.CompilerServices.TaskAwaiter<int> Test.<F>d__2.<>u__1""
IL_0095: initobj ""System.Runtime.CompilerServices.TaskAwaiter<int>""
IL_009b: ldarg.0
IL_009c: ldc.i4.m1
IL_009d: dup
IL_009e: stloc.0
IL_009f: stfld ""int Test.<F>d__2.<>1__state""
IL_00a4: ldarg.0
IL_00a5: ldloca.s V_3
IL_00a7: call ""int System.Runtime.CompilerServices.TaskAwaiter<int>.GetResult()""
IL_00ac: stfld ""int Test.<F>d__2.<>s__3""
IL_00b1: ldarg.0
IL_00b2: ldfld ""int Test.<F>d__2.<>s__1""
IL_00b7: ldarg.0
IL_00b8: ldfld ""int[] Test.<F>d__2.<>s__4""
IL_00bd: ldc.i4.3
IL_00be: ldarg.0
IL_00bf: ldfld ""int Test.<F>d__2.<>s__2""
IL_00c4: ldarg.0
IL_00c5: ldfld ""int Test.<F>d__2.<>s__3""
IL_00ca: add
IL_00cb: dup
IL_00cc: stloc.2
IL_00cd: stelem.i4
IL_00ce: ldloc.2
IL_00cf: ldc.i4.4
IL_00d0: call ""int Test.H(int, int, int)""
IL_00d5: pop
IL_00d6: ldarg.0
IL_00d7: ldnull
IL_00d8: stfld ""int[] Test.<F>d__2.<>s__4""
-IL_00dd: ldc.i4.1
IL_00de: stloc.1
IL_00df: leave.s IL_00fb
}
catch System.Exception
{
~IL_00e1: stloc.s V_5
IL_00e3: ldarg.0
IL_00e4: ldc.i4.s -2
IL_00e6: stfld ""int Test.<F>d__2.<>1__state""
IL_00eb: ldarg.0
IL_00ec: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder<int> Test.<F>d__2.<>t__builder""
IL_00f1: ldloc.s V_5
IL_00f3: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder<int>.SetException(System.Exception)""
IL_00f8: nop
IL_00f9: leave.s IL_0110
}
-IL_00fb: ldarg.0
IL_00fc: ldc.i4.s -2
IL_00fe: stfld ""int Test.<F>d__2.<>1__state""
~IL_0103: ldarg.0
IL_0104: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder<int> Test.<F>d__2.<>t__builder""
IL_0109: ldloc.1
IL_010a: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder<int>.SetResult(int)""
IL_010f: nop
IL_0110: ret
}", sequencePoints: "Test+<F>d__2.MoveNext");
var comp = CreateRuntimeAsyncCompilation(source);
comp.VerifyEmitDiagnostics(
// (18,38): error CS9328: Method 'Test.F(int[])' uses a feature that is not supported by runtime async currently. Opt the method out of runtime async by attributing it with 'System.Runtime.CompilerServices.RuntimeAsyncMethodGenerationAttribute(false)'.
// H(array[1] += 2, array[3] += await G(), 4);
Diagnostic(ErrorCode.ERR_UnsupportedFeatureInRuntimeAsync, "await G()").WithArguments("Test.F(int[])").WithLocation(18, 38)
);
// https://github.com/dotnet/roslyn/issues/79763
// var verifier = CompileAndVerify(comp, verify: Verification.Fails with
// {
// ILVerifyMessage = """
// [F]: Unexpected type on the stack. { Offset = 0x35, Found = Int32, Expected = ref '[System.Runtime]System.Threading.Tasks.Task`1<int32>' }
// """
// });
// verifier.VerifyDiagnostics();
// verifier.VerifyIL("Test.F(int[])", """
// {
// // Code size 54 (0x36)
// .maxstack 4
// .locals init (int& V_0,
// int V_1,
// int V_2,
// int V_3)
// IL_0000: ldarg.0
// IL_0001: ldc.i4.1
// IL_0002: ldelema "int"
// IL_0007: dup
// IL_0008: ldind.i4
// IL_0009: ldc.i4.2
// IL_000a: add
// IL_000b: dup
// IL_000c: stloc.3
// IL_000d: stind.i4
// IL_000e: ldloc.3
// IL_000f: ldarg.0
// IL_0010: ldc.i4.3
// IL_0011: ldelema "int"
// IL_0016: stloc.0
// IL_0017: ldloc.0
// IL_0018: ldind.i4
// IL_0019: stloc.1
// IL_001a: call "System.Threading.Tasks.Task<int> Test.G()"
// IL_001f: call "int System.Runtime.CompilerServices.AsyncHelpers.Await<int>(System.Threading.Tasks.Task<int>)"
// IL_0024: stloc.2
// IL_0025: ldloc.0
// IL_0026: ldloc.1
// IL_0027: ldloc.2
// IL_0028: add
// IL_0029: dup
// IL_002a: stloc.3
// IL_002b: stind.i4
// IL_002c: ldloc.3
// IL_002d: ldc.i4.4
// IL_002e: call "int Test.H(int, int, int)"
// IL_0033: pop
// IL_0034: ldc.i4.1
// IL_0035: ret
// }
// """);
}
[Fact]
public void SpillSequencesRelease()
{
var source = @"
using System.Threading.Tasks;
public class Test
{
public static int H(int a, int b, int c)
{
return a;
}
public static Task<int> G()
{
return null;
}
public static async Task<int> F(int[] array)
{
H(array[1] += 2, array[3] += await G(), 4);
return 1;
}
}
";
var v = CompileAndVerify(source, options: TestOptions.ReleaseDll);
v.VerifyIL("Test.<F>d__2.System.Runtime.CompilerServices.IAsyncStateMachine.MoveNext", @"
{
// Code size 251 (0xfb)
.maxstack 5
.locals init (int V_0,
int V_1,
int V_2,
int V_3,
System.Runtime.CompilerServices.TaskAwaiter<int> V_4,
System.Exception V_5)
~IL_0000: ldarg.0
IL_0001: ldfld ""int Test.<F>d__2.<>1__state""
IL_0006: stloc.0
.try
{
~IL_0007: ldloc.0
IL_0008: brfalse.s IL_007d
-IL_000a: ldarg.0
IL_000b: ldarg.0
IL_000c: ldfld ""int[] Test.<F>d__2.array""
IL_0011: ldc.i4.1
IL_0012: ldelema ""int""
IL_0017: dup
IL_0018: ldind.i4
IL_0019: ldc.i4.2
IL_001a: add
IL_001b: dup
IL_001c: stloc.3
IL_001d: stind.i4
IL_001e: ldloc.3
IL_001f: stfld ""int Test.<F>d__2.<>7__wrap1""
IL_0024: ldarg.0
IL_0025: ldarg.0
IL_0026: ldfld ""int[] Test.<F>d__2.array""
IL_002b: stfld ""int[] Test.<F>d__2.<>7__wrap3""
IL_0030: ldarg.0
IL_0031: ldfld ""int[] Test.<F>d__2.<>7__wrap3""
IL_0036: ldc.i4.3
IL_0037: ldelem.i4
IL_0038: pop
IL_0039: ldarg.0
IL_003a: ldarg.0
IL_003b: ldfld ""int[] Test.<F>d__2.<>7__wrap3""
IL_0040: ldc.i4.3
IL_0041: ldelem.i4
IL_0042: stfld ""int Test.<F>d__2.<>7__wrap2""
IL_0047: call ""System.Threading.Tasks.Task<int> Test.G()""
IL_004c: callvirt ""System.Runtime.CompilerServices.TaskAwaiter<int> System.Threading.Tasks.Task<int>.GetAwaiter()""
IL_0051: stloc.s V_4
~IL_0053: ldloca.s V_4
IL_0055: call ""bool System.Runtime.CompilerServices.TaskAwaiter<int>.IsCompleted.get""
IL_005a: brtrue.s IL_009a
IL_005c: ldarg.0
IL_005d: ldc.i4.0
IL_005e: dup
IL_005f: stloc.0
IL_0060: stfld ""int Test.<F>d__2.<>1__state""
<IL_0065: ldarg.0
IL_0066: ldloc.s V_4
IL_0068: stfld ""System.Runtime.CompilerServices.TaskAwaiter<int> Test.<F>d__2.<>u__1""
IL_006d: ldarg.0
IL_006e: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder<int> Test.<F>d__2.<>t__builder""
IL_0073: ldloca.s V_4
IL_0075: ldarg.0
IL_0076: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder<int>.AwaitUnsafeOnCompleted<System.Runtime.CompilerServices.TaskAwaiter<int>, Test.<F>d__2>(ref System.Runtime.CompilerServices.TaskAwaiter<int>, ref Test.<F>d__2)""
IL_007b: leave.s IL_00fa
>IL_007d: ldarg.0
IL_007e: ldfld ""System.Runtime.CompilerServices.TaskAwaiter<int> Test.<F>d__2.<>u__1""
IL_0083: stloc.s V_4
IL_0085: ldarg.0
IL_0086: ldflda ""System.Runtime.CompilerServices.TaskAwaiter<int> Test.<F>d__2.<>u__1""
IL_008b: initobj ""System.Runtime.CompilerServices.TaskAwaiter<int>""
IL_0091: ldarg.0
IL_0092: ldc.i4.m1
IL_0093: dup
IL_0094: stloc.0
IL_0095: stfld ""int Test.<F>d__2.<>1__state""
IL_009a: ldloca.s V_4
IL_009c: call ""int System.Runtime.CompilerServices.TaskAwaiter<int>.GetResult()""
IL_00a1: stloc.2
IL_00a2: ldarg.0
IL_00a3: ldfld ""int Test.<F>d__2.<>7__wrap1""
IL_00a8: ldarg.0
IL_00a9: ldfld ""int[] Test.<F>d__2.<>7__wrap3""
IL_00ae: ldc.i4.3
IL_00af: ldarg.0
IL_00b0: ldfld ""int Test.<F>d__2.<>7__wrap2""
IL_00b5: ldloc.2
IL_00b6: add
IL_00b7: dup
IL_00b8: stloc.3
IL_00b9: stelem.i4
IL_00ba: ldloc.3
IL_00bb: ldc.i4.4
IL_00bc: call ""int Test.H(int, int, int)""
IL_00c1: pop
IL_00c2: ldarg.0
IL_00c3: ldnull
IL_00c4: stfld ""int[] Test.<F>d__2.<>7__wrap3""
-IL_00c9: ldc.i4.1
IL_00ca: stloc.1
IL_00cb: leave.s IL_00e6
}
catch System.Exception
{
~IL_00cd: stloc.s V_5
IL_00cf: ldarg.0
IL_00d0: ldc.i4.s -2
IL_00d2: stfld ""int Test.<F>d__2.<>1__state""
IL_00d7: ldarg.0
IL_00d8: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder<int> Test.<F>d__2.<>t__builder""
IL_00dd: ldloc.s V_5
IL_00df: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder<int>.SetException(System.Exception)""
IL_00e4: leave.s IL_00fa
}
-IL_00e6: ldarg.0
IL_00e7: ldc.i4.s -2
IL_00e9: stfld ""int Test.<F>d__2.<>1__state""
~IL_00ee: ldarg.0
IL_00ef: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder<int> Test.<F>d__2.<>t__builder""
IL_00f4: ldloc.1
IL_00f5: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder<int>.SetResult(int)""
IL_00fa: ret
}", sequencePoints: "Test+<F>d__2.MoveNext");
var comp = CreateRuntimeAsyncCompilation(source);
comp.VerifyEmitDiagnostics(
// (18,38): error CS9328: Method 'Test.F(int[])' uses a feature that is not supported by runtime async currently. Opt the method out of runtime async by attributing it with 'System.Runtime.CompilerServices.RuntimeAsyncMethodGenerationAttribute(false)'.
// H(array[1] += 2, array[3] += await G(), 4);
Diagnostic(ErrorCode.ERR_UnsupportedFeatureInRuntimeAsync, "await G()").WithArguments("Test.F(int[])").WithLocation(18, 38)
);
// https://github.com/dotnet/roslyn/issues/79763
// var verifier = CompileAndVerify(comp, verify: Verification.Fails with
// {
// ILVerifyMessage = """
// [F]: Unexpected type on the stack. { Offset = 0x35, Found = Int32, Expected = ref '[System.Runtime]System.Threading.Tasks.Task`1<int32>' }
// """
// });
// verifier.VerifyDiagnostics();
// verifier.VerifyIL("Test.F(int[])", """
// {
// // Code size 54 (0x36)
// .maxstack 4
// .locals init (int& V_0,
// int V_1,
// int V_2,
// int V_3)
// IL_0000: ldarg.0
// IL_0001: ldc.i4.1
// IL_0002: ldelema "int"
// IL_0007: dup
// IL_0008: ldind.i4
// IL_0009: ldc.i4.2
// IL_000a: add
// IL_000b: dup
// IL_000c: stloc.3
// IL_000d: stind.i4
// IL_000e: ldloc.3
// IL_000f: ldarg.0
// IL_0010: ldc.i4.3
// IL_0011: ldelema "int"
// IL_0016: stloc.0
// IL_0017: ldloc.0
// IL_0018: ldind.i4
// IL_0019: stloc.1
// IL_001a: call "System.Threading.Tasks.Task<int> Test.G()"
// IL_001f: call "int System.Runtime.CompilerServices.AsyncHelpers.Await<int>(System.Threading.Tasks.Task<int>)"
// IL_0024: stloc.2
// IL_0025: ldloc.0
// IL_0026: ldloc.1
// IL_0027: ldloc.2
// IL_0028: add
// IL_0029: dup
// IL_002a: stloc.3
// IL_002b: stind.i4
// IL_002c: ldloc.3
// IL_002d: ldc.i4.4
// IL_002e: call "int Test.H(int, int, int)"
// IL_0033: pop
// IL_0034: ldc.i4.1
// IL_0035: ret
// }
// """);
}
[Fact]
public void SpillSequencesInConditionalExpression1()
{
var source = @"
using System.Threading.Tasks;
public class Test
{
public static int H(int a, int b, int c)
{
return a;
}
public static Task<int> G()
{
return null;
}
public static async Task<int> F(int[] array)
{
H(0, (1 == await G()) ? array[3] += await G() : 1, 4);
return 1;
}
}
";
CompileAndVerify(source, options: TestOptions.DebugDll);
var comp = CreateRuntimeAsyncCompilation(source);
comp.VerifyEmitDiagnostics(
// (18,45): error CS9328: Method 'Test.F(int[])' uses a feature that is not supported by runtime async currently. Opt the method out of runtime async by attributing it with 'System.Runtime.CompilerServices.RuntimeAsyncMethodGenerationAttribute(false)'.
// H(0, (1 == await G()) ? array[3] += await G() : 1, 4);
Diagnostic(ErrorCode.ERR_UnsupportedFeatureInRuntimeAsync, "await G()").WithArguments("Test.F(int[])").WithLocation(18, 45)
);
// https://github.com/dotnet/roslyn/issues/79763
// var verifier = CompileAndVerify(comp, verify: Verification.Fails with
// {
// ILVerifyMessage = """
// [F]: Unexpected type on the stack. { Offset = 0x3c, Found = Int32, Expected = ref '[System.Runtime]System.Threading.Tasks.Task`1<int32>' }
// """
// });
// verifier.VerifyDiagnostics();
// verifier.VerifyIL("Test.F(int[])", """
// {
// // Code size 61 (0x3d)
// .maxstack 3
// .locals init (int V_0,
// int V_1,
// int V_2,
// int V_3,
// int V_4)
// IL_0000: call "System.Threading.Tasks.Task<int> Test.G()"
// IL_0005: call "int System.Runtime.CompilerServices.AsyncHelpers.Await<int>(System.Threading.Tasks.Task<int>)"
// IL_000a: stloc.0
// IL_000b: ldc.i4.1
// IL_000c: ldloc.0
// IL_000d: bne.un.s IL_0030
// IL_000f: ldarg.0
// IL_0010: ldc.i4.3
// IL_0011: ldelema "int"
// IL_0016: dup
// IL_0017: ldind.i4
// IL_0018: stloc.2
// IL_0019: call "System.Threading.Tasks.Task<int> Test.G()"
// IL_001e: call "int System.Runtime.CompilerServices.AsyncHelpers.Await<int>(System.Threading.Tasks.Task<int>)"
// IL_0023: stloc.3
// IL_0024: ldloc.2
// IL_0025: ldloc.3
// IL_0026: add
// IL_0027: dup
// IL_0028: stloc.s V_4
// IL_002a: stind.i4
// IL_002b: ldloc.s V_4
// IL_002d: stloc.1
// IL_002e: br.s IL_0032
// IL_0030: ldc.i4.1
// IL_0031: stloc.1
// IL_0032: ldc.i4.0
// IL_0033: ldloc.1
// IL_0034: ldc.i4.4
// IL_0035: call "int Test.H(int, int, int)"
// IL_003a: pop
// IL_003b: ldc.i4.1
// IL_003c: ret
// }
// """);
}
[Fact]
public void SpillSequencesInNullCoalescingOperator1()
{
var source = @"
using System.Threading.Tasks;
public class C
{
public static int H(int a, object b, int c)
{
return a;
}
public static object O(int a)
{
return null;
}
public static Task<int> G()
{
return null;
}
public static async Task<int> F(int[] array)
{
H(0, O(array[0] += await G()) ?? (array[1] += await G()), 4);
return 1;
}
}
";
CompileAndVerify(source, options: TestOptions.ReleaseDll.WithMetadataImportOptions(MetadataImportOptions.All), symbolValidator: module =>
{
AssertEx.Equal(new[]
{
"<>1__state",
"<>t__builder",
"array",
"<>7__wrap1",
"<>7__wrap2",
"<>u__1",
"<>7__wrap3",
"<>7__wrap4",
}, module.GetFieldNames("C.<F>d__3"));
});
CompileAndVerify(source, verify: Verification.Passes, options: TestOptions.DebugDll.WithMetadataImportOptions(MetadataImportOptions.All), symbolValidator: module =>
{
AssertEx.Equal(new[]
{
"<>1__state",
"<>t__builder",
"array",
"<>s__1",
"<>s__2",
"<>s__3",
"<>s__4",
"<>s__5",
"<>s__6",
"<>s__7",
"<>u__1",
"<>s__8"
}, module.GetFieldNames("C.<F>d__3"));
});
var comp = CreateRuntimeAsyncCompilation(source);
comp.VerifyEmitDiagnostics(
// (23,28): error CS9328: Method 'C.F(int[])' uses a feature that is not supported by runtime async currently. Opt the method out of runtime async by attributing it with 'System.Runtime.CompilerServices.RuntimeAsyncMethodGenerationAttribute(false)'.
// H(0, O(array[0] += await G()) ?? (array[1] += await G()), 4);
Diagnostic(ErrorCode.ERR_UnsupportedFeatureInRuntimeAsync, "await G()").WithArguments("C.F(int[])").WithLocation(23, 28),
// (23,55): error CS9328: Method 'C.F(int[])' uses a feature that is not supported by runtime async currently. Opt the method out of runtime async by attributing it with 'System.Runtime.CompilerServices.RuntimeAsyncMethodGenerationAttribute(false)'.
// H(0, O(array[0] += await G()) ?? (array[1] += await G()), 4);
Diagnostic(ErrorCode.ERR_UnsupportedFeatureInRuntimeAsync, "await G()").WithArguments("C.F(int[])").WithLocation(23, 55)
);
// https://github.com/dotnet/roslyn/issues/79763
// var verifier = CompileAndVerify(comp, verify: Verification.Fails with
// {
// ILVerifyMessage = """
// [F]: Unexpected type on the stack. { Offset = 0x55, Found = Int32, Expected = ref '[System.Runtime]System.Threading.Tasks.Task`1<int32>' }
// """
// });
// verifier.VerifyDiagnostics();
// verifier.VerifyIL("C.F(int[])", """
// {
// // Code size 86 (0x56)
// .maxstack 3
// .locals init (int V_0,
// int V_1,
// object V_2,
// int V_3,
// int V_4,
// int V_5)
// IL_0000: ldarg.0
// IL_0001: ldc.i4.0
// IL_0002: ldelema "int"
// IL_0007: dup
// IL_0008: ldind.i4
// IL_0009: stloc.0
// IL_000a: call "System.Threading.Tasks.Task<int> C.G()"
// IL_000f: call "int System.Runtime.CompilerServices.AsyncHelpers.Await<int>(System.Threading.Tasks.Task<int>)"
// IL_0014: stloc.1
// IL_0015: ldloc.0
// IL_0016: ldloc.1
// IL_0017: add
// IL_0018: dup
// IL_0019: stloc.3
// IL_001a: stind.i4
// IL_001b: ldloc.3
// IL_001c: call "object C.O(int)"
// IL_0021: stloc.2
// IL_0022: ldloc.2
// IL_0023: brtrue.s IL_004b
// IL_0025: ldarg.0
// IL_0026: ldc.i4.1
// IL_0027: ldelema "int"
// IL_002c: dup
// IL_002d: ldind.i4
// IL_002e: stloc.3
// IL_002f: call "System.Threading.Tasks.Task<int> C.G()"
// IL_0034: call "int System.Runtime.CompilerServices.AsyncHelpers.Await<int>(System.Threading.Tasks.Task<int>)"
// IL_0039: stloc.s V_4
// IL_003b: ldloc.3
// IL_003c: ldloc.s V_4
// IL_003e: add
// IL_003f: dup
// IL_0040: stloc.s V_5
// IL_0042: stind.i4
// IL_0043: ldloc.s V_5
// IL_0045: box "int"
// IL_004a: stloc.2
// IL_004b: ldc.i4.0
// IL_004c: ldloc.2
// IL_004d: ldc.i4.4
// IL_004e: call "int C.H(int, object, int)"
// IL_0053: pop
// IL_0054: ldc.i4.1
// IL_0055: ret
// }
// """);
}
[WorkItem(4628, "https://github.com/dotnet/roslyn/issues/4628")]
[Fact]
public void AsyncWithShortCircuiting001()
{
var source = @"
using System;
using System.Threading.Tasks;
namespace AsyncConditionalBug {
class Program {
private readonly bool b=true;
private async Task AsyncMethod() {
Console.WriteLine(b && await Task.FromResult(false));
Console.WriteLine(b);
}
static void Main(string[] args) {
new Program().AsyncMethod().Wait();
}
}
}";
var expectedOutput = @"
False
True
";
CompileAndVerify(source, expectedOutput: expectedOutput);
var comp = CreateRuntimeAsyncCompilation(source);
var verifier = CompileAndVerify(comp, expectedOutput: CodeGenAsyncTests.ExpectedOutput(expectedOutput, isRuntimeAsync: true), verify: Verification.Fails with
{
ILVerifyMessage = """
[AsyncMethod]: Return value missing on the stack. { Offset = 0x27 }
"""
});
verifier.VerifyDiagnostics();
verifier.VerifyIL("AsyncConditionalBug.Program.AsyncMethod()", """
{
// Code size 40 (0x28)
.maxstack 1
.locals init (bool V_0)
IL_0000: ldarg.0
IL_0001: ldfld "bool AsyncConditionalBug.Program.b"
IL_0006: stloc.0
IL_0007: ldloc.0
IL_0008: brfalse.s IL_0016
IL_000a: ldc.i4.0
IL_000b: call "System.Threading.Tasks.Task<bool> System.Threading.Tasks.Task.FromResult<bool>(bool)"
IL_0010: call "bool System.Runtime.CompilerServices.AsyncHelpers.Await<bool>(System.Threading.Tasks.Task<bool>)"
IL_0015: stloc.0
IL_0016: ldloc.0
IL_0017: call "void System.Console.WriteLine(bool)"
IL_001c: ldarg.0
IL_001d: ldfld "bool AsyncConditionalBug.Program.b"
IL_0022: call "void System.Console.WriteLine(bool)"
IL_0027: ret
}
""");
}
[WorkItem(4628, "https://github.com/dotnet/roslyn/issues/4628")]
[Fact]
public void AsyncWithShortCircuiting002()
{
var source = @"
using System;
using System.Threading.Tasks;
namespace AsyncConditionalBug {
class Program {
private static readonly bool b=true;
private async Task AsyncMethod() {
Console.WriteLine(b && await Task.FromResult(false));
Console.WriteLine(b);
}
static void Main(string[] args) {
new Program().AsyncMethod().Wait();
}
}
}";
var expectedOutput = @"
False
True
";
CompileAndVerify(source, expectedOutput: expectedOutput);
var comp = CreateRuntimeAsyncCompilation(source);
var verifier = CompileAndVerify(comp, expectedOutput: CodeGenAsyncTests.ExpectedOutput(expectedOutput, isRuntimeAsync: true), verify: Verification.Fails with
{
ILVerifyMessage = """
[AsyncMethod]: Return value missing on the stack. { Offset = 0x25 }
"""
});
verifier.VerifyDiagnostics();
verifier.VerifyIL("AsyncConditionalBug.Program.AsyncMethod()", """
{
// Code size 38 (0x26)
.maxstack 1
.locals init (bool V_0)
IL_0000: ldsfld "bool AsyncConditionalBug.Program.b"
IL_0005: stloc.0
IL_0006: ldloc.0
IL_0007: brfalse.s IL_0015
IL_0009: ldc.i4.0
IL_000a: call "System.Threading.Tasks.Task<bool> System.Threading.Tasks.Task.FromResult<bool>(bool)"
IL_000f: call "bool System.Runtime.CompilerServices.AsyncHelpers.Await<bool>(System.Threading.Tasks.Task<bool>)"
IL_0014: stloc.0
IL_0015: ldloc.0
IL_0016: call "void System.Console.WriteLine(bool)"
IL_001b: ldsfld "bool AsyncConditionalBug.Program.b"
IL_0020: call "void System.Console.WriteLine(bool)"
IL_0025: ret
}
""");
}
[WorkItem(4628, "https://github.com/dotnet/roslyn/issues/4628")]
[Fact]
public void AsyncWithShortCircuiting003()
{
var source = @"
using System;
using System.Threading.Tasks;
namespace AsyncConditionalBug
{
class Program
{
private readonly string NULL = null;
private async Task AsyncMethod()
{
Console.WriteLine(NULL ?? await Task.FromResult(""hello""));
Console.WriteLine(NULL);
}
static void Main(string[] args)
{
new Program().AsyncMethod().Wait();
}
}
}";
var expectedOutput = @"
hello
";
CompileAndVerify(source, expectedOutput: expectedOutput);
var comp = CreateRuntimeAsyncCompilation(source);
var verifier = CompileAndVerify(comp, expectedOutput: CodeGenAsyncTests.ExpectedOutput(expectedOutput, isRuntimeAsync: true), verify: Verification.Fails with
{
ILVerifyMessage = """
[AsyncMethod]: Return value missing on the stack. { Offset = 0x2b }
"""
});
verifier.VerifyDiagnostics();
verifier.VerifyIL("AsyncConditionalBug.Program.AsyncMethod()", """
{
// Code size 44 (0x2c)
.maxstack 1
.locals init (string V_0)
IL_0000: ldarg.0
IL_0001: ldfld "string AsyncConditionalBug.Program.NULL"
IL_0006: stloc.0
IL_0007: ldloc.0
IL_0008: brtrue.s IL_001a
IL_000a: ldstr "hello"
IL_000f: call "System.Threading.Tasks.Task<string> System.Threading.Tasks.Task.FromResult<string>(string)"
IL_0014: call "string System.Runtime.CompilerServices.AsyncHelpers.Await<string>(System.Threading.Tasks.Task<string>)"
IL_0019: stloc.0
IL_001a: ldloc.0
IL_001b: call "void System.Console.WriteLine(string)"
IL_0020: ldarg.0
IL_0021: ldfld "string AsyncConditionalBug.Program.NULL"
IL_0026: call "void System.Console.WriteLine(string)"
IL_002b: ret
}
""");
}
[WorkItem(4638, "https://github.com/dotnet/roslyn/issues/4638")]
[Fact]
public void AsyncWithShortCircuiting004()
{
var source = @"
using System;
using System.Threading.Tasks;
namespace AsyncConditionalBug
{
class Program
{
static void Main(string[] args)
{
try
{
DoSomething(Tuple.Create(1.ToString(), Guid.NewGuid())).GetAwaiter().GetResult();
}
catch (Exception ex)
{
System.Console.Write(ex.Message);
}
}
public static async Task DoSomething(Tuple<string, Guid> item)
{
if (item.Item2 != null || await IsValid(item.Item2))
{
throw new Exception(""Not Valid!"");
};
}
private static async Task<bool> IsValid(Guid id)
{
return false;
}
}
}";
var expectedOutput = @"
Not Valid!
";
CompileAndVerify(source, expectedOutput: expectedOutput);
var comp = CreateRuntimeAsyncCompilation(source);
var verifier = CompileAndVerify(comp, expectedOutput: CodeGenAsyncTests.ExpectedOutput(expectedOutput, isRuntimeAsync: true), verify: Verification.Fails with
{
ILVerifyMessage = """
[DoSomething]: Return value missing on the stack. { Offset = 0x2b }
[IsValid]: Unexpected type on the stack. { Offset = 0x1, Found = Int32, Expected = ref '[System.Runtime]System.Threading.Tasks.Task`1<bool>' }
"""
});
verifier.VerifyDiagnostics(
// (23,17): warning CS8073: The result of the expression is always 'true' since a value of type 'Guid' is never equal to 'null' of type 'Guid?'
// if (item.Item2 != null || await IsValid(item.Item2))
Diagnostic(ErrorCode.WRN_NubExprIsConstBool2, "item.Item2 != null").WithArguments("true", "System.Guid", "System.Guid?").WithLocation(23, 17),
// (29,41): warning CS1998: This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread.
// private static async Task<bool> IsValid(Guid id)
Diagnostic(ErrorCode.WRN_AsyncLacksAwaits, "IsValid").WithLocation(29, 41)
);
verifier.VerifyIL("AsyncConditionalBug.Program.DoSomething(System.Tuple<string, System.Guid>)", """
{
// Code size 44 (0x2c)
.maxstack 1
.locals init (bool V_0)
IL_0000: ldarg.0
IL_0001: callvirt "System.Guid System.Tuple<string, System.Guid>.Item2.get"
IL_0006: pop
IL_0007: ldc.i4.1
IL_0008: stloc.0
IL_0009: ldloc.0
IL_000a: brtrue.s IL_001d
IL_000c: ldarg.0
IL_000d: callvirt "System.Guid System.Tuple<string, System.Guid>.Item2.get"
IL_0012: call "System.Threading.Tasks.Task<bool> AsyncConditionalBug.Program.IsValid(System.Guid)"
IL_0017: call "bool System.Runtime.CompilerServices.AsyncHelpers.Await<bool>(System.Threading.Tasks.Task<bool>)"
IL_001c: stloc.0
IL_001d: ldloc.0
IL_001e: brfalse.s IL_002b
IL_0020: ldstr "Not Valid!"
IL_0025: newobj "System.Exception..ctor(string)"
IL_002a: throw
IL_002b: ret
}
""");
}
[Fact]
public void SpillSequencesInLogicalBinaryOperator1()
{
var source = @"
using System.Threading.Tasks;
public class Test
{
public static int H(int a, bool b, int c)
{
return a;
}
public static bool B(int a)
{
return true;
}
public static Task<int> G()
{
return null;
}
public static async Task<int> F(int[] array)
{
H(0, B(array[0] += await G()) || B(array[1] += await G()), 4);
return 1;
}
}
";
CompileAndVerify(source, options: TestOptions.DebugDll);
var comp = CreateRuntimeAsyncCompilation(source);
comp.VerifyEmitDiagnostics(
// (23,28): error CS9328: Method 'Test.F(int[])' uses a feature that is not supported by runtime async currently. Opt the method out of runtime async by attributing it with 'System.Runtime.CompilerServices.RuntimeAsyncMethodGenerationAttribute(false)'.
// H(0, B(array[0] += await G()) || B(array[1] += await G()), 4);
Diagnostic(ErrorCode.ERR_UnsupportedFeatureInRuntimeAsync, "await G()").WithArguments("Test.F(int[])").WithLocation(23, 28),
// (23,56): error CS9328: Method 'Test.F(int[])' uses a feature that is not supported by runtime async currently. Opt the method out of runtime async by attributing it with 'System.Runtime.CompilerServices.RuntimeAsyncMethodGenerationAttribute(false)'.
// H(0, B(array[0] += await G()) || B(array[1] += await G()), 4);
Diagnostic(ErrorCode.ERR_UnsupportedFeatureInRuntimeAsync, "await G()").WithArguments("Test.F(int[])").WithLocation(23, 56)
);
// https://github.com/dotnet/roslyn/issues/79763
// var verifier = CompileAndVerify(comp, verify: Verification.Fails with
// {
// ILVerifyMessage = """
// [F]: Unexpected type on the stack. { Offset = 0x55, Found = Int32, Expected = ref '[System.Runtime]System.Threading.Tasks.Task`1<int32>' }
// """
// });
// verifier.VerifyDiagnostics();
// verifier.VerifyIL("Test.F(int[])", """
// {
// // Code size 86 (0x56)
// .maxstack 3
// .locals init (int V_0,
// int V_1,
// bool V_2,
// int V_3,
// int V_4,
// int V_5)
// IL_0000: ldarg.0
// IL_0001: ldc.i4.0
// IL_0002: ldelema "int"
// IL_0007: dup
// IL_0008: ldind.i4
// IL_0009: stloc.0
// IL_000a: call "System.Threading.Tasks.Task<int> Test.G()"
// IL_000f: call "int System.Runtime.CompilerServices.AsyncHelpers.Await<int>(System.Threading.Tasks.Task<int>)"
// IL_0014: stloc.1
// IL_0015: ldloc.0
// IL_0016: ldloc.1
// IL_0017: add
// IL_0018: dup
// IL_0019: stloc.3
// IL_001a: stind.i4
// IL_001b: ldloc.3
// IL_001c: call "bool Test.B(int)"
// IL_0021: stloc.2
// IL_0022: ldloc.2
// IL_0023: brtrue.s IL_004b
// IL_0025: ldarg.0
// IL_0026: ldc.i4.1
// IL_0027: ldelema "int"
// IL_002c: dup
// IL_002d: ldind.i4
// IL_002e: stloc.3
// IL_002f: call "System.Threading.Tasks.Task<int> Test.G()"
// IL_0034: call "int System.Runtime.CompilerServices.AsyncHelpers.Await<int>(System.Threading.Tasks.Task<int>)"
// IL_0039: stloc.s V_4
// IL_003b: ldloc.3
// IL_003c: ldloc.s V_4
// IL_003e: add
// IL_003f: dup
// IL_0040: stloc.s V_5
// IL_0042: stind.i4
// IL_0043: ldloc.s V_5
// IL_0045: call "bool Test.B(int)"
// IL_004a: stloc.2
// IL_004b: ldc.i4.0
// IL_004c: ldloc.2
// IL_004d: ldc.i4.4
// IL_004e: call "int Test.H(int, bool, int)"
// IL_0053: pop
// IL_0054: ldc.i4.1
// IL_0055: ret
// }
// """);
}
[Fact]
public void SpillArray01()
{
var source = @"
using System;
using System.Threading;
using System.Threading.Tasks;
class TestCase
{
public async Task<T> GetVal<T>(T t)
{
await Task.Delay(1);
return t;
}
public async void Run<T>(T t) where T : struct
{
int tests = 0;
try
{
tests++;
int[] arr = new int[await GetVal(4)];
if (arr.Length == 4)
Driver.Count++;
//multidimensional
tests++;
decimal[,] arr2 = new decimal[await GetVal(4), await GetVal(4)];
if (arr2.Rank == 2 && arr2.Length == 16)
Driver.Count++;
arr2 = new decimal[4, await GetVal(4)];
if (arr2.Rank == 2 && arr2.Length == 16)
Driver.Count++;
tests++;
arr2 = new decimal[await GetVal(4), 4];
if (arr2.Rank == 2 && arr2.Length == 16)
Driver.Count++;
//jagged array
tests++;
decimal?[][] arr3 = new decimal?[await GetVal(4)][];
if (arr3.Rank == 2 && arr3.Length == 4)
Driver.Count++;
}
finally
{
Driver.Result = Driver.Count - tests;
//When test complete, set the flag.
Driver.CompletedSignal.Set();
}
}
}
class Driver
{
public static int Result = -1;
public static int Count = 0;
public static AutoResetEvent CompletedSignal = new AutoResetEvent(false);
static void Main()
{
var t = new TestCase();
t.Run(6);
CompletedSignal.WaitOne();
// 0 - success
// 1 - failed (test completed)
// -1 - failed (test incomplete - deadlock, etc)
Console.WriteLine(Driver.Result);
}
}";
var expectedOutput = @"
0
";
CompileAndVerify(source, expectedOutput);
}
[Fact]
public void SpillArray01WithTaskAndRuntimeAsync()
{
var source = @"
using System;
using System.Threading;
using System.Threading.Tasks;
class TestCase
{
public async Task<T> GetVal<T>(T t)
{
await Task.Delay(1);
return t;
}
public async Task Run<T>(T t) where T : struct
{
int tests = 0;
try
{
tests++;
int[] arr = new int[await GetVal(4)];
if (arr.Length == 4)
Driver.Count++;
//multidimensional
tests++;
decimal[,] arr2 = new decimal[await GetVal(4), await GetVal(4)];
if (arr2.Rank == 2 && arr2.Length == 16)
Driver.Count++;
arr2 = new decimal[4, await GetVal(4)];
if (arr2.Rank == 2 && arr2.Length == 16)
Driver.Count++;
tests++;
arr2 = new decimal[await GetVal(4), 4];
if (arr2.Rank == 2 && arr2.Length == 16)
Driver.Count++;
//jagged array
tests++;
decimal?[][] arr3 = new decimal?[await GetVal(4)][];
if (arr3.Rank == 2 && arr3.Length == 4)
Driver.Count++;
}
finally
{
Driver.Result = Driver.Count - tests;
//When test complete, set the flag.
Driver.CompletedSignal.Set();
}
}
}
class Driver
{
public static int Result = -1;
public static int Count = 0;
public static AutoResetEvent CompletedSignal = new AutoResetEvent(false);
static void Main()
{
var t = new TestCase();
t.Run(6);
CompletedSignal.WaitOne();
// 0 - success
// 1 - failed (test completed)
// -1 - failed (test incomplete - deadlock, etc)
Console.WriteLine(Driver.Result);
}
}";
var expectedOutput = @"
0
";
CompileAndVerify(source, expectedOutput);
var comp = CreateRuntimeAsyncCompilation(source);
var verifier = CompileAndVerify(comp, expectedOutput: CodeGenAsyncTests.ExpectedOutput(expectedOutput, isRuntimeAsync: true), verify: Verification.Fails with
{
ILVerifyMessage = """
[GetVal]: Unexpected type on the stack. { Offset = 0xc, Found = value 'T', Expected = ref '[System.Runtime]System.Threading.Tasks.Task`1<T0>' }
[Run]: Return value missing on the stack. { Offset = 0x120 }
"""
});
verifier.VerifyDiagnostics(
// (63,9): warning CS4014: Because this call is not awaited, execution of the current method continues before the call is completed. Consider applying the 'await' operator to the result of the call.
// t.Run(6);
Diagnostic(ErrorCode.WRN_UnobservedAwaitableExpression, "t.Run(6)").WithLocation(63, 9)
);
verifier.VerifyIL("TestCase.Run<T>(T)", """
{
// Code size 289 (0x121)
.maxstack 3
.locals init (int V_0, //tests
decimal[,] V_1, //arr2
decimal?[][] V_2, //arr3
int V_3)
IL_0000: ldc.i4.0
IL_0001: stloc.0
.try
{
IL_0002: ldloc.0
IL_0003: ldc.i4.1
IL_0004: add
IL_0005: stloc.0
IL_0006: ldarg.0
IL_0007: ldc.i4.4
IL_0008: call "System.Threading.Tasks.Task<int> TestCase.GetVal<int>(int)"
IL_000d: call "int System.Runtime.CompilerServices.AsyncHelpers.Await<int>(System.Threading.Tasks.Task<int>)"
IL_0012: newarr "int"
IL_0017: ldlen
IL_0018: conv.i4
IL_0019: ldc.i4.4
IL_001a: bne.un.s IL_0028
IL_001c: ldsfld "int Driver.Count"
IL_0021: ldc.i4.1
IL_0022: add
IL_0023: stsfld "int Driver.Count"
IL_0028: ldloc.0
IL_0029: ldc.i4.1
IL_002a: add
IL_002b: stloc.0
IL_002c: ldarg.0
IL_002d: ldc.i4.4
IL_002e: call "System.Threading.Tasks.Task<int> TestCase.GetVal<int>(int)"
IL_0033: call "int System.Runtime.CompilerServices.AsyncHelpers.Await<int>(System.Threading.Tasks.Task<int>)"
IL_0038: ldarg.0
IL_0039: ldc.i4.4
IL_003a: call "System.Threading.Tasks.Task<int> TestCase.GetVal<int>(int)"
IL_003f: call "int System.Runtime.CompilerServices.AsyncHelpers.Await<int>(System.Threading.Tasks.Task<int>)"
IL_0044: stloc.3
IL_0045: ldloc.3
IL_0046: newobj "decimal[*,*]..ctor"
IL_004b: stloc.1
IL_004c: ldloc.1
IL_004d: callvirt "int System.Array.Rank.get"
IL_0052: ldc.i4.2
IL_0053: bne.un.s IL_006b
IL_0055: ldloc.1
IL_0056: callvirt "int System.Array.Length.get"
IL_005b: ldc.i4.s 16
IL_005d: bne.un.s IL_006b
IL_005f: ldsfld "int Driver.Count"
IL_0064: ldc.i4.1
IL_0065: add
IL_0066: stsfld "int Driver.Count"
IL_006b: ldarg.0
IL_006c: ldc.i4.4
IL_006d: call "System.Threading.Tasks.Task<int> TestCase.GetVal<int>(int)"
IL_0072: call "int System.Runtime.CompilerServices.AsyncHelpers.Await<int>(System.Threading.Tasks.Task<int>)"
IL_0077: stloc.3
IL_0078: ldc.i4.4
IL_0079: ldloc.3
IL_007a: newobj "decimal[*,*]..ctor"
IL_007f: stloc.1
IL_0080: ldloc.1
IL_0081: callvirt "int System.Array.Rank.get"
IL_0086: ldc.i4.2
IL_0087: bne.un.s IL_009f
IL_0089: ldloc.1
IL_008a: callvirt "int System.Array.Length.get"
IL_008f: ldc.i4.s 16
IL_0091: bne.un.s IL_009f
IL_0093: ldsfld "int Driver.Count"
IL_0098: ldc.i4.1
IL_0099: add
IL_009a: stsfld "int Driver.Count"
IL_009f: ldloc.0
IL_00a0: ldc.i4.1
IL_00a1: add
IL_00a2: stloc.0
IL_00a3: ldarg.0
IL_00a4: ldc.i4.4
IL_00a5: call "System.Threading.Tasks.Task<int> TestCase.GetVal<int>(int)"
IL_00aa: call "int System.Runtime.CompilerServices.AsyncHelpers.Await<int>(System.Threading.Tasks.Task<int>)"
IL_00af: ldc.i4.4
IL_00b0: newobj "decimal[*,*]..ctor"
IL_00b5: stloc.1
IL_00b6: ldloc.1
IL_00b7: callvirt "int System.Array.Rank.get"
IL_00bc: ldc.i4.2
IL_00bd: bne.un.s IL_00d5
IL_00bf: ldloc.1
IL_00c0: callvirt "int System.Array.Length.get"
IL_00c5: ldc.i4.s 16
IL_00c7: bne.un.s IL_00d5
IL_00c9: ldsfld "int Driver.Count"
IL_00ce: ldc.i4.1
IL_00cf: add
IL_00d0: stsfld "int Driver.Count"
IL_00d5: ldloc.0
IL_00d6: ldc.i4.1
IL_00d7: add
IL_00d8: stloc.0
IL_00d9: ldarg.0
IL_00da: ldc.i4.4
IL_00db: call "System.Threading.Tasks.Task<int> TestCase.GetVal<int>(int)"
IL_00e0: call "int System.Runtime.CompilerServices.AsyncHelpers.Await<int>(System.Threading.Tasks.Task<int>)"
IL_00e5: newarr "decimal?[]"
IL_00ea: stloc.2
IL_00eb: ldloc.2
IL_00ec: callvirt "int System.Array.Rank.get"
IL_00f1: ldc.i4.2
IL_00f2: bne.un.s IL_0106
IL_00f4: ldloc.2
IL_00f5: ldlen
IL_00f6: conv.i4
IL_00f7: ldc.i4.4
IL_00f8: bne.un.s IL_0106
IL_00fa: ldsfld "int Driver.Count"
IL_00ff: ldc.i4.1
IL_0100: add
IL_0101: stsfld "int Driver.Count"
IL_0106: leave.s IL_0120
}
finally
{
IL_0108: ldsfld "int Driver.Count"
IL_010d: ldloc.0
IL_010e: sub
IL_010f: stsfld "int Driver.Result"
IL_0114: ldsfld "System.Threading.AutoResetEvent Driver.CompletedSignal"
IL_0119: callvirt "bool System.Threading.EventWaitHandle.Set()"
IL_011e: pop
IL_011f: endfinally
}
IL_0120: ret
}
""");
}
[Fact]
public void SpillArray02_1()
{
var source = @"
using System;
using System.Threading;
using System.Threading.Tasks;
class TestCase
{
public async Task<T> GetVal<T>(T t)
{
await Task.Delay(1);
return t;
}
public async void Run<T>(T t) where T : struct
{
int tests = 0;
try
{
tests++;
int[] arr = new int[await GetVal(4)];
if (arr.Length == 4)
Driver.Count++;
}
finally
{
Driver.Result = Driver.Count - tests;
//When test complete, set the flag.
Driver.CompletedSignal.Set();
}
}
}
class Driver
{
public static int Result = -1;
public static int Count = 0;
public static AutoResetEvent CompletedSignal = new AutoResetEvent(false);
static void Main()
{
var t = new TestCase();
t.Run(6);
CompletedSignal.WaitOne();
// 0 - success
// 1 - failed (test completed)
// -1 - failed (test incomplete - deadlock, etc)
Console.WriteLine(Driver.Result);
}
}";
var expectedOutput = @"
0
";
CompileAndVerify(source, expectedOutput);
}
[Fact]
public void SpillArray02_1WithTaskAndRuntimeAsync()
{
var source = @"
using System;
using System.Threading;
using System.Threading.Tasks;
class TestCase
{
public async Task<T> GetVal<T>(T t)
{
await Task.Delay(1);
return t;
}
public async Task Run<T>(T t) where T : struct
{
int tests = 0;
try
{
tests++;
int[] arr = new int[await GetVal(4)];
if (arr.Length == 4)
Driver.Count++;
}
finally
{
Driver.Result = Driver.Count - tests;
//When test complete, set the flag.
Driver.CompletedSignal.Set();
}
}
}
class Driver
{
public static int Result = -1;
public static int Count = 0;
public static AutoResetEvent CompletedSignal = new AutoResetEvent(false);
static void Main()
{
var t = new TestCase();
#pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
t.Run(6);
#pragma warning restore CS4014
CompletedSignal.WaitOne();
// 0 - success
// 1 - failed (test completed)
// -1 - failed (test incomplete - deadlock, etc)
Console.WriteLine(Driver.Result);
}
}";
var expectedOutput = @"
0
";
CompileAndVerify(source, expectedOutput);
var comp = CreateRuntimeAsyncCompilation(source);
var verifier = CompileAndVerify(comp, expectedOutput: CodeGenAsyncTests.ExpectedOutput(expectedOutput, isRuntimeAsync: true), verify: Verification.Fails with
{
ILVerifyMessage = """
[GetVal]: Unexpected type on the stack. { Offset = 0xc, Found = value 'T', Expected = ref '[System.Runtime]System.Threading.Tasks.Task`1<T0>' }
[Run]: Return value missing on the stack. { Offset = 0x42 }
"""
});
verifier.VerifyDiagnostics();
verifier.VerifyIL("TestCase.Run<T>(T)", """
{
// Code size 67 (0x43)
.maxstack 2
.locals init (int V_0) //tests
IL_0000: ldc.i4.0
IL_0001: stloc.0
.try
{
IL_0002: ldloc.0
IL_0003: ldc.i4.1
IL_0004: add
IL_0005: stloc.0
IL_0006: ldarg.0
IL_0007: ldc.i4.4
IL_0008: call "System.Threading.Tasks.Task<int> TestCase.GetVal<int>(int)"
IL_000d: call "int System.Runtime.CompilerServices.AsyncHelpers.Await<int>(System.Threading.Tasks.Task<int>)"
IL_0012: newarr "int"
IL_0017: ldlen
IL_0018: conv.i4
IL_0019: ldc.i4.4
IL_001a: bne.un.s IL_0028
IL_001c: ldsfld "int Driver.Count"
IL_0021: ldc.i4.1
IL_0022: add
IL_0023: stsfld "int Driver.Count"
IL_0028: leave.s IL_0042
}
finally
{
IL_002a: ldsfld "int Driver.Count"
IL_002f: ldloc.0
IL_0030: sub
IL_0031: stsfld "int Driver.Result"
IL_0036: ldsfld "System.Threading.AutoResetEvent Driver.CompletedSignal"
IL_003b: callvirt "bool System.Threading.EventWaitHandle.Set()"
IL_0040: pop
IL_0041: endfinally
}
IL_0042: ret
}
""");
}
[Fact]
public void SpillArray02_2()
{
var source = @"
using System;
using System.Threading;
using System.Threading.Tasks;
class TestCase
{
public async Task<T> GetVal<T>(T t)
{
await Task.Delay(1);
return t;
}
public async void Run<T>(T t) where T : struct
{
int tests = 0;
try
{
int[] arr = new int[4];
tests++;
arr[0] = await GetVal(4);
if (arr[0] == 4)
Driver.Count++;
}
finally
{
Driver.Result = Driver.Count - tests;
//When test complete, set the flag.
Driver.CompletedSignal.Set();
}
}
}
class Driver
{
public static int Result = -1;
public static int Count = 0;
public static AutoResetEvent CompletedSignal = new AutoResetEvent(false);
static void Main()
{
var t = new TestCase();
t.Run(6);
CompletedSignal.WaitOne();
// 0 - success
// 1 - failed (test completed)
// -1 - failed (test incomplete - deadlock, etc)
Console.WriteLine(Driver.Result);
}
}";
var expectedOutput = @"
0
";
CompileAndVerify(source, expectedOutput);
}
[Fact]
public void SpillArray02_2WithTaskAndRuntimeAsync()
{
var source = @"
using System;
using System.Threading;
using System.Threading.Tasks;
class TestCase
{
public async Task<T> GetVal<T>(T t)
{
await Task.Delay(1);
return t;
}
public async Task Run<T>(T t) where T : struct
{
int tests = 0;
try
{
int[] arr = new int[4];
tests++;
arr[0] = await GetVal(4);
if (arr[0] == 4)
Driver.Count++;
}
finally
{
Driver.Result = Driver.Count - tests;
//When test complete, set the flag.
Driver.CompletedSignal.Set();
}
}
}
class Driver
{
public static int Result = -1;
public static int Count = 0;
public static AutoResetEvent CompletedSignal = new AutoResetEvent(false);
static void Main()
{
var t = new TestCase();
#pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
t.Run(6);
#pragma warning restore CS4014
CompletedSignal.WaitOne();
// 0 - success
// 1 - failed (test completed)
// -1 - failed (test incomplete - deadlock, etc)
Console.WriteLine(Driver.Result);
}
}";
var expectedOutput = @"
0
";
CompileAndVerify(source, expectedOutput);
var comp = CreateRuntimeAsyncCompilation(source);
var verifier = CompileAndVerify(comp, expectedOutput: CodeGenAsyncTests.ExpectedOutput(expectedOutput, isRuntimeAsync: true), verify: Verification.Fails with
{
ILVerifyMessage = """
[GetVal]: Unexpected type on the stack. { Offset = 0xc, Found = value 'T', Expected = ref '[System.Runtime]System.Threading.Tasks.Task`1<T0>' }
[Run]: Return value missing on the stack. { Offset = 0x48 }
"""
});
verifier.VerifyDiagnostics();
verifier.VerifyIL("TestCase.Run<T>(T)", """
{
// Code size 73 (0x49)
.maxstack 4
.locals init (int V_0, //tests
int V_1)
IL_0000: ldc.i4.0
IL_0001: stloc.0
.try
{
IL_0002: ldc.i4.4
IL_0003: newarr "int"
IL_0008: ldloc.0
IL_0009: ldc.i4.1
IL_000a: add
IL_000b: stloc.0
IL_000c: dup
IL_000d: ldarg.0
IL_000e: ldc.i4.4
IL_000f: call "System.Threading.Tasks.Task<int> TestCase.GetVal<int>(int)"
IL_0014: call "int System.Runtime.CompilerServices.AsyncHelpers.Await<int>(System.Threading.Tasks.Task<int>)"
IL_0019: stloc.1
IL_001a: ldc.i4.0
IL_001b: ldloc.1
IL_001c: stelem.i4
IL_001d: ldc.i4.0
IL_001e: ldelem.i4
IL_001f: ldc.i4.4
IL_0020: bne.un.s IL_002e
IL_0022: ldsfld "int Driver.Count"
IL_0027: ldc.i4.1
IL_0028: add
IL_0029: stsfld "int Driver.Count"
IL_002e: leave.s IL_0048
}
finally
{
IL_0030: ldsfld "int Driver.Count"
IL_0035: ldloc.0
IL_0036: sub
IL_0037: stsfld "int Driver.Result"
IL_003c: ldsfld "System.Threading.AutoResetEvent Driver.CompletedSignal"
IL_0041: callvirt "bool System.Threading.EventWaitHandle.Set()"
IL_0046: pop
IL_0047: endfinally
}
IL_0048: ret
}
""");
}
[Fact]
public void SpillArray02_3()
{
var source = @"
using System;
using System.Threading;
using System.Threading.Tasks;
class TestCase
{
public async Task<T> GetVal<T>(T t)
{
await Task.Delay(1);
return t;
}
public async void Run<T>(T t) where T : struct
{
int tests = 0;
try
{
int[] arr = new int[4];
arr[0] = 4;
tests++;
arr[0] += await GetVal(4);
if (arr[0] == 8)
Driver.Count++;
}
finally
{
Driver.Result = Driver.Count - tests;
//When test complete, set the flag.
Driver.CompletedSignal.Set();
}
}
}
class Driver
{
public static int Result = -1;
public static int Count = 0;
public static AutoResetEvent CompletedSignal = new AutoResetEvent(false);
static void Main()
{
var t = new TestCase();
t.Run(6);
CompletedSignal.WaitOne();
// 0 - success
// 1 - failed (test completed)
// -1 - failed (test incomplete - deadlock, etc)
Console.WriteLine(Driver.Result);
}
}";
var expectedOutput = @"
0
";
CompileAndVerify(source, expectedOutput);
}
[Fact]
public void SpillArray02_3WithTaskAndRuntimeAsync()
{
var source = @"
using System;
using System.Threading;
using System.Threading.Tasks;
class TestCase
{
public async Task<T> GetVal<T>(T t)
{
await Task.Delay(1);
return t;
}
public async Task Run<T>(T t) where T : struct
{
int tests = 0;
try
{
int[] arr = new int[4];
arr[0] = 4;
tests++;
arr[0] += await GetVal(4);
if (arr[0] == 8)
Driver.Count++;
}
finally
{
Driver.Result = Driver.Count - tests;
//When test complete, set the flag.
Driver.CompletedSignal.Set();
}
}
}
class Driver
{
public static int Result = -1;
public static int Count = 0;
public static AutoResetEvent CompletedSignal = new AutoResetEvent(false);
static void Main()
{
var t = new TestCase();
#pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
t.Run(6);
#pragma warning restore CS4014
CompletedSignal.WaitOne();
// 0 - success
// 1 - failed (test completed)
// -1 - failed (test incomplete - deadlock, etc)
Console.WriteLine(Driver.Result);
}
}";
var expectedOutput = @"
0
";
CompileAndVerify(source, expectedOutput);
var comp = CreateRuntimeAsyncCompilation(source);
comp.VerifyEmitDiagnostics(
// (23,23): error CS9328: Method 'TestCase.Run<T>(T)' uses a feature that is not supported by runtime async currently. Opt the method out of runtime async by attributing it with 'System.Runtime.CompilerServices.RuntimeAsyncMethodGenerationAttribute(false)'.
// arr[0] += await GetVal(4);
Diagnostic(ErrorCode.ERR_UnsupportedFeatureInRuntimeAsync, "await GetVal(4)").WithArguments("TestCase.Run<T>(T)").WithLocation(23, 23)
);
// https://github.com/dotnet/roslyn/issues/79763
// var verifier = CompileAndVerify(comp, expectedOutput: CodeGenAsyncTests.ExpectedOutput(expectedOutput, isRuntimeAsync: true), verify: Verification.Fails with
// {
// ILVerifyMessage = """
// [GetVal]: Unexpected type on the stack. { Offset = 0xc, Found = value 'T', Expected = ref '[System.Runtime]System.Threading.Tasks.Task`1<T0>' }
// [Run]: Return value missing on the stack. { Offset = 0x56 }
// """
// });
// verifier.VerifyDiagnostics();
// verifier.VerifyIL("TestCase.Run<T>(T)", """
// {
// // Code size 87 (0x57)
// .maxstack 4
// .locals init (int V_0, //tests
// int V_1,
// int V_2)
// IL_0000: ldc.i4.0
// IL_0001: stloc.0
// .try
// {
// IL_0002: ldc.i4.4
// IL_0003: newarr "int"
// IL_0008: dup
// IL_0009: ldc.i4.0
// IL_000a: ldc.i4.4
// IL_000b: stelem.i4
// IL_000c: ldloc.0
// IL_000d: ldc.i4.1
// IL_000e: add
// IL_000f: stloc.0
// IL_0010: dup
// IL_0011: ldc.i4.0
// IL_0012: ldelema "int"
// IL_0017: dup
// IL_0018: ldind.i4
// IL_0019: stloc.1
// IL_001a: ldarg.0
// IL_001b: ldc.i4.4
// IL_001c: call "System.Threading.Tasks.Task<int> TestCase.GetVal<int>(int)"
// IL_0021: call "int System.Runtime.CompilerServices.AsyncHelpers.Await<int>(System.Threading.Tasks.Task<int>)"
// IL_0026: stloc.2
// IL_0027: ldloc.1
// IL_0028: ldloc.2
// IL_0029: add
// IL_002a: stind.i4
// IL_002b: ldc.i4.0
// IL_002c: ldelem.i4
// IL_002d: ldc.i4.8
// IL_002e: bne.un.s IL_003c
// IL_0030: ldsfld "int Driver.Count"
// IL_0035: ldc.i4.1
// IL_0036: add
// IL_0037: stsfld "int Driver.Count"
// IL_003c: leave.s IL_0056
// }
// finally
// {
// IL_003e: ldsfld "int Driver.Count"
// IL_0043: ldloc.0
// IL_0044: sub
// IL_0045: stsfld "int Driver.Result"
// IL_004a: ldsfld "System.Threading.AutoResetEvent Driver.CompletedSignal"
// IL_004f: callvirt "bool System.Threading.EventWaitHandle.Set()"
// IL_0054: pop
// IL_0055: endfinally
// }
// IL_0056: ret
// }
// """);
}
[Fact]
public void SpillArray02_4()
{
var source = @"
using System;
using System.Threading;
using System.Threading.Tasks;
class TestCase
{
public async Task<T> GetVal<T>(T t)
{
await Task.Delay(1);
return t;
}
public async void Run<T>(T t) where T : struct
{
int tests = 0;
try
{
int[] arr = new int[] { 8, 0, 0, 0 };
tests++;
arr[1] += await (GetVal(arr[0]));
if (arr[1] == 8)
Driver.Count++;
}
finally
{
Driver.Result = Driver.Count - tests;
//When test complete, set the flag.
Driver.CompletedSignal.Set();
}
}
}
class Driver
{
public static int Result = -1;
public static int Count = 0;
public static AutoResetEvent CompletedSignal = new AutoResetEvent(false);
static void Main()
{
var t = new TestCase();
t.Run(6);
CompletedSignal.WaitOne();
// 0 - success
// 1 - failed (test completed)
// -1 - failed (test incomplete - deadlock, etc)
Console.WriteLine(Driver.Result);
}
}";
var expectedOutput = @"
0
";
CompileAndVerify(source, expectedOutput);
}
[Fact]
public void SpillArray02_4WithTaskAndRuntimeAsync()
{
var source = @"
using System;
using System.Threading;
using System.Threading.Tasks;
class TestCase
{
public async Task<T> GetVal<T>(T t)
{
await Task.Delay(1);
return t;
}
public async Task Run<T>(T t) where T : struct
{
int tests = 0;
try
{
int[] arr = new int[] { 8, 0, 0, 0 };
tests++;
arr[1] += await (GetVal(arr[0]));
if (arr[1] == 8)
Driver.Count++;
}
finally
{
Driver.Result = Driver.Count - tests;
//When test complete, set the flag.
Driver.CompletedSignal.Set();
}
}
}
class Driver
{
public static int Result = -1;
public static int Count = 0;
public static AutoResetEvent CompletedSignal = new AutoResetEvent(false);
static void Main()
{
var t = new TestCase();
#pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
t.Run(6);
#pragma warning restore CS4014
CompletedSignal.WaitOne();
// 0 - success
// 1 - failed (test completed)
// -1 - failed (test incomplete - deadlock, etc)
Console.WriteLine(Driver.Result);
}
}";
var expectedOutput = @"
0
";
CompileAndVerify(source, expectedOutput);
var comp = CreateRuntimeAsyncCompilation(source);
comp.VerifyEmitDiagnostics(
// (22,23): error CS9328: Method 'TestCase.Run<T>(T)' uses a feature that is not supported by runtime async currently. Opt the method out of runtime async by attributing it with 'System.Runtime.CompilerServices.RuntimeAsyncMethodGenerationAttribute(false)'.
// arr[1] += await (GetVal(arr[0]));
Diagnostic(ErrorCode.ERR_UnsupportedFeatureInRuntimeAsync, "await (GetVal(arr[0]))").WithArguments("TestCase.Run<T>(T)").WithLocation(22, 23)
);
// https://github.com/dotnet/roslyn/issues/79763
// var verifier = CompileAndVerify(comp, expectedOutput: CodeGenAsyncTests.ExpectedOutput(expectedOutput, isRuntimeAsync: true), verify: Verification.Fails with
// {
// ILVerifyMessage = """
// [GetVal]: Unexpected type on the stack. { Offset = 0xc, Found = value 'T', Expected = ref '[System.Runtime]System.Threading.Tasks.Task`1<T0>' }
// [Run]: Return value missing on the stack. { Offset = 0x5a }
// """
// });
// verifier.VerifyDiagnostics();
// verifier.VerifyIL("TestCase.Run<T>(T)", """
// {
// // Code size 91 (0x5b)
// .maxstack 4
// .locals init (int V_0, //tests
// int[] V_1, //arr
// int V_2,
// int V_3)
// IL_0000: ldc.i4.0
// IL_0001: stloc.0
// .try
// {
// IL_0002: ldc.i4.4
// IL_0003: newarr "int"
// IL_0008: dup
// IL_0009: ldc.i4.0
// IL_000a: ldc.i4.8
// IL_000b: stelem.i4
// IL_000c: stloc.1
// IL_000d: ldloc.0
// IL_000e: ldc.i4.1
// IL_000f: add
// IL_0010: stloc.0
// IL_0011: ldloc.1
// IL_0012: ldc.i4.1
// IL_0013: ldelema "int"
// IL_0018: dup
// IL_0019: ldind.i4
// IL_001a: stloc.2
// IL_001b: ldarg.0
// IL_001c: ldloc.1
// IL_001d: ldc.i4.0
// IL_001e: ldelem.i4
// IL_001f: call "System.Threading.Tasks.Task<int> TestCase.GetVal<int>(int)"
// IL_0024: call "int System.Runtime.CompilerServices.AsyncHelpers.Await<int>(System.Threading.Tasks.Task<int>)"
// IL_0029: stloc.3
// IL_002a: ldloc.2
// IL_002b: ldloc.3
// IL_002c: add
// IL_002d: stind.i4
// IL_002e: ldloc.1
// IL_002f: ldc.i4.1
// IL_0030: ldelem.i4
// IL_0031: ldc.i4.8
// IL_0032: bne.un.s IL_0040
// IL_0034: ldsfld "int Driver.Count"
// IL_0039: ldc.i4.1
// IL_003a: add
// IL_003b: stsfld "int Driver.Count"
// IL_0040: leave.s IL_005a
// }
// finally
// {
// IL_0042: ldsfld "int Driver.Count"
// IL_0047: ldloc.0
// IL_0048: sub
// IL_0049: stsfld "int Driver.Result"
// IL_004e: ldsfld "System.Threading.AutoResetEvent Driver.CompletedSignal"
// IL_0053: callvirt "bool System.Threading.EventWaitHandle.Set()"
// IL_0058: pop
// IL_0059: endfinally
// }
// IL_005a: ret
// }
// """);
}
[Fact]
public void SpillArray02_5()
{
var source = @"
using System;
using System.Threading;
using System.Threading.Tasks;
class TestCase
{
public async Task<T> GetVal<T>(T t)
{
await Task.Delay(1);
return t;
}
public async void Run<T>(T t) where T : struct
{
int tests = 0;
try
{
int[] arr = new int[] { 8, 8, 0, 0 };
tests++;
arr[1] += await (GetVal(arr[await GetVal(0)]));
if (arr[1] == 16)
Driver.Count++;
tests++;
arr[await GetVal(2)]++;
if (arr[2] == 1)
Driver.Count++;
}
finally
{
Driver.Result = Driver.Count - tests;
//When test complete, set the flag.
Driver.CompletedSignal.Set();
}
}
}
class Driver
{
public static int Result = -1;
public static int Count = 0;
public static AutoResetEvent CompletedSignal = new AutoResetEvent(false);
static void Main()
{
var t = new TestCase();
t.Run(6);
CompletedSignal.WaitOne();
// 0 - success
// 1 - failed (test completed)
// -1 - failed (test incomplete - deadlock, etc)
Console.WriteLine(Driver.Result);
}
}";
var expectedOutput = @"
0
";
CompileAndVerify(source, expectedOutput);
}
[Fact]
public void SpillArray02_5WithTaskAndRuntimeAsync()
{
var source = @"
using System;
using System.Threading;
using System.Threading.Tasks;
class TestCase
{
public async Task<T> GetVal<T>(T t)
{
await Task.Delay(1);
return t;
}
public async Task Run<T>(T t) where T : struct
{
int tests = 0;
try
{
int[] arr = new int[] { 8, 8, 0, 0 };
tests++;
arr[1] += await (GetVal(arr[await GetVal(0)]));
if (arr[1] == 16)
Driver.Count++;
tests++;
arr[await GetVal(2)]++;
if (arr[2] == 1)
Driver.Count++;
}
finally
{
Driver.Result = Driver.Count - tests;
//When test complete, set the flag.
Driver.CompletedSignal.Set();
}
}
}
class Driver
{
public static int Result = -1;
public static int Count = 0;
public static AutoResetEvent CompletedSignal = new AutoResetEvent(false);
static void Main()
{
var t = new TestCase();
#pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
t.Run(6);
#pragma warning restore CS4014
CompletedSignal.WaitOne();
// 0 - success
// 1 - failed (test completed)
// -1 - failed (test incomplete - deadlock, etc)
Console.WriteLine(Driver.Result);
}
}";
var expectedOutput = @"
0
";
CompileAndVerify(source, expectedOutput);
var comp = CreateRuntimeAsyncCompilation(source);
comp.VerifyEmitDiagnostics(
// (22,23): error CS9328: Method 'TestCase.Run<T>(T)' uses a feature that is not supported by runtime async currently. Opt the method out of runtime async by attributing it with 'System.Runtime.CompilerServices.RuntimeAsyncMethodGenerationAttribute(false)'.
// arr[1] += await (GetVal(arr[await GetVal(0)]));
Diagnostic(ErrorCode.ERR_UnsupportedFeatureInRuntimeAsync, "await (GetVal(arr[await GetVal(0)]))").WithArguments("TestCase.Run<T>(T)").WithLocation(22, 23)
);
// https://github.com/dotnet/roslyn/issues/79763
// var verifier = CompileAndVerify(comp, expectedOutput: CodeGenAsyncTests.ExpectedOutput(expectedOutput, isRuntimeAsync: true), verify: Verification.Fails with
// {
// ILVerifyMessage = """
// [GetVal]: Unexpected type on the stack. { Offset = 0xc, Found = value 'T', Expected = ref '[System.Runtime]System.Threading.Tasks.Task`1<T0>' }
// [Run]: Return value missing on the stack. { Offset = 0xa3 }
// """
// });
// verifier.VerifyDiagnostics();
// verifier.VerifyIL("TestCase.Run<T>(T)", """
// {
// // Code size 164 (0xa4)
// .maxstack 4
// .locals init (int V_0, //tests
// int& V_1,
// int V_2,
// int V_3,
// int[] V_4,
// int V_5)
// IL_0000: ldc.i4.0
// IL_0001: stloc.0
// .try
// {
// IL_0002: ldc.i4.4
// IL_0003: newarr "int"
// IL_0008: dup
// IL_0009: ldc.i4.0
// IL_000a: ldc.i4.8
// IL_000b: stelem.i4
// IL_000c: dup
// IL_000d: ldc.i4.1
// IL_000e: ldc.i4.8
// IL_000f: stelem.i4
// IL_0010: ldloc.0
// IL_0011: ldc.i4.1
// IL_0012: add
// IL_0013: stloc.0
// IL_0014: dup
// IL_0015: ldc.i4.1
// IL_0016: ldelema "int"
// IL_001b: stloc.1
// IL_001c: ldloc.1
// IL_001d: ldind.i4
// IL_001e: stloc.2
// IL_001f: dup
// IL_0020: stloc.s V_4
// IL_0022: ldarg.0
// IL_0023: ldc.i4.0
// IL_0024: call "System.Threading.Tasks.Task<int> TestCase.GetVal<int>(int)"
// IL_0029: call "int System.Runtime.CompilerServices.AsyncHelpers.Await<int>(System.Threading.Tasks.Task<int>)"
// IL_002e: stloc.s V_5
// IL_0030: ldarg.0
// IL_0031: ldloc.s V_4
// IL_0033: ldloc.s V_5
// IL_0035: ldelem.i4
// IL_0036: call "System.Threading.Tasks.Task<int> TestCase.GetVal<int>(int)"
// IL_003b: call "int System.Runtime.CompilerServices.AsyncHelpers.Await<int>(System.Threading.Tasks.Task<int>)"
// IL_0040: stloc.3
// IL_0041: ldloc.1
// IL_0042: ldloc.2
// IL_0043: ldloc.3
// IL_0044: add
// IL_0045: stind.i4
// IL_0046: dup
// IL_0047: ldc.i4.1
// IL_0048: ldelem.i4
// IL_0049: ldc.i4.s 16
// IL_004b: bne.un.s IL_0059
// IL_004d: ldsfld "int Driver.Count"
// IL_0052: ldc.i4.1
// IL_0053: add
// IL_0054: stsfld "int Driver.Count"
// IL_0059: ldloc.0
// IL_005a: ldc.i4.1
// IL_005b: add
// IL_005c: stloc.0
// IL_005d: dup
// IL_005e: ldarg.0
// IL_005f: ldc.i4.2
// IL_0060: call "System.Threading.Tasks.Task<int> TestCase.GetVal<int>(int)"
// IL_0065: call "int System.Runtime.CompilerServices.AsyncHelpers.Await<int>(System.Threading.Tasks.Task<int>)"
// IL_006a: stloc.3
// IL_006b: ldloc.3
// IL_006c: ldelema "int"
// IL_0071: dup
// IL_0072: ldind.i4
// IL_0073: stloc.2
// IL_0074: ldloc.2
// IL_0075: ldc.i4.1
// IL_0076: add
// IL_0077: stind.i4
// IL_0078: ldc.i4.2
// IL_0079: ldelem.i4
// IL_007a: ldc.i4.1
// IL_007b: bne.un.s IL_0089
// IL_007d: ldsfld "int Driver.Count"
// IL_0082: ldc.i4.1
// IL_0083: add
// IL_0084: stsfld "int Driver.Count"
// IL_0089: leave.s IL_00a3
// }
// finally
// {
// IL_008b: ldsfld "int Driver.Count"
// IL_0090: ldloc.0
// IL_0091: sub
// IL_0092: stsfld "int Driver.Result"
// IL_0097: ldsfld "System.Threading.AutoResetEvent Driver.CompletedSignal"
// IL_009c: callvirt "bool System.Threading.EventWaitHandle.Set()"
// IL_00a1: pop
// IL_00a2: endfinally
// }
// IL_00a3: ret
// }
// """);
}
[Fact]
public void SpillArray02_6()
{
var source = @"
using System;
using System.Threading;
using System.Threading.Tasks;
class TestCase
{
public async Task<T> GetVal<T>(T t)
{
await Task.Delay(1);
return t;
}
public async void Run<T>(T t) where T : struct
{
int tests = 0;
try
{
int[] arr = new int[4];
tests++;
arr[await GetVal(2)]++;
if (arr[2] == 1)
Driver.Count++;
}
finally
{
Driver.Result = Driver.Count - tests;
//When test complete, set the flag.
Driver.CompletedSignal.Set();
}
}
}
class Driver
{
public static int Result = -1;
public static int Count = 0;
public static AutoResetEvent CompletedSignal = new AutoResetEvent(false);
static void Main()
{
var t = new TestCase();
t.Run(6);
CompletedSignal.WaitOne();
// 0 - success
// 1 - failed (test completed)
// -1 - failed (test incomplete - deadlock, etc)
Console.WriteLine(Driver.Result);
}
}";
var expectedOutput = @"
0
";
CompileAndVerify(source, expectedOutput);
}
[Fact]
public void SpillArray02_6WithTaskAndRuntimeAsync()
{
var source = @"
using System;
using System.Threading;
using System.Threading.Tasks;
class TestCase
{
public async Task<T> GetVal<T>(T t)
{
await Task.Delay(1);
return t;
}
public async Task Run<T>(T t) where T : struct
{
int tests = 0;
try
{
int[] arr = new int[4];
tests++;
arr[await GetVal(2)]++;
if (arr[2] == 1)
Driver.Count++;
}
finally
{
Driver.Result = Driver.Count - tests;
//When test complete, set the flag.
Driver.CompletedSignal.Set();
}
}
}
class Driver
{
public static int Result = -1;
public static int Count = 0;
public static AutoResetEvent CompletedSignal = new AutoResetEvent(false);
static void Main()
{
var t = new TestCase();
#pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
t.Run(6);
#pragma warning restore CS4014
CompletedSignal.WaitOne();
// 0 - success
// 1 - failed (test completed)
// -1 - failed (test incomplete - deadlock, etc)
Console.WriteLine(Driver.Result);
}
}";
var expectedOutput = @"
0
";
CompileAndVerify(source, expectedOutput);
var comp = CreateRuntimeAsyncCompilation(source);
var verifier = CompileAndVerify(comp, expectedOutput: CodeGenAsyncTests.ExpectedOutput(expectedOutput, isRuntimeAsync: true), verify: Verification.Fails with
{
ILVerifyMessage = """
[GetVal]: Unexpected type on the stack. { Offset = 0xc, Found = value 'T', Expected = ref '[System.Runtime]System.Threading.Tasks.Task`1<T0>' }
[Run]: Return value missing on the stack. { Offset = 0x52 }
"""
});
verifier.VerifyDiagnostics();
verifier.VerifyIL("TestCase.Run<T>(T)", """
{
// Code size 83 (0x53)
.maxstack 4
.locals init (int V_0, //tests
int V_1,
int V_2)
IL_0000: ldc.i4.0
IL_0001: stloc.0
.try
{
IL_0002: ldc.i4.4
IL_0003: newarr "int"
IL_0008: ldloc.0
IL_0009: ldc.i4.1
IL_000a: add
IL_000b: stloc.0
IL_000c: dup
IL_000d: ldarg.0
IL_000e: ldc.i4.2
IL_000f: call "System.Threading.Tasks.Task<int> TestCase.GetVal<int>(int)"
IL_0014: call "int System.Runtime.CompilerServices.AsyncHelpers.Await<int>(System.Threading.Tasks.Task<int>)"
IL_0019: stloc.1
IL_001a: ldloc.1
IL_001b: ldelema "int"
IL_0020: dup
IL_0021: ldind.i4
IL_0022: stloc.2
IL_0023: ldloc.2
IL_0024: ldc.i4.1
IL_0025: add
IL_0026: stind.i4
IL_0027: ldc.i4.2
IL_0028: ldelem.i4
IL_0029: ldc.i4.1
IL_002a: bne.un.s IL_0038
IL_002c: ldsfld "int Driver.Count"
IL_0031: ldc.i4.1
IL_0032: add
IL_0033: stsfld "int Driver.Count"
IL_0038: leave.s IL_0052
}
finally
{
IL_003a: ldsfld "int Driver.Count"
IL_003f: ldloc.0
IL_0040: sub
IL_0041: stsfld "int Driver.Result"
IL_0046: ldsfld "System.Threading.AutoResetEvent Driver.CompletedSignal"
IL_004b: callvirt "bool System.Threading.EventWaitHandle.Set()"
IL_0050: pop
IL_0051: endfinally
}
IL_0052: ret
}
""");
}
[Fact]
public void SpillArray03()
{
var source = @"
using System;
using System.Threading;
using System.Threading.Tasks;
class TestCase
{
public async Task<T> GetVal<T>(T t)
{
await Task.Delay(1);
return t;
}
public async void Run<T>(T t) where T : struct
{
int tests = 0;
try
{
int[,] arr = new int[await GetVal(4), await GetVal(4)];
tests++;
arr[0, 0] = await GetVal(4);
if (arr[0, await (GetVal(0))] == 4)
Driver.Count++;
tests++;
arr[0, 0] += await GetVal(4);
if (arr[0, 0] == 8)
Driver.Count++;
tests++;
arr[1, 1] += await (GetVal(arr[0, 0]));
if (arr[1, 1] == 8)
Driver.Count++;
tests++;
arr[1, 1] += await (GetVal(arr[0, await GetVal(0)]));
if (arr[1, 1] == 16)
Driver.Count++;
tests++;
arr[2, await GetVal(2)]++;
if (arr[2, 2] == 1)
Driver.Count++;
}
finally
{
Driver.Result = Driver.Count - tests;
//When test complete, set the flag.
Driver.CompletedSignal.Set();
}
}
}
class Driver
{
public static int Result = -1;
public static int Count = 0;
public static AutoResetEvent CompletedSignal = new AutoResetEvent(false);
static void Main()
{
var t = new TestCase();
t.Run(6);
CompletedSignal.WaitOne();
// 0 - success
// 1 - failed (test completed)
// -1 - failed (test incomplete - deadlock, etc)
Console.WriteLine(Driver.Result);
}
}";
var expectedOutput = @"
0
";
CompileAndVerify(source, expectedOutput);
}
[Fact]
public void SpillArray03WithTaskAndRuntimeAsync()
{
var source = @"
using System;
using System.Threading;
using System.Threading.Tasks;
class TestCase
{
public async Task<T> GetVal<T>(T t)
{
await Task.Delay(1);
return t;
}
public async Task Run<T>(T t) where T : struct
{
int tests = 0;
try
{
int[,] arr = new int[await GetVal(4), await GetVal(4)];
tests++;
arr[0, 0] = await GetVal(4);
if (arr[0, await (GetVal(0))] == 4)
Driver.Count++;
tests++;
arr[0, 0] += await GetVal(4);
if (arr[0, 0] == 8)
Driver.Count++;
tests++;
arr[1, 1] += await (GetVal(arr[0, 0]));
if (arr[1, 1] == 8)
Driver.Count++;
tests++;
arr[1, 1] += await (GetVal(arr[0, await GetVal(0)]));
if (arr[1, 1] == 16)
Driver.Count++;
tests++;
arr[2, await GetVal(2)]++;
if (arr[2, 2] == 1)
Driver.Count++;
}
finally
{
Driver.Result = Driver.Count - tests;
//When test complete, set the flag.
Driver.CompletedSignal.Set();
}
}
}
class Driver
{
public static int Result = -1;
public static int Count = 0;
public static AutoResetEvent CompletedSignal = new AutoResetEvent(false);
static void Main()
{
var t = new TestCase();
#pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
t.Run(6);
#pragma warning restore CS4014
CompletedSignal.WaitOne();
// 0 - success
// 1 - failed (test completed)
// -1 - failed (test incomplete - deadlock, etc)
Console.WriteLine(Driver.Result);
}
}";
var expectedOutput = @"
0
";
CompileAndVerify(source, expectedOutput);
var comp = CreateRuntimeAsyncCompilation(source);
comp.VerifyEmitDiagnostics(
// (27,26): error CS9328: Method 'TestCase.Run<T>(T)' uses a feature that is not supported by runtime async currently. Opt the method out of runtime async by attributing it with 'System.Runtime.CompilerServices.RuntimeAsyncMethodGenerationAttribute(false)'.
// arr[0, 0] += await GetVal(4);
Diagnostic(ErrorCode.ERR_UnsupportedFeatureInRuntimeAsync, "await GetVal(4)").WithArguments("TestCase.Run<T>(T)").WithLocation(27, 26),
// (32,26): error CS9328: Method 'TestCase.Run<T>(T)' uses a feature that is not supported by runtime async currently. Opt the method out of runtime async by attributing it with 'System.Runtime.CompilerServices.RuntimeAsyncMethodGenerationAttribute(false)'.
// arr[1, 1] += await (GetVal(arr[0, 0]));
Diagnostic(ErrorCode.ERR_UnsupportedFeatureInRuntimeAsync, "await (GetVal(arr[0, 0]))").WithArguments("TestCase.Run<T>(T)").WithLocation(32, 26),
// (37,26): error CS9328: Method 'TestCase.Run<T>(T)' uses a feature that is not supported by runtime async currently. Opt the method out of runtime async by attributing it with 'System.Runtime.CompilerServices.RuntimeAsyncMethodGenerationAttribute(false)'.
// arr[1, 1] += await (GetVal(arr[0, await GetVal(0)]));
Diagnostic(ErrorCode.ERR_UnsupportedFeatureInRuntimeAsync, "await (GetVal(arr[0, await GetVal(0)]))").WithArguments("TestCase.Run<T>(T)").WithLocation(37, 26)
);
// https://github.com/dotnet/roslyn/issues/79763
// var verifier = CompileAndVerify(comp, expectedOutput: CodeGenAsyncTests.ExpectedOutput(expectedOutput, isRuntimeAsync: true), verify: Verification.Fails with
// {
// ILVerifyMessage = """
// [GetVal]: Unexpected type on the stack. { Offset = 0xc, Found = value 'T', Expected = ref '[System.Runtime]System.Threading.Tasks.Task`1<T0>' }
// [Run]: Return value missing on the stack. { Offset = 0x178 }
// """
// });
// verifier.VerifyDiagnostics();
// verifier.VerifyIL("TestCase.Run<T>(T)", """
// {
// // Code size 377 (0x179)
// .maxstack 5
// .locals init (int V_0, //tests
// int[,] V_1, //arr
// int V_2,
// int V_3,
// int[,] V_4,
// int V_5)
// IL_0000: ldc.i4.0
// IL_0001: stloc.0
// .try
// {
// IL_0002: ldarg.0
// IL_0003: ldc.i4.4
// IL_0004: call "System.Threading.Tasks.Task<int> TestCase.GetVal<int>(int)"
// IL_0009: call "int System.Runtime.CompilerServices.AsyncHelpers.Await<int>(System.Threading.Tasks.Task<int>)"
// IL_000e: ldarg.0
// IL_000f: ldc.i4.4
// IL_0010: call "System.Threading.Tasks.Task<int> TestCase.GetVal<int>(int)"
// IL_0015: call "int System.Runtime.CompilerServices.AsyncHelpers.Await<int>(System.Threading.Tasks.Task<int>)"
// IL_001a: stloc.2
// IL_001b: ldloc.2
// IL_001c: newobj "int[*,*]..ctor"
// IL_0021: stloc.1
// IL_0022: ldloc.0
// IL_0023: ldc.i4.1
// IL_0024: add
// IL_0025: stloc.0
// IL_0026: ldloc.1
// IL_0027: ldarg.0
// IL_0028: ldc.i4.4
// IL_0029: call "System.Threading.Tasks.Task<int> TestCase.GetVal<int>(int)"
// IL_002e: call "int System.Runtime.CompilerServices.AsyncHelpers.Await<int>(System.Threading.Tasks.Task<int>)"
// IL_0033: stloc.2
// IL_0034: ldc.i4.0
// IL_0035: ldc.i4.0
// IL_0036: ldloc.2
// IL_0037: call "int[*,*].Set"
// IL_003c: ldloc.1
// IL_003d: ldarg.0
// IL_003e: ldc.i4.0
// IL_003f: call "System.Threading.Tasks.Task<int> TestCase.GetVal<int>(int)"
// IL_0044: call "int System.Runtime.CompilerServices.AsyncHelpers.Await<int>(System.Threading.Tasks.Task<int>)"
// IL_0049: stloc.2
// IL_004a: ldc.i4.0
// IL_004b: ldloc.2
// IL_004c: call "int[*,*].Get"
// IL_0051: ldc.i4.4
// IL_0052: bne.un.s IL_0060
// IL_0054: ldsfld "int Driver.Count"
// IL_0059: ldc.i4.1
// IL_005a: add
// IL_005b: stsfld "int Driver.Count"
// IL_0060: ldloc.0
// IL_0061: ldc.i4.1
// IL_0062: add
// IL_0063: stloc.0
// IL_0064: ldloc.1
// IL_0065: ldc.i4.0
// IL_0066: ldc.i4.0
// IL_0067: call "int[*,*].Address"
// IL_006c: dup
// IL_006d: ldind.i4
// IL_006e: stloc.2
// IL_006f: ldarg.0
// IL_0070: ldc.i4.4
// IL_0071: call "System.Threading.Tasks.Task<int> TestCase.GetVal<int>(int)"
// IL_0076: call "int System.Runtime.CompilerServices.AsyncHelpers.Await<int>(System.Threading.Tasks.Task<int>)"
// IL_007b: stloc.3
// IL_007c: ldloc.2
// IL_007d: ldloc.3
// IL_007e: add
// IL_007f: stind.i4
// IL_0080: ldloc.1
// IL_0081: ldc.i4.0
// IL_0082: ldc.i4.0
// IL_0083: call "int[*,*].Get"
// IL_0088: ldc.i4.8
// IL_0089: bne.un.s IL_0097
// IL_008b: ldsfld "int Driver.Count"
// IL_0090: ldc.i4.1
// IL_0091: add
// IL_0092: stsfld "int Driver.Count"
// IL_0097: ldloc.0
// IL_0098: ldc.i4.1
// IL_0099: add
// IL_009a: stloc.0
// IL_009b: ldloc.1
// IL_009c: ldc.i4.1
// IL_009d: ldc.i4.1
// IL_009e: call "int[*,*].Address"
// IL_00a3: dup
// IL_00a4: ldind.i4
// IL_00a5: stloc.3
// IL_00a6: ldarg.0
// IL_00a7: ldloc.1
// IL_00a8: ldc.i4.0
// IL_00a9: ldc.i4.0
// IL_00aa: call "int[*,*].Get"
// IL_00af: call "System.Threading.Tasks.Task<int> TestCase.GetVal<int>(int)"
// IL_00b4: call "int System.Runtime.CompilerServices.AsyncHelpers.Await<int>(System.Threading.Tasks.Task<int>)"
// IL_00b9: stloc.2
// IL_00ba: ldloc.3
// IL_00bb: ldloc.2
// IL_00bc: add
// IL_00bd: stind.i4
// IL_00be: ldloc.1
// IL_00bf: ldc.i4.1
// IL_00c0: ldc.i4.1
// IL_00c1: call "int[*,*].Get"
// IL_00c6: ldc.i4.8
// IL_00c7: bne.un.s IL_00d5
// IL_00c9: ldsfld "int Driver.Count"
// IL_00ce: ldc.i4.1
// IL_00cf: add
// IL_00d0: stsfld "int Driver.Count"
// IL_00d5: ldloc.0
// IL_00d6: ldc.i4.1
// IL_00d7: add
// IL_00d8: stloc.0
// IL_00d9: ldloc.1
// IL_00da: ldc.i4.1
// IL_00db: ldc.i4.1
// IL_00dc: call "int[*,*].Address"
// IL_00e1: dup
// IL_00e2: ldind.i4
// IL_00e3: stloc.2
// IL_00e4: ldloc.1
// IL_00e5: stloc.s V_4
// IL_00e7: ldarg.0
// IL_00e8: ldc.i4.0
// IL_00e9: call "System.Threading.Tasks.Task<int> TestCase.GetVal<int>(int)"
// IL_00ee: call "int System.Runtime.CompilerServices.AsyncHelpers.Await<int>(System.Threading.Tasks.Task<int>)"
// IL_00f3: stloc.s V_5
// IL_00f5: ldarg.0
// IL_00f6: ldloc.s V_4
// IL_00f8: ldc.i4.0
// IL_00f9: ldloc.s V_5
// IL_00fb: call "int[*,*].Get"
// IL_0100: call "System.Threading.Tasks.Task<int> TestCase.GetVal<int>(int)"
// IL_0105: call "int System.Runtime.CompilerServices.AsyncHelpers.Await<int>(System.Threading.Tasks.Task<int>)"
// IL_010a: stloc.3
// IL_010b: ldloc.2
// IL_010c: ldloc.3
// IL_010d: add
// IL_010e: stind.i4
// IL_010f: ldloc.1
// IL_0110: ldc.i4.1
// IL_0111: ldc.i4.1
// IL_0112: call "int[*,*].Get"
// IL_0117: ldc.i4.s 16
// IL_0119: bne.un.s IL_0127
// IL_011b: ldsfld "int Driver.Count"
// IL_0120: ldc.i4.1
// IL_0121: add
// IL_0122: stsfld "int Driver.Count"
// IL_0127: ldloc.0
// IL_0128: ldc.i4.1
// IL_0129: add
// IL_012a: stloc.0
// IL_012b: ldloc.1
// IL_012c: ldarg.0
// IL_012d: ldc.i4.2
// IL_012e: call "System.Threading.Tasks.Task<int> TestCase.GetVal<int>(int)"
// IL_0133: call "int System.Runtime.CompilerServices.AsyncHelpers.Await<int>(System.Threading.Tasks.Task<int>)"
// IL_0138: stloc.3
// IL_0139: ldc.i4.2
// IL_013a: ldloc.3
// IL_013b: call "int[*,*].Address"
// IL_0140: dup
// IL_0141: ldind.i4
// IL_0142: stloc.2
// IL_0143: ldloc.2
// IL_0144: ldc.i4.1
// IL_0145: add
// IL_0146: stind.i4
// IL_0147: ldloc.1
// IL_0148: ldc.i4.2
// IL_0149: ldc.i4.2
// IL_014a: call "int[*,*].Get"
// IL_014f: ldc.i4.1
// IL_0150: bne.un.s IL_015e
// IL_0152: ldsfld "int Driver.Count"
// IL_0157: ldc.i4.1
// IL_0158: add
// IL_0159: stsfld "int Driver.Count"
// IL_015e: leave.s IL_0178
// }
// finally
// {
// IL_0160: ldsfld "int Driver.Count"
// IL_0165: ldloc.0
// IL_0166: sub
// IL_0167: stsfld "int Driver.Result"
// IL_016c: ldsfld "System.Threading.AutoResetEvent Driver.CompletedSignal"
// IL_0171: callvirt "bool System.Threading.EventWaitHandle.Set()"
// IL_0176: pop
// IL_0177: endfinally
// }
// IL_0178: ret
// }
// """);
}
[Fact]
public void SpillArray04()
{
var source = @"
using System.Threading;
using System.Threading.Tasks;
struct MyStruct<T>
{
T t { get; set; }
public T this[T index]
{
get
{
return t;
}
set
{
t = value;
}
}
}
struct TestCase
{
public async void Run()
{
try
{
MyStruct<int> ms = new MyStruct<int>();
var x = ms[index: await Goo()];
}
finally
{
Driver.CompletedSignal.Set();
}
}
public async Task<int> Goo()
{
await Task.Delay(1);
return 1;
}
}
class Driver
{
public static AutoResetEvent CompletedSignal = new AutoResetEvent(false);
static void Main()
{
var t = new TestCase();
t.Run();
CompletedSignal.WaitOne();
}
}";
CompileAndVerify(source, "");
}
[Fact]
public void SpillArray04WithTaskAndRuntimeAsync()
{
var source = @"
using System.Threading;
using System.Threading.Tasks;
struct MyStruct<T>
{
T t { get; set; }
public T this[T index]
{
get
{
return t;
}
set
{
t = value;
}
}
}
struct TestCase
{
public async Task Run()
{
try
{
MyStruct<int> ms = new MyStruct<int>();
var x = ms[index: await Goo()];
}
finally
{
Driver.CompletedSignal.Set();
}
}
public async Task<int> Goo()
{
await Task.Delay(1);
return 1;
}
}
class Driver
{
public static AutoResetEvent CompletedSignal = new AutoResetEvent(false);
static void Main()
{
var t = new TestCase();
#pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
t.Run();
#pragma warning restore CS4014
CompletedSignal.WaitOne();
}
}";
CompileAndVerify(source, "");
var comp = CreateRuntimeAsyncCompilation(source);
comp.VerifyEmitDiagnostics(
// (23,23): error CS9328: Method 'TestCase.Run()' uses a feature that is not supported by runtime async currently. Opt the method out of runtime async by attributing it with 'System.Runtime.CompilerServices.RuntimeAsyncMethodGenerationAttribute(false)'.
// public async Task Run()
Diagnostic(ErrorCode.ERR_UnsupportedFeatureInRuntimeAsync, "Run").WithArguments("TestCase.Run()").WithLocation(23, 23)
);
// https://github.com/dotnet/roslyn/issues/79763
// var verifier = CompileAndVerify(comp, expectedOutput: CodeGenAsyncTests.ExpectedOutput("", isRuntimeAsync: true), verify: Verification.Fails with
// {
// ILVerifyMessage = """
// [Run]: Return value missing on the stack. { Offset = 0x2b }
// [Goo]: Unexpected type on the stack. { Offset = 0xc, Found = Int32, Expected = ref '[System.Runtime]System.Threading.Tasks.Task`1<int32>' }
// """
// });
// verifier.VerifyDiagnostics();
// verifier.VerifyIL("TestCase.Run()", """
// {
// // Code size 44 (0x2c)
// .maxstack 2
// .locals init (MyStruct<int> V_0, //ms
// int V_1)
// .try
// {
// IL_0000: ldloca.s V_0
// IL_0002: initobj "MyStruct<int>"
// IL_0008: ldarg.0
// IL_0009: call "System.Threading.Tasks.Task<int> TestCase.Goo()"
// IL_000e: call "int System.Runtime.CompilerServices.AsyncHelpers.Await<int>(System.Threading.Tasks.Task<int>)"
// IL_0013: stloc.1
// IL_0014: ldloca.s V_0
// IL_0016: ldloc.1
// IL_0017: call "int MyStruct<int>.this[int].get"
// IL_001c: pop
// IL_001d: leave.s IL_002b
// }
// finally
// {
// IL_001f: ldsfld "System.Threading.AutoResetEvent Driver.CompletedSignal"
// IL_0024: callvirt "bool System.Threading.EventWaitHandle.Set()"
// IL_0029: pop
// IL_002a: endfinally
// }
// IL_002b: ret
// }
// """);
}
[Fact]
public void SpillArrayAssign()
{
var source = @"
using System;
using System.Threading.Tasks;
class TestCase
{
static int[] arr = new int[4];
static async Task Run()
{
arr[0] = await Task.Factory.StartNew(() => 42);
}
static void Main()
{
Task task = Run();
task.Wait();
Console.WriteLine(arr[0]);
}
}";
var expectedOutput = @"
42
";
CompileAndVerify(source, expectedOutput);
var comp = CreateRuntimeAsyncCompilation(source);
var verifier = CompileAndVerify(comp, expectedOutput: CodeGenAsyncTests.ExpectedOutput(expectedOutput, isRuntimeAsync: true), verify: Verification.Fails with
{
ILVerifyMessage = """
[Run]: Return value missing on the stack. { Offset = 0x37 }
"""
});
verifier.VerifyDiagnostics();
verifier.VerifyIL("TestCase.Run()", """
{
// Code size 56 (0x38)
.maxstack 4
.locals init (int V_0)
IL_0000: ldsfld "int[] TestCase.arr"
IL_0005: call "System.Threading.Tasks.TaskFactory System.Threading.Tasks.Task.Factory.get"
IL_000a: ldsfld "System.Func<int> TestCase.<>c.<>9__1_0"
IL_000f: dup
IL_0010: brtrue.s IL_0029
IL_0012: pop
IL_0013: ldsfld "TestCase.<>c TestCase.<>c.<>9"
IL_0018: ldftn "int TestCase.<>c.<Run>b__1_0()"
IL_001e: newobj "System.Func<int>..ctor(object, System.IntPtr)"
IL_0023: dup
IL_0024: stsfld "System.Func<int> TestCase.<>c.<>9__1_0"
IL_0029: callvirt "System.Threading.Tasks.Task<int> System.Threading.Tasks.TaskFactory.StartNew<int>(System.Func<int>)"
IL_002e: call "int System.Runtime.CompilerServices.AsyncHelpers.Await<int>(System.Threading.Tasks.Task<int>)"
IL_0033: stloc.0
IL_0034: ldc.i4.0
IL_0035: ldloc.0
IL_0036: stelem.i4
IL_0037: ret
}
""");
}
[WorkItem(19609, "https://github.com/dotnet/roslyn/issues/19609")]
[Fact]
public void SpillArrayAssign2()
{
var source = @"
#pragma warning disable CS1998 // Async method lacks 'await' operators and will run synchronously
using System.Threading.Tasks;
class Program
{
static int[] array = new int[5];
static void Main(string[] args)
{
try
{
System.Console.WriteLine(""test not awaited"");
TestNotAwaited().Wait();
}
catch
{
System.Console.WriteLine(""exception thrown"");
}
System.Console.WriteLine();
try
{
System.Console.WriteLine(""test awaited"");
TestAwaited().Wait();
}
catch
{
System.Console.WriteLine(""exception thrown"");
}
}
static async Task TestNotAwaited()
{
array[6] = Moo1();
}
static async Task TestAwaited()
{
array[6] = await Moo();
}
static int Moo1()
{
System.Console.WriteLine(""hello"");
return 123;
}
static async Task<int> Moo()
{
System.Console.WriteLine(""hello"");
return 123;
}
}";
var expectedOutput = @"
test not awaited
hello
exception thrown
test awaited
hello
exception thrown
";
CompileAndVerify(source, expectedOutput: expectedOutput);
var comp = CreateRuntimeAsyncCompilation(source);
var verifier = CompileAndVerify(comp, expectedOutput: CodeGenAsyncTests.ExpectedOutput(expectedOutput, isRuntimeAsync: true), verify: Verification.Fails with
{
ILVerifyMessage = """
[TestNotAwaited]: Return value missing on the stack. { Offset = 0xc }
[TestAwaited]: Return value missing on the stack. { Offset = 0x13 }
[Moo]: Unexpected type on the stack. { Offset = 0xc, Found = Int32, Expected = ref '[System.Runtime]System.Threading.Tasks.Task`1<int32>' }
"""
});
verifier.VerifyDiagnostics();
verifier.VerifyIL("Program.TestNotAwaited()", """
{
// Code size 13 (0xd)
.maxstack 3
IL_0000: ldsfld "int[] Program.array"
IL_0005: ldc.i4.6
IL_0006: call "int Program.Moo1()"
IL_000b: stelem.i4
IL_000c: ret
}
""");
verifier.VerifyIL("Program.TestAwaited()", """
{
// Code size 20 (0x14)
.maxstack 3
.locals init (int V_0)
IL_0000: ldsfld "int[] Program.array"
IL_0005: call "System.Threading.Tasks.Task<int> Program.Moo()"
IL_000a: call "int System.Runtime.CompilerServices.AsyncHelpers.Await<int>(System.Threading.Tasks.Task<int>)"
IL_000f: stloc.0
IL_0010: ldc.i4.6
IL_0011: ldloc.0
IL_0012: stelem.i4
IL_0013: ret
}
""");
}
[Fact]
public void SpillArrayLocal()
{
var source = @"
using System;
using System.Threading;
using System.Threading.Tasks;
class TestCase
{
public async Task<T> GetVal<T>(T t)
{
await Task.Delay(1);
return t;
}
public async void Run<T>(T t) where T : struct
{
int[] arr = new int[2] { -1, 42 };
int tests = 0;
try
{
tests++;
int t1 = arr[await GetVal(1)];
if (t1 == 42)
Driver.Count++;
}
finally
{
Driver.Result = Driver.Count - tests;
//When test complete, set the flag.
Driver.CompletedSignal.Set();
}
}
}
class Driver
{
public static int Result = -1;
public static int Count = 0;
public static AutoResetEvent CompletedSignal = new AutoResetEvent(false);
static void Main()
{
var t = new TestCase();
t.Run(6);
CompletedSignal.WaitOne();
// 0 - success
// 1 - failed (test completed)
// -1 - failed (test incomplete - deadlock, etc)
Console.WriteLine(Driver.Result);
}
}";
var expectedOutput = @"
0
";
CompileAndVerify(source, expectedOutput);
}
[Fact]
public void SpillArrayLocalWithTaskAndRuntimeAsync()
{
var source = @"
using System;
using System.Threading;
using System.Threading.Tasks;
class TestCase
{
public async Task<T> GetVal<T>(T t)
{
await Task.Delay(1);
return t;
}
public async Task Run<T>(T t) where T : struct
{
int[] arr = new int[2] { -1, 42 };
int tests = 0;
try
{
tests++;
int t1 = arr[await GetVal(1)];
if (t1 == 42)
Driver.Count++;
}
finally
{
Driver.Result = Driver.Count - tests;
//When test complete, set the flag.
Driver.CompletedSignal.Set();
}
}
}
class Driver
{
public static int Result = -1;
public static int Count = 0;
public static AutoResetEvent CompletedSignal = new AutoResetEvent(false);
static void Main()
{
var t = new TestCase();
#pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
t.Run(6);
#pragma warning restore CS4014
CompletedSignal.WaitOne();
// 0 - success
// 1 - failed (test completed)
// -1 - failed (test incomplete - deadlock, etc)
Console.WriteLine(Driver.Result);
}
}";
var expectedOutput = @"
0
";
CompileAndVerify(source, expectedOutput);
var comp = CreateRuntimeAsyncCompilation(source);
var verifier = CompileAndVerify(comp, expectedOutput: CodeGenAsyncTests.ExpectedOutput(expectedOutput, isRuntimeAsync: true), verify: Verification.Fails with
{
ILVerifyMessage = """
[GetVal]: Unexpected type on the stack. { Offset = 0xc, Found = value 'T', Expected = ref '[System.Runtime]System.Threading.Tasks.Task`1<T0>' }
[Run]: Return value missing on the stack. { Offset = 0x50 }
"""
});
verifier.VerifyDiagnostics();
verifier.VerifyIL("TestCase.Run<T>(T)", """
{
// Code size 81 (0x51)
.maxstack 4
.locals init (int[] V_0, //arr
int V_1, //tests
int V_2)
IL_0000: ldc.i4.2
IL_0001: newarr "int"
IL_0006: dup
IL_0007: ldc.i4.0
IL_0008: ldc.i4.m1
IL_0009: stelem.i4
IL_000a: dup
IL_000b: ldc.i4.1
IL_000c: ldc.i4.s 42
IL_000e: stelem.i4
IL_000f: stloc.0
IL_0010: ldc.i4.0
IL_0011: stloc.1
.try
{
IL_0012: ldloc.1
IL_0013: ldc.i4.1
IL_0014: add
IL_0015: stloc.1
IL_0016: ldloc.0
IL_0017: ldarg.0
IL_0018: ldc.i4.1
IL_0019: call "System.Threading.Tasks.Task<int> TestCase.GetVal<int>(int)"
IL_001e: call "int System.Runtime.CompilerServices.AsyncHelpers.Await<int>(System.Threading.Tasks.Task<int>)"
IL_0023: stloc.2
IL_0024: ldloc.2
IL_0025: ldelem.i4
IL_0026: ldc.i4.s 42
IL_0028: bne.un.s IL_0036
IL_002a: ldsfld "int Driver.Count"
IL_002f: ldc.i4.1
IL_0030: add
IL_0031: stsfld "int Driver.Count"
IL_0036: leave.s IL_0050
}
finally
{
IL_0038: ldsfld "int Driver.Count"
IL_003d: ldloc.1
IL_003e: sub
IL_003f: stsfld "int Driver.Result"
IL_0044: ldsfld "System.Threading.AutoResetEvent Driver.CompletedSignal"
IL_0049: callvirt "bool System.Threading.EventWaitHandle.Set()"
IL_004e: pop
IL_004f: endfinally
}
IL_0050: ret
}
""");
}
[Fact]
public void SpillArrayCompoundAssignmentLValue()
{
var source = @"
using System;
using System.Threading.Tasks;
class Driver
{
static int[] arr;
static async Task Run()
{
arr = new int[1];
arr[0] += await Task.Factory.StartNew(() => 42);
}
static void Main()
{
Run().Wait();
Console.WriteLine(arr[0]);
}
}";
var expectedOutput = @"
42
";
CompileAndVerify(source, expectedOutput);
var comp = CreateRuntimeAsyncCompilation(source);
comp.VerifyEmitDiagnostics(
// (12,19): error CS9328: Method 'Driver.Run()' uses a feature that is not supported by runtime async currently. Opt the method out of runtime async by attributing it with 'System.Runtime.CompilerServices.RuntimeAsyncMethodGenerationAttribute(false)'.
// arr[0] += await Task.Factory.StartNew(() => 42);
Diagnostic(ErrorCode.ERR_UnsupportedFeatureInRuntimeAsync, "await Task.Factory.StartNew(() => 42)").WithArguments("Driver.Run()").WithLocation(12, 19)
);
// https://github.com/dotnet/roslyn/issues/79763
// var verifier = CompileAndVerify(comp, expectedOutput: CodeGenAsyncTests.ExpectedOutput(expectedOutput, isRuntimeAsync: true), verify: Verification.Fails with
// {
// ILVerifyMessage = """
// [Run]: Return value missing on the stack. { Offset = 0x4c }
// """
// });
// verifier.VerifyDiagnostics();
// verifier.VerifyIL("Driver.Run()", """
// {
// // Code size 77 (0x4d)
// .maxstack 4
// .locals init (int V_0,
// int V_1)
// IL_0000: ldc.i4.1
// IL_0001: newarr "int"
// IL_0006: stsfld "int[] Driver.arr"
// IL_000b: ldsfld "int[] Driver.arr"
// IL_0010: ldc.i4.0
// IL_0011: ldelema "int"
// IL_0016: dup
// IL_0017: ldind.i4
// IL_0018: stloc.0
// IL_0019: call "System.Threading.Tasks.TaskFactory System.Threading.Tasks.Task.Factory.get"
// IL_001e: ldsfld "System.Func<int> Driver.<>c.<>9__1_0"
// IL_0023: dup
// IL_0024: brtrue.s IL_003d
// IL_0026: pop
// IL_0027: ldsfld "Driver.<>c Driver.<>c.<>9"
// IL_002c: ldftn "int Driver.<>c.<Run>b__1_0()"
// IL_0032: newobj "System.Func<int>..ctor(object, System.IntPtr)"
// IL_0037: dup
// IL_0038: stsfld "System.Func<int> Driver.<>c.<>9__1_0"
// IL_003d: callvirt "System.Threading.Tasks.Task<int> System.Threading.Tasks.TaskFactory.StartNew<int>(System.Func<int>)"
// IL_0042: call "int System.Runtime.CompilerServices.AsyncHelpers.Await<int>(System.Threading.Tasks.Task<int>)"
// IL_0047: stloc.1
// IL_0048: ldloc.0
// IL_0049: ldloc.1
// IL_004a: add
// IL_004b: stind.i4
// IL_004c: ret
// }
// """);
}
[Fact]
public void SpillArrayCompoundAssignmentLValueAwait()
{
var source = @"
using System;
using System.Threading.Tasks;
class Driver
{
static int[] arr;
static async Task Run()
{
arr = new int[1];
arr[await Task.Factory.StartNew(() => 0)] += await Task.Factory.StartNew(() => 42);
}
static void Main()
{
Run().Wait();
Console.WriteLine(arr[0]);
}
}";
var expectedOutput = @"
42
";
CompileAndVerify(source, expectedOutput);
var comp = CreateRuntimeAsyncCompilation(source);
comp.VerifyEmitDiagnostics(
// (12,13): error CS9328: Method 'Driver.Run()' uses a feature that is not supported by runtime async currently. Opt the method out of runtime async by attributing it with 'System.Runtime.CompilerServices.RuntimeAsyncMethodGenerationAttribute(false)'.
// arr[await Task.Factory.StartNew(() => 0)] += await Task.Factory.StartNew(() => 42);
Diagnostic(ErrorCode.ERR_UnsupportedFeatureInRuntimeAsync, "await Task.Factory.StartNew(() => 0)").WithArguments("Driver.Run()").WithLocation(12, 13)
);
// https://github.com/dotnet/roslyn/issues/79763
// var verifier = CompileAndVerify(comp, expectedOutput: CodeGenAsyncTests.ExpectedOutput(expectedOutput, isRuntimeAsync: true), verify: Verification.Fails with
// {
// ILVerifyMessage = """
// [Run]: Return value missing on the stack. { Offset = 0x7b }
// """
// });
// verifier.VerifyDiagnostics();
// verifier.VerifyIL("Driver.Run()", """
// {
// // Code size 124 (0x7c)
// .maxstack 4
// .locals init (int V_0,
// int V_1,
// int V_2)
// IL_0000: ldc.i4.1
// IL_0001: newarr "int"
// IL_0006: stsfld "int[] Driver.arr"
// IL_000b: ldsfld "int[] Driver.arr"
// IL_0010: call "System.Threading.Tasks.TaskFactory System.Threading.Tasks.Task.Factory.get"
// IL_0015: ldsfld "System.Func<int> Driver.<>c.<>9__1_0"
// IL_001a: dup
// IL_001b: brtrue.s IL_0034
// IL_001d: pop
// IL_001e: ldsfld "Driver.<>c Driver.<>c.<>9"
// IL_0023: ldftn "int Driver.<>c.<Run>b__1_0()"
// IL_0029: newobj "System.Func<int>..ctor(object, System.IntPtr)"
// IL_002e: dup
// IL_002f: stsfld "System.Func<int> Driver.<>c.<>9__1_0"
// IL_0034: callvirt "System.Threading.Tasks.Task<int> System.Threading.Tasks.TaskFactory.StartNew<int>(System.Func<int>)"
// IL_0039: call "int System.Runtime.CompilerServices.AsyncHelpers.Await<int>(System.Threading.Tasks.Task<int>)"
// IL_003e: stloc.0
// IL_003f: ldloc.0
// IL_0040: ldelema "int"
// IL_0045: dup
// IL_0046: ldind.i4
// IL_0047: stloc.1
// IL_0048: call "System.Threading.Tasks.TaskFactory System.Threading.Tasks.Task.Factory.get"
// IL_004d: ldsfld "System.Func<int> Driver.<>c.<>9__1_1"
// IL_0052: dup
// IL_0053: brtrue.s IL_006c
// IL_0055: pop
// IL_0056: ldsfld "Driver.<>c Driver.<>c.<>9"
// IL_005b: ldftn "int Driver.<>c.<Run>b__1_1()"
// IL_0061: newobj "System.Func<int>..ctor(object, System.IntPtr)"
// IL_0066: dup
// IL_0067: stsfld "System.Func<int> Driver.<>c.<>9__1_1"
// IL_006c: callvirt "System.Threading.Tasks.Task<int> System.Threading.Tasks.TaskFactory.StartNew<int>(System.Func<int>)"
// IL_0071: call "int System.Runtime.CompilerServices.AsyncHelpers.Await<int>(System.Threading.Tasks.Task<int>)"
// IL_0076: stloc.2
// IL_0077: ldloc.1
// IL_0078: ldloc.2
// IL_0079: add
// IL_007a: stind.i4
// IL_007b: ret
// }
// """);
}
[Fact]
public void SpillArrayCompoundAssignmentLValueAwait2()
{
var source = @"
using System;
using System.Threading.Tasks;
struct S1
{
public int x;
}
struct S2
{
public S1 s1;
}
class Driver
{
static async Task<int> Run()
{
var arr = new S2[1];
arr[await Task.Factory.StartNew(() => 0)].s1.x += await Task.Factory.StartNew(() => 42);
return arr[await Task.Factory.StartNew(() => 0)].s1.x;
}
static void Main()
{
var t = Run();
t.Wait();
Console.WriteLine(t.Result);
}
}";
var expectedOutput = @"
42
";
CompileAndVerify(source, expectedOutput);
var comp = CreateRuntimeAsyncCompilation(source);
comp.VerifyEmitDiagnostics(
// (20,13): error CS9328: Method 'Driver.Run()' uses a feature that is not supported by runtime async currently. Opt the method out of runtime async by attributing it with 'System.Runtime.CompilerServices.RuntimeAsyncMethodGenerationAttribute(false)'.
// arr[await Task.Factory.StartNew(() => 0)].s1.x += await Task.Factory.StartNew(() => 42);
Diagnostic(ErrorCode.ERR_UnsupportedFeatureInRuntimeAsync, "await Task.Factory.StartNew(() => 0)").WithArguments("Driver.Run()").WithLocation(20, 13),
// (20,13): error CS9328: Method 'Driver.Run()' uses a feature that is not supported by runtime async currently. Opt the method out of runtime async by attributing it with 'System.Runtime.CompilerServices.RuntimeAsyncMethodGenerationAttribute(false)'.
// arr[await Task.Factory.StartNew(() => 0)].s1.x += await Task.Factory.StartNew(() => 42);
Diagnostic(ErrorCode.ERR_UnsupportedFeatureInRuntimeAsync, "await Task.Factory.StartNew(() => 0)").WithArguments("Driver.Run()").WithLocation(20, 13)
);
// https://github.com/dotnet/roslyn/issues/79763 - support struct lifting
// var verifier = CompileAndVerify(comp, expectedOutput: CodeGenAsyncTests.ExpectedOutput(expectedOutput, isRuntimeAsync: true), verify: Verification.Fails with
// {
// ILVerifyMessage = """
// [Run]: Unexpected type on the stack. { Offset = 0xbb, Found = Int32, Expected = ref '[System.Runtime]System.Threading.Tasks.Task`1<int32>' }
// """
// });
// verifier.VerifyDiagnostics();
// verifier.VerifyIL("Driver.Run()", """
// {
// // Code size 188 (0xbc)
// .maxstack 5
// .locals init (int V_0,
// int V_1,
// int V_2)
// IL_0000: ldc.i4.1
// IL_0001: newarr "S2"
// IL_0006: dup
// IL_0007: call "System.Threading.Tasks.TaskFactory System.Threading.Tasks.Task.Factory.get"
// IL_000c: ldsfld "System.Func<int> Driver.<>c.<>9__0_0"
// IL_0011: dup
// IL_0012: brtrue.s IL_002b
// IL_0014: pop
// IL_0015: ldsfld "Driver.<>c Driver.<>c.<>9"
// IL_001a: ldftn "int Driver.<>c.<Run>b__0_0()"
// IL_0020: newobj "System.Func<int>..ctor(object, System.IntPtr)"
// IL_0025: dup
// IL_0026: stsfld "System.Func<int> Driver.<>c.<>9__0_0"
// IL_002b: callvirt "System.Threading.Tasks.Task<int> System.Threading.Tasks.TaskFactory.StartNew<int>(System.Func<int>)"
// IL_0030: call "int System.Runtime.CompilerServices.AsyncHelpers.Await<int>(System.Threading.Tasks.Task<int>)"
// IL_0035: stloc.0
// IL_0036: ldloc.0
// IL_0037: ldelema "S2"
// IL_003c: ldflda "S1 S2.s1"
// IL_0041: ldflda "int S1.x"
// IL_0046: dup
// IL_0047: ldind.i4
// IL_0048: stloc.1
// IL_0049: call "System.Threading.Tasks.TaskFactory System.Threading.Tasks.Task.Factory.get"
// IL_004e: ldsfld "System.Func<int> Driver.<>c.<>9__0_1"
// IL_0053: dup
// IL_0054: brtrue.s IL_006d
// IL_0056: pop
// IL_0057: ldsfld "Driver.<>c Driver.<>c.<>9"
// IL_005c: ldftn "int Driver.<>c.<Run>b__0_1()"
// IL_0062: newobj "System.Func<int>..ctor(object, System.IntPtr)"
// IL_0067: dup
// IL_0068: stsfld "System.Func<int> Driver.<>c.<>9__0_1"
// IL_006d: callvirt "System.Threading.Tasks.Task<int> System.Threading.Tasks.TaskFactory.StartNew<int>(System.Func<int>)"
// IL_0072: call "int System.Runtime.CompilerServices.AsyncHelpers.Await<int>(System.Threading.Tasks.Task<int>)"
// IL_0077: stloc.2
// IL_0078: ldloc.1
// IL_0079: ldloc.2
// IL_007a: add
// IL_007b: stind.i4
// IL_007c: call "System.Threading.Tasks.TaskFactory System.Threading.Tasks.Task.Factory.get"
// IL_0081: ldsfld "System.Func<int> Driver.<>c.<>9__0_2"
// IL_0086: dup
// IL_0087: brtrue.s IL_00a0
// IL_0089: pop
// IL_008a: ldsfld "Driver.<>c Driver.<>c.<>9"
// IL_008f: ldftn "int Driver.<>c.<Run>b__0_2()"
// IL_0095: newobj "System.Func<int>..ctor(object, System.IntPtr)"
// IL_009a: dup
// IL_009b: stsfld "System.Func<int> Driver.<>c.<>9__0_2"
// IL_00a0: callvirt "System.Threading.Tasks.Task<int> System.Threading.Tasks.TaskFactory.StartNew<int>(System.Func<int>)"
// IL_00a5: call "int System.Runtime.CompilerServices.AsyncHelpers.Await<int>(System.Threading.Tasks.Task<int>)"
// IL_00aa: stloc.2
// IL_00ab: ldloc.2
// IL_00ac: ldelema "S2"
// IL_00b1: ldflda "S1 S2.s1"
// IL_00b6: ldfld "int S1.x"
// IL_00bb: ret
// }
// """);
}
[Fact]
public void DoubleSpillArrayCompoundAssignment()
{
var source = @"
using System;
using System.Threading.Tasks;
struct S1
{
public int x;
}
struct S2
{
public S1 s1;
}
class Driver
{
static async Task<int> Run()
{
var arr = new S2[1];
arr[await Task.Factory.StartNew(() => 0)].s1.x += (arr[await Task.Factory.StartNew(() => 0)].s1.x += await Task.Factory.StartNew(() => 42));
return arr[await Task.Factory.StartNew(() => 0)].s1.x;
}
static void Main()
{
var t = Run();
t.Wait();
Console.WriteLine(t.Result);
}
}";
var expectedOutput = @"
42
";
CompileAndVerify(source, expectedOutput);
var comp = CreateRuntimeAsyncCompilation(source);
comp.VerifyEmitDiagnostics(
// (20,64): error CS9328: Method 'Driver.Run()' uses a feature that is not supported by runtime async currently. Opt the method out of runtime async by attributing it with 'System.Runtime.CompilerServices.RuntimeAsyncMethodGenerationAttribute(false)'.
// arr[await Task.Factory.StartNew(() => 0)].s1.x += (arr[await Task.Factory.StartNew(() => 0)].s1.x += await Task.Factory.StartNew(() => 42));
Diagnostic(ErrorCode.ERR_UnsupportedFeatureInRuntimeAsync, "await Task.Factory.StartNew(() => 0)").WithArguments("Driver.Run()").WithLocation(20, 64),
// (20,64): error CS9328: Method 'Driver.Run()' uses a feature that is not supported by runtime async currently. Opt the method out of runtime async by attributing it with 'System.Runtime.CompilerServices.RuntimeAsyncMethodGenerationAttribute(false)'.
// arr[await Task.Factory.StartNew(() => 0)].s1.x += (arr[await Task.Factory.StartNew(() => 0)].s1.x += await Task.Factory.StartNew(() => 42));
Diagnostic(ErrorCode.ERR_UnsupportedFeatureInRuntimeAsync, "await Task.Factory.StartNew(() => 0)").WithArguments("Driver.Run()").WithLocation(20, 64),
// (20,13): error CS9328: Method 'Driver.Run()' uses a feature that is not supported by runtime async currently. Opt the method out of runtime async by attributing it with 'System.Runtime.CompilerServices.RuntimeAsyncMethodGenerationAttribute(false)'.
// arr[await Task.Factory.StartNew(() => 0)].s1.x += (arr[await Task.Factory.StartNew(() => 0)].s1.x += await Task.Factory.StartNew(() => 42));
Diagnostic(ErrorCode.ERR_UnsupportedFeatureInRuntimeAsync, "await Task.Factory.StartNew(() => 0)").WithArguments("Driver.Run()").WithLocation(20, 13),
// (20,13): error CS9328: Method 'Driver.Run()' uses a feature that is not supported by runtime async currently. Opt the method out of runtime async by attributing it with 'System.Runtime.CompilerServices.RuntimeAsyncMethodGenerationAttribute(false)'.
// arr[await Task.Factory.StartNew(() => 0)].s1.x += (arr[await Task.Factory.StartNew(() => 0)].s1.x += await Task.Factory.StartNew(() => 42));
Diagnostic(ErrorCode.ERR_UnsupportedFeatureInRuntimeAsync, "await Task.Factory.StartNew(() => 0)").WithArguments("Driver.Run()").WithLocation(20, 13)
);
// https://github.com/dotnet/roslyn/issues/79763
// var verifier = CompileAndVerify(comp, expectedOutput: CodeGenAsyncTests.ExpectedOutput(expectedOutput, isRuntimeAsync: true), verify: Verification.Fails with
// {
// ILVerifyMessage = """
// [Run]: Unexpected type on the stack. { Offset = 0x113, Found = Int32, Expected = ref '[System.Runtime]System.Threading.Tasks.Task`1<int32>' }
// """
// });
// verifier.VerifyDiagnostics();
// verifier.VerifyIL("Driver.Run()", """
// {
// // Code size 276 (0x114)
// .maxstack 6
// .locals init (int V_0,
// int& V_1,
// int V_2,
// int V_3,
// int& V_4,
// int V_5,
// int V_6,
// int V_7)
// IL_0000: ldc.i4.1
// IL_0001: newarr "S2"
// IL_0006: dup
// IL_0007: call "System.Threading.Tasks.TaskFactory System.Threading.Tasks.Task.Factory.get"
// IL_000c: ldsfld "System.Func<int> Driver.<>c.<>9__0_0"
// IL_0011: dup
// IL_0012: brtrue.s IL_002b
// IL_0014: pop
// IL_0015: ldsfld "Driver.<>c Driver.<>c.<>9"
// IL_001a: ldftn "int Driver.<>c.<Run>b__0_0()"
// IL_0020: newobj "System.Func<int>..ctor(object, System.IntPtr)"
// IL_0025: dup
// IL_0026: stsfld "System.Func<int> Driver.<>c.<>9__0_0"
// IL_002b: callvirt "System.Threading.Tasks.Task<int> System.Threading.Tasks.TaskFactory.StartNew<int>(System.Func<int>)"
// IL_0030: call "int System.Runtime.CompilerServices.AsyncHelpers.Await<int>(System.Threading.Tasks.Task<int>)"
// IL_0035: stloc.0
// IL_0036: ldloc.0
// IL_0037: ldelema "S2"
// IL_003c: ldflda "S1 S2.s1"
// IL_0041: ldflda "int S1.x"
// IL_0046: stloc.1
// IL_0047: ldloc.1
// IL_0048: ldind.i4
// IL_0049: stloc.2
// IL_004a: dup
// IL_004b: call "System.Threading.Tasks.TaskFactory System.Threading.Tasks.Task.Factory.get"
// IL_0050: ldsfld "System.Func<int> Driver.<>c.<>9__0_1"
// IL_0055: dup
// IL_0056: brtrue.s IL_006f
// IL_0058: pop
// IL_0059: ldsfld "Driver.<>c Driver.<>c.<>9"
// IL_005e: ldftn "int Driver.<>c.<Run>b__0_1()"
// IL_0064: newobj "System.Func<int>..ctor(object, System.IntPtr)"
// IL_0069: dup
// IL_006a: stsfld "System.Func<int> Driver.<>c.<>9__0_1"
// IL_006f: callvirt "System.Threading.Tasks.Task<int> System.Threading.Tasks.TaskFactory.StartNew<int>(System.Func<int>)"
// IL_0074: call "int System.Runtime.CompilerServices.AsyncHelpers.Await<int>(System.Threading.Tasks.Task<int>)"
// IL_0079: stloc.3
// IL_007a: ldloc.3
// IL_007b: ldelema "S2"
// IL_0080: ldflda "S1 S2.s1"
// IL_0085: ldflda "int S1.x"
// IL_008a: stloc.s V_4
// IL_008c: ldloc.s V_4
// IL_008e: ldind.i4
// IL_008f: stloc.s V_5
// IL_0091: call "System.Threading.Tasks.TaskFactory System.Threading.Tasks.Task.Factory.get"
// IL_0096: ldsfld "System.Func<int> Driver.<>c.<>9__0_2"
// IL_009b: dup
// IL_009c: brtrue.s IL_00b5
// IL_009e: pop
// IL_009f: ldsfld "Driver.<>c Driver.<>c.<>9"
// IL_00a4: ldftn "int Driver.<>c.<Run>b__0_2()"
// IL_00aa: newobj "System.Func<int>..ctor(object, System.IntPtr)"
// IL_00af: dup
// IL_00b0: stsfld "System.Func<int> Driver.<>c.<>9__0_2"
// IL_00b5: callvirt "System.Threading.Tasks.Task<int> System.Threading.Tasks.TaskFactory.StartNew<int>(System.Func<int>)"
// IL_00ba: call "int System.Runtime.CompilerServices.AsyncHelpers.Await<int>(System.Threading.Tasks.Task<int>)"
// IL_00bf: stloc.s V_6
// IL_00c1: ldloc.1
// IL_00c2: ldloc.2
// IL_00c3: ldloc.s V_4
// IL_00c5: ldloc.s V_5
// IL_00c7: ldloc.s V_6
// IL_00c9: add
// IL_00ca: dup
// IL_00cb: stloc.s V_7
// IL_00cd: stind.i4
// IL_00ce: ldloc.s V_7
// IL_00d0: add
// IL_00d1: stind.i4
// IL_00d2: call "System.Threading.Tasks.TaskFactory System.Threading.Tasks.Task.Factory.get"
// IL_00d7: ldsfld "System.Func<int> Driver.<>c.<>9__0_3"
// IL_00dc: dup
// IL_00dd: brtrue.s IL_00f6
// IL_00df: pop
// IL_00e0: ldsfld "Driver.<>c Driver.<>c.<>9"
// IL_00e5: ldftn "int Driver.<>c.<Run>b__0_3()"
// IL_00eb: newobj "System.Func<int>..ctor(object, System.IntPtr)"
// IL_00f0: dup
// IL_00f1: stsfld "System.Func<int> Driver.<>c.<>9__0_3"
// IL_00f6: callvirt "System.Threading.Tasks.Task<int> System.Threading.Tasks.TaskFactory.StartNew<int>(System.Func<int>)"
// IL_00fb: call "int System.Runtime.CompilerServices.AsyncHelpers.Await<int>(System.Threading.Tasks.Task<int>)"
// IL_0100: stloc.s V_6
// IL_0102: ldloc.s V_6
// IL_0104: ldelema "S2"
// IL_0109: ldflda "S1 S2.s1"
// IL_010e: ldfld "int S1.x"
// IL_0113: ret
// }
// """);
}
[Fact]
public void SpillArrayInitializers1()
{
var source = @"
using System;
using System.Threading;
using System.Threading.Tasks;
class TestCase
{
public async Task<T> GetVal<T>(T t)
{
await Task.Delay(1);
return t;
}
public async void Run()
{
int tests = 0;
try
{
//jagged array
tests++;
int[][] arr1 = new[]
{
new []{await GetVal(2),await GetVal(3)},
new []{4,await GetVal(5),await GetVal(6)}
};
if (arr1[0][1] == 3 && arr1[1][1] == 5 && arr1[1][2] == 6)
Driver.Count++;
tests++;
int[][] arr2 = new[]
{
new []{await GetVal(2),await GetVal(3)},
await Goo()
};
if (arr2[0][1] == 3 && arr2[1][1] == 2)
Driver.Count++;
}
finally
{
Driver.Result = Driver.Count - tests;
//When test complete, set the flag.
Driver.CompletedSignal.Set();
}
}
public async Task<int[]> Goo()
{
await Task.Delay(1);
return new int[] { 1, 2, 3 };
}
}
class Driver
{
public static int Result = -1;
public static int Count = 0;
public static AutoResetEvent CompletedSignal = new AutoResetEvent(false);
static void Main()
{
var t = new TestCase();
t.Run();
CompletedSignal.WaitOne();
// 0 - success
// 1 - failed (test completed)
// -1 - failed (test incomplete - deadlock, etc)
Console.WriteLine(Driver.Result);
}
}";
var expectedOutput = @"
0
";
CompileAndVerify(source, expectedOutput);
}
[Fact]
public void SpillArrayInitializers1WithTaskAndRuntimeAsync()
{
var source = @"
using System;
using System.Threading;
using System.Threading.Tasks;
class TestCase
{
public async Task<T> GetVal<T>(T t)
{
await Task.Delay(1);
return t;
}
public async Task Run()
{
int tests = 0;
try
{
//jagged array
tests++;
int[][] arr1 = new[]
{
new []{await GetVal(2),await GetVal(3)},
new []{4,await GetVal(5),await GetVal(6)}
};
if (arr1[0][1] == 3 && arr1[1][1] == 5 && arr1[1][2] == 6)
Driver.Count++;
tests++;
int[][] arr2 = new[]
{
new []{await GetVal(2),await GetVal(3)},
await Goo()
};
if (arr2[0][1] == 3 && arr2[1][1] == 2)
Driver.Count++;
}
finally
{
Driver.Result = Driver.Count - tests;
//When test complete, set the flag.
Driver.CompletedSignal.Set();
}
}
public async Task<int[]> Goo()
{
await Task.Delay(1);
return new int[] { 1, 2, 3 };
}
}
class Driver
{
public static int Result = -1;
public static int Count = 0;
public static AutoResetEvent CompletedSignal = new AutoResetEvent(false);
static void Main()
{
var t = new TestCase();
#pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
t.Run();
#pragma warning restore CS4014
CompletedSignal.WaitOne();
// 0 - success
// 1 - failed (test completed)
// -1 - failed (test incomplete - deadlock, etc)
Console.WriteLine(Driver.Result);
}
}";
var expectedOutput = @"
0
";
CompileAndVerify(source, expectedOutput);
var comp = CreateRuntimeAsyncCompilation(source);
var verifier = CompileAndVerify(comp, expectedOutput: CodeGenAsyncTests.ExpectedOutput(expectedOutput, isRuntimeAsync: true), verify: Verification.Fails with
{
ILVerifyMessage = """
[GetVal]: Unexpected type on the stack. { Offset = 0xc, Found = value 'T', Expected = ref '[System.Runtime]System.Threading.Tasks.Task`1<T0>' }
[Run]: Return value missing on the stack. { Offset = 0x11b }
[Goo]: Unexpected type on the stack. { Offset = 0x1c, Found = ref 'int32[]', Expected = ref '[System.Runtime]System.Threading.Tasks.Task`1<int32[]>' }
"""
});
verifier.VerifyDiagnostics();
verifier.VerifyIL("TestCase.Run()", """
{
// Code size 284 (0x11c)
.maxstack 7
.locals init (int V_0, //tests
int[][] V_1, //arr1
int[][] V_2, //arr2
int V_3,
int V_4,
int[] V_5,
int V_6,
int V_7,
int[] V_8)
IL_0000: ldc.i4.0
IL_0001: stloc.0
.try
{
IL_0002: ldloc.0
IL_0003: ldc.i4.1
IL_0004: add
IL_0005: stloc.0
IL_0006: ldarg.0
IL_0007: ldc.i4.2
IL_0008: call "System.Threading.Tasks.Task<int> TestCase.GetVal<int>(int)"
IL_000d: call "int System.Runtime.CompilerServices.AsyncHelpers.Await<int>(System.Threading.Tasks.Task<int>)"
IL_0012: stloc.3
IL_0013: ldarg.0
IL_0014: ldc.i4.3
IL_0015: call "System.Threading.Tasks.Task<int> TestCase.GetVal<int>(int)"
IL_001a: call "int System.Runtime.CompilerServices.AsyncHelpers.Await<int>(System.Threading.Tasks.Task<int>)"
IL_001f: stloc.s V_4
IL_0021: ldc.i4.2
IL_0022: newarr "int"
IL_0027: dup
IL_0028: ldc.i4.0
IL_0029: ldloc.3
IL_002a: stelem.i4
IL_002b: dup
IL_002c: ldc.i4.1
IL_002d: ldloc.s V_4
IL_002f: stelem.i4
IL_0030: stloc.s V_5
IL_0032: ldarg.0
IL_0033: ldc.i4.5
IL_0034: call "System.Threading.Tasks.Task<int> TestCase.GetVal<int>(int)"
IL_0039: call "int System.Runtime.CompilerServices.AsyncHelpers.Await<int>(System.Threading.Tasks.Task<int>)"
IL_003e: stloc.s V_6
IL_0040: ldarg.0
IL_0041: ldc.i4.6
IL_0042: call "System.Threading.Tasks.Task<int> TestCase.GetVal<int>(int)"
IL_0047: call "int System.Runtime.CompilerServices.AsyncHelpers.Await<int>(System.Threading.Tasks.Task<int>)"
IL_004c: stloc.s V_7
IL_004e: ldc.i4.2
IL_004f: newarr "int[]"
IL_0054: dup
IL_0055: ldc.i4.0
IL_0056: ldloc.s V_5
IL_0058: stelem.ref
IL_0059: dup
IL_005a: ldc.i4.1
IL_005b: ldc.i4.3
IL_005c: newarr "int"
IL_0061: dup
IL_0062: ldc.i4.0
IL_0063: ldc.i4.4
IL_0064: stelem.i4
IL_0065: dup
IL_0066: ldc.i4.1
IL_0067: ldloc.s V_6
IL_0069: stelem.i4
IL_006a: dup
IL_006b: ldc.i4.2
IL_006c: ldloc.s V_7
IL_006e: stelem.i4
IL_006f: stelem.ref
IL_0070: stloc.1
IL_0071: ldloc.1
IL_0072: ldc.i4.0
IL_0073: ldelem.ref
IL_0074: ldc.i4.1
IL_0075: ldelem.i4
IL_0076: ldc.i4.3
IL_0077: bne.un.s IL_0095
IL_0079: ldloc.1
IL_007a: ldc.i4.1
IL_007b: ldelem.ref
IL_007c: ldc.i4.1
IL_007d: ldelem.i4
IL_007e: ldc.i4.5
IL_007f: bne.un.s IL_0095
IL_0081: ldloc.1
IL_0082: ldc.i4.1
IL_0083: ldelem.ref
IL_0084: ldc.i4.2
IL_0085: ldelem.i4
IL_0086: ldc.i4.6
IL_0087: bne.un.s IL_0095
IL_0089: ldsfld "int Driver.Count"
IL_008e: ldc.i4.1
IL_008f: add
IL_0090: stsfld "int Driver.Count"
IL_0095: ldloc.0
IL_0096: ldc.i4.1
IL_0097: add
IL_0098: stloc.0
IL_0099: ldarg.0
IL_009a: ldc.i4.2
IL_009b: call "System.Threading.Tasks.Task<int> TestCase.GetVal<int>(int)"
IL_00a0: call "int System.Runtime.CompilerServices.AsyncHelpers.Await<int>(System.Threading.Tasks.Task<int>)"
IL_00a5: stloc.s V_7
IL_00a7: ldarg.0
IL_00a8: ldc.i4.3
IL_00a9: call "System.Threading.Tasks.Task<int> TestCase.GetVal<int>(int)"
IL_00ae: call "int System.Runtime.CompilerServices.AsyncHelpers.Await<int>(System.Threading.Tasks.Task<int>)"
IL_00b3: stloc.s V_6
IL_00b5: ldc.i4.2
IL_00b6: newarr "int"
IL_00bb: dup
IL_00bc: ldc.i4.0
IL_00bd: ldloc.s V_7
IL_00bf: stelem.i4
IL_00c0: dup
IL_00c1: ldc.i4.1
IL_00c2: ldloc.s V_6
IL_00c4: stelem.i4
IL_00c5: stloc.s V_5
IL_00c7: ldarg.0
IL_00c8: call "System.Threading.Tasks.Task<int[]> TestCase.Goo()"
IL_00cd: call "int[] System.Runtime.CompilerServices.AsyncHelpers.Await<int[]>(System.Threading.Tasks.Task<int[]>)"
IL_00d2: stloc.s V_8
IL_00d4: ldc.i4.2
IL_00d5: newarr "int[]"
IL_00da: dup
IL_00db: ldc.i4.0
IL_00dc: ldloc.s V_5
IL_00de: stelem.ref
IL_00df: dup
IL_00e0: ldc.i4.1
IL_00e1: ldloc.s V_8
IL_00e3: stelem.ref
IL_00e4: stloc.2
IL_00e5: ldloc.2
IL_00e6: ldc.i4.0
IL_00e7: ldelem.ref
IL_00e8: ldc.i4.1
IL_00e9: ldelem.i4
IL_00ea: ldc.i4.3
IL_00eb: bne.un.s IL_0101
IL_00ed: ldloc.2
IL_00ee: ldc.i4.1
IL_00ef: ldelem.ref
IL_00f0: ldc.i4.1
IL_00f1: ldelem.i4
IL_00f2: ldc.i4.2
IL_00f3: bne.un.s IL_0101
IL_00f5: ldsfld "int Driver.Count"
IL_00fa: ldc.i4.1
IL_00fb: add
IL_00fc: stsfld "int Driver.Count"
IL_0101: leave.s IL_011b
}
finally
{
IL_0103: ldsfld "int Driver.Count"
IL_0108: ldloc.0
IL_0109: sub
IL_010a: stsfld "int Driver.Result"
IL_010f: ldsfld "System.Threading.AutoResetEvent Driver.CompletedSignal"
IL_0114: callvirt "bool System.Threading.EventWaitHandle.Set()"
IL_0119: pop
IL_011a: endfinally
}
IL_011b: ret
}
""");
}
[Fact]
public void SpillArrayInitializers2()
{
var source = @"
using System;
using System.Threading;
using System.Threading.Tasks;
class TestCase
{
public async Task<T> GetVal<T>(T t)
{
await Task.Delay(1);
return t;
}
public async void Run()
{
int tests = 0;
try
{
//jagged array
tests++;
int[,] arr1 =
{
{await GetVal(2),await GetVal(3)},
{await GetVal(5),await GetVal(6)}
};
if (arr1[0, 1] == 3 && arr1[1, 0] == 5 && arr1[1, 1] == 6)
Driver.Count++;
tests++;
int[,] arr2 =
{
{await GetVal(2),3},
{4,await GetVal(5)}
};
if (arr2[0, 1] == 3 && arr2[1, 1] == 5)
Driver.Count++;
}
finally
{
Driver.Result = Driver.Count - tests;
//When test complete, set the flag.
Driver.CompletedSignal.Set();
}
}
}
class Driver
{
public static int Result = -1;
public static int Count = 0;
public static AutoResetEvent CompletedSignal = new AutoResetEvent(false);
static void Main()
{
var t = new TestCase();
t.Run();
CompletedSignal.WaitOne();
Console.WriteLine(Driver.Result);
}
}";
var expectedOutput = @"
0
";
CompileAndVerify(source, expectedOutput);
}
[Fact]
public void SpillArrayInitializers2WithTaskAndRuntimeAsync()
{
var source = @"
using System;
using System.Threading;
using System.Threading.Tasks;
class TestCase
{
public async Task<T> GetVal<T>(T t)
{
await Task.Delay(1);
return t;
}
public async Task Run()
{
int tests = 0;
try
{
//jagged array
tests++;
int[,] arr1 =
{
{await GetVal(2),await GetVal(3)},
{await GetVal(5),await GetVal(6)}
};
if (arr1[0, 1] == 3 && arr1[1, 0] == 5 && arr1[1, 1] == 6)
Driver.Count++;
tests++;
int[,] arr2 =
{
{await GetVal(2),3},
{4,await GetVal(5)}
};
if (arr2[0, 1] == 3 && arr2[1, 1] == 5)
Driver.Count++;
}
finally
{
Driver.Result = Driver.Count - tests;
//When test complete, set the flag.
Driver.CompletedSignal.Set();
}
}
}
class Driver
{
public static int Result = -1;
public static int Count = 0;
public static AutoResetEvent CompletedSignal = new AutoResetEvent(false);
static void Main()
{
var t = new TestCase();
#pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
t.Run();
#pragma warning restore CS4014
CompletedSignal.WaitOne();
Console.WriteLine(Driver.Result);
}
}";
var expectedOutput = @"
0
";
CompileAndVerify(source, expectedOutput);
var comp = CreateRuntimeAsyncCompilation(source);
var verifier = CompileAndVerify(comp, expectedOutput: CodeGenAsyncTests.ExpectedOutput(expectedOutput, isRuntimeAsync: true), verify: Verification.Fails with
{
ILVerifyMessage = """
[GetVal]: Unexpected type on the stack. { Offset = 0xc, Found = value 'T', Expected = ref '[System.Runtime]System.Threading.Tasks.Task`1<T0>' }
[Run]: Return value missing on the stack. { Offset = 0x123 }
"""
});
verifier.VerifyDiagnostics();
verifier.VerifyIL("TestCase.Run()", """
{
// Code size 292 (0x124)
.maxstack 5
.locals init (int V_0, //tests
int[,] V_1, //arr1
int[,] V_2, //arr2
int V_3,
int V_4,
int V_5,
int V_6)
IL_0000: ldc.i4.0
IL_0001: stloc.0
.try
{
IL_0002: ldloc.0
IL_0003: ldc.i4.1
IL_0004: add
IL_0005: stloc.0
IL_0006: ldarg.0
IL_0007: ldc.i4.2
IL_0008: call "System.Threading.Tasks.Task<int> TestCase.GetVal<int>(int)"
IL_000d: call "int System.Runtime.CompilerServices.AsyncHelpers.Await<int>(System.Threading.Tasks.Task<int>)"
IL_0012: stloc.3
IL_0013: ldarg.0
IL_0014: ldc.i4.3
IL_0015: call "System.Threading.Tasks.Task<int> TestCase.GetVal<int>(int)"
IL_001a: call "int System.Runtime.CompilerServices.AsyncHelpers.Await<int>(System.Threading.Tasks.Task<int>)"
IL_001f: stloc.s V_4
IL_0021: ldarg.0
IL_0022: ldc.i4.5
IL_0023: call "System.Threading.Tasks.Task<int> TestCase.GetVal<int>(int)"
IL_0028: call "int System.Runtime.CompilerServices.AsyncHelpers.Await<int>(System.Threading.Tasks.Task<int>)"
IL_002d: stloc.s V_5
IL_002f: ldarg.0
IL_0030: ldc.i4.6
IL_0031: call "System.Threading.Tasks.Task<int> TestCase.GetVal<int>(int)"
IL_0036: call "int System.Runtime.CompilerServices.AsyncHelpers.Await<int>(System.Threading.Tasks.Task<int>)"
IL_003b: stloc.s V_6
IL_003d: ldc.i4.2
IL_003e: ldc.i4.2
IL_003f: newobj "int[*,*]..ctor"
IL_0044: dup
IL_0045: ldc.i4.0
IL_0046: ldc.i4.0
IL_0047: ldloc.3
IL_0048: call "int[*,*].Set"
IL_004d: dup
IL_004e: ldc.i4.0
IL_004f: ldc.i4.1
IL_0050: ldloc.s V_4
IL_0052: call "int[*,*].Set"
IL_0057: dup
IL_0058: ldc.i4.1
IL_0059: ldc.i4.0
IL_005a: ldloc.s V_5
IL_005c: call "int[*,*].Set"
IL_0061: dup
IL_0062: ldc.i4.1
IL_0063: ldc.i4.1
IL_0064: ldloc.s V_6
IL_0066: call "int[*,*].Set"
IL_006b: stloc.1
IL_006c: ldloc.1
IL_006d: ldc.i4.0
IL_006e: ldc.i4.1
IL_006f: call "int[*,*].Get"
IL_0074: ldc.i4.3
IL_0075: bne.un.s IL_0099
IL_0077: ldloc.1
IL_0078: ldc.i4.1
IL_0079: ldc.i4.0
IL_007a: call "int[*,*].Get"
IL_007f: ldc.i4.5
IL_0080: bne.un.s IL_0099
IL_0082: ldloc.1
IL_0083: ldc.i4.1
IL_0084: ldc.i4.1
IL_0085: call "int[*,*].Get"
IL_008a: ldc.i4.6
IL_008b: bne.un.s IL_0099
IL_008d: ldsfld "int Driver.Count"
IL_0092: ldc.i4.1
IL_0093: add
IL_0094: stsfld "int Driver.Count"
IL_0099: ldloc.0
IL_009a: ldc.i4.1
IL_009b: add
IL_009c: stloc.0
IL_009d: ldarg.0
IL_009e: ldc.i4.2
IL_009f: call "System.Threading.Tasks.Task<int> TestCase.GetVal<int>(int)"
IL_00a4: call "int System.Runtime.CompilerServices.AsyncHelpers.Await<int>(System.Threading.Tasks.Task<int>)"
IL_00a9: stloc.s V_6
IL_00ab: ldarg.0
IL_00ac: ldc.i4.5
IL_00ad: call "System.Threading.Tasks.Task<int> TestCase.GetVal<int>(int)"
IL_00b2: call "int System.Runtime.CompilerServices.AsyncHelpers.Await<int>(System.Threading.Tasks.Task<int>)"
IL_00b7: stloc.s V_5
IL_00b9: ldc.i4.2
IL_00ba: ldc.i4.2
IL_00bb: newobj "int[*,*]..ctor"
IL_00c0: dup
IL_00c1: ldc.i4.0
IL_00c2: ldc.i4.0
IL_00c3: ldloc.s V_6
IL_00c5: call "int[*,*].Set"
IL_00ca: dup
IL_00cb: ldc.i4.0
IL_00cc: ldc.i4.1
IL_00cd: ldc.i4.3
IL_00ce: call "int[*,*].Set"
IL_00d3: dup
IL_00d4: ldc.i4.1
IL_00d5: ldc.i4.0
IL_00d6: ldc.i4.4
IL_00d7: call "int[*,*].Set"
IL_00dc: dup
IL_00dd: ldc.i4.1
IL_00de: ldc.i4.1
IL_00df: ldloc.s V_5
IL_00e1: call "int[*,*].Set"
IL_00e6: stloc.2
IL_00e7: ldloc.2
IL_00e8: ldc.i4.0
IL_00e9: ldc.i4.1
IL_00ea: call "int[*,*].Get"
IL_00ef: ldc.i4.3
IL_00f0: bne.un.s IL_0109
IL_00f2: ldloc.2
IL_00f3: ldc.i4.1
IL_00f4: ldc.i4.1
IL_00f5: call "int[*,*].Get"
IL_00fa: ldc.i4.5
IL_00fb: bne.un.s IL_0109
IL_00fd: ldsfld "int Driver.Count"
IL_0102: ldc.i4.1
IL_0103: add
IL_0104: stsfld "int Driver.Count"
IL_0109: leave.s IL_0123
}
finally
{
IL_010b: ldsfld "int Driver.Count"
IL_0110: ldloc.0
IL_0111: sub
IL_0112: stsfld "int Driver.Result"
IL_0117: ldsfld "System.Threading.AutoResetEvent Driver.CompletedSignal"
IL_011c: callvirt "bool System.Threading.EventWaitHandle.Set()"
IL_0121: pop
IL_0122: endfinally
}
IL_0123: ret
}
""");
}
[Fact]
public void SpillArrayInitializers3()
{
var source = @"
using System;
using System.Threading;
using System.Threading.Tasks;
class TestCase
{
public async Task<T> GetVal<T>(T t)
{
await Task.Delay(1);
return t;
}
public async void Run()
{
int tests = 0;
try
{
//jagged array
tests++;
int[][] arr1 = new[]
{
new []{await GetVal(2),await Task.Run<int>(async()=>{await Task.Delay(1);return 3;})},
new []{await GetVal(5),4,await Task.Run<int>(async()=>{await Task.Delay(1);return 6;})}
};
if (arr1[0][1] == 3 && arr1[1][1] == 4 && arr1[1][2] == 6)
Driver.Count++;
tests++;
dynamic arr2 = new[]
{
new []{await GetVal(2),3},
await Goo()
};
if (arr2[0][1] == 3 && arr2[1][1] == 2)
Driver.Count++;
}
finally
{
Driver.Result = Driver.Count - tests;
//When test complete, set the flag.
Driver.CompletedSignal.Set();
}
}
public async Task<int[]> Goo()
{
await Task.Delay(1);
return new int[] { 1, 2, 3 };
}
}
class Driver
{
public static int Result = -1;
public static int Count = 0;
public static AutoResetEvent CompletedSignal = new AutoResetEvent(false);
static void Main()
{
var t = new TestCase();
t.Run();
CompletedSignal.WaitOne();
// 0 - success
// 1 - failed (test completed)
// -1 - failed (test incomplete - deadlock, etc)
Console.WriteLine(Driver.Result);
}
}";
var expectedOutput = @"
0
";
CompileAndVerify(source, expectedOutput, references: new[] { CSharpRef });
}
[Fact]
public void SpillArrayInitializers3WithTaskAndRuntimeAsync()
{
var source = @"
using System;
using System.Threading;
using System.Threading.Tasks;
class TestCase
{
public async Task<T> GetVal<T>(T t)
{
await Task.Delay(1);
return t;
}
public async Task Run()
{
int tests = 0;
try
{
//jagged array
tests++;
int[][] arr1 = new[]
{
new []{await GetVal(2),await Task.Run<int>(async()=>{await Task.Delay(1);return 3;})},
new []{await GetVal(5),4,await Task.Run<int>(async()=>{await Task.Delay(1);return 6;})}
};
if (arr1[0][1] == 3 && arr1[1][1] == 4 && arr1[1][2] == 6)
Driver.Count++;
tests++;
dynamic arr2 = new[]
{
new []{await GetVal(2),3},
await Goo()
};
if (arr2[0][1] == 3 && arr2[1][1] == 2)
Driver.Count++;
}
finally
{
Driver.Result = Driver.Count - tests;
//When test complete, set the flag.
Driver.CompletedSignal.Set();
}
}
public async Task<int[]> Goo()
{
await Task.Delay(1);
return new int[] { 1, 2, 3 };
}
}
class Driver
{
public static int Result = -1;
public static int Count = 0;
public static AutoResetEvent CompletedSignal = new AutoResetEvent(false);
static void Main()
{
var t = new TestCase();
t.Run();
CompletedSignal.WaitOne();
// 0 - success
// 1 - failed (test completed)
// -1 - failed (test incomplete - deadlock, etc)
Console.WriteLine(Driver.Result);
}
}";
var expectedOutput = @"
0
";
CompileAndVerify(source, expectedOutput, references: new[] { CSharpRef });
var comp = CreateRuntimeAsyncCompilation(source);
var verifier = CompileAndVerify(comp, expectedOutput: CodeGenAsyncTests.ExpectedOutput(expectedOutput, isRuntimeAsync: true), verify: Verification.Fails with
{
ILVerifyMessage = """
[GetVal]: Unexpected type on the stack. { Offset = 0xc, Found = value 'T', Expected = ref '[System.Runtime]System.Threading.Tasks.Task`1<T0>' }
[Run]: Return value missing on the stack. { Offset = 0x40b }
[Goo]: Unexpected type on the stack. { Offset = 0x1c, Found = ref 'int32[]', Expected = ref '[System.Runtime]System.Threading.Tasks.Task`1<int32[]>' }
[<Run>b__1_0]: Unexpected type on the stack. { Offset = 0xc, Found = Int32, Expected = ref '[System.Runtime]System.Threading.Tasks.Task`1<int32>' }
[<Run>b__1_1]: Unexpected type on the stack. { Offset = 0xc, Found = Int32, Expected = ref '[System.Runtime]System.Threading.Tasks.Task`1<int32>' }
"""
});
verifier.VerifyDiagnostics(
// (61,9): warning CS4014: Because this call is not awaited, execution of the current method continues before the call is completed. Consider applying the 'await' operator to the result of the call.
// t.Run();
Diagnostic(ErrorCode.WRN_UnobservedAwaitableExpression, "t.Run()").WithLocation(61, 9)
);
}
[Fact]
public void SpillNestedExpressionInArrayInitializer()
{
var source = @"
using System;
using System.Threading.Tasks;
class Test
{
public static async Task<int[,]> Run()
{
return new int[,] {
{1, 2, 21 + (await Task.Factory.StartNew(() => 21)) },
};
}
public static void Main()
{
var t = Run();
t.Wait();
foreach (var xs in t.Result)
{
Console.WriteLine(xs);
}
}
}";
var expectedOutput = @"
1
2
42
";
CompileAndVerify(source, expectedOutput);
var comp = CreateRuntimeAsyncCompilation(source);
var verifier = CompileAndVerify(comp, expectedOutput: CodeGenAsyncTests.ExpectedOutput(expectedOutput, isRuntimeAsync: true), verify: Verification.Fails with
{
ILVerifyMessage = """
[Run]: Unexpected type on the stack. { Offset = 0x54, Found = ref 'int32[,]', Expected = ref '[System.Runtime]System.Threading.Tasks.Task`1<int32[,]>' }
"""
});
verifier.VerifyDiagnostics();
verifier.VerifyIL("Test.Run()", """
{
// Code size 85 (0x55)
.maxstack 6
.locals init (int V_0)
IL_0000: call "System.Threading.Tasks.TaskFactory System.Threading.Tasks.Task.Factory.get"
IL_0005: ldsfld "System.Func<int> Test.<>c.<>9__0_0"
IL_000a: dup
IL_000b: brtrue.s IL_0024
IL_000d: pop
IL_000e: ldsfld "Test.<>c Test.<>c.<>9"
IL_0013: ldftn "int Test.<>c.<Run>b__0_0()"
IL_0019: newobj "System.Func<int>..ctor(object, System.IntPtr)"
IL_001e: dup
IL_001f: stsfld "System.Func<int> Test.<>c.<>9__0_0"
IL_0024: callvirt "System.Threading.Tasks.Task<int> System.Threading.Tasks.TaskFactory.StartNew<int>(System.Func<int>)"
IL_0029: call "int System.Runtime.CompilerServices.AsyncHelpers.Await<int>(System.Threading.Tasks.Task<int>)"
IL_002e: stloc.0
IL_002f: ldc.i4.1
IL_0030: ldc.i4.3
IL_0031: newobj "int[*,*]..ctor"
IL_0036: dup
IL_0037: ldc.i4.0
IL_0038: ldc.i4.0
IL_0039: ldc.i4.1
IL_003a: call "int[*,*].Set"
IL_003f: dup
IL_0040: ldc.i4.0
IL_0041: ldc.i4.1
IL_0042: ldc.i4.2
IL_0043: call "int[*,*].Set"
IL_0048: dup
IL_0049: ldc.i4.0
IL_004a: ldc.i4.2
IL_004b: ldc.i4.s 21
IL_004d: ldloc.0
IL_004e: add
IL_004f: call "int[*,*].Set"
IL_0054: ret
}
""");
}
[Fact]
public void SpillConditionalAccess()
{
var source = @"
using System;
using System.Threading.Tasks;
class Test
{
class C1
{
public int M(int x)
{
return x;
}
}
public static int Get(int x)
{
Console.WriteLine(""> "" + x);
return x;
}
public static async Task<int> F(int x)
{
return await Task.Factory.StartNew(() => x);
}
public static async Task<int?> G()
{
var c = new C1();
return c?.M(await F(Get(42)));
}
public static void Main()
{
var t = G();
System.Console.WriteLine(t.Result);
}
}";
var expectedOutput = @"
> 42
42";
CompileAndVerify(source, expectedOutput);
var comp = CreateRuntimeAsyncCompilation(source);
var verifier = CompileAndVerify(comp, expectedOutput: CodeGenAsyncTests.ExpectedOutput(expectedOutput, isRuntimeAsync: true), verify: Verification.Fails with
{
ILVerifyMessage = """
[F]: Unexpected type on the stack. { Offset = 0x28, Found = Int32, Expected = ref '[System.Runtime]System.Threading.Tasks.Task`1<int32>' }
[G]: Unexpected type on the stack. { Offset = 0x34, Found = value '[System.Runtime]System.Nullable`1<int32>', Expected = ref '[System.Runtime]System.Threading.Tasks.Task`1<System.Nullable`1<int32>>' }
"""
});
verifier.VerifyDiagnostics();
verifier.VerifyIL("Test.G()", """
{
// Code size 53 (0x35)
.maxstack 3
.locals init (Test.C1 V_0,
int? V_1,
int V_2)
IL_0000: newobj "Test.C1..ctor()"
IL_0005: stloc.0
IL_0006: ldloc.0
IL_0007: brfalse.s IL_002b
IL_0009: ldc.i4.s 42
IL_000b: call "int Test.Get(int)"
IL_0010: call "System.Threading.Tasks.Task<int> Test.F(int)"
IL_0015: call "int System.Runtime.CompilerServices.AsyncHelpers.Await<int>(System.Threading.Tasks.Task<int>)"
IL_001a: stloc.2
IL_001b: ldloca.s V_1
IL_001d: ldloc.0
IL_001e: ldloc.2
IL_001f: callvirt "int Test.C1.M(int)"
IL_0024: call "int?..ctor(int)"
IL_0029: br.s IL_0033
IL_002b: ldloca.s V_1
IL_002d: initobj "int?"
IL_0033: ldloc.1
IL_0034: ret
}
""");
}
[Fact]
public void AssignToAwait()
{
var source = @"
using System;
using System.Threading.Tasks;
class S
{
public int x = -1;
}
class Test
{
static S _s = new S();
public static async Task<S> GetS()
{
return await Task.Factory.StartNew(() => _s);
}
public static async Task Run()
{
(await GetS()).x = 42;
Console.WriteLine(_s.x);
}
}
class Driver
{
static void Main()
{
Test.Run().Wait();
}
}";
var expectedOutput = @"
42
";
CompileAndVerify(source, expectedOutput);
var comp = CreateRuntimeAsyncCompilation(source);
var verifier = CompileAndVerify(comp, expectedOutput: CodeGenAsyncTests.ExpectedOutput(expectedOutput, isRuntimeAsync: true), verify: Verification.Fails with
{
ILVerifyMessage = """
[GetS]: Unexpected type on the stack. { Offset = 0x2e, Found = ref 'S', Expected = ref '[System.Runtime]System.Threading.Tasks.Task`1<S>' }
[Run]: Return value missing on the stack. { Offset = 0x20 }
"""
});
verifier.VerifyDiagnostics();
verifier.VerifyIL("Test.Run()", """
{
// Code size 33 (0x21)
.maxstack 2
IL_0000: call "System.Threading.Tasks.Task<S> Test.GetS()"
IL_0005: call "S System.Runtime.CompilerServices.AsyncHelpers.Await<S>(System.Threading.Tasks.Task<S>)"
IL_000a: ldc.i4.s 42
IL_000c: stfld "int S.x"
IL_0011: ldsfld "S Test._s"
IL_0016: ldfld "int S.x"
IL_001b: call "void System.Console.WriteLine(int)"
IL_0020: ret
}
""");
}
[Fact]
public void AssignAwaitToAwait()
{
var source = @"
using System;
using System.Threading.Tasks;
class S
{
public int x = -1;
}
class Test
{
static S _s = new S();
public static async Task<S> GetS()
{
return await Task.Factory.StartNew(() => _s);
}
public static async Task Run()
{
(await GetS()).x = await Task.Factory.StartNew(() => 42);
Console.WriteLine(_s.x);
}
}
class Driver
{
static void Main()
{
Test.Run().Wait();
}
}";
var expectedOutput = @"
42
";
CompileAndVerify(source, expectedOutput);
var comp = CreateRuntimeAsyncCompilation(source);
var verifier = CompileAndVerify(comp, expectedOutput: CodeGenAsyncTests.ExpectedOutput(expectedOutput, isRuntimeAsync: true), verify: Verification.Fails with
{
ILVerifyMessage = """
[GetS]: Unexpected type on the stack. { Offset = 0x2e, Found = ref 'S', Expected = ref '[System.Runtime]System.Threading.Tasks.Task`1<S>' }
[Run]: Return value missing on the stack. { Offset = 0x4e }
"""
});
verifier.VerifyDiagnostics();
verifier.VerifyIL("Test.Run()", """
{
// Code size 79 (0x4f)
.maxstack 4
.locals init (int V_0)
IL_0000: call "System.Threading.Tasks.Task<S> Test.GetS()"
IL_0005: call "S System.Runtime.CompilerServices.AsyncHelpers.Await<S>(System.Threading.Tasks.Task<S>)"
IL_000a: call "System.Threading.Tasks.TaskFactory System.Threading.Tasks.Task.Factory.get"
IL_000f: ldsfld "System.Func<int> Test.<>c.<>9__2_0"
IL_0014: dup
IL_0015: brtrue.s IL_002e
IL_0017: pop
IL_0018: ldsfld "Test.<>c Test.<>c.<>9"
IL_001d: ldftn "int Test.<>c.<Run>b__2_0()"
IL_0023: newobj "System.Func<int>..ctor(object, System.IntPtr)"
IL_0028: dup
IL_0029: stsfld "System.Func<int> Test.<>c.<>9__2_0"
IL_002e: callvirt "System.Threading.Tasks.Task<int> System.Threading.Tasks.TaskFactory.StartNew<int>(System.Func<int>)"
IL_0033: call "int System.Runtime.CompilerServices.AsyncHelpers.Await<int>(System.Threading.Tasks.Task<int>)"
IL_0038: stloc.0
IL_0039: ldloc.0
IL_003a: stfld "int S.x"
IL_003f: ldsfld "S Test._s"
IL_0044: ldfld "int S.x"
IL_0049: call "void System.Console.WriteLine(int)"
IL_004e: ret
}
""");
}
[Fact]
public void SpillArglist()
{
var source = @"
using System;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
class TestCase
{
static StringBuilder sb = new StringBuilder();
public async Task Run()
{
try
{
Bar(__arglist(One(), await Two()));
if (sb.ToString() == ""OneTwo"")
Driver.Result = 0;
}
finally
{
Driver.CompleteSignal.Set();
}
}
int One()
{
sb.Append(""One"");
return 1;
}
async Task<int> Two()
{
await Task.Delay(1);
sb.Append(""Two"");
return 2;
}
void Bar(__arglist)
{
var ai = new ArgIterator(__arglist);
while (ai.GetRemainingCount() > 0)
Console.WriteLine( __refvalue(ai.GetNextArg(), int));
}
}
class Driver
{
static public AutoResetEvent CompleteSignal = new AutoResetEvent(false);
public static int Result = -1;
public static void Main()
{
TestCase tc = new TestCase();
tc.Run();
CompleteSignal.WaitOne();
Console.WriteLine(Result);
}
}";
var expectedOutput = ExecutionConditionUtil.IsDesktop ? @"
1
2
0
" : null;
CompileAndVerify(source, targetFramework: TargetFramework.NetFramework, expectedOutput: expectedOutput, verify: Verification.FailsILVerify);
var comp = CreateRuntimeAsyncCompilation(source);
comp.VerifyDiagnostics(
// (14,17): error CS9328: Method 'TestCase.Run()' uses a feature that is not supported by runtime async currently. Opt the method out of runtime async by attributing it with 'System.Runtime.CompilerServices.RuntimeAsyncMethodGenerationAttribute(false)'.
// Bar(__arglist(One(), await Two()));
Diagnostic(ErrorCode.ERR_UnsupportedFeatureInRuntimeAsync, "__arglist(One(), await Two())").WithArguments("TestCase.Run()").WithLocation(14, 17),
// (48,9): warning CS4014: Because this call is not awaited, execution of the current method continues before the call is completed. Consider applying the 'await' operator to the result of the call.
// tc.Run();
Diagnostic(ErrorCode.WRN_UnobservedAwaitableExpression, "tc.Run()").WithLocation(48, 9)
);
}
[Fact]
public void SpillObjectInitializer1()
{
var source = @"
using System;
using System.Collections;
using System.Threading;
using System.Threading.Tasks;
struct TestCase : IEnumerable
{
int X;
public async Task Run()
{
int test = 0;
int count = 0;
try
{
test++;
var x = new TestCase { X = await Bar() };
if (x.X == 1)
count++;
}
finally
{
Driver.Result = test - count;
Driver.CompleteSignal.Set();
}
}
async Task<int> Bar()
{
await Task.Delay(1);
return 1;
}
public IEnumerator GetEnumerator()
{
throw new System.NotImplementedException();
}
}
class Driver
{
static public AutoResetEvent CompleteSignal = new AutoResetEvent(false);
public static int Result = -1;
public static void Main()
{
TestCase tc = new TestCase();
#pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
tc.Run();
#pragma warning restore CS4014
CompleteSignal.WaitOne();
Console.WriteLine(Result);
}
}";
var expectedOutput = @"
0
";
CompileAndVerify(source, expectedOutput: expectedOutput);
var comp = CreateRuntimeAsyncCompilation(source);
comp.VerifyEmitDiagnostics(
// (11,23): error CS9328: Method 'TestCase.Run()' uses a feature that is not supported by runtime async currently. Opt the method out of runtime async by attributing it with 'System.Runtime.CompilerServices.RuntimeAsyncMethodGenerationAttribute(false)'.
// public async Task Run()
Diagnostic(ErrorCode.ERR_UnsupportedFeatureInRuntimeAsync, "Run").WithArguments("TestCase.Run()").WithLocation(11, 23)
);
// https://github.com/dotnet/roslyn/issues/79763
// var verifier = CompileAndVerify(comp, expectedOutput: CodeGenAsyncTests.ExpectedOutput(expectedOutput, isRuntimeAsync: true), verify: Verification.Fails with
// {
// ILVerifyMessage = """
// [Run]: Return value missing on the stack. { Offset = 0x47 }
// [Bar]: Unexpected type on the stack. { Offset = 0xc, Found = Int32, Expected = ref '[System.Runtime]System.Threading.Tasks.Task`1<int32>' }
// """
// });
// verifier.VerifyDiagnostics();
// verifier.VerifyIL("TestCase.Run()", """
// {
// // Code size 72 (0x48)
// .maxstack 2
// .locals init (int V_0, //test
// int V_1, //count
// int V_2,
// TestCase V_3)
// IL_0000: ldc.i4.0
// IL_0001: stloc.0
// IL_0002: ldc.i4.0
// IL_0003: stloc.1
// .try
// {
// IL_0004: ldloc.0
// IL_0005: ldc.i4.1
// IL_0006: add
// IL_0007: stloc.0
// IL_0008: ldloca.s V_3
// IL_000a: initobj "TestCase"
// IL_0010: ldarg.0
// IL_0011: call "System.Threading.Tasks.Task<int> TestCase.Bar()"
// IL_0016: call "int System.Runtime.CompilerServices.AsyncHelpers.Await<int>(System.Threading.Tasks.Task<int>)"
// IL_001b: stloc.2
// IL_001c: ldloca.s V_3
// IL_001e: ldloc.2
// IL_001f: stfld "int TestCase.X"
// IL_0024: ldloc.3
// IL_0025: ldfld "int TestCase.X"
// IL_002a: ldc.i4.1
// IL_002b: bne.un.s IL_0031
// IL_002d: ldloc.1
// IL_002e: ldc.i4.1
// IL_002f: add
// IL_0030: stloc.1
// IL_0031: leave.s IL_0047
// }
// finally
// {
// IL_0033: ldloc.0
// IL_0034: ldloc.1
// IL_0035: sub
// IL_0036: stsfld "int Driver.Result"
// IL_003b: ldsfld "System.Threading.AutoResetEvent Driver.CompleteSignal"
// IL_0040: callvirt "bool System.Threading.EventWaitHandle.Set()"
// IL_0045: pop
// IL_0046: endfinally
// }
// IL_0047: ret
// }
// """);
}
[Fact]
public void SpillWithByRefArguments01()
{
var source = @"
using System;
using System.Threading;
using System.Threading.Tasks;
class BaseTestCase
{
public void GooRef(ref decimal d, int x, out decimal od)
{
od = d;
d++;
}
public async Task<T> GetVal<T>(T t)
{
await Task.Delay(1);
return t;
}
}
class TestCase : BaseTestCase
{
public async void Run()
{
int tests = 0;
try
{
decimal d = 1;
decimal od;
tests++;
base.GooRef(ref d, await base.GetVal(4), out od);
if (d == 2 && od == 1) Driver.Count++;
}
finally
{
Driver.Result = Driver.Count - tests;
//When test complete, set the flag.
Driver.CompletedSignal.Set();
}
}
}
class Driver
{
public static int Result = -1;
public static int Count = 0;
public static AutoResetEvent CompletedSignal = new AutoResetEvent(false);
static void Main()
{
var t = new TestCase();
t.Run();
CompletedSignal.WaitOne();
// 0 - success
// 1 - failed (test completed)
// -1 - failed (test incomplete - deadlock, etc)
Console.WriteLine(Driver.Result);
}
}";
CompileAndVerify(source, "0");
}
[Fact]
public void SpillWithByRefArguments01WithTaskAndRuntimeAsync()
{
var source = @"
using System;
using System.Threading;
using System.Threading.Tasks;
class BaseTestCase
{
public void GooRef(ref decimal d, int x, out decimal od)
{
od = d;
d++;
}
public async Task<T> GetVal<T>(T t)
{
await Task.Delay(1);
return t;
}
}
class TestCase : BaseTestCase
{
public async Task Run()
{
int tests = 0;
try
{
decimal d = 1;
decimal od;
tests++;
base.GooRef(ref d, await base.GetVal(4), out od);
if (d == 2 && od == 1) Driver.Count++;
}
finally
{
Driver.Result = Driver.Count - tests;
//When test complete, set the flag.
Driver.CompletedSignal.Set();
}
}
}
class Driver
{
public static int Result = -1;
public static int Count = 0;
public static AutoResetEvent CompletedSignal = new AutoResetEvent(false);
static void Main()
{
var t = new TestCase();
t.Run();
CompletedSignal.WaitOne();
// 0 - success
// 1 - failed (test completed)
// -1 - failed (test incomplete - deadlock, etc)
Console.WriteLine(Driver.Result);
}
}";
CompileAndVerify(source, "0");
var comp = CreateRuntimeAsyncCompilation(source);
var verifier = CompileAndVerify(comp, verify: Verification.Fails with
{
ILVerifyMessage = """
[GetVal]: Unexpected type on the stack. { Offset = 0xc, Found = value 'T', Expected = ref '[System.Runtime]System.Threading.Tasks.Task`1<T0>' }
[Run]: Return value missing on the stack. { Offset = 0x65 }
"""
});
verifier.VerifyDiagnostics(
// (52,9): warning CS4014: Because this call is not awaited, execution of the current method continues before the call is completed. Consider applying the 'await' operator to the result of the call.
// t.Run();
Diagnostic(ErrorCode.WRN_UnobservedAwaitableExpression, "t.Run()").WithLocation(52, 9)
);
verifier.VerifyIL("TestCase.Run()", """
{
// Code size 102 (0x66)
.maxstack 4
.locals init (int V_0, //tests
decimal V_1, //d
decimal V_2, //od
int V_3)
IL_0000: ldc.i4.0
IL_0001: stloc.0
.try
{
IL_0002: ldsfld "decimal decimal.One"
IL_0007: stloc.1
IL_0008: ldloc.0
IL_0009: ldc.i4.1
IL_000a: add
IL_000b: stloc.0
IL_000c: ldarg.0
IL_000d: ldc.i4.4
IL_000e: call "System.Threading.Tasks.Task<int> BaseTestCase.GetVal<int>(int)"
IL_0013: call "int System.Runtime.CompilerServices.AsyncHelpers.Await<int>(System.Threading.Tasks.Task<int>)"
IL_0018: stloc.3
IL_0019: ldarg.0
IL_001a: ldloca.s V_1
IL_001c: ldloc.3
IL_001d: ldloca.s V_2
IL_001f: call "void BaseTestCase.GooRef(ref decimal, int, out decimal)"
IL_0024: ldloc.1
IL_0025: ldc.i4.2
IL_0026: newobj "decimal..ctor(int)"
IL_002b: call "bool decimal.op_Equality(decimal, decimal)"
IL_0030: brfalse.s IL_004b
IL_0032: ldloc.2
IL_0033: ldsfld "decimal decimal.One"
IL_0038: call "bool decimal.op_Equality(decimal, decimal)"
IL_003d: brfalse.s IL_004b
IL_003f: ldsfld "int Driver.Count"
IL_0044: ldc.i4.1
IL_0045: add
IL_0046: stsfld "int Driver.Count"
IL_004b: leave.s IL_0065
}
finally
{
IL_004d: ldsfld "int Driver.Count"
IL_0052: ldloc.0
IL_0053: sub
IL_0054: stsfld "int Driver.Result"
IL_0059: ldsfld "System.Threading.AutoResetEvent Driver.CompletedSignal"
IL_005e: callvirt "bool System.Threading.EventWaitHandle.Set()"
IL_0063: pop
IL_0064: endfinally
}
IL_0065: ret
}
""");
}
[Fact]
public void SpillOperator_Compound1()
{
var source = @"
using System;
using System.Threading;
using System.Threading.Tasks;
class TestCase
{
public async Task<T> GetVal<T>(T t)
{
await Task.Delay(1);
return t;
}
public async void Run()
{
int tests = 0;
try
{
tests++;
int[] x = new int[] { 1, 2, 3, 4 };
x[await GetVal(0)] += await GetVal(4);
if (x[0] == 5)
Driver.Count++;
}
finally
{
Driver.Result = Driver.Count - tests;
//When test complete, set the flag.
Driver.CompletedSignal.Set();
}
}
}
class Driver
{
public static int Result = -1;
public static int Count = 0;
public static AutoResetEvent CompletedSignal = new AutoResetEvent(false);
static void Main()
{
var t = new TestCase();
t.Run();
CompletedSignal.WaitOne();
// 0 - success
// 1 - failed (test completed)
// -1 - failed (test incomplete - deadlock, etc)
Console.WriteLine(Driver.Result);
}
}";
CompileAndVerify(source, "0");
}
[Fact]
public void SpillOperator_Compound1WithTaskAndRuntimeAsync()
{
var source = @"
using System;
using System.Threading;
using System.Threading.Tasks;
class TestCase
{
public async Task<T> GetVal<T>(T t)
{
await Task.Delay(1);
return t;
}
public async Task Run()
{
int tests = 0;
try
{
tests++;
int[] x = new int[] { 1, 2, 3, 4 };
x[await GetVal(0)] += await GetVal(4);
if (x[0] == 5)
Driver.Count++;
}
finally
{
Driver.Result = Driver.Count - tests;
//When test complete, set the flag.
Driver.CompletedSignal.Set();
}
}
}
class Driver
{
public static int Result = -1;
public static int Count = 0;
public static AutoResetEvent CompletedSignal = new AutoResetEvent(false);
static void Main()
{
var t = new TestCase();
#pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
t.Run();
#pragma warning restore CS4014
CompletedSignal.WaitOne();
// 0 - success
// 1 - failed (test completed)
// -1 - failed (test incomplete - deadlock, etc)
Console.WriteLine(Driver.Result);
}
}";
CompileAndVerify(source, "0");
var comp = CreateRuntimeAsyncCompilation(source);
comp.VerifyEmitDiagnostics(
// (21,15): error CS9328: Method 'TestCase.Run()' uses a feature that is not supported by runtime async currently. Opt the method out of runtime async by attributing it with 'System.Runtime.CompilerServices.RuntimeAsyncMethodGenerationAttribute(false)'.
// x[await GetVal(0)] += await GetVal(4);
Diagnostic(ErrorCode.ERR_UnsupportedFeatureInRuntimeAsync, "await GetVal(0)").WithArguments("TestCase.Run()").WithLocation(21, 15)
);
// https://github.com/dotnet/roslyn/issues/79763
// var verifier = CompileAndVerify(comp, expectedOutput: CodeGenAsyncTests.ExpectedOutput("0", isRuntimeAsync: true), verify: Verification.Fails with
// {
// ILVerifyMessage = """
// [GetVal]: Unexpected type on the stack. { Offset = 0xc, Found = value 'T', Expected = ref '[System.Runtime]System.Threading.Tasks.Task`1<T0>' }
// [Run]: Return value missing on the stack. { Offset = 0x6a }
// """
// });
// verifier.VerifyDiagnostics();
// verifier.VerifyIL("TestCase.Run()", """
// {
// // Code size 107 (0x6b)
// .maxstack 4
// .locals init (int V_0, //tests
// int V_1,
// int V_2,
// int V_3)
// IL_0000: ldc.i4.0
// IL_0001: stloc.0
// .try
// {
// IL_0002: ldloc.0
// IL_0003: ldc.i4.1
// IL_0004: add
// IL_0005: stloc.0
// IL_0006: ldc.i4.4
// IL_0007: newarr "int"
// IL_000c: dup
// IL_000d: ldtoken "<PrivateImplementationDetails>.__StaticArrayInitTypeSize=16 <PrivateImplementationDetails>.CF97ADEEDB59E05BFD73A2B4C2A8885708C4F4F70C84C64B27120E72AB733B72"
// IL_0012: call "void System.Runtime.CompilerServices.RuntimeHelpers.InitializeArray(System.Array, System.RuntimeFieldHandle)"
// IL_0017: dup
// IL_0018: ldarg.0
// IL_0019: ldc.i4.0
// IL_001a: call "System.Threading.Tasks.Task<int> TestCase.GetVal<int>(int)"
// IL_001f: call "int System.Runtime.CompilerServices.AsyncHelpers.Await<int>(System.Threading.Tasks.Task<int>)"
// IL_0024: stloc.1
// IL_0025: ldloc.1
// IL_0026: ldelema "int"
// IL_002b: dup
// IL_002c: ldind.i4
// IL_002d: stloc.2
// IL_002e: ldarg.0
// IL_002f: ldc.i4.4
// IL_0030: call "System.Threading.Tasks.Task<int> TestCase.GetVal<int>(int)"
// IL_0035: call "int System.Runtime.CompilerServices.AsyncHelpers.Await<int>(System.Threading.Tasks.Task<int>)"
// IL_003a: stloc.3
// IL_003b: ldloc.2
// IL_003c: ldloc.3
// IL_003d: add
// IL_003e: stind.i4
// IL_003f: ldc.i4.0
// IL_0040: ldelem.i4
// IL_0041: ldc.i4.5
// IL_0042: bne.un.s IL_0050
// IL_0044: ldsfld "int Driver.Count"
// IL_0049: ldc.i4.1
// IL_004a: add
// IL_004b: stsfld "int Driver.Count"
// IL_0050: leave.s IL_006a
// }
// finally
// {
// IL_0052: ldsfld "int Driver.Count"
// IL_0057: ldloc.0
// IL_0058: sub
// IL_0059: stsfld "int Driver.Result"
// IL_005e: ldsfld "System.Threading.AutoResetEvent Driver.CompletedSignal"
// IL_0063: callvirt "bool System.Threading.EventWaitHandle.Set()"
// IL_0068: pop
// IL_0069: endfinally
// }
// IL_006a: ret
// }
// """);
}
[Fact]
public void SpillOperator_Compound2()
{
var source = @"
using System;
using System.Threading;
using System.Threading.Tasks;
class TestCase
{
public async Task<T> GetVal<T>(T t)
{
await Task.Delay(1);
return t;
}
public async void Run()
{
int tests = 0;
try
{
tests++;
int[] x = new int[] { 1, 2, 3, 4 };
x[await GetVal(0)] += await GetVal(4);
if (x[0] == 5)
Driver.Count++;
}
finally
{
Driver.Result = Driver.Count - tests;
//When test complete, set the flag.
Driver.CompletedSignal.Set();
}
}
}
class Driver
{
public static int Result = -1;
public static int Count = 0;
public static AutoResetEvent CompletedSignal = new AutoResetEvent(false);
static void Main()
{
var t = new TestCase();
t.Run();
CompletedSignal.WaitOne();
// 0 - success
// 1 - failed (test completed)
// -1 - failed (test incomplete - deadlock, etc)
Console.WriteLine(Driver.Result);
}
}";
CompileAndVerify(source, "0");
}
[Fact]
public void SpillOperator_Compound2WithRuntimeAsync()
{
var source = @"
using System;
using System.Threading;
using System.Threading.Tasks;
class TestCase
{
public async Task<T> GetVal<T>(T t)
{
await Task.Delay(1);
return t;
}
public async Task Run()
{
int tests = 0;
try
{
tests++;
int[] x = new int[] { 1, 2, 3, 4 };
x[await GetVal(0)] += await GetVal(4);
if (x[0] == 5)
Driver.Count++;
}
finally
{
Driver.Result = Driver.Count - tests;
//When test complete, set the flag.
Driver.CompletedSignal.Set();
}
}
}
class Driver
{
public static int Result = -1;
public static int Count = 0;
public static AutoResetEvent CompletedSignal = new AutoResetEvent(false);
static void Main()
{
var t = new TestCase();
#pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
t.Run();
#pragma warning restore CS4014
CompletedSignal.WaitOne();
// 0 - success
// 1 - failed (test completed)
// -1 - failed (test incomplete - deadlock, etc)
Console.WriteLine(Driver.Result);
}
}";
CompileAndVerify(source, "0");
var comp = CreateRuntimeAsyncCompilation(source);
comp.VerifyEmitDiagnostics(
// (21,15): error CS9328: Method 'TestCase.Run()' uses a feature that is not supported by runtime async currently. Opt the method out of runtime async by attributing it with 'System.Runtime.CompilerServices.RuntimeAsyncMethodGenerationAttribute(false)'.
// x[await GetVal(0)] += await GetVal(4);
Diagnostic(ErrorCode.ERR_UnsupportedFeatureInRuntimeAsync, "await GetVal(0)").WithArguments("TestCase.Run()").WithLocation(21, 15)
);
// https://github.com/dotnet/roslyn/issues/79763
// var verifier = CompileAndVerify(comp, expectedOutput: CodeGenAsyncTests.ExpectedOutput("0", isRuntimeAsync: true), verify: Verification.Fails with
// {
// ILVerifyMessage = """
// [GetVal]: Unexpected type on the stack. { Offset = 0xc, Found = value 'T', Expected = ref '[System.Runtime]System.Threading.Tasks.Task`1<T0>' }
// [Run]: Return value missing on the stack. { Offset = 0x6a }
// """
// });
// verifier.VerifyDiagnostics();
// verifier.VerifyIL("TestCase.Run()", """
// {
// // Code size 107 (0x6b)
// .maxstack 4
// .locals init (int V_0, //tests
// int V_1,
// int V_2,
// int V_3)
// IL_0000: ldc.i4.0
// IL_0001: stloc.0
// .try
// {
// IL_0002: ldloc.0
// IL_0003: ldc.i4.1
// IL_0004: add
// IL_0005: stloc.0
// IL_0006: ldc.i4.4
// IL_0007: newarr "int"
// IL_000c: dup
// IL_000d: ldtoken "<PrivateImplementationDetails>.__StaticArrayInitTypeSize=16 <PrivateImplementationDetails>.CF97ADEEDB59E05BFD73A2B4C2A8885708C4F4F70C84C64B27120E72AB733B72"
// IL_0012: call "void System.Runtime.CompilerServices.RuntimeHelpers.InitializeArray(System.Array, System.RuntimeFieldHandle)"
// IL_0017: dup
// IL_0018: ldarg.0
// IL_0019: ldc.i4.0
// IL_001a: call "System.Threading.Tasks.Task<int> TestCase.GetVal<int>(int)"
// IL_001f: call "int System.Runtime.CompilerServices.AsyncHelpers.Await<int>(System.Threading.Tasks.Task<int>)"
// IL_0024: stloc.1
// IL_0025: ldloc.1
// IL_0026: ldelema "int"
// IL_002b: dup
// IL_002c: ldind.i4
// IL_002d: stloc.2
// IL_002e: ldarg.0
// IL_002f: ldc.i4.4
// IL_0030: call "System.Threading.Tasks.Task<int> TestCase.GetVal<int>(int)"
// IL_0035: call "int System.Runtime.CompilerServices.AsyncHelpers.Await<int>(System.Threading.Tasks.Task<int>)"
// IL_003a: stloc.3
// IL_003b: ldloc.2
// IL_003c: ldloc.3
// IL_003d: add
// IL_003e: stind.i4
// IL_003f: ldc.i4.0
// IL_0040: ldelem.i4
// IL_0041: ldc.i4.5
// IL_0042: bne.un.s IL_0050
// IL_0044: ldsfld "int Driver.Count"
// IL_0049: ldc.i4.1
// IL_004a: add
// IL_004b: stsfld "int Driver.Count"
// IL_0050: leave.s IL_006a
// }
// finally
// {
// IL_0052: ldsfld "int Driver.Count"
// IL_0057: ldloc.0
// IL_0058: sub
// IL_0059: stsfld "int Driver.Result"
// IL_005e: ldsfld "System.Threading.AutoResetEvent Driver.CompletedSignal"
// IL_0063: callvirt "bool System.Threading.EventWaitHandle.Set()"
// IL_0068: pop
// IL_0069: endfinally
// }
// IL_006a: ret
// }
// """);
}
[Fact]
public void Async_StackSpill_Argument_Generic04()
{
var source = @"
using System;
using System.Threading.Tasks;
public class MC<T>
{
async public System.Threading.Tasks.Task<dynamic> Goo<V>(T t, V u) { await Task.Delay(1); return u; }
}
class Test
{
static async Task<int> Goo()
{
dynamic mc = new MC<string>();
var rez = await mc.Goo<string>(null, await ((Func<Task<string>>)(async () => { await Task.Delay(1); return ""Test""; }))());
if (rez == ""Test"")
return 0;
return 1;
}
static void Main()
{
Console.WriteLine(Goo().Result);
}
}";
CompileAndVerify(source, "0", references: new[] { CSharpRef });
var comp = CreateRuntimeAsyncCompilation(source);
comp.VerifyEmitDiagnostics(
// (14,19): error CS9328: Method 'Test.Goo()' uses a feature that is not supported by runtime async currently. Opt the method out of runtime async by attributing it with 'System.Runtime.CompilerServices.RuntimeAsyncMethodGenerationAttribute(false)'.
// var rez = await mc.Goo<string>(null, await ((Func<Task<string>>)(async () => { await Task.Delay(1); return "Test"; }))());
Diagnostic(ErrorCode.ERR_UnsupportedFeatureInRuntimeAsync, @"await mc.Goo<string>(null, await ((Func<Task<string>>)(async () => { await Task.Delay(1); return ""Test""; }))())").WithArguments("Test.Goo()").WithLocation(14, 19)
);
}
[Fact]
public void AsyncStackSpill_assign01()
{
var source = @"
using System;
using System.Threading;
using System.Threading.Tasks;
struct TestCase
{
private int val;
public async Task<T> GetVal<T>(T t)
{
await Task.Delay(1);
return t;
}
public async void Run()
{
int tests = 0;
try
{
tests++;
int[] x = new int[] { 1, 2, 3, 4 };
val = x[await GetVal(0)] += await GetVal(4);
if (x[0] == 5 && val == await GetVal(5))
Driver.Count++;
}
finally
{
Driver.Result = Driver.Count - tests;
//When test complete, set the flag.
Driver.CompletedSignal.Set();
}
}
}
class Driver
{
public static int Result = -1;
public static int Count = 0;
public static AutoResetEvent CompletedSignal = new AutoResetEvent(false);
static void Main()
{
var t = new TestCase();
t.Run();
CompletedSignal.WaitOne();
// 0 - success
// 1 - failed (test completed)
// -1 - failed (test incomplete - deadlock, etc)
Console.WriteLine(Driver.Result);
}
}";
CompileAndVerify(source, "0");
}
[Fact]
public void AsyncStackSpill_assign01WithTaskAndRuntimeAsync()
{
var source = @"
using System;
using System.Threading;
using System.Threading.Tasks;
struct TestCase
{
private int val;
public async Task<T> GetVal<T>(T t)
{
await Task.Delay(1);
return t;
}
public async Task Run()
{
int tests = 0;
try
{
tests++;
int[] x = new int[] { 1, 2, 3, 4 };
val = x[await GetVal(0)] += await GetVal(4);
if (x[0] == 5 && val == await GetVal(5))
Driver.Count++;
}
finally
{
Driver.Result = Driver.Count - tests;
//When test complete, set the flag.
Driver.CompletedSignal.Set();
}
}
}
class Driver
{
public static int Result = -1;
public static int Count = 0;
public static AutoResetEvent CompletedSignal = new AutoResetEvent(false);
static void Main()
{
var t = new TestCase();
#pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
t.Run();
#pragma warning restore CS4014
CompletedSignal.WaitOne();
// 0 - success
// 1 - failed (test completed)
// -1 - failed (test incomplete - deadlock, etc)
Console.WriteLine(Driver.Result);
}
}";
CompileAndVerify(source, "0");
var comp = CreateRuntimeAsyncCompilation(source);
comp.VerifyEmitDiagnostics(
// (15,23): error CS9328: Method 'TestCase.Run()' uses a feature that is not supported by runtime async currently. Opt the method out of runtime async by attributing it with 'System.Runtime.CompilerServices.RuntimeAsyncMethodGenerationAttribute(false)'.
// public async Task Run()
Diagnostic(ErrorCode.ERR_UnsupportedFeatureInRuntimeAsync, "Run").WithArguments("TestCase.Run()").WithLocation(15, 23),
// (23,21): error CS9328: Method 'TestCase.Run()' uses a feature that is not supported by runtime async currently. Opt the method out of runtime async by attributing it with 'System.Runtime.CompilerServices.RuntimeAsyncMethodGenerationAttribute(false)'.
// val = x[await GetVal(0)] += await GetVal(4);
Diagnostic(ErrorCode.ERR_UnsupportedFeatureInRuntimeAsync, "await GetVal(0)").WithArguments("TestCase.Run()").WithLocation(23, 21)
);
// https://github.com/dotnet/roslyn/issues/79763
// var verifier = CompileAndVerify(comp, expectedOutput: CodeGenAsyncTests.ExpectedOutput("0", isRuntimeAsync: true), verify: Verification.Fails with
// {
// ILVerifyMessage = """
// [GetVal]: Unexpected type on the stack. { Offset = 0xc, Found = value 'T', Expected = ref '[System.Runtime]System.Threading.Tasks.Task`1<T0>' }
// [Run]: Return value missing on the stack. { Offset = 0x9d }
// """
// });
// verifier.VerifyDiagnostics();
// verifier.VerifyIL("TestCase.Run()", """
// {
// // Code size 158 (0x9e)
// .maxstack 5
// .locals init (int V_0, //tests
// int V_1,
// int& V_2,
// int V_3,
// int V_4,
// int V_5,
// bool V_6)
// IL_0000: ldc.i4.0
// IL_0001: stloc.0
// .try
// {
// IL_0002: ldloc.0
// IL_0003: ldc.i4.1
// IL_0004: add
// IL_0005: stloc.0
// IL_0006: ldc.i4.4
// IL_0007: newarr "int"
// IL_000c: dup
// IL_000d: ldtoken "<PrivateImplementationDetails>.__StaticArrayInitTypeSize=16 <PrivateImplementationDetails>.CF97ADEEDB59E05BFD73A2B4C2A8885708C4F4F70C84C64B27120E72AB733B72"
// IL_0012: call "void System.Runtime.CompilerServices.RuntimeHelpers.InitializeArray(System.Array, System.RuntimeFieldHandle)"
// IL_0017: dup
// IL_0018: ldarg.0
// IL_0019: ldc.i4.0
// IL_001a: call "System.Threading.Tasks.Task<int> TestCase.GetVal<int>(int)"
// IL_001f: call "int System.Runtime.CompilerServices.AsyncHelpers.Await<int>(System.Threading.Tasks.Task<int>)"
// IL_0024: stloc.1
// IL_0025: ldloc.1
// IL_0026: ldelema "int"
// IL_002b: stloc.2
// IL_002c: ldloc.2
// IL_002d: ldind.i4
// IL_002e: stloc.3
// IL_002f: ldarg.0
// IL_0030: ldc.i4.4
// IL_0031: call "System.Threading.Tasks.Task<int> TestCase.GetVal<int>(int)"
// IL_0036: call "int System.Runtime.CompilerServices.AsyncHelpers.Await<int>(System.Threading.Tasks.Task<int>)"
// IL_003b: stloc.s V_4
// IL_003d: ldarg.0
// IL_003e: ldloc.2
// IL_003f: ldloc.3
// IL_0040: ldloc.s V_4
// IL_0042: add
// IL_0043: dup
// IL_0044: stloc.s V_5
// IL_0046: stind.i4
// IL_0047: ldloc.s V_5
// IL_0049: stfld "int TestCase.val"
// IL_004e: ldc.i4.0
// IL_004f: ldelem.i4
// IL_0050: ldc.i4.5
// IL_0051: ceq
// IL_0053: stloc.s V_6
// IL_0055: ldloc.s V_6
// IL_0057: brfalse.s IL_0073
// IL_0059: ldarg.0
// IL_005a: ldfld "int TestCase.val"
// IL_005f: ldarg.0
// IL_0060: ldc.i4.5
// IL_0061: call "System.Threading.Tasks.Task<int> TestCase.GetVal<int>(int)"
// IL_0066: call "int System.Runtime.CompilerServices.AsyncHelpers.Await<int>(System.Threading.Tasks.Task<int>)"
// IL_006b: stloc.s V_4
// IL_006d: ldloc.s V_4
// IL_006f: ceq
// IL_0071: stloc.s V_6
// IL_0073: ldloc.s V_6
// IL_0075: brfalse.s IL_0083
// IL_0077: ldsfld "int Driver.Count"
// IL_007c: ldc.i4.1
// IL_007d: add
// IL_007e: stsfld "int Driver.Count"
// IL_0083: leave.s IL_009d
// }
// finally
// {
// IL_0085: ldsfld "int Driver.Count"
// IL_008a: ldloc.0
// IL_008b: sub
// IL_008c: stsfld "int Driver.Result"
// IL_0091: ldsfld "System.Threading.AutoResetEvent Driver.CompletedSignal"
// IL_0096: callvirt "bool System.Threading.EventWaitHandle.Set()"
// IL_009b: pop
// IL_009c: endfinally
// }
// IL_009d: ret
// }
// """);
}
[Fact]
public void SpillCollectionInitializer()
{
var source = @"
using System;
using System.Collections;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
struct PrivateCollection : IEnumerable
{
public List<int> lst; //public so we can check the values
public void Add(int x)
{
if (lst == null)
lst = new List<int>();
lst.Add(x);
}
public IEnumerator GetEnumerator()
{
return lst as IEnumerator;
}
}
class TestCase
{
public async Task<T> GetValue<T>(T x)
{
await Task.Delay(1);
return x;
}
public async void Run()
{
int tests = 0;
try
{
tests++;
var myCol = new PrivateCollection() {
await GetValue(1),
await GetValue(2)
};
if (myCol.lst[0] == 1 && myCol.lst[1] == 2)
Driver.Count++;
}
finally
{
Driver.Result = Driver.Count - tests;
//When test completes, set the flag.
Driver.CompletedSignal.Set();
}
}
public int Goo { get; set; }
}
class Driver
{
public static int Result = -1;
public static int Count = 0;
public static AutoResetEvent CompletedSignal = new AutoResetEvent(false);
static void Main()
{
var t = new TestCase();
t.Run();
CompletedSignal.WaitOne();
// 0 - success
// 1 - failed (test completed)
// -1 - failed (test incomplete - deadlock, etc)
Console.WriteLine(Driver.Result);
}
}";
CompileAndVerify(source, "0");
}
[Fact]
public void SpillCollectionInitializerWithRuntimeAsync()
{
var source = @"
using System;
using System.Collections;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
struct PrivateCollection : IEnumerable
{
public List<int> lst; //public so we can check the values
public void Add(int x)
{
if (lst == null)
lst = new List<int>();
lst.Add(x);
}
public IEnumerator GetEnumerator()
{
return lst as IEnumerator;
}
}
class TestCase
{
public async Task<T> GetValue<T>(T x)
{
await Task.Delay(1);
return x;
}
public async Task Run()
{
int tests = 0;
try
{
tests++;
var myCol = new PrivateCollection() {
await GetValue(1),
await GetValue(2)
};
if (myCol.lst[0] == 1 && myCol.lst[1] == 2)
Driver.Count++;
}
finally
{
Driver.Result = Driver.Count - tests;
//When test completes, set the flag.
Driver.CompletedSignal.Set();
}
}
public int Goo { get; set; }
}
class Driver
{
public static int Result = -1;
public static int Count = 0;
public static AutoResetEvent CompletedSignal = new AutoResetEvent(false);
static void Main()
{
var t = new TestCase();
t.Run();
CompletedSignal.WaitOne();
// 0 - success
// 1 - failed (test completed)
// -1 - failed (test incomplete - deadlock, etc)
Console.WriteLine(Driver.Result);
}
}";
CompileAndVerify(source, "0");
var comp = CreateRuntimeAsyncCompilation(source);
var verifier = CompileAndVerify(comp, expectedOutput: CodeGenAsyncTests.ExpectedOutput("0", isRuntimeAsync: true), verify: Verification.Fails with
{
ILVerifyMessage = """
[GetValue]: Unexpected type on the stack. { Offset = 0xc, Found = value 'T', Expected = ref '[System.Runtime]System.Threading.Tasks.Task`1<T0>' }
[Run]: Return value missing on the stack. { Offset = 0x7f }
"""
});
verifier.VerifyDiagnostics(
// (65,9): warning CS4014: Because this call is not awaited, execution of the current method continues before the call is completed. Consider applying the 'await' operator to the result of the call.
// t.Run();
Diagnostic(ErrorCode.WRN_UnobservedAwaitableExpression, "t.Run()").WithLocation(65, 9)
);
verifier.VerifyIL("TestCase.Run()", """
{
// Code size 128 (0x80)
.maxstack 2
.locals init (int V_0, //tests
PrivateCollection V_1, //myCol
int V_2,
int V_3,
PrivateCollection V_4)
IL_0000: ldc.i4.0
IL_0001: stloc.0
.try
{
IL_0002: ldloc.0
IL_0003: ldc.i4.1
IL_0004: add
IL_0005: stloc.0
IL_0006: ldloca.s V_4
IL_0008: initobj "PrivateCollection"
IL_000e: ldarg.0
IL_000f: ldc.i4.1
IL_0010: call "System.Threading.Tasks.Task<int> TestCase.GetValue<int>(int)"
IL_0015: call "int System.Runtime.CompilerServices.AsyncHelpers.Await<int>(System.Threading.Tasks.Task<int>)"
IL_001a: stloc.2
IL_001b: ldloca.s V_4
IL_001d: ldloc.2
IL_001e: call "void PrivateCollection.Add(int)"
IL_0023: ldarg.0
IL_0024: ldc.i4.2
IL_0025: call "System.Threading.Tasks.Task<int> TestCase.GetValue<int>(int)"
IL_002a: call "int System.Runtime.CompilerServices.AsyncHelpers.Await<int>(System.Threading.Tasks.Task<int>)"
IL_002f: stloc.3
IL_0030: ldloca.s V_4
IL_0032: ldloc.3
IL_0033: call "void PrivateCollection.Add(int)"
IL_0038: ldloc.s V_4
IL_003a: stloc.1
IL_003b: ldloc.1
IL_003c: ldfld "System.Collections.Generic.List<int> PrivateCollection.lst"
IL_0041: ldc.i4.0
IL_0042: callvirt "int System.Collections.Generic.List<int>.this[int].get"
IL_0047: ldc.i4.1
IL_0048: bne.un.s IL_0065
IL_004a: ldloc.1
IL_004b: ldfld "System.Collections.Generic.List<int> PrivateCollection.lst"
IL_0050: ldc.i4.1
IL_0051: callvirt "int System.Collections.Generic.List<int>.this[int].get"
IL_0056: ldc.i4.2
IL_0057: bne.un.s IL_0065
IL_0059: ldsfld "int Driver.Count"
IL_005e: ldc.i4.1
IL_005f: add
IL_0060: stsfld "int Driver.Count"
IL_0065: leave.s IL_007f
}
finally
{
IL_0067: ldsfld "int Driver.Count"
IL_006c: ldloc.0
IL_006d: sub
IL_006e: stsfld "int Driver.Result"
IL_0073: ldsfld "System.Threading.AutoResetEvent Driver.CompletedSignal"
IL_0078: callvirt "bool System.Threading.EventWaitHandle.Set()"
IL_007d: pop
IL_007e: endfinally
}
IL_007f: ret
}
""");
}
[Fact]
public void SpillRefExpr()
{
var source = @"
using System;
using System.Threading.Tasks;
class MyClass
{
public int Field;
}
class TestCase
{
public static int Goo(ref int x, int y)
{
return x + y;
}
public async Task<int> Run()
{
return Goo(
ref (new MyClass() { Field = 21 }.Field),
await Task.Factory.StartNew(() => 21));
}
}
static class Driver
{
static void Main()
{
var t = new TestCase().Run();
t.Wait();
Console.WriteLine(t.Result);
}
}";
CompileAndVerify(source, "42");
var comp = CreateRuntimeAsyncCompilation(source);
var verifier = CompileAndVerify(comp, verify: Verification.Fails with
{
ILVerifyMessage = """
[Run]: Unexpected type on the stack. { Offset = 0x47, Found = Int32, Expected = ref '[System.Runtime]System.Threading.Tasks.Task`1<int32>' }
"""
});
verifier.VerifyDiagnostics();
verifier.VerifyIL("TestCase.Run()", """
{
// Code size 72 (0x48)
.maxstack 4
.locals init (int V_0)
IL_0000: newobj "MyClass..ctor()"
IL_0005: dup
IL_0006: ldc.i4.s 21
IL_0008: stfld "int MyClass.Field"
IL_000d: call "System.Threading.Tasks.TaskFactory System.Threading.Tasks.Task.Factory.get"
IL_0012: ldsfld "System.Func<int> TestCase.<>c.<>9__1_0"
IL_0017: dup
IL_0018: brtrue.s IL_0031
IL_001a: pop
IL_001b: ldsfld "TestCase.<>c TestCase.<>c.<>9"
IL_0020: ldftn "int TestCase.<>c.<Run>b__1_0()"
IL_0026: newobj "System.Func<int>..ctor(object, System.IntPtr)"
IL_002b: dup
IL_002c: stsfld "System.Func<int> TestCase.<>c.<>9__1_0"
IL_0031: callvirt "System.Threading.Tasks.Task<int> System.Threading.Tasks.TaskFactory.StartNew<int>(System.Func<int>)"
IL_0036: call "int System.Runtime.CompilerServices.AsyncHelpers.Await<int>(System.Threading.Tasks.Task<int>)"
IL_003b: stloc.0
IL_003c: ldflda "int MyClass.Field"
IL_0041: ldloc.0
IL_0042: call "int TestCase.Goo(ref int, int)"
IL_0047: ret
}
""");
}
[Fact]
public void SpillManagedPointerAssign03()
{
var source = @"
using System;
using System.Threading;
using System.Threading.Tasks;
class TestCase
{
public async Task<T> GetVal<T>(T t)
{
await Task.Delay(1);
return t;
}
class PrivClass
{
internal struct ValueT
{
public int Field;
}
internal ValueT[] arr = new ValueT[3];
}
private PrivClass myClass;
public async void Run()
{
int tests = 0;
this.myClass = new PrivClass();
try
{
tests++;
this.myClass.arr[0].Field = await GetVal(4);
if (myClass.arr[0].Field == 4)
Driver.Count++;
tests++;
this.myClass.arr[0].Field += await GetVal(4);
if (myClass.arr[0].Field == 8)
Driver.Count++;
tests++;
this.myClass.arr[await GetVal(1)].Field += await GetVal(4);
if (myClass.arr[1].Field == 4)
Driver.Count++;
tests++;
this.myClass.arr[await GetVal(1)].Field++;
if (myClass.arr[1].Field == 5)
Driver.Count++;
}
finally
{
Driver.Result = Driver.Count - tests;
//When test complete, set the flag.
Driver.CompletedSignal.Set();
}
}
}
class Driver
{
public static int Result = -1;
public static int Count = 0;
public static AutoResetEvent CompletedSignal = new AutoResetEvent(false);
static void Main()
{
var t = new TestCase();
t.Run();
CompletedSignal.WaitOne();
// 0 - success
// 1 - failed (test completed)
// -1 - failed (test incomplete - deadlock, etc)
Console.WriteLine(Driver.Result);
}
}";
CompileAndVerify(source, "0");
}
[Fact]
public void SpillManagedPointerAssign03WithTaskAndRuntimeAsync()
{
var source = @"
using System;
using System.Threading;
using System.Threading.Tasks;
class TestCase
{
public async Task<T> GetVal<T>(T t)
{
await Task.Delay(1);
return t;
}
class PrivClass
{
internal struct ValueT
{
public int Field;
}
internal ValueT[] arr = new ValueT[3];
}
private PrivClass myClass;
public async Task Run()
{
int tests = 0;
this.myClass = new PrivClass();
try
{
tests++;
this.myClass.arr[0].Field = await GetVal(4);
if (myClass.arr[0].Field == 4)
Driver.Count++;
tests++;
this.myClass.arr[0].Field += await GetVal(4);
if (myClass.arr[0].Field == 8)
Driver.Count++;
tests++;
this.myClass.arr[await GetVal(1)].Field += await GetVal(4);
if (myClass.arr[1].Field == 4)
Driver.Count++;
tests++;
this.myClass.arr[await GetVal(1)].Field++;
if (myClass.arr[1].Field == 5)
Driver.Count++;
}
finally
{
Driver.Result = Driver.Count - tests;
//When test complete, set the flag.
Driver.CompletedSignal.Set();
}
}
}
class Driver
{
public static int Result = -1;
public static int Count = 0;
public static AutoResetEvent CompletedSignal = new AutoResetEvent(false);
static void Main()
{
var t = new TestCase();
#pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
t.Run();
#pragma warning restore CS4014
CompletedSignal.WaitOne();
// 0 - success
// 1 - failed (test completed)
// -1 - failed (test incomplete - deadlock, etc)
Console.WriteLine(Driver.Result);
}
}";
CompileAndVerify(source, "0");
var comp = CreateRuntimeAsyncCompilation(source);
comp.VerifyEmitDiagnostics(
// (39,42): error CS9328: Method 'TestCase.Run()' uses a feature that is not supported by runtime async currently. Opt the method out of runtime async by attributing it with 'System.Runtime.CompilerServices.RuntimeAsyncMethodGenerationAttribute(false)'.
// this.myClass.arr[0].Field += await GetVal(4);
Diagnostic(ErrorCode.ERR_UnsupportedFeatureInRuntimeAsync, "await GetVal(4)").WithArguments("TestCase.Run()").WithLocation(39, 42),
// (39,42): error CS9328: Method 'TestCase.Run()' uses a feature that is not supported by runtime async currently. Opt the method out of runtime async by attributing it with 'System.Runtime.CompilerServices.RuntimeAsyncMethodGenerationAttribute(false)'.
// this.myClass.arr[0].Field += await GetVal(4);
Diagnostic(ErrorCode.ERR_UnsupportedFeatureInRuntimeAsync, "await GetVal(4)").WithArguments("TestCase.Run()").WithLocation(39, 42),
// (44,30): error CS9328: Method 'TestCase.Run()' uses a feature that is not supported by runtime async currently. Opt the method out of runtime async by attributing it with 'System.Runtime.CompilerServices.RuntimeAsyncMethodGenerationAttribute(false)'.
// this.myClass.arr[await GetVal(1)].Field += await GetVal(4);
Diagnostic(ErrorCode.ERR_UnsupportedFeatureInRuntimeAsync, "await GetVal(1)").WithArguments("TestCase.Run()").WithLocation(44, 30),
// (44,30): error CS9328: Method 'TestCase.Run()' uses a feature that is not supported by runtime async currently. Opt the method out of runtime async by attributing it with 'System.Runtime.CompilerServices.RuntimeAsyncMethodGenerationAttribute(false)'.
// this.myClass.arr[await GetVal(1)].Field += await GetVal(4);
Diagnostic(ErrorCode.ERR_UnsupportedFeatureInRuntimeAsync, "await GetVal(1)").WithArguments("TestCase.Run()").WithLocation(44, 30)
);
// https://github.com/dotnet/roslyn/issues/79763
// var verifier = CompileAndVerify(comp, expectedOutput: CodeGenAsyncTests.ExpectedOutput("0", isRuntimeAsync: true), verify: Verification.Fails with
// {
// ILVerifyMessage = """
// [GetVal]: Unexpected type on the stack. { Offset = 0xc, Found = value 'T', Expected = ref '[System.Runtime]System.Threading.Tasks.Task`1<T0>' }
// [Run]: Return value missing on the stack. { Offset = 0x182 }
// """
// });
// verifier.VerifyDiagnostics();
// verifier.VerifyIL("TestCase.Run()", """
// {
// // Code size 387 (0x183)
// .maxstack 3
// .locals init (int V_0, //tests
// int V_1,
// int V_2,
// int V_3)
// IL_0000: ldc.i4.0
// IL_0001: stloc.0
// IL_0002: ldarg.0
// IL_0003: newobj "TestCase.PrivClass..ctor()"
// IL_0008: stfld "TestCase.PrivClass TestCase.myClass"
// .try
// {
// IL_000d: ldloc.0
// IL_000e: ldc.i4.1
// IL_000f: add
// IL_0010: stloc.0
// IL_0011: ldarg.0
// IL_0012: ldfld "TestCase.PrivClass TestCase.myClass"
// IL_0017: ldfld "TestCase.PrivClass.ValueT[] TestCase.PrivClass.arr"
// IL_001c: dup
// IL_001d: ldc.i4.0
// IL_001e: ldelema "TestCase.PrivClass.ValueT"
// IL_0023: pop
// IL_0024: ldarg.0
// IL_0025: ldc.i4.4
// IL_0026: call "System.Threading.Tasks.Task<int> TestCase.GetVal<int>(int)"
// IL_002b: call "int System.Runtime.CompilerServices.AsyncHelpers.Await<int>(System.Threading.Tasks.Task<int>)"
// IL_0030: stloc.1
// IL_0031: ldc.i4.0
// IL_0032: ldelema "TestCase.PrivClass.ValueT"
// IL_0037: ldloc.1
// IL_0038: stfld "int TestCase.PrivClass.ValueT.Field"
// IL_003d: ldarg.0
// IL_003e: ldfld "TestCase.PrivClass TestCase.myClass"
// IL_0043: ldfld "TestCase.PrivClass.ValueT[] TestCase.PrivClass.arr"
// IL_0048: ldc.i4.0
// IL_0049: ldelema "TestCase.PrivClass.ValueT"
// IL_004e: ldfld "int TestCase.PrivClass.ValueT.Field"
// IL_0053: ldc.i4.4
// IL_0054: bne.un.s IL_0062
// IL_0056: ldsfld "int Driver.Count"
// IL_005b: ldc.i4.1
// IL_005c: add
// IL_005d: stsfld "int Driver.Count"
// IL_0062: ldloc.0
// IL_0063: ldc.i4.1
// IL_0064: add
// IL_0065: stloc.0
// IL_0066: ldarg.0
// IL_0067: ldfld "TestCase.PrivClass TestCase.myClass"
// IL_006c: ldfld "TestCase.PrivClass.ValueT[] TestCase.PrivClass.arr"
// IL_0071: ldc.i4.0
// IL_0072: ldelema "TestCase.PrivClass.ValueT"
// IL_0077: ldflda "int TestCase.PrivClass.ValueT.Field"
// IL_007c: dup
// IL_007d: ldind.i4
// IL_007e: stloc.1
// IL_007f: ldarg.0
// IL_0080: ldc.i4.4
// IL_0081: call "System.Threading.Tasks.Task<int> TestCase.GetVal<int>(int)"
// IL_0086: call "int System.Runtime.CompilerServices.AsyncHelpers.Await<int>(System.Threading.Tasks.Task<int>)"
// IL_008b: stloc.2
// IL_008c: ldloc.1
// IL_008d: ldloc.2
// IL_008e: add
// IL_008f: stind.i4
// IL_0090: ldarg.0
// IL_0091: ldfld "TestCase.PrivClass TestCase.myClass"
// IL_0096: ldfld "TestCase.PrivClass.ValueT[] TestCase.PrivClass.arr"
// IL_009b: ldc.i4.0
// IL_009c: ldelema "TestCase.PrivClass.ValueT"
// IL_00a1: ldfld "int TestCase.PrivClass.ValueT.Field"
// IL_00a6: ldc.i4.8
// IL_00a7: bne.un.s IL_00b5
// IL_00a9: ldsfld "int Driver.Count"
// IL_00ae: ldc.i4.1
// IL_00af: add
// IL_00b0: stsfld "int Driver.Count"
// IL_00b5: ldloc.0
// IL_00b6: ldc.i4.1
// IL_00b7: add
// IL_00b8: stloc.0
// IL_00b9: ldarg.0
// IL_00ba: ldfld "TestCase.PrivClass TestCase.myClass"
// IL_00bf: ldfld "TestCase.PrivClass.ValueT[] TestCase.PrivClass.arr"
// IL_00c4: ldarg.0
// IL_00c5: ldc.i4.1
// IL_00c6: call "System.Threading.Tasks.Task<int> TestCase.GetVal<int>(int)"
// IL_00cb: call "int System.Runtime.CompilerServices.AsyncHelpers.Await<int>(System.Threading.Tasks.Task<int>)"
// IL_00d0: stloc.2
// IL_00d1: ldloc.2
// IL_00d2: ldelema "TestCase.PrivClass.ValueT"
// IL_00d7: ldflda "int TestCase.PrivClass.ValueT.Field"
// IL_00dc: dup
// IL_00dd: ldind.i4
// IL_00de: stloc.1
// IL_00df: ldarg.0
// IL_00e0: ldc.i4.4
// IL_00e1: call "System.Threading.Tasks.Task<int> TestCase.GetVal<int>(int)"
// IL_00e6: call "int System.Runtime.CompilerServices.AsyncHelpers.Await<int>(System.Threading.Tasks.Task<int>)"
// IL_00eb: stloc.3
// IL_00ec: ldloc.1
// IL_00ed: ldloc.3
// IL_00ee: add
// IL_00ef: stind.i4
// IL_00f0: ldarg.0
// IL_00f1: ldfld "TestCase.PrivClass TestCase.myClass"
// IL_00f6: ldfld "TestCase.PrivClass.ValueT[] TestCase.PrivClass.arr"
// IL_00fb: ldc.i4.1
// IL_00fc: ldelema "TestCase.PrivClass.ValueT"
// IL_0101: ldfld "int TestCase.PrivClass.ValueT.Field"
// IL_0106: ldc.i4.4
// IL_0107: bne.un.s IL_0115
// IL_0109: ldsfld "int Driver.Count"
// IL_010e: ldc.i4.1
// IL_010f: add
// IL_0110: stsfld "int Driver.Count"
// IL_0115: ldloc.0
// IL_0116: ldc.i4.1
// IL_0117: add
// IL_0118: stloc.0
// IL_0119: ldarg.0
// IL_011a: ldfld "TestCase.PrivClass TestCase.myClass"
// IL_011f: ldfld "TestCase.PrivClass.ValueT[] TestCase.PrivClass.arr"
// IL_0124: ldarg.0
// IL_0125: ldc.i4.1
// IL_0126: call "System.Threading.Tasks.Task<int> TestCase.GetVal<int>(int)"
// IL_012b: call "int System.Runtime.CompilerServices.AsyncHelpers.Await<int>(System.Threading.Tasks.Task<int>)"
// IL_0130: stloc.3
// IL_0131: ldloc.3
// IL_0132: ldelema "TestCase.PrivClass.ValueT"
// IL_0137: ldflda "int TestCase.PrivClass.ValueT.Field"
// IL_013c: dup
// IL_013d: ldind.i4
// IL_013e: stloc.1
// IL_013f: ldloc.1
// IL_0140: ldc.i4.1
// IL_0141: add
// IL_0142: stind.i4
// IL_0143: ldarg.0
// IL_0144: ldfld "TestCase.PrivClass TestCase.myClass"
// IL_0149: ldfld "TestCase.PrivClass.ValueT[] TestCase.PrivClass.arr"
// IL_014e: ldc.i4.1
// IL_014f: ldelema "TestCase.PrivClass.ValueT"
// IL_0154: ldfld "int TestCase.PrivClass.ValueT.Field"
// IL_0159: ldc.i4.5
// IL_015a: bne.un.s IL_0168
// IL_015c: ldsfld "int Driver.Count"
// IL_0161: ldc.i4.1
// IL_0162: add
// IL_0163: stsfld "int Driver.Count"
// IL_0168: leave.s IL_0182
// }
// finally
// {
// IL_016a: ldsfld "int Driver.Count"
// IL_016f: ldloc.0
// IL_0170: sub
// IL_0171: stsfld "int Driver.Result"
// IL_0176: ldsfld "System.Threading.AutoResetEvent Driver.CompletedSignal"
// IL_017b: callvirt "bool System.Threading.EventWaitHandle.Set()"
// IL_0180: pop
// IL_0181: endfinally
// }
// IL_0182: ret
// }
// """);
}
[Fact, WorkItem(36443, "https://github.com/dotnet/roslyn/issues/36443")]
public void SpillCompoundAssignmentToNullableMemberOfLocal_01()
{
var source = @"
using System;
using System.Threading.Tasks;
struct S
{
int? i;
static async Task Main()
{
S s = default;
Console.WriteLine(s.i += await GetInt());
}
static Task<int?> GetInt() => Task.FromResult((int?)1);
}";
var expectedOutput = "";
CompileAndVerify(source, expectedOutput: expectedOutput, options: TestOptions.ReleaseExe);
CompileAndVerify(source, expectedOutput: expectedOutput, options: TestOptions.DebugExe);
var comp = CreateRuntimeAsyncCompilation(source);
comp.VerifyEmitDiagnostics(
// (11,34): error CS9328: Method 'S.Main()' uses a feature that is not supported by runtime async currently. Opt the method out of runtime async by attributing it with 'System.Runtime.CompilerServices.RuntimeAsyncMethodGenerationAttribute(false)'.
// Console.WriteLine(s.i += await GetInt());
Diagnostic(ErrorCode.ERR_UnsupportedFeatureInRuntimeAsync, "await GetInt()").WithArguments("S.Main()").WithLocation(11, 34)
);
// https://github.com/dotnet/roslyn/issues/79763
// var verifier = CompileAndVerify(comp, expectedOutput: CodeGenAsyncTests.ExpectedOutput(expectedOutput, isRuntimeAsync: true), verify: Verification.Fails with
// {
// ILVerifyMessage = """
// [Main]: Return value missing on the stack. { Offset = 0x63 }
// """
// });
// verifier.VerifyDiagnostics();
// verifier.VerifyIL("S.Main()", """
// {
// // Code size 100 (0x64)
// .maxstack 3
// .locals init (S V_0, //s
// int? V_1,
// int? V_2,
// int? V_3)
// IL_0000: ldloca.s V_0
// IL_0002: initobj "S"
// IL_0008: ldloca.s V_0
// IL_000a: ldflda "int? S.i"
// IL_000f: dup
// IL_0010: ldobj "int?"
// IL_0015: stloc.1
// IL_0016: call "System.Threading.Tasks.Task<int?> S.GetInt()"
// IL_001b: call "int? System.Runtime.CompilerServices.AsyncHelpers.Await<int?>(System.Threading.Tasks.Task<int?>)"
// IL_0020: stloc.2
// IL_0021: ldloca.s V_1
// IL_0023: call "readonly bool int?.HasValue.get"
// IL_0028: ldloca.s V_2
// IL_002a: call "readonly bool int?.HasValue.get"
// IL_002f: and
// IL_0030: brtrue.s IL_003d
// IL_0032: ldloca.s V_3
// IL_0034: initobj "int?"
// IL_003a: ldloc.3
// IL_003b: br.s IL_0051
// IL_003d: ldloca.s V_1
// IL_003f: call "readonly int int?.GetValueOrDefault()"
// IL_0044: ldloca.s V_2
// IL_0046: call "readonly int int?.GetValueOrDefault()"
// IL_004b: add
// IL_004c: newobj "int?..ctor(int)"
// IL_0051: dup
// IL_0052: stloc.3
// IL_0053: stobj "int?"
// IL_0058: ldloc.3
// IL_0059: box "int?"
// IL_005e: call "void System.Console.WriteLine(object)"
// IL_0063: ret
// }
// """);
}
[Fact, WorkItem(36443, "https://github.com/dotnet/roslyn/issues/36443")]
public void SpillCompoundAssignmentToNullableMemberOfLocal_02()
{
var source = @"
class C
{
static async System.Threading.Tasks.Task Main()
{
await new C().M();
}
int field = 1;
async System.Threading.Tasks.Task M()
{
this.field += await M2();
System.Console.Write(this.field);
}
async System.Threading.Tasks.Task<int> M2()
{
await System.Threading.Tasks.Task.Yield();
return 42;
}
}
";
var expectedOutput = "43";
CompileAndVerify(source, expectedOutput: expectedOutput, options: TestOptions.DebugExe);
CompileAndVerify(source, expectedOutput: expectedOutput, options: TestOptions.ReleaseExe);
var comp = CreateRuntimeAsyncCompilation(source);
var verifier = CompileAndVerify(comp, expectedOutput: CodeGenAsyncTests.ExpectedOutput(expectedOutput, isRuntimeAsync: true), verify: Verification.Fails with
{
ILVerifyMessage = """
[Main]: Return value missing on the stack. { Offset = 0xf }
[M]: Return value missing on the stack. { Offset = 0x27 }
[M2]: Unexpected type on the stack. { Offset = 0x26, Found = Int32, Expected = ref '[System.Runtime]System.Threading.Tasks.Task`1<int32>' }
"""
});
verifier.VerifyDiagnostics();
verifier.VerifyIL("C.M()", """
{
// Code size 40 (0x28)
.maxstack 3
.locals init (int V_0,
int V_1)
IL_0000: ldarg.0
IL_0001: ldfld "int C.field"
IL_0006: stloc.0
IL_0007: ldarg.0
IL_0008: call "System.Threading.Tasks.Task<int> C.M2()"
IL_000d: call "int System.Runtime.CompilerServices.AsyncHelpers.Await<int>(System.Threading.Tasks.Task<int>)"
IL_0012: stloc.1
IL_0013: ldarg.0
IL_0014: ldloc.0
IL_0015: ldloc.1
IL_0016: add
IL_0017: stfld "int C.field"
IL_001c: ldarg.0
IL_001d: ldfld "int C.field"
IL_0022: call "void System.Console.Write(int)"
IL_0027: ret
}
""");
}
[Fact, WorkItem(36443, "https://github.com/dotnet/roslyn/issues/36443")]
public void SpillCompoundAssignmentToNullableMemberOfLocal_03()
{
var source = @"
class C
{
static async System.Threading.Tasks.Task Main()
{
await new C().M();
}
int? field = 1;
async System.Threading.Tasks.Task M()
{
this.field += await M2();
System.Console.Write(this.field);
}
async System.Threading.Tasks.Task<int?> M2()
{
await System.Threading.Tasks.Task.Yield();
return 42;
}
}
";
var expectedOutput = "43";
CompileAndVerify(source, expectedOutput: expectedOutput, options: TestOptions.ReleaseExe);
CompileAndVerify(source, expectedOutput: expectedOutput, options: TestOptions.DebugExe);
var comp = CreateRuntimeAsyncCompilation(source);
var verifier = CompileAndVerify(comp, expectedOutput: CodeGenAsyncTests.ExpectedOutput(expectedOutput, isRuntimeAsync: true), verify: Verification.Fails with
{
ILVerifyMessage = """
[Main]: Return value missing on the stack. { Offset = 0xf }
[M]: Return value missing on the stack. { Offset = 0x59 }
[M2]: Unexpected type on the stack. { Offset = 0x2b, Found = value '[System.Runtime]System.Nullable`1<int32>', Expected = ref '[System.Runtime]System.Threading.Tasks.Task`1<System.Nullable`1<int32>>' }
"""
});
verifier.VerifyDiagnostics();
verifier.VerifyIL("C.M()", """
{
// Code size 90 (0x5a)
.maxstack 3
.locals init (int? V_0,
int? V_1,
int? V_2)
IL_0000: ldarg.0
IL_0001: ldfld "int? C.field"
IL_0006: stloc.0
IL_0007: ldarg.0
IL_0008: call "System.Threading.Tasks.Task<int?> C.M2()"
IL_000d: call "int? System.Runtime.CompilerServices.AsyncHelpers.Await<int?>(System.Threading.Tasks.Task<int?>)"
IL_0012: stloc.1
IL_0013: ldarg.0
IL_0014: ldloca.s V_0
IL_0016: call "readonly bool int?.HasValue.get"
IL_001b: ldloca.s V_1
IL_001d: call "readonly bool int?.HasValue.get"
IL_0022: and
IL_0023: brtrue.s IL_0030
IL_0025: ldloca.s V_2
IL_0027: initobj "int?"
IL_002d: ldloc.2
IL_002e: br.s IL_0044
IL_0030: ldloca.s V_0
IL_0032: call "readonly int int?.GetValueOrDefault()"
IL_0037: ldloca.s V_1
IL_0039: call "readonly int int?.GetValueOrDefault()"
IL_003e: add
IL_003f: newobj "int?..ctor(int)"
IL_0044: stfld "int? C.field"
IL_0049: ldarg.0
IL_004a: ldfld "int? C.field"
IL_004f: box "int?"
IL_0054: call "void System.Console.Write(object)"
IL_0059: ret
}
""");
}
[Fact, WorkItem(36443, "https://github.com/dotnet/roslyn/issues/36443")]
public void SpillCompoundAssignmentToNullableMemberOfLocal_04()
{
var source = @"
using System;
using System.Threading.Tasks;
struct S
{
int? i;
static async Task M(S s = default)
{
s = default;
Console.WriteLine(s.i += await GetInt());
}
static async Task Main()
{
M();
}
static Task<int?> GetInt() => Task.FromResult((int?)1);
}";
var expectedOutput = "";
CompileAndVerify(source, expectedOutput: expectedOutput, options: TestOptions.ReleaseExe);
CompileAndVerify(source, expectedOutput: expectedOutput, options: TestOptions.DebugExe);
var comp = CreateRuntimeAsyncCompilation(source);
comp.VerifyEmitDiagnostics(
// (11,34): error CS9328: Method 'S.M(S)' uses a feature that is not supported by runtime async currently. Opt the method out of runtime async by attributing it with 'System.Runtime.CompilerServices.RuntimeAsyncMethodGenerationAttribute(false)'.
// Console.WriteLine(s.i += await GetInt());
Diagnostic(ErrorCode.ERR_UnsupportedFeatureInRuntimeAsync, "await GetInt()").WithArguments("S.M(S)").WithLocation(11, 34),
// (16,9): warning CS4014: Because this call is not awaited, execution of the current method continues before the call is completed. Consider applying the 'await' operator to the result of the call.
// M();
Diagnostic(ErrorCode.WRN_UnobservedAwaitableExpression, "M()").WithLocation(16, 9),
// (14,23): warning CS1998: This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread.
// static async Task Main()
Diagnostic(ErrorCode.WRN_AsyncLacksAwaits, "Main").WithLocation(14, 23)
);
// https://github.com/dotnet/roslyn/issues/79763
// var verifier = CompileAndVerify(comp, expectedOutput: CodeGenAsyncTests.ExpectedOutput(expectedOutput, isRuntimeAsync: true), verify: Verification.Fails with
// {
// ILVerifyMessage = """
// [M]: Return value missing on the stack. { Offset = 0x63 }
// [Main]: Return value missing on the stack. { Offset = 0xf }
// """
// });
// verifier.VerifyDiagnostics(
// // (14,23): warning CS1998: This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread.
// // static async Task Main()
// Diagnostic(ErrorCode.WRN_AsyncLacksAwaits, "Main").WithLocation(14, 23),
// // (16,9): warning CS4014: Because this call is not awaited, execution of the current method continues before the call is completed. Consider applying the 'await' operator to the result of the call.
// // M();
// Diagnostic(ErrorCode.WRN_UnobservedAwaitableExpression, "M()").WithLocation(16, 9)
// );
// verifier.VerifyIL("S.M(S)", """
// {
// // Code size 100 (0x64)
// .maxstack 3
// .locals init (int? V_0,
// int? V_1,
// int? V_2)
// IL_0000: ldarga.s V_0
// IL_0002: initobj "S"
// IL_0008: ldarga.s V_0
// IL_000a: ldflda "int? S.i"
// IL_000f: dup
// IL_0010: ldobj "int?"
// IL_0015: stloc.0
// IL_0016: call "System.Threading.Tasks.Task<int?> S.GetInt()"
// IL_001b: call "int? System.Runtime.CompilerServices.AsyncHelpers.Await<int?>(System.Threading.Tasks.Task<int?>)"
// IL_0020: stloc.1
// IL_0021: ldloca.s V_0
// IL_0023: call "readonly bool int?.HasValue.get"
// IL_0028: ldloca.s V_1
// IL_002a: call "readonly bool int?.HasValue.get"
// IL_002f: and
// IL_0030: brtrue.s IL_003d
// IL_0032: ldloca.s V_2
// IL_0034: initobj "int?"
// IL_003a: ldloc.2
// IL_003b: br.s IL_0051
// IL_003d: ldloca.s V_0
// IL_003f: call "readonly int int?.GetValueOrDefault()"
// IL_0044: ldloca.s V_1
// IL_0046: call "readonly int int?.GetValueOrDefault()"
// IL_004b: add
// IL_004c: newobj "int?..ctor(int)"
// IL_0051: dup
// IL_0052: stloc.2
// IL_0053: stobj "int?"
// IL_0058: ldloc.2
// IL_0059: box "int?"
// IL_005e: call "void System.Console.WriteLine(object)"
// IL_0063: ret
// }
// """);
}
[Fact]
public void SpillSacrificialRead()
{
var source = @"
using System;
using System.Threading.Tasks;
class C
{
static void F1(ref int x, int y, int z)
{
x += y + z;
}
static int F0()
{
Console.WriteLine(-1);
return 0;
}
static async Task<int> F2()
{
int[] x = new int[1] { 21 };
x = null;
F1(ref x[0], F0(), await Task.Factory.StartNew(() => 21));
return x[0];
}
public static void Main()
{
var t = F2();
try
{
t.Wait();
}
catch(Exception)
{
Console.WriteLine(0);
return;
}
Console.WriteLine(-1);
}
}";
CompileAndVerify(source, "0");
var comp = CreateRuntimeAsyncCompilation(source);
comp.VerifyEmitDiagnostics(
// (22,28): error CS9328: Method 'C.F2()' uses a feature that is not supported by runtime async currently. Opt the method out of runtime async by attributing it with 'System.Runtime.CompilerServices.RuntimeAsyncMethodGenerationAttribute(false)'.
// F1(ref x[0], F0(), await Task.Factory.StartNew(() => 21));
Diagnostic(ErrorCode.ERR_UnsupportedFeatureInRuntimeAsync, "await Task.Factory.StartNew(() => 21)").WithArguments("C.F2()").WithLocation(22, 28)
);
// https://github.com/dotnet/roslyn/issues/79763
// var verifier = CompileAndVerify(comp, verify: Verification.Fails with
// {
// ILVerifyMessage = """
// [F2]: Unexpected type on the stack. { Offset = 0x52, Found = Int32, Expected = ref '[System.Runtime]System.Threading.Tasks.Task`1<int32>' }
// """
// });
// verifier.VerifyDiagnostics();
// verifier.VerifyIL("C.F2()", """
// {
// // Code size 83 (0x53)
// .maxstack 5
// .locals init (int V_0,
// int V_1)
// IL_0000: ldc.i4.1
// IL_0001: newarr "int"
// IL_0006: dup
// IL_0007: ldc.i4.0
// IL_0008: ldc.i4.s 21
// IL_000a: stelem.i4
// IL_000b: pop
// IL_000c: ldnull
// IL_000d: dup
// IL_000e: ldc.i4.0
// IL_000f: ldelema "int"
// IL_0014: call "int C.F0()"
// IL_0019: stloc.0
// IL_001a: call "System.Threading.Tasks.TaskFactory System.Threading.Tasks.Task.Factory.get"
// IL_001f: ldsfld "System.Func<int> C.<>c.<>9__2_0"
// IL_0024: dup
// IL_0025: brtrue.s IL_003e
// IL_0027: pop
// IL_0028: ldsfld "C.<>c C.<>c.<>9"
// IL_002d: ldftn "int C.<>c.<F2>b__2_0()"
// IL_0033: newobj "System.Func<int>..ctor(object, System.IntPtr)"
// IL_0038: dup
// IL_0039: stsfld "System.Func<int> C.<>c.<>9__2_0"
// IL_003e: callvirt "System.Threading.Tasks.Task<int> System.Threading.Tasks.TaskFactory.StartNew<int>(System.Func<int>)"
// IL_0043: call "int System.Runtime.CompilerServices.AsyncHelpers.Await<int>(System.Threading.Tasks.Task<int>)"
// IL_0048: stloc.1
// IL_0049: ldloc.0
// IL_004a: ldloc.1
// IL_004b: call "void C.F1(ref int, int, int)"
// IL_0050: ldc.i4.0
// IL_0051: ldelem.i4
// IL_0052: ret
// }
// """);
}
[Fact]
public void SpillRefThisStruct()
{
var source = @"
using System;
using System.Threading.Tasks;
struct s1
{
public int X;
public async void Goo1()
{
Bar(ref this, await Task<int>.FromResult(42));
}
public void Goo2()
{
Bar(ref this, 42);
}
public void Bar(ref s1 x, int y)
{
x.X = 42;
}
}
class c1
{
public int X;
public async void Goo1()
{
Bar(this, await Task<int>.FromResult(42));
}
public void Goo2()
{
Bar(this, 42);
}
public void Bar(c1 x, int y)
{
x.X = 42;
}
}
class C
{
public static void Main()
{
{
s1 s;
s.X = -1;
s.Goo1();
Console.WriteLine(s.X);
}
{
s1 s;
s.X = -1;
s.Goo2();
Console.WriteLine(s.X);
}
{
c1 c = new c1();
c.X = -1;
c.Goo1();
Console.WriteLine(c.X);
}
{
c1 c = new c1();
c.X = -1;
c.Goo2();
Console.WriteLine(c.X);
}
}
}";
var expectedOutput = @"
-1
42
42
42
";
CompileAndVerify(source, expectedOutput);
}
[Fact]
public void SpillRefThisStruct_WithTaskAndRuntimeAsync()
{
var source = @"
using System;
using System.Threading.Tasks;
struct s1
{
public int X;
public async Task Goo1()
{
Bar(ref this, await Task<int>.FromResult(42));
}
public void Goo2()
{
Bar(ref this, 42);
}
public void Bar(ref s1 x, int y)
{
x.X = 42;
}
}
class c1
{
public int X;
public async Task Goo1()
{
Bar(this, await Task<int>.FromResult(42));
}
public void Goo2()
{
Bar(this, 42);
}
public void Bar(c1 x, int y)
{
x.X = 42;
}
}
class C
{
public static void Main()
{
{
s1 s;
s.X = -1;
#pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
s.Goo1();
#pragma warning restore CS4014
Console.WriteLine(s.X);
}
{
s1 s;
s.X = -1;
s.Goo2();
Console.WriteLine(s.X);
}
{
c1 c = new c1();
c.X = -1;
#pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
c.Goo1();
#pragma warning restore CS4014
Console.WriteLine(c.X);
}
{
c1 c = new c1();
c.X = -1;
c.Goo2();
Console.WriteLine(c.X);
}
}
}";
var expectedOutput = @"
-1
42
42
42
";
CompileAndVerify(source, expectedOutput);
var comp = CreateRuntimeAsyncCompilation(source);
comp.VerifyEmitDiagnostics(
// (9,23): error CS9328: Method 's1.Goo1()' uses a feature that is not supported by runtime async currently. Opt the method out of runtime async by attributing it with 'System.Runtime.CompilerServices.RuntimeAsyncMethodGenerationAttribute(false)'.
// public async Task Goo1()
Diagnostic(ErrorCode.ERR_UnsupportedFeatureInRuntimeAsync, "Goo1").WithArguments("s1.Goo1()").WithLocation(9, 23)
);
// https://github.com/dotnet/roslyn/issues/79763
// var verifier = CompileAndVerify(comp, expectedOutput: CodeGenAsyncTests.ExpectedOutput(expectedOutput, isRuntimeAsync: true), verify: Verification.Fails with
// {
// ILVerifyMessage = """
// [Goo1]: Return value missing on the stack. { Offset = 0x15 }
// [Goo1]: Return value missing on the stack. { Offset = 0x15 }
// """
// });
// verifier.VerifyDiagnostics();
// verifier.VerifyIL("s1.Goo1()", """
// {
// // Code size 22 (0x16)
// .maxstack 3
// .locals init (int V_0)
// IL_0000: ldc.i4.s 42
// IL_0002: call "System.Threading.Tasks.Task<int> System.Threading.Tasks.Task.FromResult<int>(int)"
// IL_0007: call "int System.Runtime.CompilerServices.AsyncHelpers.Await<int>(System.Threading.Tasks.Task<int>)"
// IL_000c: stloc.0
// IL_000d: ldarg.0
// IL_000e: ldarg.0
// IL_000f: ldloc.0
// IL_0010: call "void s1.Bar(ref s1, int)"
// IL_0015: ret
// }
// """);
// verifier.VerifyIL("c1.Goo1()", """
// {
// // Code size 22 (0x16)
// .maxstack 3
// .locals init (int V_0)
// IL_0000: ldc.i4.s 42
// IL_0002: call "System.Threading.Tasks.Task<int> System.Threading.Tasks.Task.FromResult<int>(int)"
// IL_0007: call "int System.Runtime.CompilerServices.AsyncHelpers.Await<int>(System.Threading.Tasks.Task<int>)"
// IL_000c: stloc.0
// IL_000d: ldarg.0
// IL_000e: ldarg.0
// IL_000f: ldloc.0
// IL_0010: call "void c1.Bar(c1, int)"
// IL_0015: ret
// }
// """);
}
[Fact]
[WorkItem(13734, "https://github.com/dotnet/roslyn/issues/13734")]
public void MethodGroupConversionNoSpill()
{
string source = @"
using System.Threading.Tasks;
using System;
public class AsyncBug {
public static void Main()
{
Boom().GetAwaiter().GetResult();
}
public static async Task Boom()
{
Func<Type> f = (await Task.FromResult(1)).GetType;
Console.WriteLine(f());
}
}
";
// See tracking issue https://github.com/dotnet/runtime/issues/96695
var expectedOutput = "System.Int32";
var verifier = CompileAndVerify(source, expectedOutput: expectedOutput,
verify: Verification.FailsILVerify with { ILVerifyMessage = "[MoveNext]: Unrecognized arguments for delegate .ctor. { Offset = 0x6d }" });
verifier.VerifyIL("AsyncBug.<Boom>d__1.System.Runtime.CompilerServices.IAsyncStateMachine.MoveNext()", """
{
// Code size 169 (0xa9)
.maxstack 3
.locals init (int V_0,
System.Runtime.CompilerServices.TaskAwaiter<int> V_1,
System.Exception V_2)
IL_0000: ldarg.0
IL_0001: ldfld "int AsyncBug.<Boom>d__1.<>1__state"
IL_0006: stloc.0
.try
{
IL_0007: ldloc.0
IL_0008: brfalse.s IL_003f
IL_000a: ldc.i4.1
IL_000b: call "System.Threading.Tasks.Task<int> System.Threading.Tasks.Task.FromResult<int>(int)"
IL_0010: callvirt "System.Runtime.CompilerServices.TaskAwaiter<int> System.Threading.Tasks.Task<int>.GetAwaiter()"
IL_0015: stloc.1
IL_0016: ldloca.s V_1
IL_0018: call "bool System.Runtime.CompilerServices.TaskAwaiter<int>.IsCompleted.get"
IL_001d: brtrue.s IL_005b
IL_001f: ldarg.0
IL_0020: ldc.i4.0
IL_0021: dup
IL_0022: stloc.0
IL_0023: stfld "int AsyncBug.<Boom>d__1.<>1__state"
IL_0028: ldarg.0
IL_0029: ldloc.1
IL_002a: stfld "System.Runtime.CompilerServices.TaskAwaiter<int> AsyncBug.<Boom>d__1.<>u__1"
IL_002f: ldarg.0
IL_0030: ldflda "System.Runtime.CompilerServices.AsyncTaskMethodBuilder AsyncBug.<Boom>d__1.<>t__builder"
IL_0035: ldloca.s V_1
IL_0037: ldarg.0
IL_0038: call "void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.AwaitUnsafeOnCompleted<System.Runtime.CompilerServices.TaskAwaiter<int>, AsyncBug.<Boom>d__1>(ref System.Runtime.CompilerServices.TaskAwaiter<int>, ref AsyncBug.<Boom>d__1)"
IL_003d: leave.s IL_00a8
IL_003f: ldarg.0
IL_0040: ldfld "System.Runtime.CompilerServices.TaskAwaiter<int> AsyncBug.<Boom>d__1.<>u__1"
IL_0045: stloc.1
IL_0046: ldarg.0
IL_0047: ldflda "System.Runtime.CompilerServices.TaskAwaiter<int> AsyncBug.<Boom>d__1.<>u__1"
IL_004c: initobj "System.Runtime.CompilerServices.TaskAwaiter<int>"
IL_0052: ldarg.0
IL_0053: ldc.i4.m1
IL_0054: dup
IL_0055: stloc.0
IL_0056: stfld "int AsyncBug.<Boom>d__1.<>1__state"
IL_005b: ldloca.s V_1
IL_005d: call "int System.Runtime.CompilerServices.TaskAwaiter<int>.GetResult()"
IL_0062: box "int"
IL_0067: ldftn "System.Type object.GetType()"
IL_006d: newobj "System.Func<System.Type>..ctor(object, System.IntPtr)"
IL_0072: callvirt "System.Type System.Func<System.Type>.Invoke()"
IL_0077: call "void System.Console.WriteLine(object)"
IL_007c: leave.s IL_0095
}
catch System.Exception
{
IL_007e: stloc.2
IL_007f: ldarg.0
IL_0080: ldc.i4.s -2
IL_0082: stfld "int AsyncBug.<Boom>d__1.<>1__state"
IL_0087: ldarg.0
IL_0088: ldflda "System.Runtime.CompilerServices.AsyncTaskMethodBuilder AsyncBug.<Boom>d__1.<>t__builder"
IL_008d: ldloc.2
IL_008e: call "void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetException(System.Exception)"
IL_0093: leave.s IL_00a8
}
IL_0095: ldarg.0
IL_0096: ldc.i4.s -2
IL_0098: stfld "int AsyncBug.<Boom>d__1.<>1__state"
IL_009d: ldarg.0
IL_009e: ldflda "System.Runtime.CompilerServices.AsyncTaskMethodBuilder AsyncBug.<Boom>d__1.<>t__builder"
IL_00a3: call "void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetResult()"
IL_00a8: ret
}
""");
var comp = CreateRuntimeAsyncCompilation(source);
verifier = CompileAndVerify(comp, expectedOutput: CodeGenAsyncTests.ExpectedOutput(expectedOutput, isRuntimeAsync: true), verify: Verification.Fails with
{
ILVerifyMessage = """
[Boom]: Unrecognized arguments for delegate .ctor. { Offset = 0x16 }
[Boom]: Return value missing on the stack. { Offset = 0x25 }
"""
});
verifier.VerifyDiagnostics();
verifier.VerifyIL("AsyncBug.Boom()", """
{
// Code size 38 (0x26)
.maxstack 2
IL_0000: ldc.i4.1
IL_0001: call "System.Threading.Tasks.Task<int> System.Threading.Tasks.Task.FromResult<int>(int)"
IL_0006: call "int System.Runtime.CompilerServices.AsyncHelpers.Await<int>(System.Threading.Tasks.Task<int>)"
IL_000b: box "int"
IL_0010: ldftn "System.Type object.GetType()"
IL_0016: newobj "System.Func<System.Type>..ctor(object, System.IntPtr)"
IL_001b: callvirt "System.Type System.Func<System.Type>.Invoke()"
IL_0020: call "void System.Console.WriteLine(object)"
IL_0025: ret
}
""");
}
[Fact]
[WorkItem(13734, "https://github.com/dotnet/roslyn/issues/13734")]
public void MethodGroupConversionWithSpill()
{
string source = @"
using System.Threading.Tasks;
using System;
using System.Linq;
using System.Collections.Generic;
namespace AsyncBug
{
class Program
{
private class SomeClass
{
public bool Method(int value)
{
return value % 2 == 0;
}
}
private async Task<SomeClass> Danger()
{
await Task.Yield();
return new SomeClass();
}
private async Task<IEnumerable<bool>> Killer()
{
return (new int[] {1, 2, 3, 4, 5}).Select((await Danger()).Method);
}
static void Main(string[] args)
{
foreach (var b in new Program().Killer().GetAwaiter().GetResult()) {
Console.WriteLine(b);
}
}
}
}
";
var expectedOutput = new bool[] { false, true, false, true, false }.Aggregate("", (str, next) => str += $"{next}{Environment.NewLine}");
var v = CompileAndVerify(source, expectedOutput);
var comp = CreateRuntimeAsyncCompilation(source);
var verifier = CompileAndVerify(comp, expectedOutput: CodeGenAsyncTests.ExpectedOutput(expectedOutput, isRuntimeAsync: true), verify: Verification.Fails with
{
ILVerifyMessage = """
[Danger]: Unexpected type on the stack. { Offset = 0x29, Found = ref 'AsyncBug.Program+SomeClass', Expected = ref '[System.Runtime]System.Threading.Tasks.Task`1<AsyncBug.Program+SomeClass>' }
[Killer]: Unexpected type on the stack. { Offset = 0x2e, Found = ref '[System.Runtime]System.Collections.Generic.IEnumerable`1<bool>', Expected = ref '[System.Runtime]System.Threading.Tasks.Task`1<System.Collections.Generic.IEnumerable`1<bool>>' }
"""
});
verifier.VerifyDiagnostics();
verifier.VerifyIL("AsyncBug.Program.Killer()", """
{
// Code size 47 (0x2f)
.maxstack 3
.locals init (AsyncBug.Program.SomeClass V_0)
IL_0000: ldc.i4.5
IL_0001: newarr "int"
IL_0006: dup
IL_0007: ldtoken "<PrivateImplementationDetails>.__StaticArrayInitTypeSize=20 <PrivateImplementationDetails>.4F6ADDC9659D6FB90FE94B6688A79F2A1FA8D36EC43F8F3E1D9B6528C448A384"
IL_000c: call "void System.Runtime.CompilerServices.RuntimeHelpers.InitializeArray(System.Array, System.RuntimeFieldHandle)"
IL_0011: ldarg.0
IL_0012: call "System.Threading.Tasks.Task<AsyncBug.Program.SomeClass> AsyncBug.Program.Danger()"
IL_0017: call "AsyncBug.Program.SomeClass System.Runtime.CompilerServices.AsyncHelpers.Await<AsyncBug.Program.SomeClass>(System.Threading.Tasks.Task<AsyncBug.Program.SomeClass>)"
IL_001c: stloc.0
IL_001d: ldloc.0
IL_001e: ldftn "bool AsyncBug.Program.SomeClass.Method(int)"
IL_0024: newobj "System.Func<int, bool>..ctor(object, System.IntPtr)"
IL_0029: call "System.Collections.Generic.IEnumerable<bool> System.Linq.Enumerable.Select<int, bool>(System.Collections.Generic.IEnumerable<int>, System.Func<int, bool>)"
IL_002e: ret
}
""");
}
[Fact]
[WorkItem(17706, "https://github.com/dotnet/roslyn/issues/17706")]
public void SpillAwaitBeforeRefReordered()
{
string source = @"
using System.Threading.Tasks;
public class C
{
private static int i;
static ref int P => ref i;
static void Assign(ref int first, int second)
{
first = second;
}
public static async Task M(Task<int> t)
{
// OK: await goes before the ref
Assign(second: await t, first: ref P);
}
public static void Main()
{
M(Task.FromResult(42)).Wait();
System.Console.WriteLine(i);
}
}
";
var v = CompileAndVerify(source, "42");
var comp = CreateRuntimeAsyncCompilation(source);
var verifier = CompileAndVerify(comp, verify: Verification.Fails with
{
ILVerifyMessage = """
[M]: Return value missing on the stack. { Offset = 0x12 }
"""
});
verifier.VerifyDiagnostics();
verifier.VerifyIL("C.M(System.Threading.Tasks.Task<int>)", """
{
// Code size 19 (0x13)
.maxstack 2
.locals init (int V_0)
IL_0000: ldarg.0
IL_0001: call "int System.Runtime.CompilerServices.AsyncHelpers.Await<int>(System.Threading.Tasks.Task<int>)"
IL_0006: stloc.0
IL_0007: call "ref int C.P.get"
IL_000c: ldloc.0
IL_000d: call "void C.Assign(ref int, int)"
IL_0012: ret
}
""");
}
[Fact]
[WorkItem(17706, "https://github.com/dotnet/roslyn/issues/17706")]
public void SpillRefBeforeAwaitReordered()
{
string source = @"
using System.Threading.Tasks;
public class C
{
private static int i;
static ref int P => ref i;
static void Assign(int first, ref int second)
{
second = first;
}
public static async Task M(Task<int> t)
{
// ERROR: await goes after the ref
Assign(second: ref P, first: await t);
}
public static void Main()
{
M(Task.FromResult(42)).Wait();
System.Console.WriteLine(i);
}
}
";
var comp = CreateCompilationWithMscorlib46(source, options: TestOptions.ReleaseExe);
comp.VerifyEmitDiagnostics(
// (18,28): error CS8178: A reference returned by a call to 'C.P.get' cannot be preserved across 'await' or 'yield' boundary.
// Assign(second: ref P, first: await t);
Diagnostic(ErrorCode.ERR_RefReturningCallAndAwait, "P").WithArguments("C.P.get").WithLocation(18, 28)
);
}
[Fact]
[WorkItem(27831, "https://github.com/dotnet/roslyn/issues/27831")]
public void AwaitWithInParameter_ArgModifier()
{
CreateCompilation(@"
using System.Threading.Tasks;
class Foo
{
async Task A(string s, Task<int> task)
{
C(in s, await task);
}
void C(in object obj, int length) {}
}").VerifyDiagnostics(
// (7,14): error CS1503: Argument 1: cannot convert from 'in string' to 'in object'
// C(in s, await task);
Diagnostic(ErrorCode.ERR_BadArgType, "s").WithArguments("1", "in string", "in object").WithLocation(7, 14));
}
[Fact]
[WorkItem(27831, "https://github.com/dotnet/roslyn/issues/27831")]
public void AwaitWithInParameter_NoArgModifier()
{
var source = """
using System;
using System.Threading.Tasks;
class Goo
{
static async Task Main()
{
await A("test", Task.FromResult(4));
}
static async Task A(string s, Task<int> task)
{
B(s, await task);
}
static void B(in object obj, int v)
{
Console.WriteLine(obj);
Console.WriteLine(v);
}
}
""";
var expectedOutput = """
test
4
""";
CompileAndVerify(source, expectedOutput: expectedOutput);
var comp = CreateRuntimeAsyncCompilation(source);
var verifier = CompileAndVerify(comp, expectedOutput: CodeGenAsyncTests.ExpectedOutput(expectedOutput, isRuntimeAsync: true), verify: Verification.Fails with
{
ILVerifyMessage = """
[Main]: Return value missing on the stack. { Offset = 0x15 }
[A]: Return value missing on the stack. { Offset = 0x11 }
"""
});
verifier.VerifyDiagnostics();
verifier.VerifyIL("Goo.A(string, System.Threading.Tasks.Task<int>)", """
{
// Code size 18 (0x12)
.maxstack 2
.locals init (object V_0,
int V_1)
IL_0000: ldarg.0
IL_0001: stloc.0
IL_0002: ldarg.1
IL_0003: call "int System.Runtime.CompilerServices.AsyncHelpers.Await<int>(System.Threading.Tasks.Task<int>)"
IL_0008: stloc.1
IL_0009: ldloca.s V_0
IL_000b: ldloc.1
IL_000c: call "void Goo.B(in object, int)"
IL_0011: ret
}
""");
}
[Fact, WorkItem(36856, "https://github.com/dotnet/roslyn/issues/36856")]
public void Crash36856()
{
var source = @"
using System.Threading.Tasks;
class Program
{
static void Main(string[] args)
{
}
private static async Task Serialize()
{
System.Text.Json.Serialization.JsonSerializer.Parse<string>(await TestAsync());
}
private static Task<byte[]> TestAsync()
{
return null;
}
}
namespace System.Text.Json.Serialization
{
public static class JsonSerializer
{
public static TValue Parse<TValue>(ReadOnlySpan<byte> utf8Json, JsonSerializerOptions options = null)
{
throw null;
}
}
public sealed class JsonSerializerOptions
{
}
}
";
var span = @"
namespace System
{
public readonly ref struct ReadOnlySpan<T>
{
public static implicit operator ReadOnlySpan<T>(T[] array)
{
throw null;
}
}
}
";
var v = CompileAndVerify(source + span, options: TestOptions.DebugExe);
v.VerifyMethodBody("Program.<Serialize>d__1.System.Runtime.CompilerServices.IAsyncStateMachine.MoveNext()", @"
{
// Code size 184 (0xb8)
.maxstack 3
.locals init (int V_0,
System.Runtime.CompilerServices.TaskAwaiter<byte[]> V_1,
Program.<Serialize>d__1 V_2,
System.Exception V_3)
// sequence point: <hidden>
IL_0000: ldarg.0
IL_0001: ldfld ""int Program.<Serialize>d__1.<>1__state""
IL_0006: stloc.0
.try
{
// sequence point: <hidden>
IL_0007: ldloc.0
IL_0008: brfalse.s IL_000c
IL_000a: br.s IL_000e
IL_000c: br.s IL_0047
// sequence point: {
IL_000e: nop
// sequence point: System.Text.Json.Serialization.JsonSerializer.Parse<string>(await TestAsync());
IL_000f: call ""System.Threading.Tasks.Task<byte[]> Program.TestAsync()""
IL_0014: callvirt ""System.Runtime.CompilerServices.TaskAwaiter<byte[]> System.Threading.Tasks.Task<byte[]>.GetAwaiter()""
IL_0019: stloc.1
// sequence point: <hidden>
IL_001a: ldloca.s V_1
IL_001c: call ""bool System.Runtime.CompilerServices.TaskAwaiter<byte[]>.IsCompleted.get""
IL_0021: brtrue.s IL_0063
IL_0023: ldarg.0
IL_0024: ldc.i4.0
IL_0025: dup
IL_0026: stloc.0
IL_0027: stfld ""int Program.<Serialize>d__1.<>1__state""
// async: yield
IL_002c: ldarg.0
IL_002d: ldloc.1
IL_002e: stfld ""System.Runtime.CompilerServices.TaskAwaiter<byte[]> Program.<Serialize>d__1.<>u__1""
IL_0033: ldarg.0
IL_0034: stloc.2
IL_0035: ldarg.0
IL_0036: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.<Serialize>d__1.<>t__builder""
IL_003b: ldloca.s V_1
IL_003d: ldloca.s V_2
IL_003f: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.AwaitUnsafeOnCompleted<System.Runtime.CompilerServices.TaskAwaiter<byte[]>, Program.<Serialize>d__1>(ref System.Runtime.CompilerServices.TaskAwaiter<byte[]>, ref Program.<Serialize>d__1)""
IL_0044: nop
IL_0045: leave.s IL_00b7
// async: resume
IL_0047: ldarg.0
IL_0048: ldfld ""System.Runtime.CompilerServices.TaskAwaiter<byte[]> Program.<Serialize>d__1.<>u__1""
IL_004d: stloc.1
IL_004e: ldarg.0
IL_004f: ldflda ""System.Runtime.CompilerServices.TaskAwaiter<byte[]> Program.<Serialize>d__1.<>u__1""
IL_0054: initobj ""System.Runtime.CompilerServices.TaskAwaiter<byte[]>""
IL_005a: ldarg.0
IL_005b: ldc.i4.m1
IL_005c: dup
IL_005d: stloc.0
IL_005e: stfld ""int Program.<Serialize>d__1.<>1__state""
IL_0063: ldarg.0
IL_0064: ldloca.s V_1
IL_0066: call ""byte[] System.Runtime.CompilerServices.TaskAwaiter<byte[]>.GetResult()""
IL_006b: stfld ""byte[] Program.<Serialize>d__1.<>s__1""
IL_0070: ldarg.0
IL_0071: ldfld ""byte[] Program.<Serialize>d__1.<>s__1""
IL_0076: call ""System.ReadOnlySpan<byte> System.ReadOnlySpan<byte>.op_Implicit(byte[])""
IL_007b: ldnull
IL_007c: call ""string System.Text.Json.Serialization.JsonSerializer.Parse<string>(System.ReadOnlySpan<byte>, System.Text.Json.Serialization.JsonSerializerOptions)""
IL_0081: pop
IL_0082: ldarg.0
IL_0083: ldnull
IL_0084: stfld ""byte[] Program.<Serialize>d__1.<>s__1""
IL_0089: leave.s IL_00a3
}
catch System.Exception
{
// sequence point: <hidden>
IL_008b: stloc.3
IL_008c: ldarg.0
IL_008d: ldc.i4.s -2
IL_008f: stfld ""int Program.<Serialize>d__1.<>1__state""
IL_0094: ldarg.0
IL_0095: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.<Serialize>d__1.<>t__builder""
IL_009a: ldloc.3
IL_009b: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetException(System.Exception)""
IL_00a0: nop
IL_00a1: leave.s IL_00b7
}
// sequence point: }
IL_00a3: ldarg.0
IL_00a4: ldc.i4.s -2
IL_00a6: stfld ""int Program.<Serialize>d__1.<>1__state""
// sequence point: <hidden>
IL_00ab: ldarg.0
IL_00ac: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.<Serialize>d__1.<>t__builder""
IL_00b1: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetResult()""
IL_00b6: nop
IL_00b7: ret
}
");
var comp = CreateRuntimeAsyncCompilation(source);
var verifier = CompileAndVerify(comp, verify: Verification.Fails with
{
ILVerifyMessage = """
[Serialize]: Return value missing on the stack. { Offset = 0x16 }
"""
});
verifier.VerifyDiagnostics();
verifier.VerifyIL("Program.Serialize()", """
{
// Code size 23 (0x17)
.maxstack 2
IL_0000: call "System.Threading.Tasks.Task<byte[]> Program.TestAsync()"
IL_0005: call "byte[] System.Runtime.CompilerServices.AsyncHelpers.Await<byte[]>(System.Threading.Tasks.Task<byte[]>)"
IL_000a: call "System.ReadOnlySpan<byte> System.ReadOnlySpan<byte>.op_Implicit(byte[])"
IL_000f: ldnull
IL_0010: call "string System.Text.Json.Serialization.JsonSerializer.Parse<string>(System.ReadOnlySpan<byte>, System.Text.Json.Serialization.JsonSerializerOptions)"
IL_0015: pop
IL_0016: ret
}
""");
}
[Fact, WorkItem(37461, "https://github.com/dotnet/roslyn/issues/37461")]
public void ShouldNotSpillStackallocToField_01()
{
var source = @"
using System;
using System.Threading.Tasks;
public class P
{
static async Task Main()
{
await Async1(F1(), G(F2(), stackalloc int[] { 40, 500, 6000 }));
}
static int F1() => 70000;
static int F2() => 800000;
static int G(int k, Span<int> span) => k + span.Length + span[0] + span[1] + span[2];
static Task Async1(int k, int i)
{
Console.WriteLine(k + i);
return Task.Delay(1);
}
}
";
var expectedOutput = @"876543";
var comp = CreateCompilationWithMscorlibAndSpan(source, options: TestOptions.DebugExe);
comp.VerifyDiagnostics();
var v = CompileAndVerify(
compilation: comp,
expectedOutput: expectedOutput,
verify: Verification.Fails // localloc is not verifiable.
);
comp = CreateCompilationWithMscorlibAndSpan(source, options: TestOptions.ReleaseExe);
comp.VerifyDiagnostics();
v = CompileAndVerify(
compilation: comp,
expectedOutput: expectedOutput,
verify: Verification.Fails // localloc is not verifiable.
);
comp = CreateRuntimeAsyncCompilation(source);
var verifier = CompileAndVerify(comp, expectedOutput: CodeGenAsyncTests.ExpectedOutput(expectedOutput, isRuntimeAsync: true), verify: Verification.Fails with
{
ILVerifyMessage = """
[Main]: Instruction cannot be verified. { Offset = 0xf }
[Main]: Instruction cannot be verified. { Offset = 0x2a }
[Main]: Return value missing on the stack. { Offset = 0x45 }
"""
});
verifier.VerifyDiagnostics();
verifier.VerifyIL("P.Main()", """
{
// Code size 70 (0x46)
.maxstack 4
.locals init (int V_0,
int V_1,
System.Span<int> V_2,
System.ReadOnlySpan<int> V_3)
IL_0000: call "int P.F1()"
IL_0005: stloc.0
IL_0006: call "int P.F2()"
IL_000b: stloc.1
IL_000c: ldc.i4.s 12
IL_000e: conv.u
IL_000f: localloc
IL_0011: dup
IL_0012: ldtoken "<PrivateImplementationDetails>.__StaticArrayInitTypeSize=12_Align=4 <PrivateImplementationDetails>.358467287387D6976FA2AD2813A4D1AE4F0A0865C5125FB87D822D9432AA423D4"
IL_0017: call "System.ReadOnlySpan<int> System.Runtime.CompilerServices.RuntimeHelpers.CreateSpan<int>(System.RuntimeFieldHandle)"
IL_001c: stloc.3
IL_001d: ldloca.s V_3
IL_001f: ldc.i4.0
IL_0020: call "ref readonly int System.ReadOnlySpan<int>.this[int].get"
IL_0025: ldc.i4.s 12
IL_0027: unaligned. 4
IL_002a: cpblk
IL_002c: ldc.i4.3
IL_002d: newobj "System.Span<int>..ctor(void*, int)"
IL_0032: stloc.2
IL_0033: ldloc.0
IL_0034: ldloc.1
IL_0035: ldloc.2
IL_0036: call "int P.G(int, System.Span<int>)"
IL_003b: call "System.Threading.Tasks.Task P.Async1(int, int)"
IL_0040: call "void System.Runtime.CompilerServices.AsyncHelpers.Await(System.Threading.Tasks.Task)"
IL_0045: ret
}
""");
}
[Fact, WorkItem(37461, "https://github.com/dotnet/roslyn/issues/37461")]
public void ShouldNotSpillStackallocToField_02()
{
var source = @"
using System;
using System.Threading.Tasks;
public class P
{
static async Task Main()
{
await Async1(F1(), G(F2(), stackalloc int[] { 40, await Task.FromResult(500), 6000 }));
}
static int F1() => 70000;
static int F2() => 800000;
static int G(int k, Span<int> span) => k + span.Length + span[0] + span[1] + span[2];
static Task Async1(int k, int i)
{
Console.WriteLine(k + i);
return Task.Delay(1);
}
}
";
var expectedOutput = @"876543";
var comp = CreateCompilationWithMscorlibAndSpan(source, options: TestOptions.DebugExe);
comp.VerifyDiagnostics();
var v = CompileAndVerify(
compilation: comp,
expectedOutput: expectedOutput,
verify: Verification.Fails // localloc is not verifiable.
);
comp = CreateCompilationWithMscorlibAndSpan(source, options: TestOptions.ReleaseExe);
comp.VerifyDiagnostics();
v = CompileAndVerify(
compilation: comp,
expectedOutput: expectedOutput,
verify: Verification.Fails // localloc is not verifiable.
);
comp = CreateRuntimeAsyncCompilation(source);
var verifier = CompileAndVerify(comp, expectedOutput: CodeGenAsyncTests.ExpectedOutput(expectedOutput, isRuntimeAsync: true), verify: Verification.Fails with
{
ILVerifyMessage = """
[Main]: Instruction cannot be verified. { Offset = 0x1f }
[Main]: Expected ByRef on the stack. { Offset = 0x24, Found = Native Int }
"""
});
verifier.VerifyDiagnostics();
verifier.VerifyIL("P.Main()", """
{
// Code size 80 (0x50)
.maxstack 4
.locals init (int V_0,
int V_1,
System.Span<int> V_2,
int V_3)
IL_0000: call "int P.F1()"
IL_0005: stloc.0
IL_0006: call "int P.F2()"
IL_000b: stloc.1
IL_000c: ldc.i4 0x1f4
IL_0011: call "System.Threading.Tasks.Task<int> System.Threading.Tasks.Task.FromResult<int>(int)"
IL_0016: call "int System.Runtime.CompilerServices.AsyncHelpers.Await<int>(System.Threading.Tasks.Task<int>)"
IL_001b: stloc.3
IL_001c: ldc.i4.s 12
IL_001e: conv.u
IL_001f: localloc
IL_0021: dup
IL_0022: ldc.i4.s 40
IL_0024: stind.i4
IL_0025: dup
IL_0026: ldc.i4.4
IL_0027: add
IL_0028: ldloc.3
IL_0029: stind.i4
IL_002a: dup
IL_002b: ldc.i4.2
IL_002c: conv.i
IL_002d: ldc.i4.4
IL_002e: mul
IL_002f: add
IL_0030: ldc.i4 0x1770
IL_0035: stind.i4
IL_0036: ldc.i4.3
IL_0037: newobj "System.Span<int>..ctor(void*, int)"
IL_003c: stloc.2
IL_003d: ldloc.0
IL_003e: ldloc.1
IL_003f: ldloc.2
IL_0040: call "int P.G(int, System.Span<int>)"
IL_0045: call "System.Threading.Tasks.Task P.Async1(int, int)"
IL_004a: call "void System.Runtime.CompilerServices.AsyncHelpers.Await(System.Threading.Tasks.Task)"
IL_004f: ret
}
""");
}
[Fact, WorkItem(37461, "https://github.com/dotnet/roslyn/issues/37461")]
public void ShouldNotSpillStackallocToField_03()
{
var source = @"
using System;
using System.Threading.Tasks;
public class P
{
static async Task Main()
{
await Async1(F1(), G(F2(), stackalloc int[] { 1, 2, 3 }, await F3()));
}
static object F1() => 1;
static object F2() => 1;
static Task<object> F3() => Task.FromResult<object>(1);
static int G(object obj, Span<int> span, object o2) => span.Length;
static async Task Async1(Object obj, int i) { await Task.Delay(1); }
}
";
foreach (var options in new[] { TestOptions.DebugExe, TestOptions.ReleaseExe })
{
var comp = CreateCompilationWithMscorlibAndSpan(source, options: options);
comp.VerifyDiagnostics();
comp.VerifyEmitDiagnostics(
// (8,5): error CS4007: Instance of type 'System.Span<int>' cannot be preserved across 'await' or 'yield' boundary.
// {
Diagnostic(ErrorCode.ERR_ByRefTypeAndAwait, @"{
await Async1(F1(), G(F2(), stackalloc int[] { 1, 2, 3 }, await F3()));
}").WithArguments("System.Span<int>").WithLocation(8, 5)
);
}
}
[Fact]
public void SpillStateMachineTemps()
{
var source = @"using System;
using System.Threading.Tasks;
public class C {
public static void Main()
{
Console.WriteLine(M1(new Q(), SF()).Result);
}
public static async Task<int> M1(object o, Task<bool> c)
{
return o switch
{
Q { F: { P1: true } } when await c => 1, // cached Q.F is alive
Q { F: { P2: true } } => 2,
_ => 3,
};
}
public static async Task<bool> SF()
{
await Task.Delay(10);
return false;
}
}
class Q
{
public F F => new F(true);
}
struct F
{
bool _result;
public F(bool result)
{
_result = result;
}
public bool P1 => _result;
public bool P2 => _result;
}
";
var expectedOutput = "2";
CompileAndVerify(source, options: TestOptions.ReleaseExe, expectedOutput: expectedOutput);
CompileAndVerify(source, options: TestOptions.DebugExe, expectedOutput: expectedOutput);
var comp = CreateRuntimeAsyncCompilation(source);
var verifier = CompileAndVerify(comp, expectedOutput: CodeGenAsyncTests.ExpectedOutput(expectedOutput, isRuntimeAsync: true), verify: Verification.Fails with
{
ILVerifyMessage = """
[M1]: Unexpected type on the stack. { Offset = 0x38, Found = Int32, Expected = ref '[System.Runtime]System.Threading.Tasks.Task`1<int32>' }
[SF]: Unexpected type on the stack. { Offset = 0xd, Found = Int32, Expected = ref '[System.Runtime]System.Threading.Tasks.Task`1<bool>' }
"""
});
verifier.VerifyDiagnostics();
verifier.VerifyIL("C.M1(object, System.Threading.Tasks.Task<bool>)", """
{
// Code size 57 (0x39)
.maxstack 1
.locals init (int V_0,
Q V_1,
F V_2)
IL_0000: ldarg.0
IL_0001: isinst "Q"
IL_0006: stloc.1
IL_0007: ldloc.1
IL_0008: brfalse.s IL_0035
IL_000a: ldloc.1
IL_000b: callvirt "F Q.F.get"
IL_0010: stloc.2
IL_0011: ldloca.s V_2
IL_0013: call "bool F.P1.get"
IL_0018: brtrue.s IL_0025
IL_001a: ldloca.s V_2
IL_001c: call "bool F.P2.get"
IL_0021: brtrue.s IL_0031
IL_0023: br.s IL_0035
IL_0025: ldarg.1
IL_0026: call "bool System.Runtime.CompilerServices.AsyncHelpers.Await<bool>(System.Threading.Tasks.Task<bool>)"
IL_002b: brfalse.s IL_001a
IL_002d: ldc.i4.1
IL_002e: stloc.0
IL_002f: br.s IL_0037
IL_0031: ldc.i4.2
IL_0032: stloc.0
IL_0033: br.s IL_0037
IL_0035: ldc.i4.3
IL_0036: stloc.0
IL_0037: ldloc.0
IL_0038: ret
}
""");
}
[Fact]
[WorkItem(37713, "https://github.com/dotnet/roslyn/issues/37713")]
public void RefStructInAsyncStateMachineWithWhenClause()
{
var source = @"
using System.Threading.Tasks;
class Program
{
async Task<int> M1(object o, Task<bool> c, int r)
{
return o switch
{
Q { F: { P1: true } } when await c => r, // error: cached Q.F is alive
Q { F: { P2: true } } => 2,
_ => 3,
};
}
async Task<int> M2(object o, Task<bool> c, int r)
{
return o switch
{
Q { F: { P1: true } } when await c => r, // ok: only Q.P1 is live
Q { F: { P1: true } } => 2,
_ => 3,
};
}
async Task<int> M3(object o, bool c, Task<int> r)
{
return o switch
{
Q { F: { P1: true } } when c => await r, // ok: nothing alive at await
Q { F: { P2: true } } => 2,
_ => 3,
};
}
async Task<int> M4(object o, Task<bool> c, int r)
{
return o switch
{
Q { F: { P1: true } } when await c => r, // ok: no switch state is alive
_ => 3,
};
}
}
public class Q
{
public S F => throw null!;
}
public ref struct S
{
public bool P1 => true;
public bool P2 => true;
}
";
var expectedDiagnostics = new[]
{
// (9,17): error CS4007: Instance of type 'S' cannot be preserved across 'await' or 'yield' boundary.
// Q { F: { P1: true } } when await c => r, // error: cached Q.F is alive
Diagnostic(ErrorCode.ERR_ByRefTypeAndAwait, "F").WithArguments("S").WithLocation(9, 17)
};
CreateCompilation(source, options: TestOptions.DebugDll).VerifyDiagnostics().VerifyEmitDiagnostics(expectedDiagnostics);
CreateCompilation(source, options: TestOptions.ReleaseDll).VerifyDiagnostics().VerifyEmitDiagnostics(expectedDiagnostics);
}
[Fact]
[WorkItem(37783, "https://github.com/dotnet/roslyn/issues/37783")]
public void ExpressionLambdaWithObjectInitializer()
{
var source =
@"using System;
using System.Linq.Expressions;
using System.Threading.Tasks;
class Program
{
public static async Task Main()
{
int value = 42;
Console.WriteLine(await M(() => new Box<int>() { Value = value }));
}
static Task<int> M(Expression<Func<Box<int>>> e)
{
return Task.FromResult(e.Compile()().Value);
}
}
class Box<T>
{
public T Value;
}
";
var expectedOutput = "42";
CompileAndVerify(source, expectedOutput: expectedOutput, options: TestOptions.DebugExe);
CompileAndVerify(source, expectedOutput: expectedOutput, options: TestOptions.ReleaseExe);
var comp = CreateRuntimeAsyncCompilation(source);
var verifier = CompileAndVerify(comp, expectedOutput: CodeGenAsyncTests.ExpectedOutput(expectedOutput, isRuntimeAsync: true), verify: Verification.Fails with
{
ILVerifyMessage = """
[Main]: Return value missing on the stack. { Offset = 0x77 }
"""
});
verifier.VerifyDiagnostics();
verifier.VerifyIL("Program.Main()", """
{
// Code size 120 (0x78)
.maxstack 7
.locals init (Program.<>c__DisplayClass0_0 V_0) //CS$<>8__locals0
IL_0000: newobj "Program.<>c__DisplayClass0_0..ctor()"
IL_0005: stloc.0
IL_0006: ldloc.0
IL_0007: ldc.i4.s 42
IL_0009: stfld "int Program.<>c__DisplayClass0_0.value"
IL_000e: ldtoken "Box<int>"
IL_0013: call "System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"
IL_0018: call "System.Linq.Expressions.NewExpression System.Linq.Expressions.Expression.New(System.Type)"
IL_001d: ldc.i4.1
IL_001e: newarr "System.Linq.Expressions.MemberBinding"
IL_0023: dup
IL_0024: ldc.i4.0
IL_0025: ldtoken "int Box<int>.Value"
IL_002a: ldtoken "Box<int>"
IL_002f: call "System.Reflection.FieldInfo System.Reflection.FieldInfo.GetFieldFromHandle(System.RuntimeFieldHandle, System.RuntimeTypeHandle)"
IL_0034: ldloc.0
IL_0035: ldtoken "Program.<>c__DisplayClass0_0"
IL_003a: call "System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"
IL_003f: call "System.Linq.Expressions.ConstantExpression System.Linq.Expressions.Expression.Constant(object, System.Type)"
IL_0044: ldtoken "int Program.<>c__DisplayClass0_0.value"
IL_0049: call "System.Reflection.FieldInfo System.Reflection.FieldInfo.GetFieldFromHandle(System.RuntimeFieldHandle)"
IL_004e: call "System.Linq.Expressions.MemberExpression System.Linq.Expressions.Expression.Field(System.Linq.Expressions.Expression, System.Reflection.FieldInfo)"
IL_0053: call "System.Linq.Expressions.MemberAssignment System.Linq.Expressions.Expression.Bind(System.Reflection.MemberInfo, System.Linq.Expressions.Expression)"
IL_0058: stelem.ref
IL_0059: call "System.Linq.Expressions.MemberInitExpression System.Linq.Expressions.Expression.MemberInit(System.Linq.Expressions.NewExpression, params System.Linq.Expressions.MemberBinding[])"
IL_005e: call "System.Linq.Expressions.ParameterExpression[] System.Array.Empty<System.Linq.Expressions.ParameterExpression>()"
IL_0063: call "System.Linq.Expressions.Expression<System.Func<Box<int>>> System.Linq.Expressions.Expression.Lambda<System.Func<Box<int>>>(System.Linq.Expressions.Expression, params System.Linq.Expressions.ParameterExpression[])"
IL_0068: call "System.Threading.Tasks.Task<int> Program.M(System.Linq.Expressions.Expression<System.Func<Box<int>>>)"
IL_006d: call "int System.Runtime.CompilerServices.AsyncHelpers.Await<int>(System.Threading.Tasks.Task<int>)"
IL_0072: call "void System.Console.WriteLine(int)"
IL_0077: ret
}
""");
}
[Fact]
[WorkItem(38309, "https://github.com/dotnet/roslyn/issues/38309")]
public void ExpressionLambdaWithUserDefinedControlFlow()
{
var source =
@"using System;
using System.Linq.Expressions;
using System.Threading.Tasks;
namespace RoslynFailFastReproduction
{
static class Program
{
static async Task Main(string[] args)
{
await MainAsync(args);
}
static async Task MainAsync(string[] args)
{
Expression<Func<AltBoolean, AltBoolean>> expr = x => x && x;
var result = await Task.FromResult(true);
Console.WriteLine(result);
}
class AltBoolean
{
public static AltBoolean operator &(AltBoolean x, AltBoolean y) => default;
public static bool operator true(AltBoolean x) => default;
public static bool operator false(AltBoolean x) => default;
}
}
}
";
var expectedOutput = "True";
CompileAndVerify(source, expectedOutput: expectedOutput, options: TestOptions.DebugExe);
CompileAndVerify(source, expectedOutput: expectedOutput, options: TestOptions.ReleaseExe);
var comp = CreateRuntimeAsyncCompilation(source);
var verifier = CompileAndVerify(comp, expectedOutput: CodeGenAsyncTests.ExpectedOutput(expectedOutput, isRuntimeAsync: true), verify: Verification.Fails with
{
ILVerifyMessage = """
[Main]: Return value missing on the stack. { Offset = 0xb }
[MainAsync]: Return value missing on the stack. { Offset = 0x4b }
"""
});
}
[Fact]
[WorkItem(42755, "https://github.com/dotnet/roslyn/issues/42755")]
public void KeepLtrSemantics_ClassFieldAccessOnProperty()
{
var source = @"
using System;
using System.Threading.Tasks;
class Program
{
static async Task Assign(A a)
{
a.B.x = await Write(""RHS"");
}
static async Task Main(string[] args)
{
await TestPropertyAccessThrows();
await TestFieldAccessThrows();
await TestPropertyAccessSucceeds();
}
static async Task TestPropertyAccessThrows()
{
Console.WriteLine(nameof(TestPropertyAccessThrows));
A a = null;
Console.WriteLine(""Before Assignment"");
try
{
await Assign(a);
}
catch (NullReferenceException)
{
Console.WriteLine(""Caught NullReferenceException"");
}
}
static async Task TestFieldAccessThrows()
{
Console.WriteLine(nameof(TestFieldAccessThrows));
var a = new A();
Console.WriteLine(""Before Assignment"");
try
{
await Assign(a);
}
catch (NullReferenceException)
{
Console.WriteLine(""Caught NullReferenceException"");
}
}
static async Task TestPropertyAccessSucceeds()
{
Console.WriteLine(nameof(TestPropertyAccessSucceeds));
var a = new A{ B = new B() };
Console.WriteLine(""Before Assignment a.B.x is: "" + a.B.x);
await Assign(a);
Console.WriteLine(""After Assignment a.B.x is: "" + a.B.x);
}
static async Task<int> Write(string s)
{
await Task.Yield();
Console.WriteLine(s);
return 42;
}
}
class A
{
public B B { get; set; }
}
class B
{
public int x;
}";
var comp = CreateCompilation(source, options: TestOptions.ReleaseExe);
var expectedOutput = """
TestPropertyAccessThrows
Before Assignment
Caught NullReferenceException
TestFieldAccessThrows
Before Assignment
RHS
Caught NullReferenceException
TestPropertyAccessSucceeds
Before Assignment a.B.x is: 0
RHS
After Assignment a.B.x is: 42
""";
CompileAndVerify(comp, expectedOutput: expectedOutput)
.VerifyIL("Program.<Assign>d__0.System.Runtime.CompilerServices.IAsyncStateMachine.MoveNext", @"
{
// Code size 184 (0xb8)
.maxstack 3
.locals init (int V_0,
int V_1,
System.Runtime.CompilerServices.TaskAwaiter<int> V_2,
System.Exception V_3)
IL_0000: ldarg.0
IL_0001: ldfld ""int Program.<Assign>d__0.<>1__state""
IL_0006: stloc.0
.try
{
IL_0007: ldloc.0
IL_0008: brfalse.s IL_0054
IL_000a: ldarg.0
IL_000b: ldarg.0
IL_000c: ldfld ""A Program.<Assign>d__0.a""
IL_0011: callvirt ""B A.B.get""
IL_0016: stfld ""B Program.<Assign>d__0.<>7__wrap1""
IL_001b: ldstr ""RHS""
IL_0020: call ""System.Threading.Tasks.Task<int> Program.Write(string)""
IL_0025: callvirt ""System.Runtime.CompilerServices.TaskAwaiter<int> System.Threading.Tasks.Task<int>.GetAwaiter()""
IL_002a: stloc.2
IL_002b: ldloca.s V_2
IL_002d: call ""bool System.Runtime.CompilerServices.TaskAwaiter<int>.IsCompleted.get""
IL_0032: brtrue.s IL_0070
IL_0034: ldarg.0
IL_0035: ldc.i4.0
IL_0036: dup
IL_0037: stloc.0
IL_0038: stfld ""int Program.<Assign>d__0.<>1__state""
IL_003d: ldarg.0
IL_003e: ldloc.2
IL_003f: stfld ""System.Runtime.CompilerServices.TaskAwaiter<int> Program.<Assign>d__0.<>u__1""
IL_0044: ldarg.0
IL_0045: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.<Assign>d__0.<>t__builder""
IL_004a: ldloca.s V_2
IL_004c: ldarg.0
IL_004d: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.AwaitUnsafeOnCompleted<System.Runtime.CompilerServices.TaskAwaiter<int>, Program.<Assign>d__0>(ref System.Runtime.CompilerServices.TaskAwaiter<int>, ref Program.<Assign>d__0)""
IL_0052: leave.s IL_00b7
IL_0054: ldarg.0
IL_0055: ldfld ""System.Runtime.CompilerServices.TaskAwaiter<int> Program.<Assign>d__0.<>u__1""
IL_005a: stloc.2
IL_005b: ldarg.0
IL_005c: ldflda ""System.Runtime.CompilerServices.TaskAwaiter<int> Program.<Assign>d__0.<>u__1""
IL_0061: initobj ""System.Runtime.CompilerServices.TaskAwaiter<int>""
IL_0067: ldarg.0
IL_0068: ldc.i4.m1
IL_0069: dup
IL_006a: stloc.0
IL_006b: stfld ""int Program.<Assign>d__0.<>1__state""
IL_0070: ldloca.s V_2
IL_0072: call ""int System.Runtime.CompilerServices.TaskAwaiter<int>.GetResult()""
IL_0077: stloc.1
IL_0078: ldarg.0
IL_0079: ldfld ""B Program.<Assign>d__0.<>7__wrap1""
IL_007e: ldloc.1
IL_007f: stfld ""int B.x""
IL_0084: ldarg.0
IL_0085: ldnull
IL_0086: stfld ""B Program.<Assign>d__0.<>7__wrap1""
IL_008b: leave.s IL_00a4
}
catch System.Exception
{
IL_008d: stloc.3
IL_008e: ldarg.0
IL_008f: ldc.i4.s -2
IL_0091: stfld ""int Program.<Assign>d__0.<>1__state""
IL_0096: ldarg.0
IL_0097: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.<Assign>d__0.<>t__builder""
IL_009c: ldloc.3
IL_009d: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetException(System.Exception)""
IL_00a2: leave.s IL_00b7
}
IL_00a4: ldarg.0
IL_00a5: ldc.i4.s -2
IL_00a7: stfld ""int Program.<Assign>d__0.<>1__state""
IL_00ac: ldarg.0
IL_00ad: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.<Assign>d__0.<>t__builder""
IL_00b2: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetResult()""
IL_00b7: ret
}");
comp = CreateRuntimeAsyncCompilation(source);
var verifier = CompileAndVerify(comp, expectedOutput: CodeGenAsyncTests.ExpectedOutput(expectedOutput, isRuntimeAsync: true), verify: Verification.Fails with
{
ILVerifyMessage = """
[Assign]: Return value missing on the stack. { Offset = 0x1c }
[Main]: Return value missing on the stack. { Offset = 0x1e }
[TestPropertyAccessThrows]: Return value missing on the stack. { Offset = 0x30 }
[TestFieldAccessThrows]: Return value missing on the stack. { Offset = 0x34 }
[TestPropertyAccessSucceeds]: Return value missing on the stack. { Offset = 0x64 }
[Write]: Unexpected type on the stack. { Offset = 0x2c, Found = Int32, Expected = ref '[System.Runtime]System.Threading.Tasks.Task`1<int32>' }
"""
});
verifier.VerifyDiagnostics();
verifier.VerifyIL("Program.Assign(A)", """
{
// Code size 29 (0x1d)
.maxstack 2
.locals init (int V_0)
IL_0000: ldarg.0
IL_0001: callvirt "B A.B.get"
IL_0006: ldstr "RHS"
IL_000b: call "System.Threading.Tasks.Task<int> Program.Write(string)"
IL_0010: call "int System.Runtime.CompilerServices.AsyncHelpers.Await<int>(System.Threading.Tasks.Task<int>)"
IL_0015: stloc.0
IL_0016: ldloc.0
IL_0017: stfld "int B.x"
IL_001c: ret
}
""");
}
[Fact]
[WorkItem(42755, "https://github.com/dotnet/roslyn/issues/42755")]
public void KeepLtrSemantics_ClassFieldAccessOnArray()
{
var source = @"
using System;
using System.Threading.Tasks;
class Program
{
static async Task Assign(A[] arr)
{
arr[0].x = await Write(""RHS"");
}
static async Task Main(string[] args)
{
await TestIndexerThrows();
await TestAssignmentThrows();
await TestIndexerSucceeds();
await TestReassignsArrayAndIndexerDuringAwait();
await TestReassignsTargetDuringAwait();
}
static async Task TestIndexerThrows()
{
Console.WriteLine(nameof(TestIndexerThrows));
var arr = new A[0];
Console.WriteLine(""Before Assignment"");
try
{
await Assign(arr);
}
catch (IndexOutOfRangeException)
{
Console.WriteLine(""Caught IndexOutOfRangeException"");
}
}
static async Task TestAssignmentThrows()
{
Console.WriteLine(nameof(TestAssignmentThrows));
var arr = new A[1];
Console.WriteLine(""Before Assignment"");
try
{
await Assign(arr);
}
catch (NullReferenceException)
{
Console.WriteLine(""Caught NullReferenceException"");
}
}
static async Task TestIndexerSucceeds()
{
Console.WriteLine(nameof(TestIndexerSucceeds));
var arr = new A[1]{ new A() };
Console.WriteLine(""Before Assignment arr[0].x is: "" + arr[0].x);
await Assign(arr);
Console.WriteLine(""After Assignment arr[0].x is: "" + arr[0].x);
}
static async Task TestReassignsArrayAndIndexerDuringAwait()
{
Console.WriteLine(nameof(TestReassignsArrayAndIndexerDuringAwait));
var a = new A();
var arr = new A[1]{ a };
var index = 0;
Console.WriteLine(""Before Assignment arr.Length is: "" + arr.Length);
Console.WriteLine(""Before Assignment a.x is: "" + a.x);
arr[index].x = await WriteAndReassign(""RHS"");
Console.WriteLine(""After Assignment arr.Length is: "" + arr.Length);
Console.WriteLine(""After Assignment a.x is: "" + a.x);
async Task<int> WriteAndReassign(string s)
{
await Task.Yield();
arr = new A[0];
index = 1;
Console.WriteLine(s);
return 42;
}
}
static async Task TestReassignsTargetDuringAwait()
{
Console.WriteLine(nameof(TestReassignsTargetDuringAwait));
var a = new A();
var arr = new A[1]{ a };
Console.WriteLine(""Before Assignment arr[0].x is: "" + arr[0].x);
Console.WriteLine(""Before Assignment arr[0].y is: "" + arr[0].y);
Console.WriteLine(""Before Assignment a.x is: "" + a.x);
arr[0].x = await WriteAndReassign(""RHS"");
Console.WriteLine(""After Assignment arr[0].x is: "" + arr[0].x);
Console.WriteLine(""After Assignment arr[0].y is: "" + arr[0].y);
Console.WriteLine(""After Assignment a.x is: "" + a.x);
async Task<int> WriteAndReassign(string s)
{
await Task.Yield();
arr[0] = new A{ y = true };
Console.WriteLine(s);
return 42;
}
}
static async Task<int> Write(string s)
{
await Task.Yield();
Console.WriteLine(s);
return 42;
}
}
class A
{
public int x;
public bool y;
}";
var comp = CreateCompilation(source, options: TestOptions.ReleaseExe);
var expectedOutput = """
TestIndexerThrows
Before Assignment
Caught IndexOutOfRangeException
TestAssignmentThrows
Before Assignment
RHS
Caught NullReferenceException
TestIndexerSucceeds
Before Assignment arr[0].x is: 0
RHS
After Assignment arr[0].x is: 42
TestReassignsArrayAndIndexerDuringAwait
Before Assignment arr.Length is: 1
Before Assignment a.x is: 0
RHS
After Assignment arr.Length is: 0
After Assignment a.x is: 42
TestReassignsTargetDuringAwait
Before Assignment arr[0].x is: 0
Before Assignment arr[0].y is: False
Before Assignment a.x is: 0
RHS
After Assignment arr[0].x is: 0
After Assignment arr[0].y is: True
After Assignment a.x is: 42
""";
CompileAndVerify(comp, expectedOutput: expectedOutput)
.VerifyIL("Program.<Assign>d__0.System.Runtime.CompilerServices.IAsyncStateMachine.MoveNext", @"
{
// Code size 181 (0xb5)
.maxstack 3
.locals init (int V_0,
int V_1,
System.Runtime.CompilerServices.TaskAwaiter<int> V_2,
System.Exception V_3)
IL_0000: ldarg.0
IL_0001: ldfld ""int Program.<Assign>d__0.<>1__state""
IL_0006: stloc.0
.try
{
IL_0007: ldloc.0
IL_0008: brfalse.s IL_0051
IL_000a: ldarg.0
IL_000b: ldarg.0
IL_000c: ldfld ""A[] Program.<Assign>d__0.arr""
IL_0011: ldc.i4.0
IL_0012: ldelem.ref
IL_0013: stfld ""A Program.<Assign>d__0.<>7__wrap1""
IL_0018: ldstr ""RHS""
IL_001d: call ""System.Threading.Tasks.Task<int> Program.Write(string)""
IL_0022: callvirt ""System.Runtime.CompilerServices.TaskAwaiter<int> System.Threading.Tasks.Task<int>.GetAwaiter()""
IL_0027: stloc.2
IL_0028: ldloca.s V_2
IL_002a: call ""bool System.Runtime.CompilerServices.TaskAwaiter<int>.IsCompleted.get""
IL_002f: brtrue.s IL_006d
IL_0031: ldarg.0
IL_0032: ldc.i4.0
IL_0033: dup
IL_0034: stloc.0
IL_0035: stfld ""int Program.<Assign>d__0.<>1__state""
IL_003a: ldarg.0
IL_003b: ldloc.2
IL_003c: stfld ""System.Runtime.CompilerServices.TaskAwaiter<int> Program.<Assign>d__0.<>u__1""
IL_0041: ldarg.0
IL_0042: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.<Assign>d__0.<>t__builder""
IL_0047: ldloca.s V_2
IL_0049: ldarg.0
IL_004a: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.AwaitUnsafeOnCompleted<System.Runtime.CompilerServices.TaskAwaiter<int>, Program.<Assign>d__0>(ref System.Runtime.CompilerServices.TaskAwaiter<int>, ref Program.<Assign>d__0)""
IL_004f: leave.s IL_00b4
IL_0051: ldarg.0
IL_0052: ldfld ""System.Runtime.CompilerServices.TaskAwaiter<int> Program.<Assign>d__0.<>u__1""
IL_0057: stloc.2
IL_0058: ldarg.0
IL_0059: ldflda ""System.Runtime.CompilerServices.TaskAwaiter<int> Program.<Assign>d__0.<>u__1""
IL_005e: initobj ""System.Runtime.CompilerServices.TaskAwaiter<int>""
IL_0064: ldarg.0
IL_0065: ldc.i4.m1
IL_0066: dup
IL_0067: stloc.0
IL_0068: stfld ""int Program.<Assign>d__0.<>1__state""
IL_006d: ldloca.s V_2
IL_006f: call ""int System.Runtime.CompilerServices.TaskAwaiter<int>.GetResult()""
IL_0074: stloc.1
IL_0075: ldarg.0
IL_0076: ldfld ""A Program.<Assign>d__0.<>7__wrap1""
IL_007b: ldloc.1
IL_007c: stfld ""int A.x""
IL_0081: ldarg.0
IL_0082: ldnull
IL_0083: stfld ""A Program.<Assign>d__0.<>7__wrap1""
IL_0088: leave.s IL_00a1
}
catch System.Exception
{
IL_008a: stloc.3
IL_008b: ldarg.0
IL_008c: ldc.i4.s -2
IL_008e: stfld ""int Program.<Assign>d__0.<>1__state""
IL_0093: ldarg.0
IL_0094: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.<Assign>d__0.<>t__builder""
IL_0099: ldloc.3
IL_009a: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetException(System.Exception)""
IL_009f: leave.s IL_00b4
}
IL_00a1: ldarg.0
IL_00a2: ldc.i4.s -2
IL_00a4: stfld ""int Program.<Assign>d__0.<>1__state""
IL_00a9: ldarg.0
IL_00aa: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.<Assign>d__0.<>t__builder""
IL_00af: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetResult()""
IL_00b4: ret
}");
comp = CreateRuntimeAsyncCompilation(source);
var verifier = CompileAndVerify(comp, expectedOutput: CodeGenAsyncTests.ExpectedOutput(expectedOutput, isRuntimeAsync: true), verify: Verification.Fails with
{
ILVerifyMessage = """
[Assign]: Return value missing on the stack. { Offset = 0x19 }
[Main]: Return value missing on the stack. { Offset = 0x32 }
[TestIndexerThrows]: Return value missing on the stack. { Offset = 0x35 }
[TestAssignmentThrows]: Return value missing on the stack. { Offset = 0x35 }
[TestIndexerSucceeds]: Return value missing on the stack. { Offset = 0x5c }
[TestReassignsArrayAndIndexerDuringAwait]: Return value missing on the stack. { Offset = 0xc3 }
[TestReassignsTargetDuringAwait]: Return value missing on the stack. { Offset = 0xfd }
[Write]: Unexpected type on the stack. { Offset = 0x2c, Found = Int32, Expected = ref '[System.Runtime]System.Threading.Tasks.Task`1<int32>' }
[<TestReassignsArrayAndIndexerDuringAwait>g__WriteAndReassign|0]: Unexpected type on the stack. { Offset = 0x3f, Found = Int32, Expected = ref '[System.Runtime]System.Threading.Tasks.Task`1<int32>' }
[<TestReassignsTargetDuringAwait>g__WriteAndReassign|0]: Unexpected type on the stack. { Offset = 0x40, Found = Int32, Expected = ref '[System.Runtime]System.Threading.Tasks.Task`1<int32>' }
"""
});
verifier.VerifyDiagnostics();
verifier.VerifyIL("Program.Assign(A[])", """
{
// Code size 26 (0x1a)
.maxstack 2
.locals init (int V_0)
IL_0000: ldarg.0
IL_0001: ldc.i4.0
IL_0002: ldelem.ref
IL_0003: ldstr "RHS"
IL_0008: call "System.Threading.Tasks.Task<int> Program.Write(string)"
IL_000d: call "int System.Runtime.CompilerServices.AsyncHelpers.Await<int>(System.Threading.Tasks.Task<int>)"
IL_0012: stloc.0
IL_0013: ldloc.0
IL_0014: stfld "int A.x"
IL_0019: ret
}
""");
}
[Fact]
[WorkItem(42755, "https://github.com/dotnet/roslyn/issues/42755")]
public void KeepLtrSemantics_StructFieldAccessOnArray()
{
var source = @"
using System;
using System.Threading.Tasks;
class Program
{
static async Task Assign(A[] arr)
{
arr[0].x = await Write(""RHS"");
}
static async Task Main(string[] args)
{
await TestIndexerThrows();
await TestIndexerSucceeds();
await TestReassignsArrayAndIndexerDuringAwait();
await TestReassignsTargetDuringAwait();
}
static async Task TestIndexerThrows()
{
Console.WriteLine(nameof(TestIndexerThrows));
var arr = new A[0];
Console.WriteLine(""Before Assignment"");
try
{
await Assign(arr);
}
catch (IndexOutOfRangeException)
{
Console.WriteLine(""Caught IndexOutOfRangeException"");
}
}
static async Task TestIndexerSucceeds()
{
Console.WriteLine(nameof(TestIndexerSucceeds));
var arr = new A[1];
Console.WriteLine(""Before Assignment arr[0].x is: "" + arr[0].x);
await Assign(arr);
Console.WriteLine(""After Assignment arr[0].x is: "" + arr[0].x);
}
static async Task TestReassignsArrayAndIndexerDuringAwait()
{
Console.WriteLine(nameof(TestReassignsArrayAndIndexerDuringAwait));
var arr = new A[1];
var arrCopy = arr;
var index = 0;
Console.WriteLine(""Before Assignment arr.Length is: "" + arr.Length);
Console.WriteLine(""Before Assignment arrCopy[0].x is: "" + arrCopy[0].x);
arr[index].x = await WriteAndReassign(""RHS"");
Console.WriteLine(""After Assignment arr.Length is: "" + arr.Length);
Console.WriteLine(""After Assignment arrCopy[0].x is: "" + arrCopy[0].x);
async Task<int> WriteAndReassign(string s)
{
await Task.Yield();
arr = new A[0];
index = 1;
Console.WriteLine(s);
return 42;
}
}
static async Task TestReassignsTargetDuringAwait()
{
Console.WriteLine(nameof(TestReassignsTargetDuringAwait));
var arr = new A[1];
Console.WriteLine(""Before Assignment arr[0].x is: "" + arr[0].x);
Console.WriteLine(""Before Assignment arr[0].y is: "" + arr[0].y);
arr[0].x = await WriteAndReassign(""RHS"");
Console.WriteLine(""After Assignment arr[0].x is: "" + arr[0].x);
Console.WriteLine(""Before Assignment arr[0].y is: "" + arr[0].y);
async Task<int> WriteAndReassign(string s)
{
await Task.Yield();
arr[0] = new A{y = true };
Console.WriteLine(s);
return 42;
}
}
static async Task<int> Write(string s)
{
await Task.Yield();
Console.WriteLine(s);
return 42;
}
}
struct A
{
public int x;
public bool y;
}";
var comp = CreateCompilation(source, options: TestOptions.ReleaseExe);
var expectedOutput = """
TestIndexerThrows
Before Assignment
Caught IndexOutOfRangeException
TestIndexerSucceeds
Before Assignment arr[0].x is: 0
RHS
After Assignment arr[0].x is: 42
TestReassignsArrayAndIndexerDuringAwait
Before Assignment arr.Length is: 1
Before Assignment arrCopy[0].x is: 0
RHS
After Assignment arr.Length is: 0
After Assignment arrCopy[0].x is: 42
TestReassignsTargetDuringAwait
Before Assignment arr[0].x is: 0
Before Assignment arr[0].y is: False
RHS
After Assignment arr[0].x is: 42
Before Assignment arr[0].y is: True
""";
CompileAndVerify(comp, expectedOutput: expectedOutput)
.VerifyIL("Program.<Assign>d__0.System.Runtime.CompilerServices.IAsyncStateMachine.MoveNext", @"
{
// Code size 198 (0xc6)
.maxstack 3
.locals init (int V_0,
int V_1,
System.Runtime.CompilerServices.TaskAwaiter<int> V_2,
System.Exception V_3)
IL_0000: ldarg.0
IL_0001: ldfld ""int Program.<Assign>d__0.<>1__state""
IL_0006: stloc.0
.try
{
IL_0007: ldloc.0
IL_0008: brfalse.s IL_005c
IL_000a: ldarg.0
IL_000b: ldarg.0
IL_000c: ldfld ""A[] Program.<Assign>d__0.arr""
IL_0011: stfld ""A[] Program.<Assign>d__0.<>7__wrap1""
IL_0016: ldarg.0
IL_0017: ldfld ""A[] Program.<Assign>d__0.<>7__wrap1""
IL_001c: ldc.i4.0
IL_001d: ldelema ""A""
IL_0022: pop
IL_0023: ldstr ""RHS""
IL_0028: call ""System.Threading.Tasks.Task<int> Program.Write(string)""
IL_002d: callvirt ""System.Runtime.CompilerServices.TaskAwaiter<int> System.Threading.Tasks.Task<int>.GetAwaiter()""
IL_0032: stloc.2
IL_0033: ldloca.s V_2
IL_0035: call ""bool System.Runtime.CompilerServices.TaskAwaiter<int>.IsCompleted.get""
IL_003a: brtrue.s IL_0078
IL_003c: ldarg.0
IL_003d: ldc.i4.0
IL_003e: dup
IL_003f: stloc.0
IL_0040: stfld ""int Program.<Assign>d__0.<>1__state""
IL_0045: ldarg.0
IL_0046: ldloc.2
IL_0047: stfld ""System.Runtime.CompilerServices.TaskAwaiter<int> Program.<Assign>d__0.<>u__1""
IL_004c: ldarg.0
IL_004d: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.<Assign>d__0.<>t__builder""
IL_0052: ldloca.s V_2
IL_0054: ldarg.0
IL_0055: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.AwaitUnsafeOnCompleted<System.Runtime.CompilerServices.TaskAwaiter<int>, Program.<Assign>d__0>(ref System.Runtime.CompilerServices.TaskAwaiter<int>, ref Program.<Assign>d__0)""
IL_005a: leave.s IL_00c5
IL_005c: ldarg.0
IL_005d: ldfld ""System.Runtime.CompilerServices.TaskAwaiter<int> Program.<Assign>d__0.<>u__1""
IL_0062: stloc.2
IL_0063: ldarg.0
IL_0064: ldflda ""System.Runtime.CompilerServices.TaskAwaiter<int> Program.<Assign>d__0.<>u__1""
IL_0069: initobj ""System.Runtime.CompilerServices.TaskAwaiter<int>""
IL_006f: ldarg.0
IL_0070: ldc.i4.m1
IL_0071: dup
IL_0072: stloc.0
IL_0073: stfld ""int Program.<Assign>d__0.<>1__state""
IL_0078: ldloca.s V_2
IL_007a: call ""int System.Runtime.CompilerServices.TaskAwaiter<int>.GetResult()""
IL_007f: stloc.1
IL_0080: ldarg.0
IL_0081: ldfld ""A[] Program.<Assign>d__0.<>7__wrap1""
IL_0086: ldc.i4.0
IL_0087: ldelema ""A""
IL_008c: ldloc.1
IL_008d: stfld ""int A.x""
IL_0092: ldarg.0
IL_0093: ldnull
IL_0094: stfld ""A[] Program.<Assign>d__0.<>7__wrap1""
IL_0099: leave.s IL_00b2
}
catch System.Exception
{
IL_009b: stloc.3
IL_009c: ldarg.0
IL_009d: ldc.i4.s -2
IL_009f: stfld ""int Program.<Assign>d__0.<>1__state""
IL_00a4: ldarg.0
IL_00a5: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.<Assign>d__0.<>t__builder""
IL_00aa: ldloc.3
IL_00ab: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetException(System.Exception)""
IL_00b0: leave.s IL_00c5
}
IL_00b2: ldarg.0
IL_00b3: ldc.i4.s -2
IL_00b5: stfld ""int Program.<Assign>d__0.<>1__state""
IL_00ba: ldarg.0
IL_00bb: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.<Assign>d__0.<>t__builder""
IL_00c0: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetResult()""
IL_00c5: ret
}");
comp = CreateRuntimeAsyncCompilation(source);
var verifier = CompileAndVerify(comp, expectedOutput: CodeGenAsyncTests.ExpectedOutput(expectedOutput, isRuntimeAsync: true), verify: Verification.Fails with
{
ILVerifyMessage = """
[Assign]: Return value missing on the stack. { Offset = 0x25 }
[Main]: Return value missing on the stack. { Offset = 0x28 }
[TestIndexerThrows]: Return value missing on the stack. { Offset = 0x35 }
[TestIndexerSucceeds]: Return value missing on the stack. { Offset = 0x5c }
[TestReassignsArrayAndIndexerDuringAwait]: Return value missing on the stack. { Offset = 0xda }
[TestReassignsTargetDuringAwait]: Return value missing on the stack. { Offset = 0xdb }
[Write]: Unexpected type on the stack. { Offset = 0x2c, Found = Int32, Expected = ref '[System.Runtime]System.Threading.Tasks.Task`1<int32>' }
[<TestReassignsArrayAndIndexerDuringAwait>g__WriteAndReassign|0]: Unexpected type on the stack. { Offset = 0x3f, Found = Int32, Expected = ref '[System.Runtime]System.Threading.Tasks.Task`1<int32>' }
[<TestReassignsTargetDuringAwait>g__WriteAndReassign|0]: Unexpected type on the stack. { Offset = 0x49, Found = Int32, Expected = ref '[System.Runtime]System.Threading.Tasks.Task`1<int32>' }
"""
});
verifier.VerifyDiagnostics();
verifier.VerifyIL("Program.Assign(A[])", """
{
// Code size 38 (0x26)
.maxstack 3
.locals init (int V_0)
IL_0000: ldarg.0
IL_0001: dup
IL_0002: ldc.i4.0
IL_0003: ldelema "A"
IL_0008: pop
IL_0009: ldstr "RHS"
IL_000e: call "System.Threading.Tasks.Task<int> Program.Write(string)"
IL_0013: call "int System.Runtime.CompilerServices.AsyncHelpers.Await<int>(System.Threading.Tasks.Task<int>)"
IL_0018: stloc.0
IL_0019: ldc.i4.0
IL_001a: ldelema "A"
IL_001f: ldloc.0
IL_0020: stfld "int A.x"
IL_0025: ret
}
""");
}
[Fact]
[WorkItem(42755, "https://github.com/dotnet/roslyn/issues/42755")]
public void KeepLtrSemantics_AssignmentToArray()
{
var source = @"
using System;
using System.Threading.Tasks;
class Program
{
static async Task Assign(int[] arr)
{
arr[0] = await Write(""RHS"");
}
static async Task Main(string[] args)
{
await TestIndexerThrows();
await TestIndexerSucceeds();
await TestReassignsArrayAndIndexerDuringAwait();
}
static async Task TestIndexerThrows()
{
Console.WriteLine(nameof(TestIndexerThrows));
var arr = new int[0];
Console.WriteLine(""Before Assignment"");
try
{
await Assign(arr);
}
catch (IndexOutOfRangeException)
{
Console.WriteLine(""Caught IndexOutOfRangeException"");
}
}
static async Task TestIndexerSucceeds()
{
Console.WriteLine(nameof(TestIndexerSucceeds));
var arr = new int[1];
Console.WriteLine(""Before Assignment arr[0] is: "" + arr[0]);
await Assign(arr);
Console.WriteLine(""After Assignment arr[0] is: "" + arr[0]);
}
static async Task TestReassignsArrayAndIndexerDuringAwait()
{
Console.WriteLine(nameof(TestReassignsArrayAndIndexerDuringAwait));
var arr = new int[1];
var arrCopy = arr;
var index = 0;
Console.WriteLine(""Before Assignment arr.Length is: "" + arr.Length);
Console.WriteLine(""Before Assignment arrCopy[0] is: "" + arrCopy[0]);
arr[index] = await WriteAndReassign(""RHS"");
Console.WriteLine(""After Assignment arr.Length is: "" + arr.Length);
Console.WriteLine(""After Assignment arrCopy[0] is: "" + arrCopy[0]);
async Task<int> WriteAndReassign(string s)
{
await Task.Yield();
arr = new int[0];
index = 1;
Console.WriteLine(s);
return 42;
}
}
static async Task<int> Write(string s)
{
await Task.Yield();
Console.WriteLine(s);
return 42;
}
}";
var comp = CreateCompilation(source, options: TestOptions.ReleaseExe);
var expectedOutput = """
TestIndexerThrows
Before Assignment
RHS
Caught IndexOutOfRangeException
TestIndexerSucceeds
Before Assignment arr[0] is: 0
RHS
After Assignment arr[0] is: 42
TestReassignsArrayAndIndexerDuringAwait
Before Assignment arr.Length is: 1
Before Assignment arrCopy[0] is: 0
RHS
After Assignment arr.Length is: 0
After Assignment arrCopy[0] is: 42
""";
CompileAndVerify(comp, expectedOutput: expectedOutput)
.VerifyIL("Program.<Assign>d__0.System.Runtime.CompilerServices.IAsyncStateMachine.MoveNext", @"
{
// Code size 176 (0xb0)
.maxstack 3
.locals init (int V_0,
int V_1,
System.Runtime.CompilerServices.TaskAwaiter<int> V_2,
System.Exception V_3)
IL_0000: ldarg.0
IL_0001: ldfld ""int Program.<Assign>d__0.<>1__state""
IL_0006: stloc.0
.try
{
IL_0007: ldloc.0
IL_0008: brfalse.s IL_004f
IL_000a: ldarg.0
IL_000b: ldarg.0
IL_000c: ldfld ""int[] Program.<Assign>d__0.arr""
IL_0011: stfld ""int[] Program.<Assign>d__0.<>7__wrap1""
IL_0016: ldstr ""RHS""
IL_001b: call ""System.Threading.Tasks.Task<int> Program.Write(string)""
IL_0020: callvirt ""System.Runtime.CompilerServices.TaskAwaiter<int> System.Threading.Tasks.Task<int>.GetAwaiter()""
IL_0025: stloc.2
IL_0026: ldloca.s V_2
IL_0028: call ""bool System.Runtime.CompilerServices.TaskAwaiter<int>.IsCompleted.get""
IL_002d: brtrue.s IL_006b
IL_002f: ldarg.0
IL_0030: ldc.i4.0
IL_0031: dup
IL_0032: stloc.0
IL_0033: stfld ""int Program.<Assign>d__0.<>1__state""
IL_0038: ldarg.0
IL_0039: ldloc.2
IL_003a: stfld ""System.Runtime.CompilerServices.TaskAwaiter<int> Program.<Assign>d__0.<>u__1""
IL_003f: ldarg.0
IL_0040: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.<Assign>d__0.<>t__builder""
IL_0045: ldloca.s V_2
IL_0047: ldarg.0
IL_0048: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.AwaitUnsafeOnCompleted<System.Runtime.CompilerServices.TaskAwaiter<int>, Program.<Assign>d__0>(ref System.Runtime.CompilerServices.TaskAwaiter<int>, ref Program.<Assign>d__0)""
IL_004d: leave.s IL_00af
IL_004f: ldarg.0
IL_0050: ldfld ""System.Runtime.CompilerServices.TaskAwaiter<int> Program.<Assign>d__0.<>u__1""
IL_0055: stloc.2
IL_0056: ldarg.0
IL_0057: ldflda ""System.Runtime.CompilerServices.TaskAwaiter<int> Program.<Assign>d__0.<>u__1""
IL_005c: initobj ""System.Runtime.CompilerServices.TaskAwaiter<int>""
IL_0062: ldarg.0
IL_0063: ldc.i4.m1
IL_0064: dup
IL_0065: stloc.0
IL_0066: stfld ""int Program.<Assign>d__0.<>1__state""
IL_006b: ldloca.s V_2
IL_006d: call ""int System.Runtime.CompilerServices.TaskAwaiter<int>.GetResult()""
IL_0072: stloc.1
IL_0073: ldarg.0
IL_0074: ldfld ""int[] Program.<Assign>d__0.<>7__wrap1""
IL_0079: ldc.i4.0
IL_007a: ldloc.1
IL_007b: stelem.i4
IL_007c: ldarg.0
IL_007d: ldnull
IL_007e: stfld ""int[] Program.<Assign>d__0.<>7__wrap1""
IL_0083: leave.s IL_009c
}
catch System.Exception
{
IL_0085: stloc.3
IL_0086: ldarg.0
IL_0087: ldc.i4.s -2
IL_0089: stfld ""int Program.<Assign>d__0.<>1__state""
IL_008e: ldarg.0
IL_008f: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.<Assign>d__0.<>t__builder""
IL_0094: ldloc.3
IL_0095: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetException(System.Exception)""
IL_009a: leave.s IL_00af
}
IL_009c: ldarg.0
IL_009d: ldc.i4.s -2
IL_009f: stfld ""int Program.<Assign>d__0.<>1__state""
IL_00a4: ldarg.0
IL_00a5: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.<Assign>d__0.<>t__builder""
IL_00aa: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetResult()""
IL_00af: ret
}");
comp = CreateRuntimeAsyncCompilation(source);
var verifier = CompileAndVerify(comp, expectedOutput: CodeGenAsyncTests.ExpectedOutput(expectedOutput, isRuntimeAsync: true), verify: Verification.Fails with
{
ILVerifyMessage = """
[Assign]: Return value missing on the stack. { Offset = 0x14 }
[Main]: Return value missing on the stack. { Offset = 0x1e }
[TestIndexerThrows]: Return value missing on the stack. { Offset = 0x35 }
[TestIndexerSucceeds]: Return value missing on the stack. { Offset = 0x52 }
[TestReassignsArrayAndIndexerDuringAwait]: Return value missing on the stack. { Offset = 0xbf }
[Write]: Unexpected type on the stack. { Offset = 0x2c, Found = Int32, Expected = ref '[System.Runtime]System.Threading.Tasks.Task`1<int32>' }
[<TestReassignsArrayAndIndexerDuringAwait>g__WriteAndReassign|0]: Unexpected type on the stack. { Offset = 0x3f, Found = Int32, Expected = ref '[System.Runtime]System.Threading.Tasks.Task`1<int32>' }
"""
});
verifier.VerifyDiagnostics();
verifier.VerifyIL("Program.Assign(int[])", """
{
// Code size 21 (0x15)
.maxstack 3
.locals init (int V_0)
IL_0000: ldarg.0
IL_0001: ldstr "RHS"
IL_0006: call "System.Threading.Tasks.Task<int> Program.Write(string)"
IL_000b: call "int System.Runtime.CompilerServices.AsyncHelpers.Await<int>(System.Threading.Tasks.Task<int>)"
IL_0010: stloc.0
IL_0011: ldc.i4.0
IL_0012: ldloc.0
IL_0013: stelem.i4
IL_0014: ret
}
""");
}
[Fact]
[WorkItem(42755, "https://github.com/dotnet/roslyn/issues/42755")]
public void KeepLtrSemantics_StructFieldAccessOnStructFieldAccessOnClassField()
{
var source = @"
using System;
using System.Threading.Tasks;
class Program
{
static async Task Assign(A a)
{
a.b.c.x = await Write(""RHS"");
}
static async Task Main(string[] args)
{
await TestAIsNull();
await TestAIsNotNull();
await ReassignADuringAssignment();
}
static async Task TestAIsNull()
{
Console.WriteLine(nameof(TestAIsNull));
A a = null;
Console.WriteLine(""Before Assignment"");
try
{
await Assign(a);
}
catch (NullReferenceException)
{
Console.WriteLine(""Caught NullReferenceException"");
}
}
static async Task TestAIsNotNull()
{
Console.WriteLine(nameof(TestAIsNotNull));
var a = new A();
Console.WriteLine(""Before Assignment a.b.c.x is: "" + a.b.c.x);
await Assign(a);
Console.WriteLine(""After Assignment a.b.c.x is: "" + a.b.c.x);
}
static async Task ReassignADuringAssignment()
{
Console.WriteLine(nameof(ReassignADuringAssignment));
var a = new A();
var aCopy = a;
Console.WriteLine(""Before Assignment a is null == "" + (a is null));
Console.WriteLine(""Before Assignment aCopy.b.c.x is: "" + aCopy.b.c.x);
a.b.c.x = await WriteAndReassign(""RHS"");
Console.WriteLine(""After Assignment a is null == "" + (a is null));
Console.WriteLine(""After Assignment aCopy.b.c.x is: "" + aCopy.b.c.x);
async Task<int> WriteAndReassign(string s)
{
await Task.Yield();
a = null;
Console.WriteLine(s);
return 42;
}
}
static async Task<int> Write(string s)
{
await Task.Yield();
Console.WriteLine(s);
return 42;
}
}
class A
{
public B b;
}
struct B
{
public C c;
}
struct C
{
public int x;
}";
var comp = CreateCompilation(source, options: TestOptions.ReleaseExe);
var expectedOutput = """
TestAIsNull
Before Assignment
Caught NullReferenceException
TestAIsNotNull
Before Assignment a.b.c.x is: 0
RHS
After Assignment a.b.c.x is: 42
ReassignADuringAssignment
Before Assignment a is null == False
Before Assignment aCopy.b.c.x is: 0
RHS
After Assignment a is null == True
After Assignment aCopy.b.c.x is: 42
""";
CompileAndVerify(comp, expectedOutput: expectedOutput)
.VerifyIL("Program.<Assign>d__0.System.Runtime.CompilerServices.IAsyncStateMachine.MoveNext", @"
{
// Code size 201 (0xc9)
.maxstack 3
.locals init (int V_0,
int V_1,
System.Runtime.CompilerServices.TaskAwaiter<int> V_2,
System.Exception V_3)
IL_0000: ldarg.0
IL_0001: ldfld ""int Program.<Assign>d__0.<>1__state""
IL_0006: stloc.0
.try
{
IL_0007: ldloc.0
IL_0008: brfalse.s IL_005b
IL_000a: ldarg.0
IL_000b: ldarg.0
IL_000c: ldfld ""A Program.<Assign>d__0.a""
IL_0011: stfld ""A Program.<Assign>d__0.<>7__wrap1""
IL_0016: ldarg.0
IL_0017: ldfld ""A Program.<Assign>d__0.<>7__wrap1""
IL_001c: ldfld ""B A.b""
IL_0021: pop
IL_0022: ldstr ""RHS""
IL_0027: call ""System.Threading.Tasks.Task<int> Program.Write(string)""
IL_002c: callvirt ""System.Runtime.CompilerServices.TaskAwaiter<int> System.Threading.Tasks.Task<int>.GetAwaiter()""
IL_0031: stloc.2
IL_0032: ldloca.s V_2
IL_0034: call ""bool System.Runtime.CompilerServices.TaskAwaiter<int>.IsCompleted.get""
IL_0039: brtrue.s IL_0077
IL_003b: ldarg.0
IL_003c: ldc.i4.0
IL_003d: dup
IL_003e: stloc.0
IL_003f: stfld ""int Program.<Assign>d__0.<>1__state""
IL_0044: ldarg.0
IL_0045: ldloc.2
IL_0046: stfld ""System.Runtime.CompilerServices.TaskAwaiter<int> Program.<Assign>d__0.<>u__1""
IL_004b: ldarg.0
IL_004c: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.<Assign>d__0.<>t__builder""
IL_0051: ldloca.s V_2
IL_0053: ldarg.0
IL_0054: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.AwaitUnsafeOnCompleted<System.Runtime.CompilerServices.TaskAwaiter<int>, Program.<Assign>d__0>(ref System.Runtime.CompilerServices.TaskAwaiter<int>, ref Program.<Assign>d__0)""
IL_0059: leave.s IL_00c8
IL_005b: ldarg.0
IL_005c: ldfld ""System.Runtime.CompilerServices.TaskAwaiter<int> Program.<Assign>d__0.<>u__1""
IL_0061: stloc.2
IL_0062: ldarg.0
IL_0063: ldflda ""System.Runtime.CompilerServices.TaskAwaiter<int> Program.<Assign>d__0.<>u__1""
IL_0068: initobj ""System.Runtime.CompilerServices.TaskAwaiter<int>""
IL_006e: ldarg.0
IL_006f: ldc.i4.m1
IL_0070: dup
IL_0071: stloc.0
IL_0072: stfld ""int Program.<Assign>d__0.<>1__state""
IL_0077: ldloca.s V_2
IL_0079: call ""int System.Runtime.CompilerServices.TaskAwaiter<int>.GetResult()""
IL_007e: stloc.1
IL_007f: ldarg.0
IL_0080: ldfld ""A Program.<Assign>d__0.<>7__wrap1""
IL_0085: ldflda ""B A.b""
IL_008a: ldflda ""C B.c""
IL_008f: ldloc.1
IL_0090: stfld ""int C.x""
IL_0095: ldarg.0
IL_0096: ldnull
IL_0097: stfld ""A Program.<Assign>d__0.<>7__wrap1""
IL_009c: leave.s IL_00b5
}
catch System.Exception
{
IL_009e: stloc.3
IL_009f: ldarg.0
IL_00a0: ldc.i4.s -2
IL_00a2: stfld ""int Program.<Assign>d__0.<>1__state""
IL_00a7: ldarg.0
IL_00a8: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.<Assign>d__0.<>t__builder""
IL_00ad: ldloc.3
IL_00ae: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetException(System.Exception)""
IL_00b3: leave.s IL_00c8
}
IL_00b5: ldarg.0
IL_00b6: ldc.i4.s -2
IL_00b8: stfld ""int Program.<Assign>d__0.<>1__state""
IL_00bd: ldarg.0
IL_00be: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.<Assign>d__0.<>t__builder""
IL_00c3: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetResult()""
IL_00c8: ret
}");
comp = CreateRuntimeAsyncCompilation(source);
var verifier = CompileAndVerify(comp, expectedOutput: CodeGenAsyncTests.ExpectedOutput(expectedOutput, isRuntimeAsync: true), verify: Verification.Fails with
{
ILVerifyMessage = """
[Assign]: Return value missing on the stack. { Offset = 0x28 }
[Main]: Return value missing on the stack. { Offset = 0x1e }
[TestAIsNull]: Return value missing on the stack. { Offset = 0x30 }
[TestAIsNotNull]: Return value missing on the stack. { Offset = 0x63 }
[ReassignADuringAssignment]: Return value missing on the stack. { Offset = 0xd8 }
[Write]: Unexpected type on the stack. { Offset = 0x2c, Found = Int32, Expected = ref '[System.Runtime]System.Threading.Tasks.Task`1<int32>' }
[<ReassignADuringAssignment>g__WriteAndReassign|0]: Unexpected type on the stack. { Offset = 0x33, Found = Int32, Expected = ref '[System.Runtime]System.Threading.Tasks.Task`1<int32>' }
"""
});
verifier.VerifyDiagnostics();
verifier.VerifyIL("Program.Assign(A)", """
{
// Code size 41 (0x29)
.maxstack 2
.locals init (int V_0)
IL_0000: ldarg.0
IL_0001: dup
IL_0002: ldfld "B A.b"
IL_0007: pop
IL_0008: ldstr "RHS"
IL_000d: call "System.Threading.Tasks.Task<int> Program.Write(string)"
IL_0012: call "int System.Runtime.CompilerServices.AsyncHelpers.Await<int>(System.Threading.Tasks.Task<int>)"
IL_0017: stloc.0
IL_0018: ldflda "B A.b"
IL_001d: ldflda "C B.c"
IL_0022: ldloc.0
IL_0023: stfld "int C.x"
IL_0028: ret
}
""");
}
[Fact]
[WorkItem(42755, "https://github.com/dotnet/roslyn/issues/42755")]
public void KeepLtrSemantics_ClassPropertyAssignmentOnClassProperty()
{
var source = @"
using System;
using System.Threading.Tasks;
class Program
{
static async Task Assign(A a)
{
a.b.x = await Write(""RHS"");
}
static async Task Main(string[] args)
{
await TestAIsNull();
await TestAIsNotNull();
await ReassignADuringAssignment();
}
static async Task TestAIsNull()
{
Console.WriteLine(nameof(TestAIsNull));
A a = null;
Console.WriteLine(""Before Assignment"");
try
{
await Assign(a);
}
catch (NullReferenceException)
{
Console.WriteLine(""Caught NullReferenceException"");
}
}
static async Task TestAIsNotNull()
{
Console.WriteLine(nameof(TestAIsNotNull));
var a = new A{ _b = new B() };
Console.WriteLine(""Before Assignment a._b._x is: "" + a._b._x);
await Assign(a);
Console.WriteLine(""After Assignment a._b._x is: "" + a._b._x);
}
static async Task ReassignADuringAssignment()
{
Console.WriteLine(nameof(ReassignADuringAssignment));
var a = new A{ _b = new B() };
var aCopy = a;
Console.WriteLine(""Before Assignment a is null == "" + (a is null));
Console.WriteLine(""Before Assignment aCopy._b._x is: "" + aCopy._b._x);
a.b.x = await WriteAndReassign(""RHS"");
Console.WriteLine(""After Assignment a is null == "" + (a is null));
Console.WriteLine(""After Assignment aCopy._b._x is: "" + aCopy._b._x);
async Task<int> WriteAndReassign(string s)
{
await Task.Yield();
a = null;
Console.WriteLine(s);
return 42;
}
}
static async Task<int> Write(string s)
{
await Task.Yield();
Console.WriteLine(s);
return 42;
}
}
class A
{
public B _b;
public B b { get { Console.WriteLine(""GetB""); return _b; } set { Console.WriteLine(""SetB""); _b = value; }}
}
class B
{
public int _x;
public int x { get { Console.WriteLine(""GetX""); return _x; } set { Console.WriteLine(""SetX""); _x = value; } }
}";
var comp = CreateCompilation(source, options: TestOptions.ReleaseExe);
var expectedOutput = """
TestAIsNull
Before Assignment
Caught NullReferenceException
TestAIsNotNull
Before Assignment a._b._x is: 0
GetB
RHS
SetX
After Assignment a._b._x is: 42
ReassignADuringAssignment
Before Assignment a is null == False
Before Assignment aCopy._b._x is: 0
GetB
RHS
SetX
After Assignment a is null == True
After Assignment aCopy._b._x is: 42
""";
CompileAndVerify(comp, expectedOutput: expectedOutput)
.VerifyIL("Program.<Assign>d__0.System.Runtime.CompilerServices.IAsyncStateMachine.MoveNext", @"
{
// Code size 184 (0xb8)
.maxstack 3
.locals init (int V_0,
int V_1,
System.Runtime.CompilerServices.TaskAwaiter<int> V_2,
System.Exception V_3)
IL_0000: ldarg.0
IL_0001: ldfld ""int Program.<Assign>d__0.<>1__state""
IL_0006: stloc.0
.try
{
IL_0007: ldloc.0
IL_0008: brfalse.s IL_0054
IL_000a: ldarg.0
IL_000b: ldarg.0
IL_000c: ldfld ""A Program.<Assign>d__0.a""
IL_0011: callvirt ""B A.b.get""
IL_0016: stfld ""B Program.<Assign>d__0.<>7__wrap1""
IL_001b: ldstr ""RHS""
IL_0020: call ""System.Threading.Tasks.Task<int> Program.Write(string)""
IL_0025: callvirt ""System.Runtime.CompilerServices.TaskAwaiter<int> System.Threading.Tasks.Task<int>.GetAwaiter()""
IL_002a: stloc.2
IL_002b: ldloca.s V_2
IL_002d: call ""bool System.Runtime.CompilerServices.TaskAwaiter<int>.IsCompleted.get""
IL_0032: brtrue.s IL_0070
IL_0034: ldarg.0
IL_0035: ldc.i4.0
IL_0036: dup
IL_0037: stloc.0
IL_0038: stfld ""int Program.<Assign>d__0.<>1__state""
IL_003d: ldarg.0
IL_003e: ldloc.2
IL_003f: stfld ""System.Runtime.CompilerServices.TaskAwaiter<int> Program.<Assign>d__0.<>u__1""
IL_0044: ldarg.0
IL_0045: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.<Assign>d__0.<>t__builder""
IL_004a: ldloca.s V_2
IL_004c: ldarg.0
IL_004d: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.AwaitUnsafeOnCompleted<System.Runtime.CompilerServices.TaskAwaiter<int>, Program.<Assign>d__0>(ref System.Runtime.CompilerServices.TaskAwaiter<int>, ref Program.<Assign>d__0)""
IL_0052: leave.s IL_00b7
IL_0054: ldarg.0
IL_0055: ldfld ""System.Runtime.CompilerServices.TaskAwaiter<int> Program.<Assign>d__0.<>u__1""
IL_005a: stloc.2
IL_005b: ldarg.0
IL_005c: ldflda ""System.Runtime.CompilerServices.TaskAwaiter<int> Program.<Assign>d__0.<>u__1""
IL_0061: initobj ""System.Runtime.CompilerServices.TaskAwaiter<int>""
IL_0067: ldarg.0
IL_0068: ldc.i4.m1
IL_0069: dup
IL_006a: stloc.0
IL_006b: stfld ""int Program.<Assign>d__0.<>1__state""
IL_0070: ldloca.s V_2
IL_0072: call ""int System.Runtime.CompilerServices.TaskAwaiter<int>.GetResult()""
IL_0077: stloc.1
IL_0078: ldarg.0
IL_0079: ldfld ""B Program.<Assign>d__0.<>7__wrap1""
IL_007e: ldloc.1
IL_007f: callvirt ""void B.x.set""
IL_0084: ldarg.0
IL_0085: ldnull
IL_0086: stfld ""B Program.<Assign>d__0.<>7__wrap1""
IL_008b: leave.s IL_00a4
}
catch System.Exception
{
IL_008d: stloc.3
IL_008e: ldarg.0
IL_008f: ldc.i4.s -2
IL_0091: stfld ""int Program.<Assign>d__0.<>1__state""
IL_0096: ldarg.0
IL_0097: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.<Assign>d__0.<>t__builder""
IL_009c: ldloc.3
IL_009d: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetException(System.Exception)""
IL_00a2: leave.s IL_00b7
}
IL_00a4: ldarg.0
IL_00a5: ldc.i4.s -2
IL_00a7: stfld ""int Program.<Assign>d__0.<>1__state""
IL_00ac: ldarg.0
IL_00ad: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.<Assign>d__0.<>t__builder""
IL_00b2: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetResult()""
IL_00b7: ret
}");
comp = CreateRuntimeAsyncCompilation(source);
var verifier = CompileAndVerify(comp, expectedOutput: CodeGenAsyncTests.ExpectedOutput(expectedOutput, isRuntimeAsync: true), verify: Verification.Fails with
{
ILVerifyMessage = """
[Assign]: Return value missing on the stack. { Offset = 0x1c }
[Main]: Return value missing on the stack. { Offset = 0x1e }
[TestAIsNull]: Return value missing on the stack. { Offset = 0x30 }
[TestAIsNotNull]: Return value missing on the stack. { Offset = 0x64 }
[ReassignADuringAssignment]: Return value missing on the stack. { Offset = 0xcd }
[Write]: Unexpected type on the stack. { Offset = 0x2c, Found = Int32, Expected = ref '[System.Runtime]System.Threading.Tasks.Task`1<int32>' }
[<ReassignADuringAssignment>g__WriteAndReassign|0]: Unexpected type on the stack. { Offset = 0x33, Found = Int32, Expected = ref '[System.Runtime]System.Threading.Tasks.Task`1<int32>' }
"""
});
verifier.VerifyDiagnostics();
verifier.VerifyIL("Program.Assign(A)", """
{
// Code size 29 (0x1d)
.maxstack 2
.locals init (int V_0)
IL_0000: ldarg.0
IL_0001: callvirt "B A.b.get"
IL_0006: ldstr "RHS"
IL_000b: call "System.Threading.Tasks.Task<int> Program.Write(string)"
IL_0010: call "int System.Runtime.CompilerServices.AsyncHelpers.Await<int>(System.Threading.Tasks.Task<int>)"
IL_0015: stloc.0
IL_0016: ldloc.0
IL_0017: callvirt "void B.x.set"
IL_001c: ret
}
""");
}
[WorkItem(19609, "https://github.com/dotnet/roslyn/issues/19609")]
[Fact]
public void KeepLtrSemantics_FieldAccessOnClass()
{
var source = @"
using System;
using System.Threading.Tasks;
class Program
{
static async Task Assign(A a)
{
a.x = await Write(""RHS"");
}
static async Task Main(string[] args)
{
await TestAIsNull();
await TestAIsNotNull();
await ReassignADuringAssignment();
}
static async Task TestAIsNull()
{
Console.WriteLine(nameof(TestAIsNull));
A a = null;
Console.WriteLine(""Before Assignment"");
try
{
await Assign(a);
}
catch (NullReferenceException)
{
Console.WriteLine(""Caught NullReferenceException"");
}
}
static async Task TestAIsNotNull()
{
Console.WriteLine(nameof(TestAIsNotNull));
var a = new A();
Console.WriteLine(""Before Assignment a.x is: "" + a.x);
await Assign(a);
Console.WriteLine(""After Assignment a.x is: "" + a.x);
}
static async Task ReassignADuringAssignment()
{
Console.WriteLine(nameof(ReassignADuringAssignment));
var a = new A();
var aCopy = a;
Console.WriteLine(""Before Assignment a is null == "" + (a is null));
Console.WriteLine(""Before Assignment aCopy.x is: "" + aCopy.x);
a.x = await WriteAndReassign(""RHS"");
Console.WriteLine(""After Assignment a is null == "" + (a is null));
Console.WriteLine(""After Assignment aCopy.x is: "" + aCopy.x);
async Task<int> WriteAndReassign(string s)
{
await Task.Yield();
a = null;
Console.WriteLine(s);
return 42;
}
}
static async Task<int> Write(string s)
{
await Task.Yield();
Console.WriteLine(s);
return 42;
}
}
class A
{
public int x;
}";
var comp = CreateCompilation(source, options: TestOptions.ReleaseExe);
var expectedOutput = """
TestAIsNull
Before Assignment
RHS
Caught NullReferenceException
TestAIsNotNull
Before Assignment a.x is: 0
RHS
After Assignment a.x is: 42
ReassignADuringAssignment
Before Assignment a is null == False
Before Assignment aCopy.x is: 0
RHS
After Assignment a is null == True
After Assignment aCopy.x is: 42
""";
CompileAndVerify(comp, expectedOutput: expectedOutput)
.VerifyIL("Program.<Assign>d__0.System.Runtime.CompilerServices.IAsyncStateMachine.MoveNext", @"
{
// Code size 179 (0xb3)
.maxstack 3
.locals init (int V_0,
int V_1,
System.Runtime.CompilerServices.TaskAwaiter<int> V_2,
System.Exception V_3)
IL_0000: ldarg.0
IL_0001: ldfld ""int Program.<Assign>d__0.<>1__state""
IL_0006: stloc.0
.try
{
IL_0007: ldloc.0
IL_0008: brfalse.s IL_004f
IL_000a: ldarg.0
IL_000b: ldarg.0
IL_000c: ldfld ""A Program.<Assign>d__0.a""
IL_0011: stfld ""A Program.<Assign>d__0.<>7__wrap1""
IL_0016: ldstr ""RHS""
IL_001b: call ""System.Threading.Tasks.Task<int> Program.Write(string)""
IL_0020: callvirt ""System.Runtime.CompilerServices.TaskAwaiter<int> System.Threading.Tasks.Task<int>.GetAwaiter()""
IL_0025: stloc.2
IL_0026: ldloca.s V_2
IL_0028: call ""bool System.Runtime.CompilerServices.TaskAwaiter<int>.IsCompleted.get""
IL_002d: brtrue.s IL_006b
IL_002f: ldarg.0
IL_0030: ldc.i4.0
IL_0031: dup
IL_0032: stloc.0
IL_0033: stfld ""int Program.<Assign>d__0.<>1__state""
IL_0038: ldarg.0
IL_0039: ldloc.2
IL_003a: stfld ""System.Runtime.CompilerServices.TaskAwaiter<int> Program.<Assign>d__0.<>u__1""
IL_003f: ldarg.0
IL_0040: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.<Assign>d__0.<>t__builder""
IL_0045: ldloca.s V_2
IL_0047: ldarg.0
IL_0048: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.AwaitUnsafeOnCompleted<System.Runtime.CompilerServices.TaskAwaiter<int>, Program.<Assign>d__0>(ref System.Runtime.CompilerServices.TaskAwaiter<int>, ref Program.<Assign>d__0)""
IL_004d: leave.s IL_00b2
IL_004f: ldarg.0
IL_0050: ldfld ""System.Runtime.CompilerServices.TaskAwaiter<int> Program.<Assign>d__0.<>u__1""
IL_0055: stloc.2
IL_0056: ldarg.0
IL_0057: ldflda ""System.Runtime.CompilerServices.TaskAwaiter<int> Program.<Assign>d__0.<>u__1""
IL_005c: initobj ""System.Runtime.CompilerServices.TaskAwaiter<int>""
IL_0062: ldarg.0
IL_0063: ldc.i4.m1
IL_0064: dup
IL_0065: stloc.0
IL_0066: stfld ""int Program.<Assign>d__0.<>1__state""
IL_006b: ldloca.s V_2
IL_006d: call ""int System.Runtime.CompilerServices.TaskAwaiter<int>.GetResult()""
IL_0072: stloc.1
IL_0073: ldarg.0
IL_0074: ldfld ""A Program.<Assign>d__0.<>7__wrap1""
IL_0079: ldloc.1
IL_007a: stfld ""int A.x""
IL_007f: ldarg.0
IL_0080: ldnull
IL_0081: stfld ""A Program.<Assign>d__0.<>7__wrap1""
IL_0086: leave.s IL_009f
}
catch System.Exception
{
IL_0088: stloc.3
IL_0089: ldarg.0
IL_008a: ldc.i4.s -2
IL_008c: stfld ""int Program.<Assign>d__0.<>1__state""
IL_0091: ldarg.0
IL_0092: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.<Assign>d__0.<>t__builder""
IL_0097: ldloc.3
IL_0098: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetException(System.Exception)""
IL_009d: leave.s IL_00b2
}
IL_009f: ldarg.0
IL_00a0: ldc.i4.s -2
IL_00a2: stfld ""int Program.<Assign>d__0.<>1__state""
IL_00a7: ldarg.0
IL_00a8: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.<Assign>d__0.<>t__builder""
IL_00ad: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetResult()""
IL_00b2: ret
}");
comp = CreateRuntimeAsyncCompilation(source);
var verifier = CompileAndVerify(comp, expectedOutput: CodeGenAsyncTests.ExpectedOutput(expectedOutput, isRuntimeAsync: true), verify: Verification.Fails with
{
ILVerifyMessage = """
[Assign]: Return value missing on the stack. { Offset = 0x17 }
[Main]: Return value missing on the stack. { Offset = 0x1e }
[TestAIsNull]: Return value missing on the stack. { Offset = 0x30 }
[TestAIsNotNull]: Return value missing on the stack. { Offset = 0x4f }
[ReassignADuringAssignment]: Return value missing on the stack. { Offset = 0xb3 }
[Write]: Unexpected type on the stack. { Offset = 0x2c, Found = Int32, Expected = ref '[System.Runtime]System.Threading.Tasks.Task`1<int32>' }
[<ReassignADuringAssignment>g__WriteAndReassign|0]: Unexpected type on the stack. { Offset = 0x33, Found = Int32, Expected = ref '[System.Runtime]System.Threading.Tasks.Task`1<int32>' }
"""
});
verifier.VerifyDiagnostics();
verifier.VerifyIL("Program.Assign(A)", """
{
// Code size 24 (0x18)
.maxstack 2
.locals init (int V_0)
IL_0000: ldarg.0
IL_0001: ldstr "RHS"
IL_0006: call "System.Threading.Tasks.Task<int> Program.Write(string)"
IL_000b: call "int System.Runtime.CompilerServices.AsyncHelpers.Await<int>(System.Threading.Tasks.Task<int>)"
IL_0010: stloc.0
IL_0011: ldloc.0
IL_0012: stfld "int A.x"
IL_0017: ret
}
""");
}
[Fact]
[WorkItem(42755, "https://github.com/dotnet/roslyn/issues/42755")]
public void KeepLtrSemantics_CompoundAssignment()
{
var source = @"
using System;
using System.Threading.Tasks;
class Program
{
static async Task Assign(A a)
{
a.x += await Write(""RHS"");
}
static async Task Main(string[] args)
{
await TestAIsNull();
await TestAIsNotNull();
await ReassignADuringAssignment();
await ReassignXDuringAssignment();
}
static async Task TestAIsNull()
{
Console.WriteLine(nameof(TestAIsNull));
A a = null;
Console.WriteLine(""Before Assignment"");
try
{
await Assign(a);
}
catch (NullReferenceException)
{
Console.WriteLine(""Caught NullReferenceException"");
}
}
static async Task TestAIsNotNull()
{
Console.WriteLine(nameof(TestAIsNotNull));
var a = new A(){ x = 1 };
Console.WriteLine(""Before Assignment a.x is: "" + a.x);
await Assign(a);
Console.WriteLine(""After Assignment a.x is: "" + a.x);
}
static async Task ReassignADuringAssignment()
{
Console.WriteLine(nameof(ReassignADuringAssignment));
var a = new A(){ x = 1 };
var aCopy = a;
Console.WriteLine(""Before Assignment a is null == "" + (a is null));
Console.WriteLine(""Before Assignment aCopy.x is: "" + aCopy.x);
a.x += await WriteAndReassign(""RHS"");
Console.WriteLine(""After Assignment a is null == "" + (a is null));
Console.WriteLine(""After Assignment aCopy.x is: "" + aCopy.x);
async Task<int> WriteAndReassign(string s)
{
await Task.Yield();
a = null;
Console.WriteLine(s);
return 42;
}
}
static async Task ReassignXDuringAssignment()
{
Console.WriteLine(nameof(ReassignXDuringAssignment));
var a = new A(){ x = 1 };
Console.WriteLine(""Before Assignment a.x is: "" + a.x);
a.x += await WriteAndReassign(""RHS"");
Console.WriteLine(""After Assignment a.x is: "" + a.x);
async Task<int> WriteAndReassign(string s)
{
await Task.Yield();
a.x = 100;
Console.WriteLine(s);
return 42;
}
}
static async Task<int> Write(string s)
{
await Task.Yield();
Console.WriteLine(s);
return 42;
}
}
class A
{
public int x;
}";
var comp = CreateCompilation(source, options: TestOptions.ReleaseExe);
var expectedOutput = """
TestAIsNull
Before Assignment
Caught NullReferenceException
TestAIsNotNull
Before Assignment a.x is: 1
RHS
After Assignment a.x is: 43
ReassignADuringAssignment
Before Assignment a is null == False
Before Assignment aCopy.x is: 1
RHS
After Assignment a is null == True
After Assignment aCopy.x is: 43
ReassignXDuringAssignment
Before Assignment a.x is: 1
RHS
After Assignment a.x is: 43
""";
CompileAndVerify(comp, expectedOutput: expectedOutput)
.VerifyIL("Program.<Assign>d__0.System.Runtime.CompilerServices.IAsyncStateMachine.MoveNext", @"
{
// Code size 202 (0xca)
.maxstack 3
.locals init (int V_0,
A V_1,
int V_2,
System.Runtime.CompilerServices.TaskAwaiter<int> V_3,
System.Exception V_4)
IL_0000: ldarg.0
IL_0001: ldfld ""int Program.<Assign>d__0.<>1__state""
IL_0006: stloc.0
.try
{
IL_0007: ldloc.0
IL_0008: brfalse.s IL_005d
IL_000a: ldarg.0
IL_000b: ldfld ""A Program.<Assign>d__0.a""
IL_0010: stloc.1
IL_0011: ldarg.0
IL_0012: ldloc.1
IL_0013: stfld ""A Program.<Assign>d__0.<>7__wrap1""
IL_0018: ldarg.0
IL_0019: ldloc.1
IL_001a: ldfld ""int A.x""
IL_001f: stfld ""int Program.<Assign>d__0.<>7__wrap2""
IL_0024: ldstr ""RHS""
IL_0029: call ""System.Threading.Tasks.Task<int> Program.Write(string)""
IL_002e: callvirt ""System.Runtime.CompilerServices.TaskAwaiter<int> System.Threading.Tasks.Task<int>.GetAwaiter()""
IL_0033: stloc.3
IL_0034: ldloca.s V_3
IL_0036: call ""bool System.Runtime.CompilerServices.TaskAwaiter<int>.IsCompleted.get""
IL_003b: brtrue.s IL_0079
IL_003d: ldarg.0
IL_003e: ldc.i4.0
IL_003f: dup
IL_0040: stloc.0
IL_0041: stfld ""int Program.<Assign>d__0.<>1__state""
IL_0046: ldarg.0
IL_0047: ldloc.3
IL_0048: stfld ""System.Runtime.CompilerServices.TaskAwaiter<int> Program.<Assign>d__0.<>u__1""
IL_004d: ldarg.0
IL_004e: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.<Assign>d__0.<>t__builder""
IL_0053: ldloca.s V_3
IL_0055: ldarg.0
IL_0056: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.AwaitUnsafeOnCompleted<System.Runtime.CompilerServices.TaskAwaiter<int>, Program.<Assign>d__0>(ref System.Runtime.CompilerServices.TaskAwaiter<int>, ref Program.<Assign>d__0)""
IL_005b: leave.s IL_00c9
IL_005d: ldarg.0
IL_005e: ldfld ""System.Runtime.CompilerServices.TaskAwaiter<int> Program.<Assign>d__0.<>u__1""
IL_0063: stloc.3
IL_0064: ldarg.0
IL_0065: ldflda ""System.Runtime.CompilerServices.TaskAwaiter<int> Program.<Assign>d__0.<>u__1""
IL_006a: initobj ""System.Runtime.CompilerServices.TaskAwaiter<int>""
IL_0070: ldarg.0
IL_0071: ldc.i4.m1
IL_0072: dup
IL_0073: stloc.0
IL_0074: stfld ""int Program.<Assign>d__0.<>1__state""
IL_0079: ldloca.s V_3
IL_007b: call ""int System.Runtime.CompilerServices.TaskAwaiter<int>.GetResult()""
IL_0080: stloc.2
IL_0081: ldarg.0
IL_0082: ldfld ""A Program.<Assign>d__0.<>7__wrap1""
IL_0087: ldarg.0
IL_0088: ldfld ""int Program.<Assign>d__0.<>7__wrap2""
IL_008d: ldloc.2
IL_008e: add
IL_008f: stfld ""int A.x""
IL_0094: ldarg.0
IL_0095: ldnull
IL_0096: stfld ""A Program.<Assign>d__0.<>7__wrap1""
IL_009b: leave.s IL_00b6
}
catch System.Exception
{
IL_009d: stloc.s V_4
IL_009f: ldarg.0
IL_00a0: ldc.i4.s -2
IL_00a2: stfld ""int Program.<Assign>d__0.<>1__state""
IL_00a7: ldarg.0
IL_00a8: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.<Assign>d__0.<>t__builder""
IL_00ad: ldloc.s V_4
IL_00af: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetException(System.Exception)""
IL_00b4: leave.s IL_00c9
}
IL_00b6: ldarg.0
IL_00b7: ldc.i4.s -2
IL_00b9: stfld ""int Program.<Assign>d__0.<>1__state""
IL_00be: ldarg.0
IL_00bf: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.<Assign>d__0.<>t__builder""
IL_00c4: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetResult()""
IL_00c9: ret
}");
comp = CreateRuntimeAsyncCompilation(source);
var verifier = CompileAndVerify(comp, expectedOutput: CodeGenAsyncTests.ExpectedOutput(expectedOutput, isRuntimeAsync: true), verify: Verification.Fails with
{
ILVerifyMessage = """
[Assign]: Return value missing on the stack. { Offset = 0x22 }
[Main]: Return value missing on the stack. { Offset = 0x28 }
[TestAIsNull]: Return value missing on the stack. { Offset = 0x30 }
[TestAIsNotNull]: Return value missing on the stack. { Offset = 0x56 }
[ReassignADuringAssignment]: Return value missing on the stack. { Offset = 0xc9 }
[ReassignXDuringAssignment]: Return value missing on the stack. { Offset = 0x88 }
[Write]: Unexpected type on the stack. { Offset = 0x2c, Found = Int32, Expected = ref '[System.Runtime]System.Threading.Tasks.Task`1<int32>' }
[<ReassignADuringAssignment>g__WriteAndReassign|0]: Unexpected type on the stack. { Offset = 0x33, Found = Int32, Expected = ref '[System.Runtime]System.Threading.Tasks.Task`1<int32>' }
[<ReassignXDuringAssignment>g__WriteAndReassign|0]: Unexpected type on the stack. { Offset = 0x39, Found = Int32, Expected = ref '[System.Runtime]System.Threading.Tasks.Task`1<int32>' }
"""
});
verifier.VerifyDiagnostics();
verifier.VerifyIL("Program.Assign(A)", """
{
// Code size 35 (0x23)
.maxstack 3
.locals init (A V_0,
int V_1,
int V_2)
IL_0000: ldarg.0
IL_0001: dup
IL_0002: stloc.0
IL_0003: ldfld "int A.x"
IL_0008: stloc.1
IL_0009: ldstr "RHS"
IL_000e: call "System.Threading.Tasks.Task<int> Program.Write(string)"
IL_0013: call "int System.Runtime.CompilerServices.AsyncHelpers.Await<int>(System.Threading.Tasks.Task<int>)"
IL_0018: stloc.2
IL_0019: ldloc.0
IL_001a: ldloc.1
IL_001b: ldloc.2
IL_001c: add
IL_001d: stfld "int A.x"
IL_0022: ret
}
""");
}
[Fact]
[WorkItem(42755, "https://github.com/dotnet/roslyn/issues/42755")]
public void KeepLtrSemantics_CompoundAssignmentProperties()
{
var source = @"
using System;
using System.Threading.Tasks;
class Program
{
static async Task Assign(A a)
{
a.x += await Write(""RHS"");
}
static async Task Main(string[] args)
{
await TestAIsNull();
await TestAIsNotNull();
await ReassignADuringAssignment();
await ReassignXDuringAssignment();
}
static async Task TestAIsNull()
{
Console.WriteLine(nameof(TestAIsNull));
A a = null;
Console.WriteLine(""Before Assignment"");
try
{
await Assign(a);
}
catch (NullReferenceException)
{
Console.WriteLine(""Caught NullReferenceException"");
}
}
static async Task TestAIsNotNull()
{
Console.WriteLine(nameof(TestAIsNotNull));
var a = new A(){ _x = 1 };
Console.WriteLine(""Before Assignment a._x is: "" + a._x);
await Assign(a);
Console.WriteLine(""After Assignment a._x is: "" + a._x);
}
static async Task ReassignADuringAssignment()
{
Console.WriteLine(nameof(ReassignADuringAssignment));
var a = new A(){ _x = 1 };
var aCopy = a;
Console.WriteLine(""Before Assignment a is null == "" + (a is null));
Console.WriteLine(""Before Assignment aCopy._x is: "" + aCopy._x);
a.x += await WriteAndReassign(""RHS"");
Console.WriteLine(""After Assignment a is null == "" + (a is null));
Console.WriteLine(""After Assignment aCopy._x is: "" + aCopy._x);
async Task<int> WriteAndReassign(string s)
{
await Task.Yield();
a = null;
Console.WriteLine(s);
return 42;
}
}
static async Task ReassignXDuringAssignment()
{
Console.WriteLine(nameof(ReassignXDuringAssignment));
var a = new A(){ _x = 1 };
Console.WriteLine(""Before Assignment a._x is: "" + a._x);
a.x += await WriteAndReassign(""RHS"");
Console.WriteLine(""After Assignment a._x is: "" + a._x);
async Task<int> WriteAndReassign(string s)
{
await Task.Yield();
a._x = 100;
Console.WriteLine(s);
return 42;
}
}
static async Task<int> Write(string s)
{
await Task.Yield();
Console.WriteLine(s);
return 42;
}
}
class A
{
public int _x;
public int x { get { Console.WriteLine(""GetX""); return _x; } set { Console.WriteLine(""SetX""); _x = value; } }
}";
var comp = CreateCompilation(source, options: TestOptions.ReleaseExe);
var expectedOutput = """
TestAIsNull
Before Assignment
Caught NullReferenceException
TestAIsNotNull
Before Assignment a._x is: 1
GetX
RHS
SetX
After Assignment a._x is: 43
ReassignADuringAssignment
Before Assignment a is null == False
Before Assignment aCopy._x is: 1
GetX
RHS
SetX
After Assignment a is null == True
After Assignment aCopy._x is: 43
ReassignXDuringAssignment
Before Assignment a._x is: 1
GetX
RHS
SetX
After Assignment a._x is: 43
""";
CompileAndVerify(comp, expectedOutput: expectedOutput)
.VerifyIL("Program.<Assign>d__0.System.Runtime.CompilerServices.IAsyncStateMachine.MoveNext", @"
{
// Code size 202 (0xca)
.maxstack 3
.locals init (int V_0,
A V_1,
int V_2,
System.Runtime.CompilerServices.TaskAwaiter<int> V_3,
System.Exception V_4)
IL_0000: ldarg.0
IL_0001: ldfld ""int Program.<Assign>d__0.<>1__state""
IL_0006: stloc.0
.try
{
IL_0007: ldloc.0
IL_0008: brfalse.s IL_005d
IL_000a: ldarg.0
IL_000b: ldfld ""A Program.<Assign>d__0.a""
IL_0010: stloc.1
IL_0011: ldarg.0
IL_0012: ldloc.1
IL_0013: stfld ""A Program.<Assign>d__0.<>7__wrap1""
IL_0018: ldarg.0
IL_0019: ldloc.1
IL_001a: callvirt ""int A.x.get""
IL_001f: stfld ""int Program.<Assign>d__0.<>7__wrap2""
IL_0024: ldstr ""RHS""
IL_0029: call ""System.Threading.Tasks.Task<int> Program.Write(string)""
IL_002e: callvirt ""System.Runtime.CompilerServices.TaskAwaiter<int> System.Threading.Tasks.Task<int>.GetAwaiter()""
IL_0033: stloc.3
IL_0034: ldloca.s V_3
IL_0036: call ""bool System.Runtime.CompilerServices.TaskAwaiter<int>.IsCompleted.get""
IL_003b: brtrue.s IL_0079
IL_003d: ldarg.0
IL_003e: ldc.i4.0
IL_003f: dup
IL_0040: stloc.0
IL_0041: stfld ""int Program.<Assign>d__0.<>1__state""
IL_0046: ldarg.0
IL_0047: ldloc.3
IL_0048: stfld ""System.Runtime.CompilerServices.TaskAwaiter<int> Program.<Assign>d__0.<>u__1""
IL_004d: ldarg.0
IL_004e: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.<Assign>d__0.<>t__builder""
IL_0053: ldloca.s V_3
IL_0055: ldarg.0
IL_0056: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.AwaitUnsafeOnCompleted<System.Runtime.CompilerServices.TaskAwaiter<int>, Program.<Assign>d__0>(ref System.Runtime.CompilerServices.TaskAwaiter<int>, ref Program.<Assign>d__0)""
IL_005b: leave.s IL_00c9
IL_005d: ldarg.0
IL_005e: ldfld ""System.Runtime.CompilerServices.TaskAwaiter<int> Program.<Assign>d__0.<>u__1""
IL_0063: stloc.3
IL_0064: ldarg.0
IL_0065: ldflda ""System.Runtime.CompilerServices.TaskAwaiter<int> Program.<Assign>d__0.<>u__1""
IL_006a: initobj ""System.Runtime.CompilerServices.TaskAwaiter<int>""
IL_0070: ldarg.0
IL_0071: ldc.i4.m1
IL_0072: dup
IL_0073: stloc.0
IL_0074: stfld ""int Program.<Assign>d__0.<>1__state""
IL_0079: ldloca.s V_3
IL_007b: call ""int System.Runtime.CompilerServices.TaskAwaiter<int>.GetResult()""
IL_0080: stloc.2
IL_0081: ldarg.0
IL_0082: ldfld ""A Program.<Assign>d__0.<>7__wrap1""
IL_0087: ldarg.0
IL_0088: ldfld ""int Program.<Assign>d__0.<>7__wrap2""
IL_008d: ldloc.2
IL_008e: add
IL_008f: callvirt ""void A.x.set""
IL_0094: ldarg.0
IL_0095: ldnull
IL_0096: stfld ""A Program.<Assign>d__0.<>7__wrap1""
IL_009b: leave.s IL_00b6
}
catch System.Exception
{
IL_009d: stloc.s V_4
IL_009f: ldarg.0
IL_00a0: ldc.i4.s -2
IL_00a2: stfld ""int Program.<Assign>d__0.<>1__state""
IL_00a7: ldarg.0
IL_00a8: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.<Assign>d__0.<>t__builder""
IL_00ad: ldloc.s V_4
IL_00af: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetException(System.Exception)""
IL_00b4: leave.s IL_00c9
}
IL_00b6: ldarg.0
IL_00b7: ldc.i4.s -2
IL_00b9: stfld ""int Program.<Assign>d__0.<>1__state""
IL_00be: ldarg.0
IL_00bf: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.<Assign>d__0.<>t__builder""
IL_00c4: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetResult()""
IL_00c9: ret
}");
comp = CreateRuntimeAsyncCompilation(source);
var verifier = CompileAndVerify(comp, expectedOutput: CodeGenAsyncTests.ExpectedOutput(expectedOutput, isRuntimeAsync: true), verify: Verification.Fails with
{
ILVerifyMessage = """
[Assign]: Return value missing on the stack. { Offset = 0x22 }
[Main]: Return value missing on the stack. { Offset = 0x28 }
[TestAIsNull]: Return value missing on the stack. { Offset = 0x30 }
[TestAIsNotNull]: Return value missing on the stack. { Offset = 0x56 }
[ReassignADuringAssignment]: Return value missing on the stack. { Offset = 0xc9 }
[ReassignXDuringAssignment]: Return value missing on the stack. { Offset = 0x88 }
[Write]: Unexpected type on the stack. { Offset = 0x2c, Found = Int32, Expected = ref '[System.Runtime]System.Threading.Tasks.Task`1<int32>' }
[<ReassignADuringAssignment>g__WriteAndReassign|0]: Unexpected type on the stack. { Offset = 0x33, Found = Int32, Expected = ref '[System.Runtime]System.Threading.Tasks.Task`1<int32>' }
[<ReassignXDuringAssignment>g__WriteAndReassign|0]: Unexpected type on the stack. { Offset = 0x39, Found = Int32, Expected = ref '[System.Runtime]System.Threading.Tasks.Task`1<int32>' }
"""
});
verifier.VerifyDiagnostics();
verifier.VerifyIL("Program.Assign(A)", """
{
// Code size 35 (0x23)
.maxstack 3
.locals init (A V_0,
int V_1,
int V_2)
IL_0000: ldarg.0
IL_0001: dup
IL_0002: stloc.0
IL_0003: callvirt "int A.x.get"
IL_0008: stloc.1
IL_0009: ldstr "RHS"
IL_000e: call "System.Threading.Tasks.Task<int> Program.Write(string)"
IL_0013: call "int System.Runtime.CompilerServices.AsyncHelpers.Await<int>(System.Threading.Tasks.Task<int>)"
IL_0018: stloc.2
IL_0019: ldloc.0
IL_001a: ldloc.1
IL_001b: ldloc.2
IL_001c: add
IL_001d: callvirt "void A.x.set"
IL_0022: ret
}
""");
}
[WorkItem(19609, "https://github.com/dotnet/roslyn/issues/19609")]
[Fact]
public void KeepLtrSemantics_AssignmentToAssignment()
{
var source = @"
using System;
using System.Threading.Tasks;
class Program
{
static async Task Assign(A a, B b)
{
a.b.x = b.x = await Write(""RHS"");
}
static async Task Main(string[] args)
{
await TestAIsNullBIsNull();
await TestAIsNullBIsNotNull();
await TestAIsNotNullBIsNull();
await TestADotBIsNullBIsNotNull();
await TestADotBIsNotNullBIsNotNull();
}
static async Task TestAIsNullBIsNull()
{
Console.WriteLine(nameof(TestAIsNullBIsNull));
A a = null;
B b = null;
Console.WriteLine(""Before Assignment"");
try
{
await Assign(a, b);
}
catch (NullReferenceException)
{
Console.WriteLine(""Caught NullReferenceException"");
}
}
static async Task TestAIsNullBIsNotNull()
{
Console.WriteLine(nameof(TestAIsNullBIsNotNull));
A a = null;
B b = new B();
Console.WriteLine(""Before Assignment"");
try
{
await Assign(a, b);
}
catch (NullReferenceException)
{
Console.WriteLine(""Caught NullReferenceException"");
}
}
static async Task TestAIsNotNullBIsNull()
{
Console.WriteLine(nameof(TestAIsNotNullBIsNull));
A a = new A{ b = new B() };
B b = null;
Console.WriteLine(""Before Assignment"");
try
{
await Assign(a, b);
}
catch (NullReferenceException)
{
Console.WriteLine(""Caught NullReferenceException"");
}
}
static async Task TestADotBIsNullBIsNotNull()
{
Console.WriteLine(nameof(TestADotBIsNullBIsNotNull));
A a = new A();
B b = new B();
Console.WriteLine(""Before Assignment"");
try
{
await Assign(a, b);
}
catch (NullReferenceException)
{
Console.WriteLine(""Caught NullReferenceException"");
}
}
static async Task TestADotBIsNotNullBIsNotNull()
{
Console.WriteLine(nameof(TestADotBIsNotNullBIsNotNull));
A a = new A{ b = new B() };
B b = new B();
Console.WriteLine(""Before Assignment a.b.x is: "" + a.b.x);
Console.WriteLine(""Before Assignment b.x is: "" + b.x);
await Assign(a, b);
Console.WriteLine(""After Assignment a.b.x is: "" + a.b.x);
Console.WriteLine(""After Assignment b.x is: "" + b.x);
}
static async Task<int> Write(string s)
{
await Task.Yield();
Console.WriteLine(s);
return 42;
}
}
class A
{
public B b;
}
class B
{
public int x;
}";
var comp = CreateCompilation(source, options: TestOptions.ReleaseExe);
var expectedOutput = """
TestAIsNullBIsNull
Before Assignment
Caught NullReferenceException
TestAIsNullBIsNotNull
Before Assignment
Caught NullReferenceException
TestAIsNotNullBIsNull
Before Assignment
RHS
Caught NullReferenceException
TestADotBIsNullBIsNotNull
Before Assignment
RHS
Caught NullReferenceException
TestADotBIsNotNullBIsNotNull
Before Assignment a.b.x is: 0
Before Assignment b.x is: 0
RHS
After Assignment a.b.x is: 42
After Assignment b.x is: 42
""";
CompileAndVerify(comp, expectedOutput: expectedOutput)
.VerifyIL("Program.<Assign>d__0.System.Runtime.CompilerServices.IAsyncStateMachine.MoveNext", @"
{
// Code size 219 (0xdb)
.maxstack 4
.locals init (int V_0,
int V_1,
System.Runtime.CompilerServices.TaskAwaiter<int> V_2,
int V_3,
System.Exception V_4)
IL_0000: ldarg.0
IL_0001: ldfld ""int Program.<Assign>d__0.<>1__state""
IL_0006: stloc.0
.try
{
IL_0007: ldloc.0
IL_0008: brfalse.s IL_0060
IL_000a: ldarg.0
IL_000b: ldarg.0
IL_000c: ldfld ""A Program.<Assign>d__0.a""
IL_0011: ldfld ""B A.b""
IL_0016: stfld ""B Program.<Assign>d__0.<>7__wrap1""
IL_001b: ldarg.0
IL_001c: ldarg.0
IL_001d: ldfld ""B Program.<Assign>d__0.b""
IL_0022: stfld ""B Program.<Assign>d__0.<>7__wrap2""
IL_0027: ldstr ""RHS""
IL_002c: call ""System.Threading.Tasks.Task<int> Program.Write(string)""
IL_0031: callvirt ""System.Runtime.CompilerServices.TaskAwaiter<int> System.Threading.Tasks.Task<int>.GetAwaiter()""
IL_0036: stloc.2
IL_0037: ldloca.s V_2
IL_0039: call ""bool System.Runtime.CompilerServices.TaskAwaiter<int>.IsCompleted.get""
IL_003e: brtrue.s IL_007c
IL_0040: ldarg.0
IL_0041: ldc.i4.0
IL_0042: dup
IL_0043: stloc.0
IL_0044: stfld ""int Program.<Assign>d__0.<>1__state""
IL_0049: ldarg.0
IL_004a: ldloc.2
IL_004b: stfld ""System.Runtime.CompilerServices.TaskAwaiter<int> Program.<Assign>d__0.<>u__1""
IL_0050: ldarg.0
IL_0051: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.<Assign>d__0.<>t__builder""
IL_0056: ldloca.s V_2
IL_0058: ldarg.0
IL_0059: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.AwaitUnsafeOnCompleted<System.Runtime.CompilerServices.TaskAwaiter<int>, Program.<Assign>d__0>(ref System.Runtime.CompilerServices.TaskAwaiter<int>, ref Program.<Assign>d__0)""
IL_005e: leave.s IL_00da
IL_0060: ldarg.0
IL_0061: ldfld ""System.Runtime.CompilerServices.TaskAwaiter<int> Program.<Assign>d__0.<>u__1""
IL_0066: stloc.2
IL_0067: ldarg.0
IL_0068: ldflda ""System.Runtime.CompilerServices.TaskAwaiter<int> Program.<Assign>d__0.<>u__1""
IL_006d: initobj ""System.Runtime.CompilerServices.TaskAwaiter<int>""
IL_0073: ldarg.0
IL_0074: ldc.i4.m1
IL_0075: dup
IL_0076: stloc.0
IL_0077: stfld ""int Program.<Assign>d__0.<>1__state""
IL_007c: ldloca.s V_2
IL_007e: call ""int System.Runtime.CompilerServices.TaskAwaiter<int>.GetResult()""
IL_0083: stloc.1
IL_0084: ldarg.0
IL_0085: ldfld ""B Program.<Assign>d__0.<>7__wrap1""
IL_008a: ldarg.0
IL_008b: ldfld ""B Program.<Assign>d__0.<>7__wrap2""
IL_0090: ldloc.1
IL_0091: dup
IL_0092: stloc.3
IL_0093: stfld ""int B.x""
IL_0098: ldloc.3
IL_0099: stfld ""int B.x""
IL_009e: ldarg.0
IL_009f: ldnull
IL_00a0: stfld ""B Program.<Assign>d__0.<>7__wrap1""
IL_00a5: ldarg.0
IL_00a6: ldnull
IL_00a7: stfld ""B Program.<Assign>d__0.<>7__wrap2""
IL_00ac: leave.s IL_00c7
}
catch System.Exception
{
IL_00ae: stloc.s V_4
IL_00b0: ldarg.0
IL_00b1: ldc.i4.s -2
IL_00b3: stfld ""int Program.<Assign>d__0.<>1__state""
IL_00b8: ldarg.0
IL_00b9: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.<Assign>d__0.<>t__builder""
IL_00be: ldloc.s V_4
IL_00c0: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetException(System.Exception)""
IL_00c5: leave.s IL_00da
}
IL_00c7: ldarg.0
IL_00c8: ldc.i4.s -2
IL_00ca: stfld ""int Program.<Assign>d__0.<>1__state""
IL_00cf: ldarg.0
IL_00d0: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.<Assign>d__0.<>t__builder""
IL_00d5: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetResult()""
IL_00da: ret
}");
comp = CreateRuntimeAsyncCompilation(source);
var verifier = CompileAndVerify(comp, expectedOutput: CodeGenAsyncTests.ExpectedOutput(expectedOutput, isRuntimeAsync: true), verify: Verification.Fails with
{
ILVerifyMessage = """
[Assign]: Return value missing on the stack. { Offset = 0x27 }
[Main]: Return value missing on the stack. { Offset = 0x32 }
[TestAIsNullBIsNull]: Return value missing on the stack. { Offset = 0x33 }
[TestAIsNullBIsNotNull]: Return value missing on the stack. { Offset = 0x37 }
[TestAIsNotNullBIsNull]: Return value missing on the stack. { Offset = 0x42 }
[TestADotBIsNullBIsNotNull]: Return value missing on the stack. { Offset = 0x3b }
[TestADotBIsNotNullBIsNotNull]: Return value missing on the stack. { Offset = 0x9f }
[Write]: Unexpected type on the stack. { Offset = 0x2c, Found = Int32, Expected = ref '[System.Runtime]System.Threading.Tasks.Task`1<int32>' }
"""
});
verifier.VerifyDiagnostics();
verifier.VerifyIL("Program.Assign(A, B)", """
{
// Code size 40 (0x28)
.maxstack 4
.locals init (B V_0,
int V_1,
int V_2)
IL_0000: ldarg.0
IL_0001: ldfld "B A.b"
IL_0006: ldarg.1
IL_0007: stloc.0
IL_0008: ldstr "RHS"
IL_000d: call "System.Threading.Tasks.Task<int> Program.Write(string)"
IL_0012: call "int System.Runtime.CompilerServices.AsyncHelpers.Await<int>(System.Threading.Tasks.Task<int>)"
IL_0017: stloc.1
IL_0018: ldloc.0
IL_0019: ldloc.1
IL_001a: dup
IL_001b: stloc.2
IL_001c: stfld "int B.x"
IL_0021: ldloc.2
IL_0022: stfld "int B.x"
IL_0027: ret
}
""");
}
[WorkItem(19609, "https://github.com/dotnet/roslyn/issues/19609")]
[Fact]
public void KeepLtrSemantics_AssignmentToAssignmentProperties()
{
var source = @"
using System;
using System.Threading.Tasks;
class Program
{
static async Task Assign(A a, B b)
{
a.b.x = b.x = await Write(""RHS"");
}
static async Task Main(string[] args)
{
await TestAIsNullBIsNull();
await TestAIsNullBIsNotNull();
await TestAIsNotNullBIsNull();
await TestADotBIsNullBIsNotNull();
await TestADotBIsNotNullBIsNotNull();
}
static async Task TestAIsNullBIsNull()
{
Console.WriteLine(nameof(TestAIsNullBIsNull));
A a = null;
B b = null;
Console.WriteLine(""Before Assignment"");
try
{
await Assign(a, b);
}
catch (NullReferenceException)
{
Console.WriteLine(""Caught NullReferenceException"");
}
}
static async Task TestAIsNullBIsNotNull()
{
Console.WriteLine(nameof(TestAIsNullBIsNotNull));
A a = null;
B b = new B();
Console.WriteLine(""Before Assignment"");
try
{
await Assign(a, b);
}
catch (NullReferenceException)
{
Console.WriteLine(""Caught NullReferenceException"");
}
}
static async Task TestAIsNotNullBIsNull()
{
Console.WriteLine(nameof(TestAIsNotNullBIsNull));
A a = new A{ _b = new B() };
B b = null;
Console.WriteLine(""Before Assignment"");
try
{
await Assign(a, b);
}
catch (NullReferenceException)
{
Console.WriteLine(""Caught NullReferenceException"");
}
}
static async Task TestADotBIsNullBIsNotNull()
{
Console.WriteLine(nameof(TestADotBIsNullBIsNotNull));
A a = new A();
B b = new B();
Console.WriteLine(""Before Assignment"");
try
{
await Assign(a, b);
}
catch (NullReferenceException)
{
Console.WriteLine(""Caught NullReferenceException"");
}
}
static async Task TestADotBIsNotNullBIsNotNull()
{
Console.WriteLine(nameof(TestADotBIsNotNullBIsNotNull));
A a = new A{ _b = new B() };
B b = new B();
Console.WriteLine(""Before Assignment a._b._x is: "" + a._b._x);
Console.WriteLine(""Before Assignment b._x is: "" + b._x);
await Assign(a, b);
Console.WriteLine(""After Assignment a._b._x is: "" + a._b._x);
Console.WriteLine(""After Assignment b._x is: "" + b._x);
}
static async Task<int> Write(string s)
{
await Task.Yield();
Console.WriteLine(s);
return 42;
}
}
class A
{
public B _b;
public B b { get { Console.WriteLine(""GetB""); return _b; } set { Console.WriteLine(""SetB""); _b = value; }}
}
class B
{
public int _x;
public int x { get { Console.WriteLine(""GetX""); return _x; } set { Console.WriteLine(""SetX""); _x = value; } }
}";
var comp = CreateCompilation(source, options: TestOptions.ReleaseExe);
var expectedOutput = """
TestAIsNullBIsNull
Before Assignment
Caught NullReferenceException
TestAIsNullBIsNotNull
Before Assignment
Caught NullReferenceException
TestAIsNotNullBIsNull
Before Assignment
GetB
RHS
Caught NullReferenceException
TestADotBIsNullBIsNotNull
Before Assignment
GetB
RHS
SetX
Caught NullReferenceException
TestADotBIsNotNullBIsNotNull
Before Assignment a._b._x is: 0
Before Assignment b._x is: 0
GetB
RHS
SetX
SetX
After Assignment a._b._x is: 42
After Assignment b._x is: 42
""";
CompileAndVerify(comp, expectedOutput: expectedOutput)
.VerifyIL("Program.<Assign>d__0.System.Runtime.CompilerServices.IAsyncStateMachine.MoveNext", @"
{
// Code size 219 (0xdb)
.maxstack 3
.locals init (int V_0,
int V_1,
int V_2,
System.Runtime.CompilerServices.TaskAwaiter<int> V_3,
System.Exception V_4)
IL_0000: ldarg.0
IL_0001: ldfld ""int Program.<Assign>d__0.<>1__state""
IL_0006: stloc.0
.try
{
IL_0007: ldloc.0
IL_0008: brfalse.s IL_0060
IL_000a: ldarg.0
IL_000b: ldarg.0
IL_000c: ldfld ""A Program.<Assign>d__0.a""
IL_0011: callvirt ""B A.b.get""
IL_0016: stfld ""B Program.<Assign>d__0.<>7__wrap1""
IL_001b: ldarg.0
IL_001c: ldarg.0
IL_001d: ldfld ""B Program.<Assign>d__0.b""
IL_0022: stfld ""B Program.<Assign>d__0.<>7__wrap2""
IL_0027: ldstr ""RHS""
IL_002c: call ""System.Threading.Tasks.Task<int> Program.Write(string)""
IL_0031: callvirt ""System.Runtime.CompilerServices.TaskAwaiter<int> System.Threading.Tasks.Task<int>.GetAwaiter()""
IL_0036: stloc.3
IL_0037: ldloca.s V_3
IL_0039: call ""bool System.Runtime.CompilerServices.TaskAwaiter<int>.IsCompleted.get""
IL_003e: brtrue.s IL_007c
IL_0040: ldarg.0
IL_0041: ldc.i4.0
IL_0042: dup
IL_0043: stloc.0
IL_0044: stfld ""int Program.<Assign>d__0.<>1__state""
IL_0049: ldarg.0
IL_004a: ldloc.3
IL_004b: stfld ""System.Runtime.CompilerServices.TaskAwaiter<int> Program.<Assign>d__0.<>u__1""
IL_0050: ldarg.0
IL_0051: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.<Assign>d__0.<>t__builder""
IL_0056: ldloca.s V_3
IL_0058: ldarg.0
IL_0059: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.AwaitUnsafeOnCompleted<System.Runtime.CompilerServices.TaskAwaiter<int>, Program.<Assign>d__0>(ref System.Runtime.CompilerServices.TaskAwaiter<int>, ref Program.<Assign>d__0)""
IL_005e: leave.s IL_00da
IL_0060: ldarg.0
IL_0061: ldfld ""System.Runtime.CompilerServices.TaskAwaiter<int> Program.<Assign>d__0.<>u__1""
IL_0066: stloc.3
IL_0067: ldarg.0
IL_0068: ldflda ""System.Runtime.CompilerServices.TaskAwaiter<int> Program.<Assign>d__0.<>u__1""
IL_006d: initobj ""System.Runtime.CompilerServices.TaskAwaiter<int>""
IL_0073: ldarg.0
IL_0074: ldc.i4.m1
IL_0075: dup
IL_0076: stloc.0
IL_0077: stfld ""int Program.<Assign>d__0.<>1__state""
IL_007c: ldloca.s V_3
IL_007e: call ""int System.Runtime.CompilerServices.TaskAwaiter<int>.GetResult()""
IL_0083: stloc.1
IL_0084: ldarg.0
IL_0085: ldfld ""B Program.<Assign>d__0.<>7__wrap2""
IL_008a: ldloc.1
IL_008b: dup
IL_008c: stloc.2
IL_008d: callvirt ""void B.x.set""
IL_0092: ldarg.0
IL_0093: ldfld ""B Program.<Assign>d__0.<>7__wrap1""
IL_0098: ldloc.2
IL_0099: callvirt ""void B.x.set""
IL_009e: ldarg.0
IL_009f: ldnull
IL_00a0: stfld ""B Program.<Assign>d__0.<>7__wrap1""
IL_00a5: ldarg.0
IL_00a6: ldnull
IL_00a7: stfld ""B Program.<Assign>d__0.<>7__wrap2""
IL_00ac: leave.s IL_00c7
}
catch System.Exception
{
IL_00ae: stloc.s V_4
IL_00b0: ldarg.0
IL_00b1: ldc.i4.s -2
IL_00b3: stfld ""int Program.<Assign>d__0.<>1__state""
IL_00b8: ldarg.0
IL_00b9: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.<Assign>d__0.<>t__builder""
IL_00be: ldloc.s V_4
IL_00c0: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetException(System.Exception)""
IL_00c5: leave.s IL_00da
}
IL_00c7: ldarg.0
IL_00c8: ldc.i4.s -2
IL_00ca: stfld ""int Program.<Assign>d__0.<>1__state""
IL_00cf: ldarg.0
IL_00d0: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.<Assign>d__0.<>t__builder""
IL_00d5: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetResult()""
IL_00da: ret
}");
comp = CreateRuntimeAsyncCompilation(source);
var verifier = CompileAndVerify(comp, expectedOutput: CodeGenAsyncTests.ExpectedOutput(expectedOutput, isRuntimeAsync: true), verify: Verification.Fails with
{
ILVerifyMessage = """
[Assign]: Return value missing on the stack. { Offset = 0x25 }
[Main]: Return value missing on the stack. { Offset = 0x32 }
[TestAIsNullBIsNull]: Return value missing on the stack. { Offset = 0x33 }
[TestAIsNullBIsNotNull]: Return value missing on the stack. { Offset = 0x37 }
[TestAIsNotNullBIsNull]: Return value missing on the stack. { Offset = 0x42 }
[TestADotBIsNullBIsNotNull]: Return value missing on the stack. { Offset = 0x3b }
[TestADotBIsNotNullBIsNotNull]: Return value missing on the stack. { Offset = 0x9f }
[Write]: Unexpected type on the stack. { Offset = 0x2c, Found = Int32, Expected = ref '[System.Runtime]System.Threading.Tasks.Task`1<int32>' }
"""
});
verifier.VerifyDiagnostics();
verifier.VerifyIL("Program.Assign(A, B)", """
{
// Code size 38 (0x26)
.maxstack 4
.locals init (int V_0,
int V_1)
IL_0000: ldarg.0
IL_0001: callvirt "B A.b.get"
IL_0006: ldarg.1
IL_0007: ldstr "RHS"
IL_000c: call "System.Threading.Tasks.Task<int> Program.Write(string)"
IL_0011: call "int System.Runtime.CompilerServices.AsyncHelpers.Await<int>(System.Threading.Tasks.Task<int>)"
IL_0016: stloc.0
IL_0017: ldloc.0
IL_0018: dup
IL_0019: stloc.1
IL_001a: callvirt "void B.x.set"
IL_001f: ldloc.1
IL_0020: callvirt "void B.x.set"
IL_0025: ret
}
""");
}
[Fact]
[WorkItem(42755, "https://github.com/dotnet/roslyn/issues/42755")]
public void AssignmentToFieldOfStaticFieldOfStruct()
{
var source = @"
using System;
using System.Threading.Tasks;
class Program
{
static async Task Assign()
{
A.b.x = await Write(""RHS"");
}
static async Task<int> Write(string s)
{
await Task.Yield();
Console.WriteLine(s);
return 42;
}
static async Task Main(string[] args)
{
Console.WriteLine(""Before Assignment A.b.x is: "" + A.b.x);
await Assign();
Console.WriteLine(""After Assignment A.b.x is: "" + A.b.x);
}
}
struct A
{
public static B b;
}
struct B
{
public int x;
}";
var comp = CreateCompilation(source, options: TestOptions.ReleaseExe);
var expectedOutput = """
Before Assignment A.b.x is: 0
RHS
After Assignment A.b.x is: 42
""";
CompileAndVerify(comp, expectedOutput: expectedOutput)
.VerifyIL("Program.<Assign>d__0.System.Runtime.CompilerServices.IAsyncStateMachine.MoveNext", @"
{
// Code size 159 (0x9f)
.maxstack 3
.locals init (int V_0,
int V_1,
System.Runtime.CompilerServices.TaskAwaiter<int> V_2,
System.Exception V_3)
IL_0000: ldarg.0
IL_0001: ldfld ""int Program.<Assign>d__0.<>1__state""
IL_0006: stloc.0
.try
{
IL_0007: ldloc.0
IL_0008: brfalse.s IL_0043
IL_000a: ldstr ""RHS""
IL_000f: call ""System.Threading.Tasks.Task<int> Program.Write(string)""
IL_0014: callvirt ""System.Runtime.CompilerServices.TaskAwaiter<int> System.Threading.Tasks.Task<int>.GetAwaiter()""
IL_0019: stloc.2
IL_001a: ldloca.s V_2
IL_001c: call ""bool System.Runtime.CompilerServices.TaskAwaiter<int>.IsCompleted.get""
IL_0021: brtrue.s IL_005f
IL_0023: ldarg.0
IL_0024: ldc.i4.0
IL_0025: dup
IL_0026: stloc.0
IL_0027: stfld ""int Program.<Assign>d__0.<>1__state""
IL_002c: ldarg.0
IL_002d: ldloc.2
IL_002e: stfld ""System.Runtime.CompilerServices.TaskAwaiter<int> Program.<Assign>d__0.<>u__1""
IL_0033: ldarg.0
IL_0034: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.<Assign>d__0.<>t__builder""
IL_0039: ldloca.s V_2
IL_003b: ldarg.0
IL_003c: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.AwaitUnsafeOnCompleted<System.Runtime.CompilerServices.TaskAwaiter<int>, Program.<Assign>d__0>(ref System.Runtime.CompilerServices.TaskAwaiter<int>, ref Program.<Assign>d__0)""
IL_0041: leave.s IL_009e
IL_0043: ldarg.0
IL_0044: ldfld ""System.Runtime.CompilerServices.TaskAwaiter<int> Program.<Assign>d__0.<>u__1""
IL_0049: stloc.2
IL_004a: ldarg.0
IL_004b: ldflda ""System.Runtime.CompilerServices.TaskAwaiter<int> Program.<Assign>d__0.<>u__1""
IL_0050: initobj ""System.Runtime.CompilerServices.TaskAwaiter<int>""
IL_0056: ldarg.0
IL_0057: ldc.i4.m1
IL_0058: dup
IL_0059: stloc.0
IL_005a: stfld ""int Program.<Assign>d__0.<>1__state""
IL_005f: ldloca.s V_2
IL_0061: call ""int System.Runtime.CompilerServices.TaskAwaiter<int>.GetResult()""
IL_0066: stloc.1
IL_0067: ldsflda ""B A.b""
IL_006c: ldloc.1
IL_006d: stfld ""int B.x""
IL_0072: leave.s IL_008b
}
catch System.Exception
{
IL_0074: stloc.3
IL_0075: ldarg.0
IL_0076: ldc.i4.s -2
IL_0078: stfld ""int Program.<Assign>d__0.<>1__state""
IL_007d: ldarg.0
IL_007e: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.<Assign>d__0.<>t__builder""
IL_0083: ldloc.3
IL_0084: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetException(System.Exception)""
IL_0089: leave.s IL_009e
}
IL_008b: ldarg.0
IL_008c: ldc.i4.s -2
IL_008e: stfld ""int Program.<Assign>d__0.<>1__state""
IL_0093: ldarg.0
IL_0094: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.<Assign>d__0.<>t__builder""
IL_0099: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetResult()""
IL_009e: ret
}");
comp = CreateRuntimeAsyncCompilation(source);
var verifier = CompileAndVerify(comp, expectedOutput: CodeGenAsyncTests.ExpectedOutput(expectedOutput, isRuntimeAsync: true), verify: Verification.Fails with
{
ILVerifyMessage = """
[Assign]: Return value missing on the stack. { Offset = 0x1b }
[Write]: Unexpected type on the stack. { Offset = 0x2c, Found = Int32, Expected = ref '[System.Runtime]System.Threading.Tasks.Task`1<int32>' }
[Main]: Return value missing on the stack. { Offset = 0x46 }
"""
});
verifier.VerifyDiagnostics();
verifier.VerifyIL("Program.Assign()", """
{
// Code size 28 (0x1c)
.maxstack 2
.locals init (int V_0)
IL_0000: ldstr "RHS"
IL_0005: call "System.Threading.Tasks.Task<int> Program.Write(string)"
IL_000a: call "int System.Runtime.CompilerServices.AsyncHelpers.Await<int>(System.Threading.Tasks.Task<int>)"
IL_000f: stloc.0
IL_0010: ldsflda "B A.b"
IL_0015: ldloc.0
IL_0016: stfld "int B.x"
IL_001b: ret
}
""");
}
[Fact, WorkItem(47191, "https://github.com/dotnet/roslyn/issues/47191")]
public void AssignStaticStructField()
{
var source = @"
using System;
using System.Threading.Tasks;
public struct S1
{
public int Field;
}
public class C
{
public static S1 s1;
static async Task M(Task<int> t)
{
s1.Field = await t;
}
static async Task Main()
{
await M(Task.FromResult(1));
Console.Write(s1.Field);
}
}";
var expectedOutput = "1";
var verifier = CompileAndVerify(source, expectedOutput: expectedOutput);
verifier.VerifyDiagnostics();
var comp = CreateRuntimeAsyncCompilation(source);
verifier = CompileAndVerify(comp, expectedOutput: CodeGenAsyncTests.ExpectedOutput(expectedOutput, isRuntimeAsync: true), verify: Verification.Fails with
{
ILVerifyMessage = """
[M]: Return value missing on the stack. { Offset = 0x12 }
[Main]: Return value missing on the stack. { Offset = 0x1f }
"""
});
verifier.VerifyDiagnostics();
verifier.VerifyIL("C.M(System.Threading.Tasks.Task<int>)", """
{
// Code size 19 (0x13)
.maxstack 2
.locals init (int V_0)
IL_0000: ldarg.0
IL_0001: call "int System.Runtime.CompilerServices.AsyncHelpers.Await<int>(System.Threading.Tasks.Task<int>)"
IL_0006: stloc.0
IL_0007: ldsflda "S1 C.s1"
IL_000c: ldloc.0
IL_000d: stfld "int S1.Field"
IL_0012: ret
}
""");
}
[Fact, WorkItem(47191, "https://github.com/dotnet/roslyn/issues/47191")]
public void AssignStaticStructField_ViaUsingStatic()
{
var source = @"
using System;
using System.Threading.Tasks;
using static C;
public struct S1
{
public int Field;
}
public class C
{
public static S1 s1;
}
public class Program
{
static async Task M(Task<int> t)
{
s1.Field = await t;
}
static async Task Main()
{
await M(Task.FromResult(1));
Console.Write(s1.Field);
}
}
";
var expectedOutput = "1";
var verifier = CompileAndVerify(source, expectedOutput: expectedOutput);
verifier.VerifyDiagnostics();
var comp = CreateRuntimeAsyncCompilation(source);
verifier = CompileAndVerify(comp, expectedOutput: CodeGenAsyncTests.ExpectedOutput(expectedOutput, isRuntimeAsync: true), verify: Verification.Fails with
{
ILVerifyMessage = """
[M]: Return value missing on the stack. { Offset = 0x12 }
[Main]: Return value missing on the stack. { Offset = 0x1f }
"""
});
verifier.VerifyDiagnostics();
verifier.VerifyIL("Program.M(System.Threading.Tasks.Task<int>)", """
{
// Code size 19 (0x13)
.maxstack 2
.locals init (int V_0)
IL_0000: ldarg.0
IL_0001: call "int System.Runtime.CompilerServices.AsyncHelpers.Await<int>(System.Threading.Tasks.Task<int>)"
IL_0006: stloc.0
IL_0007: ldsflda "S1 C.s1"
IL_000c: ldloc.0
IL_000d: stfld "int S1.Field"
IL_0012: ret
}
""");
}
[Fact, WorkItem(47191, "https://github.com/dotnet/roslyn/issues/47191")]
public void AssignInstanceStructField()
{
var source = @"
using System;
using System.Threading.Tasks;
public struct S1
{
public int Field;
}
public class C
{
public S1 s1;
async Task M(Task<int> t)
{
s1.Field = await t;
}
static async Task Main()
{
var c = new C();
await c.M(Task.FromResult(1));
Console.Write(c.s1.Field);
}
}";
var expectedOutput = "1";
var verifier = CompileAndVerify(source, expectedOutput: expectedOutput);
verifier.VerifyDiagnostics();
var comp = CreateRuntimeAsyncCompilation(source);
verifier = CompileAndVerify(comp, expectedOutput: CodeGenAsyncTests.ExpectedOutput(expectedOutput, isRuntimeAsync: true), verify: Verification.Fails with
{
ILVerifyMessage = """
[M]: Return value missing on the stack. { Offset = 0x1a }
[Main]: Return value missing on the stack. { Offset = 0x25 }
"""
});
verifier.VerifyDiagnostics();
verifier.VerifyIL("C.M(System.Threading.Tasks.Task<int>)", """
{
// Code size 27 (0x1b)
.maxstack 2
.locals init (int V_0)
IL_0000: ldarg.0
IL_0001: ldfld "S1 C.s1"
IL_0006: pop
IL_0007: ldarg.1
IL_0008: call "int System.Runtime.CompilerServices.AsyncHelpers.Await<int>(System.Threading.Tasks.Task<int>)"
IL_000d: stloc.0
IL_000e: ldarg.0
IL_000f: ldflda "S1 C.s1"
IL_0014: ldloc.0
IL_0015: stfld "int S1.Field"
IL_001a: ret
}
""");
}
}
}
|