#prog #rust #article
В rustc есть такое дизайнерское решение: замыкание захватывает в сгенерированном типе все типы из своего окружения, в том числе и те, которые не имеют никакого отношения к коду замыкания. Это приводит к увеличению числа генерируемого LLVM IR и, как следствие, замедлению компиляции. И если выдумаете, что это чисто теоретическая проблема, то вот вам опровержение:
issue в репе раста, в котором Толян David Tolnay говорит, что:
> In fact this closure contributes more LLVM IR than all but 5 significantly larger functions
И это для замыкания, которое делает то, что вообще не зависит от захватываемых параметров!
Один из подходов для решения этой проблемы — добавить анализ, который будет проверять, что тИповые параметры реально используются, и для неиспользуемых не проделывать мономорфизацию. Именно такой анализ под названием "polymorphisation"
реализовал человек по имени
David Wood, причём как часть
своей магистерской диссертации. К сожалению, выяснилось, что этот анализ неполон и в реализованном виде может
приводить к мискомпиляции кода (метка regression-from-stable-to-nightly). В итоге проблему пришлось решить
отключением полиморфизации.
С того момента утекло немало воды и были внесены некоторые улучшения, но полиморфизация так и осталось проходом, отключённым по умолчанию. В немалой степени это связано с тем, что этот анализ был реализован в виде запроса, который рассматривает не более одной функции за раз. Для уточнения анализа требовалось сделать анализ транзитивным, что не работает с текущей архитектурой компилятора, которая запрещает циклы запросов. Я связался с Давидом, и он сказал мне, что у
lcnr есть идеи, как это можно исправить, и даже дал ссылки на наработки:
1,
2. Другое дело, что в текущем виде решение пока что неработоспособно, и последнее шевеление был в октябре этого года. Давид, впрочем, сказал, что это у него в списке дел на следующий год.
И ещё кое-что. Отсутствие полиморфизации позволяет написать
код, в котором замыкание захватывает собственный тип и потому приводит к ошибке компиляции на этапе мономорфизации. Что совсем нехорошо, мономорфизация происходит по требованию, а потому то, компилируется код или нет, зависит от уровня оптимизации, точнее, от того, сможет ли оптимизация убрать мертвый путь исполнения, который триггерит бесконечную мономорфизацию.
Вот такая вот фигня.
P. S.: диссертацию советую прочитать, это неплохой экскурс во внутреннее устройство rustc, а в начале много ссылок на работ по оптимизации, связанные со специализацией и генерализацией кода.