В 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 появилась более точная логика, которая анализирует все ограничения на тип одновременно. Если все ограничения указывают на единственный возможный тип - компилятор выбирает его сразу. Если же ограничения противоречат друг другу - компилятор понимает, что выражение ошибочно, и не тратит время на перебор.
Что это дает на практике:
Есть несколько примеров, которые раньше компилировались очень долго или вообще не компилировались.
Цепочки вызовов с lazy, flatMap, map, filter - раньше занимали секунды, теперь миллисекунды.
Что будет дальше:
Планируется дальнейшее улучшение binding inference для более сложных выражений с дженериками и замыканиями. Также работают над улучшением диагностики. Сейчас при ошибке тайпчекер переключается в диагностический режим и пытается найти все возможные варианты, чтобы выдать понятную ошибку. Это может быть очень медленным. В будущих версиях диагностику тоже ускорят.
Вывод:
Swift 6.4 не делает тайпчекер идеальным, но делает его заметно быстрее в распространенных сценариях. Механизмы disjunction pruning и улучшенный binding inference позволяют компилятору быстрее принимать решения и избегать перебора заведомо неподходящих вариантов.
Это не решит все проблемы с тайпчекингом, но во многих случаях ошибка «unable to type-check in reasonable time» станет встречаться реже. А в некоторых сложных выражениях компиляция ускорится в десятки раз. Хорошее улучшение для повседневной разработки.