src/Executor/ReferenceExecutor.php
private function defaultTypeResolver($value, $context, ResolveInfo $info, AbstractType $abstractType)
    {
        // First, look for `__typename`.
        if ($value !== null &&
            (is_array($value) || $value instanceof ArrayAccess) &&
            isset($value['__typename']) &&
            is_string($value['__typename'])
        ) {
            return $value['__typename'];
        }
        if ($abstractType instanceof InterfaceType && $info->schema->getConfig()->typeLoader) {
            Warning::warnOnce(
                sprintf(
                    'GraphQL Interface Type `%s` returned `null` from its `resolveType` function ' .
                    'for value: %s. Switching to slow resolution method using `isTypeOf` ' .
                    'of all possible implementations. It requires full schema scan and degrades query performance significantly. ' .
                    ' Make sure your `resolveType` always returns valid implementation or throws.',
                    $abstractType->name,
                    Utils::printSafe($value)
                ),
                Warning::WARNING_FULL_SCHEMA_SCAN
            );
        }
        // Otherwise, test each possible type.
        $possibleTypes           = $info->schema->getPossibleTypes($abstractType);
        $promisedIsTypeOfResults = [];
        foreach ($possibleTypes as $index => $type) {
            $isTypeOfResult = $type->isTypeOf($value, $context, $info);
            if ($isTypeOfResult === null) {
                continue;
            }
            $promise = $this->getPromise($isTypeOfResult);
            if ($promise) {
                $promisedIsTypeOfResults[$index] = $promise;
            } elseif ($isTypeOfResult) {
                return $type;
            }
        }
        if (! empty($promisedIsTypeOfResults)) {
            return $this->exeContext->promises->all($promisedIsTypeOfResults)
                ->then(static function ($isTypeOfResults) use ($possibleTypes) {
                    foreach ($isTypeOfResults as $index => $result) {
                        if ($result) {
                            return $possibleTypes[$index];
                        }
                    }

                    return null;
                });
        }

        return null;
    }
private function defaultTypeResolver($value, $context, ResolveInfo $info, AbstractType $abstractType)
    {
        // First, look for `__typename`.
        if ($value !== null &&
            (is_array($value) || $value instanceof ArrayAccess) &&
            isset($value['__typename']) &&
            is_string($value['__typename'])
        ) {
            return $value['__typename'];
        }
        if ($abstractType instanceof InterfaceType && $info->schema->getConfig()->typeLoader) {
            Warning::warnOnce(
                sprintf(
                    'GraphQL Interface Type `%s` returned `null` from its `resolveType` function ' .
                    'for value: %s. Switching to slow resolution method using `isTypeOf` ' .
                    'of all possible implementations. It requires full schema scan and degrades query performance significantly. ' .
                    ' Make sure your `resolveType` always returns valid implementation or throws.',
                    $abstractType->name,
                    Utils::printSafe($value)
                ),
                Warning::WARNING_FULL_SCHEMA_SCAN
            );
        }
        // Otherwise, test each possible type.
        $possibleTypes           = $info->schema->getPossibleTypes($abstractType);
        $promisedIsTypeOfResults = [];
        foreach ($possibleTypes as $index => $type) {
            $isTypeOfResult = $type->isTypeOf($value, $context, $info);
            if ($isTypeOfResult === null) {
                continue;
            }
            $promise = $this->getPromise($isTypeOfResult);
            if ($promise) {
                $promisedIsTypeOfResults[$index] = $promise;
            } elseif ($isTypeOfResult) {
                return $type;
            }
        }
        if (! empty($promisedIsTypeOfResults)) {
            return $this->exeContext->promises->all($promisedIsTypeOfResults)
                ->then(static function ($isTypeOfResults) use ($possibleTypes) {
                    foreach ($isTypeOfResults as $index => $result) {
                        if ($result) {
                            return $possibleTypes[$index];
                        }
                    }

                    return null;
                });
        }

        return null;
    }
If a resolveType function is not given, then a default resolve behavior is
used which attempts two strategies:

First, See if the provided value has a `__typename` field defined, if so, use
that value as name of the resolved type.

Otherwise, test each possible type for the abstract type by calling
isTypeOf for the object being coerced, returning the first type that matches.

@param mixed|null $value
@param mixed|null $context

@return ObjectType|Promise|null