,error_levels?:string[]}> */ public function providerValidCodeParse(): iterable { return [ 'argumentUnpackingLiteral' => [ ' [ ' [ '$a' => 'non-empty-list', ], ], 'arrayMergeArgumentUnpacking' => [ ' [ '$b' => 'array{0: int, 1: int}', ], ], 'preserveTypesWhenUnpacking' => [ '> */ function getData(): array { return [ ["a", "b"], ["c", "d"] ]; } /** * @return array */ function f1(): array { $data = getData(); return array_merge($data[0], $data[1]); } /** * @return array */ function f2(): array { $data = getData(); return array_merge(...$data); } /** * @return array */ function f3(): array { $data = getData(); return array_merge([], ...$data); }', ], 'unpackArg' => [ ' */ function Baz(string ...$c) { Foo(...$c); return $c; }', ], 'unpackByRefArg' => [ ' [ '$y' => 'int', '$z' => 'array', ], ], 'callMapClassOptionalArg' => [ 'invoke(null, "cool");', ], 'sortFunctions' => [ ' 5, "a" => 8]; ksort($a); $b = ["b" => 5, "a" => 8]; sort($b); ', 'assertions' => [ '$a' => 'array{a: int, b: int}', '$b' => 'list', ], ], 'arrayModificationFunctions' => [ ' 5, "a" => 8]; array_unshift($a, (bool)rand(0, 1)); $b = ["b" => 5, "a" => 8]; array_push($b, (bool)rand(0, 1)); ', 'assertions' => [ '$a' => 'non-empty-array', '$b' => 'non-empty-array', ], ], 'byRefArgAssignment' => [ ' [ ' [ ' [ ' $arr */ function foo(array $arr) : void { } /** @return array */ function bar() : array { return []; } /** @psalm-suppress InvalidScalarArgument */ foo(bar());', ], 'allowArrayScalarForArrayStringWithScalarIgnored' => [ ' $arr */ function foo(array $arr) : void {} /** @return array */ function bar() : array { return []; } /** @psalm-suppress InvalidScalarArgument */ foo(bar());', ], 'unpackObjectlikeListArgs' => [ ' [ ' 'non-empty-list' ] ], 'iterableSplat' => [ ' $args */ function foo(iterable $args): int { return intval(...$args); } /** @param ArrayIterator $args */ function bar(ArrayIterator $args): int { return intval(...$args); }', ], 'unpackListWithOptional' => [ ' [ ' [ ' [ ' "hello", "age" => 5]; takesArguments(...$args);', [], [], '8.0' ], 'useNamedVariadicArguments' => [ ' [ ' 5]);', [], [], '8.0' ], 'variadicArgsOptional' => [ ' [ ' [ ' */ public function foo(int ...$values): array { return $values; } } ', ], ]; } /** * @return iterable */ public function providerInvalidCodeParse(): iterable { return [ 'arrayPushArgumentUnpackingWithBadArg' => [ ' 'InvalidArgument', ], 'possiblyInvalidArgument' => [ ' 'PossiblyInvalidArgument', ], 'possiblyInvalidArgumentWithOverlap' => [ ' 'PossiblyInvalidArgument', ], 'possiblyInvalidArgumentWithMixed' => [ ' 'PossiblyInvalidArgument', ], 'expectsNonNullAndPassedPossiblyNull' => [ ' 'PossiblyNullArgument' ], 'useInvalidNamedArgument' => [ ' 'InvalidNamedArgument' ], 'usePositionalArgAfterNamed' => [ ' 'InvalidNamedArgument' ], 'useUnpackedInvalidNamedArgument' => [ ' 'InvalidNamedArgument', [], false, '8.0' ], 'noNamedArgsMethod' => [ ' 'NamedArgumentNotAllowed', ], 'noNamedArgsFunction' => [ ' 'NamedArgumentNotAllowed', ], 'arrayWithoutAllNamedParameters' => [ ' 'MixedArgument', [], false, '8.0' ], 'arrayWithoutAllNamedParametersSuppressMixed' => [ ' 'TooFewArguments', [], false, '8.0' ], 'wrongTypeVariadicArguments' => [ ' 'InvalidScalarArgument', [], false, '8.0' ], 'byrefVarSetsPossible' => [ ' 'PossiblyUndefinedGlobalVariable', ], 'overwriteNamedParam' => [ ' 'InvalidNamedArgument', [], false, '8.0' ], 'overwriteOrderedNamedParam' => [ ' 'InvalidNamedArgument', [], false, '8.0' ], 'overwriteOrderedWithUnpackedNamedParam' => [ ' 2]);', 'error_message' => 'InvalidNamedArgument', [], false, '8.0' ], 'variadicArgumentIsNotList' => [ ' */ function foo(int ...$values): array { return $values; } ', 'error_message' => 'MixedReturnTypeCoercion', ], 'preventUnpackingPossiblyIterable' => [ '|object */ $test = [1, 2]; foo(...$test); ', 'error_message' => 'PossiblyInvalidArgument' ], 'SKIPPED-preventUnpackingPossiblyArray' => [ '|object */ $test = [1, 2]; foo(...$test); ', 'error_message' => 'PossiblyInvalidArgument' ], 'noNamedArguments' => [ ' 'NamedArgumentNotAllowed', [], false, '8.0', ], 'noNamedArgumentsUnpackIterable' => [ ' */ $test = ["arg1" => 1, "arg2" => 2]; foo(...$test); ', 'error_message' => 'NamedArgumentNotAllowed', [], false, '8.0', ], 'variadicArgumentWithNoNamedArgumentsPreventsPassingArrayWithStringKey' => [ ' */ function foo(int ...$values): array { return $values; } foo(...["a" => 0]); ', 'error_message' => 'NamedArgumentNotAllowed', ], 'unpackNonArrayKeyIterable' => [ ' */ $test = null; foo(...$test); ', 'error_message' => 'InvalidArgument', ], 'numericStringIsNotNonFalsy' => [ ' 'ArgumentTypeCoercion', ], 'objectIsNotObjectWithProperties' => [ ' 42]; } /** @param object{hmm:float} $_o */ function takesObject($_o): void {} takesObject(makeObj()); // expected: ArgumentTypeCoercion ', 'error_message' => 'ArgumentTypeCoercion', ], 'MissingMandatoryParamWithNamedParams' => [ ' 'TooFewArguments', ], ]; } }