/// <summary>
        /// Resolves an invocation.
        /// </summary>
        /// <param name="target">The target of the invocation. Usually a MethodGroupResolveResult.</param>
        /// <param name="arguments">
        /// Arguments passed to the method.
        /// The resolver may mutate this array to wrap elements in <see cref="ConversionResolveResult"/>s!
        /// </param>
        /// <param name="argumentNames">
        /// The argument names. Pass the null string for positional arguments.
        /// </param>
        /// <returns>InvocationResolveResult or UnknownMethodResolveResult</returns>
        public ResolveResult ResolveInvocation(ResolveResult target, ResolveResult[] arguments, string[] argumentNames = null)
        {
            // C# 4.0 spec: §7.6.5

            if (target.Type.Kind == TypeKind.Dynamic) {
                return new DynamicInvocationResolveResult(target, DynamicInvocationType.Invocation, AddArgumentNamesIfNecessary(arguments, argumentNames));
            }

            MethodGroupResolveResult mgrr = target as MethodGroupResolveResult;
            if (mgrr != null) {
                if (arguments.Any(a => a.Type.Kind == TypeKind.Dynamic)) {
                    // If we have dynamic arguments, we need to represent the invocation as a dynamic invocation if there is more than one applicable method.
                    var or2 = CreateOverloadResolution(arguments, argumentNames, mgrr.TypeArguments.ToArray());
                    var applicableMethods = mgrr.MethodsGroupedByDeclaringType.SelectMany(m => m, (x, m) => new { x.DeclaringType, Method = m }).Where(x => OverloadResolution.IsApplicable(or2.AddCandidate(x.Method))).ToList();

                    if (applicableMethods.Count > 1) {
                        ResolveResult actualTarget;
                        if (applicableMethods.All(x => x.Method.IsStatic) && !(mgrr.TargetResult is TypeResolveResult))
                            actualTarget = new TypeResolveResult(mgrr.TargetType);
                        else
                            actualTarget = mgrr.TargetResult;

                        var l = new List<MethodListWithDeclaringType>();
                        foreach (var m in applicableMethods) {
                            if (l.Count == 0 || l[l.Count - 1].DeclaringType != m.DeclaringType)
                                l.Add(new MethodListWithDeclaringType(m.DeclaringType));
                            l[l.Count - 1].Add(m.Method);
                        }
                        return new DynamicInvocationResolveResult(new MethodGroupResolveResult(actualTarget, mgrr.MethodName, l, mgrr.TypeArguments), DynamicInvocationType.Invocation, AddArgumentNamesIfNecessary(arguments, argumentNames));
                    }
                }

                OverloadResolution or = mgrr.PerformOverloadResolution(compilation, arguments, argumentNames, checkForOverflow: checkForOverflow, conversions: conversions);
                if (or.BestCandidate != null) {
                    if (or.BestCandidate.IsStatic && !or.IsExtensionMethodInvocation && !(mgrr.TargetResult is TypeResolveResult))
                        return or.CreateResolveResult(new TypeResolveResult(mgrr.TargetType));
                    else
                        return or.CreateResolveResult(mgrr.TargetResult);
                } else {
                    // No candidate found at all (not even an inapplicable one).
                    // This can happen with empty method groups (as sometimes used with extension methods)
                    return new UnknownMethodResolveResult(
                        mgrr.TargetType, mgrr.MethodName, mgrr.TypeArguments, CreateParameters(arguments, argumentNames));
                }
            }
            UnknownMemberResolveResult umrr = target as UnknownMemberResolveResult;
            if (umrr != null) {
                return new UnknownMethodResolveResult(umrr.TargetType, umrr.MemberName, umrr.TypeArguments, CreateParameters(arguments, argumentNames));
            }
            UnknownIdentifierResolveResult uirr = target as UnknownIdentifierResolveResult;
            if (uirr != null && CurrentTypeDefinition != null) {
                return new UnknownMethodResolveResult(CurrentTypeDefinition, uirr.Identifier, EmptyList<IType>.Instance, CreateParameters(arguments, argumentNames));
            }
            IMethod invokeMethod = target.Type.GetDelegateInvokeMethod();
            if (invokeMethod != null) {
                OverloadResolution or = CreateOverloadResolution(arguments, argumentNames);
                or.AddCandidate(invokeMethod);
                return new CSharpInvocationResolveResult(
                    target, invokeMethod, //invokeMethod.ReturnType.Resolve(context),
                    or.GetArgumentsWithConversionsAndNames(), or.BestCandidateErrors,
                    isExpandedForm: or.BestCandidateIsExpandedForm,
                    isDelegateInvocation: true,
                    argumentToParameterMap: or.GetArgumentToParameterMap());
            }
            return ErrorResult;
        }
        /// <summary>
        /// Resolves an object creation.
        /// </summary>
        /// <param name="type">Type of the object to create.</param>
        /// <param name="arguments">
        /// Arguments passed to the constructor.
        /// The resolver may mutate this array to wrap elements in <see cref="ConversionResolveResult"/>s!
        /// </param>
        /// <param name="argumentNames">
        /// The argument names. Pass the null string for positional arguments.
        /// </param>
        /// <param name="allowProtectedAccess">
        /// Whether to allow calling protected constructors.
        /// This should be false except when resolving constructor initializers.
        /// </param>
        /// <param name="initializerStatements">
        /// Statements for Objects/Collections initializer.
        /// <see cref="InvocationResolveResult.InitializerStatements"/>
        /// </param>
        /// <returns>InvocationResolveResult or ErrorResolveResult</returns>
        public ResolveResult ResolveObjectCreation(IType type, ResolveResult[] arguments, string[] argumentNames = null, bool allowProtectedAccess = false, IList<ResolveResult> initializerStatements = null)
        {
            if (type.Kind == TypeKind.Delegate && arguments.Length == 1) {
                ResolveResult input = arguments[0];
                IMethod invoke = input.Type.GetDelegateInvokeMethod();
                if (invoke != null) {
                    input = new MethodGroupResolveResult(
                        input, invoke.Name,
                        methods: new[] { new MethodListWithDeclaringType(invoke.DeclaringType) { invoke } },
                    typeArguments: EmptyList<IType>.Instance
                    );
                }
                return Convert(input, type);
            }
            OverloadResolution or = CreateOverloadResolution(arguments, argumentNames);
            MemberLookup lookup = CreateMemberLookup();
            var allApplicable = (arguments.Any(a => a.Type.Kind == TypeKind.Dynamic) ? new List<IMethod>() : null);
            foreach (IMethod ctor in type.GetConstructors()) {
                if (lookup.IsAccessible(ctor, allowProtectedAccess)) {
                    var orErrors = or.AddCandidate(ctor);
                    if (allApplicable != null && OverloadResolution.IsApplicable(orErrors))
                        allApplicable.Add(ctor);
                }
                else
                    or.AddCandidate(ctor, OverloadResolutionErrors.Inaccessible);
            }

            if (allApplicable != null && allApplicable.Count > 1) {
                // If we have dynamic arguments, we need to represent the invocation as a dynamic invocation if there is more than one applicable constructor.
                return new DynamicInvocationResolveResult(new MethodGroupResolveResult(null, allApplicable[0].Name, new[] { new MethodListWithDeclaringType(type, allApplicable) }, null), DynamicInvocationType.ObjectCreation, AddArgumentNamesIfNecessary(arguments, argumentNames), initializerStatements);
            }

            if (or.BestCandidate != null) {
                return or.CreateResolveResult(null, initializerStatements);
            } else {
                return new ErrorResolveResult(type);
            }
        }
        /// <summary>
        /// Resolves an indexer access.
        /// </summary>
        /// <param name="target">Target expression.</param>
        /// <param name="arguments">
        /// Arguments passed to the indexer.
        /// The resolver may mutate this array to wrap elements in <see cref="ConversionResolveResult"/>s!
        /// </param>
        /// <param name="argumentNames">
        /// The argument names. Pass the null string for positional arguments.
        /// </param>
        /// <returns>ArrayAccessResolveResult, InvocationResolveResult, or ErrorResolveResult</returns>
        public ResolveResult ResolveIndexer(ResolveResult target, ResolveResult[] arguments, string[] argumentNames = null)
        {
            switch (target.Type.Kind) {
            case TypeKind.Dynamic:
                return new DynamicInvocationResolveResult(target, DynamicInvocationType.Indexing, AddArgumentNamesIfNecessary(arguments, argumentNames));

            case TypeKind.Array:
            case TypeKind.Pointer:
                // §7.6.6.1 Array access / §18.5.3 Pointer element access
                AdjustArrayAccessArguments(arguments);
                return new ArrayAccessResolveResult(((TypeWithElementType)target.Type).ElementType, target, arguments);
            }

            // §7.6.6.2 Indexer access

            MemberLookup lookup = CreateMemberLookup();
            var indexers = lookup.LookupIndexers(target.Type);

            if (arguments.Any(a => a.Type.Kind == TypeKind.Dynamic)) {
                // If we have dynamic arguments, we need to represent the invocation as a dynamic invocation if there is more than one applicable indexer.
                var or2 = CreateOverloadResolution(arguments, argumentNames, null);
                var applicableIndexers = indexers.SelectMany(x => x).Where(m => OverloadResolution.IsApplicable(or2.AddCandidate(m))).ToList();

                if (applicableIndexers.Count > 1) {
                    return new DynamicInvocationResolveResult(target, DynamicInvocationType.Indexing, AddArgumentNamesIfNecessary(arguments, argumentNames));
                }
            }

            OverloadResolution or = CreateOverloadResolution(arguments, argumentNames);
            or.AddMethodLists(indexers);
            if (or.BestCandidate != null) {
                return or.CreateResolveResult(target);
            } else {
                return ErrorResult;
            }
        }