diff --git a/server/src/core/evaluation.rs b/server/src/core/evaluation.rs index 88371e11..5ee3d37d 100644 --- a/server/src/core/evaluation.rs +++ b/server/src/core/evaluation.rs @@ -1037,7 +1037,7 @@ impl Evaluation { let name = expr.id.to_string(); (Symbol::infer_name(odoo, &parent, &name, Some(expr.range.end().to_u32())), name) }, - _ => unreachable!("NamedExpr can only have an identifier") + _ => return AnalyzeAstResult::from_only_diagnostics(diagnostics) } }, ExprOrIdent::Ident(expr) => { diff --git a/server/src/core/odoo.rs b/server/src/core/odoo.rs index ec78a6ff..da66efb7 100644 --- a/server/src/core/odoo.rs +++ b/server/src/core/odoo.rs @@ -1476,7 +1476,7 @@ impl Odoo { session.log_message(MessageType::INFO, format!("File Change Event: {}, version {}", path.to_str().unwrap(), version)); let (file_updated, file_info) = session.sync_odoo.get_file_mgr().borrow_mut().update_file_info(session, &path.sanitize(), content, Some(version), false); file_info.borrow_mut().publish_diagnostics(session); //To push potential syntax errors or refresh previous one - return (file_info.borrow().valid && (!file_info.borrow().opened || version >= 0), file_updated); + return (!file_info.borrow().opened || version >= 0, file_updated); } (false, false) } diff --git a/server/src/core/python_arch_builder.rs b/server/src/core/python_arch_builder.rs index 7a97cca4..61bd1aab 100644 --- a/server/src/core/python_arch_builder.rs +++ b/server/src/core/python_arch_builder.rs @@ -91,10 +91,6 @@ impl PythonArchBuilder { false => {session.sync_odoo.get_file_mgr().borrow().get_file_info(&path).unwrap()} }; self.file_info = Some(file_info_rc.clone()); - if !file_info_rc.borrow().valid { - symbol.borrow_mut().set_build_status(BuildSteps::ARCH, BuildStatus::PENDING); - return - } if self.file_mode { //diagnostics for functions are stored directly on funcs let mut file_info = file_info_rc.borrow_mut(); @@ -743,17 +739,19 @@ impl PythonArchBuilder { let mut last_test_section = test_section.index; self.visit_expr(session, &if_stmt.test); - scope.borrow_mut().as_mut_symbol_mgr().add_section( // first body section - if_stmt.body.first().unwrap().range().start(), - None // Take preceding section (if test) - ); - self.ast_indexes.push(0 as u16); //0 for body - self.visit_node(session, &if_stmt.body)?; - self.ast_indexes.pop(); - - let body_section = SectionIndex::INDEX(scope.borrow().as_symbol_mgr().get_last_index()); + let mut stmt_sections = if if_stmt.body.is_empty() { + vec![] + } else { + scope.borrow_mut().as_mut_symbol_mgr().add_section( // first body section + if_stmt.body[0].range().start(), + None // Take preceding section (if test) + ); + self.ast_indexes.push(0 as u16); //0 for body + self.visit_node(session, &if_stmt.body)?; + self.ast_indexes.pop(); + vec![ SectionIndex::INDEX(scope.borrow().as_symbol_mgr().get_last_index())] + }; - let mut stmt_sections = vec![body_section]; let mut else_clause_exists = false; let stmt_clauses_iter = if_stmt.elif_else_clauses.iter().enumerate().map(|(index, elif_else_clause)|{ @@ -767,18 +765,21 @@ impl PythonArchBuilder { }, None => else_clause_exists = true } + if elif_else_clause.body.is_empty() { + return Ok::, Error>(None); + } scope.borrow_mut().as_mut_symbol_mgr().add_section( - elif_else_clause.body.first().unwrap().range().start(), + elif_else_clause.body[0].range().start(), Some(SectionIndex::INDEX(last_test_section)) ); self.ast_indexes.push((index + 1) as u16); //0 for body, so index + 1 self.visit_node(session, &elif_else_clause.body)?; self.ast_indexes.pop(); let clause_section = SectionIndex::INDEX(scope.borrow().as_symbol_mgr().get_last_index()); - Ok::(clause_section) + Ok::, Error>(Some(clause_section)) }); - stmt_sections.extend(stmt_clauses_iter.collect::, _>>()?); + stmt_sections.extend(stmt_clauses_iter.collect::, _>>()?.into_iter().filter_map(|x| x).collect::>()); if !else_clause_exists{ // If there is no else clause, the there is an implicit else clause @@ -804,15 +805,17 @@ impl PythonArchBuilder { AssignTargetType::Name(ref name_expr) => { scope.borrow_mut().add_new_variable(session, oyarn!("{}", name_expr.id), &name_expr.range); }, - AssignTargetType::Attribute(ref attr_expr) => { + AssignTargetType::Attribute(_) => { } } } let previous_section = SectionIndex::INDEX(scope.borrow().as_symbol_mgr().get_last_index()); - scope.borrow_mut().as_mut_symbol_mgr().add_section( - for_stmt.body.first().unwrap().range().start(), - None - ); + if let Some(first_body_stmt) = for_stmt.body.first() { + scope.borrow_mut().as_mut_symbol_mgr().add_section( + first_body_stmt.range().start(), + None + ); + } self.ast_indexes.push(0 as u16); self.visit_node(session, &for_stmt.body)?; @@ -821,7 +824,7 @@ impl PythonArchBuilder { if !for_stmt.orelse.is_empty(){ scope.borrow_mut().as_mut_symbol_mgr().add_section( - for_stmt.orelse.first().unwrap().range().start(), + for_stmt.orelse[0].range().start(), Some(previous_section.clone()) ); self.ast_indexes.push(1 as u16); @@ -859,8 +862,11 @@ impl PythonArchBuilder { match handler { ruff_python_ast::ExceptHandler::ExceptHandler(h) => { if !catch_all_except_exists { catch_all_except_exists = h.type_.is_none()}; + if h.body.is_empty() { + continue; + } scope.borrow_mut().as_mut_symbol_mgr().add_section( - h.body.first().unwrap().range().start(), + h.body[0].range().start(), Some(previous_section.clone()) ); self.ast_indexes.push(index as u16); @@ -876,7 +882,7 @@ impl PythonArchBuilder { stmt_sections.remove(0); } scope.borrow_mut().as_mut_symbol_mgr().add_section( - try_stmt.orelse.first().unwrap().range().start(), + try_stmt.orelse[0].range().start(), Some(previous_section.clone()) ); self.ast_indexes.push(1 as u16); @@ -975,11 +981,13 @@ impl PythonArchBuilder { fn visit_while(&mut self, session: &mut SessionInfo, while_stmt: &StmtWhile) -> Result<(), Error> { // TODO: Handle breaks for sections let scope = self.sym_stack.last().unwrap().clone(); - let body_section = scope.borrow_mut().as_mut_symbol_mgr().add_section( - while_stmt.body.first().unwrap().range().start(), - None - ); - let previous_section = SectionIndex::INDEX(body_section.index - 1); + let previous_section = SectionIndex::INDEX(scope.borrow().as_symbol_mgr().get_last_index()); + if let Some(first_body_stmt) = while_stmt.body.first() { + scope.borrow_mut().as_mut_symbol_mgr().add_section( + first_body_stmt.range().start(), + None + ); + } self.visit_expr(session, &while_stmt.test); self.ast_indexes.push(0 as u16); // 0 for body self.visit_node(session, &while_stmt.body)?; @@ -988,7 +996,7 @@ impl PythonArchBuilder { let mut stmt_sections = vec![body_section]; if !while_stmt.orelse.is_empty(){ scope.borrow_mut().as_mut_symbol_mgr().add_section( - while_stmt.orelse.first().unwrap().range().start(), + while_stmt.orelse[0].range().start(), Some(previous_section.clone()) ); self.ast_indexes.push(1 as u16); // 1 for else diff --git a/server/src/core/python_validator.rs b/server/src/core/python_validator.rs index 2835d824..90e1b6a1 100644 --- a/server/src/core/python_validator.rs +++ b/server/src/core/python_validator.rs @@ -90,7 +90,7 @@ impl PythonValidator { self.sym_stack[0].borrow_mut().set_build_status(BuildSteps::VALIDATION, BuildStatus::INVALID); return; } - if file_info.file_info_ast.borrow().ast.is_some() && file_info.valid { + if file_info.file_info_ast.borrow().ast.is_some() { let old_noqa = session.current_noqa.clone(); session.current_noqa = self.sym_stack[0].borrow().get_noqas(); let file_info_ast = file_info.file_info_ast.borrow(); diff --git a/server/src/core/symbols/symbol.rs b/server/src/core/symbols/symbol.rs index c8be0eb1..9c3ece2f 100644 --- a/server/src/core/symbols/symbol.rs +++ b/server/src/core/symbols/symbol.rs @@ -1234,6 +1234,18 @@ impl Symbol { } } + /// Return all symbols before the given position that are visible in the body of this symbol. + pub fn get_all_visible_symbols(&self, name_prefix: &String, position: u32) -> HashMap>>> { + match self { + Symbol::Class(c) => c.get_all_visible_symbols(name_prefix, position), + Symbol::File(f) => f.get_all_visible_symbols(name_prefix, position), + Symbol::Package(PackageSymbol::Module(m)) => m.get_all_visible_symbols(name_prefix, position), + Symbol::Package(PackageSymbol::PythonPackage(p)) => p.get_all_visible_symbols(name_prefix, position), + Symbol::Function(f) => f.get_all_visible_symbols(name_prefix, position), + _ => HashMap::new(), + } + } + /** * Return a symbol that can be called from outside of the body of the symbol */ @@ -2100,22 +2112,27 @@ impl Symbol { /* Return all the symbols that are available at a given position or in a scope for a given start name */ - pub fn get_all_inferred_names(on_symbol: &Rc>, name: &String, position: Option) -> Vec>> { - fn helper(on_symbol: &Rc>, name: &String, position: Option, acc: &mut Vec>>) { + pub fn get_all_inferred_names(on_symbol: &Rc>, name: &String, position: u32) -> HashMap>>> { + fn helper( + on_symbol: &Rc>, name: &String, position: u32, acc: &mut HashMap>>> + ) { // Add symbols from files and functions - if matches!(on_symbol.borrow().typ(), SymType::FILE | SymType::FUNCTION){ - acc.extend(on_symbol.borrow().all_symbols().filter(|sym| - sym.borrow().name().starts_with(name) && (position.is_none() || !sym.borrow().has_range() || position.unwrap() > sym.borrow().range().end().to_u32()) - )) - }; + if matches!(on_symbol.borrow().typ(), SymType::FILE | SymType::FUNCTION) { + let symbols_map = on_symbol.borrow().get_all_visible_symbols(name, position); + for (sym_name, sym_vec) in symbols_map { + acc.entry(sym_name) + .or_default() + .extend(sym_vec); + } + } // Traverse upwards if we are under a class or a function - if matches!(on_symbol.borrow().typ(), SymType::CLASS | SymType::FUNCTION){ + if matches!(on_symbol.borrow().typ(), SymType::CLASS | SymType::FUNCTION) { if let Some(parent) = on_symbol.borrow().parent().as_ref().and_then(|parent_weak| parent_weak.upgrade()) { helper(&parent, name, position, acc); } - }; + } } - let mut results: Vec>> = vec![]; + let mut results= HashMap::new(); helper(on_symbol, name, position, &mut results); results } diff --git a/server/src/core/symbols/symbol_mgr.rs b/server/src/core/symbols/symbol_mgr.rs index cc28d734..31884e48 100644 --- a/server/src/core/symbols/symbol_mgr.rs +++ b/server/src/core/symbols/symbol_mgr.rs @@ -37,6 +37,7 @@ pub trait SymbolMgr { fn get_ext_symbol(&self, name: OYarn) -> Option<&Vec>>>; fn _init_symbol_mgr(&mut self); fn _get_loc_symbol(&self, map: &HashMap>>>, position: u32, index: &SectionIndex, acc: &mut HashSet) -> ContentSymbols; + fn get_all_visible_symbols(&self, name_prefix: &String, position: u32) -> HashMap>>>; } @@ -156,6 +157,24 @@ macro_rules! impl_section_mgr_for { res } + fn get_all_visible_symbols(&self, name_prefix: &String, position: u32) -> HashMap>>> { + let mut result = HashMap::new(); + let current_section = self.get_section_for(position); + let current_index = SectionIndex::INDEX(current_section.index); + + for (name, section_map) in self.symbols.iter() { + if !name.starts_with(name_prefix) { + continue; + } + let mut seen = HashSet::new(); + let content = self._get_loc_symbol(section_map, position, ¤t_index, &mut seen); + + if !content.symbols.is_empty() { + result.insert(name.clone(), content.symbols); + } + } + result + } } )+) } diff --git a/server/src/features/completion.rs b/server/src/features/completion.rs index 4570ac0d..ff4e7235 100644 --- a/server/src/features/completion.rs +++ b/server/src/features/completion.rs @@ -1,5 +1,6 @@ -use std::collections::HashMap; +use std::collections::{HashMap, HashSet}; use std::{cell::RefCell, rc::Rc}; +use itertools::Itertools; use lsp_types::{CompletionItem, CompletionItemKind, CompletionItemLabelDetails, CompletionList, CompletionResponse, MarkupContent}; use ruff_python_ast::{Decorator, ExceptHandler, Expr, ExprAttribute, ExprIf, ExprName, ExprSubscript, ExprYield, Stmt, StmtGlobal, StmtImport, StmtImportFrom, StmtNonlocal}; use ruff_text_size::{Ranged, TextSize}; @@ -16,6 +17,8 @@ use crate::core::symbols::symbol::Symbol; use crate::features::features_utils::FeaturesUtils; use crate::core::file_mgr::FileInfo; +use super::features_utils::TypeInfo; + #[allow(non_camel_case_types)] #[derive(Debug)] @@ -43,10 +46,10 @@ impl CompletionFeature { character: u32 ) -> Option { let offset = file_info.borrow().position_to_offset(line, character); - let mut file_info = file_info.borrow_mut(); + let file_info = file_info.borrow(); let file_info_ast = file_info.file_info_ast.borrow(); let ast = file_info_ast.ast.as_ref().unwrap(); - complete_vec_stmt(ast, session, file_symbol, offset) + complete_vec_stmt(ast, session, file_symbol, offset).or_else(|| complete_name(session, file_symbol, offset, false, &S!(""))) } } @@ -102,7 +105,7 @@ fn complete_vec_stmt(stmts: &Vec, session: &mut SessionInfo, file_symbol: if stmts.iter().last().unwrap().range().end().to_usize() >= offset { return complete_stmt(session, file_symbol, stmts.iter().last().unwrap(), offset); } - //The user is writting after the last stmt + //The user is writing after the last stmt None } @@ -391,7 +394,7 @@ fn complete_expr(expr: &Expr, session: &mut SessionInfo, file: &Rc complete_attribut(session, file, expr_attribute, offset, is_param, expected_type), Expr::Subscript(expr_subscript) => complete_subscript(session, file, expr_subscript, offset, is_param, expected_type), Expr::Starred(_) => None, - Expr::Name(expr_name) => complete_name(session, file, expr_name, offset, is_param, expected_type), + Expr::Name(expr_name) => complete_name_expression(session, file, expr_name, offset, is_param, expected_type), Expr::List(expr_list) => complete_list(session, file, expr_list, offset, is_param, expected_type), Expr::Tuple(expr_tuple) => complete_tuple(session, file, expr_tuple, offset, is_param, expected_type), Expr::Slice(_) => None, @@ -787,23 +790,22 @@ fn complete_subscript(session: &mut SessionInfo, file: &Rc>, exp complete_expr(&expr_subscript.slice, session, file, offset, false, &vec![]) } -fn complete_name(session: &mut SessionInfo, file: &Rc>, expr_name: &ExprName, offset: usize, is_param: bool, expected_type: &Vec) -> Option { - let mut items = vec![]; - let name = expr_name.id.to_string(); +fn complete_name_expression(session: &mut SessionInfo, file: &Rc>, expr_name: &ExprName, offset: usize, is_param: bool, _expected_type: &Vec) -> Option { if expr_name.range.end().to_usize() == offset { - let scope = Symbol::get_scope_symbol(file.clone(), offset as u32, is_param); - let symbols = Symbol::get_all_inferred_names(&scope, &name, Some(offset as u32)); - for symbol in symbols { - items.push(CompletionItem { - label: symbol.borrow().name().to_string(), - kind: Some(lsp_types::CompletionItemKind::VARIABLE), - ..Default::default() - }); - } + complete_name(session, file, offset, is_param, &expr_name.id.to_string()) + } else { + None } +} + +fn complete_name(session: &mut SessionInfo, file: &Rc>, offset: usize, is_param: bool, name: &String) -> Option { + let scope = Symbol::get_scope_symbol(file.clone(), offset as u32, is_param); + let symbols = Symbol::get_all_inferred_names(&scope, name, offset as u32); Some(CompletionResponse::List(CompletionList { is_incomplete: false, - items + items: symbols.into_iter().map(|(_symbol_name, symbols)| { + build_completion_item_from_symbol(session, symbols, HashMap::new()) + }).collect::>(), })) } @@ -935,7 +937,7 @@ fn add_nested_field_names( let mut found_one = false; for (final_sym, dep) in symbols.iter() { //search for at least one that is a field if dep.is_none() && (specific_field_type.is_none() || final_sym.borrow().is_specific_field(session, &["Many2one", "One2many", "Many2many", specific_field_type.as_ref().unwrap().as_str()])){ - items.push(build_completion_item_from_symbol(session, final_sym, HashMap::new(), dep.clone())); + items.push(build_completion_item_from_symbol(session, vec![final_sym.clone()], HashMap::new())); found_one = true; continue; } @@ -993,169 +995,56 @@ fn add_model_attributes( if _symbol_name.starts_with(attribute_name) { if let Some((final_sym, dep)) = symbols.first() { let context_of_symbol = HashMap::from([(S!("base_attr"), ContextValue::SYMBOL(Rc::downgrade(&parent_sym)))]); - items.push(build_completion_item_from_symbol(session, final_sym, context_of_symbol, dep.clone())); + items.push(build_completion_item_from_symbol(session, vec![final_sym.clone()], context_of_symbol)); } } } } -fn build_completion_item_from_symbol(session: &mut SessionInfo, symbol: &Rc>, context_of_symbol: Context, dependency: Option) -> CompletionItem { - //TODO use dependency to show it? or to filter depending of configuration - let typ = Symbol::follow_ref(&&EvaluationSymbolPtr::WEAK(EvaluationSymbolWeak::new( - Rc::downgrade(symbol), - None, - false, - )), session, &mut None, false, true, None, &mut vec![]); - let mut label_details = Some(CompletionItemLabelDetails { - detail: None, - description: None, - }); - if typ.len() > 1 { - label_details = Some(CompletionItemLabelDetails { - detail: None, - description: Some(S!("Any")), - }) - } else if typ.len() == 1 && typ[0].is_weak() { - label_details= match typ[0].upgrade_weak().unwrap().borrow().typ() { - SymType::CLASS => Some(CompletionItemLabelDetails { - detail: None, - description: Some(typ[0].upgrade_weak().unwrap().borrow().name().to_string()), - }), - SymType::VARIABLE => { - let var_upgraded = typ[0].upgrade_weak().unwrap(); - let var = var_upgraded.borrow(); - if var.evaluations().as_ref().unwrap().len() == 1 { - if var.evaluations().as_ref().unwrap()[0].value.is_some() { - match var.evaluations().as_ref().unwrap()[0].value.as_ref().unwrap() { - EvaluationValue::ANY() => None, - EvaluationValue::CONSTANT(expr) => { - match expr { - Expr::StringLiteral(expr_string_literal) => { - Some(CompletionItemLabelDetails { - detail: None, - description: Some(expr_string_literal.value.to_string()), - }) - }, - Expr::BytesLiteral(_) => None, - Expr::NumberLiteral(_) => { - Some(CompletionItemLabelDetails { - detail: None, - description: Some(S!("Number")), - }) - }, - Expr::BooleanLiteral(expr_boolean_literal) => { - Some(CompletionItemLabelDetails { - detail: None, - description: Some(expr_boolean_literal.value.to_string()), - }) - }, - Expr::NoneLiteral(_) => { - Some(CompletionItemLabelDetails { - detail: None, - description: Some(S!("None")), - }) - }, - Expr::EllipsisLiteral(_) => None, - _ => {None} - } - }, - EvaluationValue::DICT(_) => None, - EvaluationValue::LIST(_) => None, - EvaluationValue::TUPLE(_) => None, - } - } else { - None - } - } else { - None - } - }, - SymType::FUNCTION => { - let func_upgraded = typ[0].upgrade_weak().unwrap(); - let func = func_upgraded.borrow(); - if func.evaluations().as_ref().unwrap().len() == 1 { //TODO handle multiple evaluations - if func.evaluations().as_ref().unwrap()[0].value.is_some() { - match func.evaluations().as_ref().unwrap()[0].value.as_ref().unwrap() { - EvaluationValue::ANY() => None, - EvaluationValue::CONSTANT(expr) => { - match expr { - Expr::StringLiteral(expr_string_literal) => { - Some(CompletionItemLabelDetails { - detail: None, - description: Some(expr_string_literal.value.to_string()), - }) - }, - Expr::BytesLiteral(_) => None, - Expr::NumberLiteral(_) => { - Some(CompletionItemLabelDetails { - detail: None, - description: Some(S!("Number")), - }) - }, - Expr::BooleanLiteral(expr_boolean_literal) => { - Some(CompletionItemLabelDetails { - detail: None, - description: Some(expr_boolean_literal.value.to_string()), - }) - }, - Expr::NoneLiteral(_) => { - Some(CompletionItemLabelDetails { - detail: None, - description: Some(S!("None")), - }) - }, - Expr::EllipsisLiteral(_) => None, - _ => {None} - } - }, - EvaluationValue::DICT(_) => None, - EvaluationValue::LIST(_) => None, - EvaluationValue::TUPLE(_) => None, - } - } else { - //TODO - Some(CompletionItemLabelDetails { - detail: None, - description: Some(S!("Any")), - }) - } - } else { - if func.evaluations().as_ref().unwrap().is_empty() { - Some(CompletionItemLabelDetails { - detail: None, - description: Some(S!("None")), - }) - } else { - Some(CompletionItemLabelDetails { - detail: None, - description: Some(S!("Any")), - }) - } - } - } - _ => {Some(CompletionItemLabelDetails { - detail: None, - description: None, - })} - }; +fn build_completion_item_from_symbol(session: &mut SessionInfo, symbols: Vec>>, context_of_symbol: Context) -> CompletionItem { + if symbols.is_empty() { + return CompletionItem::default(); } + //TODO use dependency to show it? or to filter depending of configuration + let typ = symbols.iter().flat_map(|symbol| + Symbol::follow_ref(&&EvaluationSymbolPtr::WEAK(EvaluationSymbolWeak::new( + Rc::downgrade(symbol), + None, + false, + )), session, &mut None, false, false, None, &mut vec![]) + ).collect::>(); + let type_details = typ.iter().map(|eval| + FeaturesUtils::get_inferred_types(session, eval, &mut Some(context_of_symbol.clone()), &symbols[0].borrow().typ()) + ).collect::>(); + let label_details_description = match type_details.len() { + 0 => None, + 1 => Some(match &type_details.iter().next().unwrap() { + TypeInfo::CALLABLE(c) => c.return_types.clone(), + TypeInfo::VALUE(v) => v.clone(), + }), + _ => Some(format!("{} types", type_details.len())), + }; + CompletionItem { - label: symbol.borrow().name().to_string(), - label_details: label_details, - detail: None, - kind: Some(get_completion_item_kind(symbol)), - sort_text: Some(get_sort_text_for_symbol(symbol)), + label: symbols[0].borrow().name().to_string(), + label_details: Some(CompletionItemLabelDetails { + detail: None, + description: label_details_description, + }), + detail: Some(type_details.iter().map(|detail| detail.to_string()).join(" | ").to_string()), + kind: Some(get_completion_item_kind(&symbols[0])), + sort_text: Some(get_sort_text_for_symbol(&symbols[0])), documentation: Some( lsp_types::Documentation::MarkupContent(MarkupContent { kind: lsp_types::MarkupKind::Markdown, - value: FeaturesUtils::build_markdown_description(session, None, &vec![ + value: FeaturesUtils::build_markdown_description(session, None, &symbols.iter().map(|symbol| Evaluation { symbol: EvaluationSymbol::new_with_symbol(Rc::downgrade(symbol), None, - context_of_symbol, + context_of_symbol.clone(), None), value: None, range: None - }], + }).collect::>(), &None, None) })), ..Default::default() diff --git a/server/src/features/features_utils.rs b/server/src/features/features_utils.rs index 60e12b08..ad961b5a 100644 --- a/server/src/features/features_utils.rs +++ b/server/src/features/features_utils.rs @@ -19,15 +19,23 @@ use crate::{oyarn, Sy, S}; #[derive(Clone, Eq, PartialEq, Hash)] -struct CallableSignature { - arguments: String, - return_types: String, +pub struct CallableSignature { + pub arguments: String, + pub return_types: String, } #[derive(Clone, Eq, PartialEq, Hash)] -enum TypeInfo { +pub enum TypeInfo { CALLABLE(CallableSignature), VALUE(String), } +impl TypeInfo { + pub(crate) fn to_string(&self) -> String { + match self { + TypeInfo::CALLABLE(CallableSignature { arguments, return_types }) => format!("(({}) -> {})", arguments, return_types), + TypeInfo::VALUE(value) => value.clone(), + } + } +} #[derive(Clone)] struct InferredType { eval_ptr: EvaluationSymbolPtr, @@ -444,7 +452,7 @@ impl FeaturesUtils { /// Return return type representation of evaluation /// for a function evaluation it is typically (_arg: _arg_type, ...) -> (_result_type) /// for variable it just shows the type, or Any if it fails to find it - fn get_inferred_types(session: &mut SessionInfo, eval: &EvaluationSymbolPtr, context: &mut Option, symbol_type: &SymType) -> TypeInfo { + pub fn get_inferred_types(session: &mut SessionInfo, eval: &EvaluationSymbolPtr, context: &mut Option, symbol_type: &SymType) -> TypeInfo { if *symbol_type == SymType::CLASS{ return TypeInfo::VALUE(S!("")); } @@ -465,7 +473,7 @@ impl FeaturesUtils { } } }; - context.as_mut().unwrap().insert(S!("base_call"), ContextValue::SYMBOL(call_parent)); + context.as_mut().map(|ctx| ctx.insert(S!("base_call"), ContextValue::SYMBOL(call_parent))); let return_type = match inferred_type.evaluations() { Some(func_eval) => { let type_names: Vec<_> = func_eval.iter().flat_map(|eval|{ @@ -481,7 +489,7 @@ impl FeaturesUtils { }, None => S!("None"), }; - context.as_mut().unwrap().remove(&S!("base_call")); + context.as_mut().map(|ctx| ctx.remove(&S!("base_call"))); let argument_names = inferred_type.as_func().args.iter().map(|arg| FeaturesUtils::argument_presentation(session, arg)).join(", "); TypeInfo::CALLABLE(CallableSignature { arguments: argument_names, return_types: return_type }) }, @@ -535,7 +543,7 @@ impl FeaturesUtils { } let return_types_string = inferred_types.iter().map(|rt| match &rt.eval_info { TypeInfo::CALLABLE(CallableSignature { arguments, return_types }) => { - if single_func_eval {return_types.clone()} else {format!("({}) -> {})", arguments, return_types)} + if single_func_eval {return_types.clone()} else {format!("(({}) -> {})", arguments, return_types)} }, TypeInfo::VALUE(value) => value.clone(), }).unique().collect::>();