aver/codegen/scc.rs
1//! Bare-name → `FnId` projection helpers for codegen boundary code.
2//!
3//! `call_graph` is **scope-local by design** — every public fn operates on
4//! a single scope (entry module OR one dep module), returns bare-name
5//! results, and Aver's module DAG invariant keeps cross-module SCCs
6//! impossible so the bare-name keying is correct within a scope (see
7//! `project_aver_module_dag` memory).
8//!
9//! Codegen, however, needs `FnId` identity once it joins per-scope
10//! results into a global view (`CodegenContext.recursive_fns` /
11//! `mutual_tco_members` are FnId-keyed after #145 phase C). The
12//! conversion is mechanical — pick `FnKey::entry` or `FnKey::in_module`
13//! based on scope and look the ID up — but writing it inline in every
14//! place that consumes a per-scope bare-name set turned `build_context`
15//! / `refresh_facts` / `pipeline.rs` proof setup into ~120 lines of
16//! near-identical `filter_map` blocks. These two helpers collapse the
17//! pattern.
18
19use std::collections::HashSet;
20
21use crate::ir::{FnId, FnKey, SymbolTable};
22
23/// Project a sequence of bare fn names (as `&str`) to `FnId`s through
24/// the symbol table. `scope = None` resolves names against the entry
25/// scope; `Some(prefix)` resolves against the dep module with that
26/// prefix. Names that don't resolve (built-ins, synthetic helpers
27/// the table excludes) are dropped silently — same semantics every
28/// per-scope union loop already had.
29pub fn bare_names_to_fn_ids<'a>(
30 names: impl IntoIterator<Item = &'a str>,
31 symbols: &SymbolTable,
32 scope: Option<&str>,
33) -> HashSet<FnId> {
34 names
35 .into_iter()
36 .filter_map(|n| symbols.fn_id_of(&fn_key_in_scope(scope, n)))
37 .collect()
38}
39
40/// Same shape as [`bare_names_to_fn_ids`] but accepts an iterator over
41/// `&String` (which is what `HashSet<String>` / `Vec<String>` from
42/// `AnalysisResult.recursive_fns` / `mutual_tco_members` yields). Avoids
43/// `.iter().map(String::as_str)` ceremony at every call site.
44pub fn analysis_set_to_fn_ids<'a, I>(
45 names: I,
46 symbols: &SymbolTable,
47 scope: Option<&str>,
48) -> HashSet<FnId>
49where
50 I: IntoIterator<Item = &'a String>,
51{
52 bare_names_to_fn_ids(names.into_iter().map(String::as_str), symbols, scope)
53}
54
55fn fn_key_in_scope(scope: Option<&str>, name: &str) -> FnKey {
56 match scope {
57 Some(prefix) => FnKey::in_module(prefix.to_string(), name),
58 None => FnKey::entry(name),
59 }
60}