Browse Source

#3593: ObjectInitializers: allow castclass instructions wrapping the init instruction to support the pattern used for covariant returns on non-supporting platforms such as .NET 4.x.

pull/3606/head
Siegfried Pammer 2 months ago
parent
commit
588c243929
  1. 19
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/InitializerTests.cs
  2. 11
      ICSharpCode.Decompiler/IL/Transforms/TransformCollectionAndObjectInitializers.cs

19
ICSharpCode.Decompiler.Tests/TestCases/Pretty/InitializerTests.cs

@ -229,6 +229,11 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty.InitializerTests @@ -229,6 +229,11 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty.InitializerTests
public string S = "abc";
public Item I;
}
public record DerivedFields : Fields
{
public ConsoleKey E;
}
#endif
public interface IData
@ -1145,6 +1150,20 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty.InitializerTests @@ -1145,6 +1150,20 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty.InitializerTests
}
};
}
public DerivedFields DerivedRecordTest(DerivedFields input)
{
return input with {
A = 42,
D = 43,
I = new Item {
Value7 = input with {
A = 44,
D = 45
}
}
};
}
#endif
private TData GenericObjectInitializer<TData>() where TData : IData, new()

11
ICSharpCode.Decompiler/IL/Transforms/TransformCollectionAndObjectInitializers.cs

@ -47,6 +47,13 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -47,6 +47,13 @@ namespace ICSharpCode.Decompiler.IL.Transforms
var insertionPos = initInst.ChildIndex;
var siblings = initInst.Parent!.Children;
IMethod currentMethod = context.Function.Method!;
// we allow a castclass instruction to wrap the init instruction:
// this is needed, for example, for inherited record types used on .NET runtimes (e.g., .NET 4.x),
// where covariant return types are not supported.
if (initInst.MatchCastClass(out var arg, out var targetType))
{
initInst = arg;
}
switch (initInst)
{
case NewObj newObjInst:
@ -100,6 +107,10 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -100,6 +107,10 @@ namespace ICSharpCode.Decompiler.IL.Transforms
}
return;
}
if (targetType != null)
{
instType = targetType;
}
// Copy-propagate stack slot holding an 'ldloca' of the variable
if (pos < block.Instructions.Count && block.Instructions[pos + 1] is StLoc { Variable: { Kind: VariableKind.StackSlot, IsSingleDefinition: true }, Value: LdLoca ldLoca } stLocStack && ldLoca.Variable == v)
{

Loading…
Cancel
Save