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

Sorting of @psalm-return intersection type may lead to detecting mixed instead of correct type #1677

Closed
Ocramius opened this issue May 24, 2019 · 2 comments
Labels

Comments

@Ocramius
Copy link
Contributor

Ocramius commented May 24, 2019

I am very sorry for reporting this one without a shorter reproduce scenario, but it seems to be a combination of sorting, inheritance priority, and class detection. I'll try putting the relevant code in here, but the issue is extracted from following code: Ocramius/ProxyManager@5357b03

<?php

class MyProxiedClass
{
    /** @return string */
    public function sayHello()
    {
        return 'Hello!';
    }
}

/**
 * @psalm-template DecoratedClassName of object
 */
interface ProxyInterface
{
}

interface LazyLoadingInterface extends ProxyInterface
{
    public function initializeProxy() : bool;
}

/**
 * @psalm-template WrappedValueHolderType of object
 */
interface ValueHolderInterface extends ProxyInterface
{
    /**
     * @psalm-return WrappedValueHolderType|null
     */
    public function getWrappedValueHolderValue() : ?object;
}

interface VirtualProxyInterface extends LazyLoadingInterface, ValueHolderInterface
{
}


class LazyLoadingValueHolderFactory
{

    /**
     * @param array<string, mixed> $proxyOptions
     *
     * @psalm-template RealObjectType of object
     *
     * @psalm-param class-string<RealObjectType> $className
     *
     * @psalm-return RealObjectType&VirtualProxyInterface&ValueHolderInterface<RealObjectType>
     * @disabled-psalm-return RealObjectType&ValueHolderInterface<RealObjectType>&VirtualProxyInterface
     */
    public function createProxy(
        string $className,
        Closure $initializer,
        array $proxyOptions = []
    ) : VirtualProxyInterface {
        // ... snip ... 
    }
}

$valueHolder = (new LazyLoadingValueHolderFactory())
    ->createProxy(MyProxiedClass::class, function () {});

$valueHolder->initializeProxy();

$wrappedValue = $valueHolder->getWrappedValueHolderValue();

assert(null !== $wrappedValue);

echo $wrappedValue->sayHello();

https://psalm.dev/r/8a169678e8

$wrappedValue seems to be inferred to mixed when using this code, while using the second @disabled-psalm-return, it infers MyProxiedClass:

-     * @psalm-return RealObjectType&VirtualProxyInterface&ValueHolderInterface<RealObjectType>
-     * @disabled-psalm-return RealObjectType&ValueHolderInterface<RealObjectType>&VirtualProxyInterface
+     * @psalm-return RealObjectType&ValueHolderInterface<RealObjectType>&VirtualProxyInterface
@muglug
Copy link
Collaborator

muglug commented May 25, 2019

I think this is caused by #1686 - you have an unparameterised VirtualProxyInterface with a method getWrappedValueHolderValue that returns object|null, and that object supersedes the return type of the parameterised ValueHolderInterface

@muglug
Copy link
Collaborator

muglug commented May 26, 2019

Fixed by 8b9de8b

@muglug muglug closed this as completed May 26, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants