@@ -18,6 +18,14 @@ final class ConditionalType implements CompoundType, LateResolvableType
1818 use LateResolvableTypeTrait;
1919 use NonGeneralizableTypeTrait;
2020
21+ private ?Type $ normalizedIf = null ;
22+ 23+ private ?Type $ normalizedElse = null ;
24+ 25+ private ?Type $ subjectWithTargetIntersectedType = null ;
26+ 27+ private ?Type $ subjectWithTargetRemovedType = null ;
28+ 2129 public function __construct (
2230 private Type $ subject ,
2331 private Type $ target ,
@@ -113,37 +121,33 @@ protected function getResult(): Type
113121 {
114122 $ isSuperType = $ this ->target ->isSuperTypeOf ($ this ->subject );
115123
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- 128124 if ($ isSuperType ->yes ()) {
129- return $ yesType ();
125+ return ! $ this -> negated ? $ this -> getNormalizedIf () : $ this -> getNormalizedElse ();
130126 }
131127
132128 if ($ isSuperType ->no ()) {
133- return $ noType ();
129+ return ! $ this -> negated ? $ this -> getNormalizedElse () : $ this -> getNormalizedIf ();
134130 }
135131
136- return TypeCombinator::union ($ yesType (), $ noType ());
132+ return TypeCombinator::union (
133+ $ this ->getNormalizedIf (),
134+ $ this ->getNormalizedElse (),
135+ );
137136 }
138137
139138 public function traverse (callable $ cb ): Type
140139 {
141140 $ subject = $ cb ($ this ->subject );
142141 $ 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+ ) {
147151 return $ this ;
148152 }
149153
@@ -158,10 +162,15 @@ public function traverseSimultaneously(Type $right, callable $cb): Type
158162
159163 $ subject = $ cb ($ this ->subject , $ right ->subject );
160164 $ 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+ ) {
165174 return $ this ;
166175 }
167176
@@ -193,4 +202,34 @@ public static function __set_state(array $properties): Type
193202 );
194203 }
195204
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+ 196235}
0 commit comments