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 Was Not found" For Intersection Type #2057

Open
XedinUnknown opened this issue Oct 6, 2024 · 4 comments · May be fixed by #2058
Open

"Class Was Not found" For Intersection Type #2057

XedinUnknown opened this issue Oct 6, 2024 · 4 comments · May be fixed by #2058
Labels
bug Something isn't working

Comments

@XedinUnknown
Copy link

  • Larastan Version: 2.9.8
  • Laravel Version: 10.48.22

Description

As described in phpstan/phpstan#11812, there's a "class was not found" error for something that in fact an intersection type, and it only happens in some place and not another seemingly very similar place. Here's the complete output:

 -- ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 
     Error
 -- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------   
     Internal error: Class Domain\Shared\Collections\TreeLikeCollectionInterface&Illuminate\Database\Eloquent\Collection was not found while trying to analyse it - discovering symbols is probably not configured properly. while    
     analysing file /var/www/html/src/Domain/Programming/Models/Bodypart.php
     Post the following stack trace to https://github.com/phpstan/phpstan/issues/new?template=Bug_report.yaml:
     ## phar:///var/www/html/vendor/phpstan/phpstan/phpstan.phar/src/Reflection/BetterReflection/BetterReflectionProvider.php(182)
     #0 phar:///var/www/html/vendor/phpstan/phpstan/phpstan.phar/src/Reflection/ReflectionProvider/MemoizingReflectionProvider.php(43): PHPStan\Reflection\BetterReflection\BetterReflectionProvider->getClass()
     #1 /var/www/html/vendor/larastan/larastan/src/Support/CollectionHelper.php(86): PHPStan\Reflection\ReflectionProvider\MemoizingReflectionProvider->getClass()
     #2 /var/www/html/vendor/larastan/larastan/src/ReturnTypes/RelationCollectionExtension.php(70): Larastan\Larastan\Support\CollectionHelper->determineCollectionClass()
     #3 phar:///var/www/html/vendor/phpstan/phpstan/phpstan.phar/src/Analyser/MutatingScope.php(3918): Larastan\Larastan\ReturnTypes\RelationCollectionExtension->getTypeFromMethodCall()
     #4 phar:///var/www/html/vendor/phpstan/phpstan/phpstan.phar/src/Analyser/MutatingScope.php(1616): PHPStan\Analyser\MutatingScope->methodCallReturnType()
     #5 phar:///var/www/html/vendor/phpstan/phpstan/phpstan.phar/src/Analyser/MutatingScope.php(1622): PHPStan\Analyser\MutatingScope->PHPStan\Analyser\{closure}()
     #6 phar:///var/www/html/vendor/phpstan/phpstan/phpstan.phar/src/Analyser/MutatingScope.php(600): PHPStan\Analyser\MutatingScope->resolveType()
     #7 phar:///var/www/html/vendor/phpstan/phpstan/phpstan.phar/src/Analyser/MutatingScope.php(826): PHPStan\Analyser\MutatingScope->getType()                                                                                     
     #8 phar:///var/www/html/vendor/phpstan/phpstan/phpstan.phar/src/Analyser/MutatingScope.php(600): PHPStan\Analyser\MutatingScope->resolveType()
     #9 phar:///var/www/html/vendor/phpstan/phpstan/phpstan.phar/src/Analyser/NodeScopeResolver.php(1798): PHPStan\Analyser\MutatingScope->getType()
     #10 phar:///var/www/html/vendor/phpstan/phpstan/phpstan.phar/src/Analyser/NodeScopeResolver.php(724): PHPStan\Analyser\NodeScopeResolver->findEarlyTerminatingExpr()
     #11 phar:///var/www/html/vendor/phpstan/phpstan/phpstan.phar/src/Analyser/NodeScopeResolver.php(464): PHPStan\Analyser\NodeScopeResolver->processStmtNode()
     #12 phar:///var/www/html/vendor/phpstan/phpstan/phpstan.phar/src/Analyser/NodeScopeResolver.php(652): PHPStan\Analyser\NodeScopeResolver->processStmtNodes()
     #13 phar:///var/www/html/vendor/phpstan/phpstan/phpstan.phar/src/Analyser/NodeScopeResolver.php(464): PHPStan\Analyser\NodeScopeResolver->processStmtNode()
     #14 phar:///var/www/html/vendor/phpstan/phpstan/phpstan.phar/src/Analyser/NodeScopeResolver.php(4477): PHPStan\Analyser\NodeScopeResolver->processStmtNodes()
     #15 phar:///var/www/html/vendor/phpstan/phpstan/phpstan.phar/src/Analyser/NodeScopeResolver.php(4492): PHPStan\Analyser\NodeScopeResolver->processNodesForTraitUse()
     #16 phar:///var/www/html/vendor/phpstan/phpstan/phpstan.phar/src/Analyser/NodeScopeResolver.php(4488): PHPStan\Analyser\NodeScopeResolver->processNodesForTraitUse()
     #17 phar:///var/www/html/vendor/phpstan/phpstan/phpstan.phar/src/Analyser/NodeScopeResolver.php(4492): PHPStan\Analyser\NodeScopeResolver->processNodesForTraitUse()
     #18 phar:///var/www/html/vendor/phpstan/phpstan/phpstan.phar/src/Analyser/NodeScopeResolver.php(4431): PHPStan\Analyser\NodeScopeResolver->processNodesForTraitUse()
     #19 phar:///var/www/html/vendor/phpstan/phpstan/phpstan.phar/src/Analyser/NodeScopeResolver.php(924): PHPStan\Analyser\NodeScopeResolver->processTraitUse()
     #20 phar:///var/www/html/vendor/phpstan/phpstan/phpstan.phar/src/Analyser/NodeScopeResolver.php(464): PHPStan\Analyser\NodeScopeResolver->processStmtNode()
     #21 phar:///var/www/html/vendor/phpstan/phpstan/phpstan.phar/src/Analyser/NodeScopeResolver.php(789): PHPStan\Analyser\NodeScopeResolver->processStmtNodes()
     #22 phar:///var/www/html/vendor/phpstan/phpstan/phpstan.phar/src/Analyser/NodeScopeResolver.php(464): PHPStan\Analyser\NodeScopeResolver->processStmtNode()
     #23 phar:///var/www/html/vendor/phpstan/phpstan/phpstan.phar/src/Analyser/NodeScopeResolver.php(759): PHPStan\Analyser\NodeScopeResolver->processStmtNodes()
     #24 phar:///var/www/html/vendor/phpstan/phpstan/phpstan.phar/src/Analyser/NodeScopeResolver.php(429): PHPStan\Analyser\NodeScopeResolver->processStmtNode()
     #25 phar:///var/www/html/vendor/phpstan/phpstan/phpstan.phar/src/Analyser/FileAnalyser.php(179): PHPStan\Analyser\NodeScopeResolver->processNodes()
     #26 phar:///var/www/html/vendor/phpstan/phpstan/phpstan.phar/src/Command/WorkerCommand.php(139): PHPStan\Analyser\FileAnalyser->analyseFile()
     #27 phar:///var/www/html/vendor/phpstan/phpstan/phpstan.phar/vendor/evenement/evenement/src/EventEmitterTrait.php(111): PHPStan\Command\WorkerCommand::PHPStan\Command\{closure}()
     #28 phar:///var/www/html/vendor/phpstan/phpstan/phpstan.phar/vendor/clue/ndjson-react/src/Decoder.php(117): _PHPStan_4f7beffdf\Evenement\EventEmitter->emit()
     #29 phar:///var/www/html/vendor/phpstan/phpstan/phpstan.phar/vendor/evenement/evenement/src/EventEmitterTrait.php(111): _PHPStan_4f7beffdf\Clue\React\NDJson\Decoder->handleData()
     #30 phar:///var/www/html/vendor/phpstan/phpstan/phpstan.phar/vendor/react/stream/src/Util.php(62): _PHPStan_4f7beffdf\Evenement\EventEmitter->emit()
     #31 phar:///var/www/html/vendor/phpstan/phpstan/phpstan.phar/vendor/evenement/evenement/src/EventEmitterTrait.php(111): _PHPStan_4f7beffdf\React\Stream\Util::_PHPStan_4f7beffdf\React\Stream\{closure}()
     #32 phar:///var/www/html/vendor/phpstan/phpstan/phpstan.phar/vendor/react/stream/src/DuplexResourceStream.php(168): _PHPStan_4f7beffdf\Evenement\EventEmitter->emit()
     #33 phar:///var/www/html/vendor/phpstan/phpstan/phpstan.phar/vendor/react/event-loop/src/StreamSelectLoop.php(201): _PHPStan_4f7beffdf\React\Stream\DuplexResourceStream->handleData()                                         
     #34 phar:///var/www/html/vendor/phpstan/phpstan/phpstan.phar/vendor/react/event-loop/src/StreamSelectLoop.php(173): _PHPStan_4f7beffdf\React\EventLoop\StreamSelectLoop->waitForStreamActivity()
     #35 phar:///var/www/html/vendor/phpstan/phpstan/phpstan.phar/src/Command/WorkerCommand.php(99): _PHPStan_4f7beffdf\React\EventLoop\StreamSelectLoop->run()
     #36 phar:///var/www/html/vendor/phpstan/phpstan/phpstan.phar/vendor/symfony/console/Command/Command.php(259): PHPStan\Command\WorkerCommand->execute()
     #37 phar:///var/www/html/vendor/phpstan/phpstan/phpstan.phar/vendor/symfony/console/Application.php(870): _PHPStan_4f7beffdf\Symfony\Component\Console\Command\Command->run()
     #38 phar:///var/www/html/vendor/phpstan/phpstan/phpstan.phar/vendor/symfony/console/Application.php(261): _PHPStan_4f7beffdf\Symfony\Component\Console\Application->doRunCommand()
     #39 phar:///var/www/html/vendor/phpstan/phpstan/phpstan.phar/vendor/symfony/console/Application.php(157): _PHPStan_4f7beffdf\Symfony\Component\Console\Application->doRun()
     #40 phar:///var/www/html/vendor/phpstan/phpstan/phpstan.phar/bin/phpstan(124): _PHPStan_4f7beffdf\Symfony\Component\Console\Application->run()
     #41 phar:///var/www/html/vendor/phpstan/phpstan/phpstan.phar/bin/phpstan(125): _PHPStan_4f7beffdf\{closure}()
     #42 /var/www/html/vendor/phpstan/phpstan/phpstan(8): require('...')
     #43 /var/www/html/vendor/bin/phpstan(119): include('...')
     #44 {main}
 -- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------   


                                                                                                                        
 [ERROR] Found 1 error                                                                                                  
                                                                                                                        

⚠️  Result is incomplete because of severe errors. ⚠️
   Fix these errors first and then re-run PHPStan
   to get all reported errors.

Elapsed time: 16 seconds
Used memory: 180.5 MB

Laravel code where the issue was found

This code has nothing to do with Laravel per se: just an interface and a trait. But some types that it uses are from Laravel.

@XedinUnknown XedinUnknown added the bug Something isn't working label Oct 6, 2024
@calebdw
Copy link
Contributor

calebdw commented Oct 6, 2024

Can you please share the code that causes the crash?

@XedinUnknown
Copy link
Author

I'm having trouble isolating exactly what is causing the crash. Here are the interface and the trait; I've removed the bodies of longer functions for brevity.

<?php

namespace Domain\Shared\Models;

use Domain\Shared\Collections\TreeLikeCollection;
use Domain\Shared\Collections\TreeLikeCollectionInterface;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Support\Facades\App;

/**
 * @see HierarchicalModelInterface
 *
 * @phpstan-import-type ParentId from HierarchicalModelInterface
 */
trait HierarchicalModelTrait
{
    public function getParentKeyName(): int|string|null
    {
        return 'parent_id';
    }

    public function newCollection(array $models = []): TreeLikeCollectionInterface
    {
        return App::makeWith(TreeLikeCollection::class, ['items' => $models]);
    }

    public function parent(): BelongsTo
    {
        return $this->belongsTo(static::class, $this->getParentKeyName());
    }

    public function children(): HasMany
    {
        return $this->hasMany(static::class, $this->getParentKeyName());
    }

    /**
     * Recursively retrieve all children of this instance.
     */
    public function getDescendants(): Collection & TreeLikeCollectionInterface
    {
    }

    /**
     * Recursively retrieve all parents of this instance.
     */
    public function getAncestors(): Collection & TreeLikeCollectionInterface
    {
    }
}
<?php

namespace Domain\Shared\Models;

use Domain\Shared\Collections\TreeLikeCollectionInterface;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\HasMany;

/**
 * @phpstan-type ParentId = int|string
 *
 * @phpstan-require-extends Model
 *
 * @property static $parent
 * @property Collection<array-key, static>&TreeLikeCollectionInterface<static> $children
 */
interface HierarchicalModelInterface
{
    /**
     * Retrieve the name of the field which holds the key of this entity's parent.
     *
     * @return ?ParentId
     */
    public function getParentKeyName(): int|string|null;

    /**
     * @see Model::newCollection()
     *
     * @param array<static> $models The models for the new collection
     *
     * @return Collection & TreeLikeCollectionInterface The new collection.
     */
    public function newCollection(array $models = []): TreeLikeCollectionInterface;

    /**
     * Relationship to the parent entity.
     */
    public function parent(): BelongsTo;

    /**
     * Relationship to the child entities.
     */
    public function children(): HasMany;

    /**
     * Retrieves all children of this instance recursively.
     */
    public function getDescendants(): Collection & TreeLikeCollectionInterface;

    /**
     * Retrieves all parents of this instance recursively.
     */
    public function getAncestors(): Collection & TreeLikeCollectionInterface;
}

The getDescendants() and getAncestors() return Collection & TreeLikeCollectionInterface no problem, and type-hint that in both the trait (and therefore class) and interface. If I do the same with newCollection(), I get the symptoms described in the original post.

@calebdw
Copy link
Contributor

calebdw commented Oct 7, 2024

This is being caused in the CollectionHelper:

$collectionClassName = $this->determineCollectionClassName($modelClassName);
$collectionReflection = $this->reflectionProvider->getClass($collectionClassName);

We are not properly handling intersection types

@calebdw calebdw linked a pull request Oct 7, 2024 that will close this issue
@XedinUnknown
Copy link
Author

Thanks for the quick response! Looking forward to the fix 🙏

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants