Skip to content

Commit 72ec631

Browse files
phpstan-botclaude
andcommitted
Add non-regression tests for phpstan/phpstan#5298 and phpstan/phpstan#3028
Ensure ObjectType::equals() change doesn't regress generic type invariance checks for template type assignments and return types. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 5e2cd3b commit 72ec631

File tree

2 files changed

+93
-0
lines changed

2 files changed

+93
-0
lines changed
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
<?php
2+
3+
declare(strict_types = 1);
4+
5+
namespace Bug3028;
6+
7+
use function PHPStan\Testing\assertType;
8+
9+
interface Output { }
10+
final class OutputImpl1 implements Output { }
11+
final class OutputImpl2 implements Output { }
12+
13+
/** @template O of Output */
14+
interface Format
15+
{
16+
/** @return O */
17+
public function output() : Output;
18+
19+
/** @param O $o */
20+
public function replace(Output $o) : void;
21+
}
22+
23+
/** @implements Format<OutputImpl1> */
24+
final class FormatImpl1 implements Format
25+
{
26+
public OutputImpl1 $o;
27+
28+
public function __construct() { $this->o = new OutputImpl1; }
29+
30+
public function output() : Output { return new OutputImpl1(); }
31+
32+
/** @param OutputImpl1 $o */
33+
public function replace(Output $o) : void { $this->o = $o; }
34+
}
35+
36+
/**
37+
* @template O of Output
38+
* @param Format<O> $outputFormat
39+
* @return Format<Output>
40+
*/
41+
function run(Format $outputFormat) : Format {
42+
return $outputFormat;
43+
}
44+
45+
function test(): void
46+
{
47+
$a = new FormatImpl1;
48+
assertType('Bug3028\FormatImpl1', $a);
49+
assertType('Bug3028\Format<Bug3028\Output>', run($a));
50+
assertType('Bug3028\Output', run($a)->output());
51+
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
<?php
2+
3+
declare(strict_types = 1);
4+
5+
namespace Bug5298;
6+
7+
use function PHPStan\Testing\assertType;
8+
9+
interface WorldProvider{}
10+
interface WritableWorldProvider extends WorldProvider{}
11+
12+
/**
13+
* @phpstan-template TWorldProvider of WorldProvider
14+
*/
15+
class WorldProviderManagerEntry{
16+
/** @phpstan-param TWorldProvider $provider */
17+
public function acceptsTWorldProvider(WorldProvider $provider) : void{}
18+
}
19+
20+
final class WorldProviderManager{
21+
/** @phpstan-var array<string, WorldProviderManagerEntry<WorldProvider>> */
22+
protected $providers = [];
23+
24+
/**
25+
* @phpstan-template T of WorldProvider
26+
* @phpstan-param WorldProviderManagerEntry<T> $providerEntry
27+
*/
28+
public function addProvider(WorldProviderManagerEntry $providerEntry, string $name, bool $overwrite = false) : void{
29+
$name = strtolower($name);
30+
if(!$overwrite and isset($this->providers[$name])){
31+
throw new \InvalidArgumentException("Alias \"$name\" is already assigned");
32+
}
33+
assertType('array<string, Bug5298\WorldProviderManagerEntry<Bug5298\WorldProvider>>', $this->providers);
34+
assertType('Bug5298\WorldProviderManagerEntry<T of Bug5298\WorldProvider (method Bug5298\WorldProviderManager::addProvider(), argument)>', $providerEntry);
35+
$this->providers[$name] = $providerEntry;
36+
}
37+
38+
public function doSomething(string $name, WorldProvider $provider) : void{
39+
assertType('Bug5298\WorldProviderManagerEntry<Bug5298\WorldProvider>', $this->providers[$name]);
40+
$this->providers[$name]->acceptsTWorldProvider($provider);
41+
}
42+
}

0 commit comments

Comments
 (0)