В Swift 6.4 продолжается работа над улучшением тайпчекера. Знаменитая ошибка «The compiler is unable to type-check this expression in reasonable time» во многих ситуациях теперь будет появляться реже. Слава Пестов в большом посте на Swift Forums делится прогрессом по роадмапу и показывает, как это работает на практике.
О проблеме известно давно:
Тайпчекер в Swift - это сложная система, которая пытается вывести типы выражений, когда они не указаны явно. Чем больше перегрузок, дженериков и неявных преобразований, тем сложнее компилятору найти правильный тип. Иногда он перебирает слишком много вариантов и либо выдает ошибку, либо компилирует слишком долго.
В Swift 6.3 добавили механизм favoring - когда компилятор пытается угадать наиболее вероятный вариант перегрузки и проверяет его первым. Это работает хорошо, когда угадывание правильное. Но если нет - компилятор все равно перебирает все варианты, и это может занять много времени.
Что изменилось в Swift 6.4:
В Swift 6.4 появился механизм, который называется disjunction pruning - обрезка перегрузок. Суть простая: когда компилятор проверяет конкретную перегрузку функции, он может понять, что она точно не подходит. В таком случае он просто исключает этот вариант из рассмотрения.
Раньше компилятор мог потратить время на перебор вариантов, которые заведомо не работают. Теперь он сразу понимает, что вариант не подходит, и даже не пытается его проверить.
Это работает в двух направлениях. Если из всех вариантов остался только один подходящий - компилятор сразу выбирает его, не тратя время на остальные. Если же подходящих вариантов не осталось - компилятор сразу понимает, что выражение ошибочно, и не пытается перебирать дальше.
Улучшения в binding inference:
Вторая важная область - вывод конкретных типов из неявных преобразований. Раньше, когда компилятор видел выражение вроде Int conv
$T (где $T - неизвестный тип), он не мог сразу понять, чему равен $T. Приходилось откладывать решение и перебирать варианты позже.В Swift 6.4 появилась более точная логика, которая анализирует все ограничения на тип одновременно. Если все ограничения указывают на единственный возможный тип - компилятор выбирает его сразу. Если же ограничения противоречат друг другу - компилятор понимает, что выражение ошибочно, и не тратит время на перебор.
Что это дает на практике:
Есть несколько примеров, которые раньше компилировались очень долго или вообще не компилировались.
🔵Побитовые операции с UInt64:
func f(word: UInt64, offset: Int, numBits: Int) -> UInt {
return UInt((word >> offset) & ((1 << numBits) - 1) & ((1 << numBits) - 1) & ((1 << numBits) - 1))
}В Swift 6.3 это выражение было слишком сложным для тайпчекера. В Swift 6.4 компилируется мгновенно.
🔵Операции с SIMD:
func f() {
let u = SIMD2<Float>(0, 1)
let v = SIMD2<Float>(1, 2)
let r = [2*u + 3*v, 4*u + 5*v, 5*u + 6*v, 6*u + 7*v]
}Теперь тоже компилируется быстро.
🔵Словари с IUO (implicitly unwrapped optional):
func f(str: CFString!) {
let _ = [
str: String(str),
str: String(str),
str: String(str)
]
}Раньше было слишком сложно, теперь - мгновенно.
🔵Цепочки вызовов с lazy, flatMap, map, filter - раньше занимали секунды, теперь миллисекунды.
🔗 Читать подробнее
💡 Вывод:
Swift 6.4 не делает тайпчекер идеальным, но делает его заметно быстрее в распространенных сценариях. Механизмы disjunction pruning и улучшенный binding inference позволяют компилятору быстрее принимать решения и избегать перебора заведомо неподходящих вариантов.
Это не решит все проблемы с тайпчекингом, но во многих случаях ошибка «unable to type-check in reasonable time» станет встречаться реже. А в некоторых сложных выражениях компиляция ускорится в десятки раз. Хорошее улучшение для повседневной разработки.
Подписаться на канал:
➡️ Telegram | Max