protected function typeIsCompatible(
        RuntimeConfiguration $configuration,
        Type $documentedType,
        Type $nativeType,
        $depth = 0
    ) {
        $this->typeCheck->typeIsCompatible(func_get_args());

        // callable
        if (
            $this->useNativeCallable($configuration) &&
            $documentedType instanceof CallableType
        ) {
            return $nativeType instanceof CallableType;
        }

        // null
        if ($documentedType instanceof NullType) {
            if ($depth < 1) {
                return $nativeType instanceof MixedType;
            }

            return $nativeType instanceof NullType;
        }

        // traversable
        if ($documentedType instanceof TraversableType) {
            return
                !$documentedType->primaryType() instanceof ArrayType ||
                $nativeType instanceof TraversableType
            ;
        }

        // tuple
        if ($documentedType instanceof TupleType) {
            return $nativeType instanceof TraversableType;
        }

        // object of type
        if (
            $documentedType instanceof ObjectType &&
            null !== $documentedType->ofType()
        ) {
            if (!$nativeType instanceof ObjectType) {
                return false;
            }
            if ($nativeType->ofType()->isRuntimeEquivalentTo($documentedType->ofType())) {
                return true;
            }

            $documentedClassReflector = new ReflectionClass(
                $documentedType->ofType()->string()
            );

            return $documentedClassReflector->isSubclassOf(
                $nativeType->ofType()->string()
            );
        }

        // or type
        if ($documentedType instanceof OrType) {
            if ($nativeType instanceof OrType) {
                foreach ($documentedType->types() as $documentedSubType) {
                    $compatible = false;
                    foreach ($nativeType->types() as $nativeSubType) {
                        $compatible = $this->typeIsCompatible(
                            $configuration,
                            $documentedSubType,
                            $nativeSubType,
                            $depth + 1
                        );
                        if ($compatible) {
                            break;
                        }
                    }
                    if (!$compatible) {
                        return false;
                    }
                }

                return $compatible;
            }

            if (!$nativeType instanceof MixedType) {
                return false;
            }

            $hasArray = false;
            $hasCallable = false;
            $hasNull = false;
            $hasObjectOfType = false;
            $impossibleNatively = false;
            foreach ($documentedType->types() as $documentedSubType) {
                if (
                    $documentedSubType instanceof TraversableType &&
                    $documentedSubType->primaryType() instanceof ArrayType
                ) {
                    $hasArray = true;
                } elseif ($documentedSubType instanceof CallableType) {
                    $hasCallable = true;
                } elseif ($documentedSubType instanceof NullType) {
                    $hasNull = true;
                } elseif (
                    $documentedSubType instanceof ObjectType &&
                    null !== $documentedSubType->ofType()
                ) {
                    $hasObjectOfType = true;
                } else {
                    return true;
                }
            }

            return
                (!$this->useNativeCallable($configuration) && $hasCallable) ||
                ($hasArray && $hasCallable) ||
                ($hasArray && $hasObjectOfType) ||
                ($hasCallable && $hasObjectOfType)
            ;
        }

        // and type
        if ($documentedType instanceof AndType) {
            foreach ($documentedType->types() as $documentedSubType) {
                $compatible = $this->typeIsCompatible(
                    $configuration,
                    $documentedSubType,
                    $nativeType,
                    $depth + 1
                );
                if ($compatible) {
                    return true;
                }
            }

            return false;
        }

        return $nativeType instanceof MixedType;
    }
protected function typeIsCompatible(
        RuntimeConfiguration $configuration,
        Type $documentedType,
        Type $nativeType,
        $depth = 0
    ) {
        $this->typeCheck->typeIsCompatible(func_get_args());

        // callable
        if (
            $this->useNativeCallable($configuration) &&
            $documentedType instanceof CallableType
        ) {
            return $nativeType instanceof CallableType;
        }

        // null
        if ($documentedType instanceof NullType) {
            if ($depth < 1) {
                return $nativeType instanceof MixedType;
            }

            return $nativeType instanceof NullType;
        }

        // traversable
        if ($documentedType instanceof TraversableType) {
            return
                !$documentedType->primaryType() instanceof ArrayType ||
                $nativeType instanceof TraversableType
            ;
        }

        // tuple
        if ($documentedType instanceof TupleType) {
            return $nativeType instanceof TraversableType;
        }

        // object of type
        if (
            $documentedType instanceof ObjectType &&
            null !== $documentedType->ofType()
        ) {
            if (!$nativeType instanceof ObjectType) {
                return false;
            }
            if ($nativeType->ofType()->isRuntimeEquivalentTo($documentedType->ofType())) {
                return true;
            }

            $documentedClassReflector = new ReflectionClass(
                $documentedType->ofType()->string()
            );

            return $documentedClassReflector->isSubclassOf(
                $nativeType->ofType()->string()
            );
        }

        // or type
        if ($documentedType instanceof OrType) {
            if ($nativeType instanceof OrType) {
                foreach ($documentedType->types() as $documentedSubType) {
                    $compatible = false;
                    foreach ($nativeType->types() as $nativeSubType) {
                        $compatible = $this->typeIsCompatible(
                            $configuration,
                            $documentedSubType,
                            $nativeSubType,
                            $depth + 1
                        );
                        if ($compatible) {
                            break;
                        }
                    }
                    if (!$compatible) {
                        return false;
                    }
                }

                return $compatible;
            }

            if (!$nativeType instanceof MixedType) {
                return false;
            }

            $hasArray = false;
            $hasCallable = false;
            $hasNull = false;
            $hasObjectOfType = false;
            $impossibleNatively = false;
            foreach ($documentedType->types() as $documentedSubType) {
                if (
                    $documentedSubType instanceof TraversableType &&
                    $documentedSubType->primaryType() instanceof ArrayType
                ) {
                    $hasArray = true;
                } elseif ($documentedSubType instanceof CallableType) {
                    $hasCallable = true;
                } elseif ($documentedSubType instanceof NullType) {
                    $hasNull = true;
                } elseif (
                    $documentedSubType instanceof ObjectType &&
                    null !== $documentedSubType->ofType()
                ) {
                    $hasObjectOfType = true;
                } else {
                    return true;
                }
            }

            return
                (!$this->useNativeCallable($configuration) && $hasCallable) ||
                ($hasArray && $hasCallable) ||
                ($hasArray && $hasObjectOfType) ||
                ($hasCallable && $hasObjectOfType)
            ;
        }

        // and type
        if ($documentedType instanceof AndType) {
            foreach ($documentedType->types() as $documentedSubType) {
                $compatible = $this->typeIsCompatible(
                    $configuration,
                    $documentedSubType,
                    $nativeType,
                    $depth + 1
                );
                if ($compatible) {
                    return true;
                }
            }

            return false;
        }

        return $nativeType instanceof MixedType;
    }
@param RuntimeConfiguration $configuration
@param Type                 $documentedType
@param Type                 $nativeType
@param integer              $depth

@return boolean