Browse Source

#1759: Follow-up: Handle nested generic arguments as well.

pull/1790/head
Siegfried Pammer 6 years ago
parent
commit
413c9eba2c
  1. 9
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/DelegateConstruction.cs
  2. 27
      ICSharpCode.Decompiler/IL/Transforms/TransformDisplayClassUsage.cs

9
ICSharpCode.Decompiler.Tests/TestCases/Pretty/DelegateConstruction.cs

@ -376,5 +376,14 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
return captured;
};
}
public static Func<TCaptured> CapturedTypeParameter2<TNonCaptured, TCaptured>(TNonCaptured a, Func<TNonCaptured, List<TCaptured>> f)
{
List<TCaptured> captured = f(a);
return delegate {
Console.WriteLine(captured.GetType().FullName);
return captured.FirstOrDefault();
};
}
}
}

27
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];
}
}
}
Loading…
Cancel
Save