Browse Source

#1749: Represent multi-instruction BlockContainers in expression-context as inlined delegate invocation.

pull/1791/head
Siegfried Pammer 6 years ago
parent
commit
64b9511aca
  1. 29
      ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs
  2. 22
      ICSharpCode.Decompiler/CSharp/StatementBuilder.cs
  3. 2
      ICSharpCode.Decompiler/TypeSystem/ParameterizedType.cs

29
ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs

@ -67,6 +67,7 @@ namespace ICSharpCode.Decompiler.CSharp @@ -67,6 +67,7 @@ namespace ICSharpCode.Decompiler.CSharp
/// </remarks>
sealed class ExpressionBuilder : ILVisitor<TranslationContext, TranslatedExpression>
{
readonly StatementBuilder statementBuilder;
readonly IDecompilerTypeSystem typeSystem;
internal readonly ITypeResolveContext decompilationContext;
internal readonly ILFunction currentFunction;
@ -77,9 +78,10 @@ namespace ICSharpCode.Decompiler.CSharp @@ -77,9 +78,10 @@ namespace ICSharpCode.Decompiler.CSharp
internal readonly DecompilerSettings settings;
readonly CancellationToken cancellationToken;
public ExpressionBuilder(IDecompilerTypeSystem typeSystem, ITypeResolveContext decompilationContext, ILFunction currentFunction, DecompilerSettings settings, CancellationToken cancellationToken)
public ExpressionBuilder(StatementBuilder statementBuilder, IDecompilerTypeSystem typeSystem, ITypeResolveContext decompilationContext, ILFunction currentFunction, DecompilerSettings settings, CancellationToken cancellationToken)
{
Debug.Assert(decompilationContext != null);
this.statementBuilder = statementBuilder;
this.typeSystem = typeSystem;
this.decompilationContext = decompilationContext;
this.currentFunction = currentFunction;
@ -1940,6 +1942,31 @@ namespace ICSharpCode.Decompiler.CSharp @@ -1940,6 +1942,31 @@ namespace ICSharpCode.Decompiler.CSharp
}
}
protected internal override TranslatedExpression VisitBlockContainer(BlockContainer container, TranslationContext context)
{
var oldReturnContainer = statementBuilder.currentReturnContainer;
var oldResultType = statementBuilder.currentResultType;
var oldIsIterator = statementBuilder.currentIsIterator;
statementBuilder.currentReturnContainer = container;
statementBuilder.currentResultType = context.TypeHint;
statementBuilder.currentIsIterator = false;
try {
var body = statementBuilder.ConvertAsBlock(container);
body.InsertChildAfter(null, new Comment(" Could not convert BlockContainer to single expression"), Roles.Comment);
var ame = new AnonymousMethodExpression { Body = body };
var delegateType = new ParameterizedType(compilation.FindType(typeof(Func<>)), InferReturnType(body));
var invocationTarget = new CastExpression(ConvertType(delegateType), ame);
return new InvocationExpression(new MemberReferenceExpression(invocationTarget, "Invoke"))
.WithILInstruction(container)
.WithRR(new CSharpInvocationResolveResult(new ResolveResult(delegateType), delegateType.GetDelegateInvokeMethod(), EmptyList<ResolveResult>.Instance));
} finally {
statementBuilder.currentReturnContainer = oldReturnContainer;
statementBuilder.currentResultType = oldResultType;
statementBuilder.currentIsIterator = oldIsIterator;
}
}
internal TranslatedExpression TranslateTarget(ILInstruction target, bool nonVirtualInvocation,
bool memberStatic, IType memberDeclaringType)
{

22
ICSharpCode.Decompiler/CSharp/StatementBuilder.cs

@ -28,7 +28,6 @@ using System; @@ -28,7 +28,6 @@ using System;
using System.Threading;
using ICSharpCode.Decompiler.IL.Transforms;
using ICSharpCode.Decompiler.CSharp.Syntax.PatternMatching;
using ICSharpCode.Decompiler.CSharp.Resolver;
namespace ICSharpCode.Decompiler.CSharp
{
@ -40,11 +39,18 @@ namespace ICSharpCode.Decompiler.CSharp @@ -40,11 +39,18 @@ namespace ICSharpCode.Decompiler.CSharp
readonly DecompilerSettings settings;
readonly CancellationToken cancellationToken;
internal BlockContainer currentReturnContainer;
internal IType currentResultType;
internal bool currentIsIterator;
public StatementBuilder(IDecompilerTypeSystem typeSystem, ITypeResolveContext decompilationContext, ILFunction currentFunction, DecompilerSettings settings, CancellationToken cancellationToken)
{
Debug.Assert(typeSystem != null && decompilationContext != null);
this.exprBuilder = new ExpressionBuilder(typeSystem, decompilationContext, currentFunction, settings, cancellationToken);
this.exprBuilder = new ExpressionBuilder(this, typeSystem, decompilationContext, currentFunction, settings, cancellationToken);
this.currentFunction = currentFunction;
this.currentReturnContainer = (BlockContainer)currentFunction.Body;
this.currentIsIterator = currentFunction.IsIterator;
this.currentResultType = currentFunction.IsAsync ? currentFunction.AsyncReturnType : currentFunction.ReturnType;
this.typeSystem = typeSystem;
this.settings = settings;
this.cancellationToken = cancellationToken;
@ -300,19 +306,17 @@ namespace ICSharpCode.Decompiler.CSharp @@ -300,19 +306,17 @@ namespace ICSharpCode.Decompiler.CSharp
{
if (inst.TargetContainer == breakTarget)
return new BreakStatement();
if (inst.IsLeavingFunction) {
if (currentFunction.IsIterator)
if (inst.TargetContainer == currentReturnContainer) {
if (currentIsIterator)
return new YieldBreakStatement();
else if (!inst.Value.MatchNop()) {
IType targetType = currentFunction.IsAsync ? currentFunction.AsyncReturnType : currentFunction.ReturnType;
var expr = exprBuilder.Translate(inst.Value, typeHint: targetType)
.ConvertTo(targetType, exprBuilder, allowImplicitConversion: true);
var expr = exprBuilder.Translate(inst.Value, typeHint: currentResultType)
.ConvertTo(currentResultType, exprBuilder, allowImplicitConversion: true);
return new ReturnStatement(expr);
} else
return new ReturnStatement();
}
string label;
if (!endContainerLabels.TryGetValue(inst.TargetContainer, out label)) {
if (!endContainerLabels.TryGetValue(inst.TargetContainer, out string label)) {
label = "end_" + inst.TargetLabel;
endContainerLabels.Add(inst.TargetContainer, label);
}

2
ICSharpCode.Decompiler/TypeSystem/ParameterizedType.cs

@ -67,7 +67,7 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -67,7 +67,7 @@ namespace ICSharpCode.Decompiler.TypeSystem
/// Fast internal version of the constructor. (no safety checks)
/// Keeps the array that was passed and assumes it won't be modified.
/// </summary>
internal ParameterizedType(IType genericType, IType[] typeArguments)
internal ParameterizedType(IType genericType, params IType[] typeArguments)
{
Debug.Assert(genericType.TypeParameterCount == typeArguments.Length);
this.genericType = genericType;

Loading…
Cancel
Save