1: <?php declare(strict_types = 1);
2:
3: namespace PHPStan\PhpDocParser\Ast\Type;
4:
5: use PHPStan\PhpDocParser\Ast\NodeAttributes;
6: use function implode;
7: use function sprintf;
8:
9: class GenericTypeNode implements TypeNode
10: {
11:
12: public const VARIANCE_INVARIANT = 'invariant';
13: public const VARIANCE_COVARIANT = 'covariant';
14: public const VARIANCE_CONTRAVARIANT = 'contravariant';
15: public const VARIANCE_BIVARIANT = 'bivariant';
16:
17: use NodeAttributes;
18:
19: /** @var IdentifierTypeNode */
20: public $type;
21:
22: /** @var TypeNode[] */
23: public $genericTypes;
24:
25: /** @var (self::VARIANCE_*)[] */
26: public $variances;
27:
28: /**
29: * @param TypeNode[] $genericTypes
30: * @param (self::VARIANCE_*)[] $variances
31: */
32: public function __construct(IdentifierTypeNode $type, array $genericTypes, array $variances = [])
33: {
34: $this->type = $type;
35: $this->genericTypes = $genericTypes;
36: $this->variances = $variances;
37: }
38:
39:
40: public function __toString(): string
41: {
42: $genericTypes = [];
43:
44: foreach ($this->genericTypes as $index => $type) {
45: $variance = $this->variances[$index] ?? self::VARIANCE_INVARIANT;
46: if ($variance === self::VARIANCE_INVARIANT) {
47: $genericTypes[] = (string) $type;
48: } elseif ($variance === self::VARIANCE_BIVARIANT) {
49: $genericTypes[] = '*';
50: } else {
51: $genericTypes[] = sprintf('%s %s', $variance, $type);
52: }
53: }
54:
55: return $this->type . '<' . implode(', ', $genericTypes) . '>';
56: }
57:
58: }
59: