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: public IdentifierTypeNode $type;
20:
21: /** @var TypeNode[] */
22: public array $genericTypes;
23:
24: /** @var (self::VARIANCE_*)[] */
25: public array $variances;
26:
27: /**
28: * @param TypeNode[] $genericTypes
29: * @param (self::VARIANCE_*)[] $variances
30: */
31: public function __construct(IdentifierTypeNode $type, array $genericTypes, array $variances = [])
32: {
33: $this->type = $type;
34: $this->genericTypes = $genericTypes;
35: $this->variances = $variances;
36: }
37:
38:
39: public function __toString(): string
40: {
41: $genericTypes = [];
42:
43: foreach ($this->genericTypes as $index => $type) {
44: $variance = $this->variances[$index] ?? self::VARIANCE_INVARIANT;
45: if ($variance === self::VARIANCE_INVARIANT) {
46: $genericTypes[] = (string) $type;
47: } elseif ($variance === self::VARIANCE_BIVARIANT) {
48: $genericTypes[] = '*';
49: } else {
50: $genericTypes[] = sprintf('%s %s', $variance, $type);
51: }
52: }
53:
54: return $this->type . '<' . implode(', ', $genericTypes) . '>';
55: }
56:
57: }
58: