iter 22b.3.2: mono_symbol — primitive surface forms + hash for compound

This commit is contained in:
2026-05-09 20:21:24 +02:00
parent 108115f7dd
commit 028227587b
3 changed files with 87 additions and 2 deletions
+1 -1
View File
@@ -251,7 +251,7 @@ fn unify(a: &Type, b: &Type, subst: &mut Subst) -> Result<()> {
pub mod builtins;
pub mod diagnostic;
pub mod lift;
mod mono;
pub mod mono;
pub use diagnostic::{Diagnostic, Severity};
pub use lift::lift_letrecs;
+44 -1
View File
@@ -51,7 +51,7 @@
//! the implementation so the constraint is visible to anyone
//! extending the skeleton.
use ailang_core::ast::Def;
use ailang_core::ast::{Def, Type};
use ailang_core::workspace::Workspace;
use crate::Result;
@@ -87,3 +87,46 @@ fn workspace_has_typeclasses(ws: &Workspace) -> bool {
m.defs.iter().any(|d| matches!(d, Def::Class(_) | Def::Instance(_)))
})
}
/// Iter 22b.3: deterministic mono-symbol name for a `(method,
/// type)` pair. Primitive types (`Int`, `Bool`, `Str`, `Float`,
/// `Unit`) produce `<method>#<surface-name>` for diagnostic and
/// ABI legibility. All other types — parameterised cons,
/// user-defined ADTs, function types — fall to
/// `<method>#<8-hex-prefix-of-canonical-type-hash>`. The hash
/// route ensures uniqueness without requiring a flattened
/// surface form for arbitrarily nested types.
///
/// Determinism: `ailang_core::canonical::type_hash` is the same
/// function `workspace::build_registry` uses to key
/// [`Registry::entries`], so a registry-key match implies a
/// `mono_symbol` match.
pub fn mono_symbol(method: &str, ty: &Type) -> String {
if let Some(prim) = primitive_surface_name(ty) {
return format!("{method}#{prim}");
}
let full_hash = ailang_core::canonical::type_hash(ty);
// 8-hex prefix is enough for low-collision keying across the
// workspace; the full hash remains in the registry for
// disambiguation should one ever be needed.
format!("{method}#{}", &full_hash[..8])
}
/// Iter 22b.3: returns the surface name iff `ty` is a zero-arity
/// primitive `Type::Con`. Used by [`mono_symbol`] to gate the
/// human-readable form. The match is intentionally narrow:
/// `Int<args>` (which is malformed but parser-accepting) is
/// treated as compound, so it falls to the hash form.
fn primitive_surface_name(ty: &Type) -> Option<&'static str> {
match ty {
Type::Con { name, args } if args.is_empty() => match name.as_str() {
"Int" => Some("Int"),
"Bool" => Some("Bool"),
"Str" => Some("Str"),
"Float" => Some("Float"),
"Unit" => Some("Unit"),
_ => None,
},
_ => None,
}
}