diff --git a/ICSharpCode.Decompiler/Ast/Transforms/DelegateConstruction.cs b/ICSharpCode.Decompiler/Ast/Transforms/DelegateConstruction.cs index 871fc2546..1e0ce47bf 100644 --- a/ICSharpCode.Decompiler/Ast/Transforms/DelegateConstruction.cs +++ b/ICSharpCode.Decompiler/Ast/Transforms/DelegateConstruction.cs @@ -330,12 +330,30 @@ namespace ICSharpCode.Decompiler.Ast.Transforms if (right is ThisReferenceExpression) { isParameter = true; } else if (right is IdentifierExpression) { - // handle parameters only if the whole method contains no other occurrance except for 'right' + // handle parameters only if the whole method contains no other occurrence except for 'right' ILVariable v = right.Annotation(); isParameter = v.IsParameter && parameterOccurrances.Count(c => c == v) == 1; - if (!isParameter && TypeAnalysis.IsSameType(v.Type, fieldDef.FieldType) && IsPotentialClosure(context, v.Type.ResolveWithinSameModule())) { + if (!isParameter && IsPotentialClosure(context, v.Type.ResolveWithinSameModule())) { + // parent display class within the same method + // (closure2.localsX = closure1;) isDisplayClassParentPointerAssignment = true; } + } else if (right is MemberReferenceExpression) { + // copy of parent display class reference from an outer lambda + // closure2.localsX = this.localsY + MemberReferenceExpression mre = m.Get("right").Single(); + do { + // descend into the targets of the mre as long as the field types are closures + FieldDefinition fieldDef2 = mre.Annotation().ResolveWithinSameModule(); + if (fieldDef2 == null || !IsPotentialClosure(context, fieldDef2.FieldType.ResolveWithinSameModule())) { + break; + } + // if we finally get to a this reference, it's copying a display class parent pointer + if (mre.Target is ThisReferenceExpression) { + isDisplayClassParentPointerAssignment = true; + } + mre = mre.Target as MemberReferenceExpression; + } while (mre != null); } if (isParameter || isDisplayClassParentPointerAssignment) { dict[fieldDef] = right; diff --git a/ICSharpCode.Decompiler/Tests/DelegateConstruction.cs b/ICSharpCode.Decompiler/Tests/DelegateConstruction.cs index 248337da2..14f6ce8e1 100644 --- a/ICSharpCode.Decompiler/Tests/DelegateConstruction.cs +++ b/ICSharpCode.Decompiler/Tests/DelegateConstruction.cs @@ -25,21 +25,25 @@ public static class DelegateConstruction public Action CaptureOfThisAndParameterInForEach(int a) { - foreach (var item in Enumerable.Empty()) { - return delegate { - CaptureOfThisAndParameter(item + a); - }; + foreach (int item in Enumerable.Empty()) { + if (item > 0) { + return delegate { + CaptureOfThisAndParameter(item + a); + }; + } } return null; } public Action CaptureOfThisAndParameterInForEachWithItemCopy(int a) { - foreach (var item in Enumerable.Empty()) { + foreach (int item in Enumerable.Empty()) { int copyOfItem = item; - return delegate { - CaptureOfThisAndParameter(item + a + copyOfItem); - }; + if (item > 0) { + return delegate { + CaptureOfThisAndParameter(item + a + copyOfItem); + }; + } } return null; } @@ -162,4 +166,9 @@ public static class DelegateConstruction { return b => c => a + b + c; } + + public static Func>> CurriedAddition2(int a) + { + return b => c => d => a + b + c + d; + } }