Skip to content

Improve/fix type StringOrArray extension#167

Merged
szepeviktor merged 4 commits intoszepeviktor:masterfrom
herndlm:fix-string-or-array-extension
Mar 1, 2023
Merged

Improve/fix type StringOrArray extension#167
szepeviktor merged 4 commits intoszepeviktor:masterfrom
herndlm:fix-string-or-array-extension

Conversation

@herndlm
Copy link
Copy Markdown
Contributor

@herndlm herndlm commented Feb 27, 2023

Closes #154

Successor of #163

  • Gets rid of deprecated instanceof
  • Fixes return types for nested arrays
  • Adds more type precision by not dropping array key types, supporting constant arrays and returning '' in case of an invalid type input
  • Adds support for union/intersection types

}

if (count($type->getConstantArrays()) > 0) {
return TypeCombinator::union(
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

those wouldn't even be needed anymore I guess because this function is wrapped in a TypeTraverser already that deals with union types. the alternative would be to explicitly handle only the first constant array and array below instead of all of them. not sure what is simpler / reads better, in the end it might not matter much..

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@herndlm I also think that if (count($type->getConstantArrays()) > 0) {...} is no longer needed.

Copy link
Copy Markdown
Contributor Author

@herndlm herndlm Feb 27, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The question is how to do it differently. A condition like that has to stay to access only the first ConstantArray and get rid of the union for example. Or any other ideas?

Copy link
Copy Markdown
Contributor

@IanDelMar IanDelMar Feb 28, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Had a closer look. What about this?

        $maybeEmptyArray = [];
        if (count($type->getConstantArrays()) > 0) {
            $constantArray = $type->getConstantArrays()[0];
            if (
                $constantArray->isOptionalKey(0) &&
                $constantArray->getArraySize()->equals(IntegerRangeType::fromInterval(0, 1))
            ) {
                $maybeEmptyArray[] = $constantArray;
            }
        }

        return TypeCombinator::union(
            ...array_merge(
                $maybeEmptyArray,
                array_map(
                    function (ArrayType $arrayType): Type {
                        return $arrayType->setOffsetValueType(
                            $arrayType->getIterableKeyType(),
                            $this->getType($arrayType->getIterableValueType())
                        );
                    },
                    $type->getArrays()
                )
            )
        );

I don't think that it matters whether we use $type->getConstantArrays()[0] or foreach ($type->getConstantArrays() as $constantArray) {}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, this fails for

/** @var 'foo'|array{foo?: true, bar: int} $union */
$union = null;
assertType('array{foo?: string, bar: string}|string', esc_sql($union));

with

-'array{foo?: string, bar: string}|string'
+'array{foo?: string|true, bar: int|string}|string'

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

got rid of the array_map and union

Comment thread tests/data/esc_sql.php Outdated
Comment thread tests/data/esc_sql.php Outdated
Comment thread tests/data/esc_sql.php Outdated
Comment thread tests/data/esc_sql.php Outdated
Comment thread src/StringOrArrayDynamicFunctionReturnTypeExtension.php Outdated
Comment thread src/StringOrArrayDynamicFunctionReturnTypeExtension.php Outdated
Comment thread src/StringOrArrayDynamicFunctionReturnTypeExtension.php Outdated
@szepeviktor
Copy link
Copy Markdown
Owner

Does PHP allow $this in a closure? I would not allow it!

@herndlm
Copy link
Copy Markdown
Contributor Author

herndlm commented Feb 27, 2023

Does PHP allow $this in a closure? I would not allow it!

sure, there's no reason against it. without such code (and also e.g. with the weird Neutron CS rule that forbids to have a callable assigned to a var) PHPStan wouldn't be able to efficiently parse and handle the AST to figure out types

@herndlm
Copy link
Copy Markdown
Contributor Author

herndlm commented Feb 27, 2023

@IanDelMar let me/us know please what you think of this. I did briefly confirm the test cases with a real WordPress, but I don't know the internals of the escaping function well enough. Maybe @johnbillion can quickly check too :)

Comment thread tests/data/esc_sql.php
@IanDelMar
Copy link
Copy Markdown
Contributor

@herndlm Looks good to me!

Co-authored-by: IanDelMar <[email protected]>
@szepeviktor
Copy link
Copy Markdown
Owner

Is it ready to merge?

return new StringType();
}

if (!$type->isArray()->yes()) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if (!$type->isArray()->yes()) {
if ($type->isArray()->no()) {

Copy link
Copy Markdown
Owner

@szepeviktor szepeviktor Feb 28, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If it is a maybe type !yes means maybe or no,
no means no only.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Both are not a 100% correct I suppose, the maybe case might need another extra handling instead of just returning the input below. I'll check it later.

Copy link
Copy Markdown
Contributor Author

@herndlm herndlm Feb 28, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

dealing with the maybe here is highly annoying, e.g. your proposed change would lead to a *NEVER* (mine to a '') when a maybe array like mixed or iterable is passed. both are wrong. and in both cases PHPStan should be complaining because esc_sql does not support those types via PHPDoc. Natively it does of course, I know..

And I can't even say what we would return with a mixed, I guess we could just bail out early and not handle and return the default type or smth like that

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

adapted, what do you think? should at least be simpler and less wrong now :)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thought the same, but can't return null here because this is wrapped with the TypeTraverser:map() which doesn't allow returning null AFAIK

Copy link
Copy Markdown
Contributor Author

@herndlm herndlm Feb 28, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

BTW just curious, your profile says Vienna but you seem yo be active very late until into the night. Are you still in Vienna? I'm from Austria and lived there too, missing it a bit from time to time..

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I still live in Vienna. My activity time mainly depends on my day job and after work napping :-D. Vienna is a nice place to live. I would miss it too at least in late spring and summer.

Copy link
Copy Markdown
Contributor Author

@herndlm herndlm Mar 1, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And good old boss Viktor is in Budapest, the twin cities, right? :)
Anyway, shall we merge? :P

Also: sorry for calling you old Viktor

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am old.

@herndlm herndlm force-pushed the fix-string-or-array-extension branch from d8ab289 to 3f1821e Compare February 28, 2023 08:27
@szepeviktor szepeviktor merged commit 2320e5b into szepeviktor:master Mar 1, 2023
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.

Incorrect return type for esc_sql(), wp_slash() and wp_unslash()

3 participants