psalm: Template psalm-throws

I could not find any similar issue. I have a usecase

<?php
/**
 * @template T
 *
 * @psalm-param string|null $nullable
 * @psalm-param T $exception
 *
 * @psalm-throws T
 */
function expect(?string $nullable, Exception $exception) 
{
    if ($nullable === null) {
    	throw $exception;
    }
    
    return $nullable;
}
expect('test', new RuntimeException('Test is null'));

My proposal:

@psalm-throws should take generic parameter same as @psalm-param or @psalm-var.

About this issue

  • Original URL
  • State: closed
  • Created 4 years ago
  • Reactions: 3
  • Comments: 18 (1 by maintainers)

Most upvoted comments

I have use case for this (I initially reported #6098 which was closed as duplicate of this).

Sometimes you want to pass as input the exception you’re going to throw, and in that case it would be nice to now that you’re throwing the same time of exception you’re passing in.

I would like to have this code to actually work

/**
 * @template A
 * @template B
 */
class Either
{
    /**
     * @template E of Throwable
     * @param E $e
     * @return B
     * @throws E
     */
    public function fromRightThrow(Throwable $e)
    {
        return $this->eval(
            /**
             * @param A $_
             * @return B
             * @throws E
             */
            function ($_) use ($e) {
                throw $e;
            },
            /**
             * @param B $b
             * @return B
             */
            fn ($b) => $b
        );
    }
}

That would mean type parameter inference would affect surrounding code (the catch statement).

@orklah so is that snipped now pointing to an potential feature request or is it a bug? Because I still think that using * @psalm-throws IdReferencedEntityNotFoundException<EntityIdClass> should be possible or?

(Using in terms of causing a check.)

Hi, it seems that I’m trying to to something similar, which is also failing. Maybe it’s a potential feature that could be added?

https://psalm.dev/r/ed7ca295c5

<?php

/**
 * @template EntityIdClass
 */
interface IdReferencedEntityNotFoundException extends \Throwable
{
    /**
     * @return ?EntityIdClass
     */
    public function getRequestedId();
}


/**
 * @template EntityIdClass
 * @template EntityClass
 */
interface GenericGetByIdCapableRepository
{
    /**
     * @param  EntityIdClass                                      $id
     * @throws IdReferencedEntityNotFoundException<EntityIdClass>
     * @return EntityClass
     * @psalm-param EntityIdClass $id
     * @psalm-return EntityClass
     */
    public function getById($id);
}

Gives

ERROR: UndefinedDocblockClass - 23:16 - Docblock-defined class, interface or enum named IdReferencedEntityNotFoundException does not exist

I would expect no errors after all.

Thank you!

use @phpstan-throws instead of @throws