TranslatedExpression HandleDelegateConstruction(CallInstruction inst) { ILInstruction func = inst.Arguments[1]; IMethod method; switch (func.OpCode) { case OpCode.LdFtn: method = ((LdFtn)func).Method; break; case OpCode.LdVirtFtn: method = ((LdVirtFtn)func).Method; break; default: throw new ArgumentException($"Unknown instruction type: {func.OpCode}"); } var invokeMethod = inst.Method.DeclaringType.GetDelegateInvokeMethod(); TranslatedExpression target; IType targetType; if (method.IsExtensionMethod && invokeMethod != null && method.Parameters.Count - 1 == invokeMethod.Parameters.Count) { target = expressionBuilder.Translate(inst.Arguments[0]); targetType = method.Parameters[0].Type; } else { target = expressionBuilder.TranslateTarget(method, inst.Arguments[0], func.OpCode == OpCode.LdFtn); targetType = method.DeclaringType; } var lookup = new MemberLookup(resolver.CurrentTypeDefinition, resolver.CurrentTypeDefinition.ParentAssembly); var or = new OverloadResolution(resolver.Compilation, method.Parameters.SelectArray(p => new TypeResolveResult(p.Type))); var result = lookup.Lookup(target.ResolveResult, method.Name, method.TypeArguments, false); bool needsCast = true; if (result is MethodGroupResolveResult mgrr) { or.AddMethodLists(mgrr.MethodsGroupedByDeclaringType.ToArray()); var expectedTargetDetails = new ExpectedTargetDetails { CallOpCode = inst.OpCode }; needsCast = (or.BestCandidateErrors != OverloadResolutionErrors.None || !IsAppropriateCallTarget(expectedTargetDetails, method, or.BestCandidate)); } if (needsCast) { target = target.ConvertTo(targetType, expressionBuilder); result = lookup.Lookup(target.ResolveResult, method.Name, method.TypeArguments, false); } var mre = new MemberReferenceExpression(target, method.Name); mre.TypeArguments.AddRange(method.TypeArguments.Select(expressionBuilder.ConvertType)); mre.WithRR(result); var oce = new ObjectCreateExpression(expressionBuilder.ConvertType(inst.Method.DeclaringType), mre) .WithILInstruction(inst) .WithRR(new ConversionResolveResult( inst.Method.DeclaringType, new MemberResolveResult(target.ResolveResult, method), Conversion.MethodGroupConversion(method, func.OpCode == OpCode.LdVirtFtn, false))); return(oce); }
TranslatedExpression HandleDelegateConstruction(CallInstruction inst) { ILInstruction func = inst.Arguments[1]; IMethod method; switch (func.OpCode) { case OpCode.LdFtn: method = ((LdFtn)func).Method; break; case OpCode.LdVirtFtn: method = ((LdVirtFtn)func).Method; break; default: throw new ArgumentException($"Unknown instruction type: {func.OpCode}"); } var invokeMethod = inst.Method.DeclaringType.GetDelegateInvokeMethod(); TranslatedExpression target; IType targetType; bool requireTarget; if (method.IsExtensionMethod && invokeMethod != null && method.Parameters.Count - 1 == invokeMethod.Parameters.Count) { targetType = method.Parameters[0].Type; target = expressionBuilder.Translate(inst.Arguments[0], targetType); target = ExpressionBuilder.UnwrapBoxingConversion(target); requireTarget = true; } else { targetType = method.DeclaringType; target = expressionBuilder.TranslateTarget(method, inst.Arguments[0], func.OpCode == OpCode.LdFtn); target = ExpressionBuilder.UnwrapBoxingConversion(target); requireTarget = expressionBuilder.HidesVariableWithName(method.Name) || (method.IsStatic ? !expressionBuilder.IsCurrentOrContainingType(method.DeclaringTypeDefinition) : !(target.Expression is ThisReferenceExpression)); } var expectedTargetDetails = new ExpectedTargetDetails { CallOpCode = inst.OpCode }; bool needsCast = false; ResolveResult result = null; var or = new OverloadResolution(resolver.Compilation, method.Parameters.SelectArray(p => new TypeResolveResult(p.Type))); if (!requireTarget) { result = resolver.ResolveSimpleName(method.Name, method.TypeArguments, isInvocationTarget: false); if (result is MethodGroupResolveResult mgrr) { or.AddMethodLists(mgrr.MethodsGroupedByDeclaringType.ToArray()); requireTarget = (or.BestCandidateErrors != OverloadResolutionErrors.None || !IsAppropriateCallTarget(expectedTargetDetails, method, or.BestCandidate)); } else { requireTarget = true; } } MemberLookup lookup = null; if (requireTarget) { lookup = new MemberLookup(resolver.CurrentTypeDefinition, resolver.CurrentTypeDefinition.ParentAssembly); var rr = lookup.Lookup(target.ResolveResult, method.Name, method.TypeArguments, false); needsCast = true; result = rr; if (rr is MethodGroupResolveResult mgrr) { or.AddMethodLists(mgrr.MethodsGroupedByDeclaringType.ToArray()); needsCast = (or.BestCandidateErrors != OverloadResolutionErrors.None || !IsAppropriateCallTarget(expectedTargetDetails, method, or.BestCandidate)); } } if (needsCast) { Debug.Assert(requireTarget); target = target.ConvertTo(targetType, expressionBuilder); result = lookup.Lookup(target.ResolveResult, method.Name, method.TypeArguments, false); } Expression targetExpression; if (requireTarget) { var mre = new MemberReferenceExpression(target, method.Name); mre.TypeArguments.AddRange(method.TypeArguments.Select(expressionBuilder.ConvertType)); mre.WithRR(result); targetExpression = mre; } else { var ide = new IdentifierExpression(method.Name) .WithRR(result); targetExpression = ide; } var oce = new ObjectCreateExpression(expressionBuilder.ConvertType(inst.Method.DeclaringType), targetExpression) .WithILInstruction(inst) .WithRR(new ConversionResolveResult( inst.Method.DeclaringType, new MemberResolveResult(target.ResolveResult, method), Conversion.MethodGroupConversion(method, func.OpCode == OpCode.LdVirtFtn, false))); return(oce); }