-
Notifications
You must be signed in to change notification settings - Fork 666
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
[Templating] assertig that a string
is non-empty-string
using a generic validator results in a *false* redundant condition error
#6573
Comments
I found these snippets: https://psalm.dev/r/ae244c6b02<?php
/**
* @template-covariant T
*/
interface Type {
/**
* @psalm-assert-if-true T $value
*/
public function matches(mixed $value): bool;
}
/**
* @return Type<non-empty-string>
*/
function non_empty_string_type(): Type { exit(0); }
$f = 'hello';
assert(non_empty_string_type()->matches($f));
https://psalm.dev/r/515024a452<?php
interface Type {
/**
* @psalm-assert-if-true non-empty-string $value
*/
public function matches(mixed $value): bool;
}
/**
* @return Type
*/
function non_empty_string_type(): Type { exit(0); }
$f = 'hello';
assert(non_empty_string_type()->matches($f));
https://psalm.dev/r/b0278b0493<?php
/**
* @template T
*/
interface Type {
/**
* @psalm-assert-if-true T $value
*/
public function matches(mixed $value): bool;
}
/**
* @return Type<non-empty-string>
*/
function non_empty_string_type(): Type { exit(0); }
$f = 'hello';
assert(non_empty_string_type()->matches($f));
|
Nice investigation. Thanks! |
I went back to january but this snippet still produced the same error with Psalm's code. Are you sure this is related with Psalm 4.10 specifically? |
@orklah not sure which psalm version exactly broke this, but in February when matches() was introduced, and we where using |
Not sure what I should look at, there's a lot of Psalm errors in the CI for this branch. |
This works in 4.4.1, and fails in 4.10: https://psalm.dev/r/5aee8f5518 to fix this in 4.10, we have to replace |
I found these snippets: https://psalm.dev/r/5aee8f5518<?php
/**
* @template T
*/
interface Type {
/**
* @psalm-assert-if-true T $value
*/
public function matches(mixed $value): bool;
}
/**
* @return Type<non-empty-string>
*/
function non_empty_string_type(): Type { exit(0); }
/**
* @return Type<int>
*/
function int_type(): Type { exit(0); }
/**
* @template T
* @param list<Type<T>> $_types
* @return Type<list<T>>
*/
function list_type(array $_types): Type { exit(0); }
$a = non_empty_string_type();
$b = int_type();
$c = list_type([$a, $b]);
$_d = list_type([$a, $b, $c]);
|
Oh, so this is related to the 'Incompatible types found for" error. For reference, here are similar issues: and it seems it was introduced by Matt refactoring some code here: acc7ee2 He made some fix for one case here: a205a23 and there was some explanation here: #6073 (comment) It's well above my current knowledge of Psalm though... |
I think the covariant issue is not a problem, however, i also don't think |
just spent 2 hours trying to fix this issue, and come up with nothing :) |
not sure why psalm thinks we are matching |
If it helps, here's the script i'm using for testing/debugging:
this shouldn't fail. |
and something that is even more weird, is this: https://psalm.dev/r/cb32f3e4cc here psalm asserts that it is a non-empty-string, not that it is a string, and no redundant condition error is trigger ( for asserting that a string, is already a string )
|
I found these snippets: https://psalm.dev/r/cb32f3e4cc<?php
/**
* @template-covariant T
*/
interface Type {
/**
* @param mixed $value
*
* @psalm-assert T $value
*/
public function matches($value): bool;
}
/**
* @template-implements Type<non-empty-string>
*/
final class NonEmptyStringType implements Type {
/**
* @param mixed $value
*
* @psalm-assert non-empty-string $value
*/
public function matches($value): bool
{
return is_string($value) && $value !== '';
}
}
/**
* @return Type<non-empty-string>
*/
function non_empty_string(): Type {
return new NonEmptyStringType();
}
function bar(): string { return 'hello'; }
function main(): void
{
$value = bar();
$type = non_empty_string();
$type->matches($value);
if ($value === '') {
echo 'foo';
} else {
echo 'bar';
}
}
https://psalm.dev/r/9d9005ffee<?php
/**
* @param mixed $value
* @psalm-assert non-empty-string $value
*/
function assertNonEmpty($value): bool { return false; }
|
In https://psalm.dev/r/cb32f3e4cc I think you should have typed |
I found these snippets: https://psalm.dev/r/cb32f3e4cc<?php
/**
* @template-covariant T
*/
interface Type {
/**
* @param mixed $value
*
* @psalm-assert T $value
*/
public function matches($value): bool;
}
/**
* @template-implements Type<non-empty-string>
*/
final class NonEmptyStringType implements Type {
/**
* @param mixed $value
*
* @psalm-assert non-empty-string $value
*/
public function matches($value): bool
{
return is_string($value) && $value !== '';
}
}
/**
* @return Type<non-empty-string>
*/
function non_empty_string(): Type {
return new NonEmptyStringType();
}
function bar(): string { return 'hello'; }
function main(): void
{
$value = bar();
$type = non_empty_string();
$type->matches($value);
if ($value === '') {
echo 'foo';
} else {
echo 'bar';
}
}
|
no, i used |
I found these snippets: https://psalm.dev/r/cb32f3e4cc<?php
/**
* @template-covariant T
*/
interface Type {
/**
* @param mixed $value
*
* @psalm-assert T $value
*/
public function matches($value): bool;
}
/**
* @template-implements Type<non-empty-string>
*/
final class NonEmptyStringType implements Type {
/**
* @param mixed $value
*
* @psalm-assert non-empty-string $value
*/
public function matches($value): bool
{
return is_string($value) && $value !== '';
}
}
/**
* @return Type<non-empty-string>
*/
function non_empty_string(): Type {
return new NonEmptyStringType();
}
function bar(): string { return 'hello'; }
function main(): void
{
$value = bar();
$type = non_empty_string();
$type->matches($value);
if ($value === '') {
echo 'foo';
} else {
echo 'bar';
}
}
|
Can you check that one again @azjezz ? I think underlying issues have been solved here |
Yes 🎉 my test case ( https://psalm.dev/r/507963421d ) is now passing, thank you! |
I found these snippets: https://psalm.dev/r/507963421d<?php
/**
* @template-covariant T
*/
interface Type {
/**
* @param mixed $value
*
* @psalm-assert-if-true T $value
*/
public function matches($value): bool;
}
/**
* @template-implements Type<non-empty-string>
*/
final class NonEmptyStringType implements Type {
/**
* @param mixed $value
*
* @psalm-assert-if-true non-empty-string $value
*/
public function matches($value): bool
{
return is_string($value) && $value !== '';
}
}
/**
* @return Type<non-empty-string>
*/
function non_empty_string(): Type {
return new NonEmptyStringType();
}
function bar(): string { return 'hello'; }
function main(): void
{
$value = bar();
$type = non_empty_string();
if ($type->matches($value)) {
echo 'foo';
} else {
echo 'bar';
}
}
|
example: https://psalm.dev/r/ae244c6b02
If we replace
Type<non-empty-string>
with a concrete class, we get no issues: https://psalm.dev/r/515024a452investigating further, this seems to be related to
covariant
templating: https://psalm.dev/r/b0278b0493whatever psalm changed in 4.10, completely broke PSL Type component, we now have the choice to either go back to using
@template
and not be able to create a union type, and any other array type, or keep as is and removematches
validator ( both options are BC breaking, currently down stream users are getting a type error either in the constructor ( for PSL < 1.8 ), or when usingmatches
( PSL >= 1.8, which usescovariant
)ref: azjezz/psl#227
ref: azjezz/psl#231
ref: azjezz/psl#212
ref: azjezz/psl#214
The text was updated successfully, but these errors were encountered: