- 
  Notifications
 
You must be signed in to change notification settings  - Fork 545
 
Fix ext-ds object diffing and merging #95
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
Conversation
/cc @enumag
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It doesn't make much sense to me to use the data structures this way but technically this is of course correct. 👍
I don't particularly like "TValue2" but I'm not sure what to replace it with.
Tests aren't necessary in my opinion. What do you think @ondrejmirtes?
You can write some using NodeScopeResolverTest::testFileAsserts() if you want to, it can’t hurt.
To sum up:
diff() and intersect() only modify current map based on keys
merge(), xor(), union() result in some mixed kind of map C from maps A and B
I think that that enumerates all methods that need to be modified here.
c99c435 to
 9231640  
 Compare
 
 I agree TValue2 sucks a bit. Looked around for some inspiration but found none...
Another thought for map: shouldn't there be a TKey2 used as well? There is nothing preventing the other map to have different type of keys, is there? Map::intersect() would return Map<TKey&TKey2, TValue>.
@enumag intersect afaik returns only values whose keys are in both maps. So the keys must be of the same type to return anything.
But for the second group there should indeed be TKey2 and the resulting type is Map<TKey|TKey2, TValue|TValue2>
( merge(), xor(), union() )
9231640 to
 3c707d1  
 Compare
 
 
intersect afaik returns only values whose keys are in both maps
yup that's why the keys in resulting map need to be both, meaning TKey&TKey2
But both is union |, not intersection &, hm?
Also
$map = new Map([1=>1]); $map->put('2', '2');
modifies the type but I have no idea how to implement that. Maybe through some extension?
Not sure why tests fail, can't spot a bug. Any idea?
But both is union |, not intersection &, hm?
For the intersect method result to contain a key it needs to be in both maps. Meaning it needs to be of both type TKey and type TKey2 at the same time. Hence &.
As for #95 (comment) you should annotate such map with /** @var Map<string|int, string|int>. It's illegal to change the type later.
you should annotate such map with /** @var Map<string|int, string|int>.
not having to do that is desired, I'm trying to avoid all comments or unnecessary assertions in code if possible.
It's possible with array but I'm not sure how that's implemented.
<?php declare(strict_types = 1); $array = ['a']; // initially array<string> $array[] = 1; // phpstan now knows it's array<string|int> foreach($array as $entry) { if(is_string($entry) || is_int($entry)) { continue; } throw new \Exception(); }
@simPod I don't know how that's done either. @ondrejmirtes ?
@enumag Can you formulate your question? I don't know what you're asking about. This code seems OK: https://phpstan.org/r/f8a9f24b-de0b-424c-93da-02dafa902560
Is the question how does this piece of code modifies the original object?
$map = new Map([1=>1]); $map->put('2', '2');
How is the object modified? What's the result of this following code?
$map = new Map([1=>1]); $map === 'aaa'; $map->put('2', '2'); $map === 'aaa';
bc8d39d to
 3e1ce5d  
 Compare
 
 I got lost a bit but the question is how to make this work:
<?php declare(strict_types = 1); $set = new Set('a'); // initially Set<string> $set->add(1); // phpstan now does not know it's Set<string|int>. How to make PHPStan know?
The actual dilema is:
- Do you want to report it as a problem?
 - Or do you want to modify the type of the set?
 
I think it makes sense to do only one, and right now it's doing 1). Which is what you want from generics...
It is reported as a problem now and I'd like to modify the type of the set instead. Same behaviour as array has.
If you want to make it Set<string|int> from the beginning you should use @var.
I don't think this is how generics should work. When people write Set<string> they usually want to enforce that.
Otherwise you should use mixed here and not TValue: https://github.com/phpstan/phpstan-src/blob/master/stubs/ext-ds.stub#L567-L572
When people write Set they usually want to enforce that.
Sure but what if I don't write it?
It is still the same with arrays. If I declare array<string> I definitely want to enforce it. But if I write $arr = []; the inner type is not defined. Then this is possible: $arr[] = 1; $arr[] = '1'.
// this should be possible $set = new Set(); $set->add(1, '1'); // this is error /** @var Set<string> $set */ $set = new Set(); $set->add(1, '1');
I don't think this PR should be blocked on this request. Can I review it?
Definitely agree, I'll just address this #95 (comment) in 15m
Ok, I have not touched this https://github.com/phpstan/phpstan-src/blob/master/stubs/ext-ds.stub#L567-L572 so we can discuss it later.
Same would then be with eg. https://github.com/phpstan/phpstan-src/blob/master/stubs/ext-ds.stub#L227-L233.
You can review, thanks.
Co-Authored-By: Jáchym Toušek <enumag@gmail.com>
4094498 to
 ddd59ee  
 Compare
 
 The test needs to be skipped if Ds extension isn't loaded. (You can for example return an empty array from the data provider.) Otherwise it's good to merge 👍
Next step should probably be something that would detect wrong usage of Map::intersect() and Set::intersect(). Some type intersections (like string&int) end up as NeverType and with the current stubs they wouldn't get detected.
It might be interesting to do this generally as part of generics implementation.
Thank you!
Could you maybe send some similar stubs to https://github.com/JetBrains/phpstorm-stubs? Then PHPStan could analyze the code even without the ds extension loaded. They're probably not intereted in generics since PhpStorm doesn't support them, but even with the usual @param mixed etc. it would be beneficial (not just for PHPStan).
Yeah I was planning to send them there because right now PHPStorm doesn't know about Ds classes at all so I have to use composer install --dev php-ds/php-ds for PHPStorm to even know that these classes exist. I was just waiting for this to be merged. I'll try to do it tomorrow.
I have not found a way to test this on my project yet.
Rather than creating issue I tried to fix stubs or at least show the idea. The values do not need to have the same type and this should address it.