1: <?php declare(strict_types = 1);
2:
3: namespace PHPStan\Type;
4:
5: use PHPStan\ShouldNotHappenException;
6: use PHPStan\TrinaryLogic;
7: use function array_map;
8: use function array_merge;
9: use function array_unique;
10: use function array_values;
11:
12: /**
13: * @api
14: */
15: final class IsSuperTypeOfResult
16: {
17:
18: /**
19: * @api
20: * @param list<string> $reasons
21: */
22: public function __construct(
23: public readonly TrinaryLogic $result,
24: public readonly array $reasons,
25: )
26: {
27: }
28:
29: /**
30: * @phpstan-assert-if-true =false $this->no()
31: * @phpstan-assert-if-true =false $this->maybe()
32: */
33: public function yes(): bool
34: {
35: return $this->result->yes();
36: }
37:
38: /**
39: * @phpstan-assert-if-true =false $this->no()
40: * @phpstan-assert-if-true =false $this->yes()
41: */
42: public function maybe(): bool
43: {
44: return $this->result->maybe();
45: }
46:
47: /**
48: * @phpstan-assert-if-true =false $this->maybe()
49: * @phpstan-assert-if-true =false $this->yes()
50: */
51: public function no(): bool
52: {
53: return $this->result->no();
54: }
55:
56: public static function createYes(): self
57: {
58: return new self(TrinaryLogic::createYes(), []);
59: }
60:
61: /**
62: * @param list<string> $reasons
63: */
64: public static function createNo(array $reasons = []): self
65: {
66: return new self(TrinaryLogic::createNo(), $reasons);
67: }
68:
69: public static function createMaybe(): self
70: {
71: return new self(TrinaryLogic::createMaybe(), []);
72: }
73:
74: public static function createFromBoolean(bool $value): self
75: {
76: return new self(TrinaryLogic::createFromBoolean($value), []);
77: }
78:
79: public function toAcceptsResult(): AcceptsResult
80: {
81: return new AcceptsResult($this->result, $this->reasons);
82: }
83:
84: public function and(self ...$others): self
85: {
86: $results = [];
87: $reasons = [];
88: foreach ($others as $other) {
89: $results[] = $other->result;
90: $reasons[] = $other->reasons;
91: }
92:
93: return new self(
94: $this->result->and(...$results),
95: array_values(array_unique(array_merge($this->reasons, ...$reasons))),
96: );
97: }
98:
99: public function or(self ...$others): self
100: {
101: $results = [];
102: $reasons = [];
103: foreach ($others as $other) {
104: $results[] = $other->result;
105: $reasons[] = $other->reasons;
106: }
107:
108: return new self(
109: $this->result->or(...$results),
110: array_values(array_unique(array_merge($this->reasons, ...$reasons))),
111: );
112: }
113:
114: /**
115: * @param callable(string): string $cb
116: */
117: public function decorateReasons(callable $cb): self
118: {
119: $reasons = [];
120: foreach ($this->reasons as $reason) {
121: $reasons[] = $cb($reason);
122: }
123:
124: return new self($this->result, $reasons);
125: }
126:
127: public static function extremeIdentity(self ...$operands): self
128: {
129: if ($operands === []) {
130: throw new ShouldNotHappenException();
131: }
132:
133: $result = TrinaryLogic::extremeIdentity(...array_map(static fn (self $result) => $result->result, $operands));
134:
135: return new self($result, self::mergeReasons($operands));
136: }
137:
138: public static function maxMin(self ...$operands): self
139: {
140: if ($operands === []) {
141: throw new ShouldNotHappenException();
142: }
143:
144: $result = TrinaryLogic::maxMin(...array_map(static fn (self $result) => $result->result, $operands));
145:
146: return new self($result, self::mergeReasons($operands));
147: }
148:
149: public function negate(): self
150: {
151: return new self($this->result->negate(), $this->reasons);
152: }
153:
154: public function describe(): string
155: {
156: return $this->result->describe();
157: }
158:
159: /**
160: * @param array<self> $operands
161: *
162: * @return list<string>
163: */
164: private static function mergeReasons(array $operands): array
165: {
166: $reasons = [];
167: foreach ($operands as $operand) {
168: foreach ($operand->reasons as $reason) {
169: $reasons[] = $reason;
170: }
171: }
172:
173: return array_values(array_unique($reasons));
174: }
175:
176: }
177: