Skip to content

Implement ext-ds generics#60

Merged
ondrejmirtes merged 6 commits intophpstan:masterfrom
enumag:feature/ds-generics
Jan 2, 2020
Merged

Implement ext-ds generics#60
ondrejmirtes merged 6 commits intophpstan:masterfrom
enumag:feature/ds-generics

Conversation

@enumag
Copy link
Copy Markdown
Contributor

@enumag enumag commented Dec 17, 2019

Supercedes #24.

  1. I noticed in existing stubs that you sometimes use @template and sometimes @template-covariant. Can you explain the difference to me please?

  2. How do I test this on my project now that phpstan is distributed as phar?

@enumag enumag force-pushed the feature/ds-generics branch from 06c0768 to d1c0675 Compare December 17, 2019 13:57
@ondrejmirtes
Copy link
Copy Markdown
Member

Can you explain the difference to me please?

If you want to allow passing Foo<DateTimeImmutable> into Foo<DateTimeInterface>, you need @template-covariant above Foo.

How do I test this on my project now that phpstan is distributed as phar?

By including the stubs directly in your project first.

@ondrejmirtes
Copy link
Copy Markdown
Member

ondrejmirtes commented Dec 19, 2019

I've ran this PR on top of my local branch where I do some basic stub validation. Here are the errors:

  36     Class Ds\Deque implements generic interface ArrayAccess but does not specify its types: TKey, TValue
  36     Class Ds\Deque implements generic interface IteratorAggregate but does not specify its types: TKey,
         TValue
  127    PHPDoc tag @throws with type UnderflowException is not subtype of Throwable
  135    PHPDoc tag @throws with type UnderflowException is not subtype of Throwable
  143    PHPDoc tag @throws with type OutOfRangeException is not subtype of Throwable
  200    PHPDoc tag @throws with type OutOfBoundsException is not subtype of Throwable
  223    Return typehint of method Ds\Map::pairs() has invalid type Ds\Tkey.
  258    PHPDoc tag @throws with type OutOfBoundsException is not subtype of Throwable
  258    Parameter $default of method Ds\Map::remove() has invalid typehint type Ds\TDefault.
  258    Return typehint of method Ds\Map::remove() has invalid type Ds\TDefault.
  346    Property Ds\Pair::$key has no typehint specified.
  351    Property Ds\Pair::$value has no typehint specified.
  401    PHPDoc tag @throws with type UnderflowException is not subtype of Throwable
  407    PHPDoc tag @throws with type OutOfRangeException is not subtype of Throwable
  413    PHPDoc tag @throws with type OutOfRangeException is not subtype of Throwable
  425    PHPDoc tag @throws with type UnderflowException is not subtype of Throwable
  444    PHPDoc tag @throws with type UnderflowException is not subtype of Throwable
  463    PHPDoc tag @throws with type OutOfRangeException is not subtype of Throwable
  474    PHPDoc tag @throws with type OutOfRangeException is not subtype of Throwable
  480    PHPDoc tag @throws with type UnderflowException is not subtype of Throwable
  510    Class Ds\Vector implements generic interface ArrayAccess but does not specify its types: TKey, TValue
  605    PHPDoc tag @throws with type UnderflowException is not subtype of Throwable
  613    PHPDoc tag @throws with type OutOfRangeException is not subtype of Throwable
  629    PHPDoc tag @throws with type UnderflowException is not subtype of Throwable

@enumag
Copy link
Copy Markdown
Contributor Author

enumag commented Dec 19, 2019

If you want to allow passing Foo<DateTimeImmutable> into Foo<DateTimeInterface>, you need @template-covariant above Foo.

Hmm... isn't that always the case? Can you give an example where @template-covariant should NOT be used? Because honestly I can't think of one.

I've ran this PR on top of my local branch where I do some basic stub validation. Here are the errors:

Thanks! This is very helpful.

@ondrejmirtes
Copy link
Copy Markdown
Member

It's not always the case, if you're not careful you can produce a runtime error. See:

/**
 * @param Collection<Animal> $animalCollection
 */
function addAnimal(Collection $animalCollection): void
{
    $collection->add(new Cat()); // this is fine, code does not violate anything
}

/**
 * @param Collection<Dog> $dogCollection
 */
function takesDogList(Collection $dogCollection): void
{
    addAnimal($dogCollection); // this is not, Cat will be added
}

@enumag
Copy link
Copy Markdown
Contributor Author

enumag commented Dec 19, 2019

Ok, that explains it a bit. Though I still don't quite understand how to decide which type parameter should be covariant and which shouldn't. 🤔

@ondrejmirtes
Copy link
Copy Markdown
Member

ondrejmirtes commented Dec 19, 2019

I must admit I don't either. But PHPStan can usually point out if the @template-covariant would break something, so you can try it out.

@ondrejmirtes
Copy link
Copy Markdown
Member

Turns out the @throws stuff was false positive. If you rebase your branch on top of master, you should see these errors:

  36     Class Ds\Deque implements generic interface ArrayAccess but does not specify its types: TKey, TValue
  36     Class Ds\Deque implements generic interface IteratorAggregate but does not specify its types: TKey, TValue
  223    Return typehint of method Ds\Map::pairs() has invalid type Ds\Tkey.
  258    Parameter $default of method Ds\Map::remove() has invalid typehint type Ds\TDefault.
  258    Return typehint of method Ds\Map::remove() has invalid type Ds\TDefault.
  346    Property Ds\Pair::$key has no typehint specified.
  351    Property Ds\Pair::$value has no typehint specified.
  510    Class Ds\Vector implements generic interface ArrayAccess but does not specify its types: TKey, TValue

@enumag enumag force-pushed the feature/ds-generics branch 2 times, most recently from 5794584 to 5946c81 Compare January 2, 2020 08:16
@enumag
Copy link
Copy Markdown
Contributor Author

enumag commented Jan 2, 2020

Rebased to master but I don't know how to run the tests to see the errors you reported earlier. When I run phing I'm getting some completely unrelated issues:

➜  phpstan-src git:(feature/ds-generics) vendor/bin/phing
PHP Deprecated:  Array and string offset access syntax with curly braces is deprecated in /home/tousek/Projects/phpstan/phpstan-src/vendor/phing/phing/classes/phing/system/io/UnixFileSystem.php on line 97
PHP Stack trace:
PHP   1. {main}() /home/tousek/Projects/phpstan/phpstan-src/vendor/phing/phing/bin/phing:0
PHP   2. require_once() /home/tousek/Projects/phpstan/phpstan-src/vendor/phing/phing/bin/phing:14
PHP   3. Phing::fire() /home/tousek/Projects/phpstan/phpstan-src/vendor/phing/phing/bin/phing.php:58
PHP   4. Phing::start() /home/tousek/Projects/phpstan/phpstan-src/vendor/phing/phing/classes/phing/Phing.php:347
PHP   5. Phing->execute() /home/tousek/Projects/phpstan/phpstan-src/vendor/phing/phing/classes/phing/Phing.php:182
PHP   6. PhingFile->__construct() /home/tousek/Projects/phpstan/phpstan-src/vendor/phing/phing/classes/phing/Phing.php:560
PHP   7. FileSystem::getFileSystem() /home/tousek/Projects/phpstan/phpstan-src/vendor/phing/phing/classes/phing/system/io/PhingFile.php:62
PHP Deprecated:  Array and string offset access syntax with curly braces is deprecated in /home/tousek/Projects/phpstan/phpstan-src/vendor/phing/phing/classes/phing/system/io/UnixFileSystem.php on line 126
PHP Stack trace:
PHP   1. {main}() /home/tousek/Projects/phpstan/phpstan-src/vendor/phing/phing/bin/phing:0
PHP   2. require_once() /home/tousek/Projects/phpstan/phpstan-src/vendor/phing/phing/bin/phing:14
PHP   3. Phing::fire() /home/tousek/Projects/phpstan/phpstan-src/vendor/phing/phing/bin/phing.php:58
PHP   4. Phing::start() /home/tousek/Projects/phpstan/phpstan-src/vendor/phing/phing/classes/phing/Phing.php:347
PHP   5. Phing->execute() /home/tousek/Projects/phpstan/phpstan-src/vendor/phing/phing/classes/phing/Phing.php:182
PHP   6. PhingFile->__construct() /home/tousek/Projects/phpstan/phpstan-src/vendor/phing/phing/classes/phing/Phing.php:560
PHP   7. FileSystem::getFileSystem() /home/tousek/Projects/phpstan/phpstan-src/vendor/phing/phing/classes/phing/system/io/PhingFile.php:62
PHP Deprecated:  Array and string offset access syntax with curly braces is deprecated in /home/tousek/Projects/phpstan/phpstan-src/vendor/phing/phing/classes/phing/system/io/UnixFileSystem.php on line 139
PHP Stack trace:
PHP   1. {main}() /home/tousek/Projects/phpstan/phpstan-src/vendor/phing/phing/bin/phing:0
PHP   2. require_once() /home/tousek/Projects/phpstan/phpstan-src/vendor/phing/phing/bin/phing:14
PHP   3. Phing::fire() /home/tousek/Projects/phpstan/phpstan-src/vendor/phing/phing/bin/phing.php:58
PHP   4. Phing::start() /home/tousek/Projects/phpstan/phpstan-src/vendor/phing/phing/classes/phing/Phing.php:347
PHP   5. Phing->execute() /home/tousek/Projects/phpstan/phpstan-src/vendor/phing/phing/classes/phing/Phing.php:182
PHP   6. PhingFile->__construct() /home/tousek/Projects/phpstan/phpstan-src/vendor/phing/phing/classes/phing/Phing.php:560
PHP   7. FileSystem::getFileSystem() /home/tousek/Projects/phpstan/phpstan-src/vendor/phing/phing/classes/phing/system/io/PhingFile.php:62
PHP Deprecated:  Array and string offset access syntax with curly braces is deprecated in /home/tousek/Projects/phpstan/phpstan-src/vendor/phing/phing/classes/phing/system/io/UnixFileSystem.php on line 177
PHP Stack trace:
PHP   1. {main}() /home/tousek/Projects/phpstan/phpstan-src/vendor/phing/phing/bin/phing:0
PHP   2. require_once() /home/tousek/Projects/phpstan/phpstan-src/vendor/phing/phing/bin/phing:14
PHP   3. Phing::fire() /home/tousek/Projects/phpstan/phpstan-src/vendor/phing/phing/bin/phing.php:58
PHP   4. Phing::start() /home/tousek/Projects/phpstan/phpstan-src/vendor/phing/phing/classes/phing/Phing.php:347
PHP   5. Phing->execute() /home/tousek/Projects/phpstan/phpstan-src/vendor/phing/phing/classes/phing/Phing.php:182
PHP   6. PhingFile->__construct() /home/tousek/Projects/phpstan/phpstan-src/vendor/phing/phing/classes/phing/Phing.php:560
PHP   7. FileSystem::getFileSystem() /home/tousek/Projects/phpstan/phpstan-src/vendor/phing/phing/classes/phing/system/io/PhingFile.php:62
PHP Deprecated:  Array and string offset access syntax with curly braces is deprecated in /home/tousek/Projects/phpstan/phpstan-src/vendor/phing/phing/classes/phing/system/io/UnixFileSystem.php on line 197
PHP Stack trace:
PHP   1. {main}() /home/tousek/Projects/phpstan/phpstan-src/vendor/phing/phing/bin/phing:0
PHP   2. require_once() /home/tousek/Projects/phpstan/phpstan-src/vendor/phing/phing/bin/phing:14
PHP   3. Phing::fire() /home/tousek/Projects/phpstan/phpstan-src/vendor/phing/phing/bin/phing.php:58
PHP   4. Phing::start() /home/tousek/Projects/phpstan/phpstan-src/vendor/phing/phing/classes/phing/Phing.php:347
PHP   5. Phing->execute() /home/tousek/Projects/phpstan/phpstan-src/vendor/phing/phing/classes/phing/Phing.php:182
PHP   6. PhingFile->__construct() /home/tousek/Projects/phpstan/phpstan-src/vendor/phing/phing/classes/phing/Phing.php:560
PHP   7. FileSystem::getFileSystem() /home/tousek/Projects/phpstan/phpstan-src/vendor/phing/phing/classes/phing/system/io/PhingFile.php:62
PHP Deprecated:  Array and string offset access syntax with curly braces is deprecated in /home/tousek/Projects/phpstan/phpstan-src/vendor/phing/phing/classes/phing/system/io/UnixFileSystem.php on line 258
PHP Stack trace:
PHP   1. {main}() /home/tousek/Projects/phpstan/phpstan-src/vendor/phing/phing/bin/phing:0
PHP   2. require_once() /home/tousek/Projects/phpstan/phpstan-src/vendor/phing/phing/bin/phing:14
PHP   3. Phing::fire() /home/tousek/Projects/phpstan/phpstan-src/vendor/phing/phing/bin/phing.php:58
PHP   4. Phing::start() /home/tousek/Projects/phpstan/phpstan-src/vendor/phing/phing/classes/phing/Phing.php:347
PHP   5. Phing->execute() /home/tousek/Projects/phpstan/phpstan-src/vendor/phing/phing/classes/phing/Phing.php:182
PHP   6. PhingFile->__construct() /home/tousek/Projects/phpstan/phpstan-src/vendor/phing/phing/classes/phing/Phing.php:560
PHP   7. FileSystem::getFileSystem() /home/tousek/Projects/phpstan/phpstan-src/vendor/phing/phing/classes/phing/system/io/PhingFile.php:62
Buildfile: /home/tousek/Projects/phpstan/phpstan-src/build.xml

PHPStan > composer-validate:

./composer.json is valid

PHPStan > composer-install:

Loading composer repositories with package information
Installing dependencies (including require-dev) from lock file
Nothing to install or update
Generating autoload files
ocramius/package-versions:  Generating version class...
ocramius/package-versions: ...done generating version class
PHP CodeSniffer Config installed_paths set to ../../slevomat/coding-standard

PHPStan > lint:

PHP 7.4.0 | 10 parallel jobs
............................................................   60/1044 (5 %)
............................................................  120/1044 (11 %)
............................................................  180/1044 (17 %)
............................................................  240/1044 (22 %)
............................................................  300/1044 (28 %)
............................................................  360/1044 (34 %)
............................................................  420/1044 (40 %)
............................................................  480/1044 (45 %)
............................................................  540/1044 (51 %)
...........................................................S  600/1044 (57 %)
S...........................................................  660/1044 (63 %)
............................................................  720/1044 (68 %)
............................................................  780/1044 (74 %)
............................................................  840/1044 (80 %)
............................................................  900/1044 (86 %)
............................................................  960/1044 (91 %)
............................................................ 1020/1044 (97 %)
........................                                     1044/1044 (100 %)


Checked 1042 files in 2 seconds, skipped 2 files
No syntax error found

PHPStan > cs:


PHPStan > composer-normalize-check:

./composer.json is already normalized.

PHPStan > composer-require-checker:

ComposerRequireChecker 2.0.0
There were no unknown symbols found.

PHPStan > test-configuration-validate:

  [xmllint] /home/tousek/Projects/phpstan/phpstan-src/tests/phpunit.xml validated with schema

PHPStan > tests:

PHPUnit 7.5.18 by Sebastian Bergmann and contributors.

FFFFFSSFFFFFFFFFFFF.....................FFFFFFFFFFFFFF.......   61 / 4579 (  1%)
.............................................................  122 / 4579 (  2%)
.............................................................  183 / 4579 (  3%)
.............................................................  244 / 4579 (  5%)
.............................................................  305 / 4579 (  6%)
.........................S...................................  366 / 4579 (  7%)
.............................................................  427 / 4579 (  9%)
.............................................................  488 / 4579 ( 10%)
.............................................................  549 / 4579 ( 11%)
.............................................................  610 / 4579 ( 13%)
.............................................................  671 / 4579 ( 14%)
.............................................................  732 / 4579 ( 15%)
.............................................................  793 / 4579 ( 17%)
.............................................................  854 / 4579 ( 18%)
.............................................................  915 / 4579 ( 19%)
.............................................................  976 / 4579 ( 21%)
............................................................. 1037 / 4579 ( 22%)
............................................................. 1098 / 4579 ( 23%)
............................................................. 1159 / 4579 ( 25%)
............................................................. 1220 / 4579 ( 26%)
............................................................. 1281 / 4579 ( 27%)
............................................................. 1342 / 4579 ( 29%)
............................................................. 1403 / 4579 ( 30%)
............................................................. 1464 / 4579 ( 31%)
............................................................. 1525 / 4579 ( 33%)
............................................................. 1586 / 4579 ( 34%)
............................................................. 1647 / 4579 ( 35%)
............................................................. 1708 / 4579 ( 37%)
............................................................. 1769 / 4579 ( 38%)
............................................................. 1830 / 4579 ( 39%)
............................................................. 1891 / 4579 ( 41%)
............................................................. 1952 / 4579 ( 42%)
............................................................. 2013 / 4579 ( 43%)
............................................................. 2074 / 4579 ( 45%)
............................................................. 2135 / 4579 ( 46%)
............................................................. 2196 / 4579 ( 47%)
............................................................. 2257 / 4579 ( 49%)
............................................................. 2318 / 4579 ( 50%)
............................................................. 2379 / 4579 ( 51%)
............................................................. 2440 / 4579 ( 53%)
............................................................. 2501 / 4579 ( 54%)
............................................................. 2562 / 4579 ( 55%)
......S...................................................... 2623 / 4579 ( 57%)
............................................................. 2684 / 4579 ( 58%)
............................................................. 2745 / 4579 ( 59%)
..............................F..Could not read "tests/phpunit.xml".

BUILD FAILED
/home/tousek/Projects/phpstan/phpstan-src/build.xml:186:3: Task exited with code 1

Total time: 5 minutes  17.85 seconds

@enumag
Copy link
Copy Markdown
Contributor Author

enumag commented Jan 2, 2020

I fixed the errors you posted but I still don't know what to do with @template-covariant. I thought I would put it everywhere and revert it for all cases where phpstan would report a problem but since I can't get that report, I can't do it.

@enumag
Copy link
Copy Markdown
Contributor Author

enumag commented Jan 2, 2020

I added the dynamic return type extension. I tested it on my project and it seems to work fine.

@enumag
Copy link
Copy Markdown
Contributor Author

enumag commented Jan 2, 2020

In my project when I put @template-covariant instead of @template everywhere in ext-ds.php it doesn't report any new errors. Should I use covariant everywhere then? Not sure...

@ondrejmirtes
Copy link
Copy Markdown
Member

Hi, the build is failing, please fix it: https://travis-ci.org/phpstan/phpstan-src/jobs/631809338?utm_medium=notification&utm_source=github_status

It's not ideal to run the build on PHP 7.4. PHPStan supports it, but Phing outputs some deprecated warnings and PHPCS is completely skipped.

@ondrejmirtes
Copy link
Copy Markdown
Member

If PHPStan isn't reporting anything, template-covariant should be fine.

@enumag enumag force-pushed the feature/ds-generics branch from 5c273fe to 8301008 Compare January 2, 2020 12:20
@enumag
Copy link
Copy Markdown
Contributor Author

enumag commented Jan 2, 2020

Coding style should be fixed now. Changed everything to @template-covariant too.

@enumag
Copy link
Copy Markdown
Contributor Author

enumag commented Jan 2, 2020

Build is failing because the ds extension is missing on travis so we need to add it using pecl. I'm not exactly sure where though since your travis configuration if quite complicated.

@ondrejmirtes
Copy link
Copy Markdown
Member

The extension isn’t necessary for anything, the code doesn’t depend on it. Why does it fail? (I’m on mobile.)

@enumag
Copy link
Copy Markdown
Contributor Author

enumag commented Jan 2, 2020

Here is the failure:

ComposerRequireChecker 2.0.0
The following unknown symbols were found:
+----------------+--------------------+
| unknown symbol | guessed dependency |
+----------------+--------------------+
| Ds\Map         |                    |
+----------------+--------------------+

Since it only reports the Map class, I assume it's because of the DsMapDynamicReturnTypeExtension which I added to correctly handle the Map::get() and Map::remove() methods.

@enumag
Copy link
Copy Markdown
Contributor Author

enumag commented Jan 2, 2020

This is the issue I think:

final class DsMapDynamicReturnTypeExtension implements DynamicMethodReturnTypeExtension
{
	public function getClass(): string
	{
		return Map::class;
	}

Maybe I should use return 'Ds\Map'; instead?

@ondrejmirtes
Copy link
Copy Markdown
Member

Yes 😊

@ondrejmirtes
Copy link
Copy Markdown
Member

There are apparently some errors in the stubs. Please run vendor/bin/phing phpstan locally to see them. (It's possible it's going to be about the covariance.)

@enumag
Copy link
Copy Markdown
Contributor Author

enumag commented Jan 2, 2020

Well that reported @template-covariant as an error everywhere except for 3 places. I reverted it everywhere except these 3 cases but I'm still not quite sure what's correct.

@ondrejmirtes
Copy link
Copy Markdown
Member

Looks awesome, thank you! We can course-correct if some problems appear in the future.

@ondrejmirtes ondrejmirtes merged commit 26d27be into phpstan:master Jan 2, 2020
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.

2 participants