Управление ориентировано на выражения, а pattern точно задаёт, как единожды вычисленное значение проверяется, сужается, разбирается, связывается и учитывается в coverage.
Политика
if и match дают значение при согласованных ветвях. Каждая ветвь match начинается с case, catch-all — _. Есть literal, range, binding, type, constructor, array с rest .., structural record, nominal record и упорядоченный or-pattern. if let вычисляет scrutinee один раз и создаёт immutable bindings только в success-body; while let повторяет тест до первого несовпадения.
Определённое поведение
Ветка с guard не даёт exhaustiveness coverage. Закрытый enum проверяется по вариантам и irrefutable payload. List-rest получает Array<T>. Nominal-record pattern сначала проверяет declaration identity, затем поля слева направо. Or-pattern испытывает альтернативы слева направо со scratch bindings; binding-альтернативы должны иметь одинаковые имена и связанный overlap type. Выражение for собирает хвосты body по порядку, а instruction-for и while значения не дают.
Ограничения и явный отказ
Запрещены ...rest, qualified enum cases, пустой nominal-record pattern, parenthesized pattern, while let ... else, guard в голове if let и утечка bindings. Несовпадение refutable pattern в comprehension — fault, не фильтр. Bare break/continue требуют локальную цель; только контекстный loop объявляет labels и объединяет break values. Top-level return и общие statement arms у match статически ошибочны.
Отложенная граница
Goto-like labels, labels у while/for, переход через функцию, публичный Never, усиленные termination claims, расширенные pattern heads и fault-catching control отложены. Если scrutinee недостаточно конечен для статической проверки, канонический пример использует явный catch-all.
Пример
function describe(values: Array<int>) -> string {
match values {
case [] => "empty"
case [only] => "one: {only}"
case [head, ..tail] => "head: {head}, rest: {tail.length}"
}
}
let label = describe([1, 2, 3])