Если коротко: в nightly-сборках Rust по умолчанию включают следующую версию анализатора заимствований — Polonius Alpha. В ближайшие месяцы разработчики планируют подготовить её к стабилизации.
Что меняется
У Rust появляется новая версия анализатора заимствований. Первый анализатор, известный как AST borrowck, имел множество ограничений. В 2019 году его заменили механизмом NLL — за исключением режима миграции, который использовался для более понятных сообщений об ошибках. Окончательно этот режим удалили в 2022 году.
Работа над Polonius началась в 2018 году как часть развития NLL. Первая реализация проходила набор тестов NLL и принимала корректный код, который NLL отклонял. Однако её производительность оказалась неприемлемой.
В большинстве случаев проверка заимствований работала медленнее NLL, а на некоторых программах время компиляции увеличивалось настолько, что практическое использование Polonius было невозможно. В последующие годы разработчики пытались ускорить исходную модель, но устранить основные проблемы с производительностью не удалось.
В 2023 году команда предложила новый вариант анализатора в стиле Polonius. Он потребовал минимальных изменений в существующей реализации NLL и сохранил возможность в дальнейшем принимать больше корректных программ.
Изначально эту версию рассчитывали подготовить к стабилизации ещё в 2024 году, но работа затянулась из-за других задач и технических сложностей.
Polonius Alpha включают в nightly-сборках
Сейчас команда не знает о нерешённых проблемах в той части Polonius, которую планируют стабилизировать под названием Polonius Alpha. Производительность также считается в целом приемлемой для стабилизации, хотя отдельные детали разработчики ещё продолжают оценивать.
Поэтому Polonius Alpha включают в nightly-сборках Rust по умолчанию. До стабилизации, запланированной на конец 2026 года, команда рассчитывает выявить:
-
серьёзные регрессии производительности;
-
потенциально некорректное поведение анализатора;
-
проблемы с диагностикой и сообщениями об ошибках.
На момент публикации разработчики не обнаружили изменений в диагностике. Сообщать о проблемах можно через GitHub или Zulip.
Что умеет Polonius Alpha
Главное отличие Polonius Alpha от NLL — анализ отношений между временами жизни с учётом конкретной ветки выполнения программы.
Минимальный пример кода, который принимает Polonius Alpha, но отклоняет текущий анализатор NLL:
fn reborrow(a: &mut u8) -> &mut u8 { let b = &mut *a; if true { b } else { a }}
На практике чаще встречается похожая ситуация при работе с HashMap:
fn get_mut_or_default<'r, K: Hash + Eq + Copy, V: Default>( map: &'r mut HashMap<K, V>, key: K,) -> &'r mut V { match map.get_mut(&key) { Some(value) => value, None => { map.insert(key, V::default()); map.get_mut(&key).unwrap() } }}
В этом примере функция либо возвращает существующее значение из HashMap, либо добавляет значение по умолчанию и затем возвращает изменяемую ссылку на него. NLL считает, что заимствование, созданное вызовом get_mut, может сохраняться и в ветке None, поэтому последующий вызов insert приводит к ошибке. Polonius Alpha анализирует ветки выполнения отдельно и понимает, что в ветке None предыдущее заимствование больше не используется.
Проблема в том, что ветка Some(value) => value заставляет анализатор заимствований считать, что ссылка, возвращаемая из map.get_mut(&key), существует на протяжении всей функции из-за возвращаемого типа &'r mut V. При этом в ветке None это заимствование уже не используется.
Текущий анализатор NLL не учитывает такие различия между ветками выполнения: его анализ не зависит от потока выполнения программы. Polonius Alpha решает эту проблему за счёт анализа с учётом конкретных веток и понимает, что в ветке None исходное заимствование больше не активно.
Ограничения Polonius Alpha
При этом Polonius Alpha пока нельзя считать полностью завершённой заменой старой реализации Polonius. Некоторые программы, которые успешно компилировались с первоначальной медленной реализацией Polonius, всё ещё не проходят проверку с Polonius Alpha.
Например:
struct X { next: Option<Box<X>> }fn conditional() { let mut b = Some(Box::new(X { next: None })); let mut p = &mut b; while let Some(now) = p { if true { p = &mut now.next; } }}
Впрочем, разработчики отмечают, что нашли и обратные случаи: есть программы, которые компилируются с Polonius Alpha, но не проходят проверку старой реализацией Polonius. Поэтому Polonius Alpha нельзя считать просто подмножеством предыдущей версии.
Производительность
Сейчас Polonius Alpha выполняет как минимум тот же объём работы, что и NLL, а в некоторых случаях больше. Поэтому команда отдельно следит за возможными ухудшениями времени компиляции.
При проверке десяти тысяч самых популярных пакетов на crates.io разработчики обнаружили относительно небольшое количество заметных регрессий. Даже в тех случаях, когда они проявляются, влияние обычно остаётся небольшим.

На графике каждая точка соответствует одному из 10 тысяч самых загружаемых пакетов на crates.io. Чёрная линия обозначает условный порог значимой регрессии: ухудшение времени компиляции на 1% с дополнительным масштабированием для проектов, которые собираются менее чем за 30 секунд. Красным отмечены пакеты, которые превысили этот порог.
По горизонтальной оси показано время компиляции пакета без зависимостей при использовании NLL. По вертикальной — отношение времени компиляции с Polonius Alpha к времени компиляции с NLL.
Для пяти наиболее проблемных пакетов из верхней части списка разработчики отдельно анализируют причины замедления.

За пределами топ-10 тысяч пакетов команда в первую очередь проверяла проекты с большим количеством заимствований. Максимальная обнаруженная регрессия составила примерно 2–3 раза.
Разработчики уже начали разбирать причины этих замедлений и ищут способы их устранить. При этом они считают, что в целом такие изменения производительности допустимы: подобные случаи редкие, а получаемые возможности Polonius Alpha существенно расширяют возможности проверки заимствований по сравнению с NLL.
Как отключить Polonius Alpha
Polonius Alpha включён только в nightly-сборках Rust. Если нужно вернуться к стандартному анализатору NLL, его можно отключить через параметр -Zpolonius=off.
Например, напрямую при запуске rustc:
-Zpolonius=off
или через переменную окружения:
RUSTFLAGS=-Zpolonius=off
Также настройку можно добавить в файл .cargo/config.toml проекта:
[target.x86_64-unknown-linux-gnu]rustflags = ["-Zpolonius=off"]
Разработчики предлагают сообщать в GitHub или Zulip о случаях, когда приходится отключать Polonius Alpha, и описывать причины такого решения.
Что дальше
В ближайшие месяцы команда Rust будет отслеживать сообщения об ошибках в GitHub и Zulip, исправлять известные проблемы с производительностью и готовить внутреннюю документацию по реализации.
После этого разработчики планируют стабилизировать Polonius Alpha до конца 2026 года.
При этом команда отмечает: хотя существуют программы, которые хотелось бы поддержать в будущем, но которые пока не компилируются ни с Polonius Alpha, ни с NLL, активное развитие новых возможностей Polonius после стабилизации этой версии пока не запланировано.
В дальнейшем работа будет в основном сосредоточена на оптимизации и исправлении проблем с производительностью. К развитию новых возможностей Polonius команда может вернуться позже, но сейчас Polonius Alpha уже решает большинство наиболее частых проблем проверки заимствований, поэтому разработчики переключают внимание на другие приоритетные задачи.
Разобраться, как Rust выглядит на фоне других современных платформ, можно 5 августа на бесплатном демо-уроке с практикующими экспертами — «Битва нативных платформ: Spring Boot 4, Quarkus, Micronaut, KMP, Go и Rust».
Полный список бесплатных уроков августа смотрите в дайджесте.
ссылка на оригинал статьи https://habr.com/ru/articles/1066902/