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

Psalm v5: __toString of some types does not return exact return type anymore #7985

Closed
boesing opened this issue May 18, 2022 · 8 comments
Closed

Comments

@boesing
Copy link
Contributor

boesing commented May 18, 2022

In psalm v4, using (string) $type on an instance of TNumericString returned numeric-string.
As of psalm v5, this now returns string.

Is this an expected behavior?

@psalm-github-bot
Copy link

Hey @boesing, can you reproduce the issue on https://psalm.dev ?

@orklah
Copy link
Collaborator

orklah commented May 18, 2022

This would probably be an effect of #7409

But I don't get how it happens. Calling __toString on a TNumericString targets Atomic::__toString which itself calls $this->getId() which resolves to TNumericString::getId() with $exact to true. When calling that, it should return numeric-string. Are you sure this is the behavior you have?

@boesing
Copy link
Contributor Author

boesing commented May 18, 2022

I at least have failing codeception tests regarding this.

Will see if I can debug the reason.

@boesing
Copy link
Contributor Author

boesing commented May 18, 2022

It seems that in case of a Union, false is passed to Atomic#getId:

$types[] = (string)$type;

$types[] = $type->getId(false);

@orklah
Copy link
Collaborator

orklah commented May 18, 2022

Oh I see, it was in a union. Could you try pushing a PR to change that to true? I think this will have other unwanted effects but I can't remember which. CI should tell us that

@boesing
Copy link
Contributor Author

boesing commented May 18, 2022

I probably just gonna switch to Atomic#getId directly instead.
Since the affected commit did not just change the Union but also other places, either reverting the commit or moving over to Atomic#getId would be a proper solution, right?

I guess you knew what you did there and thus I better not question that 😂

@orklah
Copy link
Collaborator

orklah commented May 18, 2022

Honestly, the whole thing was a mess before :(

__toString was generally used to return a less detailed version of a type but it was not consistent, some function were calling other and then were overriden to call something else entirely. And nothing was documented.

We have a few BC break for Psalm 5 linked to this PR

[BC] Atomic::__toString() used to return a string representation of the type that was using double quotes (") to quote literals. This is now using single quotes (') to be more aligned with the rest of the codebase.

[BC] Atomic::__toString() is now final

[BC] Atomic::__toString() now returns a more detailed version of the type (it calls getId() under the hood)

[BC] Atomic::getId() has now a first param $exact. Calling the method with false will return a less detailed version of the type in some cases (similarly to what __toString used to return)

To give you a slight idea, here's what happened in 4.x:
TNumericString extends TNonEmptyString which itself extends TString.

Calling __toString on TString returns string
Calling __toString on TNonEmptyString returns string
Calling __toString on TNumericString returns numeric-string

Calling getKey on TString returns string
Calling getKey on TNonEmptyString returns string
Calling getKey on TNumericString returns numeric-string

Calling getId on TString returns string
Calling getId on TNonEmptyString returns non-empty-string
Calling getId on TNumericString returns numeric-string

So I had to make choices and break things in some places. I kept the original idea that __toString should be the one used for debug and that can be less detailed while getId should always be the more detailed but this could break things in some places when relying on the output of __toString

Disclaimer: I'm aware this is still a mess. For example, Union::__toString use less detailed types but Atomic::__toString use more detailed types. (IIRC, it's because one is used by Psalm for tests so I can't change that), but at least, it reduces the complexity of the system. It could probably still be improved and I'd be surprised if we don't refactor that once again in Psalm 6 !

@boesing
Copy link
Contributor Author

boesing commented May 19, 2022

Yah, for my use-case, Atomic#getId is exactly what I need. Was not aware of that back in the days and thus, using that method is fine for me.
Closing here as this is actually working as expected for psalm v5.

Thanks for explanation!

@boesing boesing closed this as completed May 19, 2022
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

No branches or pull requests

2 participants