Type projections, part 1: call-site variance in GenericObjectType#2471
Type projections, part 1: call-site variance in GenericObjectType#2471ondrejmirtes merged 3 commits intophpstan:1.10.xfrom
Conversation
|
You've opened the pull request against the latest branch 1.11.x. If your code is relevant on 1.10.x and you want it to be released sooner, please rebase your pull request and change its target to 1.10.x. |
|
I don't trust Rector with downgrading switch to match, please rewrite the code manually 😊 I'd love to review this PR but please make the build green first - there are some failures in integration projects but everything in phpstan-src should be green. Thanks! |
e086d29 to
b82cc17
Compare
|
Ok, rewritten. From what I've skimmed through, all failures in phpstan-src were related to that |
|
Soo if I remember our conversation correctly, the idea is:
The above points describe "declaration site variance". Type projections are basically "call site variance", meaning:
Can you tell me if this PR allows me to do the second bullet list? And do you plan to send more PRs, and what they are gonna do? Thank you :) |
|
Sure :)
Correct.
To be more precise, we want to pass /** @param Collection<covariant Animal> $collection */
function doSomething(Collection $collection): void
{
// now this function accepts Collection<Dog>
// at the cost of not being able to call $collection->add()
}This PR allows – and tests – the first part ("now this function accepts
I'm planning to send two more PRs:
I have the code more or less ready, so the PRs should come in quick succession. I just didn't want to overwhelm you like last time 😅 |
b82cc17 to
174fc20
Compare
src/Reflection/ClassReflection.php
Outdated
There was a problem hiding this comment.
I don't get the need of having these on ClassReflection. Declare-site variance is already taken care of as part of TemplateTag and ClassReflection::getTemplateTags(). Call-site variance is taken care of in GenericObjectType. Why do we need this in ClassReflection?
There was a problem hiding this comment.
Lots of other code deals with ClassReflection rather than GenericObjectType. As of now, I think the main benefit is in the getDisplayName() so that the type displayed in error messages matches the type that's written in code:
<?php
/** @template T */
interface Collection
{
function clear(int $flags): void;
}
/** @param Collection<*> $collection */
function foo(Collection $collection): void
{
$collection->clear();
}12 Method Collection<*>::clear() invoked with 0 parameters, 1 required.
Without the code in ClassReflection, it would say Collection<mixed> (or, e.g., Collection<Animal> instead of Collection<covariant Animal>) which I find rather misleading.
I'm not so sure about the other usages. Now that I think of it, I think it's not necessary in ObjectType, because there should always be invariance anyway. I haven't yet found out if the usage in StaticType is significant or not.
Anyway, even if the methods could become private for the sake of this PR, I would need public access to them in the subsequent PRs.
There was a problem hiding this comment.
Alright, I get it, but I'd prefer if the method name said something like "projection" or "call site" because right now it's a bit confusing. You can access declaration variance through TemplateTag::getVariance() too and getTemplateTypeVarianceMap on ClassReflection seems like the same thing.
There was a problem hiding this comment.
Ok, that's fair :)
ondrejmirtes
left a comment
There was a problem hiding this comment.
Otherwise good to merge :)
src/Reflection/ClassReflection.php
Outdated
There was a problem hiding this comment.
Alright, I get it, but I'd prefer if the method name said something like "projection" or "call site" because right now it's a bit confusing. You can access declaration variance through TemplateTag::getVariance() too and getTemplateTypeVarianceMap on ClassReflection seems like the same thing.
b66a0a9 to
c296ac2
Compare
|
Decided to put this on 1.10.x :) So that it can be released sooner once finished. Thank you! |
I think I've got most of type projections figured out and prototyped, so here we go!
As you suggested, I'm starting small by introducing call-site variance to
GenericObjectType(andClassReflection, transitively), and adding support for bivariance intoTemplateTypeVariance.Looking forward to your thoughts, and to finally having type projections in PHPStan 🤞