1616use ArrayIterator ;
1717use InvalidArgumentException ;
1818use phpDocumentor \Reflection \Types \Array_ ;
19+ use phpDocumentor \Reflection \Types \Expression_ ;
1920use phpDocumentor \Reflection \Types \ClassString ;
2021use phpDocumentor \Reflection \Types \Collection ;
2122use phpDocumentor \Reflection \Types \Compound ;
@@ -134,9 +135,9 @@ public function resolve(string $type, ?Context $context = null) : Type
134135 $ context = new Context ('' );
135136 }
136137
137- // split the type string into tokens `|`, `?`, `<`, `>`, `,`, `(`, `)[]`, '<', '>' and type names
138+ // split the type string into tokens `|`, `?`, `<`, `>`, `,`, `(`, `)`, ` []`, '<', '>' and type names
138139 $ tokens = preg_split (
139- '/( \\|| \\?|<|>|, ?| \\(| \\)(?: \\[ \\]) +)/ ' ,
140+ '/( \\|| \\?|<|>|&| , ?| \\(| \\)| \\[ \\]+)/ ' ,
140141 $ type ,
141142 -1 ,
142143 PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE
@@ -163,6 +164,7 @@ private function parseTypes(ArrayIterator $tokens, Context $context, int $parser
163164 {
164165 $ types = [];
165166 $ token = '' ;
167+ $ compoundToken = '| ' ;
166168 while ($ tokens ->valid ()) {
167169 $ token = $ tokens ->current ();
168170 if ($ token === null ) {
@@ -171,7 +173,7 @@ private function parseTypes(ArrayIterator $tokens, Context $context, int $parser
171173 );
172174 }
173175
174- if ($ token === '| ' ) {
176+ if ($ token === '| ' || $ token === ' & ' ) {
175177 if (count ($ types ) === 0 ) {
176178 throw new RuntimeException (
177179 'A type is missing before a type separator '
@@ -189,6 +191,7 @@ private function parseTypes(ArrayIterator $tokens, Context $context, int $parser
189191 );
190192 }
191193
194+ $ compoundToken = $ token ;
192195 $ tokens ->next ();
193196 } elseif ($ token === '? ' ) {
194197 if (!in_array ($ parserContext , [
@@ -209,22 +212,16 @@ private function parseTypes(ArrayIterator $tokens, Context $context, int $parser
209212 $ tokens ->next ();
210213 $ type = $ this ->parseTypes ($ tokens , $ context , self ::PARSER_IN_ARRAY_EXPRESSION );
211214
212- $ resolvedType = new Array_ ($ type );
213-
214215 $ token = $ tokens ->current ();
215- // Someone did not properly close their array expression ..
216- if ($ token === null ) {
216+ if ($ token === null ) { // Someone did not properly close their array expression ..
217217 break ;
218218 }
219219
220- // we generate arrays corresponding to the number of '[]' after the ')'
221- $ numberOfArrays = (strlen ($ token ) - 1 ) / 2 ;
222- for ($ i = 0 ; $ i < $ numberOfArrays - 1 ; ++$ i ) {
223- $ resolvedType = new Array_ ($ resolvedType );
224- }
220+ $ tokens ->next ();
221+
222+ $ resolvedType = new Expression_ ($ type );
225223
226224 $ types [] = $ resolvedType ;
227- $ tokens ->next ();
228225 } elseif ($ parserContext === self ::PARSER_IN_ARRAY_EXPRESSION && $ token [0 ] === ') ' ) {
229226 break ;
230227 } elseif ($ token === '< ' ) {
@@ -248,6 +245,16 @@ private function parseTypes(ArrayIterator $tokens, Context $context, int $parser
248245 && ($ token === '> ' || trim ($ token ) === ', ' )
249246 ) {
250247 break ;
248+ } elseif ($ token === self ::OPERATOR_ARRAY ) {
249+ end ($ types );
250+ $ last = key ($ types );
251+ $ lastItem = $ types [$ last ];
252+ if ($ lastItem instanceof Expression_) {
253+ $ lastItem = $ lastItem ->getValueType ();
254+ }
255+ $ types [$ last ] = new Array_ ($ lastItem );
256+
257+ $ tokens ->next ();
251258 } else {
252259 $ type = $ this ->resolveSingleType ($ token , $ context );
253260 $ tokens ->next ();
@@ -259,7 +266,7 @@ private function parseTypes(ArrayIterator $tokens, Context $context, int $parser
259266 }
260267 }
261268
262- if ($ token === '| ' ) {
269+ if ($ token === '| ' || $ token === ' & ' ) {
263270 throw new RuntimeException (
264271 'A type is missing after a type separator '
265272 );
@@ -287,7 +294,7 @@ private function parseTypes(ArrayIterator $tokens, Context $context, int $parser
287294 return $ types [0 ];
288295 }
289296
290- return new Compound ($ types );
297+ return new Compound ($ types, $ compoundToken );
291298 }
292299
293300 /**
@@ -304,8 +311,6 @@ private function resolveSingleType(string $type, Context $context) : object
304311 switch (true ) {
305312 case $ this ->isKeyword ($ type ):
306313 return $ this ->resolveKeyword ($ type );
307- case $ this ->isTypedArray ($ type ):
308- return $ this ->resolveTypedArray ($ type , $ context );
309314 case $ this ->isFqsen ($ type ):
310315 return $ this ->resolveTypedObject ($ type );
311316 case $ this ->isPartialStructuralElementName ($ type ):
@@ -345,18 +350,6 @@ public function addKeyword(string $keyword, string $typeClassName) : void
345350 $ this ->keywords [$ keyword ] = $ typeClassName ;
346351 }
347352
348- /**
349- * Detects whether the given type represents an array.
350- *
351- * @param string $type A relative or absolute type as defined in the phpDocumentor documentation.
352- *
353- * @psalm-pure
354- */
355- private function isTypedArray (string $ type ) : bool
356- {
357- return substr ($ type , -2 ) === self ::OPERATOR_ARRAY ;
358- }
359-
360353 /**
361354 * Detects whether the given type represents a PHPDoc keyword.
362355 *
@@ -391,16 +384,6 @@ private function isFqsen(string $type) : bool
391384 return strpos ($ type , self ::OPERATOR_NAMESPACE ) === 0 ;
392385 }
393386
394- /**
395- * Resolves the given typed array string (i.e. `string[]`) into an Array object with the right types set.
396- *
397- * @psalm-pure
398- */
399- private function resolveTypedArray (string $ type , Context $ context ) : Array_
400- {
401- return new Array_ ($ this ->resolveSingleType (substr ($ type , 0 , -2 ), $ context ));
402- }
403-
404387 /**
405388 * Resolves the given keyword (such as `string`) into a Type object representing that keyword.
406389 *
0 commit comments