@@ -18,6 +18,14 @@ final class ConditionalType implements CompoundType, LateResolvableType
18
18
use LateResolvableTypeTrait;
19
19
use NonGeneralizableTypeTrait;
20
20
21
+ private ?Type $ normalizedIf = null ;
22
+
23
+ private ?Type $ normalizedElse = null ;
24
+
25
+ private ?Type $ subjectWithTargetIntersectedType = null ;
26
+
27
+ private ?Type $ subjectWithTargetRemovedType = null ;
28
+
21
29
public function __construct (
22
30
private Type $ subject ,
23
31
private Type $ target ,
@@ -113,37 +121,33 @@ protected function getResult(): Type
113
121
{
114
122
$ isSuperType = $ this ->target ->isSuperTypeOf ($ this ->subject );
115
123
116
- $ intersectedType = TypeCombinator::intersect ($ this ->subject , $ this ->target );
117
- $ removedType = TypeCombinator::remove ($ this ->subject , $ this ->target );
118
-
119
- $ yesType = fn () => TypeTraverser::map (
120
- !$ this ->negated ? $ this ->if : $ this ->else ,
121
- fn (Type $ type , callable $ traverse ) => $ type === $ this ->subject ? (!$ this ->negated ? $ intersectedType : $ removedType ) : $ traverse ($ type ),
122
- );
123
- $ noType = fn () => TypeTraverser::map (
124
- !$ this ->negated ? $ this ->else : $ this ->if ,
125
- fn (Type $ type , callable $ traverse ) => $ type === $ this ->subject ? (!$ this ->negated ? $ removedType : $ intersectedType ) : $ traverse ($ type ),
126
- );
127
-
128
124
if ($ isSuperType ->yes ()) {
129
- return $ yesType ();
125
+ return ! $ this -> negated ? $ this -> getNormalizedIf () : $ this -> getNormalizedElse ();
130
126
}
131
127
132
128
if ($ isSuperType ->no ()) {
133
- return $ noType ();
129
+ return ! $ this -> negated ? $ this -> getNormalizedElse () : $ this -> getNormalizedIf ();
134
130
}
135
131
136
- return TypeCombinator::union ($ yesType (), $ noType ());
132
+ return TypeCombinator::union (
133
+ $ this ->getNormalizedIf (),
134
+ $ this ->getNormalizedElse (),
135
+ );
137
136
}
138
137
139
138
public function traverse (callable $ cb ): Type
140
139
{
141
140
$ subject = $ cb ($ this ->subject );
142
141
$ target = $ cb ($ this ->target );
143
- $ if = $ cb ($ this ->if );
144
- $ else = $ cb ($ this ->else );
145
-
146
- if ($ this ->subject === $ subject && $ this ->target === $ target && $ this ->if === $ if && $ this ->else === $ else ) {
142
+ $ if = $ cb ($ this ->getNormalizedIf ());
143
+ $ else = $ cb ($ this ->getNormalizedElse ());
144
+
145
+ if (
146
+ $ this ->subject === $ subject
147
+ && $ this ->target === $ target
148
+ && $ this ->getNormalizedIf () === $ if
149
+ && $ this ->getNormalizedElse () === $ else
150
+ ) {
147
151
return $ this ;
148
152
}
149
153
@@ -158,10 +162,15 @@ public function traverseSimultaneously(Type $right, callable $cb): Type
158
162
159
163
$ subject = $ cb ($ this ->subject , $ right ->subject );
160
164
$ target = $ cb ($ this ->target , $ right ->target );
161
- $ if = $ cb ($ this ->if , $ right ->if );
162
- $ else = $ cb ($ this ->else , $ right ->else );
163
-
164
- if ($ this ->subject === $ subject && $ this ->target === $ target && $ this ->if === $ if && $ this ->else === $ else ) {
165
+ $ if = $ cb ($ this ->getNormalizedIf (), $ right ->getNormalizedIf ());
166
+ $ else = $ cb ($ this ->getNormalizedElse (), $ right ->getNormalizedElse ());
167
+
168
+ if (
169
+ $ this ->subject === $ subject
170
+ && $ this ->target === $ target
171
+ && $ this ->getNormalizedIf () === $ if
172
+ && $ this ->getNormalizedElse () === $ else
173
+ ) {
165
174
return $ this ;
166
175
}
167
176
@@ -193,4 +202,34 @@ public static function __set_state(array $properties): Type
193
202
);
194
203
}
195
204
205
+ private function getNormalizedIf (): Type
206
+ {
207
+ return $ this ->normalizedIf ??= TypeTraverser::map (
208
+ $ this ->if ,
209
+ fn (Type $ type , callable $ traverse ) => $ type === $ this ->subject
210
+ ? (!$ this ->negated ? $ this ->getSubjectWithTargetIntersectedType () : $ this ->getSubjectWithTargetRemovedType ())
211
+ : $ traverse ($ type ),
212
+ );
213
+ }
214
+
215
+ private function getNormalizedElse (): Type
216
+ {
217
+ return $ this ->normalizedElse ??= TypeTraverser::map (
218
+ $ this ->else ,
219
+ fn (Type $ type , callable $ traverse ) => $ type === $ this ->subject
220
+ ? (!$ this ->negated ? $ this ->getSubjectWithTargetRemovedType () : $ this ->getSubjectWithTargetIntersectedType ())
221
+ : $ traverse ($ type ),
222
+ );
223
+ }
224
+
225
+ private function getSubjectWithTargetIntersectedType (): Type
226
+ {
227
+ return $ this ->subjectWithTargetIntersectedType ??= TypeCombinator::intersect ($ this ->subject , $ this ->target );
228
+ }
229
+
230
+ private function getSubjectWithTargetRemovedType (): Type
231
+ {
232
+ return $ this ->subjectWithTargetRemovedType ??= TypeCombinator::remove ($ this ->subject , $ this ->target );
233
+ }
234
+
196
235
}
0 commit comments