← All results

class-string-map<T of X, T> is a Psalm-only dependent generic

Group: Advanced PHPDoc types · Category: ecosystem · File: phpdoc_advanced_psalm_class_string_map.php

It types a map whose keys are class-strings and whose value is an instance of that exact class. Only Psalm models this dependent relationship; other analyzers do not recognize the keyword. This records who parses it at all. References: - Psalm TClassStringMap (class-string-map<T as Foo, T>)

Analyzer results

AnalyzerVersionResultDiagnostics
phan 6.0.7Phan 6.0.7 php-ast version 1.1.3 PHP version used to run Phan: 8.5.9 Unrecognized
phpdoc_advanced_psalm_class_string_map.php:19: Saw possibly unextractable annotation for a fragment of comment '* @param class-string-map<T of \Throwable, T> $map': after class-string, did not see an element name (will guess based on comment order) [PhanUnextractableAnnotationElementName]
phpdoc_advanced_psalm_class_string_map.php:19: Saw a token Phan may have failed to parse after '* @param class-string-map<T of \Throwable, T> $map': after class-string, saw '-' [PhanUnextractableAnnotationSuffix]
  • Recognition: spelling not resolved — reported on declaration line(s) 19
  • Enforcement: 0/1 of the expected violations reported — incidental, since the spelling was not resolved
phpstan 2.2.8PHPStan - PHP Static Analysis Tool 2.2.8 Unrecognized
phpdoc_advanced_psalm_class_string_map.php:19: PHPDoc tag @param has invalid value (class-string-map<T of \Throwable, T> $map): Unexpected token "of", expected '>' at offset 33 on line 2 [identifier=phpDoc.parseError] [reported-from-level=2]
phpdoc_advanced_psalm_class_string_map.php:21: Function Conformance\Tests\PhpdocAdvancedPsalmClassStringMap\acceptsThrowableMap() has parameter $map with no value type specified in iterable type array. [identifier=missingType.iterableValue] [reported-from-level=6]
With strict-rules
phpdoc_advanced_psalm_class_string_map.php:19: PHPDoc tag @param has invalid value (class-string-map<T of \Throwable, T> $map): Unexpected token "of", expected '>' at offset 33 on line 2 [identifier=phpDoc.parseError]
phpdoc_advanced_psalm_class_string_map.php:21: Function Conformance\Tests\PhpdocAdvancedPsalmClassStringMap\acceptsThrowableMap() has parameter $map with no value type specified in iterable type array. [identifier=missingType.iterableValue]
  • Recognition: spelling not resolved — reported on declaration line(s) 19, 21
  • Enforcement: 0/1 of the expected violations reported — incidental, since the spelling was not resolved
psalm 6.16.1Psalm 6.16.1@f1f5de594dc76faf8784e02d3dc4716c91c6f6ac
next: 7.0.0-beta19
Incidental (1/1)
phpdoc_advanced_psalm_class_string_map.php:26: Argument 1 of Conformance\Tests\PhpdocAdvancedPsalmClassStringMap\acceptsThrowableMap expects class-string-map<T as object, T:class-string-map as object>, but array{RuntimeException::class: RuntimeException} provided [InvalidArgument]
phpdoc_advanced_psalm_class_string_map.php:29: Argument 1 of Conformance\Tests\PhpdocAdvancedPsalmClassStringMap\acceptsThrowableMap expects class-string-map<T as object, T:class-string-map as object>, but array{RuntimeException::class: LogicException} provided [InvalidArgument]
  • Recognition: spelling resolved
  • Enforcement: 1/1 of the expected violations reported — incidental, since values the type admits were also rejected on line(s) 26
Expectation diff
Line 26: Expected valid value to be accepted, got ["Argument 1 of Conformance\\Tests\\PhpdocAdvancedPsalmClassStringMap\\acceptsThrowableMap expects class-string-map<T as object, T:class-string-map as object>, but array{RuntimeException::class: RuntimeException} provided [InvalidArgument]"]
mago 1.46.0mago 1.46.0 Unrecognized
phpdoc_advanced_psalm_class_string_map.php:19: Unexpected token in PHPDoc type [invalid-docblock]
phpdoc_advanced_psalm_class_string_map.php:19: Failed to parse function-like docblock comment. [malformed-docblock-comment]
  • Recognition: spelling not resolved — reported on declaration line(s) 19
  • Enforcement: 0/1 of the expected violations reported — incidental, since the spelling was not resolved
mir 0.70.1mir 0.70.1 Incidental (1/1)
phpdoc_advanced_psalm_class_string_map.php:26: InvalidArgument: Argument $map of acceptsThrowableMap() expects 'array<class-string, Conformance\Tests\PhpdocAdvancedPsalmClassStringMap\T>', got 'array<class-string<RuntimeException>, RuntimeException>' [MIR0201]
phpdoc_advanced_psalm_class_string_map.php:29: InvalidArgument: Argument $map of acceptsThrowableMap() expects 'array<class-string, Conformance\Tests\PhpdocAdvancedPsalmClassStringMap\T>', got 'array<class-string<RuntimeException>, LogicException>' [MIR0201]
  • Recognition: spelling resolved
  • Enforcement: 1/1 of the expected violations reported — incidental, since values the type admits were also rejected on line(s) 26
Expectation diff
Line 26: Expected valid value to be accepted, got ["InvalidArgument: Argument $map of acceptsThrowableMap() expects 'array<class-string, Conformance\\Tests\\PhpdocAdvancedPsalmClassStringMap\\T>', got 'array<class-string<RuntimeException>, RuntimeException>' [MIR0201]"]
phpantom 0.9.0phpantom_lsp 0.9.0 Unrecognized
phpdoc_advanced_psalm_class_string_map.php:19: Class 'Conformance\Tests\PhpdocAdvancedPsalmClassStringMap\class-string-map<T of \Throwable, T>' not found [unknown_class]
  • Recognition: spelling not resolved — reported on declaration line(s) 19
  • Enforcement: 0/1 of the expected violations reported — incidental, since the spelling was not resolved
intelephense 1.18.5intelephense 1.18.5 Unrecognized
phpdoc_advanced_psalm_class_string_map.php:19: PHPDoc undefined type 'Conformance\Tests\PhpdocAdvancedPsalmClassStringMap\T'. [P1133]
phpdoc_advanced_psalm_class_string_map.php:19: PHPDoc parse error. Unexpected token. [P1129]
phpdoc_advanced_psalm_class_string_map.php:19: PHPDoc undefined type 'Conformance\Tests\PhpdocAdvancedPsalmClassStringMap\of'. [P1133]
  • Recognition: spelling not resolved — reported on declaration line(s) 19
  • Enforcement: 0/1 of the expected violations reported — incidental, since the spelling was not resolved
phpy 0.2.0phpy 0.2.0 Unrecognized
phpdoc_advanced_psalm_class_string_map.php:19: Use of unknown class: 'Conformance\Tests\PhpdocAdvancedPsalmClassStringMap\class-string-map'
  • Recognition: spelling not resolved — reported on declaration line(s) 19
  • Enforcement: 0/1 of the expected violations reported — incidental, since the spelling was not resolved
qodana 262.8665.325Qodana 262.8665.325 Unrecognized
phpdoc_advanced_psalm_class_string_map.php:19: Argument type does not match the declared [PhpDocSignatureInspection]
phpdoc_advanced_psalm_class_string_map.php:19: Undefined class 'class-string-map' [PhpUndefinedClassInspection]
phpdoc_advanced_psalm_class_string_map.php:19: Undefined class 'T' [PhpUndefinedClassInspection]
  • Recognition: spelling not resolved — reported on declaration line(s) 19
  • Enforcement: 0/1 of the expected violations reported — incidental, since the spelling was not resolved
noverify 0.5.5NoVerify, version 0.5.5: built on: 2025.04.22 14:36:46 OS: r-kuchinskas arm64 Commit: 4774b82f8adc53fbef38f95e97af4b953b4d1529 Unrecognized ⚠ 1 false positive
phpdoc_advanced_psalm_class_string_map.php:12: Class or interface named \Conformance\Tests\PhpdocAdvancedPsalmClassStringMap\class-string-map does not exist [undefinedClass]
phpdoc_advanced_psalm_class_string_map.php:21: param $map miss matched with phpdoc type <<class-string-map<T of \Throwable, T>>> [funcParamTypeMissMatch]
  • Recognition: spelling not resolved — reported on declaration line(s) 21
  • Enforcement: 0/1 of the expected violations reported — incidental, since the spelling was not resolved
  • False positives: line(s) 12
Expectation diff
Line 12: Unexpected errors ["Class or interface named \\Conformance\\Tests\\PhpdocAdvancedPsalmClassStringMap\\class-string-map does not exist [undefinedClass]"]
steins 0.1.5steins 0.1.5 (2026-08-12 revision 39b4cc1) Unrecognized
phpdoc_advanced_psalm_class_string_map.php:19: `@param class-string-map<T of \Throwable, T> $map` does not parse (expected CloseAngle, found Identifier) — the tag declares nothing [phpdoc.unparsable]
  • Recognition: spelling not resolved — reported on declaration line(s) 19
  • Enforcement: 0/1 of the expected violations reported — incidental, since the spelling was not resolved

Notes: Psalm's `T of X` template bound isn't valid inside a plain generic-argument list in steins-phpdoc's grammar, so `class-string-map<T of \Throwable, T>` fails to parse entirely and the whole `@param` drops to no envelope (ADR-0029) — the dependent key-to-value relationship is never checked.

phpstan-strict 2.2.8PHPStan - PHP Static Analysis Tool 2.2.8 Unrecognized
phpdoc_advanced_psalm_class_string_map.php:19: PHPDoc tag @param has invalid value (class-string-map<T of \Throwable, T> $map): Unexpected token "of", expected '>' at offset 33 on line 2 [identifier=phpDoc.parseError]
phpdoc_advanced_psalm_class_string_map.php:21: Function Conformance\Tests\PhpdocAdvancedPsalmClassStringMap\acceptsThrowableMap() has parameter $map with no value type specified in iterable type array. [identifier=missingType.iterableValue]
  • Recognition: spelling not resolved — reported on declaration line(s) 19, 21
  • Enforcement: 0/1 of the expected violations reported — incidental, since the spelling was not resolved
psalm-next 7.0.0-beta19Psalm 7.0.0-beta19@7e751c06a756fa64dc4c759c09fe4a173afcb433 Incidental (1/1)
phpdoc_advanced_psalm_class_string_map.php:26: Argument 1 of Conformance\Tests\PhpdocAdvancedPsalmClassStringMap\acceptsThrowableMap expects class-string-map<T as object, T:class-string-map as object>, but array{RuntimeException::class: RuntimeException} provided [InvalidArgument]
phpdoc_advanced_psalm_class_string_map.php:29: Argument 1 of Conformance\Tests\PhpdocAdvancedPsalmClassStringMap\acceptsThrowableMap expects class-string-map<T as object, T:class-string-map as object>, but array{RuntimeException::class: LogicException} provided [InvalidArgument]
  • Recognition: spelling resolved
  • Enforcement: 1/1 of the expected violations reported — incidental, since values the type admits were also rejected on line(s) 26
Expectation diff
Line 26: Expected valid value to be accepted, got ["Argument 1 of Conformance\\Tests\\PhpdocAdvancedPsalmClassStringMap\\acceptsThrowableMap expects class-string-map<T as object, T:class-string-map as object>, but array{RuntimeException::class: RuntimeException} provided [InvalidArgument]"]

Source

<?php

declare(strict_types=1);

namespace Conformance\Tests\PhpdocAdvancedPsalmClassStringMap;

/**
 * `class-string-map<T of X, T>` is a Psalm-only dependent generic.
 *
 * It types a map whose keys are class-strings and whose value is an instance of
 * that exact class. Only Psalm models this dependent relationship; other
 * analyzers do not recognize the keyword. This records who parses it at all.
 *
 * References:
 * - Psalm TClassStringMap (class-string-map<T as Foo, T>)
 */

/**
 * @param class-string-map<T of \Throwable, T> $map
 */
function acceptsThrowableMap(array $map): void // T: class-string-map<T of \Throwable, T>
{
}

// A class-string key mapped to an instance of that class is valid.
acceptsThrowableMap([\RuntimeException::class => new \RuntimeException()]); // V

// A value that is not an instance of the key class is rejected by Psalm.
acceptsThrowableMap([\RuntimeException::class => new \LogicException()]); // E?: value must be an instance of the class-string key