public function handle(FieldValue $fieldValue): array
    {
        $fieldDefinitionNode = $fieldValue->getField();

        // Directives have the first priority for defining a resolver for a field
        if ($resolverDirective = $this->directiveFactory->createFieldResolver($fieldDefinitionNode)) {
            $this->fieldValue = $resolverDirective->resolveField($fieldValue);
        } else {
            $this->fieldValue = $fieldValue->setResolver(
                $fieldValue->getParentName() === 'Subscription'
                    ? $this->providesSubscriptionResolver->provideSubscriptionResolver($fieldValue)
                    : $this->providesResolver->provideResolver($fieldValue)
            );
        }

        $resolverWithMiddleware = $this->pipeline
            ->send($this->fieldValue)
            ->through(
                $this->directiveFactory->createFieldMiddleware($fieldDefinitionNode)
            )
            ->via('handleField')
            ->then(
                function (FieldValue $fieldValue): FieldValue {
                    return $fieldValue;
                }
            )
            ->getResolver();

        $argumentValues = $this->getArgumentValues();

        $this->fieldValue->setResolver(
            function () use ($argumentValues, $resolverWithMiddleware) {
                $this->setResolverArguments(...func_get_args());

                $this->validationErrorBuffer = (new ErrorBuffer)->setErrorType('validation');
                $this->builder = new Builder;

                $this->queryFilter = QueryFilter::getInstance($this->fieldValue);

                $argumentValues->each(
                    function (ArgumentValue $argumentValue): void {
                        $this->handleArgDirectivesRecursively(
                            $argumentValue->getType(),
                            $argumentValue->getAstNode(),
                            [$argumentValue->getName()]
                        );
                    }
                );

                $this->runArgDirectives();

                // Apply the argument spreadings after we are finished with all
                // the other argument handling
                foreach ($this->spreadPaths as $argumentPath) {
                    $inputValues = $this->argValue($argumentPath);
                    $this->unsetArgValue($argumentPath);

                    array_pop($argumentPath);

                    foreach ($inputValues as $key => $value) {
                        $this->setArgValue(
                            array_merge($argumentPath, [$key]),
                            $value
                        );
                    }
                }

                $this->builder->setQueryFilter(
                    $this->queryFilter
                );

                // The final resolver can access the builder through the ResolveInfo
                $this->resolveInfo->builder = $this->builder;

                return $resolverWithMiddleware($this->root, $this->args, $this->context, $this->resolveInfo);
            }
        );

        // To see what is allowed here, look at the validation rules in
        // GraphQL\Type\Definition\FieldDefinition::getDefinition()
        return [
            'name' => $fieldDefinitionNode->name->value,
            'type' => $this->fieldValue->getReturnType(),
            'args' => $this->getInputValueDefinitions($argumentValues),
            'resolve' => $this->fieldValue->getResolver(),
            'description' => data_get($fieldDefinitionNode->description, 'value'),
            'complexity' => $this->fieldValue->getComplexity(),
            'deprecationReason' => $this->fieldValue->getDeprecationReason(),
        ];
    }