From 413c9eba2c677e3304dc29f192d4c98c7673cd88 Mon Sep 17 00:00:00 2001 From: Siegfried Pammer Date: Thu, 31 Oct 2019 20:34:25 +0100 Subject: [PATCH] #1759: Follow-up: Handle nested generic arguments as well. --- .../TestCases/Pretty/DelegateConstruction.cs | 9 +++++++ .../Transforms/TransformDisplayClassUsage.cs | 27 +++++++------------ 2 files changed, 19 insertions(+), 17 deletions(-) diff --git a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/DelegateConstruction.cs b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/DelegateConstruction.cs index c7c4ff78e..2409c65a9 100644 --- a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/DelegateConstruction.cs +++ b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/DelegateConstruction.cs @@ -376,5 +376,14 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty return captured; }; } + + public static Func CapturedTypeParameter2(TNonCaptured a, Func> f) + { + List captured = f(a); + return delegate { + Console.WriteLine(captured.GetType().FullName); + return captured.FirstOrDefault(); + }; + } } } diff --git a/ICSharpCode.Decompiler/IL/Transforms/TransformDisplayClassUsage.cs b/ICSharpCode.Decompiler/IL/Transforms/TransformDisplayClassUsage.cs index 344d9f756..728979707 100644 --- a/ICSharpCode.Decompiler/IL/Transforms/TransformDisplayClassUsage.cs +++ b/ICSharpCode.Decompiler/IL/Transforms/TransformDisplayClassUsage.cs @@ -303,6 +303,10 @@ namespace ICSharpCode.Decompiler.IL.Transforms // Get display class info if (!IsDisplayClassLoad(target, out var displayClassLoad) || !displayClasses.TryGetValue(displayClassLoad, out var displayClass)) return; + // We want the specialized version, so that display-class type parameters are + // substituted with the type parameters from the use-site. + var fieldType = field.Type; + // However, use the unspecialized member definition to make reference comparisons in dictionary possible. field = (IField)field.MemberDefinition; if (displayClass.Variables.TryGetValue(field, out DisplayClassVariable info)) { // If the display class field was previously initialized, we use a simple assignment. @@ -321,7 +325,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms if (displayClass.IsMono && displayClass.CaptureScope == null && !IsOuterClosureReference(field)) { displayClass.CaptureScope = BlockContainer.FindClosestContainer(inst); } - v = displayClass.DeclaringFunction.RegisterVariable(VariableKind.Local, GetVariableTypeFromClosureField(field), field.Name); + v = displayClass.DeclaringFunction.RegisterVariable(VariableKind.Local, fieldType, field.Name); v.HasInitialValue = true; v.CaptureScope = displayClass.CaptureScope; inst.ReplaceWith(new StLoc(v, inst.Value).WithILRange(inst)); @@ -365,12 +369,16 @@ namespace ICSharpCode.Decompiler.IL.Transforms // Get display class info if (!IsDisplayClassLoad(inst.Target, out var displayClassLoad) || !displayClasses.TryGetValue(displayClassLoad, out var displayClass)) return; + // Use the unspecialized member definition to make reference comparisons in dictionary possible. var field = (IField)inst.Field.MemberDefinition; + // However, we want the specialized version, so that display-class type parameters are + // substituted with the type parameters from the use-site. + var fieldType = inst.Field.Type; if (!displayClass.Variables.TryGetValue(field, out DisplayClassVariable info)) { context.Step($"Introduce captured variable for {field.FullName}", inst); // Introduce a fresh variable for the display class field. Debug.Assert(displayClass.Definition == field.DeclaringTypeDefinition); - var v = displayClass.DeclaringFunction.RegisterVariable(VariableKind.Local, GetVariableTypeFromClosureField(field), field.Name); + var v = displayClass.DeclaringFunction.RegisterVariable(VariableKind.Local, fieldType, field.Name); v.HasInitialValue = true; v.CaptureScope = displayClass.CaptureScope; inst.ReplaceWith(new LdLoca(v).WithILRange(inst)); @@ -381,20 +389,5 @@ namespace ICSharpCode.Decompiler.IL.Transforms Debug.Fail("LdFlda pattern not supported!"); } } - - private IType GetVariableTypeFromClosureField(IField field) - { - if (!(field.Type is ITypeParameter typeParameter)) - return field.Type; - var rootMethod = context.Function.Method; - if (typeParameter.Owner != field.DeclaringTypeDefinition) - return field.Type; - if (typeParameter.Index >= rootMethod.TypeParameters.Count) { - Debug.Assert(false, "Cannot map display-class type parameter to method type parameter"); - return field.Type; - } - - return rootMethod.TypeParameters[typeParameter.Index]; - } } }