Browse Source

MergeSimilarTypes: add support for more kinds of types

pull/4077/head
Daniel Grunwald 2 weeks ago
parent
commit
fa3de7bfa4
  1. 25
      ICSharpCode.Decompiler.Tests/Semantics/TypeInferenceTests.cs
  2. 50
      ICSharpCode.Decompiler/CSharp/Resolver/TypeInference.cs

25
ICSharpCode.Decompiler.Tests/Semantics/TypeInferenceTests.cs

@ -23,6 +23,7 @@ using System.Collections.Immutable; @@ -23,6 +23,7 @@ using System.Collections.Immutable;
using System.Collections.ObjectModel;
using System.IO;
using System.Linq;
using System.Reflection.Metadata;
using ICSharpCode.Decompiler.CSharp.Resolver;
using ICSharpCode.Decompiler.Metadata;
@ -713,6 +714,15 @@ namespace ICSharpCode.Decompiler.Tests.Semantics @@ -713,6 +714,15 @@ namespace ICSharpCode.Decompiler.Tests.Semantics
ImmutableArray.CreateRange(elementNames));
}
FunctionPointerType MakeFunctionPointerType(ICompilation comp, IType returnType)
{
return new FunctionPointerType(
(MetadataModule)comp.MainModule,
SignatureCallingConvention.Default, ImmutableArray<IType>.Empty,
returnType, returnIsRefReadOnly: false,
ImmutableArray<IType>.Empty, ImmutableArray<ReferenceKind>.Empty);
}
[Test]
public void BestCommonTypeMergesTupleElementNames()
{
@ -730,6 +740,21 @@ namespace ICSharpCode.Decompiler.Tests.Semantics @@ -730,6 +740,21 @@ namespace ICSharpCode.Decompiler.Tests.Semantics
Assert.That(success);
}
[Test]
public void BestCommonTypeMergesFunctionPointerTupleElementNames()
{
var comp = RefAssemblyCompilation.Instance;
var inference = new TypeInference(comp);
Assert.That(
inference.GetBestCommonType(new[] {
new ResolveResult(MakeFunctionPointerType(comp, MakeTupleType(comp, "a", "b"))),
new ResolveResult(MakeFunctionPointerType(comp, MakeTupleType(comp, "a", "c")))
}, out bool success),
Is.EqualTo(MakeFunctionPointerType(comp, MakeTupleType(comp, "a", null))));
Assert.That(success);
}
[Test]
public void FixingMergesTupleElementNamesOfExactAndLowerBounds()
{

50
ICSharpCode.Decompiler/CSharp/Resolver/TypeInference.cs

@ -1101,6 +1101,15 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver @@ -1101,6 +1101,15 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
var nullability = MergeNullability(arrA.Nullability, arrB.Nullability, variance);
return new ArrayType(arrA.Compilation, mergedElem, arrA.Dimensions, nullability);
}
if (a is ByReferenceType refA && b is ByReferenceType refB)
{
var mergedElem = MergeSimilarTypes(
refA.ElementType, refB.ElementType,
variance.Combine(VarianceModifier.Invariant));
if (mergedElem == null)
return null;
return new ByReferenceType(mergedElem);
}
if (a is PointerType ptrA && b is PointerType ptrB)
{
var mergedElem = MergeSimilarTypes(
@ -1110,6 +1119,47 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver @@ -1110,6 +1119,47 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
return null;
return new PointerType(mergedElem);
}
if (a is FunctionPointerType fnPtrA && b is FunctionPointerType fnPtrB
&& fnPtrA.CallingConvention == fnPtrB.CallingConvention
&& fnPtrA.CustomCallingConventions.SequenceEqual(fnPtrB.CustomCallingConventions)
&& fnPtrA.ReturnIsRefReadOnly == fnPtrB.ReturnIsRefReadOnly
&& fnPtrA.ParameterTypes.Length == fnPtrB.ParameterTypes.Length
&& fnPtrA.ParameterReferenceKinds.SequenceEqual(fnPtrB.ParameterReferenceKinds))
{
var mergedReturn = MergeSimilarTypes(
fnPtrA.ReturnType, fnPtrB.ReturnType,
variance.Combine(VarianceModifier.Covariant));
if (mergedReturn == null)
return null;
var mergedParameters = ImmutableArray.CreateBuilder<IType>(fnPtrA.ParameterTypes.Length);
for (int i = 0; i < fnPtrA.ParameterTypes.Length; i++)
{
var mergedParameter = MergeSimilarTypes(
fnPtrA.ParameterTypes[i], fnPtrB.ParameterTypes[i],
variance.Combine(VarianceModifier.Contravariant));
if (mergedParameter == null)
return null;
mergedParameters.Add(mergedParameter);
}
return fnPtrA.WithSignature(mergedReturn, mergedParameters.MoveToImmutable());
}
if (a is ModifiedType modA && b is ModifiedType modB
&& modA.Kind == modB.Kind
&& modA.Modifier.Equals(modB.Modifier))
{
var mergedElem = MergeSimilarTypes(modA.ElementType, modB.ElementType, variance);
if (mergedElem == null)
return null;
return new ModifiedType(modA.Modifier, mergedElem, modA.Kind == TypeKind.ModReq);
}
if (a is UnknownType unknownTypeA && b is UnknownType unknownTypeB
&& unknownTypeA.FullTypeName == unknownTypeB.FullTypeName)
{
if (unknownTypeA.IsReferenceType == unknownTypeB.IsReferenceType)
return unknownTypeA;
else
return unknownTypeA.WithoutReferenceTypeKnowledge();
}
return null;
}

Loading…
Cancel
Save