iter rpe.1.tidy: subst.rs preserves Type::Fn modes through rebuild

Closes audit-rpe.1's [medium] drift: qualify_local_types_codegen
and apply_subst_to_type at crates/ailang-codegen/src/subst.rs:188 +
:217 both carried the field-spread Type::Fn rebuild shape that
strips param_modes and ret_mode to vec![] / ParamMode::Implicit.
Symmetric to the feb9413 substitute_rigids fix flagged in that
commit's message as a bug class.

Fix: bind param_modes and ret_mode in the destructure, thread
them through unchanged. cargo test --workspace 564/0/3; clippy + doc
zero warnings.

Audit-rpe.1's [nit] dead Emitter.strings field deferred as
known-debt — it cycles over an empty map harmlessly.

Three other field-spread Type::Fn rebuild sites in
ailang-check/src/lib.rs and lift.rs follow the same pattern but
are not currently flagged by failing tests; left in place pending
correctness-reachability verification per the journal Known debt
section.
This commit is contained in:
2026-05-14 02:19:05 +02:00
parent 973f50bf68
commit 21d821e371
2 changed files with 64 additions and 6 deletions
+6 -6
View File
@@ -185,15 +185,15 @@ pub(crate) fn qualify_local_types_codegen(
.collect(),
}
}
Type::Fn { params, ret, effects, .. } => Type::Fn {
Type::Fn { params, ret, effects, param_modes, ret_mode } => Type::Fn {
params: params
.iter()
.map(|p| qualify_local_types_codegen(p, owner_module, owner_local_types))
.collect(),
ret: Box::new(qualify_local_types_codegen(ret, owner_module, owner_local_types)),
effects: effects.clone(),
param_modes: vec![],
ret_mode: ParamMode::Implicit,
param_modes: param_modes.clone(),
ret_mode: *ret_mode,
},
Type::Forall { vars, constraints, body } => Type::Forall {
vars: vars.clone(),
@@ -214,12 +214,12 @@ pub(crate) fn apply_subst_to_type(t: &Type, subst: &BTreeMap<String, Type>) -> T
name: name.clone(),
args: args.iter().map(|a| apply_subst_to_type(a, subst)).collect(),
},
Type::Fn { params, ret, effects, .. } => Type::Fn {
Type::Fn { params, ret, effects, param_modes, ret_mode } => Type::Fn {
params: params.iter().map(|p| apply_subst_to_type(p, subst)).collect(),
ret: Box::new(apply_subst_to_type(ret, subst)),
effects: effects.clone(),
param_modes: vec![],
ret_mode: ParamMode::Implicit,
param_modes: param_modes.clone(),
ret_mode: *ret_mode,
},
Type::Forall { vars, constraints, body } => {
// Inner forall shadows: don't substitute re-bound names.
@@ -0,0 +1,58 @@
# iter rpe.1.tidy — Close audit-rpe.1 [medium] drift
**Date:** 2026-05-14
**Started from:** 973f50b (post-rpe.1 + audit-rpe.1)
**Status:** DONE
## Summary
Closes the single `[medium]` drift item surfaced by audit-rpe.1:
`crates/ailang-codegen/src/subst.rs:188,217``qualify_local_types_codegen`
and `apply_subst_to_type` both carried the exact
`Type::Fn { params, ret, effects, .. }` field-spread that drops
`param_modes` and `ret_mode` to `vec![]` / `ParamMode::Implicit`. This
is the same shape the print-leak bugfix at commit feb9413 corrected
in `crates/ailang-check/src/lib.rs::substitute_rigids`, and the
feb9413 commit message explicitly flagged any other instance as a
latent bug in the same class.
Fix: preserve both fields through the rebuild — `param_modes.clone()`
(it's a `Vec`) and `*ret_mode` (Copy). Symmetric to the feb9413 fix.
The audit's `[nit]` finding (dead `Emitter.strings` field in
`crates/ailang-codegen/src/lib.rs`, an orphan after `intern_string`
was removed in rpe.1 Task 4) is left as a follow-up tidy candidate —
it cycles over an empty map harmlessly and isn't an audit gate.
## Files touched
- `crates/ailang-codegen/src/subst.rs:188`
`qualify_local_types_codegen` Type::Fn arm now binds
`param_modes` and `ret_mode` and threads them through.
- `crates/ailang-codegen/src/subst.rs:217`
`apply_subst_to_type` Type::Fn arm same shape.
## Verification
- `cargo test --workspace` → 564 / 0 / 3 (baseline holds).
- `cargo clippy --workspace --all-targets` → 0 warnings.
- `cargo doc --workspace --no-deps` → 0 warnings.
## Concerns
- (none)
## Known debt
- `Emitter.strings` field in `crates/ailang-codegen/src/lib.rs`
remains dead. Cycles over empty map; no behavioural impact.
Roll into a future opportunistic cleanup.
- Three other field-spread `Type::Fn` rebuild sites
(`crates/ailang-check/src/lib.rs:93` and `:3492`,
`crates/ailang-check/src/lift.rs:875`) ALSO drop `param_modes`
/ `ret_mode` to `vec![]` / `Implicit`. They were not flagged
by audit-rpe.1 because no currently-failing test pins them.
Leaving conservatively in place — a flag for a future
fieldtest or audit cycle. The pattern of field-spread-and-
drop is the bug class; whether each site is correctness-
reachable is what needs verification before changing.