Skip to content

Commit

Permalink
feat(type): Notnull type optimizations
Browse files Browse the repository at this point in the history
  • Loading branch information
veewee committed Apr 9, 2024
1 parent a33de34 commit 7d37566
Show file tree
Hide file tree
Showing 4 changed files with 89 additions and 6 deletions.
2 changes: 1 addition & 1 deletion docs/component/type.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@
- [non_empty_dict](./../../src/Psl/Type/non_empty_dict.php#L18)
- [non_empty_string](./../../src/Psl/Type/non_empty_string.php#L14)
- [non_empty_vec](./../../src/Psl/Type/non_empty_vec.php#L16)
- [nonnull](./../../src/Psl/Type/nonnull.php#L16)
- [nonnull](./../../src/Psl/Type/nonnull.php#L18)
- [null](./../../src/Psl/Type/null.php#L14)
- [nullable](./../../src/Psl/Type/nullable.php#L16)
- [num](./../../src/Psl/Type/num.php#L14)
Expand Down
22 changes: 18 additions & 4 deletions src/Psl/Type/Internal/NonNullType.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,19 +18,29 @@
final readonly class NonNullType extends Type\Type
{
/**
* @psalm-assert-if-true mixed $value
* @template T of mixed
*
* @param T $value
*
* @psalm-assert-if-true T $value
*
* @ara-assert-if-true nonnull $value
*
* @return (T is null ? false : true)
*/
public function matches(mixed $value): bool
{
return null !== $value;
}

/**
* @template T of mixed
*
* @param T $value
*
* @ara-return nonnull
*
* @return mixed
* @return (T is null ? never : T)
*/
public function coerce(mixed $value): mixed
{
Expand All @@ -42,13 +52,17 @@ public function coerce(mixed $value): mixed
}

/**
* @template T
*
* @param T $value
*
* @ara-assert nonnull $value
*
* @psalm-assert mixed $value
* @psalm-assert T $value
*
* @ara-return nonnull
*
* @return mixed
* @return (T is null ? never : T)
*/
public function assert(mixed $value): mixed
{
Expand Down
4 changes: 3 additions & 1 deletion src/Psl/Type/nonnull.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,16 @@

namespace Psl\Type;

use Psl\Type\Internal\NonNullType;

/**
* @psalm-pure
*
* @psalm-suppress ImpureStaticVariable - The $instance is always the same and is considered pure.
*
* @ara-return TypeInterface<nonnull>
*
* @return TypeInterface<mixed>
* @return NonNullType
*/
function nonnull(): TypeInterface
{
Expand Down
67 changes: 67 additions & 0 deletions tests/static-analysis/Type/nonnull.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
<?php

declare(strict_types=1);

namespace Psl\Tests\StaticAnalysis\Type;

use Psl\Type;

/**
* @throws Type\Exception\AssertException
*/
function returns_non_null_assertion(?string $state): string
{
return Type\nonnull()->assert($state);
}

/**
* @throws Type\Exception\AssertException
*
* Asserting still leeds to mixed (including null) return type.
* This won't be solvable until psalm supports a TNotNull type.
*/
function returns_non_null_assertion_asserted(?string $state): ?string
{
Type\nonnull()->assert($state);

return $state;
}

/**
* @throws Type\Exception\CoercionException
*/
function returns_non_null_coercion(?string $state): string
{
return Type\nonnull()->coerce($state);
}

/**
* @return true
*/
function returns_truthy_match(string $state): bool
{
return Type\nonnull()->matches($state);
}

/**
* @return false
*/
function returns_falsy_match(null $state = null): bool
{
return Type\nonnull()->matches($state);
}

/**
* @throws Type\Exception\CoercionException
*
* Wrapping it in container types still leeds to mixed (including null) return type.
* This won't be solvable until psalm supports a TNotNull type.
*
* @return array<'mightBeNull', mixed>
*/
function returns_mixed_in_shape(mixed $data): array
{
return Type\shape([
'mightBeNull' => Type\nonnull(),
])->coerce($data);
}

0 comments on commit 7d37566

Please sign in to comment.