Skip to content

Commit cd2e6bd

Browse files
committed
fix: class-string with template contains non-object type
1 parent f1f5de5 commit cd2e6bd

2 files changed

Lines changed: 46 additions & 0 deletions

File tree

src/Psalm/Internal/Type/TypeParser.php

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -458,6 +458,7 @@ private static function getGenericParamClass(
458458
Union &$as,
459459
string $defining_class,
460460
bool $from_docblock = false,
461+
bool $allow_skip_invalid_type = false,
461462
): TTemplateParamClass {
462463
if ($as->hasMixed()) {
463464
return new TTemplateParamClass(
@@ -469,6 +470,8 @@ private static function getGenericParamClass(
469470
);
470471
}
471472

473+
$last_invalid_type = null;
474+
472475
foreach ($as->getAtomicTypes() as $t) {
473476
if ($t instanceof TObject) {
474477
return new TTemplateParamClass(
@@ -518,6 +521,11 @@ private static function getGenericParamClass(
518521
}
519522

520523
if (!$t instanceof TNamedObject) {
524+
if ($allow_skip_invalid_type) {
525+
$last_invalid_type = $t;
526+
continue;
527+
}
528+
521529
throw new TypeParseTreeException(
522530
'Invalid templated classname \'' . $t->getId() . '\'',
523531
);
@@ -532,6 +540,12 @@ private static function getGenericParamClass(
532540
);
533541
}
534542

543+
if ($last_invalid_type !== null) {
544+
throw new TypeParseTreeException(
545+
'Invalid templated classname \'' . $t->getId() . '\'',
546+
);
547+
}
548+
535549
throw new LogicException('Should never get here');
536550
}
537551

@@ -766,6 +780,7 @@ private static function getTypeFromGenericTree(
766780
$template_type_map[$class_name][$first_class],
767781
$first_class,
768782
$from_docblock,
783+
true,
769784
);
770785
}
771786

tests/ClassLikeStringTest.php

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -911,6 +911,26 @@ function test(string $class): string {
911911
return $class;
912912
}
913913
914+
$r = test(A::class);',
915+
'assertions' => [
916+
'$r' => 'class-string<A>',
917+
],
918+
],
919+
'classStringOfUnionTypeArrayOrObject' => [
920+
'code' => '<?php
921+
922+
class A {}
923+
924+
/**
925+
* @template T as array|object
926+
*
927+
* @param class-string<T> $class
928+
* @return class-string<T>
929+
*/
930+
function test(string $class): string {
931+
return $class;
932+
}
933+
914934
$r = test(A::class);',
915935
'assertions' => [
916936
'$r' => 'class-string<A>',
@@ -1052,6 +1072,17 @@ function foo(string $s) : string {
10521072
}',
10531073
'error_message' => 'InvalidReturnStatement',
10541074
],
1075+
'genericTypeWithoutAnyValidType' => [
1076+
'code' => '<?php
1077+
/**
1078+
* @param class-string<T> $s
1079+
* @template T as string|bool
1080+
*/
1081+
function foo(string $s) : string {
1082+
return $s;
1083+
}',
1084+
'error_message' => 'InvalidDocblock',
1085+
],
10551086
];
10561087
}
10571088
}

0 commit comments

Comments
 (0)