*/ public readonly array $parameters, public readonly Type $returnType, ) {} public static function default(): self { return self::$default ??= new self([], MixedType::get()); } public function accepts(mixed $value): bool { return is_callable($value); } public function compiledAccept(ComplianceNode $node): ComplianceNode { return Node::functionCall('is_callable', [$node]); } public function matches(Type $other): bool { if ($other instanceof MixedType) { return true; } if ($other instanceof UnionType) { return $other->isMatchedBy($this); } if (! $other instanceof self) { return false; } if (count($this->parameters) < count($other->parameters)) { return false; } foreach ($this->parameters as $key => $parameter) { if (! isset($other->parameters[$key])) { // @infection-ignore-all break; } if (! $parameter->matches($other->parameters[$key])) { return false; } } return $this->returnType->matches($other->returnType); } public function traverse(): array { return [...$this->parameters, $this->returnType]; } public function replace(callable $callback): Type { return new self( array_map($callback, $this->parameters), $callback($this->returnType), ); } public function inferGenericsFrom(Type $other, Generics $generics): Generics { return $generics; } public function nativeType(): Type { return $this; } public function toString(): string { if ($this === self::default()) { return 'callable'; } // PHP8.5 use pipes $parameters = implode( ', ', array_map(static fn (Type $type): string => $type->toString(), $this->parameters), ); return "callable($parameters): {$this->returnType->toString()}"; } }