Présentation du langage Evergreen

Evergreen se positionne comme un langage système dont la sûreté est démontrée à la compilation. Le principe central, explicitement indiqué sur le site officiel, consiste à placer les invariants directement à côté du code qu’ils décrivent. Cette proximité vise à rendre les obligations de sécurité visibles pour le développeur et exploitables par le compilateur.

Mécanisme d’invariants et de vérification

Le langage introduit trois catégories d’invariants : préconditions, postconditions et invariants de données. Elles sont exprimées dans une clause where suivie d’une clause ensures. L’exemple fourni montre une fonction increment qui accepte un usize n avec la précondition n < usize::MAX et garantit, via ensures result > n, que le résultat dépasse l’entrée. Le compilateur analyse ces annotations et rejette le code si les contraintes ne peuvent être satisfaites statiquement.

fn increment(n: usize) -> usize
    where n < usize::MAX
    ensures result > n
{
    n + 1
}

Cette vérification s’effectue à la phase de compilation, ce qui élimine le besoin d’instructions de contrôle d’exécution supplémentaires pour les cas couverts par les invariants. Le modèle s’apparente à la programmation par contrat, mais avec une implémentation intégrée au processus de génération de code machine.

Implications pour la sûreté des systèmes

En contraignant les programmes à respecter des propriétés formelles avant l’exécution, Evergreen réduit la surface d’erreurs classiques telles que les débordements d’entier ou les violations de conditions d’état. La preuve de sécurité est ainsi ancrée dans le binaire produit, ce qui facilite les audits de conformité pour des environnements critiques (ex. : systèmes embarqués, pilotes). De plus, la visibilité des invariants dans le code source améliore la lisibilité et la maintenabilité, car chaque fonction porte explicitement ses exigences et garanties.

Limites et perspectives

Le modèle repose sur la capacité du compilateur à résoudre les contraintes exprimées. Des invariants complexes, notamment ceux dépendant de comportements dynamiques ou d’interactions inter‑processus, peuvent dépasser les capacités d’analyse statique et rester non vérifiables. Dans ces cas, le développeur doit soit simplifier les spécifications, soit recourir à des vérifications dynamiques complémentaires. Le site ne précise pas les performances du processus de compilation ni la compatibilité avec les écosystèmes existants (ex. : interopérabilité avec du code C ou Rust). Ces points constituent des axes d’évolution pour la maturité du langage.

En résumé, Evergreen propose une approche où les invariants sont traités comme des obligations de compilation, offrant une garantie de sûreté avant l’exécution tout en imposant des exigences d’analyse statique qui peuvent limiter l’expression de certaines logiques complexes.