Browse Source

#918: CallBuilder: Add fix-up logic for lambda expressions with anonymous parameter types to ensure the correct overload is called after removing the 'implicit' call to 'new Nullable<T>(T value)'.

pull/946/head
Siegfried Pammer 8 years ago
parent
commit
818a90af95
  1. 38
      ICSharpCode.Decompiler/CSharp/CallBuilder.cs
  2. 2
      ICSharpCode.Decompiler/CSharp/Resolver/LambdaResolveResult.cs

38
ICSharpCode.Decompiler/CSharp/CallBuilder.cs

@ -143,12 +143,18 @@ namespace ICSharpCode.Decompiler.CSharp
.WithILInstruction(inst) .WithILInstruction(inst)
.WithRR(rr); .WithRR(rr);
} else { } else {
if (IsUnambiguousCall(inst, target, method, Array.Empty<IType>(), arguments) != OverloadResolutionErrors.None) { if (IsUnambiguousCall(inst, target, method, Array.Empty<IType>(), arguments) != OverloadResolutionErrors.None) {
for (int i = 0; i < arguments.Count; i++) { for (int i = 0; i < arguments.Count; i++) {
if (!settings.AnonymousTypes || !expectedParameters[i].Type.ContainsAnonymousType()) if (settings.AnonymousTypes && expectedParameters[i].Type.ContainsAnonymousType()) {
if (arguments[i].Expression is LambdaExpression lambda) {
ModifyReturnTypeOfLambda(lambda);
}
} else {
arguments[i] = arguments[i].ConvertTo(expectedParameters[i].Type, expressionBuilder); arguments[i] = arguments[i].ConvertTo(expectedParameters[i].Type, expressionBuilder);
} }
} }
}
return new ObjectCreateExpression(expressionBuilder.ConvertType(inst.Method.DeclaringType), arguments.SelectArray(arg => arg.Expression)) return new ObjectCreateExpression(expressionBuilder.ConvertType(inst.Method.DeclaringType), arguments.SelectArray(arg => arg.Expression))
.WithILInstruction(inst).WithRR(rr); .WithILInstruction(inst).WithRR(rr);
} }
@ -180,9 +186,14 @@ namespace ICSharpCode.Decompiler.CSharp
if (!argumentsCasted) { if (!argumentsCasted) {
argumentsCasted = true; argumentsCasted = true;
for (int i = 0; i < arguments.Count; i++) { for (int i = 0; i < arguments.Count; i++) {
if (!settings.AnonymousTypes || !expectedParameters[i].Type.ContainsAnonymousType()) if (settings.AnonymousTypes && expectedParameters[i].Type.ContainsAnonymousType()) {
if (arguments[i].Expression is LambdaExpression lambda) {
ModifyReturnTypeOfLambda(lambda);
}
} else {
arguments[i] = arguments[i].ConvertTo(expectedParameters[i].Type, expressionBuilder); arguments[i] = arguments[i].ConvertTo(expectedParameters[i].Type, expressionBuilder);
} }
}
} else if (!targetCasted) { } else if (!targetCasted) {
targetCasted = true; targetCasted = true;
target = target.ConvertTo(method.DeclaringType, expressionBuilder); target = target.ConvertTo(method.DeclaringType, expressionBuilder);
@ -213,6 +224,29 @@ namespace ICSharpCode.Decompiler.CSharp
} }
} }
private void ModifyReturnTypeOfLambda(LambdaExpression lambda)
{
var resolveResult = (DecompiledLambdaResolveResult)lambda.GetResolveResult();
if (lambda.Body is Expression exprBody)
lambda.Body = new TranslatedExpression(exprBody.Detach()).ConvertTo(resolveResult.ReturnType, expressionBuilder);
else
ModifyReturnStatementInsideLambda(resolveResult.ReturnType, lambda);
resolveResult.InferredReturnType = resolveResult.ReturnType;
}
private void ModifyReturnStatementInsideLambda(IType returnType, AstNode parent)
{
foreach (var child in parent.Children) {
if (child is LambdaExpression || child is AnonymousMethodExpression)
continue;
if (child is ReturnStatement ret) {
ret.Expression = new TranslatedExpression(ret.Expression.Detach()).ConvertTo(returnType, expressionBuilder);
continue;
}
ModifyReturnStatementInsideLambda(returnType, child);
}
}
private bool IsDelegateEqualityComparison(IMethod method, IList<TranslatedExpression> arguments) private bool IsDelegateEqualityComparison(IMethod method, IList<TranslatedExpression> arguments)
{ {
// Comparison on a delegate type is a C# builtin operator // Comparison on a delegate type is a C# builtin operator

2
ICSharpCode.Decompiler/CSharp/Resolver/LambdaResolveResult.cs

@ -109,7 +109,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
/// Can differ from <c>ReturnType</c> if a return statement /// Can differ from <c>ReturnType</c> if a return statement
/// performs an implicit conversion. /// performs an implicit conversion.
/// </summary> /// </summary>
public readonly IType InferredReturnType; public IType InferredReturnType;
public DecompiledLambdaResolveResult(IL.ILFunction function, public DecompiledLambdaResolveResult(IL.ILFunction function,
IType delegateType, IType delegateType,

Loading…
Cancel
Save