use std::cell::RefCell;
use std::collections::HashSet;
use std::sync::Arc;
use mir_types::Type;
use crate::db::{Fqcn, MirDatabase};
thread_local! {
static INFER_IN_PROGRESS: RefCell<HashSet<Arc<str>>> = RefCell::new(HashSet::new());
}
pub(crate) struct InferGuard(Arc<str>);
impl Drop for InferGuard {
fn drop(&mut self) {
INFER_IN_PROGRESS.with(|s| s.borrow_mut().remove(&self.0));
}
}
pub(crate) fn try_mark_infer_in_progress(path: Arc<str>) -> Option<InferGuard> {
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()));
Some(InferGuard(path))
}
pub fn inferred_function_return_type_demand(db: &dyn MirDatabase, fqn: &str) -> Option<Arc<Type>> {
let sf = crate::db::function_loc(db, Fqcn::from_str(db, fqn))?.file();
let path = sf.path(db).clone();
let _guard = try_mark_infer_in_progress(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 sf = crate::db::class_like_loc(db, Fqcn::from_str(db, fqcn))?.file();
let path = sf.path(db).clone();
let _guard = try_mark_infer_in_progress(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()
}
pub fn inferred_property_type_demand(
db: &dyn MirDatabase,
fqcn: &str,
name: &str,
) -> Option<Arc<Type>> {
let sf = crate::db::class_like_loc(db, Fqcn::from_str(db, fqcn))?.file();
let path = sf.path(db).clone();
let _guard = try_mark_infer_in_progress(path)?;
let inferred = crate::db::infer_file_return_types(db, sf);
inferred
.properties
.get(&(Arc::<str>::from(fqcn), Arc::<str>::from(name)))
.cloned()
}