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