Browse Source

Add one more test for generics to OverloadResolution + Fix

pull/850/head
Siegfried Pammer 8 years ago
parent
commit
f844ac1b09
  1. 19
      ICSharpCode.Decompiler.Tests/TestCases/Correctness/OverloadResolution.cs
  2. 76
      ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs

19
ICSharpCode.Decompiler.Tests/TestCases/Correctness/OverloadResolution.cs

@ -33,6 +33,7 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Correctness
TestIssue180(); TestIssue180();
TestExtensionMethod(); TestExtensionMethod();
TestParamsMethod(); TestParamsMethod();
Generics();
} }
#region params with nulls #region params with nulls
@ -132,5 +133,23 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Correctness
Console.WriteLine("ExtensionMethod(obj)"); Console.WriteLine("ExtensionMethod(obj)");
} }
#endregion #endregion
#region Generics
static void Generics()
{
GenericsTest<int>(null);
GenericsTest<long>((object)null);
}
static void GenericsTest<T>(string x) where T : struct
{
Console.WriteLine("GenericsTest<" + typeof(T).Name + ">(string: " + x + ");");
}
static void GenericsTest<T>(object x) where T : struct
{
Console.WriteLine("GenericsTest<" + typeof(T).Name + ">(object: " + x + ");");
}
#endregion
} }
} }

76
ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs

@ -1136,64 +1136,54 @@ namespace ICSharpCode.Decompiler.CSharp
if (method.IsAccessor && (method.AccessorOwner.SymbolKind == SymbolKind.Indexer || method.Parameters.Count == allowedParamCount)) { if (method.IsAccessor && (method.AccessorOwner.SymbolKind == SymbolKind.Indexer || method.Parameters.Count == allowedParamCount)) {
expr = HandleAccessorCall(inst, target, method, arguments.ToList()); expr = HandleAccessorCall(inst, target, method, arguments.ToList());
} else { } else {
var lookup = new MemberLookup(resolver.CurrentTypeDefinition, resolver.CurrentTypeDefinition.ParentAssembly);
var result = lookup.Lookup(target.ResolveResult, method.Name, EmptyList<IType>.Instance, true) as MethodGroupResolveResult;
bool requireTypeArguments = false; bool requireTypeArguments = false;
bool targetCasted = false;
bool argumentsCasted = false;
IType[] typeArguments = Array.Empty<IType>(); IType[] typeArguments = Array.Empty<IType>();
// 1. OverloadResolutionErrors IsUnambiguousCall()
// Try overload resolution and check if the correct call is selected with the given casts. {
if (result == null) { var lookup = new MemberLookup(resolver.CurrentTypeDefinition, resolver.CurrentTypeDefinition.ParentAssembly);
for (int i = 0; i < arguments.Length; i++) { var result = lookup.Lookup(target.ResolveResult, method.Name, EmptyList<IType>.Instance, true) as MethodGroupResolveResult;
if (!method.Parameters[i].Type.ContainsAnonymousType()) if (result == null)
arguments[i] = arguments[i].ConvertTo(method.Parameters[i].Type, this); return OverloadResolutionErrors.AmbiguousMatch;
} var or = new OverloadResolution(resolver.Compilation, arguments.SelectArray(a => a.ResolveResult), typeArguments: typeArguments);
} else {
var or = new OverloadResolution(resolver.Compilation, arguments.Select(a => a.ResolveResult).ToArray());
or.AddMethodLists(result.MethodsGroupedByDeclaringType.ToArray()); or.AddMethodLists(result.MethodsGroupedByDeclaringType.ToArray());
switch (or.BestCandidateErrors) { if (or.BestCandidateErrors != OverloadResolutionErrors.None)
return or.BestCandidateErrors;
if (!IsAppropriateCallTarget(method, or.GetBestCandidateWithSubstitutedTypeArguments(), inst.OpCode == OpCode.CallVirt))
return OverloadResolutionErrors.AmbiguousMatch;
return OverloadResolutionErrors.None;
}
OverloadResolutionErrors errors;
while ((errors = IsUnambiguousCall()) != OverloadResolutionErrors.None) {
switch (errors) {
case OverloadResolutionErrors.TypeInferenceFailed: case OverloadResolutionErrors.TypeInferenceFailed:
case OverloadResolutionErrors.WrongNumberOfTypeArguments: case OverloadResolutionErrors.WrongNumberOfTypeArguments:
if (requireTypeArguments) goto default;
requireTypeArguments = true; requireTypeArguments = true;
typeArguments = method.TypeArguments.ToArray(); typeArguments = method.TypeArguments.ToArray();
break; continue;
default: default:
if (or.BestCandidateErrors != OverloadResolutionErrors.None || !IsAppropriateCallTarget(method, or.GetBestCandidateWithSubstitutedTypeArguments(), inst.OpCode == OpCode.CallVirt)) { if (!argumentsCasted) {
argumentsCasted = true;
for (int i = 0; i < arguments.Length; i++) { for (int i = 0; i < arguments.Length; i++) {
if (!method.Parameters[i].Type.ContainsAnonymousType()) if (!method.Parameters[i].Type.ContainsAnonymousType())
arguments[i] = arguments[i].ConvertTo(method.Parameters[i].Type, this); arguments[i] = arguments[i].ConvertTo(method.Parameters[i].Type, this);
} }
} else if (!targetCasted) {
targetCasted = true;
target = target.ConvertTo(method.DeclaringType, this);
} else if (!requireTypeArguments) {
requireTypeArguments = true;
typeArguments = method.TypeArguments.ToArray();
} else {
break;
} }
break; continue;
} }
break;
}
result = lookup.Lookup(target.ResolveResult, method.Name, typeArguments, true) as MethodGroupResolveResult;
// 2.
// Try overload resolution again and if anything goes wrong,
// fix the call by explicitly casting to method.DeclaringType.
if (result == null) {
target = target.ConvertTo(method.DeclaringType, this);
} else {
var or = new OverloadResolution(resolver.Compilation, arguments.Select(a => a.ResolveResult).ToArray(), typeArguments: typeArguments);
or.AddMethodLists(result.MethodsGroupedByDeclaringType.ToArray());
if (or.BestCandidateErrors != OverloadResolutionErrors.None || !IsAppropriateCallTarget(method, or.GetBestCandidateWithSubstitutedTypeArguments(), inst.OpCode == OpCode.CallVirt))
target = target.ConvertTo(method.DeclaringType, this);
}
result = lookup.Lookup(target.ResolveResult, method.Name, typeArguments, true) as MethodGroupResolveResult;
// 3.
// Try overload resolution again and if anything goes wrong,
// fix the call by explicitly stating the type arguments.
if (result == null) {
requireTypeArguments = true;
} else {
var or = new OverloadResolution(resolver.Compilation, arguments.Select(a => a.ResolveResult).ToArray(), typeArguments: typeArguments);
or.AddMethodLists(result.MethodsGroupedByDeclaringType.ToArray());
if (or.BestCandidateErrors != OverloadResolutionErrors.None || !IsAppropriateCallTarget(method, or.GetBestCandidateWithSubstitutedTypeArguments(), inst.OpCode == OpCode.CallVirt))
requireTypeArguments = true;
} }
Expression targetExpr = target.Expression; Expression targetExpr = target.Expression;

Loading…
Cancel
Save