Skip to content

Commit

Permalink
Added self and parent types
Browse files Browse the repository at this point in the history
  • Loading branch information
vudaltsov committed Feb 7, 2024
1 parent 5fbfd03 commit 7f738d0
Show file tree
Hide file tree
Showing 15 changed files with 315 additions and 8 deletions.
36 changes: 36 additions & 0 deletions src/ParentClassStringLiteralType.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<?php

declare(strict_types=1);

namespace Typhoon\Type;

/**
* @api
* @psalm-immutable
* @implements Type<class-string>
* Absence of a template declaration for the object type is intentional. Consider a trait: parent::class type declared in
* this trait does not represent class of the trait, but an instance of a class that uses this trait.
*/
final class ParentClassStringLiteralType implements Type
{
/**
* @var class-string
*/
public readonly string $declaredAtClass;

/**
* @internal
* @psalm-internal Typhoon\Type
* @param class-string $declaredAtClass
*/
public function __construct(
string $declaredAtClass,
) {
$this->declaredAtClass = $declaredAtClass;
}

public function accept(TypeVisitor $visitor): mixed
{
return $visitor->visitParentClassStringLiteral($this);
}
}
44 changes: 44 additions & 0 deletions src/ParentType.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
<?php

declare(strict_types=1);

namespace Typhoon\Type;

/**
* @api
* @psalm-immutable
* @implements Type<object>
* Absence of a template declaration for the object type is intentional. Consider a trait: parent type declared in
* this trait does not represent instance of the trait, but an instance of a class that uses this trait.
*/
final class ParentType implements Type
{
/**
* @var class-string
*/
public readonly string $declaredAtClass;

/**
* @var list<Type>
*/
public readonly array $templateArguments;

/**
* @internal
* @psalm-internal Typhoon\Type
* @param class-string $declaredAtClass
* @param list<Type> $templateArguments
*/
public function __construct(
string $declaredAtClass,
array $templateArguments = [],
) {
$this->declaredAtClass = $declaredAtClass;
$this->templateArguments = $templateArguments;
}

public function accept(TypeVisitor $visitor): mixed
{
return $visitor->visitParent($this);
}
}
36 changes: 36 additions & 0 deletions src/SelfClassStringLiteralType.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<?php

declare(strict_types=1);

namespace Typhoon\Type;

/**
* @api
* @psalm-immutable
* @implements Type<class-string>
* Absence of a template declaration for the object type is intentional. Consider a trait: self::class type declared in
* this trait does not represent class of the trait, but an instance of a class that uses this trait.
*/
final class SelfClassStringLiteralType implements Type
{
/**
* @var class-string
*/
public readonly string $declaredAtClass;

/**
* @internal
* @psalm-internal Typhoon\Type
* @param class-string $declaredAtClass
*/
public function __construct(
string $declaredAtClass,
) {
$this->declaredAtClass = $declaredAtClass;
}

public function accept(TypeVisitor $visitor): mixed
{
return $visitor->visitSelfClassStringLiteral($this);
}
}
44 changes: 44 additions & 0 deletions src/SelfType.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
<?php

declare(strict_types=1);

namespace Typhoon\Type;

/**
* @api
* @psalm-immutable
* @implements Type<object>
* Absence of a template declaration for the object type is intentional. Consider a trait: self type declared in
* this trait does not represent instance of the trait, but an instance of a class that uses this trait.
*/
final class SelfType implements Type
{
/**
* @var class-string
*/
public readonly string $declaredAtClass;

/**
* @var list<Type>
*/
public readonly array $templateArguments;

/**
* @internal
* @psalm-internal Typhoon\Type
* @param class-string $declaredAtClass
* @param list<Type> $templateArguments
*/
public function __construct(
string $declaredAtClass,
array $templateArguments = [],
) {
$this->declaredAtClass = $declaredAtClass;
$this->templateArguments = $templateArguments;
}

public function accept(TypeVisitor $visitor): mixed
{
return $visitor->visitSelf($this);
}
}
36 changes: 36 additions & 0 deletions src/StaticClassStringLiteralType.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<?php

declare(strict_types=1);

namespace Typhoon\Type;

/**
* @api
* @psalm-immutable
* @implements Type<class-string>
* Absence of a template declaration for the object type is intentional. Consider a trait: static::class type declared in
* this trait does not represent class of the trait, but an instance of a class that uses this trait.
*/
final class StaticClassStringLiteralType implements Type
{
/**
* @var class-string
*/
public readonly string $declaredAtClass;

/**
* @internal
* @psalm-internal Typhoon\Type
* @param class-string $declaredAtClass
*/
public function __construct(
string $declaredAtClass,
) {
$this->declaredAtClass = $declaredAtClass;
}

public function accept(TypeVisitor $visitor): mixed
{
return $visitor->visitStaticClassStringLiteral($this);
}
}
9 changes: 5 additions & 4 deletions src/StaticType.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,14 @@
/**
* @api
* @psalm-immutable
* @template-covariant TObject of object
* @implements Type<TObject>
* @implements Type<object>
* Absence of a template declaration for the object type is intentional. Consider a trait: self type declared in
* this trait does not represent instance of the trait, but an instance of a class that uses this trait.
*/
final class StaticType implements Type
{
/**
* @var class-string<TObject>
* @var class-string
*/
public readonly string $declaredAtClass;

Expand All @@ -25,7 +26,7 @@ final class StaticType implements Type
/**
* @internal
* @psalm-internal Typhoon\Type
* @param class-string<TObject> $declaredAtClass
* @param class-string $declaredAtClass
* @param list<Type> $templateArguments
*/
public function __construct(
Expand Down
15 changes: 15 additions & 0 deletions src/TypeVisitor.php
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,15 @@ public function visitNumericString(NumericStringType $type): mixed;
/** @return TReturn */
public function visitClassStringLiteral(ClassStringLiteralType $type): mixed;

/** @return TReturn */
public function visitSelfClassStringLiteral(SelfClassStringLiteralType $type): mixed;

/** @return TReturn */
public function visitParentClassStringLiteral(ParentClassStringLiteralType $type): mixed;

/** @return TReturn */
public function visitStaticClassStringLiteral(StaticClassStringLiteralType $type): mixed;

/** @return TReturn */
public function visitNamedClassString(NamedClassStringType $type): mixed;

Expand Down Expand Up @@ -125,6 +134,12 @@ public function visitIterable(IterableType $type): mixed;
/** @return TReturn */
public function visitNamedObject(NamedObjectType $type): mixed;

/** @return TReturn */
public function visitSelf(SelfType $type): mixed;

/** @return TReturn */
public function visitParent(ParentType $type): mixed;

/** @return TReturn */
public function visitStatic(StaticType $type): mixed;

Expand Down
51 changes: 48 additions & 3 deletions src/types.php
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,33 @@ public static function classString(string|Type $classOrType): ClassStringLiteral
return new NamedClassStringType($classOrType);
}

/**
* @psalm-pure
* @param class-string $declaredAtClass
*/
public static function selfClassString(string $declaredAtClass): SelfClassStringLiteralType
{
return new SelfClassStringLiteralType($declaredAtClass);
}

/**
* @psalm-pure
* @param class-string $declaredAtClass
*/
public static function parentClassString(string $declaredAtClass): ParentClassStringLiteralType
{
return new ParentClassStringLiteralType($declaredAtClass);
}

/**
* @psalm-pure
* @param class-string $declaredAtClass
*/
public static function staticClassString(string $declaredAtClass): StaticClassStringLiteralType
{
return new StaticClassStringLiteralType($declaredAtClass);
}

/**
* @psalm-pure
* @template TValue
Expand Down Expand Up @@ -265,9 +292,27 @@ public static function object(string $class, Type ...$templateArguments): NamedO
/**
* @psalm-pure
* @no-named-arguments
* @template TObject of object
* @param class-string<TObject> $declaredAtClass
* @return StaticType<TObject>
* @param class-string $declaredAtClass
*/
public static function self(string $declaredAtClass, Type ...$templateArguments): SelfType
{
return new SelfType($declaredAtClass, $templateArguments);
}

/**
* @psalm-pure
* @no-named-arguments
* @param class-string $declaredAtClass
*/
public static function parent(string $declaredAtClass, Type ...$templateArguments): ParentType
{
return new ParentType($declaredAtClass, $templateArguments);
}

/**
* @psalm-pure
* @no-named-arguments
* @param class-string $declaredAtClass
*/
public static function static(string $declaredAtClass, Type ...$templateArguments): StaticType
{
Expand Down
5 changes: 5 additions & 0 deletions tests/PsalmTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -66,8 +66,13 @@ public static function extractType(Type $_type): mixed
#[TestWith([__DIR__ . '/psalm/NumericType.phpt'])]
#[TestWith([__DIR__ . '/psalm/ObjectShapeType.phpt'])]
#[TestWith([__DIR__ . '/psalm/ObjectType.phpt'])]
#[TestWith([__DIR__ . '/psalm/ParentClassStringLiteralType.phpt'])]
#[TestWith([__DIR__ . '/psalm/ParentType.phpt'])]
#[TestWith([__DIR__ . '/psalm/ResourceType.phpt'])]
#[TestWith([__DIR__ . '/psalm/ScalarType.phpt'])]
#[TestWith([__DIR__ . '/psalm/SelfClassStringLiteralType.phpt'])]
#[TestWith([__DIR__ . '/psalm/SelfType.phpt'])]
#[TestWith([__DIR__ . '/psalm/StaticClassStringLiteralType.phpt'])]
#[TestWith([__DIR__ . '/psalm/StaticType.phpt'])]
#[TestWith([__DIR__ . '/psalm/StringLiteralType.phpt'])]
#[TestWith([__DIR__ . '/psalm/StringType.phpt'])]
Expand Down
9 changes: 9 additions & 0 deletions tests/psalm/ParentClassStringLiteralType.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
--FILE--
<?php

namespace Typhoon\Type;

$_type = PsalmTest::extractType(new ParentClassStringLiteralType(\stdClass::class));
/** @psalm-check-type-exact $_type = \class-string */

--EXPECT--
9 changes: 9 additions & 0 deletions tests/psalm/ParentType.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
--FILE--
<?php

namespace Typhoon\Type;

$_type = PsalmTest::extractType(new ParentType(\stdClass::class));
/** @psalm-check-type-exact $_type = \object */

--EXPECT--
9 changes: 9 additions & 0 deletions tests/psalm/SelfClassStringLiteralType.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
--FILE--
<?php

namespace Typhoon\Type;

$_type = PsalmTest::extractType(new SelfClassStringLiteralType(\stdClass::class));
/** @psalm-check-type-exact $_type = \class-string */

--EXPECT--
9 changes: 9 additions & 0 deletions tests/psalm/SelfType.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
--FILE--
<?php

namespace Typhoon\Type;

$_type = PsalmTest::extractType(new SelfType(\stdClass::class));
/** @psalm-check-type-exact $_type = \object */

--EXPECT--
9 changes: 9 additions & 0 deletions tests/psalm/StaticClassStringLiteralType.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
--FILE--
<?php

namespace Typhoon\Type;

$_type = PsalmTest::extractType(new StaticClassStringLiteralType(\stdClass::class));
/** @psalm-check-type-exact $_type = \class-string */

--EXPECT--
2 changes: 1 addition & 1 deletion tests/psalm/StaticType.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,6 @@
namespace Typhoon\Type;

$_type = PsalmTest::extractType(new StaticType(\stdClass::class));
/** @psalm-check-type-exact $_type = \stdClass */
/** @psalm-check-type-exact $_type = \object */

--EXPECT--

0 comments on commit 7f738d0

Please sign in to comment.