use hashbrown::HashMap;
use emmylua_parser::LuaAstNode;
use crate::{
DbIndex, InFiled, InferFailReason, LuaDocReturnInfo, LuaSemanticDeclId, LuaType, LuaTypeCache,
SignatureReturnStatus, compilation::analyzer::infer_cache_manager::InferCacheManager,
infer_expr, infer_param,
};
use super::UnResolve;
pub fn check_reach_reason(
db: &DbIndex,
infer_manager: &mut InferCacheManager,
reason: &InferFailReason,
) -> Option<bool> {
match reason {
InferFailReason::None
| InferFailReason::FieldNotFound
| InferFailReason::UnResolveOperatorCall
| InferFailReason::RecursiveInfer => Some(true),
InferFailReason::UnResolveDeclType(decl_id) => {
let decl = db.get_decl_index().get_decl(decl_id)?;
let typ = db.get_type_index().get_type_cache(&(*decl_id).into());
if typ.is_none() && decl.is_param() {
return Some(infer_param(db, decl).is_ok());
}
Some(typ.is_some())
}
InferFailReason::UnResolveTypeDecl(type_id) => {
Some(db.get_type_index().get_type_decl(type_id).is_some())
}
InferFailReason::UnResolveMemberType(member_id) => {
let member = db.get_member_index().get_member(member_id)?;
let key = member.get_key();
let owner = db.get_member_index().get_current_owner(member_id)?;
let member_item = db.get_member_index().get_member_item(owner, key)?;
Some(member_item.resolve_type(db).is_ok())
}
InferFailReason::UnResolveExpr(expr) => {
let cache = infer_manager.get_infer_cache(expr.file_id);
Some(infer_expr(db, cache, expr.value.clone()).is_ok())
}
InferFailReason::UnResolveSignatureReturn(signature_id) => {
let signature = db.get_signature_index().get(signature_id)?;
Some(signature.is_resolve_return())
}
InferFailReason::UnResolveModuleExport(file_id) => {
let module = db.get_module_index().get_module(*file_id)?;
Some(module.export_type.is_some())
}
}
}
pub fn resolve_all_reason(
db: &mut DbIndex,
reason_unresolves: &mut HashMap<InferFailReason, Vec<UnResolve>>,
loop_count: usize,
) {
for (reason, _) in reason_unresolves.iter_mut() {
resolve_as_any(db, reason, loop_count);
}
}
pub fn resolve_as_any(db: &mut DbIndex, reason: &InferFailReason, loop_count: usize) -> Option<()> {
match reason {
InferFailReason::None
| InferFailReason::FieldNotFound
| InferFailReason::UnResolveTypeDecl(_)
| InferFailReason::UnResolveOperatorCall
| InferFailReason::RecursiveInfer => {
return Some(());
}
InferFailReason::UnResolveDeclType(decl_id) => {
db.get_type_index_mut()
.bind_type((*decl_id).into(), LuaTypeCache::InferType(LuaType::Any));
}
InferFailReason::UnResolveMemberType(member_id) => {
if loop_count == 0 {
return Some(());
}
let member = db.get_member_index().get_member(member_id)?;
let key = member.get_key();
let owner = db.get_member_index().get_current_owner(member_id)?;
let member_item = db.get_member_index().get_member_item(owner, key)?;
let opt_type = member_item.resolve_type(db).ok();
if opt_type.is_none() {
let semantic_member_id = member_item.resolve_semantic_decl(db)?;
if let LuaSemanticDeclId::Member(member_id) = semantic_member_id {
db.get_type_index_mut()
.bind_type(member_id.into(), LuaTypeCache::InferType(LuaType::Any));
}
}
}
InferFailReason::UnResolveExpr(expr) => {
let key = InFiled::new(expr.file_id, expr.value.get_syntax_id());
db.get_type_index_mut()
.bind_type(key.into(), LuaTypeCache::InferType(LuaType::Any));
}
InferFailReason::UnResolveSignatureReturn(signature_id) => {
let signature = db.get_signature_index_mut().get_mut(signature_id)?;
if !signature.is_resolve_return() {
signature.return_docs = vec![LuaDocReturnInfo {
name: None,
type_ref: LuaType::Any,
description: None,
attributes: None,
}];
signature.resolve_return = SignatureReturnStatus::InferResolve;
}
}
InferFailReason::UnResolveModuleExport(file_id) => {
let module = db.get_module_index_mut().get_module_mut(*file_id)?;
if module.export_type.is_none() {
module.export_type = Some(LuaType::Any);
}
}
}
Some(())
}