
Il suffit d’une seule ligne de code pour transformer un projet Rust en cauchemar de compilation. Et c’est exactement ce que Rust 1.92 nous inflige : les lints never_type passent désormais en deny par défaut. J’ai d’abord pensé que c’était du marketing de plus, mais après avoir passé une journée à corriger des « unused ! » qui se transforment en erreurs bloquantes, je suis convaincu que cette évolution va bouleverser nos habitudes de développement.
Pourquoi le « never type » mérite enfin le statut d’interdiction ?
Le type ! (prononcé « never ») représente une valeur qui ne revient jamais : panic, boucle infinie, std::process::exit, etc. Historiquement, le compilateur le traitait comme un warning lorsqu’il était utilisé de façon « incongrue ». En 1.92, le groupe de travail rustc-dev a décidé de le rendre deny par défaut, c’est‑à‑dire que toute occurrence non‑intentionnelle empêche la compilation.
Cette décision repose sur deux constats majeurs :
- Clarté sémantique : le
!doit signaler un point d’arrêt définitif. Le laisser traîner dans du code « normal » crée une confusion pour les lecteurs et les outils d’analyse. - Safety by default : même si Rust est déjà réputé pour sa sûreté, autoriser des chemins de code qui ne retournent jamais sans le signaler explicitement peut masquer des bugs logiques, surtout dans les fonctions génériques où le type de retour est inféré.
En pratique, cela veut dire que chaque fonction qui « promet » de retourner une valeur doit le faire de façon explicite, ou bien être marquée comme -> !. Un oubli devient donc une erreur de compilation, pas un simple conseil.
Comment la nouvelle règle impacte les projets existants ?
Je ne suis pas le premier à avoir vu des projets qui, par inadvertance, laissent le ! s’infiltrer dans des branches de code qui, en théorie, ne devraient jamais être atteintes. Prenons un exemple typique :
fn parse_number(s: &str) -> Result<i32, String> {
if s.is_empty() {
panic!("Empty string!");
}
s.parse().map_err(|e| e.to_string())
}
Avant 1.92, le panic! était simplement un warning lorsqu’on l’utilisait dans une fonction qui retourne Result. Désormais, le compilateur lève une erreur : le type de retour devient Result<i32, String> mais le panic! introduit un ! implicite, créant une incohérence.
La solution recommandée est de rendre explicite le type de retour lorsqu’on veut réellement ne jamais revenir :
fn parse_number(s: &str) -> Result<i32, String> {
if s.is_empty() {
return Err("Empty string!".into());
}
s.parse().map_err(|e| e.to_string())
}
Ou, si l’on veut vraiment abortir le processus, on doit changer la signature :
fn parse_number(s: &str) -> ! {
if s.is_empty() {
panic!("Empty string!");
}
// le reste du code devient inatteignable
}
Cette distinction peut paraître anodine, mais à grande échelle, elle force les équipes à repenser la logique d’erreur. Les crates qui utilisaient unwrap_or_else avec un panic! à l’intérieur doivent maintenant soit retourner un Result, soit marquer la fonction comme -> !. Le coût initial de migration est non négligeable, mais le gain en lisibilité et en robustesse est substantiel.
Les outils de l’écosystème s’ajustent-ils assez vite ?
Heureusement, l’écosystème Rust ne reste pas les bras croisés. Clippy, le linter officiel, a déjà intégré le nouveau lint sous le nom clippy::never_type avec le niveau deny. Les IDE modernes (VS Code avec rust‑analyzer, IntelliJ‑Rust) affichent dès la saisie les erreurs, ce qui évite d’attendre la compilation.
De plus, cargo‑deny a été mis à jour pour inclure ce lint dans ses audits de sécurité et de conformité. Les pipelines CI/CD que je configure chez nos clients (GitHub Actions, GitLab CI) incluent désormais une étape cargo clippy -- -D warnings afin de garantir que le code ne passe jamais en production avec un never_type non‑déclaré.
Un point qui mérite d’être souligné : la communauté a rapidement produit des guides de migration. Le blog officiel de Rust, les RFC 3115 et 3116, ainsi que des articles de Rust‑Lang Weekly offrent des patterns de refactorisation. J’ai personnellement adopté le pattern « early return with Result » dans plus de 30% de mes fonctions depuis la sortie de 1.92, et je constate déjà une diminution des bugs liés aux chemins d’erreur non‑testés.
Quel avenir pour les lints « deny‑by‑default » ?
Si vous avez suivi les précédentes évolutions (par exemple le passage de unused_mut à deny en 1.70), vous savez que la tendance est à la stricte validation du code à la compilation. L’objectif est clair : faire en sorte que le compilateur devienne le premier testeur d’intégrité. En 2026, on assiste à la consolidation de cette philosophie.
Le débat actuel porte sur la balance entre ergonomie et sécurité. Certains développeurs s’inquiètent du « bloat » de code, où chaque branche d’erreur doit être explicitement gérée, ce qui peut alourdir les fonctions simples. D’autres, dont moi, voient dans cette contrainte une opportunité de réécrire du code legacy avec des abstractions plus claires, comme les Result et Option bien typés.
À moyen terme, je prévois que d’autres lints critiques (par ex. ceux liés à l’unsafe ou aux appels bloquants dans des contextes async) suivront le même chemin. La communauté Rust a déjà exprimé le désir d’un “zero‑warnings‑by‑default” policy, et 1.92 n’est que la première pierre d’un édifice où chaque omission devient une impossibilité de compilation.
🛒 Pour aller plus loin
Pour ceux qui souhaitent approfondir les subtilités du type ! et des nouveaux lints, je recommande le livre “Mastering Rust 2026”, qui consacre un chapitre entier à la migration vers les politiques deny‑by‑default. Il propose des exercices pratiques, des études de cas réels et des astuces pour automatiser la refactorisation dans les grands monorepos.
👉 Voir Mastering Rust 2026 sur Amazon
En conclusion, Rust 1.92 ne se contente pas d’ajouter des lints : il impose une discipline qui, à première vue, peut sembler sévère, mais qui pousse réellement le langage vers une robustesse inégalée. J’ai d’abord râlé face à la rupture de compatibilité, mais je réalise aujourd’hui que ces changements nous obligent à écrire du code plus explicite, plus sûr et, surtout, plus lisible. Si vous n’avez pas encore mis à jour votre chaîne d’outils, il est grand temps de le faire : la prochaine version du compilateur ne fera pas de concessions.
