refactor(check): unify the two Type-Con qualifiers over an is-local predicate
qualify_local_types and qualify_workspace_types were two ~55-line recursive Type rewriters identical in every arm (Con skip-guards for already-dotted and primitive names; Fn/Var/Forall recursion) except the bare-name decision: the local form rewrites iff the name is in local_types; the workspace form leaves names own to the module bare and otherwise searches module_types for the defining module. Factor the recursion into one rewrite_type_cons that takes the bare- name decision as a `&dyn Fn(&str) -> Option<String>` (Some = rewrite to this qualified name, None = leave bare). The two public functions are now thin wrappers passing their respective closure. Recursion order and Con-arm check order are preserved exactly; cross-module qualification tests green.
This commit is contained in:
@@ -4739,50 +4739,53 @@ fn strip_own_module_qual(t: &Type, module: &str) -> Type {
|
||||
}
|
||||
}
|
||||
|
||||
fn qualify_local_types(t: &Type, owner_module: &str, local_types: &IndexMap<String, TypeDef>) -> Type {
|
||||
/// Shared `Type::Con`-rewriting recursion behind [`qualify_local_types`]
|
||||
/// and [`qualify_workspace_types`]. Walks every `Type` variant and, for
|
||||
/// each bare (non-dotted, non-primitive) `Con` name, consults
|
||||
/// `rewrite_bare`: `Some(qualified)` replaces the name, `None` leaves it
|
||||
/// untouched. Already-qualified names (containing `.`) and primitive
|
||||
/// names are never offered to the predicate — they always pass through
|
||||
/// unchanged. The recursion is mode-preserving: `param_modes` /
|
||||
/// `ret_mode` and `effects` / `vars` / constraint classes are cloned
|
||||
/// verbatim, only nested `Con`-cons get renamed. The typed-MIR boundary
|
||||
/// qualifies a cross-module callee sig through here, and the codegen
|
||||
/// drop path reads `ret_mode == Own` off that node to decide RC
|
||||
/// trackability; stripping the mode here erased the Own signal for a
|
||||
/// monomorphised polymorphic intrinsic (e.g. `RawBuf.set`), leaking the
|
||||
/// owned temporary at the call site.
|
||||
fn rewrite_type_cons(t: &Type, rewrite_bare: &dyn Fn(&str) -> Option<String>) -> Type {
|
||||
match t {
|
||||
Type::Con { name, args } => {
|
||||
// The first two branches share the body `name.clone()` but
|
||||
// express semantically distinct reasons (already qualified;
|
||||
// primitive needs no qualification). Combining them with
|
||||
// `||` would obscure why each disqualifies the name.
|
||||
#[allow(clippy::if_same_then_else)]
|
||||
// The first two guards both pass the name through unchanged
|
||||
// but express semantically distinct reasons (already
|
||||
// qualified; primitive needs no qualification). Only a bare,
|
||||
// non-primitive name is offered to `rewrite_bare`.
|
||||
let qualified_name = if name.contains('.') {
|
||||
name.clone()
|
||||
} else if ailang_core::primitives::is_primitive_name(name) {
|
||||
name.clone()
|
||||
} else if local_types.contains_key(name) {
|
||||
format!("{owner_module}.{name}")
|
||||
} else {
|
||||
name.clone()
|
||||
rewrite_bare(name).unwrap_or_else(|| name.clone())
|
||||
};
|
||||
Type::Con {
|
||||
name: qualified_name,
|
||||
args: args
|
||||
.iter()
|
||||
.map(|a| qualify_local_types(a, owner_module, local_types))
|
||||
.map(|a| rewrite_type_cons(a, rewrite_bare))
|
||||
.collect(),
|
||||
}
|
||||
}
|
||||
// Qualification only renames `Con` type-cons; it never changes
|
||||
// the fn's arity, so the positional `param_modes` stay aligned.
|
||||
// Preserve them (and `ret_mode`): this transform must be
|
||||
// mode-preserving, mirroring the sister `qualify_workspace_types`
|
||||
// and `Subst::apply`. The typed-MIR boundary qualifies a
|
||||
// cross-module callee sig through here, and the codegen drop path
|
||||
// reads `ret_mode == Own` off that node to decide RC trackability;
|
||||
// stripping the mode here erased the Own signal for a
|
||||
// monomorphised polymorphic intrinsic (e.g. `RawBuf.set`), leaking
|
||||
// the owned temporary at the call site.
|
||||
Type::Fn { params, param_modes, ret, ret_mode, effects } => Type::Fn {
|
||||
params: params
|
||||
.iter()
|
||||
.map(|p| qualify_local_types(p, owner_module, local_types))
|
||||
.map(|p| rewrite_type_cons(p, rewrite_bare))
|
||||
.collect(),
|
||||
ret: Box::new(qualify_local_types(ret, owner_module, local_types)),
|
||||
effects: effects.clone(),
|
||||
param_modes: param_modes.clone(),
|
||||
ret: Box::new(rewrite_type_cons(ret, rewrite_bare)),
|
||||
ret_mode: ret_mode.clone(),
|
||||
effects: effects.clone(),
|
||||
},
|
||||
Type::Forall { vars, constraints, body } => Type::Forall {
|
||||
vars: vars.clone(),
|
||||
@@ -4790,15 +4793,27 @@ fn qualify_local_types(t: &Type, owner_module: &str, local_types: &IndexMap<Stri
|
||||
.iter()
|
||||
.map(|c| Constraint {
|
||||
class: c.class.clone(),
|
||||
type_: qualify_local_types(&c.type_, owner_module, local_types),
|
||||
type_: rewrite_type_cons(&c.type_, rewrite_bare),
|
||||
})
|
||||
.collect(),
|
||||
body: Box::new(qualify_local_types(body, owner_module, local_types)),
|
||||
body: Box::new(rewrite_type_cons(body, rewrite_bare)),
|
||||
},
|
||||
Type::Var { .. } => t.clone(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Rewrites bare `Type::Con` references that resolve against
|
||||
/// `local_types` (the owner module's own types) into qualified
|
||||
/// `<owner_module>.<name>` form. A bare name that is not a known local
|
||||
/// type is left untouched.
|
||||
fn qualify_local_types(t: &Type, owner_module: &str, local_types: &IndexMap<String, TypeDef>) -> Type {
|
||||
rewrite_type_cons(t, &|name| {
|
||||
local_types
|
||||
.contains_key(name)
|
||||
.then(|| format!("{owner_module}.{name}"))
|
||||
})
|
||||
}
|
||||
|
||||
/// prep.1 (kernel-extension-mechanics): rewrites bare cross-module
|
||||
/// `Type::Con` references in a consumer module's declared types into
|
||||
/// qualified `<home>.<Type>` form. Symmetric to [`qualify_local_types`]
|
||||
@@ -4813,53 +4828,19 @@ pub(crate) fn qualify_workspace_types(
|
||||
own_local_types: &IndexMap<String, TypeDef>,
|
||||
module_types: &BTreeMap<String, IndexMap<String, TypeDef>>,
|
||||
) -> Type {
|
||||
match t {
|
||||
Type::Con { name, args } => {
|
||||
let qualified_name = if name.contains('.') {
|
||||
name.clone()
|
||||
} else if ailang_core::primitives::is_primitive_name(name) {
|
||||
name.clone()
|
||||
} else if own_local_types.contains_key(name) {
|
||||
name.clone()
|
||||
} else if let Some(home) = module_types
|
||||
.iter()
|
||||
.find_map(|(m, types)| if types.contains_key(name) { Some(m.clone()) } else { None })
|
||||
{
|
||||
format!("{home}.{name}")
|
||||
rewrite_type_cons(t, &|name| {
|
||||
if own_local_types.contains_key(name) {
|
||||
None
|
||||
} else {
|
||||
name.clone()
|
||||
};
|
||||
Type::Con {
|
||||
name: qualified_name,
|
||||
args: args
|
||||
.iter()
|
||||
.map(|a| qualify_workspace_types(a, own_local_types, module_types))
|
||||
.collect(),
|
||||
module_types.iter().find_map(|(m, types)| {
|
||||
if types.contains_key(name) {
|
||||
Some(format!("{m}.{name}"))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
Type::Fn { params, ret, effects, param_modes, ret_mode } => Type::Fn {
|
||||
params: params
|
||||
.iter()
|
||||
.map(|p| qualify_workspace_types(p, own_local_types, module_types))
|
||||
.collect(),
|
||||
ret: Box::new(qualify_workspace_types(ret, own_local_types, module_types)),
|
||||
effects: effects.clone(),
|
||||
param_modes: param_modes.clone(),
|
||||
ret_mode: ret_mode.clone(),
|
||||
},
|
||||
Type::Forall { vars, constraints, body } => Type::Forall {
|
||||
vars: vars.clone(),
|
||||
constraints: constraints
|
||||
.iter()
|
||||
.map(|c| Constraint {
|
||||
class: c.class.clone(),
|
||||
type_: qualify_workspace_types(&c.type_, own_local_types, module_types),
|
||||
})
|
||||
.collect(),
|
||||
body: Box::new(qualify_workspace_types(body, own_local_types, module_types)),
|
||||
},
|
||||
Type::Var { .. } => t.clone(),
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/// prep.1: walk a [`Module`] and rewrite every `Type` annotation
|
||||
|
||||
Reference in New Issue
Block a user