protected static function coerceValueAST(TypeInterface $type, $ast, $variables = NULL)
    {
        if ($type instanceof NonNullModifier) {
            // Note: we're not checking that the result of coerceValueAST is non-null.
            // We're assuming that this query has been validated and the value used
            // here is of the correct type.
            return self::coerceValueAST($type->getWrappedType(), $ast, $variables);
        }

        if (!$ast) {
            return NULL;
        }

        if ($ast::KIND === Node::KIND_VARIABLE) {
            $variableName = $ast->get('name')->get('value');

            if (!isset($variables, $variables[$variableName])) {
                return NULL;
            }

            // Note: we're not doing any checking that this variable is correct. We're
            // assuming that this query has been validated and the variable usage here
            // is of the correct type.
            return $variables[$variableName];
        }

        if ($type instanceof ListModifier) {
            $itemType = $type->getWrappedType();

            if ($ast::KIND === Node::KIND_ARRAY_VALUE) {
                $tmp = [];
                foreach ($ast->get('values') as $itemAST) {
                    $tmp[] = self::coerceValueAST($itemType, $itemAST, $variables);
                }

                return $tmp;
            } else {
                return [self::coerceValueAST($itemType, $ast, $variables)];
            }
        }

        if ($type instanceof InputObjectType) {
            $fields = $type->getFields();

            if ($ast::KIND !== Node::KIND_OBJECT_VALUE) {
                return NULL;
            }

            $asts = array_reduce($ast->get('fields'), function ($carry, $field) {
                $carry[$field->get('name')->get('value')] = $field;
                return $carry;
            }, []);

            $object = [];
            foreach ($fields as $name => $item) {
                $field = $asts[$name];
                $fieldValue = self::coerceValueAST($item->getType(), $field ? $field->get('value') : NULL, $variables);
                $object[$name] = $fieldValue === NULL ? $item->getDefaultValue() : $fieldValue;
            }

            return $object;
        }

        if ($type instanceof ScalarType || $type instanceof EnumType) {
            $coerced = $type->coerceLiteral($ast);

            if (isset($coerced)) {
                return $coerced;
            }
        }

        return NULL;
    }