iter clippy-sweep: clear all 61 cargo clippy warnings
Hygiene sweep across the workspace under `cargo clippy --workspace
--all-targets`. Before: 61 warnings. After: zero. Tests stay 563
green, `cargo doc` stays at zero warnings, and all three bench
scripts exit 0 against existing baselines.
Twelve lint classes, three fix shapes:
- Documentation hygiene (~32 hits): `doc_lazy_continuation` resolved
by adding blank lines before continuation paragraphs or rephrasing
the offending line; plus four `empty_line_after_doc_comments` hits
in workspace.rs where eight `///` blocks left orphan by form-a.1
T5 test relocation were converted to plain `//`.
- Idiomatic refactors (~16 hits): `.err().expect()` → `.expect_err()`,
redundant `.into_iter()` and `.into()` removed, `|f| g(f)` →
`g`, `.trim().split_whitespace()` → `.split_whitespace()`,
`push_str("x")` → `push('x')`, two manual `impl Default` flipped
to `#[derive(Default)]` + `#[default]`, two nested `if let Some(_)
= …` collapsed.
- Block extraction (1 hit): a 13-line block inside an `else if`
condition in synth's Var-arm extracted to a new helper
`is_class_method_dispatch(name, env)` next to
`qualifier_is_class_shape`.
Three `#[allow]`s with inline rationale where clippy's suggestion
would lose meaning: `only_used_in_recursion` on walk_pattern (the
parameter preserves the five-fn walker-framework signature
uniformity), 2× `if_same_then_else` on qualify_local_types shapes
(two branches encode semantically distinct disqualification
reasons), `too_many_arguments` on `Emitter::new` (8 workspace-flat
tables; bundling would just rename boilerplate).
This commit is contained in:
@@ -2363,6 +2363,7 @@ pub(crate) fn parse_method_qualifier(name: &str) -> (&str, Option<String>) {
|
||||
/// - bare-class qualifier, e.g. `"Show.show"` — class names are
|
||||
/// PascalCase per repo convention (first character uppercase).
|
||||
/// - module-qualified class qualifier, e.g. `"prelude.Show.show"`.
|
||||
///
|
||||
/// Rejects qualifier shapes that look like cross-module-fn calls
|
||||
/// (`"std_list.length"`): qualifier starts with lowercase, no
|
||||
/// inner dot — falls through to the qualified-fn arm.
|
||||
@@ -2382,6 +2383,19 @@ pub(crate) fn qualifier_is_class_shape(qualifier_opt: &Option<String>) -> bool {
|
||||
}
|
||||
}
|
||||
|
||||
/// mq.2 dispatch entry predicate: the synth Var-arm runs this to
|
||||
/// decide whether `name` should be routed through the class-method
|
||||
/// dispatch helper. Matches a bare method name (e.g. `"show"`) or a
|
||||
/// class-shaped qualifier (`"Show.show"`, `"prelude.Show.show"`).
|
||||
/// A 1-dot lowercase name (`"std_list.length"`) is structurally a
|
||||
/// cross-module-fn call per mq.1's canonical-form rule and falls
|
||||
/// through to the qualified-fn arm.
|
||||
fn is_class_method_dispatch(name: &str, env: &Env) -> bool {
|
||||
let (method_name, qualifier_opt) = parse_method_qualifier(name);
|
||||
qualifier_is_class_shape(&qualifier_opt)
|
||||
&& env.method_to_candidate_classes.contains_key(method_name)
|
||||
}
|
||||
|
||||
/// mq.tidy: predicate for the `class-method-shadowed-by-fn`
|
||||
/// warning emission. The full spec rule (§"Class-fn collisions"
|
||||
/// 161-162) requires a class candidate WITH AN INSTANCE FOR THE
|
||||
@@ -2750,20 +2764,7 @@ pub(crate) fn synth(
|
||||
// Bare name resolves through implicit import; the
|
||||
// unqualified name in the owner module is the same `name`.
|
||||
(qualified, Some((owner_module, name.clone())))
|
||||
} else if {
|
||||
// mq.2 dispatch entry: the Var arm matches a class
|
||||
// method either bare (`"show"`) or qualified
|
||||
// (`"prelude.Show.show"`). `parse_method_qualifier`
|
||||
// splits at the last dot; a `Some(qualifier)` with no
|
||||
// inner dot is a 1-dot name (`std_list.length`) —
|
||||
// structurally a cross-module-fn call per mq.1's
|
||||
// canonical-form rule (class qualifiers are always
|
||||
// `<module>.<Class>`), so we fall through to the
|
||||
// qualified-fn arm below in that case.
|
||||
let (method_name, qualifier_opt) = parse_method_qualifier(name);
|
||||
qualifier_is_class_shape(&qualifier_opt)
|
||||
&& env.method_to_candidate_classes.contains_key(method_name)
|
||||
} {
|
||||
} else if is_class_method_dispatch(name, env) {
|
||||
// mq.2: type-driven dispatch entry. The Var arm runs
|
||||
// before App-arm unification, so the arg type is not
|
||||
// available here. The dispatch helper resolves on
|
||||
@@ -3456,6 +3457,11 @@ fn maybe_instantiate(t: Type, counter: &mut u32) -> Type {
|
||||
fn qualify_local_types(t: &Type, owner_module: &str, local_types: &IndexMap<String, TypeDef>) -> 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)]
|
||||
let qualified_name = if name.contains('.') {
|
||||
name.clone()
|
||||
} else if ailang_core::primitives::is_primitive_name(name) {
|
||||
@@ -3726,9 +3732,10 @@ pub struct Env {
|
||||
/// mq.2: workspace-flat inverse of [`Self::class_methods`] — for
|
||||
/// each method name, the set of qualified class names that declare
|
||||
/// it. Pre-mq.3, the `MethodNameCollision` invariant guarantees
|
||||
/// each set is singleton; mq.3 lifts the invariant and cardinality
|
||||
/// > 1 becomes legal. Synth's `Term::Var` arm consults this index
|
||||
/// for type-driven dispatch (spec §Architecture's 5-step rule).
|
||||
/// each set is singleton; mq.3 lifts the invariant and any
|
||||
/// cardinality above one becomes legal. Synth's `Term::Var` arm
|
||||
/// consults this index for type-driven dispatch (spec
|
||||
/// §Architecture's 5-step rule).
|
||||
pub method_to_candidate_classes: BTreeMap<String, BTreeSet<String>>,
|
||||
/// mq.3: post-superclass-expansion declared constraints of the
|
||||
/// active fn body being checked. Populated by `check_fn` before
|
||||
@@ -5512,7 +5519,7 @@ mod tests {
|
||||
ret_mode: ParamMode::Implicit,
|
||||
}),
|
||||
},
|
||||
vec!["x".into()],
|
||||
vec!["x"],
|
||||
Term::Let {
|
||||
name: "z".into(),
|
||||
value: Box::new(Term::Lit { lit: Literal::Int { value: 7 } }),
|
||||
|
||||
@@ -198,7 +198,7 @@ pub fn lift_letrecs(m: &Module) -> Result<Module> {
|
||||
}
|
||||
}
|
||||
|
||||
out.defs.extend(lifter.lifted.into_iter());
|
||||
out.defs.extend(lifter.lifted);
|
||||
Ok(out)
|
||||
}
|
||||
|
||||
|
||||
@@ -714,7 +714,7 @@ fn collect_pattern_binders(p: &Pattern) -> Vec<String> {
|
||||
Pattern::Var { name } => vec![name.clone()],
|
||||
Pattern::Ctor { fields, .. } => fields
|
||||
.iter()
|
||||
.flat_map(|f| collect_pattern_binders(f))
|
||||
.flat_map(collect_pattern_binders)
|
||||
.collect(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1025,25 +1025,25 @@ fn rewrite_mono_calls(
|
||||
let is_poly_free_fn = !is_class_method && poly_free_fns.contains(name);
|
||||
let should_advance = (is_class_method || is_poly_free_fn) && !locals.contains(name);
|
||||
if should_advance {
|
||||
if let Some(slot) = ordered_targets.get(*cursor) {
|
||||
if let Some(t) = slot {
|
||||
let (sym, defining_module) = match t {
|
||||
MonoTarget::ClassMethod { method, type_, defining_module, .. } => {
|
||||
(mono_symbol(method, type_), defining_module.as_str())
|
||||
}
|
||||
MonoTarget::FreeFn { name: fn_name, type_args, defining_module } => {
|
||||
(mono_symbol_n(fn_name, type_args.as_slice()), defining_module.as_str())
|
||||
}
|
||||
};
|
||||
let new_name = if defining_module == caller_module {
|
||||
sym
|
||||
} else {
|
||||
format!("{}.{}", defining_module, sym)
|
||||
};
|
||||
*name = new_name;
|
||||
}
|
||||
// else: residual / observation was non-concrete →
|
||||
// leave name unchanged.
|
||||
// The outer `Some` means the cursor slot exists; the inner
|
||||
// `Some` means the observation at that slot is concrete.
|
||||
// A `Some(None)` slot is a residual / non-concrete
|
||||
// observation and leaves the name unchanged.
|
||||
if let Some(Some(t)) = ordered_targets.get(*cursor) {
|
||||
let (sym, defining_module) = match t {
|
||||
MonoTarget::ClassMethod { method, type_, defining_module, .. } => {
|
||||
(mono_symbol(method, type_), defining_module.as_str())
|
||||
}
|
||||
MonoTarget::FreeFn { name: fn_name, type_args, defining_module } => {
|
||||
(mono_symbol_n(fn_name, type_args.as_slice()), defining_module.as_str())
|
||||
}
|
||||
};
|
||||
let new_name = if defining_module == caller_module {
|
||||
sym
|
||||
} else {
|
||||
format!("{}.{}", defining_module, sym)
|
||||
};
|
||||
*name = new_name;
|
||||
}
|
||||
*cursor += 1;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user