Ejemplo n.º 1
0
        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);
        }
Ejemplo n.º 2
0
        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);
        }