refactor: collapse duplicated helpers and drop dead code across check/core/codegen
Pure simplification pass, no behaviour change — hashes, canonical forms, diagnostic codes, and emitted IR are byte-identical (hash-pin and IR-pin tests unchanged and green). ailang-check: - strip_forall and collect_pattern_binders were triplicated verbatim across linearity.rs / reuse_shape.rs / uniqueness.rs; hoisted each to a single pub(crate) fn in lib.rs. - mono.rs::pattern_binders was a fourth copy of collect_pattern_binders (iterative style, same result for every Pattern shape); deleted, now calls the shared fn. - maybe_instantiate and expect_eq were single-call wrappers; inlined at their sole call sites and removed. ailang-core: - collect_used_in_pattern was a verbatim duplicate of pattern_binds; deleted, call site repointed. pattern_binds made private (no external callers; the doc-comment's lift_letrecs claim was stale). - is_false serde helper replaced by std::ops::Not::not at the four skip_serializing_if sites (all plain-bool fields); helper removed. - test-only any_nested_ctor / any_let_rec folded into one generic any_term(t, &pred) walker. - removed dead test helpers tmp_dir / examples_dir, orphaned when their tests relocated to tests/workspace_pin.rs. ailang-codegen: - removed the write-only Emitter::types field, its populating loop, and the now-unused CtorInfo struct it fed. - adt_drop_symbol / adt_partial_drop_symbol differed only in a prefix literal; folded into one adt_symbol(prefix, ...). Symbol strings unchanged. Net -180 LOC.
This commit is contained in:
@@ -41,7 +41,7 @@ pub struct Module {
|
||||
/// from canonical JSON when `false`, so every pre-existing
|
||||
/// fixture's hash is bit-stable. See prep.3 of the
|
||||
/// kernel-extension-mechanics milestone.
|
||||
#[serde(default, skip_serializing_if = "is_false")]
|
||||
#[serde(default, skip_serializing_if = "std::ops::Not::not")]
|
||||
pub kernel: bool,
|
||||
/// Imports of other modules. Resolved by the workspace loader as
|
||||
/// `<root_dir>/<module>.ail.json`.
|
||||
@@ -174,7 +174,7 @@ pub struct TypeDef {
|
||||
#[serde(
|
||||
default,
|
||||
rename = "drop-iterative",
|
||||
skip_serializing_if = "is_false"
|
||||
skip_serializing_if = "std::ops::Not::not"
|
||||
)]
|
||||
pub drop_iterative: bool,
|
||||
/// Closed-set restriction on type-parameter instantiation. Maps
|
||||
@@ -452,7 +452,7 @@ pub enum Term {
|
||||
callee: Box<Term>,
|
||||
#[serde(default)]
|
||||
args: Vec<Term>,
|
||||
#[serde(default, skip_serializing_if = "is_false")]
|
||||
#[serde(default, skip_serializing_if = "std::ops::Not::not")]
|
||||
tail: bool,
|
||||
},
|
||||
/// Let-binding: `value` is evaluated and bound to `name` in `body`.
|
||||
@@ -494,7 +494,7 @@ pub enum Term {
|
||||
Do {
|
||||
op: String,
|
||||
args: Vec<Term>,
|
||||
#[serde(default, skip_serializing_if = "is_false")]
|
||||
#[serde(default, skip_serializing_if = "std::ops::Not::not")]
|
||||
tail: bool,
|
||||
},
|
||||
/// Constructor application. `type_name` binds the ADT, `ctor` the
|
||||
@@ -903,17 +903,6 @@ impl PartialEq for Type {
|
||||
}
|
||||
impl Eq for Type {}
|
||||
|
||||
/// Serde helper for `#[serde(skip_serializing_if = "is_false")]`.
|
||||
///
|
||||
/// Used by [`Term::App::tail`] and [`Term::Do::tail`] so the `tail`
|
||||
/// flag is omitted from the canonical JSON whenever it is false,
|
||||
/// preserving bit-identical hashes for every fixture that does not
|
||||
/// carry the flag.
|
||||
#[allow(clippy::trivially_copy_pass_by_ref)]
|
||||
fn is_false(b: &bool) -> bool {
|
||||
!*b
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
@@ -384,7 +384,7 @@ fn collect_used_in_term(t: &Term, used: &mut BTreeSet<String>) {
|
||||
Term::Match { scrutinee, arms } => {
|
||||
collect_used_in_term(scrutinee, used);
|
||||
for arm in arms {
|
||||
collect_used_in_pattern(&arm.pat, used);
|
||||
pattern_binds(&arm.pat, used);
|
||||
collect_used_in_term(&arm.body, used);
|
||||
}
|
||||
}
|
||||
@@ -439,22 +439,6 @@ fn collect_used_in_term(t: &Term, used: &mut BTreeSet<String>) {
|
||||
}
|
||||
}
|
||||
|
||||
/// Walks a pattern and inserts every [`Pattern::Var.name`] into `used`.
|
||||
fn collect_used_in_pattern(p: &Pattern, used: &mut BTreeSet<String>) {
|
||||
match p {
|
||||
Pattern::Wild => {}
|
||||
Pattern::Var { name } => {
|
||||
used.insert(name.clone());
|
||||
}
|
||||
Pattern::Lit { .. } => {}
|
||||
Pattern::Ctor { fields, .. } => {
|
||||
for sub in fields {
|
||||
collect_used_in_pattern(sub, used);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// State carried across a module-wide desugar pass.
|
||||
///
|
||||
/// `counter` is incremented for every fresh-name request; `used`
|
||||
@@ -1540,11 +1524,7 @@ fn rename_pattern_binders(pat: &Pattern, renamed: &BTreeMap<String, String>) ->
|
||||
/// collect every name a pattern binds into `out`. Mirrors
|
||||
/// `Pattern::pattern_bound_names` in `ailang-codegen`; duplicated here
|
||||
/// because `ailang-core` cannot depend on the codegen crate.
|
||||
///
|
||||
/// made `pub` so callers (e.g. `ailang-check::lift_letrecs`)
|
||||
/// can reproduce the same shadowing semantics during their own
|
||||
/// scope-aware walks.
|
||||
pub fn pattern_binds(p: &Pattern, out: &mut BTreeSet<String>) {
|
||||
fn pattern_binds(p: &Pattern, out: &mut BTreeSet<String>) {
|
||||
match p {
|
||||
Pattern::Wild | Pattern::Lit { .. } => {}
|
||||
Pattern::Var { name } => {
|
||||
@@ -1949,85 +1929,58 @@ pub fn find_non_callee_use(t: &Term, name: &str) -> Option<Term> {
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
/// Generic test-only tree walk: returns true if `pred` holds for
|
||||
/// `t` or any of its subterms. The structural recursion visits the
|
||||
/// same subterm set every node-specific walker needs (callee/args,
|
||||
/// let value+body, if branches, match scrutinee + arm bodies, etc.).
|
||||
fn any_term(t: &Term, pred: &impl Fn(&Term) -> bool) -> bool {
|
||||
if pred(t) {
|
||||
return true;
|
||||
}
|
||||
match t {
|
||||
Term::Lit { .. } | Term::Var { .. } | Term::Intrinsic => false,
|
||||
Term::App { callee, args, .. } => {
|
||||
any_term(callee, pred) || args.iter().any(|a| any_term(a, pred))
|
||||
}
|
||||
Term::Let { value, body, .. } => any_term(value, pred) || any_term(body, pred),
|
||||
Term::If { cond, then, else_ } => {
|
||||
any_term(cond, pred) || any_term(then, pred) || any_term(else_, pred)
|
||||
}
|
||||
Term::Do { args, .. } => args.iter().any(|a| any_term(a, pred)),
|
||||
Term::Ctor { args, .. } => args.iter().any(|a| any_term(a, pred)),
|
||||
Term::Match { scrutinee, arms } => {
|
||||
any_term(scrutinee, pred) || arms.iter().any(|a| any_term(&a.body, pred))
|
||||
}
|
||||
Term::Lam { body, .. } => any_term(body, pred),
|
||||
Term::Seq { lhs, rhs } => any_term(lhs, pred) || any_term(rhs, pred),
|
||||
Term::LetRec { body, in_term, .. } => {
|
||||
any_term(body, pred) || any_term(in_term, pred)
|
||||
}
|
||||
Term::Clone { value } => any_term(value, pred),
|
||||
Term::ReuseAs { source, body } => any_term(source, pred) || any_term(body, pred),
|
||||
Term::Loop { binders, body } => {
|
||||
binders.iter().any(|b| any_term(&b.init, pred)) || any_term(body, pred)
|
||||
}
|
||||
Term::Recur { args } => args.iter().any(|a| any_term(a, pred)),
|
||||
Term::New { args, .. } => args.iter().any(|arg| match arg {
|
||||
NewArg::Value(v) => any_term(v, pred),
|
||||
NewArg::Type(_) => false,
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
/// Helper: walk a term, return true iff any [`Pattern::Ctor`] in
|
||||
/// any reachable [`Term::Match`] has a non-flat field.
|
||||
fn any_nested_ctor(t: &Term) -> bool {
|
||||
match t {
|
||||
Term::Lit { .. } | Term::Var { .. } => false,
|
||||
Term::App { callee, args, .. } => {
|
||||
any_nested_ctor(callee) || args.iter().any(any_nested_ctor)
|
||||
}
|
||||
Term::Let { value, body, .. } => any_nested_ctor(value) || any_nested_ctor(body),
|
||||
Term::If { cond, then, else_ } => {
|
||||
any_nested_ctor(cond) || any_nested_ctor(then) || any_nested_ctor(else_)
|
||||
}
|
||||
Term::Do { args, .. } => args.iter().any(any_nested_ctor),
|
||||
Term::Ctor { args, .. } => args.iter().any(any_nested_ctor),
|
||||
Term::Match { scrutinee, arms } => {
|
||||
if any_nested_ctor(scrutinee) {
|
||||
return true;
|
||||
}
|
||||
for a in arms {
|
||||
if !is_flat(&a.pat) {
|
||||
return true;
|
||||
}
|
||||
if any_nested_ctor(&a.body) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
Term::Lam { body, .. } => any_nested_ctor(body),
|
||||
Term::Seq { lhs, rhs } => any_nested_ctor(lhs) || any_nested_ctor(rhs),
|
||||
Term::LetRec { body, in_term, .. } => {
|
||||
any_nested_ctor(body) || any_nested_ctor(in_term)
|
||||
}
|
||||
Term::Clone { value } => any_nested_ctor(value),
|
||||
Term::ReuseAs { source, body } => any_nested_ctor(source) || any_nested_ctor(body),
|
||||
Term::Loop { binders, body } => {
|
||||
binders.iter().any(|b| any_nested_ctor(&b.init)) || any_nested_ctor(body)
|
||||
}
|
||||
Term::Recur { args } => args.iter().any(any_nested_ctor),
|
||||
Term::New { args, .. } => args.iter().any(|arg| match arg {
|
||||
NewArg::Value(v) => any_nested_ctor(v),
|
||||
NewArg::Type(_) => false,
|
||||
}),
|
||||
Term::Intrinsic => false,
|
||||
}
|
||||
any_term(t, &|x| {
|
||||
matches!(x, Term::Match { arms, .. } if arms.iter().any(|a| !is_flat(&a.pat)))
|
||||
})
|
||||
}
|
||||
|
||||
/// Helper: walk a term, return true iff any [`Term::LetRec`] is
|
||||
/// reachable. After 16b.1 desugaring this should be `false`.
|
||||
fn any_let_rec(t: &Term) -> bool {
|
||||
match t {
|
||||
Term::Lit { .. } | Term::Var { .. } => false,
|
||||
Term::App { callee, args, .. } => {
|
||||
any_let_rec(callee) || args.iter().any(any_let_rec)
|
||||
}
|
||||
Term::Let { value, body, .. } => any_let_rec(value) || any_let_rec(body),
|
||||
Term::If { cond, then, else_ } => {
|
||||
any_let_rec(cond) || any_let_rec(then) || any_let_rec(else_)
|
||||
}
|
||||
Term::Do { args, .. } => args.iter().any(any_let_rec),
|
||||
Term::Ctor { args, .. } => args.iter().any(any_let_rec),
|
||||
Term::Match { scrutinee, arms } => {
|
||||
any_let_rec(scrutinee) || arms.iter().any(|a| any_let_rec(&a.body))
|
||||
}
|
||||
Term::Lam { body, .. } => any_let_rec(body),
|
||||
Term::Seq { lhs, rhs } => any_let_rec(lhs) || any_let_rec(rhs),
|
||||
Term::LetRec { .. } => true,
|
||||
Term::Clone { value } => any_let_rec(value),
|
||||
Term::ReuseAs { source, body } => any_let_rec(source) || any_let_rec(body),
|
||||
Term::Loop { binders, body } => {
|
||||
binders.iter().any(|b| any_let_rec(&b.init)) || any_let_rec(body)
|
||||
}
|
||||
Term::Recur { args } => args.iter().any(any_let_rec),
|
||||
Term::New { args, .. } => args.iter().any(|arg| match arg {
|
||||
NewArg::Value(v) => any_let_rec(v),
|
||||
NewArg::Type(_) => false,
|
||||
}),
|
||||
Term::Intrinsic => false,
|
||||
}
|
||||
any_term(t, &|x| matches!(x, Term::LetRec { .. }))
|
||||
}
|
||||
|
||||
/// a `match` containing `(Cons a (Cons b _))` desugars to
|
||||
|
||||
@@ -1659,16 +1659,6 @@ mod tests {
|
||||
path
|
||||
}
|
||||
|
||||
fn tmp_dir(tag: &str) -> PathBuf {
|
||||
let d = std::env::temp_dir().join(format!(
|
||||
"ailang_workspace_test_{tag}_{}",
|
||||
std::process::id()
|
||||
));
|
||||
let _ = fs::remove_dir_all(&d);
|
||||
fs::create_dir_all(&d).unwrap();
|
||||
d
|
||||
}
|
||||
|
||||
// `loads_example_workspace_happy_path` + `loads_workspace_auto_injects_prelude`
|
||||
// relocated to `crates/ailang-core/tests/workspace_pin.rs` in iter
|
||||
// form-a.1 Task 5 (use `ailang_surface::load_workspace` on `.ail`
|
||||
@@ -1692,16 +1682,6 @@ mod tests {
|
||||
// `iter22b1_workspace_with_no_classes_has_empty_registry` relocated
|
||||
// to `crates/ailang-core/tests/workspace_pin.rs` in iter form-a.1 Task 5.
|
||||
|
||||
fn examples_dir() -> PathBuf {
|
||||
let manifest_dir = env!("CARGO_MANIFEST_DIR");
|
||||
Path::new(manifest_dir)
|
||||
.parent()
|
||||
.unwrap()
|
||||
.parent()
|
||||
.unwrap()
|
||||
.join("examples")
|
||||
}
|
||||
|
||||
// a coherent instance (in the class's module)
|
||||
// loads cleanly and produces one registry entry from the
|
||||
// fixture itself. With the auto-loaded prelude (iter 23.2)
|
||||
|
||||
Reference in New Issue
Block a user