Browse Source

Fix #1759: Substitute display-class type parameters with method type parameters in TransformDisplayClassUsage.

pull/1790/head
Siegfried Pammer 7 years ago
parent
commit
6330be36b3
  1. 34
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/DelegateConstruction.cs
  2. 19
      ICSharpCode.Decompiler/IL/Transforms/TransformDisplayClassUsage.cs

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

@ -151,6 +151,7 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
{ {
void M3(); void M3();
} }
public class BaseClass : IM3 public class BaseClass : IM3
{ {
protected virtual void M1() protected virtual void M1()
@ -163,6 +164,7 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
{ {
} }
} }
public class SubClass : BaseClass public class SubClass : BaseClass
{ {
protected override void M2() protected override void M2()
@ -193,6 +195,7 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
Noop("M3", M3); Noop("M3", M3);
#endif #endif
} }
public void Test2() public void Test2()
{ {
Noop("M3.new", new BaseClass().M3); Noop("M3.new", new BaseClass().M3);
@ -204,6 +207,28 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
} }
} }
public class GenericTest<TNonCaptured, TCaptured>
{
public Func<TCaptured> GetFunc(Func<TNonCaptured, TCaptured> f)
{
TCaptured captured = f(default(TNonCaptured));
return delegate {
Console.WriteLine(captured.GetType().FullName);
return captured;
};
}
public Func<TNonCaptured, TNonCapturedMP, TCaptured> GetFunc<TNonCapturedMP>(Func<TCaptured> f)
{
TCaptured captured = f();
return delegate(TNonCaptured a, TNonCapturedMP d) {
Console.WriteLine(a.GetHashCode());
Console.WriteLine(captured.GetType().FullName);
return captured;
};
}
}
public static Func<string, string, bool> test0 = (string a, string b) => string.IsNullOrEmpty(a) || string.IsNullOrEmpty(b); public static Func<string, string, bool> test0 = (string a, string b) => string.IsNullOrEmpty(a) || string.IsNullOrEmpty(b);
public static Func<string, string, bool> test1 = (string a, string b) => string.IsNullOrEmpty(a) || !string.IsNullOrEmpty(b); public static Func<string, string, bool> test1 = (string a, string b) => string.IsNullOrEmpty(a) || !string.IsNullOrEmpty(b);
public static Func<string, string, bool> test2 = (string a, string b) => !string.IsNullOrEmpty(a) || string.IsNullOrEmpty(b); public static Func<string, string, bool> test2 = (string a, string b) => !string.IsNullOrEmpty(a) || string.IsNullOrEmpty(b);
@ -342,5 +367,14 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
{ {
return (int b) => (int c) => (int d) => a + b + c + d; return (int b) => (int c) => (int d) => a + b + c + d;
} }
public static Func<TCaptured> CapturedTypeParameter1<TNonCaptured, TCaptured>(TNonCaptured a, Func<TNonCaptured, TCaptured> f)
{
TCaptured captured = f(a);
return delegate {
Console.WriteLine(captured.GetType().FullName);
return captured;
};
}
} }
} }

19
ICSharpCode.Decompiler/IL/Transforms/TransformDisplayClassUsage.cs

@ -321,7 +321,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
if (displayClass.IsMono && displayClass.CaptureScope == null && !IsOuterClosureReference(field)) { if (displayClass.IsMono && displayClass.CaptureScope == null && !IsOuterClosureReference(field)) {
displayClass.CaptureScope = BlockContainer.FindClosestContainer(inst); displayClass.CaptureScope = BlockContainer.FindClosestContainer(inst);
} }
v = displayClass.DeclaringFunction.RegisterVariable(VariableKind.Local, field.Type, field.Name); v = displayClass.DeclaringFunction.RegisterVariable(VariableKind.Local, GetVariableTypeFromClosureField(field), field.Name);
v.HasInitialValue = true; v.HasInitialValue = true;
v.CaptureScope = displayClass.CaptureScope; v.CaptureScope = displayClass.CaptureScope;
inst.ReplaceWith(new StLoc(v, inst.Value).WithILRange(inst)); inst.ReplaceWith(new StLoc(v, inst.Value).WithILRange(inst));
@ -370,7 +370,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
context.Step($"Introduce captured variable for {field.FullName}", inst); context.Step($"Introduce captured variable for {field.FullName}", inst);
// Introduce a fresh variable for the display class field. // Introduce a fresh variable for the display class field.
Debug.Assert(displayClass.Definition == field.DeclaringTypeDefinition); Debug.Assert(displayClass.Definition == field.DeclaringTypeDefinition);
var v = displayClass.DeclaringFunction.RegisterVariable(VariableKind.Local, field.Type, field.Name); var v = displayClass.DeclaringFunction.RegisterVariable(VariableKind.Local, GetVariableTypeFromClosureField(field), field.Name);
v.HasInitialValue = true; v.HasInitialValue = true;
v.CaptureScope = displayClass.CaptureScope; v.CaptureScope = displayClass.CaptureScope;
inst.ReplaceWith(new LdLoca(v).WithILRange(inst)); inst.ReplaceWith(new LdLoca(v).WithILRange(inst));
@ -381,5 +381,20 @@ namespace ICSharpCode.Decompiler.IL.Transforms
Debug.Fail("LdFlda pattern not supported!"); 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