Hello,
First of, thanks for the quick fix with the earlier issues, can confirm they now all pass with v0.10.0.
And found another bug while reviewing/verifying the TypePHP results:
/**
* @template TTag of Tag
*/
trait HasManyTags
{
/**
* @param TTag $record
*/
public function addTag(Tag $record): static { /* … */ }
}
final class HasManyTagsTest extends TestCase
{
private function createSubject(): object
{
return new class {
/**
* @use HasManyTags<TextTag|ShippingMethodTag>
*/
use HasManyTags;
};
}
}
$subject->addTag(new ShippingMethodTag(/* … */));
Actual:
class@anonymous …\HasManyTagsTest.php:221$48a::addTag(): Argument $record (template TTag = TextTag)
must be of type TextTag, ShippingMethodTag given
The binding TypePHP reports (TTag = TextTag) is not the @use one; it is inferred from the first addTag() call, so every later call with another union member fails.
Root cause read from the vendor source (v0.10.0 paths): SpecialTypeResolver::parseFileMetadata() (src/Internal/Resolver/SpecialTypeResolver.php:1113-1116) registers $currentClass only for a class, interface, trait or enum token followed by a name token, then files every trait-use docblock it meets under that class (:1121-1124). An anonymous class never becomes a key, so getClassTraitUseDocs('class@anonymous …') stays empty and the anonymous class's @use doc is attributed to the enclosing named class instead. @use on named classes is unaffected.
Expected: the @use docblock on the anonymous class binds TTag = TextTag|ShippingMethodTag, as PHPStan resolves it; both calls are accepted.
Hello,
First of, thanks for the quick fix with the earlier issues, can confirm they now all pass with v0.10.0.
And found another bug while reviewing/verifying the TypePHP results:
Actual:
The binding TypePHP reports (
TTag = TextTag) is not the@useone; it is inferred from the firstaddTag()call, so every later call with another union member fails.Root cause read from the vendor source (v0.10.0 paths):
SpecialTypeResolver::parseFileMetadata()(src/Internal/Resolver/SpecialTypeResolver.php:1113-1116) registers$currentClassonly for a class, interface, trait or enum token followed by a name token, then files every trait-use docblock it meets under that class (:1121-1124). An anonymous class never becomes a key, sogetClassTraitUseDocs('class@anonymous …')stays empty and the anonymous class's@usedoc is attributed to the enclosing named class instead.@useon named classes is unaffected.Expected: the
@usedocblock on the anonymous class bindsTTag = TextTag|ShippingMethodTag, as PHPStan resolves it; both calls are accepted.