Skip to content

feat: add @valinor-* annotations to override an unparseable type - #830

Merged
romm merged 1 commit into
masterfrom
feat/valinor-annotations
Jul 29, 2026
Merged

feat: add @valinor-* annotations to override an unparseable type#830
romm merged 1 commit into
masterfrom
feat/valinor-annotations

Conversation

@romm

@romm romm commented Jul 29, 2026

Copy link
Copy Markdown
Member

PHPStan and Psalm accept type syntaxes that this library cannot parse, for instance a conditional type like ($a is 1 ? int : null). Such a type ends up unresolvable, and the only way out was to remove or weaken the annotation, making the static analysis tools lose information the library was not able to use anyway.

The annotations @valinor-var, @valinor-param and @valinor-return can now declare a type that only this library reads. They take precedence over their @phpstan-*, @psalm-* and native counterparts, so both worlds can be served by the same docblock:

final class SomeClass
{
    /**
     * @phpstan-param ($a is 1 ? int : null) $b
     * @valinor-param int|null $b
     */
    public function __construct(
        public readonly int $a,
        public readonly ?int $b,
    ) {}
}

Finding the parameter name declared by a @param-like annotation now ignores the $variable tokens nested inside brackets, so a conditional type such as ($a is 1 ? int : string) $b is bound to $b and not to the $a appearing inside the type.

Fixes #448

PHPStan and Psalm accept type syntaxes that this library cannot parse,
for instance a conditional type like `($a is 1 ? int : null)`. Such a
type ends up unresolvable, and the only way out was to remove or weaken
the annotation, making the static analysis tools lose information the
library was not able to use anyway.

The annotations `@valinor-var`, `@valinor-param` and `@valinor-return`
can now declare a type that only this library reads. They take
precedence over their `@phpstan-*`, `@psalm-*` and native counterparts,
so both worlds can be served by the same docblock:

```php
final class SomeClass
{
    /**
     * @phpstan-param ($a is 1 ? int : null) $b
     * @valinor-param int|null $b
     */
    public function __construct(
        public readonly int $a,
        public readonly ?int $b,
    ) {}
}
```

Finding the parameter name declared by a `@param`-like annotation now
ignores the `$variable` tokens nested inside brackets, so a conditional
type such as `($a is 1 ? int : string) $b` is bound to `$b` and not to
the `$a` appearing inside the type.
@romm
romm merged commit 11938c5 into master Jul 29, 2026
30 checks passed
@romm
romm deleted the feat/valinor-annotations branch July 29, 2026 22:57
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Valinor may crash when encountering a PHPStan/Psalm type syntax it doesn't support yet

1 participant