Browse Source

Merge pull request #4089 from icsharpcode/infer-type-with-compilation

Always pass the type system into InferType().
pull/4095/head
Daniel Grunwald 2 weeks ago committed by GitHub
parent
commit
1522aee302
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 5
      ICSharpCode.Decompiler.Tests/TestCases/VBPretty/VBAnonymousTypes.cs
  2. 3
      ICSharpCode.Decompiler.Tests/VBPrettyTestRunner.cs
  3. 11
      ICSharpCode.Decompiler/IL/ILTypeExtensions.cs
  4. 15
      ICSharpCode.Decompiler/IL/Instructions/CompoundAssignmentInstruction.cs
  5. 2
      ICSharpCode.Decompiler/IL/Instructions/InstructionCollection.cs
  6. 66
      ICSharpCode.Decompiler/IL/Transforms/TransformAssignment.cs

5
ICSharpCode.Decompiler.Tests/TestCases/VBPretty/VBAnonymousTypes.cs

@ -12,13 +12,8 @@ using Microsoft.VisualBasic.CompilerServices; @@ -12,13 +12,8 @@ using Microsoft.VisualBasic.CompilerServices;
// A VB anonymous type. Its properties are settable and only those declared 'Key'
// take part in Equals and GetHashCode, so it cannot be written as a C# anonymous
// type and is declared here instead.
#if LEGACY_VBC && OPT
[DebuggerDisplay("Value={Value}, Name={Name}")]
[CompilerGenerated]
#else
[CompilerGenerated]
[DebuggerDisplay("Value={Value}, Name={Name}")]
#endif
internal sealed class VB_AnonymousType_0<T0, T1>
{
#if !OPT && !LEGACY_VBC

3
ICSharpCode.Decompiler.Tests/VBPrettyTestRunner.cs

@ -193,7 +193,8 @@ namespace ICSharpCode.Decompiler.Tests @@ -193,7 +193,8 @@ namespace ICSharpCode.Decompiler.Tests
}
var executable = await Tester.CompileVB(vbFile, options | CompilerOptions.ReferenceVisualBasic, exeFile).ConfigureAwait(false);
var decompiled = await Tester.DecompileCSharp(executable.PathToAssembly, settings ?? new DecompilerSettings { FileScopedNamespaces = false }).ConfigureAwait(false);
settings ??= new DecompilerSettings { FileScopedNamespaces = false, SortCustomAttributes = true };
var decompiled = await Tester.DecompileCSharp(executable.PathToAssembly, settings).ConfigureAwait(false);
CodeAssert.FilesAreEqual(csFile, decompiled, Tester.GetPreprocessorSymbols(options).ToArray());
Tester.RepeatOnIOError(() => File.Delete(decompiled));

11
ICSharpCode.Decompiler/IL/ILTypeExtensions.cs

@ -17,6 +17,7 @@ @@ -17,6 +17,7 @@
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System.Diagnostics;
using System.Linq;
using ICSharpCode.Decompiler.TypeSystem;
@ -215,17 +216,15 @@ namespace ICSharpCode.Decompiler.IL @@ -215,17 +216,15 @@ namespace ICSharpCode.Decompiler.IL
/// If not returning UnknownType, must return a type that can store
/// the result of the instruction without loss of information.
/// </remarks>
public static IType InferType(this ILInstruction inst, ICompilation? compilation)
public static IType InferType(this ILInstruction inst, ICompilation compilation)
{
Debug.Assert(compilation != null);
switch (inst)
{
case NewObj newObj:
return newObj.Method.DeclaringType ?? SpecialType.UnknownType;
case NewArr newArr:
if (compilation != null)
return new ArrayType(compilation, newArr.Type, newArr.Indices.Count);
else
return SpecialType.UnknownType;
return new ArrayType(compilation, newArr.Type, newArr.Indices.Count);
case Call call:
return call.Method.ReturnType;
case CallVirt callVirt:
@ -258,8 +257,6 @@ namespace ICSharpCode.Decompiler.IL @@ -258,8 +257,6 @@ namespace ICSharpCode.Decompiler.IL
}
return new ByReferenceType(ldelema.Type);
case Comp comp:
if (compilation == null)
return SpecialType.UnknownType;
switch (comp.LiftingKind)
{
case ComparisonLiftingKind.None:

15
ICSharpCode.Decompiler/IL/Instructions/CompoundAssignmentInstruction.cs

@ -153,10 +153,11 @@ namespace ICSharpCode.Decompiler.IL @@ -153,10 +153,11 @@ namespace ICSharpCode.Decompiler.IL
public bool IsLifted { get; }
public NumericCompoundAssign(BinaryNumericInstruction binary, ILInstruction target,
CompoundTargetKind targetKind, ILInstruction value, IType type, CompoundEvalMode evalMode)
CompoundTargetKind targetKind, ILInstruction value, IType type, CompoundEvalMode evalMode,
Transforms.ILTransformContext context)
: base(OpCode.NumericCompoundAssign, evalMode, target, targetKind, value)
{
Debug.Assert(IsBinaryCompatibleWithType(binary, type, null));
Debug.Assert(IsBinaryCompatibleWithType(binary, type, context));
this.CheckForOverflow = binary.CheckForOverflow;
this.Sign = binary.Sign;
this.LeftInputType = binary.LeftInputType;
@ -166,14 +167,14 @@ namespace ICSharpCode.Decompiler.IL @@ -166,14 +167,14 @@ namespace ICSharpCode.Decompiler.IL
this.IsLifted = binary.IsLifted;
this.type = type;
this.AddILRange(binary);
Debug.Assert(evalMode == CompoundEvalMode.EvaluatesToNewValue || (Operator == BinaryNumericOperator.Add || Operator == BinaryNumericOperator.Sub));
Debug.Assert(evalMode == CompoundEvalMode.EvaluatesToNewValue || Operator == BinaryNumericOperator.Add || Operator == BinaryNumericOperator.Sub);
Debug.Assert(this.ResultType == (IsLifted ? StackType.O : UnderlyingResultType));
}
/// <summary>
/// Gets whether the specific binary instruction is compatible with a compound operation on the specified type.
/// </summary>
internal static bool IsBinaryCompatibleWithType(BinaryNumericInstruction binary, IType type, DecompilerSettings? settings)
internal static bool IsBinaryCompatibleWithType(BinaryNumericInstruction binary, IType type, Transforms.ILTransformContext context)
{
if (binary.IsLifted)
{
@ -220,7 +221,7 @@ namespace ICSharpCode.Decompiler.IL @@ -220,7 +221,7 @@ namespace ICSharpCode.Decompiler.IL
// If the LHS is C# 9 IntPtr (but not nint or C# 11 IntPtr):
// "target.intptr *= 2;" is compiler error, but
// "target.intptr *= (nint)2;" works
if (settings != null && !settings.NativeIntegers)
if (!context.Settings.NativeIntegers)
{
// But if native integers are not available, we cannot use compound assignment.
return false;
@ -235,7 +236,7 @@ namespace ICSharpCode.Decompiler.IL @@ -235,7 +236,7 @@ namespace ICSharpCode.Decompiler.IL
}
if (binary.Sign != Sign.None)
{
bool signMismatchAllowed = (binary.Sign == Sign.Unsigned && binary.Operator == BinaryNumericOperator.ShiftRight && (settings == null || settings.UnsignedRightShift));
bool signMismatchAllowed = binary.Sign == Sign.Unsigned && binary.Operator == BinaryNumericOperator.ShiftRight && context.Settings.UnsignedRightShift;
if (type.IsCSharpSmallIntegerType())
{
// C# will use numeric promotion to int, binary op must be signed
@ -250,7 +251,7 @@ namespace ICSharpCode.Decompiler.IL @@ -250,7 +251,7 @@ namespace ICSharpCode.Decompiler.IL
}
}
// Can't transform if the RHS value would be need to be truncated for the LHS type.
if (Transforms.TransformAssignment.IsImplicitTruncation(binary.Right, type, null, binary.IsLifted))
if (Transforms.TransformAssignment.IsImplicitTruncation(binary.Right, type, context.TypeSystem, binary.IsLifted))
return false;
return true;
}

2
ICSharpCode.Decompiler/IL/Instructions/InstructionCollection.cs

@ -292,7 +292,7 @@ namespace ICSharpCode.Decompiler.IL @@ -292,7 +292,7 @@ namespace ICSharpCode.Decompiler.IL
parentInstruction.InstructionCollectionUpdateComplete();
}
public bool Remove(T item)
public bool Remove(T? item)
{
int index = IndexOf(item);
if (index >= 0)

66
ICSharpCode.Decompiler/IL/Transforms/TransformAssignment.cs

@ -16,12 +16,16 @@ @@ -16,12 +16,16 @@
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
#nullable enable
using System;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Linq.Expressions;
using ICSharpCode.Decompiler.CSharp;
using ICSharpCode.Decompiler.CSharp.Transforms;
using ICSharpCode.Decompiler.TypeSystem;
using ICSharpCode.Decompiler.Util;
@ -37,7 +41,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -37,7 +41,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
/// </remarks>
public class TransformAssignment : IStatementTransform
{
StatementTransformContext context;
StatementTransformContext context = null!;
void IStatementTransform.Run(Block block, int pos, StatementTransformContext context)
{
@ -109,8 +113,10 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -109,8 +113,10 @@ namespace ICSharpCode.Decompiler.IL.Transforms
}
ILVariable local;
int nextPos;
if (block.Instructions[pos + 1] is StLoc localStore)
StLoc? localStore;
if (block.Instructions[pos + 1] is StLoc localStoreInst)
{ // with extra local
localStore = localStoreInst;
if (localStore.Variable.Kind != VariableKind.Local || !localStore.Value.MatchLdLoc(inst.Variable))
return false;
// if we're using an extra local, we'll delete "s", so check that that doesn't have any additional uses
@ -179,7 +185,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -179,7 +185,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
return false;
if (call.ResultType != StackType.Void || call.Arguments.Count == 0)
return false;
IProperty property = call.Method.AccessorOwner as IProperty;
IProperty? property = call.Method.AccessorOwner as IProperty;
if (property == null)
return false;
if (!call.Method.Equals(property.Setter))
@ -246,30 +252,28 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -246,30 +252,28 @@ namespace ICSharpCode.Decompiler.IL.Transforms
};
}
static ILInstruction UnwrapSmallIntegerConv(ILInstruction inst, out Conv conv)
static ILInstruction UnwrapSmallIntegerConv(ILInstruction inst, [NotNullWhen(true)] out Conv? conv)
{
conv = inst as Conv;
if (conv != null && conv.Kind == ConversionKind.Truncate && conv.TargetType.IsSmallIntegerType())
if (inst is Conv { Kind: ConversionKind.Truncate } convInst && convInst.TargetType.IsSmallIntegerType())
{
// for compound assignments to small integers, the compiler emits a "conv" instruction
return conv.Argument;
}
else
{
return inst;
conv = convInst;
return convInst.Argument;
}
conv = null;
return inst;
}
static bool ValidateCompoundAssign(BinaryNumericInstruction binary, Conv conv, IType targetType, DecompilerSettings settings)
static bool ValidateCompoundAssign(BinaryNumericInstruction binary, Conv? conv, IType targetType, ILTransformContext context)
{
if (!NumericCompoundAssign.IsBinaryCompatibleWithType(binary, targetType, settings))
if (!NumericCompoundAssign.IsBinaryCompatibleWithType(binary, targetType, context))
return false;
if (conv != null && !(conv.TargetType == targetType.ToPrimitiveType() && conv.CheckForOverflow == binary.CheckForOverflow))
return false; // conv does not match binary operation
return true;
}
static bool MatchingGetterAndSetterCalls(CallInstruction getterCall, CallInstruction setterCall, out Action<ILTransformContext> finalizeMatch)
static bool MatchingGetterAndSetterCalls(CallInstruction? getterCall, CallInstruction? setterCall, out Action<ILTransformContext>? finalizeMatch)
{
finalizeMatch = null;
if (getterCall == null || setterCall == null || !IsSameMember(getterCall.Method.AccessorOwner, setterCall.Method.AccessorOwner))
@ -378,13 +382,13 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -378,13 +382,13 @@ namespace ICSharpCode.Decompiler.IL.Transforms
}
if (!IsMatchingCompoundLoad(binary.Left, compoundStore, out var target, out var targetKind, out var finalizeMatch, forbiddenVariable: storeInSetter?.Variable))
return false;
if (!ValidateCompoundAssign(binary, smallIntConv, targetType, context.Settings))
if (!ValidateCompoundAssign(binary, smallIntConv, targetType, context))
return false;
context.Step($"Compound assignment (binary.numeric)", compoundStore);
finalizeMatch?.Invoke(context);
newInst = new NumericCompoundAssign(
binary, target, targetKind, binary.Right,
targetType, CompoundEvalMode.EvaluatesToNewValue);
targetType, CompoundEvalMode.EvaluatesToNewValue, context);
}
else if (setterValue is Call operatorCall && operatorCall.Method.IsOperator)
{
@ -684,8 +688,8 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -684,8 +688,8 @@ namespace ICSharpCode.Decompiler.IL.Transforms
///
/// Every IsCompoundStore() call should be followed by an IsMatchingCompoundLoad() call.
/// </remarks>
static bool IsCompoundStore(ILInstruction inst, out IType storeType,
out ILInstruction value, ICompilation compilation)
static bool IsCompoundStore(ILInstruction inst, [NotNullWhen(true)] out IType? storeType,
[NotNullWhen(true)] out ILInstruction? value, ICompilation compilation)
{
value = null;
storeType = null;
@ -773,10 +777,10 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -773,10 +777,10 @@ namespace ICSharpCode.Decompiler.IL.Transforms
/// Instruction preceding the load.
/// </param>
static bool IsMatchingCompoundLoad(ILInstruction load, ILInstruction store,
out ILInstruction target, out CompoundTargetKind targetKind,
out Action<ILTransformContext> finalizeMatch,
ILVariable forbiddenVariable = null,
ILInstruction previousInstruction = null)
[NotNullWhen(true)] out ILInstruction? target, out CompoundTargetKind targetKind,
out Action<ILTransformContext>? finalizeMatch,
ILVariable? forbiddenVariable = null,
ILInstruction? previousInstruction = null)
{
target = null;
targetKind = 0;
@ -870,7 +874,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -870,7 +874,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
var targetType = targetType1;
var stloc_outer = store as StLoc;
var stloc_inner = value1 as StLoc;
LdLoc ldloc;
LdLoc? ldloc;
var binary = UnwrapSmallIntegerConv(value2, out var conv) as BinaryNumericInstruction;
if (binary != null && (binary.Right.MatchLdcI(1) || binary.Right.MatchLdcF4(1) || binary.Right.MatchLdcF8(1)))
{
@ -884,7 +888,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -884,7 +888,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
targetType = SwapSign(targetType, context.TypeSystem);
}
if (!ValidateCompoundAssign(binary, conv, targetType, context.Settings))
if (!ValidateCompoundAssign(binary, conv, targetType, context))
return false;
ldloc = binary.Left as LdLoc;
}
@ -917,7 +921,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -917,7 +921,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
if (binary != null)
{
block.Instructions[pos] = new StLoc(stloc_outer.Variable, new NumericCompoundAssign(
binary, target, targetKind, binary.Right, targetType, CompoundEvalMode.EvaluatesToNewValue));
binary, target, targetKind, binary.Right, targetType, CompoundEvalMode.EvaluatesToNewValue, context));
}
else
{
@ -955,7 +959,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -955,7 +959,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
{
return false;
}
StLoc stloc;
StLoc? stloc;
var binary = UnwrapSmallIntegerConv(value, out var conv) as BinaryNumericInstruction;
if (binary != null && (binary.Right.MatchLdcI(1) || binary.Right.MatchLdcF4(1) || binary.Right.MatchLdcF8(1)))
{
@ -969,7 +973,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -969,7 +973,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
targetType = SwapSign(targetType, context.TypeSystem);
}
if (!ValidateCompoundAssign(binary, conv, targetType, context.Settings))
if (!ValidateCompoundAssign(binary, conv, targetType, context))
return false;
stloc = binary.Left as StLoc;
}
@ -998,7 +1002,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -998,7 +1002,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
if (binary != null)
{
block.Instructions[pos] = new StLoc(stloc.Variable, new NumericCompoundAssign(
binary, target, targetKind, binary.Right, targetType, CompoundEvalMode.EvaluatesToOldValue));
binary, target, targetKind, binary.Right, targetType, CompoundEvalMode.EvaluatesToOldValue, context));
}
else
{
@ -1077,12 +1081,12 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -1077,12 +1081,12 @@ namespace ICSharpCode.Decompiler.IL.Transforms
// Change the sign of the type to skip implicit truncation
stObj.Type = targetType = SwapSign(targetType, context.TypeSystem);
}
if (!ValidateCompoundAssign(binary, conv, targetType, context.Settings))
if (!ValidateCompoundAssign(binary, conv, targetType, context))
return false;
context.Step("TransformPostIncDecOperator (builtin)", inst);
finalizeMatch?.Invoke(context);
inst.Value = new NumericCompoundAssign(binary, target, targetKind, binary.Right,
targetType, CompoundEvalMode.EvaluatesToOldValue);
targetType, CompoundEvalMode.EvaluatesToOldValue, context);
}
else if (value is Call operatorCall && operatorCall.Method.IsOperator && operatorCall.Arguments.Count == 1)
{
@ -1111,7 +1115,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -1111,7 +1115,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
return true;
}
static bool IsSameMember(IMember a, IMember b)
static bool IsSameMember(IMember? a, IMember? b)
{
if (a == null || b == null)
return false;

Loading…
Cancel
Save