use std::cell::RefCell;
use std::collections::HashSet;
use std::sync::Arc;
use mir_types::Type;
use crate::db::{MirDatabase, SymbolLoc};
thread_local! {
static INFER_IN_PROGRESS: RefCell<HashSet<Arc<str>>> = RefCell::new(HashSet::new());
}
struct InferGuard(Arc<str>);
impl Drop for InferGuard {
fn drop(&mut self) {
INFER_IN_PROGRESS.with(|s| s.borrow_mut().remove(&self.0));
}
}
pub fn inferred_function_return_type_demand(db: &dyn MirDatabase, fqn: &str) -> Option<Arc<Type>> {
let idx = crate::db::workspace_index(db);
let key = mir_types::Name::new(fqn).ascii_lowercase();
let sf = match idx.functions.get(&key)? {
SymbolLoc::Function { file, .. } => *file,
_ => return None,
};
let path = sf.path(db);
let already_active = INFER_IN_PROGRESS.with(|s| s.borrow().contains(&path));
if already_active {
return None;
}
INFER_IN_PROGRESS.with(|s| s.borrow_mut().insert(path.clone()));
let _guard = InferGuard(path);
let inferred = crate::db::infer_file_return_types(db, sf);
inferred.functions.get(fqn).cloned()
}
pub fn inferred_method_return_type_demand(
db: &dyn MirDatabase,
fqcn: &str,
method_name_lower: &str,
) -> Option<Arc<Type>> {
let idx = crate::db::workspace_index(db);
let key = mir_types::Name::new(fqcn).ascii_lowercase();
let sf = match idx.class_like.get(&key)? {
SymbolLoc::Class { file, .. }
| SymbolLoc::Interface { file, .. }
| SymbolLoc::Trait { file, .. }
| SymbolLoc::Enum { file, .. } => *file,
_ => return None,
};
let path = sf.path(db);
let already_active = INFER_IN_PROGRESS.with(|s| s.borrow().contains(&path));
if already_active {
return None;
}
INFER_IN_PROGRESS.with(|s| s.borrow_mut().insert(path.clone()));
let _guard = InferGuard(path);
let inferred = crate::db::infer_file_return_types(db, sf);
inferred
.methods
.get(&(Arc::<str>::from(fqcn), Arc::<str>::from(method_name_lower)))
.cloned()
}