use std::collections::{HashMap, HashSet};
use std::sync::OnceLock;
use crate::parser::Type;
use super::OwnershipMode;
#[derive(Debug, Clone)]
pub struct FunctionSignature {
pub name: String,
pub param_types: Vec<Type>,
pub param_ownership: Vec<OwnershipMode>,
pub return_type: Option<Type>,
pub return_ownership: OwnershipMode,
pub has_self_receiver: bool,
pub is_extern: bool,
}
impl FunctionSignature {
pub fn arg_param_index(&self, arg_index: usize) -> usize {
if self.has_self_receiver {
arg_index + 1
} else {
arg_index
}
}
pub fn param_ownership_for_arg(&self, arg_index: usize) -> Option<&OwnershipMode> {
self.param_ownership.get(self.arg_param_index(arg_index))
}
pub fn param_type_for_arg(&self, arg_index: usize) -> Option<&Type> {
self.param_types.get(self.arg_param_index(arg_index))
}
}
static STDLIB_BASELINE: OnceLock<SignatureRegistry> = OnceLock::new();
#[derive(Debug, Clone)]
pub struct SignatureRegistry {
pub signatures: HashMap<String, FunctionSignature>,
type_collision_keys: HashSet<String>,
ownership_collision_keys: HashSet<String>,
method_index: HashMap<String, Vec<String>>,
}
impl Default for SignatureRegistry {
fn default() -> Self {
Self::new()
}
}
impl SignatureRegistry {
pub fn new() -> Self {
let baseline = STDLIB_BASELINE.get_or_init(|| {
let mut registry = SignatureRegistry {
signatures: HashMap::new(),
type_collision_keys: HashSet::new(),
ownership_collision_keys: HashSet::new(),
method_index: HashMap::new(),
};
if let Err(e) = crate::stdlib_scanner::populate_runtime_signatures(&mut registry) {
eprintln!("Warning: Failed to scan runtime signatures: {}", e);
eprintln!("Continuing with empty registry - may generate incorrect borrows");
}
Self::load_stdlib_meta(&mut registry);
registry
});
baseline.clone()
}
pub fn empty() -> Self {
SignatureRegistry {
signatures: HashMap::new(),
type_collision_keys: HashSet::new(),
ownership_collision_keys: HashSet::new(),
method_index: HashMap::new(),
}
}
fn load_stdlib_meta(registry: &mut Self) {
use std::path::Path;
let candidates = [
Path::new("stdlib_meta").to_path_buf(),
Path::new(env!("CARGO_MANIFEST_DIR")).join("stdlib_meta"),
];
for dir in &candidates {
if dir.is_dir() {
crate::metadata::merge_wj_meta_signatures_from_dir(dir, registry);
return;
}
}
}
pub fn add_function(&mut self, name: String, sig: FunctionSignature) {
if let Some(existing) = self.signatures.get(&name) {
if existing.param_types != sig.param_types {
let stub_like = existing.param_types.is_empty() || sig.param_types.is_empty();
if !stub_like {
self.type_collision_keys.insert(name.clone());
}
} else if existing.param_ownership != sig.param_ownership {
self.ownership_collision_keys.insert(name.clone());
}
if name.contains("::") && existing.has_self_receiver && !sig.has_self_receiver {
return;
}
}
if let Some(suffix) = name.rsplit_once("::").map(|(_, s)| s.to_string()) {
self.method_index
.entry(suffix)
.or_default()
.push(name.clone());
}
self.signatures.insert(name, sig);
}
pub fn get_signature(&self, name: &str) -> Option<&FunctionSignature> {
self.signatures.get(name)
}
pub fn has_collision(&self, name: &str) -> bool {
if self.type_collision_keys.contains(name) || self.ownership_collision_keys.contains(name) {
return true;
}
self.has_method_name_collision(name)
}
pub fn has_method_name_collision(&self, method: &str) -> bool {
self.has_method_name_collision_for_type(None, method)
}
pub fn should_skip_int_to_float_auto_cast(
&self,
type_name: Option<&str>,
method: &str,
qualified_key: Option<&str>,
) -> bool {
if qualified_key.is_some_and(|k| self.type_collision_keys.contains(k)) {
return true;
}
self.has_method_name_collision_for_type(type_name, method)
}
pub fn has_method_name_collision_for_type(
&self,
type_name: Option<&str>,
method: &str,
) -> bool {
let Some(keys) = self.method_index.get(method) else {
return false;
};
let filtered: Vec<&String> = if let Some(tn) = type_name {
keys.iter()
.filter(|k| {
k.ends_with(&format!("::{method}"))
&& (k.as_str() == format!("{tn}::{method}")
|| k.contains(&format!("::{tn}::")))
})
.collect()
} else {
keys.iter().collect()
};
if filtered.len() < 2 {
return false;
}
let mut first: Option<&FunctionSignature> = None;
for key in filtered {
if let Some(sig) = self.signatures.get(key) {
if let Some(f) = first {
if f.param_types != sig.param_types || f.param_ownership != sig.param_ownership
{
return true;
}
} else {
first = Some(sig);
}
}
}
false
}
pub fn all_signatures(&self) -> impl Iterator<Item = (&String, &FunctionSignature)> {
self.signatures.iter()
}
pub fn lookup_method(&self, name: &str) -> Option<&FunctionSignature> {
self.get_signature(name)
.or_else(|| self.find_signature_ending_with(name))
}
pub fn find_signature_ending_with(&self, suffix: &str) -> Option<&FunctionSignature> {
if let Some(keys) = self.method_index.get(suffix) {
for key in keys {
if let Some(sig) = self.signatures.get(key) {
return Some(sig);
}
}
}
None
}
pub fn find_signature_by_name_and_arg_count(
&self,
name: &str,
arg_count: usize,
) -> Option<&FunctionSignature> {
if let Some(sig) = self.signatures.get(name) {
let sig_args = if sig.has_self_receiver {
sig.param_ownership.len().saturating_sub(1)
} else {
sig.param_ownership.len()
};
if sig_args == arg_count {
return Some(sig);
}
}
if let Some(keys) = self.method_index.get(name) {
for key in keys {
if let Some(sig) = self.signatures.get(key) {
let sig_args = if sig.has_self_receiver {
sig.param_ownership.len().saturating_sub(1)
} else {
sig.param_ownership.len()
};
if sig_args == arg_count {
return Some(sig);
}
}
}
}
None
}
pub fn register_module_aliases(
&mut self,
source: &SignatureRegistry,
file_stem: &str,
module_path: &str,
) {
if file_stem.is_empty() {
return;
}
for (name, sig) in &source.signatures {
if !name.contains("::") {
self.add_function(format!("{}::{}", file_stem, name), sig.clone());
}
if !module_path.is_empty() {
self.add_function(format!("{}::{}", module_path, name), sig.clone());
}
}
}
pub fn ownership_changed(old: &FunctionSignature, new: &FunctionSignature) -> bool {
old.param_ownership != new.param_ownership
|| old.return_ownership != new.return_ownership
|| old.has_self_receiver != new.has_self_receiver
}
pub fn from_program_declarations(program: &crate::parser::Program<'_>) -> Self {
let mut registry = Self::empty();
Self::collect_declarations_from_items(&program.items, &mut registry);
registry
}
fn collect_declarations_from_items(
items: &[crate::parser::ast::core::Item<'_>],
registry: &mut Self,
) {
use crate::parser::ast::core::Item;
for item in items {
match item {
Item::Function { decl, .. } => {
let sig = Self::signature_stub_from_decl(decl, &decl.name);
registry.add_function(decl.name.clone(), sig);
}
Item::Impl { block, .. } => {
let base_type_name = block
.type_name
.split('<')
.next()
.unwrap_or(&block.type_name);
for func in &block.functions {
let sig = Self::signature_stub_from_decl(func, &func.name);
let qualified_name = format!("{}::{}", base_type_name, func.name);
registry.add_function(qualified_name, sig.clone());
registry.add_function(func.name.clone(), sig);
}
}
Item::Trait { decl, .. } => {
for method in &decl.methods {
let has_self_receiver = method
.parameters
.first()
.is_some_and(|p| p.name == "self" || p.name == "mut self");
let param_types: Vec<Type> =
method.parameters.iter().map(|p| p.type_.clone()).collect();
let param_ownership = vec![OwnershipMode::Owned; param_types.len()];
let sig = FunctionSignature {
name: method.name.clone(),
param_types,
param_ownership,
return_type: method.return_type.clone(),
return_ownership: OwnershipMode::Owned,
has_self_receiver,
is_extern: false,
};
registry.add_function(format!("{}::{}", decl.name, method.name), sig);
}
}
Item::Mod { items, .. } => {
Self::collect_declarations_from_items(items, registry);
}
_ => {}
}
}
}
fn signature_stub_from_decl(
func: &crate::parser::ast::core::FunctionDecl<'_>,
name: &str,
) -> FunctionSignature {
let has_self_receiver = func
.parameters
.first()
.is_some_and(|p| p.name == "self" || p.name == "mut self");
let param_types: Vec<Type> = func.parameters.iter().map(|p| p.type_.clone()).collect();
let param_ownership = vec![OwnershipMode::Owned; param_types.len()];
FunctionSignature {
name: name.to_string(),
param_types,
param_ownership,
return_type: func.return_type.clone(),
return_ownership: OwnershipMode::Owned,
has_self_receiver,
is_extern: func.is_extern,
}
}
pub fn merge(&mut self, other: &SignatureRegistry) {
for (name, sig) in &other.signatures {
if let Some(existing) = self.signatures.get(name) {
if existing.param_types != sig.param_types {
let stub_like = existing.param_types.is_empty() || sig.param_types.is_empty();
if !stub_like {
self.type_collision_keys.insert(name.clone());
}
} else if existing.param_ownership != sig.param_ownership {
self.ownership_collision_keys.insert(name.clone());
}
}
if let Some(suffix) = name.rsplit_once("::").map(|(_, s)| s.to_string()) {
self.method_index
.entry(suffix)
.or_default()
.push(name.clone());
}
self.signatures.insert(name.clone(), sig.clone());
}
self.type_collision_keys
.extend(other.type_collision_keys.iter().cloned());
self.ownership_collision_keys
.extend(other.ownership_collision_keys.iter().cloned());
}
pub fn delta_from_base(
base: &SignatureRegistry,
updated: &SignatureRegistry,
) -> SignatureDelta {
let mut changed = HashMap::new();
for (name, sig) in &updated.signatures {
let is_new_or_changed = match base.signatures.get(name) {
None => true,
Some(old) => Self::ownership_changed(old, sig),
};
if is_new_or_changed {
changed.insert(name.clone(), sig.clone());
}
}
SignatureDelta { changed }
}
pub fn merge_delta(&mut self, delta: &SignatureDelta) {
for (name, sig) in &delta.changed {
if let Some(suffix) = name.rsplit_once("::").map(|(_, s)| s.to_string()) {
self.method_index
.entry(suffix)
.or_default()
.push(name.clone());
}
self.signatures.insert(name.clone(), sig.clone());
}
}
}
#[derive(Debug, Clone, Default)]
pub struct SignatureDelta {
pub changed: HashMap<String, FunctionSignature>,
}