summaryrefslogtreecommitdiff
path: root/vendor/sebastian/type/src
diff options
context:
space:
mode:
authorAndrew Dolgov <[email protected]>2022-03-22 12:24:31 +0300
committerAndrew Dolgov <[email protected]>2022-03-22 12:24:31 +0300
commit1c4f7ab3b838b23afb2ee4dab14acbf75956e952 (patch)
tree0a19274107d717efe92d2c0376cd3105fead5a11 /vendor/sebastian/type/src
parent711662948768492e8d05b778a7d80eacaec368d2 (diff)
* add phpunit as a dev dependency
* add some basic tests for UrlHelper::rewrite_relative() * fix UrlHelper::rewrite_relative() to work better on non-absolute relative URL paths
Diffstat (limited to 'vendor/sebastian/type/src')
-rw-r--r--vendor/sebastian/type/src/CallableType.php197
-rw-r--r--vendor/sebastian/type/src/FalseType.php46
-rw-r--r--vendor/sebastian/type/src/GenericObjectType.php46
-rw-r--r--vendor/sebastian/type/src/IterableType.php76
-rw-r--r--vendor/sebastian/type/src/MixedType.php33
-rw-r--r--vendor/sebastian/type/src/NullType.php43
-rw-r--r--vendor/sebastian/type/src/ObjectType.php66
-rw-r--r--vendor/sebastian/type/src/ReflectionMapper.php123
-rw-r--r--vendor/sebastian/type/src/SimpleType.php92
-rw-r--r--vendor/sebastian/type/src/StaticType.php60
-rw-r--r--vendor/sebastian/type/src/Type.php101
-rw-r--r--vendor/sebastian/type/src/TypeName.php113
-rw-r--r--vendor/sebastian/type/src/UnionType.php115
-rw-r--r--vendor/sebastian/type/src/UnknownType.php43
-rw-r--r--vendor/sebastian/type/src/VoidType.php28
-rw-r--r--vendor/sebastian/type/src/exception/Exception.php16
-rw-r--r--vendor/sebastian/type/src/exception/LogicException.php14
-rw-r--r--vendor/sebastian/type/src/exception/RuntimeException.php14
18 files changed, 1226 insertions, 0 deletions
diff --git a/vendor/sebastian/type/src/CallableType.php b/vendor/sebastian/type/src/CallableType.php
new file mode 100644
index 000000000..026762eaf
--- /dev/null
+++ b/vendor/sebastian/type/src/CallableType.php
@@ -0,0 +1,197 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of sebastian/type.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace SebastianBergmann\Type;
+
+use function assert;
+use function class_exists;
+use function count;
+use function explode;
+use function function_exists;
+use function is_array;
+use function is_object;
+use function is_string;
+use function strpos;
+use Closure;
+use ReflectionClass;
+use ReflectionException;
+use ReflectionObject;
+
+final class CallableType extends Type
+{
+ /**
+ * @var bool
+ */
+ private $allowsNull;
+
+ public function __construct(bool $nullable)
+ {
+ $this->allowsNull = $nullable;
+ }
+
+ /**
+ * @throws RuntimeException
+ */
+ public function isAssignable(Type $other): bool
+ {
+ if ($this->allowsNull && $other instanceof NullType) {
+ return true;
+ }
+
+ if ($other instanceof self) {
+ return true;
+ }
+
+ if ($other instanceof ObjectType) {
+ if ($this->isClosure($other)) {
+ return true;
+ }
+
+ if ($this->hasInvokeMethod($other)) {
+ return true;
+ }
+ }
+
+ if ($other instanceof SimpleType) {
+ if ($this->isFunction($other)) {
+ return true;
+ }
+
+ if ($this->isClassCallback($other)) {
+ return true;
+ }
+
+ if ($this->isObjectCallback($other)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ public function name(): string
+ {
+ return 'callable';
+ }
+
+ public function allowsNull(): bool
+ {
+ return $this->allowsNull;
+ }
+
+ private function isClosure(ObjectType $type): bool
+ {
+ return !$type->className()->isNamespaced() && $type->className()->simpleName() === Closure::class;
+ }
+
+ /**
+ * @throws RuntimeException
+ */
+ private function hasInvokeMethod(ObjectType $type): bool
+ {
+ $className = $type->className()->qualifiedName();
+ assert(class_exists($className));
+
+ try {
+ $class = new ReflectionClass($className);
+ // @codeCoverageIgnoreStart
+ } catch (ReflectionException $e) {
+ throw new RuntimeException(
+ $e->getMessage(),
+ (int) $e->getCode(),
+ $e
+ );
+ // @codeCoverageIgnoreEnd
+ }
+
+ if ($class->hasMethod('__invoke')) {
+ return true;
+ }
+
+ return false;
+ }
+
+ private function isFunction(SimpleType $type): bool
+ {
+ if (!is_string($type->value())) {
+ return false;
+ }
+
+ return function_exists($type->value());
+ }
+
+ private function isObjectCallback(SimpleType $type): bool
+ {
+ if (!is_array($type->value())) {
+ return false;
+ }
+
+ if (count($type->value()) !== 2) {
+ return false;
+ }
+
+ if (!is_object($type->value()[0]) || !is_string($type->value()[1])) {
+ return false;
+ }
+
+ [$object, $methodName] = $type->value();
+
+ return (new ReflectionObject($object))->hasMethod($methodName);
+ }
+
+ private function isClassCallback(SimpleType $type): bool
+ {
+ if (!is_string($type->value()) && !is_array($type->value())) {
+ return false;
+ }
+
+ if (is_string($type->value())) {
+ if (strpos($type->value(), '::') === false) {
+ return false;
+ }
+
+ [$className, $methodName] = explode('::', $type->value());
+ }
+
+ if (is_array($type->value())) {
+ if (count($type->value()) !== 2) {
+ return false;
+ }
+
+ if (!is_string($type->value()[0]) || !is_string($type->value()[1])) {
+ return false;
+ }
+
+ [$className, $methodName] = $type->value();
+ }
+
+ assert(isset($className) && is_string($className) && class_exists($className));
+ assert(isset($methodName) && is_string($methodName));
+
+ try {
+ $class = new ReflectionClass($className);
+
+ if ($class->hasMethod($methodName)) {
+ $method = $class->getMethod($methodName);
+
+ return $method->isPublic() && $method->isStatic();
+ }
+ // @codeCoverageIgnoreStart
+ } catch (ReflectionException $e) {
+ throw new RuntimeException(
+ $e->getMessage(),
+ (int) $e->getCode(),
+ $e
+ );
+ // @codeCoverageIgnoreEnd
+ }
+
+ return false;
+ }
+}
diff --git a/vendor/sebastian/type/src/FalseType.php b/vendor/sebastian/type/src/FalseType.php
new file mode 100644
index 000000000..425f363c0
--- /dev/null
+++ b/vendor/sebastian/type/src/FalseType.php
@@ -0,0 +1,46 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of sebastian/type.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace SebastianBergmann\Type;
+
+final class FalseType extends Type
+{
+ public function isAssignable(Type $other): bool
+ {
+ if ($other instanceof self) {
+ return true;
+ }
+
+ return $other instanceof SimpleType &&
+ $other->name() === 'bool' &&
+ $other->value() === false;
+ }
+
+ public function name(): string
+ {
+ return 'false';
+ }
+
+ public function allowsNull(): bool
+ {
+ return false;
+ }
+
+ /**
+ * @deprecated
+ *
+ * @codeCoverageIgnore
+ *
+ * @throws LogicException
+ */
+ public function getReturnTypeDeclaration(): string
+ {
+ throw new LogicException;
+ }
+}
diff --git a/vendor/sebastian/type/src/GenericObjectType.php b/vendor/sebastian/type/src/GenericObjectType.php
new file mode 100644
index 000000000..6871008bd
--- /dev/null
+++ b/vendor/sebastian/type/src/GenericObjectType.php
@@ -0,0 +1,46 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of sebastian/type.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace SebastianBergmann\Type;
+
+final class GenericObjectType extends Type
+{
+ /**
+ * @var bool
+ */
+ private $allowsNull;
+
+ public function __construct(bool $nullable)
+ {
+ $this->allowsNull = $nullable;
+ }
+
+ public function isAssignable(Type $other): bool
+ {
+ if ($this->allowsNull && $other instanceof NullType) {
+ return true;
+ }
+
+ if (!$other instanceof ObjectType) {
+ return false;
+ }
+
+ return true;
+ }
+
+ public function name(): string
+ {
+ return 'object';
+ }
+
+ public function allowsNull(): bool
+ {
+ return $this->allowsNull;
+ }
+}
diff --git a/vendor/sebastian/type/src/IterableType.php b/vendor/sebastian/type/src/IterableType.php
new file mode 100644
index 000000000..c5bc6627b
--- /dev/null
+++ b/vendor/sebastian/type/src/IterableType.php
@@ -0,0 +1,76 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of sebastian/type.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace SebastianBergmann\Type;
+
+use function assert;
+use function class_exists;
+use function is_iterable;
+use ReflectionClass;
+use ReflectionException;
+
+final class IterableType extends Type
+{
+ /**
+ * @var bool
+ */
+ private $allowsNull;
+
+ public function __construct(bool $nullable)
+ {
+ $this->allowsNull = $nullable;
+ }
+
+ /**
+ * @throws RuntimeException
+ */
+ public function isAssignable(Type $other): bool
+ {
+ if ($this->allowsNull && $other instanceof NullType) {
+ return true;
+ }
+
+ if ($other instanceof self) {
+ return true;
+ }
+
+ if ($other instanceof SimpleType) {
+ return is_iterable($other->value());
+ }
+
+ if ($other instanceof ObjectType) {
+ $className = $other->className()->qualifiedName();
+ assert(class_exists($className));
+
+ try {
+ return (new ReflectionClass($className))->isIterable();
+ // @codeCoverageIgnoreStart
+ } catch (ReflectionException $e) {
+ throw new RuntimeException(
+ $e->getMessage(),
+ (int) $e->getCode(),
+ $e
+ );
+ // @codeCoverageIgnoreEnd
+ }
+ }
+
+ return false;
+ }
+
+ public function name(): string
+ {
+ return 'iterable';
+ }
+
+ public function allowsNull(): bool
+ {
+ return $this->allowsNull;
+ }
+}
diff --git a/vendor/sebastian/type/src/MixedType.php b/vendor/sebastian/type/src/MixedType.php
new file mode 100644
index 000000000..7ad9191da
--- /dev/null
+++ b/vendor/sebastian/type/src/MixedType.php
@@ -0,0 +1,33 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of sebastian/type.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace SebastianBergmann\Type;
+
+final class MixedType extends Type
+{
+ public function isAssignable(Type $other): bool
+ {
+ return !$other instanceof VoidType;
+ }
+
+ public function asString(): string
+ {
+ return 'mixed';
+ }
+
+ public function name(): string
+ {
+ return 'mixed';
+ }
+
+ public function allowsNull(): bool
+ {
+ return true;
+ }
+}
diff --git a/vendor/sebastian/type/src/NullType.php b/vendor/sebastian/type/src/NullType.php
new file mode 100644
index 000000000..8481fceb8
--- /dev/null
+++ b/vendor/sebastian/type/src/NullType.php
@@ -0,0 +1,43 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of sebastian/type.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace SebastianBergmann\Type;
+
+final class NullType extends Type
+{
+ public function isAssignable(Type $other): bool
+ {
+ return !($other instanceof VoidType);
+ }
+
+ public function name(): string
+ {
+ return 'null';
+ }
+
+ public function asString(): string
+ {
+ return 'null';
+ }
+
+ /**
+ * @deprecated
+ *
+ * @codeCoverageIgnore
+ */
+ public function getReturnTypeDeclaration(): string
+ {
+ return '';
+ }
+
+ public function allowsNull(): bool
+ {
+ return true;
+ }
+}
diff --git a/vendor/sebastian/type/src/ObjectType.php b/vendor/sebastian/type/src/ObjectType.php
new file mode 100644
index 000000000..c71273cb4
--- /dev/null
+++ b/vendor/sebastian/type/src/ObjectType.php
@@ -0,0 +1,66 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of sebastian/type.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace SebastianBergmann\Type;
+
+use function is_subclass_of;
+use function strcasecmp;
+
+final class ObjectType extends Type
+{
+ /**
+ * @var TypeName
+ */
+ private $className;
+
+ /**
+ * @var bool
+ */
+ private $allowsNull;
+
+ public function __construct(TypeName $className, bool $allowsNull)
+ {
+ $this->className = $className;
+ $this->allowsNull = $allowsNull;
+ }
+
+ public function isAssignable(Type $other): bool
+ {
+ if ($this->allowsNull && $other instanceof NullType) {
+ return true;
+ }
+
+ if ($other instanceof self) {
+ if (0 === strcasecmp($this->className->qualifiedName(), $other->className->qualifiedName())) {
+ return true;
+ }
+
+ if (is_subclass_of($other->className->qualifiedName(), $this->className->qualifiedName(), true)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ public function name(): string
+ {
+ return $this->className->qualifiedName();
+ }
+
+ public function allowsNull(): bool
+ {
+ return $this->allowsNull;
+ }
+
+ public function className(): TypeName
+ {
+ return $this->className;
+ }
+}
diff --git a/vendor/sebastian/type/src/ReflectionMapper.php b/vendor/sebastian/type/src/ReflectionMapper.php
new file mode 100644
index 000000000..db9baf425
--- /dev/null
+++ b/vendor/sebastian/type/src/ReflectionMapper.php
@@ -0,0 +1,123 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of sebastian/type.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace SebastianBergmann\Type;
+
+use function assert;
+use function sprintf;
+use ReflectionMethod;
+use ReflectionNamedType;
+use ReflectionType;
+use ReflectionUnionType;
+
+final class ReflectionMapper
+{
+ public function fromMethodReturnType(ReflectionMethod $method): Type
+ {
+ if (!$this->reflectionMethodHasReturnType($method)) {
+ return new UnknownType;
+ }
+
+ $returnType = $this->reflectionMethodGetReturnType($method);
+
+ assert($returnType instanceof ReflectionNamedType || $returnType instanceof ReflectionUnionType);
+
+ if ($returnType instanceof ReflectionNamedType) {
+ if ($returnType->getName() === 'self') {
+ return ObjectType::fromName(
+ $method->getDeclaringClass()->getName(),
+ $returnType->allowsNull()
+ );
+ }
+
+ if ($returnType->getName() === 'static') {
+ return new StaticType(
+ TypeName::fromReflection($method->getDeclaringClass()),
+ $returnType->allowsNull()
+ );
+ }
+
+ if ($returnType->getName() === 'mixed') {
+ return new MixedType;
+ }
+
+ if ($returnType->getName() === 'parent') {
+ $parentClass = $method->getDeclaringClass()->getParentClass();
+
+ // @codeCoverageIgnoreStart
+ if ($parentClass === false) {
+ throw new RuntimeException(
+ sprintf(
+ '%s::%s() has a "parent" return type declaration but %s does not have a parent class',
+ $method->getDeclaringClass()->getName(),
+ $method->getName(),
+ $method->getDeclaringClass()->getName()
+ )
+ );
+ }
+ // @codeCoverageIgnoreEnd
+
+ return ObjectType::fromName(
+ $parentClass->getName(),
+ $returnType->allowsNull()
+ );
+ }
+
+ return Type::fromName(
+ $returnType->getName(),
+ $returnType->allowsNull()
+ );
+ }
+
+ assert($returnType instanceof ReflectionUnionType);
+
+ $types = [];
+
+ foreach ($returnType->getTypes() as $type) {
+ assert($type instanceof ReflectionNamedType);
+
+ if ($type->getName() === 'self') {
+ $types[] = ObjectType::fromName(
+ $method->getDeclaringClass()->getName(),
+ false
+ );
+ } else {
+ $types[] = Type::fromName($type->getName(), false);
+ }
+ }
+
+ return new UnionType(...$types);
+ }
+
+ private function reflectionMethodHasReturnType(ReflectionMethod $method): bool
+ {
+ if ($method->hasReturnType()) {
+ return true;
+ }
+
+ if (!method_exists($method, 'hasTentativeReturnType')) {
+ return false;
+ }
+
+ return $method->hasTentativeReturnType();
+ }
+
+ private function reflectionMethodGetReturnType(ReflectionMethod $method): ?ReflectionType
+ {
+ if ($method->hasReturnType()) {
+ return $method->getReturnType();
+ }
+
+ if (!method_exists($method, 'getTentativeReturnType')) {
+ return null;
+ }
+
+ return $method->getTentativeReturnType();
+ }
+}
diff --git a/vendor/sebastian/type/src/SimpleType.php b/vendor/sebastian/type/src/SimpleType.php
new file mode 100644
index 000000000..8bf0bf7df
--- /dev/null
+++ b/vendor/sebastian/type/src/SimpleType.php
@@ -0,0 +1,92 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of sebastian/type.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace SebastianBergmann\Type;
+
+use function strtolower;
+
+final class SimpleType extends Type
+{
+ /**
+ * @var string
+ */
+ private $name;
+
+ /**
+ * @var bool
+ */
+ private $allowsNull;
+
+ /**
+ * @var mixed
+ */
+ private $value;
+
+ public function __construct(string $name, bool $nullable, $value = null)
+ {
+ $this->name = $this->normalize($name);
+ $this->allowsNull = $nullable;
+ $this->value = $value;
+ }
+
+ public function isAssignable(Type $other): bool
+ {
+ if ($this->allowsNull && $other instanceof NullType) {
+ return true;
+ }
+
+ if ($this->name === 'bool' && $other->name() === 'false') {
+ return true;
+ }
+
+ if ($other instanceof self) {
+ return $this->name === $other->name;
+ }
+
+ return false;
+ }
+
+ public function name(): string
+ {
+ return $this->name;
+ }
+
+ public function allowsNull(): bool
+ {
+ return $this->allowsNull;
+ }
+
+ public function value()
+ {
+ return $this->value;
+ }
+
+ private function normalize(string $name): string
+ {
+ $name = strtolower($name);
+
+ switch ($name) {
+ case 'boolean':
+ return 'bool';
+
+ case 'real':
+ case 'double':
+ return 'float';
+
+ case 'integer':
+ return 'int';
+
+ case '[]':
+ return 'array';
+
+ default:
+ return $name;
+ }
+ }
+}
diff --git a/vendor/sebastian/type/src/StaticType.php b/vendor/sebastian/type/src/StaticType.php
new file mode 100644
index 000000000..6833094d1
--- /dev/null
+++ b/vendor/sebastian/type/src/StaticType.php
@@ -0,0 +1,60 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of sebastian/type.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace SebastianBergmann\Type;
+
+final class StaticType extends Type
+{
+ /**
+ * @var TypeName
+ */
+ private $className;
+
+ /**
+ * @var bool
+ */
+ private $allowsNull;
+
+ public function __construct(TypeName $className, bool $allowsNull)
+ {
+ $this->className = $className;
+ $this->allowsNull = $allowsNull;
+ }
+
+ public function isAssignable(Type $other): bool
+ {
+ if ($this->allowsNull && $other instanceof NullType) {
+ return true;
+ }
+
+ if (!$other instanceof ObjectType) {
+ return false;
+ }
+
+ if (0 === strcasecmp($this->className->qualifiedName(), $other->className()->qualifiedName())) {
+ return true;
+ }
+
+ if (is_subclass_of($other->className()->qualifiedName(), $this->className->qualifiedName(), true)) {
+ return true;
+ }
+
+ return false;
+ }
+
+ public function name(): string
+ {
+ return 'static';
+ }
+
+ public function allowsNull(): bool
+ {
+ return $this->allowsNull;
+ }
+}
diff --git a/vendor/sebastian/type/src/Type.php b/vendor/sebastian/type/src/Type.php
new file mode 100644
index 000000000..679223d96
--- /dev/null
+++ b/vendor/sebastian/type/src/Type.php
@@ -0,0 +1,101 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of sebastian/type.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace SebastianBergmann\Type;
+
+use function get_class;
+use function gettype;
+use function strtolower;
+
+abstract class Type
+{
+ public static function fromValue($value, bool $allowsNull): self
+ {
+ if ($value === false) {
+ return new FalseType;
+ }
+
+ $typeName = gettype($value);
+
+ if ($typeName === 'object') {
+ return new ObjectType(TypeName::fromQualifiedName(get_class($value)), $allowsNull);
+ }
+
+ $type = self::fromName($typeName, $allowsNull);
+
+ if ($type instanceof SimpleType) {
+ $type = new SimpleType($typeName, $allowsNull, $value);
+ }
+
+ return $type;
+ }
+
+ public static function fromName(string $typeName, bool $allowsNull): self
+ {
+ switch (strtolower($typeName)) {
+ case 'callable':
+ return new CallableType($allowsNull);
+
+ case 'false':
+ return new FalseType;
+
+ case 'iterable':
+ return new IterableType($allowsNull);
+
+ case 'null':
+ return new NullType;
+
+ case 'object':
+ return new GenericObjectType($allowsNull);
+
+ case 'unknown type':
+ return new UnknownType;
+
+ case 'void':
+ return new VoidType;
+
+ case 'array':
+ case 'bool':
+ case 'boolean':
+ case 'double':
+ case 'float':
+ case 'int':
+ case 'integer':
+ case 'real':
+ case 'resource':
+ case 'resource (closed)':
+ case 'string':
+ return new SimpleType($typeName, $allowsNull);
+
+ default:
+ return new ObjectType(TypeName::fromQualifiedName($typeName), $allowsNull);
+ }
+ }
+
+ public function asString(): string
+ {
+ return ($this->allowsNull() ? '?' : '') . $this->name();
+ }
+
+ /**
+ * @deprecated
+ *
+ * @codeCoverageIgnore
+ */
+ public function getReturnTypeDeclaration(): string
+ {
+ return ': ' . $this->asString();
+ }
+
+ abstract public function isAssignable(Type $other): bool;
+
+ abstract public function name(): string;
+
+ abstract public function allowsNull(): bool;
+}
diff --git a/vendor/sebastian/type/src/TypeName.php b/vendor/sebastian/type/src/TypeName.php
new file mode 100644
index 000000000..b076e89e0
--- /dev/null
+++ b/vendor/sebastian/type/src/TypeName.php
@@ -0,0 +1,113 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of sebastian/type.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace SebastianBergmann\Type;
+
+use function array_pop;
+use function explode;
+use function implode;
+use function substr;
+use ReflectionClass;
+
+final class TypeName
+{
+ /**
+ * @var ?string
+ */
+ private $namespaceName;
+
+ /**
+ * @var string
+ */
+ private $simpleName;
+
+ public static function fromQualifiedName(string $fullClassName): self
+ {
+ if ($fullClassName[0] === '\\') {
+ $fullClassName = substr($fullClassName, 1);
+ }
+
+ $classNameParts = explode('\\', $fullClassName);
+
+ $simpleName = array_pop($classNameParts);
+ $namespaceName = implode('\\', $classNameParts);
+
+ return new self($namespaceName, $simpleName);
+ }
+
+ public static function fromReflection(ReflectionClass $type): self
+ {
+ return new self(
+ $type->getNamespaceName(),
+ $type->getShortName()
+ );
+ }
+
+ public function __construct(?string $namespaceName, string $simpleName)
+ {
+ if ($namespaceName === '') {
+ $namespaceName = null;
+ }
+
+ $this->namespaceName = $namespaceName;
+ $this->simpleName = $simpleName;
+ }
+
+ public function namespaceName(): ?string
+ {
+ return $this->namespaceName;
+ }
+
+ public function simpleName(): string
+ {
+ return $this->simpleName;
+ }
+
+ public function qualifiedName(): string
+ {
+ return $this->namespaceName === null
+ ? $this->simpleName
+ : $this->namespaceName . '\\' . $this->simpleName;
+ }
+
+ /**
+ * @deprecated Use namespaceName() instead
+ *
+ * @codeCoverageIgnore
+ */
+ public function getNamespaceName(): ?string
+ {
+ return $this->namespaceName();
+ }
+
+ /**
+ * @deprecated Use simpleName() instead
+ *
+ * @codeCoverageIgnore
+ */
+ public function getSimpleName(): string
+ {
+ return $this->simpleName();
+ }
+
+ /**
+ * @deprecated Use qualifiedName() instead
+ *
+ * @codeCoverageIgnore
+ */
+ public function getQualifiedName(): string
+ {
+ return $this->qualifiedName();
+ }
+
+ public function isNamespaced(): bool
+ {
+ return $this->namespaceName !== null;
+ }
+}
diff --git a/vendor/sebastian/type/src/UnionType.php b/vendor/sebastian/type/src/UnionType.php
new file mode 100644
index 000000000..10c4a49b5
--- /dev/null
+++ b/vendor/sebastian/type/src/UnionType.php
@@ -0,0 +1,115 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of sebastian/type.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace SebastianBergmann\Type;
+
+use function count;
+use function implode;
+use function sort;
+
+final class UnionType extends Type
+{
+ /**
+ * @psalm-var list<Type>
+ */
+ private $types;
+
+ /**
+ * @throws RuntimeException
+ */
+ public function __construct(Type ...$types)
+ {
+ $this->ensureMinimumOfTwoTypes(...$types);
+ $this->ensureOnlyValidTypes(...$types);
+
+ $this->types = $types;
+ }
+
+ public function isAssignable(Type $other): bool
+ {
+ foreach ($this->types as $type) {
+ if ($type->isAssignable($other)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ public function asString(): string
+ {
+ return $this->name();
+ }
+
+ /**
+ * @deprecated
+ *
+ * @codeCoverageIgnore
+ */
+ public function getReturnTypeDeclaration(): string
+ {
+ return ': ' . $this->name();
+ }
+
+ public function name(): string
+ {
+ $types = [];
+
+ foreach ($this->types as $type) {
+ $types[] = $type->name();
+ }
+
+ sort($types);
+
+ return implode('|', $types);
+ }
+
+ public function allowsNull(): bool
+ {
+ foreach ($this->types as $type) {
+ if ($type instanceof NullType) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * @throws RuntimeException
+ */
+ private function ensureMinimumOfTwoTypes(Type ...$types): void
+ {
+ if (count($types) < 2) {
+ throw new RuntimeException(
+ 'A union type must be composed of at least two types'
+ );
+ }
+ }
+
+ /**
+ * @throws RuntimeException
+ */
+ private function ensureOnlyValidTypes(Type ...$types): void
+ {
+ foreach ($types as $type) {
+ if ($type instanceof UnknownType) {
+ throw new RuntimeException(
+ 'A union type must not be composed of an unknown type'
+ );
+ }
+
+ if ($type instanceof VoidType) {
+ throw new RuntimeException(
+ 'A union type must not be composed of a void type'
+ );
+ }
+ }
+ }
+}
diff --git a/vendor/sebastian/type/src/UnknownType.php b/vendor/sebastian/type/src/UnknownType.php
new file mode 100644
index 000000000..dde4c6788
--- /dev/null
+++ b/vendor/sebastian/type/src/UnknownType.php
@@ -0,0 +1,43 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of sebastian/type.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace SebastianBergmann\Type;
+
+final class UnknownType extends Type
+{
+ public function isAssignable(Type $other): bool
+ {
+ return true;
+ }
+
+ public function name(): string
+ {
+ return 'unknown type';
+ }
+
+ public function asString(): string
+ {
+ return '';
+ }
+
+ /**
+ * @deprecated
+ *
+ * @codeCoverageIgnore
+ */
+ public function getReturnTypeDeclaration(): string
+ {
+ return '';
+ }
+
+ public function allowsNull(): bool
+ {
+ return true;
+ }
+}
diff --git a/vendor/sebastian/type/src/VoidType.php b/vendor/sebastian/type/src/VoidType.php
new file mode 100644
index 000000000..18c017564
--- /dev/null
+++ b/vendor/sebastian/type/src/VoidType.php
@@ -0,0 +1,28 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of sebastian/type.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace SebastianBergmann\Type;
+
+final class VoidType extends Type
+{
+ public function isAssignable(Type $other): bool
+ {
+ return $other instanceof self;
+ }
+
+ public function name(): string
+ {
+ return 'void';
+ }
+
+ public function allowsNull(): bool
+ {
+ return false;
+ }
+}
diff --git a/vendor/sebastian/type/src/exception/Exception.php b/vendor/sebastian/type/src/exception/Exception.php
new file mode 100644
index 000000000..e0e7ee579
--- /dev/null
+++ b/vendor/sebastian/type/src/exception/Exception.php
@@ -0,0 +1,16 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of sebastian/type.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace SebastianBergmann\Type;
+
+use Throwable;
+
+interface Exception extends Throwable
+{
+}
diff --git a/vendor/sebastian/type/src/exception/LogicException.php b/vendor/sebastian/type/src/exception/LogicException.php
new file mode 100644
index 000000000..243582166
--- /dev/null
+++ b/vendor/sebastian/type/src/exception/LogicException.php
@@ -0,0 +1,14 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of sebastian/type.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace SebastianBergmann\Type;
+
+final class LogicException extends \LogicException implements Exception
+{
+}
diff --git a/vendor/sebastian/type/src/exception/RuntimeException.php b/vendor/sebastian/type/src/exception/RuntimeException.php
new file mode 100644
index 000000000..4dfea6a6a
--- /dev/null
+++ b/vendor/sebastian/type/src/exception/RuntimeException.php
@@ -0,0 +1,14 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of sebastian/type.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace SebastianBergmann\Type;
+
+final class RuntimeException extends \RuntimeException implements Exception
+{
+}