|   1:  | <?php declare(strict_types = 1); | 
|   2:  |  | 
|   3:  | namespace PHPStan\Type; | 
|   4:  |  | 
|   5:  | use PHPStan\PhpDocParser\Ast\Type\GenericTypeNode; | 
|   6:  | use PHPStan\PhpDocParser\Ast\Type\IdentifierTypeNode; | 
|   7:  | use PHPStan\PhpDocParser\Ast\Type\TypeNode; | 
|   8:  | use PHPStan\Type\Generic\TemplateTypeVariance; | 
|   9:  | use PHPStan\Type\Traits\LateResolvableTypeTrait; | 
|  10:  | use PHPStan\Type\Traits\NonGeneralizableTypeTrait; | 
|  11:  | use function sprintf; | 
|  12:  |  | 
|  13:  |  | 
|  14:  | final class ValueOfType implements CompoundType, LateResolvableType | 
|  15:  | { | 
|  16:  |  | 
|  17:  | 	use LateResolvableTypeTrait; | 
|  18:  | 	use NonGeneralizableTypeTrait; | 
|  19:  |  | 
|  20:  | 	public function __construct(private Type $type) | 
|  21:  | 	{ | 
|  22:  | 	} | 
|  23:  |  | 
|  24:  | 	public function getReferencedClasses(): array | 
|  25:  | 	{ | 
|  26:  | 		return $this->type->getReferencedClasses(); | 
|  27:  | 	} | 
|  28:  |  | 
|  29:  | 	public function getReferencedTemplateTypes(TemplateTypeVariance $positionVariance): array | 
|  30:  | 	{ | 
|  31:  | 		return $this->type->getReferencedTemplateTypes($positionVariance); | 
|  32:  | 	} | 
|  33:  |  | 
|  34:  | 	public function equals(Type $type): bool | 
|  35:  | 	{ | 
|  36:  | 		return $type instanceof self | 
|  37:  | 			&& $this->type->equals($type->type); | 
|  38:  | 	} | 
|  39:  |  | 
|  40:  | 	public function describe(VerbosityLevel $level): string | 
|  41:  | 	{ | 
|  42:  | 		return sprintf('value-of<%s>', $this->type->describe($level)); | 
|  43:  | 	} | 
|  44:  |  | 
|  45:  | 	public function isResolvable(): bool | 
|  46:  | 	{ | 
|  47:  | 		return !TypeUtils::containsTemplateType($this->type); | 
|  48:  | 	} | 
|  49:  |  | 
|  50:  | 	protected function getResult(): Type | 
|  51:  | 	{ | 
|  52:  | 		if ($this->type->isEnum()->yes()) { | 
|  53:  | 			$valueTypes = []; | 
|  54:  | 			foreach ($this->type->getEnumCases() as $enumCase) { | 
|  55:  | 				$valueType = $enumCase->getBackingValueType(); | 
|  56:  | 				if ($valueType === null) { | 
|  57:  | 					continue; | 
|  58:  | 				} | 
|  59:  |  | 
|  60:  | 				$valueTypes[] = $valueType; | 
|  61:  | 			} | 
|  62:  |  | 
|  63:  | 			return TypeCombinator::union(...$valueTypes); | 
|  64:  | 		} | 
|  65:  |  | 
|  66:  | 		return $this->type->getIterableValueType(); | 
|  67:  | 	} | 
|  68:  |  | 
|  69:  | 	 | 
|  70:  |  | 
|  71:  |  | 
|  72:  | 	public function traverse(callable $cb): Type | 
|  73:  | 	{ | 
|  74:  | 		$type = $cb($this->type); | 
|  75:  |  | 
|  76:  | 		if ($this->type === $type) { | 
|  77:  | 			return $this; | 
|  78:  | 		} | 
|  79:  |  | 
|  80:  | 		return new self($type); | 
|  81:  | 	} | 
|  82:  |  | 
|  83:  | 	public function traverseSimultaneously(Type $right, callable $cb): Type | 
|  84:  | 	{ | 
|  85:  | 		if (!$right instanceof self) { | 
|  86:  | 			return $this; | 
|  87:  | 		} | 
|  88:  |  | 
|  89:  | 		$type = $cb($this->type, $right->type); | 
|  90:  |  | 
|  91:  | 		if ($this->type === $type) { | 
|  92:  | 			return $this; | 
|  93:  | 		} | 
|  94:  |  | 
|  95:  | 		return new self($type); | 
|  96:  | 	} | 
|  97:  |  | 
|  98:  | 	public function toPhpDocNode(): TypeNode | 
|  99:  | 	{ | 
| 100:  | 		return new GenericTypeNode(new IdentifierTypeNode('value-of'), [$this->type->toPhpDocNode()]); | 
| 101:  | 	} | 
| 102:  |  | 
| 103:  | } | 
| 104:  |  |