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

Do not generalize class-string during template type inference #1038

Merged
merged 1 commit into from Feb 27, 2022

Conversation

arnaud-lb
Copy link
Contributor

@arnaud-lb arnaud-lb commented Feb 26, 2022

This prevents generalization of class-string types during template type inference.

Fixes phpstan/phpstan#6505

Note:

I'm now wondering if we should generalize inferred types at all. Generalization allows expressions such as new Foo(1) to be inferred as Foo<int> rather than Foo<1>, which is useful. However, sometimes we may actually want a Foo<1>, and the current behavior makes this impossible.

It could be useful to be able to create a Foo<non-empty-string>, a Foo<numeric-string>, or a Foo<int<100,200>>.

If we stopped generalizing at all, a new Foo(1) would infer to Foo<1>, and new Collection([1,2,3]) would infer to Collection<1|2|3>, which is less useful in most case, but it gives the control to the user. The user would be able to generalize the type manually, like this:

/** @var int[] $elems */
$elems = [1, 2, 3];
new Collection($elems);

or like this:

/** @param int[] $elems */
function makeCollection($elems) {
    return new Collection($elems);
}

@ondrejmirtes
Copy link
Member

Thank you, I like this and appreciate it!

About the generics generalization problem - it's really really tricky. People have different needs and I worry that we can't guess them. I think that new Collection([1, 2, 3]) definitely has to become Collection<int>.

PHPStan currently has a little logic that half-works - if the Collection had @template T of int, it'd become Collection<1|2|3> instead.

I also have this issue phpstan/phpstan#6433 and phpstan/phpstan#6695 that I might solve thanks to this PR. It's another case where less precise generalization is welcome.

One solution might be to put the user in control of the problem with some annotation like @template-more-precise T or something like that, but I don't know if we're that far to justify it.

@ondrejmirtes ondrejmirtes merged commit 1b117f7 into phpstan:master Feb 27, 2022
@ZebulanStanphill
Copy link
Contributor

@ondrejmirtes It's worth noting that TypeScript has a bit of a related dilemma involving how to make a type less specific without having to use the (type-unsafe) as keyword (which is the TS equivalent of @var). See microsoft/TypeScript#47920.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
3 participants