,error_levels?:string[]}> */ public function providerValidCodeParse() { return [ 'validSimpleAnnotations' => [ 'getString(); $child->setInteger(4);', 'assertions' => [ '$a' => 'string', ], ], 'anotherSimpleExample' => [ 'b = new B(); } public function c(string $s) : void {} /** * @param array $arguments * @return mixed */ public function __call(string $method, array $arguments) { return $this->b->$method(...$arguments); } } class B { public function b(): void { echo "b"; } public function c(int $s) : void {} } $a = new A(); $a->b();' ], 'allowConstructor' => [ 'i = 1; } } class M { public function __construct() {} } /** * @mixin M */ class A extends AParent {}' ], 'implicitMixin' => [ 'valid()) { if (!$iterator->isDot() && $iterator->isLink()) {} $iterator->next(); } }' ], 'wrapCustomIterator' => [ 'index(0);', [ '$b' => 'bool', ] ], 'templatedMixin' => [ ' */ class Bar {} $bar = new Bar(); $b = $bar->hi();', [ '$b' => 'string', ] ], 'templatedMixinSelf' => [ 'item = $item; } /** * @return T */ public function get() { return $this->item; } } /** * @mixin Animal */ class Dog { public function __construct() {} } function getDog(): Dog { return (new Dog())->get(); }' ], 'inheritPropertyAnnotations' => [ 'foo; }' ], 'inheritTemplatedMixinWithStatic' => [ 'var = $var; } /** * @psalm-return T */ public function type() { return $this->var; } } /** * @template T as object * @mixin Mixin */ abstract class Foo { /** @var Mixin */ public object $obj; public function __call(string $name, array $args) { return $this->obj->$name(...$args); } } /** * @extends Foo */ abstract class FooChild extends Foo{} /** * @psalm-suppress MissingConstructor */ final class FooGrandChild extends FooChild {} function test() : FooGrandChild { return (new FooGrandChild)->type(); }' ], 'inheritTemplatedMixinWithStaticAndFinalClass' => [ 'var = $var; } /** * @psalm-return self */ public function getMixin() { return $this; } } /** * @template T as object * @mixin Mixin */ abstract class Foo { /** @var Mixin */ public object $obj; public function __call(string $name, array $args) { return $this->obj->$name(...$args); } } /** * @extends Foo */ abstract class FooChild extends Foo{} /** * @psalm-suppress MissingConstructor */ final class FooGrandChild extends FooChild {} /** * @psalm-return Mixin */ function test() : Mixin { return (new FooGrandChild)->getMixin(); }' ], ]; } /** * @return iterable */ public function providerInvalidCodeParse() { return [ 'undefinedMixinClass' => [ ' 'UndefinedDocblockClass' ], 'undefinedMixinClassWithPropertyFetch' => [ 'foo;', 'error_message' => 'UndefinedPropertyFetch' ], 'undefinedMixinClassWithPropertyAssignment' => [ 'foo = "bar";', 'error_message' => 'UndefinedPropertyAssignment' ], 'undefinedMixinClassWithMethodCall' => [ 'foo();', 'error_message' => 'UndefinedMethod' ], 'inheritTemplatedMixinWithSelf' => [ 'var = $var; } /** * @psalm-return T */ public function type() { return $this->var; } } /** * @template T as object * @mixin Mixin */ abstract class Foo { /** @var Mixin */ public object $obj; public function __call(string $name, array $args) { return $this->obj->$name(...$args); } } /** * @extends Foo */ abstract class FooChild extends Foo{} /** * @psalm-suppress MissingConstructor */ final class FooGrandChild extends FooChild {} function test() : FooGrandChild { return (new FooGrandChild)->type(); }', 'error_message' => 'LessSpecificReturnStatement' ], ]; } }