Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

class-string-map is not working as documented #10095

Closed
stof opened this issue Aug 9, 2023 · 4 comments
Closed

class-string-map is not working as documented #10095

stof opened this issue Aug 9, 2023 · 4 comments

Comments

@stof
Copy link
Contributor

stof commented Aug 9, 2023

The documentation shows class-string-map<T of Foo, SomethingBasedOn<T>> while the working syntax is class-string-map<T as Foo, SomethingBasedOn<T>>. It looks like of does not work there, only as (unlike in @template).

@psalm-github-bot
Copy link

Hey @stof, can you reproduce the issue on https://psalm.dev ?

@stof
Copy link
Contributor Author

stof commented Aug 9, 2023

see https://psalm.dev/r/6f7e81fe99 for a reproducer, which is literally a copy-paste of the example in the documentation of class-string-map

@psalm-github-bot
Copy link

I found these snippets:

https://psalm.dev/r/6f7e81fe99
<?php

/**
 * @psalm-consistent-constructor
 */
class Foo {}

/**
 * @psalm-consistent-constructor
 */
class Bar extends Foo {}

class A {
  /** @var class-string-map<T of Foo, T> */
  private static array $map = [];

  /**
   * @template U of Foo
   * @param class-string<U> $class
   * @return U
   */
  public static function get(string $class) : Foo {
    if (isset(self::$map[$class])) {
      return self::$map[$class];
    }

    self::$map[$class] = new $class();
    return self::$map[$class];
  }
}

$foo = A::get(Foo::class);
$bar = A::get(Bar::class);

/** @psalm-trace $foo */; // Foo
/** @psalm-trace $bar */; // Bar
Psalm output (using commit 73ebe22):

INFO: Trace - 35:25 - $foo: Foo

INFO: Trace - 36:25 - $bar: Bar

ERROR: UndefinedDocblockClass - 15:18 - Docblock-defined class, interface or enum named T does not exist

ERROR: InvalidReturnStatement - 24:14 - The inferred type 'T' does not match the declared return type 'U:fn-a::get as Foo' for A::get

ERROR: PropertyTypeCoercion - 27:5 - A::$map expects 'class-string-map<TofFoo as object, T>',  parent type 'class-string-map<TofFoo as object, T|(TofFoo:class-string-map as object)>' provided

ERROR: InvalidReturnStatement - 28:12 - The inferred type 'T|(U:fn-a::get as Foo)' does not match the declared return type 'U:fn-a::get as Foo' for A::get

ERROR: InvalidReturnType - 20:14 - The declared return type 'U:fn-a::get as Foo' for A::get is incorrect, got 'T|(U:fn-a::get as Foo)'

ERROR: UndefinedDocblockClass - 15:3 - Docblock-defined class, interface or enum named T does not exist

@weirdan
Copy link
Collaborator

weirdan commented Feb 10, 2024

Fixed in #10326

@weirdan weirdan closed this as completed Feb 10, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants