slopc

Proc macro Rust volontairement dangereuse: `todo!()` devient un appel LLM pendant la compilation.

RôleAuteur
TrajectoireCrate Rust / blague compilable
ÉquipeOpen source
slopc
Proc macro volontairement maudite
01 / UNE BLAGUE QUI COMPILE

Une blague qui compile

J'ai écrit slopc comme une mauvaise idée construite assez sérieusement pour devenir exécutable. Ce n'est pas un outil à recommander.

Le principe tient en une annotation: poser #[slop] sur une fonction, laisser un todo!() dans le corps, puis demander à un modèle de remplir l'implémentation pendant cargo build . La publication Reddit l'annonçait comme une blague dangereuse. Le dépôt assume la même chose dans le README, les exemples et le SECURITY.md .

readme.rsCURSED API
#[slop(retries = 5, hint = "recursive descent or shunting-yard")]fn eval_expr(expr: &str) -> f64 {    todo!()}

En 2026, faire écrire du Rust par un modèle n'est plus le détail notable. Le détail notable, c'est l'endroit où ce Rust entre dans le programme: pas dans l'éditeur, pas dans une PR, mais dans la chaîne de compilation.

02 / LE TRAJET DANS CARGO BUILD

Le trajet dans cargo build

La macro récupère la signature de fonction, les doc comments, le corps, les dépendances du Cargo.toml et parfois un fichier de contexte. Elle fabrique un prompt, appelle un endpoint compatible OpenAI/OpenRouter, puis attend une fonction Rust complète.

Le résultat passe ensuite dans syn . slopc refuse quelques patterns évidents comme unwrap , expect , panic , todo et unimplemented , tente une compilation avec rustc , puis renvoie l'erreur au modèle quand ça casse. Si run_doctests est activé, les exemples de documentation deviennent aussi des tests. Les générations sont mises en cache sous target/slop-cache/ .

compile pathPROC MACRO
fn stub -> prompt -> LLM output -> syn parse -> lint -> rustc -> cache

La configuration passe par les arguments de l'attribut, les variables SLOP_* , slop.toml et les valeurs par défaut. Je lui ai donné tout l'habillage d'une crate normale: metadata Cargo, exemples, licence AGPL-3.0-only, documentation, cache, options de retry.

03 / LE CODE HORS CHAMP

Le code hors champ

C'est le détail qui rend la blague moins gratuite. Le diff montre une signature, des doc comments et un todo!() . Rien de bien inquiétant si on lit seulement le fichier source. Puis la compilation ouvre une autre porte: requête réseau, réponse du modèle, génération de tokens, cache local.

Le code à relire n'habite plus seulement le dépôt. Il peut se trouver dans target/slop-cache/ , dans une sortie de macro, ou dans une réponse de modèle que personne ne relira. Une hallucination serait déjà un bug. Ici, l'implémentation arrive aussi par un endroit que la revue de code ne regarde pas.

Rust ajoute une ironie assez pratique. Le premier relecteur, ici, c'est rustc . Les tokens invalides échouent. Les types cassés échouent. Les fonctions qui ne compilent pas repartent au modèle avec une erreur. Les doctests servent aussi de contrat de comportement pour le seul acteur du système qui va écrire le corps.

04 / CE QUE LES PROC MACROS AUTORISENT

Ce que les proc macros autorisent

slopc abuse d'une vraie capacité du langage. Une proc macro reçoit des tokens, peut les analyser, ouvrir des fichiers, lire l'environnement, produire d'autres tokens. C'est une force de Rust: beaucoup de crates sérieuses s'en servent pour enlever du code répétitif ou vérifier une forme à la compilation.

Ici, la même porte sert à appeler un service réseau et à introduire une implémentation générée. La blague tient parce que cette frontière existe déjà. Elle ne force pas Cargo à faire quelque chose d'exotique. Elle met simplement une très mauvaise idée à l'intérieur d'un mécanisme prévu pour produire du code.

Cette nuance compte. Une blague purement absurde s'oublie vite. Une blague qui utilise correctement l'extension du compilateur laisse une gêne plus utile: si une dépendance de build peut exécuter du code, alors la confiance dans la build fait partie du périmètre de sécurité.

05 / POURQUOI LA BLAGUE A TOUCHÉ JUSTE

Pourquoi la blague a touché juste

La discussion Reddit a surtout confirmé que le projet était lisible au bon niveau. Certains l'ont pris comme une blague technique. D'autres ont immédiatement parlé de non-déterminisme, de fuite de contexte, d'API key, de supply-chain et de builds impossibles à reproduire.

Le dépôt empile volontairement les avertissements. Le README joue avec l'idée. Le SECURITY.md dit de ne pas utiliser le projet. La licence AGPL-3.0-only ajoute même un garde-fou administratif: avant d'arriver en production, la dépendance a de bonnes chances de faire tousser un scanner juridique.

  • #[slop] remplace des todo!() par du code généré.
  • Les erreurs rustc peuvent repartir au modèle jusqu'à épuisement des retries.
  • nocache peut forcer une nouvelle génération à chaque compilation.
  • La génération peut dépendre d'un service réseau, d'une clé API et de l'état du prompt.
  • Le README et SECURITY.md préviennent explicitement de ne pas l'utiliser en production.
06 / CE QU'IL RESTE QUAND LA BLAGUE EST FINIE

Ce qu'il reste quand la blague est finie

slopc ne propose pas une architecture. Il met un mauvais workflow sur la table avec assez de détails pour qu'on puisse l'inspecter.

La leçon utile tient dans les endroits où le projet essaie de se protéger malgré tout: cache local, refus de quelques patterns dangereux, compilation systématique, doctests optionnels, documentation qui ne prétend pas être sûre. Aucun de ces garde-fous ne rend l'idée bonne. Ils montrent seulement où il faudrait regarder si ce genre de génération devenait moins absurde ailleurs: reproductibilité, revue du code généré, sortie réseau pendant la build, contrat de tests, responsabilité de la dépendance.

Pour un petit dépôt maudit, c'est déjà beaucoup.