64 lines
2.6 KiB
Rust
64 lines
2.6 KiB
Rust
//! The primitive-name set: `Int`, `Bool`, `Str`, `Unit`. Single
|
|
//! source of truth for "is this name a built-in zero-arity type
|
|
//! 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 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 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" | "Float")
|
|
}
|
|
|
|
/// Returns the static-lifetime surface name iff `name` is a
|
|
/// 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"),
|
|
"Bool" => Some("Bool"),
|
|
"Str" => Some("Str"),
|
|
"Unit" => Some("Unit"),
|
|
"Float" => Some("Float"),
|
|
_ => 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", "Float", "List", "Foo", "", "int"] {
|
|
assert_eq!(
|
|
is_primitive_name(name),
|
|
primitive_surface_name(name).is_some(),
|
|
"lockstep violation for {name:?}"
|
|
);
|
|
}
|
|
// The loop's assert_eq! passes vacuously when both functions
|
|
// return `false`/`None` for a name; the explicit assertions
|
|
// below catch the case where a primitive is silently removed
|
|
// from both functions but stays in the loop list.
|
|
assert!(is_primitive_name("Float"), "Float must be a primitive");
|
|
assert_eq!(
|
|
primitive_surface_name("Float"),
|
|
Some("Float"),
|
|
"Float surface name must be \"Float\""
|
|
);
|
|
}
|
|
}
|