diff --git a/docs/features/async-streams.md b/docs/features/async-streams.md index 94451737be0d6..9f9b064c316f3 100644 --- a/docs/features/async-streams.md +++ b/docs/features/async-streams.md @@ -201,7 +201,7 @@ else if (token.Equals(this.parameterProxy) || token.Equals(default)) else { result.combinedTokens = CancellationTokenSource.CreateLinkedTokenSource(this.parameterProxy, token); - result.parameter = combinedTokens.Token; + result.parameter = result.combinedTokens.Token; } ``` For a discussion of the threadID check, see https://github.com/dotnet/corefx/issues/3481 diff --git a/src/Compilers/CSharp/Portable/Lowering/AsyncRewriter/AsyncRewriter.AsyncIteratorRewriter.cs b/src/Compilers/CSharp/Portable/Lowering/AsyncRewriter/AsyncRewriter.AsyncIteratorRewriter.cs index c305d9afe130f..09387aac28dff 100644 --- a/src/Compilers/CSharp/Portable/Lowering/AsyncRewriter/AsyncRewriter.AsyncIteratorRewriter.cs +++ b/src/Compilers/CSharp/Portable/Lowering/AsyncRewriter/AsyncRewriter.AsyncIteratorRewriter.cs @@ -207,10 +207,10 @@ protected override void InitializeStateMachine(ArrayBuilder body F.New(stateMachineType.Constructor.AsMember(frameType), F.Literal(initialState)))); } - protected override BoundStatement InitializeParameterField(MethodSymbol getEnumeratorMethod, ParameterSymbol parameter, BoundExpression resultParameter, BoundExpression parameterProxy) + protected override BoundStatement InitializeParameterField(MethodSymbol getEnumeratorMethod, ParameterSymbol parameter, BoundExpression result, BoundExpression resultParameter, BoundExpression parameterProxy) { - BoundStatement result; - if (_combinedTokensField is object && + BoundStatement initializeParameterFieldResult; + if (_combinedTokensField is not null && !parameter.IsExtensionParameterImplementation() && parameter.HasEnumeratorCancellationAttribute && parameter.Type.Equals(F.Compilation.GetWellKnownType(WellKnownType.System_Threading_CancellationToken), TypeCompareKind.ConsiderEverything)) @@ -227,12 +227,13 @@ protected override BoundStatement InitializeParameterField(MethodSymbol getEnume // else // { // result.combinedTokens = CancellationTokenSource.CreateLinkedTokenSource(this.parameterProxy, token); - // result.parameter = combinedTokens.Token; + // result.parameter = result.combinedTokens.Token; // } BoundParameter tokenParameter = F.Parameter(getEnumeratorMethod.Parameters[0]); - BoundFieldAccess combinedTokens = F.Field(F.This(), _combinedTokensField); - result = F.If( + BoundFieldAccess resultCombinedTokens = F.Field(result, _combinedTokensField); + + initializeParameterFieldResult = F.If( // if (this.parameterProxy.Equals(default)) F.Call(parameterProxy, WellKnownMember.System_Threading_CancellationToken__Equals, F.Default(parameterProxy.Type)), // result.parameter = token; @@ -246,18 +247,18 @@ protected override BoundStatement InitializeParameterField(MethodSymbol getEnume thenClause: F.Assignment(resultParameter, parameterProxy), elseClauseOpt: F.Block( // result.combinedTokens = CancellationTokenSource.CreateLinkedTokenSource(this.parameterProxy, token); - F.Assignment(combinedTokens, F.StaticCall(WellKnownMember.System_Threading_CancellationTokenSource__CreateLinkedTokenSource, parameterProxy, tokenParameter)), + F.Assignment(resultCombinedTokens, F.StaticCall(WellKnownMember.System_Threading_CancellationTokenSource__CreateLinkedTokenSource, parameterProxy, tokenParameter)), // result.parameter = result.combinedTokens.Token; - F.Assignment(resultParameter, F.Property(combinedTokens, WellKnownMember.System_Threading_CancellationTokenSource__Token))))); + F.Assignment(resultParameter, F.Property(resultCombinedTokens, WellKnownMember.System_Threading_CancellationTokenSource__Token))))); } else { // For parameters that don't have [EnumeratorCancellation], initialize their parameter fields // result.parameter = this.parameterProxy; - result = F.Assignment(resultParameter, parameterProxy); + initializeParameterFieldResult = F.Assignment(resultParameter, parameterProxy); } - return result; + return initializeParameterFieldResult; } protected override BoundStatement GenerateStateMachineCreation(LocalSymbol stateMachineVariable, NamedTypeSymbol frameType, IReadOnlyDictionary proxies) diff --git a/src/Compilers/CSharp/Portable/Lowering/StateMachineRewriter/StateMachineRewriter.cs b/src/Compilers/CSharp/Portable/Lowering/StateMachineRewriter/StateMachineRewriter.cs index 6c5fc05a07aff..4ffae3cc9e6d9 100644 --- a/src/Compilers/CSharp/Portable/Lowering/StateMachineRewriter/StateMachineRewriter.cs +++ b/src/Compilers/CSharp/Portable/Lowering/StateMachineRewriter/StateMachineRewriter.cs @@ -430,7 +430,7 @@ protected SynthesizedImplementationMethod GenerateIteratorGetEnumerator(MethodSy var thisInitialized = F.GenerateLabel("thisInitialized"); - if ((object)initialThreadIdField != null) + if (initialThreadIdField is not null) { managedThreadId = MakeCurrentThreadId(); @@ -487,15 +487,22 @@ protected SynthesizedImplementationMethod GenerateIteratorGetEnumerator(MethodSy CapturedSymbolReplacement proxy; if (copyDest.TryGetValue(parameter, out proxy)) { + // result + BoundExpression result = F.Local(resultVariable); + // result.parameter BoundExpression resultParameter = proxy.Replacement( F.Syntax, - static (stateMachineType, arg) => arg.F.Local(arg.resultVariable), - (F, resultVariable)); + static (stateMachineType, result) => result, + result); // this.parameterProxy - BoundExpression parameterProxy = copySrc[parameter].Replacement(F.Syntax, static (stateMachineType, F) => F.This(), F); - BoundStatement copy = InitializeParameterField(getEnumeratorMethod, parameter, resultParameter, parameterProxy); + BoundExpression parameterProxy = copySrc[parameter].Replacement( + F.Syntax, + static (stateMachineType, F) => F.This(), + F + ); + BoundStatement copy = InitializeParameterField(getEnumeratorMethod, parameter, result, resultParameter, parameterProxy); bodyBuilder.Add(copy); } @@ -516,7 +523,7 @@ protected virtual void GenerateResetInstance(ArrayBuilder builde F.Assignment(F.Field(F.This(), stateField), F.Literal(initialState))); } - protected virtual BoundStatement InitializeParameterField(MethodSymbol getEnumeratorMethod, ParameterSymbol parameter, BoundExpression resultParameter, BoundExpression parameterProxy) + protected virtual BoundStatement InitializeParameterField(MethodSymbol getEnumeratorMethod, ParameterSymbol parameter, BoundExpression result, BoundExpression resultParameter, BoundExpression parameterProxy) { Debug.Assert(!method.IsIterator || !method.IsAsync); // an override handles async-iterators diff --git a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncIteratorTests.cs b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncIteratorTests.cs index ee2351156ea27..f40df15977f14 100644 --- a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncIteratorTests.cs +++ b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncIteratorTests.cs @@ -3241,14 +3241,14 @@ .locals init (C.d__0 V_0, IL_007f: ldfld ""System.Threading.CancellationToken C.d__0.<>3__token"" IL_0084: stfld ""System.Threading.CancellationToken C.d__0.token"" IL_0089: br.s IL_00ae - IL_008b: ldarg.0 + IL_008b: ldloc.0 IL_008c: ldarg.0 IL_008d: ldfld ""System.Threading.CancellationToken C.d__0.<>3__token"" IL_0092: ldarg.1 IL_0093: call ""System.Threading.CancellationTokenSource System.Threading.CancellationTokenSource.CreateLinkedTokenSource(System.Threading.CancellationToken, System.Threading.CancellationToken)"" IL_0098: stfld ""System.Threading.CancellationTokenSource C.d__0.<>x__combinedTokens"" IL_009d: ldloc.0 - IL_009e: ldarg.0 + IL_009e: ldloc.0 IL_009f: ldfld ""System.Threading.CancellationTokenSource C.d__0.<>x__combinedTokens"" IL_00a4: callvirt ""System.Threading.CancellationToken System.Threading.CancellationTokenSource.Token.get"" IL_00a9: stfld ""System.Threading.CancellationToken C.d__0.token"" @@ -3455,73 +3455,73 @@ public static async partial System.Collections.Generic.IAsyncEnumerable M(" // we generate initialization logic for the token parameter verifier.VerifyIL("C.d__0.System.Collections.Generic.IAsyncEnumerable.GetAsyncEnumerator(System.Threading.CancellationToken)", @" { - // Code size 176 (0xb0) - .maxstack 3 - .locals init (C.d__0 V_0, + // Code size 176 (0xb0) + .maxstack 3 + .locals init (C.d__0 V_0, System.Threading.CancellationToken V_1) - IL_0000: ldarg.0 - IL_0001: ldfld ""int C.d__0.<>1__state"" - IL_0006: ldc.i4.s -2 - IL_0008: bne.un.s IL_0035 - IL_000a: ldarg.0 - IL_000b: ldfld ""int C.d__0.<>l__initialThreadId"" - IL_0010: call ""int System.Environment.CurrentManagedThreadId.get"" - IL_0015: bne.un.s IL_0035 - IL_0017: ldarg.0 - IL_0018: ldc.i4.s -3 - IL_001a: stfld ""int C.d__0.<>1__state"" - IL_001f: ldarg.0 - IL_0020: call ""System.Runtime.CompilerServices.AsyncIteratorMethodBuilder System.Runtime.CompilerServices.AsyncIteratorMethodBuilder.Create()"" - IL_0025: stfld ""System.Runtime.CompilerServices.AsyncIteratorMethodBuilder C.d__0.<>t__builder"" - IL_002a: ldarg.0 - IL_002b: ldc.i4.0 - IL_002c: stfld ""bool C.d__0.<>w__disposeMode"" - IL_0031: ldarg.0 - IL_0032: stloc.0 - IL_0033: br.s IL_003d - IL_0035: ldc.i4.s -3 - IL_0037: newobj ""C.d__0..ctor(int)"" - IL_003c: stloc.0 - IL_003d: ldarg.0 - IL_003e: ldflda ""System.Threading.CancellationToken C.d__0.<>3__token"" - IL_0043: ldloca.s V_1 - IL_0045: initobj ""System.Threading.CancellationToken"" - IL_004b: ldloc.1 - IL_004c: call ""bool System.Threading.CancellationToken.Equals(System.Threading.CancellationToken)"" - IL_0051: brfalse.s IL_005c - IL_0053: ldloc.0 - IL_0054: ldarg.1 - IL_0055: stfld ""System.Threading.CancellationToken C.d__0.token"" - IL_005a: br.s IL_00ae - IL_005c: ldarga.s V_1 - IL_005e: ldarg.0 - IL_005f: ldfld ""System.Threading.CancellationToken C.d__0.<>3__token"" - IL_0064: call ""bool System.Threading.CancellationToken.Equals(System.Threading.CancellationToken)"" - IL_0069: brtrue.s IL_007d - IL_006b: ldarga.s V_1 - IL_006d: ldloca.s V_1 - IL_006f: initobj ""System.Threading.CancellationToken"" - IL_0075: ldloc.1 - IL_0076: call ""bool System.Threading.CancellationToken.Equals(System.Threading.CancellationToken)"" - IL_007b: brfalse.s IL_008b - IL_007d: ldloc.0 - IL_007e: ldarg.0 - IL_007f: ldfld ""System.Threading.CancellationToken C.d__0.<>3__token"" - IL_0084: stfld ""System.Threading.CancellationToken C.d__0.token"" - IL_0089: br.s IL_00ae - IL_008b: ldarg.0 - IL_008c: ldarg.0 - IL_008d: ldfld ""System.Threading.CancellationToken C.d__0.<>3__token"" - IL_0092: ldarg.1 - IL_0093: call ""System.Threading.CancellationTokenSource System.Threading.CancellationTokenSource.CreateLinkedTokenSource(System.Threading.CancellationToken, System.Threading.CancellationToken)"" - IL_0098: stfld ""System.Threading.CancellationTokenSource C.d__0.<>x__combinedTokens"" - IL_009d: ldloc.0 - IL_009e: ldarg.0 - IL_009f: ldfld ""System.Threading.CancellationTokenSource C.d__0.<>x__combinedTokens"" - IL_00a4: callvirt ""System.Threading.CancellationToken System.Threading.CancellationTokenSource.Token.get"" - IL_00a9: stfld ""System.Threading.CancellationToken C.d__0.token"" - IL_00ae: ldloc.0 - IL_00af: ret + IL_0000: ldarg.0 + IL_0001: ldfld ""int C.d__0.<>1__state"" + IL_0006: ldc.i4.s -2 + IL_0008: bne.un.s IL_0035 + IL_000a: ldarg.0 + IL_000b: ldfld ""int C.d__0.<>l__initialThreadId"" + IL_0010: call ""int System.Environment.CurrentManagedThreadId.get"" + IL_0015: bne.un.s IL_0035 + IL_0017: ldarg.0 + IL_0018: ldc.i4.s -3 + IL_001a: stfld ""int C.d__0.<>1__state"" + IL_001f: ldarg.0 + IL_0020: call ""System.Runtime.CompilerServices.AsyncIteratorMethodBuilder System.Runtime.CompilerServices.AsyncIteratorMethodBuilder.Create()"" + IL_0025: stfld ""System.Runtime.CompilerServices.AsyncIteratorMethodBuilder C.d__0.<>t__builder"" + IL_002a: ldarg.0 + IL_002b: ldc.i4.0 + IL_002c: stfld ""bool C.d__0.<>w__disposeMode"" + IL_0031: ldarg.0 + IL_0032: stloc.0 + IL_0033: br.s IL_003d + IL_0035: ldc.i4.s -3 + IL_0037: newobj ""C.d__0..ctor(int)"" + IL_003c: stloc.0 + IL_003d: ldarg.0 + IL_003e: ldflda ""System.Threading.CancellationToken C.d__0.<>3__token"" + IL_0043: ldloca.s V_1 + IL_0045: initobj ""System.Threading.CancellationToken"" + IL_004b: ldloc.1 + IL_004c: call ""bool System.Threading.CancellationToken.Equals(System.Threading.CancellationToken)"" + IL_0051: brfalse.s IL_005c + IL_0053: ldloc.0 + IL_0054: ldarg.1 + IL_0055: stfld ""System.Threading.CancellationToken C.d__0.token"" + IL_005a: br.s IL_00ae + IL_005c: ldarga.s V_1 + IL_005e: ldarg.0 + IL_005f: ldfld ""System.Threading.CancellationToken C.d__0.<>3__token"" + IL_0064: call ""bool System.Threading.CancellationToken.Equals(System.Threading.CancellationToken)"" + IL_0069: brtrue.s IL_007d + IL_006b: ldarga.s V_1 + IL_006d: ldloca.s V_1 + IL_006f: initobj ""System.Threading.CancellationToken"" + IL_0075: ldloc.1 + IL_0076: call ""bool System.Threading.CancellationToken.Equals(System.Threading.CancellationToken)"" + IL_007b: brfalse.s IL_008b + IL_007d: ldloc.0 + IL_007e: ldarg.0 + IL_007f: ldfld ""System.Threading.CancellationToken C.d__0.<>3__token"" + IL_0084: stfld ""System.Threading.CancellationToken C.d__0.token"" + IL_0089: br.s IL_00ae + IL_008b: ldloc.0 + IL_008c: ldarg.0 + IL_008d: ldfld ""System.Threading.CancellationToken C.d__0.<>3__token"" + IL_0092: ldarg.1 + IL_0093: call ""System.Threading.CancellationTokenSource System.Threading.CancellationTokenSource.CreateLinkedTokenSource(System.Threading.CancellationToken, System.Threading.CancellationToken)"" + IL_0098: stfld ""System.Threading.CancellationTokenSource C.d__0.<>x__combinedTokens"" + IL_009d: ldloc.0 + IL_009e: ldloc.0 + IL_009f: ldfld ""System.Threading.CancellationTokenSource C.d__0.<>x__combinedTokens"" + IL_00a4: callvirt ""System.Threading.CancellationToken System.Threading.CancellationTokenSource.Token.get"" + IL_00a9: stfld ""System.Threading.CancellationToken C.d__0.token"" + IL_00ae: ldloc.0 + IL_00af: ret }"); // we generate disposal logic for the combinedTokens field @@ -3778,14 +3778,14 @@ .locals init (C.<g__local|0_0>d V_0, IL_007f: ldfld ""System.Threading.CancellationToken C.<g__local|0_0>d.<>3__token"" IL_0084: stfld ""System.Threading.CancellationToken C.<g__local|0_0>d.token"" IL_0089: br.s IL_00ae - IL_008b: ldarg.0 + IL_008b: ldloc.0 IL_008c: ldarg.0 IL_008d: ldfld ""System.Threading.CancellationToken C.<g__local|0_0>d.<>3__token"" IL_0092: ldarg.1 IL_0093: call ""System.Threading.CancellationTokenSource System.Threading.CancellationTokenSource.CreateLinkedTokenSource(System.Threading.CancellationToken, System.Threading.CancellationToken)"" IL_0098: stfld ""System.Threading.CancellationTokenSource C.<g__local|0_0>d.<>x__combinedTokens"" IL_009d: ldloc.0 - IL_009e: ldarg.0 + IL_009e: ldloc.0 IL_009f: ldfld ""System.Threading.CancellationTokenSource C.<g__local|0_0>d.<>x__combinedTokens"" IL_00a4: callvirt ""System.Threading.CancellationToken System.Threading.CancellationTokenSource.Token.get"" IL_00a9: stfld ""System.Threading.CancellationToken C.<g__local|0_0>d.token"" @@ -7681,14 +7681,14 @@ .locals init (C.d__1 V_0, IL_008b: ldfld ""System.Threading.CancellationToken C.d__1.<>3__token1"" IL_0090: stfld ""System.Threading.CancellationToken C.d__1.token1"" IL_0095: br.s IL_00ba - IL_0097: ldarg.0 + IL_0097: ldloc.0 IL_0098: ldarg.0 IL_0099: ldfld ""System.Threading.CancellationToken C.d__1.<>3__token1"" IL_009e: ldarg.1 IL_009f: call ""System.Threading.CancellationTokenSource System.Threading.CancellationTokenSource.CreateLinkedTokenSource(System.Threading.CancellationToken, System.Threading.CancellationToken)"" IL_00a4: stfld ""System.Threading.CancellationTokenSource C.d__1.<>x__combinedTokens"" IL_00a9: ldloc.0 - IL_00aa: ldarg.0 + IL_00aa: ldloc.0 IL_00ab: ldfld ""System.Threading.CancellationTokenSource C.d__1.<>x__combinedTokens"" IL_00b0: callvirt ""System.Threading.CancellationToken System.Threading.CancellationTokenSource.Token.get"" IL_00b5: stfld ""System.Threading.CancellationToken C.d__1.token1"" @@ -7756,81 +7756,81 @@ static async System.Collections.Generic.IAsyncEnumerable Iter(int value, [E // GetAsyncEnumerator's token parameter is used directly, since the argument token is default verifier.VerifyIL("C.<
g__Iter|0_0>d.System.Collections.Generic.IAsyncEnumerable.GetAsyncEnumerator(System.Threading.CancellationToken)", @" { - // Code size 200 (0xc8) - .maxstack 3 - .locals init (C.<
g__Iter|0_0>d V_0, + // Code size 200 (0xc8) + .maxstack 3 + .locals init (C.<
g__Iter|0_0>d V_0, System.Threading.CancellationToken V_1) - IL_0000: ldarg.0 - IL_0001: ldfld ""int C.<
g__Iter|0_0>d.<>1__state"" - IL_0006: ldc.i4.s -2 - IL_0008: bne.un.s IL_0035 - IL_000a: ldarg.0 - IL_000b: ldfld ""int C.<
g__Iter|0_0>d.<>l__initialThreadId"" - IL_0010: call ""int System.Environment.CurrentManagedThreadId.get"" - IL_0015: bne.un.s IL_0035 - IL_0017: ldarg.0 - IL_0018: ldc.i4.s -3 - IL_001a: stfld ""int C.<
g__Iter|0_0>d.<>1__state"" - IL_001f: ldarg.0 - IL_0020: call ""System.Runtime.CompilerServices.AsyncIteratorMethodBuilder System.Runtime.CompilerServices.AsyncIteratorMethodBuilder.Create()"" - IL_0025: stfld ""System.Runtime.CompilerServices.AsyncIteratorMethodBuilder C.<
g__Iter|0_0>d.<>t__builder"" - IL_002a: ldarg.0 - IL_002b: ldc.i4.0 - IL_002c: stfld ""bool C.<
g__Iter|0_0>d.<>w__disposeMode"" - IL_0031: ldarg.0 - IL_0032: stloc.0 - IL_0033: br.s IL_003d - IL_0035: ldc.i4.s -3 - IL_0037: newobj ""C.<
g__Iter|0_0>d..ctor(int)"" - IL_003c: stloc.0 - IL_003d: ldloc.0 - IL_003e: ldarg.0 - IL_003f: ldfld ""int C.<
g__Iter|0_0>d.<>3__value"" - IL_0044: stfld ""int C.<
g__Iter|0_0>d.value"" - IL_0049: ldarg.0 - IL_004a: ldflda ""System.Threading.CancellationToken C.<
g__Iter|0_0>d.<>3__token1"" - IL_004f: ldloca.s V_1 - IL_0051: initobj ""System.Threading.CancellationToken"" - IL_0057: ldloc.1 - IL_0058: call ""bool System.Threading.CancellationToken.Equals(System.Threading.CancellationToken)"" - IL_005d: brfalse.s IL_0068 - IL_005f: ldloc.0 - IL_0060: ldarg.1 - IL_0061: stfld ""System.Threading.CancellationToken C.<
g__Iter|0_0>d.token1"" - IL_0066: br.s IL_00ba - IL_0068: ldarga.s V_1 - IL_006a: ldarg.0 - IL_006b: ldfld ""System.Threading.CancellationToken C.<
g__Iter|0_0>d.<>3__token1"" - IL_0070: call ""bool System.Threading.CancellationToken.Equals(System.Threading.CancellationToken)"" - IL_0075: brtrue.s IL_0089 - IL_0077: ldarga.s V_1 - IL_0079: ldloca.s V_1 - IL_007b: initobj ""System.Threading.CancellationToken"" - IL_0081: ldloc.1 - IL_0082: call ""bool System.Threading.CancellationToken.Equals(System.Threading.CancellationToken)"" - IL_0087: brfalse.s IL_0097 - IL_0089: ldloc.0 - IL_008a: ldarg.0 - IL_008b: ldfld ""System.Threading.CancellationToken C.<
g__Iter|0_0>d.<>3__token1"" - IL_0090: stfld ""System.Threading.CancellationToken C.<
g__Iter|0_0>d.token1"" - IL_0095: br.s IL_00ba - IL_0097: ldarg.0 - IL_0098: ldarg.0 - IL_0099: ldfld ""System.Threading.CancellationToken C.<
g__Iter|0_0>d.<>3__token1"" - IL_009e: ldarg.1 - IL_009f: call ""System.Threading.CancellationTokenSource System.Threading.CancellationTokenSource.CreateLinkedTokenSource(System.Threading.CancellationToken, System.Threading.CancellationToken)"" - IL_00a4: stfld ""System.Threading.CancellationTokenSource C.<
g__Iter|0_0>d.<>x__combinedTokens"" - IL_00a9: ldloc.0 - IL_00aa: ldarg.0 - IL_00ab: ldfld ""System.Threading.CancellationTokenSource C.<
g__Iter|0_0>d.<>x__combinedTokens"" - IL_00b0: callvirt ""System.Threading.CancellationToken System.Threading.CancellationTokenSource.Token.get"" - IL_00b5: stfld ""System.Threading.CancellationToken C.<
g__Iter|0_0>d.token1"" - IL_00ba: ldloc.0 - IL_00bb: ldarg.0 - IL_00bc: ldfld ""System.Threading.CancellationToken C.<
g__Iter|0_0>d.<>3__origToken"" - IL_00c1: stfld ""System.Threading.CancellationToken C.<
g__Iter|0_0>d.origToken"" - IL_00c6: ldloc.0 - IL_00c7: ret + IL_0000: ldarg.0 + IL_0001: ldfld ""int C.<
g__Iter|0_0>d.<>1__state"" + IL_0006: ldc.i4.s -2 + IL_0008: bne.un.s IL_0035 + IL_000a: ldarg.0 + IL_000b: ldfld ""int C.<
g__Iter|0_0>d.<>l__initialThreadId"" + IL_0010: call ""int System.Environment.CurrentManagedThreadId.get"" + IL_0015: bne.un.s IL_0035 + IL_0017: ldarg.0 + IL_0018: ldc.i4.s -3 + IL_001a: stfld ""int C.<
g__Iter|0_0>d.<>1__state"" + IL_001f: ldarg.0 + IL_0020: call ""System.Runtime.CompilerServices.AsyncIteratorMethodBuilder System.Runtime.CompilerServices.AsyncIteratorMethodBuilder.Create()"" + IL_0025: stfld ""System.Runtime.CompilerServices.AsyncIteratorMethodBuilder C.<
g__Iter|0_0>d.<>t__builder"" + IL_002a: ldarg.0 + IL_002b: ldc.i4.0 + IL_002c: stfld ""bool C.<
g__Iter|0_0>d.<>w__disposeMode"" + IL_0031: ldarg.0 + IL_0032: stloc.0 + IL_0033: br.s IL_003d + IL_0035: ldc.i4.s -3 + IL_0037: newobj ""C.<
g__Iter|0_0>d..ctor(int)"" + IL_003c: stloc.0 + IL_003d: ldloc.0 + IL_003e: ldarg.0 + IL_003f: ldfld ""int C.<
g__Iter|0_0>d.<>3__value"" + IL_0044: stfld ""int C.<
g__Iter|0_0>d.value"" + IL_0049: ldarg.0 + IL_004a: ldflda ""System.Threading.CancellationToken C.<
g__Iter|0_0>d.<>3__token1"" + IL_004f: ldloca.s V_1 + IL_0051: initobj ""System.Threading.CancellationToken"" + IL_0057: ldloc.1 + IL_0058: call ""bool System.Threading.CancellationToken.Equals(System.Threading.CancellationToken)"" + IL_005d: brfalse.s IL_0068 + IL_005f: ldloc.0 + IL_0060: ldarg.1 + IL_0061: stfld ""System.Threading.CancellationToken C.<
g__Iter|0_0>d.token1"" + IL_0066: br.s IL_00ba + IL_0068: ldarga.s V_1 + IL_006a: ldarg.0 + IL_006b: ldfld ""System.Threading.CancellationToken C.<
g__Iter|0_0>d.<>3__token1"" + IL_0070: call ""bool System.Threading.CancellationToken.Equals(System.Threading.CancellationToken)"" + IL_0075: brtrue.s IL_0089 + IL_0077: ldarga.s V_1 + IL_0079: ldloca.s V_1 + IL_007b: initobj ""System.Threading.CancellationToken"" + IL_0081: ldloc.1 + IL_0082: call ""bool System.Threading.CancellationToken.Equals(System.Threading.CancellationToken)"" + IL_0087: brfalse.s IL_0097 + IL_0089: ldloc.0 + IL_008a: ldarg.0 + IL_008b: ldfld ""System.Threading.CancellationToken C.<
g__Iter|0_0>d.<>3__token1"" + IL_0090: stfld ""System.Threading.CancellationToken C.<
g__Iter|0_0>d.token1"" + IL_0095: br.s IL_00ba + IL_0097: ldloc.0 + IL_0098: ldarg.0 + IL_0099: ldfld ""System.Threading.CancellationToken C.<
g__Iter|0_0>d.<>3__token1"" + IL_009e: ldarg.1 + IL_009f: call ""System.Threading.CancellationTokenSource System.Threading.CancellationTokenSource.CreateLinkedTokenSource(System.Threading.CancellationToken, System.Threading.CancellationToken)"" + IL_00a4: stfld ""System.Threading.CancellationTokenSource C.<
g__Iter|0_0>d.<>x__combinedTokens"" + IL_00a9: ldloc.0 + IL_00aa: ldloc.0 + IL_00ab: ldfld ""System.Threading.CancellationTokenSource C.<
g__Iter|0_0>d.<>x__combinedTokens"" + IL_00b0: callvirt ""System.Threading.CancellationToken System.Threading.CancellationTokenSource.Token.get"" + IL_00b5: stfld ""System.Threading.CancellationToken C.<
g__Iter|0_0>d.token1"" + IL_00ba: ldloc.0 + IL_00bb: ldarg.0 + IL_00bc: ldfld ""System.Threading.CancellationToken C.<
g__Iter|0_0>d.<>3__origToken"" + IL_00c1: stfld ""System.Threading.CancellationToken C.<
g__Iter|0_0>d.origToken"" + IL_00c6: ldloc.0 + IL_00c7: ret } "); } @@ -11930,5 +11930,81 @@ .locals init (int V_0, } """); } + + [Fact] + [WorkItem(81467, "https://github.com/dotnet/roslyn/issues/81467")] + public void Multiple_GetAsyncEnumerator_Calls_Should_Dispose_Linked_Tokens() + { + string testUtilsSource = """ +#pragma warning disable CS0436 // Type conflicts with imported type + +public static class TestUtils +{ + public static System.Threading.CancellationTokenSource CreateOriginalCancellationTokenSource() + { + return new System.Threading.CancellationTokenSource(); + } +} +"""; + var testUtilsComp = CreateCompilation(testUtilsSource, options: TestOptions.ReleaseDll); + var testUtilsRef = testUtilsComp.EmitToImageReference(aliases: ["TestUtils"]); + + string source = """ +#pragma warning disable CS0436 // Type conflicts with imported type + +extern alias TestUtils; + +using System.Collections.Generic; +using System.Runtime.CompilerServices; +using System.Threading; +using System.Threading.Tasks; + +class C +{ + static async IAsyncEnumerable Create([EnumeratorCancellation] CancellationToken cancellationToken) + { + yield return default!; + yield return default!; + } + + static async Task Main() + { + var cts = new CancellationTokenSource(); + + var iterator = Create(cts.Token); + + var cts1 = new CancellationTokenSource(); + var cts2 = new CancellationTokenSource(); + var cts3 = new CancellationTokenSource(); + + var it1 = iterator.GetAsyncEnumerator(cts1.Token); + var it2 = iterator.GetAsyncEnumerator(cts2.Token); + var it3 = iterator.GetAsyncEnumerator(cts3.Token); + + await it1.DisposeAsync(); + await it2.DisposeAsync(); + await it3.DisposeAsync(); + } +} + +namespace System.Threading +{ + public class CancellationTokenSource + { + // This ensures that the tokens are always different (CancellationToken.Equals(CancellationToken) == false) to force the tokens to be linked + public CancellationToken Token => TestUtils::TestUtils.CreateOriginalCancellationTokenSource().Token; + public void Dispose() { System.Console.Write('d'); } + public void Cancel() { } + public static CancellationTokenSource CreateLinkedTokenSource(CancellationToken token1, CancellationToken token2) => new(); + } +} +"""; + + var comp = CreateCompilationWithTasksExtensions(new[] { source, EnumeratorCancellationAttributeType, AsyncStreamsTypes }, options: TestOptions.DebugExe, references: [testUtilsRef]); + + comp.VerifyDiagnostics(); + + CompileAndVerify(comp, expectedOutput: "ddd"); + } } } diff --git a/src/Compilers/CSharp/Test/Emit3/Semantics/ExtensionTests.cs b/src/Compilers/CSharp/Test/Emit3/Semantics/ExtensionTests.cs index 9f93bdc4afcb7..9d7a1f50cf577 100644 --- a/src/Compilers/CSharp/Test/Emit3/Semantics/ExtensionTests.cs +++ b/src/Compilers/CSharp/Test/Emit3/Semantics/ExtensionTests.cs @@ -42465,14 +42465,14 @@ .locals init (C.d__1 V_0, IL_008b: ldfld "System.Threading.CancellationToken C.d__1.<>3__token2" IL_0090: stfld "System.Threading.CancellationToken C.d__1.token2" IL_0095: br.s IL_00ba - IL_0097: ldarg.0 + IL_0097: ldloc.0 IL_0098: ldarg.0 IL_0099: ldfld "System.Threading.CancellationToken C.d__1.<>3__token2" IL_009e: ldarg.1 IL_009f: call "System.Threading.CancellationTokenSource System.Threading.CancellationTokenSource.CreateLinkedTokenSource(System.Threading.CancellationToken, System.Threading.CancellationToken)" IL_00a4: stfld "System.Threading.CancellationTokenSource C.d__1.<>x__combinedTokens" IL_00a9: ldloc.0 - IL_00aa: ldarg.0 + IL_00aa: ldloc.0 IL_00ab: ldfld "System.Threading.CancellationTokenSource C.d__1.<>x__combinedTokens" IL_00b0: callvirt "System.Threading.CancellationToken System.Threading.CancellationTokenSource.Token.get" IL_00b5: stfld "System.Threading.CancellationToken C.d__1.token2" @@ -42563,14 +42563,14 @@ .locals init (C.d__1 V_0, IL_007f: ldfld "System.Threading.CancellationToken C.d__1.<>3__token" IL_0084: stfld "System.Threading.CancellationToken C.d__1.token" IL_0089: br.s IL_00ae - IL_008b: ldarg.0 + IL_008b: ldloc.0 IL_008c: ldarg.0 IL_008d: ldfld "System.Threading.CancellationToken C.d__1.<>3__token" IL_0092: ldarg.1 IL_0093: call "System.Threading.CancellationTokenSource System.Threading.CancellationTokenSource.CreateLinkedTokenSource(System.Threading.CancellationToken, System.Threading.CancellationToken)" IL_0098: stfld "System.Threading.CancellationTokenSource C.d__1.<>x__combinedTokens" IL_009d: ldloc.0 - IL_009e: ldarg.0 + IL_009e: ldloc.0 IL_009f: ldfld "System.Threading.CancellationTokenSource C.d__1.<>x__combinedTokens" IL_00a4: callvirt "System.Threading.CancellationToken System.Threading.CancellationTokenSource.Token.get" IL_00a9: stfld "System.Threading.CancellationToken C.d__1.token" @@ -42743,14 +42743,14 @@ .locals init (C.d__1 V_0, IL_0097: ldfld "System.Threading.CancellationToken C.d__1.<>3__token2" IL_009c: stfld "System.Threading.CancellationToken C.d__1.token2" IL_00a1: br.s IL_00c6 - IL_00a3: ldarg.0 + IL_00a3: ldloc.0 IL_00a4: ldarg.0 IL_00a5: ldfld "System.Threading.CancellationToken C.d__1.<>3__token2" IL_00aa: ldarg.1 IL_00ab: call "System.Threading.CancellationTokenSource System.Threading.CancellationTokenSource.CreateLinkedTokenSource(System.Threading.CancellationToken, System.Threading.CancellationToken)" IL_00b0: stfld "System.Threading.CancellationTokenSource C.d__1.<>x__combinedTokens" IL_00b5: ldloc.0 - IL_00b6: ldarg.0 + IL_00b6: ldloc.0 IL_00b7: ldfld "System.Threading.CancellationTokenSource C.d__1.<>x__combinedTokens" IL_00bc: callvirt "System.Threading.CancellationToken System.Threading.CancellationTokenSource.Token.get" IL_00c1: stfld "System.Threading.CancellationToken C.d__1.token2"