1

I'm getting used to use psalm, but I'm facing an issue. I already have this structure in C# and it worked out for me. I didn't really get how I could solve this using psalm.

I have a ContextInterface and another implementing it.

interface ContextInterface { public function getProductId(): int; }
interface SingleContextInterface extends ContextInterface { public function getWidth(): int; }

Additionally I have strategy interfaces for them.

/**
 * @template-covariant T as ContextInterface
 * @psalm-immutable
 */
interface CalculatorInterface
{
    /**
     * @psalm-param T $context
     */
    public function getPrice(ContextInterface $context): int;
}

/**
 * @template T as SingleContextInterface
 * @template-extends CalculatorInterface<T>
 * @psalm-immutable
 */
interface SingleDimensionalPriceCalculator extends CalculatorInterface { }

And one class implementing the interface:

/**
 * @template T as SingleContextInterface
 * @template-implements SingleDimensionalPriceCalculator<T>
 * @psalm-immutable
 */
class SingleDimensionCalculator implements SingleDimensionalPriceCalculator
{
    /**
     * @psalm-param SingleContextInterface $context
     */ 
    public function getPrice(ContextInterface $context): int
    {
        $context->getWidth();
        return 1;
    }
    
}

For the getWidth() method call I receive the following error:

ERROR: ImpureMethodCall - 37:19 - Cannot call an possibly-mutating method SingleContextInterface::getWidth from a mutation-free context

The example on psalm.dev

Of course the real case is more complicated and contains more interfaces.

Zoltán Fekete
  • 504
  • 1
  • 6
  • 22

1 Answers1

0

I figured, the problem was that I marked the template on CalculatorInterface as covariant. I can just extend it without, it being covariant.

Example on psalm.dev

Zoltán Fekete
  • 504
  • 1
  • 6
  • 22
  • You also dropped `@immutable`, so it's quite natural that you don't get mutability errors anymore – weirdan Jun 11 '21 at 15:12
  • Adding `@psalm-immutable` on `SingleContextInterface` would fix that as it would mark `getWidth()` as pure. – weirdan Jun 11 '21 at 15:15