<?php

/**
 * @psalm-immutable
 */
class DateTimeImmutable implements DateTimeInterface
{
    public function __construct(string $time = "now", DateTimeZone $tz = null) {}
}

/**
 * @psalm-immutable
 */
class DateTimeZone
{
    public function __construct(string $tz) {}
}

interface Throwable
{
    /**
     * @psalm-mutation-free
     */
    public function getMessage() : string;

    /**
     * @psalm-mutation-free
     *
     * @return int|string https://www.php.net/manual/en/throwable.getcode.php
     */
    public function getCode();

    /**
     * @psalm-mutation-free
     */
    public function getFile() : string;

    /**
     * @psalm-mutation-free
     */
    public function getLine() : int;

    /**
     * @psalm-mutation-free
     */
    public function getTrace() : array;

    /**
     * @psalm-mutation-free
     */
    public function getPrevious() : ?Throwable;

    /**
     * @psalm-mutation-free
     */
    public function getTraceAsString() : string;
}

class Exception implements Throwable
{
    /**
     * @var string
     */
    protected $message = '';

    /**
     * @var int
     */
    protected $code = 0;

    /**
     * @var string
     */
    protected $file = '';

    /**
     * @var int
     */
    protected $line = 0;

    /**
     * @psalm-external-mutation-free
     * @param string $message
     * @param int $code
     * @param Throwable $previous
     */
    public function __construct($message = "", $code = 0, Throwable $previous = null) {}

    /**
     * @psalm-mutation-free
     */
    public final function getMessage() : string {}

    /**
     * @psalm-mutation-free
     *
     * @return int|string https://www.php.net/manual/en/throwable.getcode.php
     */
    public final function getCode() {}

    /**
     * @psalm-mutation-free
     */
    public final function getFile(): string {}

    /**
     * @psalm-mutation-free
     */
    public final function getLine(): int {}

    /**
     * @psalm-mutation-free
     */
    public final function getTrace() : array {}

    /**
     * @psalm-mutation-free
     */
    public final function getPrevious() : ?Throwable {}

    /**
     * @psalm-mutation-free
     */
    public final function getTraceAsString() : string {}
}

class Error implements Throwable
{
    /**
     * @var string
     */
    protected $message = '';

    /**
     * @var int
     */
    protected $code = 0;

    /**
     * @var string
     */
    protected $file = '';

    /**
     * @var int
     */
    protected $line = 0;

    /**
     * @psalm-external-mutation-free
     * @param string $message
     * @param int $code
     * @param Throwable $previous
     */
    public function __construct($message = "", $code = 0, Throwable $previous = null) {}

    /**
     * @psalm-mutation-free
     */
    public final function getMessage() : string {}

    /**
     * @psalm-mutation-free
     */
    public final function getCode(): int {}

    /**
     * @psalm-mutation-free
     */
    public final function getFile(): string {}

    /**
     * @psalm-mutation-free
     */
    public final function getLine(): int{}

    /**
     * @psalm-mutation-free
     */
    public final function getTrace() : array {}

    /**
     * @psalm-mutation-free
     */
    public final function getPrevious() : ?Throwable {}

    /**
     * @psalm-mutation-free
     */
    public final function getTraceAsString() : string {}
}
