@@ -199,32 +199,82 @@ private function collectTypeAliases(\ReflectionClass $reflection, TypeContext $t
199
199
}
200
200
201
201
$ aliases = [];
202
- foreach ($ this ->getPhpDocNode ($ rawDocNode )->getTagsByName ('@psalm-type ' ) + $ this ->getPhpDocNode ($ rawDocNode )->getTagsByName ('@phpstan-type ' ) as $ tag ) {
203
- if (!$ tag ->value instanceof TypeAliasTagValueNode) {
202
+ $ resolvedAliases = [];
203
+
204
+ foreach ($ this ->getPhpDocNode ($ rawDocNode )->getTagsByName ('@psalm-import-type ' ) + $ this ->getPhpDocNode ($ rawDocNode )->getTagsByName ('@phpstan-import-type ' ) as $ tag ) {
205
+ if (!$ tag ->value instanceof TypeAliasImportTagValueNode) {
204
206
continue ;
205
207
}
206
208
207
- $ aliases [$ tag ->value ->alias ] = $ this ->stringTypeResolver ->resolve ((string ) $ tag ->value ->type , $ typeContext );
209
+ /** @var ObjectType $importedFromType */
210
+ $ importedFromType = $ this ->stringTypeResolver ->resolve ((string ) $ tag ->value ->importedFrom , $ typeContext );
211
+ $ importedFromContext = $ this ->createFromClassName ($ importedFromType ->getClassName ());
212
+
213
+ $ typeAlias = $ importedFromContext ->typeAliases [$ tag ->value ->importedAlias ] ?? null ;
214
+ if (!$ typeAlias ) {
215
+ throw new LogicException (\sprintf ('Cannot find any "%s" type alias in "%s". ' , $ tag ->value ->importedAlias , $ importedFromType ->getClassName ()));
216
+ }
217
+
218
+ $ resolvedAliases [$ tag ->value ->importedAs ?? $ tag ->value ->importedAlias ] = $ typeAlias ;
208
219
}
209
220
210
- foreach ($ this ->getPhpDocNode ($ rawDocNode )->getTagsByName ('@psalm-import- type ' ) + $ this ->getPhpDocNode ($ rawDocNode )->getTagsByName ('@phpstan-import -type ' ) as $ tag ) {
211
- if (!$ tag ->value instanceof TypeAliasImportTagValueNode ) {
221
+ foreach ($ this ->getPhpDocNode ($ rawDocNode )->getTagsByName ('@psalm-type ' ) + $ this ->getPhpDocNode ($ rawDocNode )->getTagsByName ('@phpstan-type ' ) as $ tag ) {
222
+ if (!$ tag ->value instanceof TypeAliasTagValueNode ) {
212
223
continue ;
213
224
}
214
225
215
- /** @var ObjectType $importedType */
216
- $ importedType = $ this ->stringTypeResolver ->resolve ((string ) $ tag ->value ->importedFrom , $ typeContext );
217
- $ importedTypeContext = $ this ->createFromClassName ($ importedType ->getClassName ());
226
+ $ aliases [$ tag ->value ->alias ] = (string ) $ tag ->value ->type ;
227
+ }
218
228
219
- $ typeAlias = $ importedTypeContext ->typeAliases [$ tag ->value ->importedAlias ] ?? null ;
220
- if (!$ typeAlias ) {
221
- throw new LogicException (\sprintf ('Cannot find any "%s" type alias in "%s". ' , $ tag ->value ->importedAlias , $ importedType ->getClassName ()));
229
+ return $ this ->resolveTypeAliases ($ aliases , $ resolvedAliases , $ typeContext );
230
+ }
231
+
232
+ /**
233
+ * @param array<string, string> $toResolve
234
+ * @param array<string, Type> $resolved
235
+ *
236
+ * @return array<string, Type>
237
+ */
238
+ private function resolveTypeAliases (array $ toResolve , array $ resolved , TypeContext $ typeContext ): array
239
+ {
240
+ if ([] === $ toResolve ) {
241
+ return [];
242
+ }
243
+
244
+ $ typeContext = new TypeContext (
245
+ $ typeContext ->calledClassName ,
246
+ $ typeContext ->declaringClassName ,
247
+ $ typeContext ->namespace ,
248
+ $ typeContext ->uses ,
249
+ $ typeContext ->templates ,
250
+ $ typeContext ->typeAliases + $ resolved ,
251
+ );
252
+
253
+ $ succeeded = false ;
254
+ $ lastFailure = null ;
255
+ $ lastFailingAlias = null ;
256
+
257
+ foreach ($ toResolve as $ alias => $ type ) {
258
+ try {
259
+ $ resolved [$ alias ] = $ this ->stringTypeResolver ->resolve ($ type , $ typeContext );
260
+ unset($ toResolve [$ alias ]);
261
+ $ succeeded = true ;
262
+ } catch (UnsupportedException $ lastFailure ) {
263
+ $ lastFailingAlias = $ alias ;
222
264
}
265
+ }
266
+
267
+ // nothing has succeeded, the result won't be different from the
268
+ // previous one, we can stop here.
269
+ if (!$ succeeded ) {
270
+ throw new LogicException (\sprintf ('Cannot resolve "%s" type alias. ' , $ lastFailingAlias ), 0 , $ lastFailure );
271
+ }
223
272
224
- $ aliases [$ tag ->value ->importedAs ?? $ tag ->value ->importedAlias ] = $ typeAlias ;
273
+ if ([] !== $ toResolve ) {
274
+ return $ this ->resolveTypeAliases ($ toResolve , $ resolved , $ typeContext );
225
275
}
226
276
227
- return $ aliases ;
277
+ return $ resolved ;
228
278
}
229
279
230
280
private function getPhpDocNode (string $ rawDocNode ): PhpDocNode
0 commit comments