未验证 提交 703bfbc5 编写于 作者: J Julien Couvreur 提交者: GitHub

Call `AsyncVoidMethodBuilder.SetResult()` in `DisposeAsync()` (#30104)

上级 dd14a94c
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Diagnostics;
......@@ -95,6 +96,8 @@ internal sealed class AsyncMethodToStateMachineRewriter : MethodToStateMachineRe
_nextAwaiterId = slotAllocatorOpt?.PreviousAwaiterSlotCount ?? 0;
}
private bool IsAsyncIterator => _asyncIteratorInfo != null;
private FieldSymbol GetAwaiterField(TypeSymbol awaiterType)
{
FieldSymbol result;
......@@ -168,7 +171,7 @@ internal void GenerateMoveNext(BoundStatement body, MethodSymbol moveNextMethod)
// The remaining code is hidden to hide the fact that it can run concurrently with the task's continuation
}
if (_asyncIteratorInfo == null)
if (!IsAsyncIterator)
{
// builder.SetResult([RetVal])
bodyBuilder.Add(
......@@ -241,7 +244,7 @@ private BoundCatchBlock GenerateExceptionHandling(LocalSymbol exceptionLocal)
BoundExpression assignFinishedState =
F.AssignmentExpression(F.Field(F.This(), stateField), F.Literal(StateMachineStates.FinishedStateMachine));
if (_asyncIteratorInfo == null)
if (!IsAsyncIterator)
{
return new BoundCatchBlock(
F.Syntax,
......@@ -451,7 +454,7 @@ private BoundBlock GenerateAwaitForIncompleteTask(LocalSymbol awaiterTemp)
? F.Local(awaiterTemp)
: F.Convert(awaiterFieldType, F.Local(awaiterTemp))));
if (_asyncIteratorInfo != null)
if (IsAsyncIterator)
{
blockBuilder.Add(
GenerateResetPromiseIfInactive());
......@@ -611,7 +614,7 @@ private BoundStatement GenerateAwaitOnCompleted(TypeSymbol loweredAwaiterType, L
private BoundStatement GenerateResetPromiseIfInactive()
{
Debug.Assert(_asyncIteratorInfo != null);
Debug.Assert(IsAsyncIterator);
// this.promiseIsActive = true;
BoundFieldAccess promiseIsActiveField = F.Field(F.This(), _asyncIteratorInfo.PromiseIsActiveField);
......@@ -632,23 +635,6 @@ private BoundStatement GenerateResetPromiseIfInactive()
thenClause: F.Block(assignTrue, callReset));
}
private BoundStatement GenerateSetResultOnPromiseIfActive(bool result)
{
Debug.Assert(_asyncIteratorInfo != null);
// this.promiseOfValueOrEnd.SetResult(result);
BoundExpressionStatement callSetResult = GenerateSetResultOnPromise(result);
// Produce:
// if (this.promiseIsActive)
// {
// this.promiseOfValueOrEnd.SetResult(result);
// }
return F.If(
F.Field(F.This(), _asyncIteratorInfo.PromiseIsActiveField),
thenClause: callSetResult);
}
private BoundExpressionStatement GenerateSetResultOnPromise(bool result)
{
// Produce:
......@@ -708,11 +694,13 @@ public override BoundNode VisitYieldReturnStatement(BoundYieldReturnStatement no
F.Assignment(F.Field(F.This(), stateField), F.Literal(stateNumber)));
blockBuilder.Add(
// if (promiseIsActive)
// if (this.promiseIsActive)
// {
// _valueOrEndPromise.SetResult(true);
// this.promiseOfValueOrEnd.SetResult(true);
// }
GenerateSetResultOnPromiseIfActive(true));
F.If(
F.Field(F.This(), _asyncIteratorInfo.PromiseIsActiveField),
thenClause: F.Block(GenerateSetResultOnPromise(true))));
blockBuilder.Add(
// goto <exit_label>;
......
......@@ -418,6 +418,7 @@ private void GenerateIStrongBox_get_Value()
private void GenerateIAsyncDisposable_DisposeAsync()
{
// Produce the implementation of `ValueTask IAsyncDisposable.DisposeAsync()`:
// this.builder.SetResult();
// this._valueOrEndPromise.Reset();
// this._state = StateNotStarted;
// return default;
......@@ -438,6 +439,13 @@ private void GenerateIAsyncDisposable_DisposeAsync()
F.WellKnownMethod(WellKnownMember.System_Threading_Tasks_ManualResetValueTaskSourceLogic_T__Reset)
.AsMember((NamedTypeSymbol)_promiseOfValueOrEndField.Type);
bodyBuilder.Add(
// this.builder.SetResult();
F.ExpressionStatement(
F.Call(
F.Field(F.This(), _builderField),
_asyncMethodBuilderMemberCollection.SetResult)));
bodyBuilder.Add(
// this._valueOrEndPromise.Reset();
F.ExpressionStatement(
......
......@@ -551,7 +551,7 @@ async System.Collections.Generic.IAsyncEnumerable<int> M2()
);
}
[ConditionalFact(typeof(WindowsDesktopOnly))]
[Fact]
public void CallingWaitForNextAsyncTwice()
{
string source = @"
......@@ -569,16 +569,18 @@ static async System.Collections.Generic.IAsyncEnumerable<int> M()
static async System.Threading.Tasks.Task Main()
{
Write(""0 "");
var enumerator = M().GetAsyncEnumerator();
var found = await enumerator.WaitForNextAsync();
if (!found) throw null;
Write(""3 "");
found = await enumerator.WaitForNextAsync();
if (!found) throw null;
var value = enumerator.TryGetNext(out var success);
Write($""{value} "");
await enumerator.WaitForNextAsync();
Write(""6"");
using await (var enumerator = M().GetAsyncEnumerator())
{
var found = await enumerator.WaitForNextAsync();
if (!found) throw null;
Write(""3 "");
found = await enumerator.WaitForNextAsync();
if (!found) throw null;
var value = enumerator.TryGetNext(out var success);
Write($""{value} "");
await enumerator.WaitForNextAsync();
Write(""6"");
}
}
}";
var comp = CreateCompilationWithTasksExtensions(new[] { source, s_common }, options: TestOptions.DebugExe);
......@@ -586,7 +588,7 @@ static async System.Threading.Tasks.Task Main()
CompileAndVerify(comp, expectedOutput: "0 1 2 3 4 5 6");
}
[ConditionalFact(typeof(WindowsDesktopOnly))]
[ConditionalFact(typeof(WindowsOnly), Reason = ConditionalSkipReason.NativePdbRequiresDesktop)]
public void AsyncIteratorWithAwaitCompletedAndYield()
{
string source = @"
......@@ -712,6 +714,26 @@ .maxstack 2
IL_0040: newobj ""System.Threading.Tasks.ValueTask<bool>..ctor(System.Threading.Tasks.Sources.IValueTaskSource<bool>, short)""
IL_0045: ret
}");
verifier.VerifyIL("C.<M>d__0.System.IAsyncDisposable.DisposeAsync()", @"
{
// Code size 39 (0x27)
.maxstack 2
.locals init (System.Threading.Tasks.ValueTask V_0)
IL_0000: ldarg.0
IL_0001: ldflda ""System.Runtime.CompilerServices.AsyncVoidMethodBuilder C.<M>d__0.<>t__builder""
IL_0006: call ""void System.Runtime.CompilerServices.AsyncVoidMethodBuilder.SetResult()""
IL_000b: ldarg.0
IL_000c: ldflda ""System.Threading.Tasks.ManualResetValueTaskSourceLogic<bool> C.<M>d__0.<>v__promiseOfValueOrEnd""
IL_0011: call ""void System.Threading.Tasks.ManualResetValueTaskSourceLogic<bool>.Reset()""
IL_0016: ldarg.0
IL_0017: ldc.i4.m1
IL_0018: stfld ""int C.<M>d__0.<>1__state""
IL_001d: ldloca.s V_0
IL_001f: initobj ""System.Threading.Tasks.ValueTask""
IL_0025: ldloc.0
IL_0026: ret
}
");
verifier.VerifyIL("C.<M>d__0.System.Runtime.CompilerServices.IStrongBox<System.Threading.Tasks.ManualResetValueTaskSourceLogic<bool>>.get_Value()", @"
{
// Code size 7 (0x7)
......@@ -1096,7 +1118,7 @@ public static async System.Collections.Generic.IAsyncEnumerable<int> M()
);
}
[ConditionalFact(typeof(WindowsDesktopOnly))]
[Fact]
public void AsyncIteratorWithAwaitCompletedAndOneYieldAndOneInvocation()
{
string source = @"
......@@ -1126,7 +1148,7 @@ static async System.Threading.Tasks.Task Main()
CompileAndVerify(comp, expectedOutput: "0 1 2 3 4 Done");
}
[ConditionalFact(typeof(WindowsDesktopOnly))]
[Fact]
public void AsyncIteratorWithAwaitCompletedAndTwoYields()
{
string source = @"
......@@ -1157,7 +1179,7 @@ static async System.Threading.Tasks.Task Main()
CompileAndVerify(comp, expectedOutput: "0 1 2 3 4 5 Done");
}
[ConditionalFact(typeof(WindowsDesktopOnly))]
[Fact]
public void AsyncIteratorWithYieldAndAwait()
{
string source = @"
......@@ -1186,7 +1208,7 @@ static async System.Threading.Tasks.Task Main()
CompileAndVerify(comp, expectedOutput: "0 1 2 3 Done");
}
[ConditionalFact(typeof(WindowsDesktopOnly))]
[Fact]
public void AsyncIteratorWithAwaitCompletedAndYieldBreak()
{
string source = @"
......@@ -1215,7 +1237,7 @@ static async System.Threading.Tasks.Task Main()
CompileAndVerify(comp, expectedOutput: "0 1 2 Done");
}
[ConditionalFact(typeof(WindowsDesktopOnly))]
[Fact]
public void AsyncIteratorWithAwaitCompletedAndYieldBreakAndYieldReturn()
{
string source = @"
......@@ -1249,7 +1271,7 @@ static async System.Threading.Tasks.Task Main()
CompileAndVerify(comp, expectedOutput: "0 1 2 3 Done");
}
[ConditionalFact(typeof(WindowsDesktopOnly))]
[Fact]
public void AsyncIteratorWithCustomCode()
{
verify(new[] { AwaitSlow, Write, Yield, AwaitSlow });
......@@ -1363,7 +1385,7 @@ async System.Collections.Generic.IAsyncEnumerable<int> local()
}
}
[ConditionalFact(typeof(WindowsDesktopOnly))]
[Fact]
public void AsyncIteratorWithAwaitAndYieldAndAwait()
{
string source = @"
......@@ -1413,7 +1435,7 @@ async System.Collections.Generic.IAsyncEnumerable<int> M()
);
}
[ConditionalFact(typeof(WindowsDesktopOnly))]
[Fact]
public void AsyncIteratorWithYieldReturnOnly()
{
string source = @"
......@@ -1440,7 +1462,7 @@ public static async System.Threading.Tasks.Task Main()
CompileAndVerify(comp, expectedOutput: "1");
}
[ConditionalFact(typeof(WindowsDesktopOnly))]
[Fact]
public void AsyncIteratorWithYieldBreakOnly()
{
string source = @"
......@@ -1515,7 +1537,7 @@ async System.Collections.Generic.IAsyncEnumerable<int> M()
);
}
[ConditionalFact(typeof(WindowsDesktopOnly))]
[Fact]
public void TestWaitForNextAsyncCalledOutOfTurn()
{
string source = @"
......@@ -1524,26 +1546,27 @@ class C
{
public static async System.Threading.Tasks.Task Main()
{
var enumerator = new C().M().GetAsyncEnumerator();
await enumerator.WaitForNextAsync();
await enumerator.WaitForNextAsync();
await enumerator.WaitForNextAsync();
var value = enumerator.TryGetNext(out bool success);
Assert(success);
Assert(value == 42);
using await (var enumerator = new C().M().GetAsyncEnumerator())
{
await enumerator.WaitForNextAsync();
await enumerator.WaitForNextAsync();
await enumerator.WaitForNextAsync();
enumerator.TryGetNext(out success);
Assert(!success);
var value = enumerator.TryGetNext(out bool success);
Assert(success);
Assert(value == 42);
await enumerator.WaitForNextAsync();
await enumerator.WaitForNextAsync();
await enumerator.WaitForNextAsync();
enumerator.TryGetNext(out success);
Assert(!success);
value = enumerator.TryGetNext(out success);
Assert(success);
Assert(value == 43);
await enumerator.WaitForNextAsync();
await enumerator.WaitForNextAsync();
await enumerator.WaitForNextAsync();
value = enumerator.TryGetNext(out success);
Assert(success);
Assert(value == 43);
}
Write(""Done"");
}
async System.Collections.Generic.IAsyncEnumerable<int> M()
......@@ -1562,7 +1585,7 @@ static void Assert(bool b)
CompileAndVerify(comp, expectedOutput: "Done");
}
[ConditionalFact(typeof(WindowsDesktopOnly))]
[Fact]
public void TestTryGetNextCalledOutOfTurn()
{
string source = @"
......@@ -1571,24 +1594,26 @@ class C
{
public static async System.Threading.Tasks.Task Main()
{
var enumerator = new C().M().GetAsyncEnumerator();
await enumerator.WaitForNextAsync();
var value = enumerator.TryGetNext(out bool success);
Assert(success);
Assert(value == 42);
using await (var enumerator = new C().M().GetAsyncEnumerator())
{
await enumerator.WaitForNextAsync();
enumerator.TryGetNext(out success);
Assert(!success);
var value = enumerator.TryGetNext(out bool success);
Assert(success);
Assert(value == 42);
try
{
enumerator.TryGetNext(out success);
}
catch (System.Exception e)
{
Assert(e != null);
Write(""Done"");
Assert(!success);
try
{
enumerator.TryGetNext(out success);
}
catch (System.Exception e)
{
Assert(e != null);
Write(""Done"");
}
}
}
async System.Collections.Generic.IAsyncEnumerable<int> M()
......@@ -1608,7 +1633,7 @@ static void Assert(bool b)
//CompileAndVerify(comp, expectedOutput: "Done");
}
[ConditionalFact(typeof(WindowsDesktopOnly))]
[Fact]
public void TestThrownException_WhilePromiseInactive()
{
string source = @"
......@@ -1617,23 +1642,25 @@ class C
{
public static async System.Threading.Tasks.Task Main()
{
var enumerator = new C().M().GetAsyncEnumerator();
await enumerator.WaitForNextAsync();
using await (var enumerator = new C().M().GetAsyncEnumerator())
{
await enumerator.WaitForNextAsync();
var value = enumerator.TryGetNext(out bool success);
Assert(success);
Assert(value == 42);
var value = enumerator.TryGetNext(out bool success);
Assert(success);
Assert(value == 42);
try
{
enumerator.TryGetNext(out success);
Write(""UNREACHABLE"");
}
catch (System.Exception e)
{
Assert(e.Message == ""message"");
try
{
enumerator.TryGetNext(out success);
Write(""UNREACHABLE"");
}
catch (System.Exception e)
{
Assert(e.Message == ""message"");
}
Write(""Done"");
}
Write(""Done"");
}
async System.Collections.Generic.IAsyncEnumerable<int> M()
{
......@@ -1653,7 +1680,7 @@ static void Assert(bool b)
CompileAndVerify(comp, expectedOutput: "Done");
}
[ConditionalFact(typeof(WindowsDesktopOnly))]
[Fact]
public void TestThrownException_WhilePromiseActive()
{
string source = @"
......@@ -1662,26 +1689,28 @@ class C
{
public static async System.Threading.Tasks.Task Main()
{
var enumerator = new C().M().GetAsyncEnumerator();
await enumerator.WaitForNextAsync();
using await (var enumerator = new C().M().GetAsyncEnumerator())
{
await enumerator.WaitForNextAsync();
var value = enumerator.TryGetNext(out bool success);
Assert(success);
Assert(value == 42);
var value = enumerator.TryGetNext(out bool success);
Assert(success);
Assert(value == 42);
enumerator.TryGetNext(out success);
Assert(!success);
enumerator.TryGetNext(out success);
Assert(!success);
try
{
await enumerator.WaitForNextAsync();
Write(""UNREACHABLE"");
}
catch (System.Exception e)
{
Assert(e.Message == ""message"");
try
{
await enumerator.WaitForNextAsync();
Write(""UNREACHABLE"");
}
catch (System.Exception e)
{
Assert(e.Message == ""message"");
}
Write(""Done"");
}
Write(""Done"");
}
async System.Collections.Generic.IAsyncEnumerable<int> M()
{
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册