Elao/PhpEnums

Pslam errors with FlagBag

Opened this issue · 11 comments

I have some errors when I use the FlagBag class and test within Psalm.

Example:

namespace App\Enum;

enum Permissions: int
{
    case Execute = 1 << 0;
    case Write = 1 << 1;
    case Read = 1 << 2;
}

I then use this enumeration within FlagBag:

$flagBag = FlagBag::from(Permissions::class);

Pslam report this error:

ERROR: InvalidArgument - Argument 1 of Elao\Enum\FlagBag::from expects Elao\Enum\T|class-string<Elao\Enum\T>, App\Enum\Permissions::class provided (see https://psalm.dev/004)
        FlagBag::from(Permissions::class);

We have annoted the Permissions class ?

does adding:

 * @template T of \BackedEnum

to the FlagBag::from method solves this?

Yes, with this change, Pslam does not more complain about invalid argument.

PR welcomed then :)

Fixed in #193

Hello,

I open this error again because Pslam complains about the following code:

private function getDefaultPermissions(): FlagBag
{
    return FlagBag::from(Permissions::Execute , Permissions::Write, Permissions::Read);
}

Argument 2 of Elao\Enum\FlagBag::from expects Elao\Enum\T, but enum(App\Enum\Permissions::Execute) provided (see https://psalm.dev/004)

Argument 3 of Elao\Enum\FlagBag::from expects Elao\Enum\T, but enum(App\Enum\Permissions::SHOW) provided (see https://psalm.dev/004)

I have modified the from function with this annotation:

/**
  * @template E of \BackedEnum
  * @param class-string<E>|E $enumOrType
  * @param E ...$flags
  * @return FlagBag<E>
  */
public static function from(string|\BackedEnum $enumOrType, \BackedEnum ...$flags): static
{
    //...
}

And it work without error.

It seems the suggested code triggers an issue with PHPStan :

 ------ -----------------------------------------------------------------------------------------------------------------------------
  Line   FlagBag.php
 ------ -----------------------------------------------------------------------------------------------------------------------------
  90     PHPDoc tag @return with type Elao\Enum\FlagBag<E of BackedEnum> is incompatible with native type static(Elao\Enum\FlagBag<T
         of BackedEnum>).
 ------ -----------------------------------------------------------------------------------------------------------------------------

OK. I tested with a new specific PHPStan annotation and it's work for both (PHPStan and Pslam):

/**
 * @param class-string<T>|T $enumOrType
 * 
 * @phpstan-return FlagBag<T>
 *
 * @psalm-template E of \BackedEnum
 * @psalm-param E ...$flags
 * @psalm-return FlagBag<E>
 */
public static function from(string|\BackedEnum $enumOrType, \BackedEnum ...$flags): static
{
    // ...
}

Any news about this ?

Thanks

Does

/**
 * @param class-string<T>|T $enumOrType
 * @param T ...$flags
 *
 * @return FlagBag<T>
 */
public static function from(string|\BackedEnum $enumOrType, \BackedEnum ...$flags): static
{
    // ...
}

work? I don't get why we should add another generic type E (nor specific annotations)

It is not working for me. I tried with the following annotations (using a new named template):

/**
  * @template E of \BackedEnum
  *
  * @param class-string<E> $enumType
  *
  * @return FlagBag<E>
  */
public static function fromAll(string $enumType): FlagBag
{
    // ...
}

And it's working! I do the same for the from function:

/**
  * @template E of \BackedEnum
  * 
  * @param class-string<E>|E $enumOrType
  * @param E ...$flags
  * 
  * @return FlagBag<E>
  */
public static function from(string|\BackedEnum $enumOrType, \BackedEnum ...$flags): static
{
    // ...
}

Great news! Would you be up to provide the PR?