From 9523a1cd63cdd399608194ea43a873fd7ac82182 Mon Sep 17 00:00:00 2001 From: Brummel Date: Sun, 10 May 2026 04:13:41 +0200 Subject: [PATCH] iter 22-tidy.4: pin lockstep invariant + tighten module doc --- crates/ailang-core/src/primitives.rs | 45 +++++++++++++++++++--------- 1 file changed, 31 insertions(+), 14 deletions(-) diff --git a/crates/ailang-core/src/primitives.rs b/crates/ailang-core/src/primitives.rs index 24418f6..5a10434 100644 --- a/crates/ailang-core/src/primitives.rs +++ b/crates/ailang-core/src/primitives.rs @@ -3,27 +3,24 @@ //! constructor?" Every typecheck and codegen site that gates //! behaviour on the primitive set goes through this module. //! -//! Adding a primitive: append to BOTH functions below; the four -//! consumers compile-fail-loudly if the predicate is forgotten -//! (the failure is a missed branch, not a panic), but -//! `primitive_surface_name` will silently return `None` for the -//! new name unless its `match` is extended too. Keep the two -//! functions in lockstep. +//! Adding a primitive: append to BOTH functions below. The lockstep +//! invariant ([`is_primitive_name`] is `true` iff +//! [`primitive_surface_name`] is `Some`) is pinned by the unit test +//! at the bottom of this file — extending only one of the two +//! fails the test before the bug reaches a consumer. /// Returns `true` iff `name` is one of the built-in zero-arity -/// primitive type constructors. Cross-crate predicate consumed by -/// `ailang-check` (`linearity::is_heap_type`, `lib::check_type_well_formed`, -/// `lib::qualify_local_types`) and `ailang-codegen` -/// (`subst::qualify_local_types_codegen`). +/// primitive type constructors. Cross-crate predicate used by +/// typecheck-time well-formedness gating, the heap-type filter, +/// the local-type qualifier, and the codegen substitution path. pub fn is_primitive_name(name: &str) -> bool { matches!(name, "Int" | "Bool" | "Str" | "Unit") } /// Returns the static-lifetime surface name iff `name` is a -/// primitive. Used by `mono::primitive_surface_name` to embed the -/// human-readable form in monomorphised symbol names; the static -/// lifetime is what makes the symbol-builder's `&'static str` -/// signature work. +/// primitive. Used by the mono pass to embed the human-readable +/// form in monomorphised symbol names; the static lifetime is what +/// makes the symbol-builder's `&'static str` signature work. pub fn primitive_surface_name(name: &str) -> Option<&'static str> { match name { "Int" => Some("Int"), @@ -33,3 +30,23 @@ pub fn primitive_surface_name(name: &str) -> Option<&'static str> { _ => None, } } + +#[cfg(test)] +mod tests { + use super::*; + + /// The two functions must agree on which names are primitive: + /// `is_primitive_name(n)` true iff `primitive_surface_name(n)` + /// is `Some`. The list of names tested mirrors the literal set + /// inside both functions plus a sample non-primitive. + #[test] + fn predicate_and_surface_name_agree() { + for name in ["Int", "Bool", "Str", "Unit", "List", "Foo", "", "int"] { + assert_eq!( + is_primitive_name(name), + primitive_surface_name(name).is_some(), + "lockstep violation for {name:?}" + ); + } + } +}