Skip to content

Commit

Permalink
[Type] Introduce the Type API (#44)
Browse files Browse the repository at this point in the history
  • Loading branch information
azjezz committed Aug 3, 2020
1 parent f5db896 commit 4784d00
Show file tree
Hide file tree
Showing 65 changed files with 2,782 additions and 14 deletions.
2 changes: 1 addition & 1 deletion src/Psl/Gen/from_entries.php
Expand Up @@ -10,7 +10,7 @@
* Returns a generator where each mapping is defined by the given key/value
* tuples.
*
* @psalm-template Tk of array-key
* @psalm-template Tk
* @psalm-template Tv
*
* @psalm-param iterable<array{0: Tk, 1: Tv}> $entries
Expand Down
4 changes: 2 additions & 2 deletions src/Psl/Gen/pull_with_key.php
Expand Up @@ -23,9 +23,9 @@
* 70 => 'H', 131 => 'I', 264 => 'J', 521 => 'K', 1034 => 'L'
* )
*
* @psalm-template Tk1 of array-key
* @psalm-template Tk1
* @psalm-template Tv1
* @psalm-template Tk2 of array-key
* @psalm-template Tk2
* @psalm-template Tv2
*
* @psalm-param iterable<Tk1, Tv1> $iterable
Expand Down
4 changes: 2 additions & 2 deletions src/Psl/Gen/reindex.php
Expand Up @@ -26,8 +26,8 @@
* 24 => ['id' => 24, 'name' => 'bar']
* )
*
* @psalm-template Tk1 of array-key
* @psalm-template Tk2 of array-key
* @psalm-template Tk1
* @psalm-template Tk2
* @psalm-template Tv
*
* @psalm-param iterable<Tk1, Tv> $iterable Iterable to reindex
Expand Down
7 changes: 5 additions & 2 deletions src/Psl/Gen/repeat.php
Expand Up @@ -35,8 +35,11 @@ function repeat($value, ?int $num = null): Generator
{
Psl\invariant(null === $num || $num >= 0, 'Number of repetitions must be non-negative');

/** @var int $num */
$num ??= Math\INFINITY;
if (null === $num) {
/** @var int $num */
$num = Math\INFINITY;
}

for ($i = 0; $i < $num; ++$i) {
yield $value;
}
Expand Down
37 changes: 36 additions & 1 deletion src/Psl/Internal/Loader.php
Expand Up @@ -287,6 +287,22 @@ final class Loader
'Psl\invariant',
'Psl\invariant_violation',
'Psl\sequence',
'Psl\Type\arr',
'Psl\Type\array_key',
'Psl\Type\bool',
'Psl\Type\float',
'Psl\Type\int',
'Psl\Type\intersection',
'Psl\Type\iterable',
'Psl\Type\mixed',
'Psl\Type\null',
'Psl\Type\nullable',
'Psl\Type\num',
'Psl\Type\object',
'Psl\Type\resource',
'Psl\Type\string',
'Psl\Type\scalar',
'Psl\Type\union',
];

public const INTERFACES = [
Expand All @@ -302,10 +318,29 @@ final class Loader
'Psl\Collection\IMutableVector',
'Psl\Collection\IMap',
'Psl\Collection\IMutableMap',
'Psl\Type\Internal\ArrayKeyType',
'Psl\Type\Internal\ArrayType',
'Psl\Type\Internal\BoolType',
'Psl\Type\Internal\FloatType',
'Psl\Type\Internal\IntersectionType',
'Psl\Type\Internal\IntType',
'Psl\Type\Internal\IterableType',
'Psl\Type\Internal\MixedType',
'Psl\Type\Internal\NullType',
'Psl\Type\Internal\NumType',
'Psl\Type\Internal\ObjectType',
'Psl\Type\Internal\ResourceType',
'Psl\Type\Internal\StringType',
'Psl\Type\Internal\UnionType',
'Psl\Type\Exception\TypeTrace',
'Psl\Type\Exception\TypeAssertException',
'Psl\Type\Exception\TypeCoercionException',
'Psl\Type\Exception\TypeException',
'Psl\Type\Type',
];

public const TRAITS = [

'Psl\Type\Internal\TypeTraceTrait',
];

public const CLASSES = [
Expand Down
2 changes: 1 addition & 1 deletion src/Psl/Iter/from_entries.php
Expand Up @@ -10,7 +10,7 @@
* Returns an iterator where each mapping is defined by the given key/value
* tuples.
*
* @psalm-template Tk of array-key
* @psalm-template Tk
* @psalm-template Tv
*
* @psalm-param iterable<array{0: Tk, 1: Tv}> $entries
Expand Down
4 changes: 2 additions & 2 deletions src/Psl/Iter/pull_with_key.php
Expand Up @@ -23,9 +23,9 @@
* 70 => 'H', 131 => 'I', 264 => 'J', 521 => 'K', 1034 => 'L'
* )
*
* @psalm-template Tk1 of array-key
* @psalm-template Tk1
* @psalm-template Tv1
* @psalm-template Tk2 of array-key
* @psalm-template Tk2
* @psalm-template Tv2
*
* @psalm-param iterable<Tk1, Tv1> $iterable
Expand Down
4 changes: 2 additions & 2 deletions src/Psl/Iter/reindex.php
Expand Up @@ -26,8 +26,8 @@
* 24 => ['id' => 24, 'name' => 'bar']
* )
*
* @psalm-template Tk1 of array-key
* @psalm-template Tk2 of array-key
* @psalm-template Tk1
* @psalm-template Tk2
* @psalm-template Tv
*
* @psalm-param iterable<Tk1, Tv> $iterable Iterable to reindex
Expand Down
2 changes: 1 addition & 1 deletion src/Psl/Str/join.php
Expand Up @@ -17,7 +17,7 @@
* Str\join(['Hello', 'World'], ', ')
* => Str('Hello, World')
*
* @param string[] $pieces the array of strings to implode
* @param iterable<string> $pieces the array of strings to implode
*
* @return string a string containing a string representation of all the array
* elements in the same order, with the glue string between each element
Expand Down
35 changes: 35 additions & 0 deletions src/Psl/Type/Exception/TypeAssertException.php
@@ -0,0 +1,35 @@
<?php

declare(strict_types=1);

namespace Psl\Type\Exception;

use Psl\Str;

final class TypeAssertException extends TypeException
{
private string $expected;

public function __construct(string $actual, string $expected, TypeTrace $typeTrace)
{
parent::__construct(Str\format('Expected "%s", got "%s".', $expected, $actual), $actual, $typeTrace);

$this->expected = $expected;
}

public function getExpectedType(): string
{
return $this->expected;
}

/**
* @param mixed $value
*/
public static function withValue(
$value,
string $expected_type,
TypeTrace $trace
): self {
return new self(static::getDebugType($value), $expected_type, $trace);
}
}
39 changes: 39 additions & 0 deletions src/Psl/Type/Exception/TypeCoercionException.php
@@ -0,0 +1,39 @@
<?php

declare(strict_types=1);

namespace Psl\Type\Exception;

use Psl\Str;

final class TypeCoercionException extends TypeException
{
private string $target;

public function __construct(string $actual, string $target, TypeTrace $typeTrace)
{
parent::__construct(
Str\format('Could not coerce "%s" to type "%s".', $actual, $target),
$actual,
$typeTrace,
);

$this->target = $target;
}

public function getTargetType(): string
{
return $this->target;
}

/**
* @param mixed $value
*/
public static function withValue(
$value,
string $target,
TypeTrace $typeTrace
): self {
return new self(static::getDebugType($value), $target, $typeTrace);
}
}
55 changes: 55 additions & 0 deletions src/Psl/Type/Exception/TypeException.php
@@ -0,0 +1,55 @@
<?php

declare(strict_types=1);

namespace Psl\Type\Exception;

use Psl\Exception\RuntimeException;
use Psl\Str;

abstract class TypeException extends RuntimeException
{
private TypeTrace $typeTrace;
private string $actual;

public function __construct(
string $message,
string $actual,
TypeTrace $typeTrace
) {
parent::__construct($message);

$this->actual = $actual;
$this->typeTrace = $typeTrace;
}

public function getActualType(): string
{
return $this->actual;
}

public function getTypeTrace(): TypeTrace
{
return $this->typeTrace;
}

/**
* @param mixed $value
*/
protected static function getDebugType($value): string
{
if (is_object($value)) {
$actual_type = get_class($value);
} elseif (is_resource($value)) {
$actual_type = Str\format('resource<%s>', get_resource_type($value));
} elseif (is_int($value)) {
$actual_type = 'int';
} elseif (is_float($value)) {
$actual_type = 'float';
} else {
$actual_type = gettype($value);
}

return $actual_type;
}
}
29 changes: 29 additions & 0 deletions src/Psl/Type/Exception/TypeTrace.php
@@ -0,0 +1,29 @@
<?php

declare(strict_types=1);

namespace Psl\Type\Exception;

final class TypeTrace
{
/**
* @var string[]
*/
private array $frames = [];

public function withFrame(string $frame): self
{
$self = clone $this;
$self->frames[] = $frame;

return $self;
}

/**
* @return string[]
*/
public function getFrames(): array
{
return $this->frames;
}
}
23 changes: 23 additions & 0 deletions src/Psl/Type/Internal/ArrayKeyType.php
@@ -0,0 +1,23 @@
<?php

declare(strict_types=1);

namespace Psl\Type\Internal;

/**
* @extends UnionType<string, int>
*
* @internal
*/
final class ArrayKeyType extends UnionType
{
public function __construct()
{
parent::__construct(new StringType(), new IntType());
}

public function toString(): string
{
return 'array-key';
}
}

0 comments on commit 4784d00

Please sign in to comment.