Browse Source

Add tests for 'async IAsyncEnumerable'.

Remove [AsyncIteratorStateMachine] attribute and left-over ldc.i4 instructions.
pull/1730/head
Daniel Grunwald 6 years ago
parent
commit
de33e79384
  1. 1
      ICSharpCode.Decompiler.Tests/ICSharpCode.Decompiler.Tests.csproj
  2. 6
      ICSharpCode.Decompiler.Tests/PrettyTestRunner.cs
  3. 37
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/AsyncStreams.cs
  4. 6
      ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs
  5. 7
      ICSharpCode.Decompiler/IL/ControlFlow/AsyncAwaitDecompiler.cs
  6. 6
      ICSharpCode.Decompiler/IL/ControlFlow/ControlFlowSimplification.cs
  7. 2
      ICSharpCode.Decompiler/TypeSystem/Implementation/KnownAttributes.cs

1
ICSharpCode.Decompiler.Tests/ICSharpCode.Decompiler.Tests.csproj

@ -81,6 +81,7 @@ @@ -81,6 +81,7 @@
<Compile Include="DisassemblerPrettyTestRunner.cs" />
<Compile Include="TestCases\Correctness\StringConcat.cs" />
<Compile Include="TestCases\ILPretty\ConstantBlobs.cs" />
<None Include="TestCases\Pretty\AsyncStreams.cs" />
<None Include="TestCases\Pretty\AsyncUsing.cs" />
<Compile Include="TestCases\Pretty\OutVariables.cs" />
<Compile Include="TestCases\Pretty\CustomTaskType.cs" />

6
ICSharpCode.Decompiler.Tests/PrettyTestRunner.cs

@ -307,6 +307,12 @@ namespace ICSharpCode.Decompiler.Tests @@ -307,6 +307,12 @@ namespace ICSharpCode.Decompiler.Tests
Run(cscOptions: cscOptions);
}
[Test]
public void AsyncStreams([ValueSource(nameof(dotnetCoreOnlyOptions))] CompilerOptions cscOptions)
{
RunForLibrary(cscOptions: cscOptions);
}
[Test]
public void AsyncUsing([ValueSource(nameof(dotnetCoreOnlyOptions))] CompilerOptions cscOptions)
{

37
ICSharpCode.Decompiler.Tests/TestCases/Pretty/AsyncStreams.cs

@ -0,0 +1,37 @@ @@ -0,0 +1,37 @@
using System.Collections.Generic;
using System.Threading.Tasks;
namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
{
public class AsyncStreams
{
public static async IAsyncEnumerable<int> CountTo(int until)
{
for (int i = 0; i < until; i++) {
yield return i;
await Task.Delay(10);
}
}
public static async IAsyncEnumerable<int> AlwaysThrow()
{
throw null;
yield break;
}
public static async IAsyncEnumerator<int> InfiniteLoop()
{
while (true) {
}
yield break;
}
public static async IAsyncEnumerable<int> InfiniteLoopWithAwait()
{
while (true) {
await Task.Delay(10);
}
yield break;
}
}
}

6
ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs

@ -1343,7 +1343,11 @@ namespace ICSharpCode.Decompiler.CSharp @@ -1343,7 +1343,11 @@ namespace ICSharpCode.Decompiler.CSharp
if (localSettings.DecompileMemberBodies && !body.Descendants.Any(d => d is YieldReturnStatement || d is YieldBreakStatement)) {
body.Add(new YieldBreakStatement());
}
RemoveAttribute(entityDecl, KnownAttribute.IteratorStateMachine);
if (function.IsAsync) {
RemoveAttribute(entityDecl, KnownAttribute.AsyncIteratorStateMachine);
} else {
RemoveAttribute(entityDecl, KnownAttribute.IteratorStateMachine);
}
if (function.StateMachineCompiledWithMono) {
RemoveAttribute(entityDecl, KnownAttribute.DebuggerHidden);
}

7
ICSharpCode.Decompiler/IL/ControlFlow/AsyncAwaitDecompiler.cs

@ -174,9 +174,14 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow @@ -174,9 +174,14 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow
CopyPropagation.Propagate(stloc, context);
}
new RemoveDeadVariableInit().Run(function, context);
// Run inlining, but don't remove dead variables (they might get revived by TranslateFieldsToLocalAccess)
foreach (var block in function.Descendants.OfType<Block>()) {
// Run inlining, but don't remove dead variables (they might get revived by TranslateFieldsToLocalAccess)
ILInlining.InlineAllInBlock(function, block, context);
if (IsAsyncEnumerator) {
// Remove lone 'ldc.i4', those are sometimes left over after C# compiler
// optimizes out stores to the state variable.
block.Instructions.RemoveAll(inst => inst.OpCode == OpCode.LdcI4);
}
}
context.StepEndGroup();
}

6
ICSharpCode.Decompiler/IL/ControlFlow/ControlFlowSimplification.cs

@ -46,7 +46,7 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow @@ -46,7 +46,7 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow
context.CancellationToken.ThrowIfCancellationRequested();
RemoveNopInstructions(block);
RemoveDeadStackStores(block, aggressive: context.Settings.RemoveDeadStores);
RemoveDeadStackStores(block, context);
InlineVariableInReturnBlock(block, context);
// 1st pass SimplifySwitchInstruction before SimplifyBranchChains()
@ -70,13 +70,15 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow @@ -70,13 +70,15 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow
block.Instructions.RemoveAll(inst => inst.OpCode == OpCode.Nop);
}
private void RemoveDeadStackStores(Block block, bool aggressive)
private static void RemoveDeadStackStores(Block block, ILTransformContext context)
{
bool aggressive = context.Settings.RemoveDeadStores;
// Previously copy propagation did this;
// ideally the ILReader would already do this,
// for now do this here (even though it's not control-flow related).
for (int i = block.Instructions.Count - 1; i >= 0; i--) {
if (block.Instructions[i] is StLoc stloc && stloc.Variable.IsSingleDefinition && stloc.Variable.LoadCount == 0 && stloc.Variable.Kind == VariableKind.StackSlot) {
context.Step($"Remove dead stack store {stloc.Variable.Name}", stloc);
if (aggressive ? SemanticHelper.IsPure(stloc.Value.Flags) : IsSimple(stloc.Value)) {
Debug.Assert(SemanticHelper.IsPure(stloc.Value.Flags));
block.Instructions.RemoveAt(i++);

2
ICSharpCode.Decompiler/TypeSystem/Implementation/KnownAttributes.cs

@ -64,6 +64,7 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -64,6 +64,7 @@ namespace ICSharpCode.Decompiler.TypeSystem
IteratorStateMachine,
AsyncStateMachine,
AsyncMethodBuilder,
AsyncIteratorStateMachine,
// Field attributes:
FieldOffset,
@ -131,6 +132,7 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -131,6 +132,7 @@ namespace ICSharpCode.Decompiler.TypeSystem
new TopLevelTypeName("System.Runtime.CompilerServices", nameof(IteratorStateMachineAttribute)),
new TopLevelTypeName("System.Runtime.CompilerServices", nameof(AsyncStateMachineAttribute)),
new TopLevelTypeName("System.Runtime.CompilerServices", "AsyncMethodBuilderAttribute"),
new TopLevelTypeName("System.Runtime.CompilerServices", "AsyncIteratorStateMachineAttribute"),
// Field attributes:
new TopLevelTypeName("System.Runtime.InteropServices", nameof(FieldOffsetAttribute)),
new TopLevelTypeName("System", nameof(NonSerializedAttribute)),

Loading…
Cancel
Save