Почему перечисления не расширяемы

У классов есть контракты на их методы:

<?php

class A {}
class
B extends A {}

function
foo(A $a) {}

function
bar(B $b) {
foo($b);
}
?>

Этот код безопасен для типов, поскольку B следует контракту A, и, благодаря магии ковариантности и контравариантности, любое ожидание, которое может быть у человека в отношении методов, будет сохранено, за исключением исключений.

У перечислений есть контракты на их варианты, а не методы:

<?php
enum ErrorCode {
case
SOMETHING_BROKE;
}

function
quux(ErrorCode $errorCode)
{
// Кажется, что этот код охватывает все варианты
match ($errorCode) {
ErrorCode::SOMETHING_BROKE => true,
}
}

?>

Оператор match в функции quux может быть статически проанализирован, чтобы охватить все случаи в ErrorCode.

Но представьте, что было бы разрешено расширять перечисления:

<?php
// Экспериментальный код, в котором перечисления не являются конечными.
// Обратите внимание, что это не будет работать в PHP.
enum MoreErrorCode extends ErrorCode {
case
PEBKAC;
}

function
fot(MoreErrorCode $errorCode) {
quux($errorCode);
}

fot(MoreErrorCode::PEBKAC);

?>

Согласно обычным правилам наследования, класс, расширяющий другой класс, пройдёт проверку типа.

Проблема заключается в том, что оператор match в quux() уже не охватывает все случаи. Поскольку оно не знает о MoreErrorCode::PEBKAC, match выбросит исключение.

Из-за этого перечисления являются окончательными и не могут быть расширены.