From b71c253942be4bf61b45d63779ecfabcd7e82989 Mon Sep 17 00:00:00 2001 From: sofia Date: Tue, 29 Jul 2025 21:39:14 +0300 Subject: [PATCH] Add types to hovers in LSP, fix around and add metas --- reid-lsp/src/main.rs | 185 +++++++++++++++++++++--- reid/src/ast/mod.rs | 6 +- reid/src/ast/parse.rs | 14 +- reid/src/ast/process.rs | 5 +- reid/src/ast/token_stream.rs | 4 +- reid/src/codegen/allocator.rs | 4 +- reid/src/codegen/mod.rs | 4 +- reid/src/mir/fmt.rs | 6 +- reid/src/mir/implement.rs | 4 +- reid/src/mir/linker.rs | 2 +- reid/src/mir/mod.rs | 4 +- reid/src/mir/pass.rs | 2 +- reid/src/mir/typecheck/typecheck.rs | 4 +- reid/src/mir/typecheck/typeinference.rs | 2 +- 14 files changed, 199 insertions(+), 47 deletions(-) diff --git a/reid-lsp/src/main.rs b/reid-lsp/src/main.rs index 7cffd37..1b0bd40 100644 --- a/reid-lsp/src/main.rs +++ b/reid-lsp/src/main.rs @@ -3,7 +3,10 @@ use std::path::PathBuf; use dashmap::DashMap; use reid::ast::lexer::{FullToken, Position}; -use reid::mir::{self, Context, StructType, TypeKind}; +use reid::mir::{ + self, Context, FunctionCall, FunctionDefinition, FunctionParam, IfExpression, SourceModuleId, StructType, TypeKind, + WhileStatement, +}; use reid::{compile_module, parse_module, perform_all_passes}; use tower_lsp::jsonrpc::Result; use tower_lsp::lsp_types::{ @@ -78,12 +81,6 @@ impl LanguageServer for Backend { let tokens = self.tokens.get(&file_name); let position = params.text_document_position_params.position; - self.client - .log_message( - MessageType::INFO, - format!("line {}, col {}", position.line, position.character), - ) - .await; let token = if let Some(tokens) = &tokens { tokens.iter().find(|tok| { tok.position.1 == position.line + 1 @@ -95,17 +92,21 @@ impl LanguageServer for Backend { }; let ty = if let Some(token) = token { - if let Some(ty) = self.types.get(&file_name).unwrap().get(token) { - ty.clone() + if let Some(possible_ty) = self.types.get(&file_name).unwrap().get(token) { + if let Some(ty) = possible_ty.clone() { + format!("{}", ty) + } else { + String::from("no type") + } } else { - None + String::from("no token") } } else { - None + String::from("no token") }; Ok(Some(Hover { - contents: HoverContents::Scalar(MarkedString::String(format!("{:?}", ty))), + contents: HoverContents::Scalar(MarkedString::String(format!("{}", ty))), range: None, })) } @@ -139,7 +140,7 @@ impl Backend { let mut reid_error = None; let mut tokens = None; - let token_types = DashMap::new(); + let mut token_types_opt = None; match parse_module(¶ms.text, file_name.clone(), &mut map) { Ok(module) => { @@ -157,9 +158,11 @@ impl Backend { if module.module_id != module_id { continue; } + let token_types = DashMap::new(); for (idx, token) in module.tokens.iter().enumerate() { token_types.insert(token.clone(), find_type_in_context(&module, idx)); } + token_types_opt = Some(token_types); } } Err(e) => { @@ -178,8 +181,9 @@ impl Backend { } if let Some(tokens) = &tokens { - if let Some(reid_error) = reid_error { + if let Some(mut reid_error) = reid_error { let mut diagnostics = Vec::new(); + reid_error.errors.dedup(); for error in reid_error.errors { let meta = error.get_meta(); let positions = meta @@ -226,7 +230,9 @@ impl Backend { if let Some(tokens) = tokens.take() { self.tokens.insert(file_name.clone(), tokens); } - self.types.insert(file_name.clone(), token_types); + if let Some(token_types) = token_types_opt { + self.types.insert(file_name.clone(), token_types); + } } } @@ -278,7 +284,7 @@ pub fn find_type_in_context(module: &mir::Module, token_idx: usize) -> Option find_type_in_block(&block, token_idx), + mir::FunctionDefinitionKind::Local(block, _) => find_type_in_block(&block, module.module_id, token_idx), mir::FunctionDefinitionKind::Extern(_) => None, mir::FunctionDefinitionKind::Intrinsic(_) => None, }; @@ -286,8 +292,151 @@ pub fn find_type_in_context(module: &mir::Module, token_idx: usize) -> Option Option { - for statement in &block.statements {} +pub fn find_type_in_block(block: &mir::Block, module_id: SourceModuleId, token_idx: usize) -> Option { + if !block.meta.contains(token_idx) { + return None; + } + + for statement in &block.statements { + if !statement.1.contains(token_idx) { + continue; + } + match &statement.0 { + mir::StmtKind::Let(named_variable_ref, _, expression) => { + if named_variable_ref.2.contains(token_idx) { + return expression + .return_type(&Default::default(), module_id) + .ok() + .map(|(_, ty)| ty); + } else { + return find_type_in_expr(&expression, module_id, token_idx); + } + } + mir::StmtKind::Set(lhs, rhs) => { + return find_type_in_expr(lhs, module_id, token_idx).or(find_type_in_expr(rhs, module_id, token_idx)); + } + mir::StmtKind::Import(_) => {} + mir::StmtKind::Expression(expression) => return find_type_in_expr(expression, module_id, token_idx), + mir::StmtKind::While(WhileStatement { condition, block, .. }) => { + return find_type_in_expr(condition, module_id, token_idx) + .or(find_type_in_block(block, module_id, token_idx)); + } + } + } + + if let Some((_, Some(return_exp))) = &block.return_expression { + if let Some(ty) = find_type_in_expr(return_exp, module_id, token_idx) { + return Some(ty); + } + } None } + +pub fn find_type_in_expr(expr: &mir::Expression, module_id: SourceModuleId, token_idx: usize) -> Option { + if !expr.1.contains(token_idx) { + return None; + } + + match &expr.0 { + mir::ExprKind::Variable(named_variable_ref) => Some(named_variable_ref.0.clone()), + mir::ExprKind::Indexed(value, type_kind, index_expr) => Some( + find_type_in_expr(&value, module_id, token_idx) + .or(find_type_in_expr(&index_expr, module_id, token_idx)) + .unwrap_or(type_kind.clone()), + ), + mir::ExprKind::Accessed(expression, type_kind, _, meta) => { + if meta.contains(token_idx) { + Some(type_kind.clone()) + } else { + find_type_in_expr(&expression, module_id, token_idx) + } + } + mir::ExprKind::Array(expressions) => { + for expr in expressions { + if let Some(ty) = find_type_in_expr(expr, module_id, token_idx) { + return Some(ty); + } + } + None + } + mir::ExprKind::Struct(name, items) => { + for (_, expr, meta) in items { + if meta.contains(token_idx) { + return expr.return_type(&Default::default(), module_id).map(|(_, t)| t).ok(); + } + if let Some(ty) = find_type_in_expr(expr, module_id, token_idx) { + return Some(ty); + } + } + Some(TypeKind::CustomType(mir::CustomTypeKey(name.clone(), module_id))) + } + mir::ExprKind::Literal(literal) => Some(literal.as_type()), + mir::ExprKind::BinOp(binary_operator, lhs, rhs, type_kind) => { + if let Some(ty) = find_type_in_expr(lhs, module_id, token_idx) { + return Some(ty); + } + if let Some(ty) = find_type_in_expr(rhs, module_id, token_idx) { + return Some(ty); + } + Some(type_kind.clone()) + } + mir::ExprKind::FunctionCall(FunctionCall { + return_type, + parameters, + .. + }) => { + for expr in parameters { + if let Some(ty) = find_type_in_expr(expr, module_id, token_idx) { + return Some(ty); + } + } + Some(return_type.clone()) + } + mir::ExprKind::AssociatedFunctionCall( + _, + FunctionCall { + return_type, + parameters, + .. + }, + ) => { + for expr in parameters { + if let Some(ty) = find_type_in_expr(expr, module_id, token_idx) { + return Some(ty); + } + } + Some(return_type.clone()) + } + mir::ExprKind::If(IfExpression(cond, then_e, else_e)) => find_type_in_expr(&cond, module_id, token_idx) + .or(find_type_in_expr(&then_e, module_id, token_idx)) + .or(else_e.clone().and_then(|e| find_type_in_expr(&e, module_id, token_idx))), + mir::ExprKind::Block(block) => find_type_in_block(block, module_id, token_idx), + mir::ExprKind::Borrow(expression, mutable) => { + if let Some(ty) = find_type_in_expr(&expression, module_id, token_idx) { + return Some(ty); + } + if let Ok(inner) = expression.return_type(&Default::default(), module_id).map(|(_, ty)| ty) { + Some(TypeKind::Borrow(Box::new(inner.clone()), *mutable)) + } else { + None + } + } + mir::ExprKind::Deref(expression) => { + if let Some(ty) = find_type_in_expr(&expression, module_id, token_idx) { + return Some(ty); + } + if let Ok(TypeKind::Borrow(inner, _)) = + expression.return_type(&Default::default(), module_id).map(|(_, ty)| ty) + { + Some(*inner.clone()) + } else { + None + } + } + mir::ExprKind::CastTo(expression, type_kind) => { + Some(find_type_in_expr(&expression, module_id, token_idx).unwrap_or(type_kind.clone())) + } + mir::ExprKind::GlobalRef(_, type_kind) => Some(type_kind.clone()), + } +} diff --git a/reid/src/ast/mod.rs b/reid/src/ast/mod.rs index fd35fd5..18859d7 100644 --- a/reid/src/ast/mod.rs +++ b/reid/src/ast/mod.rs @@ -1,7 +1,7 @@ //! This is the module that contains relevant code to parsing Reid, that is to //! say transforming a Vec of FullTokens into a loose parsed AST that can be //! used for unwrapping syntax sugar, and then be transformed into Reid MIR. -use std::path::PathBuf; +use std::{fs::Metadata, path::PathBuf}; use token_stream::TokenRange; @@ -88,7 +88,7 @@ pub enum ExpressionKind { /// Array-indexed, e.g. [] Indexed(Box, Box), /// Struct-accessed, e.g. . - Accessed(Box, String), + Accessed(Box, String, TokenRange), /// Associated function call, but with a shorthand AccessCall(Box, Box), Binop(BinaryOperator, Box, Box), @@ -216,7 +216,7 @@ pub enum ReturnType { #[derive(Debug, Clone)] pub struct StructExpression { name: String, - fields: Vec<(String, Expression)>, + fields: Vec<(String, Expression, TokenRange)>, range: TokenRange, } diff --git a/reid/src/ast/parse.rs b/reid/src/ast/parse.rs index f11a8a7..2a64150 100644 --- a/reid/src/ast/parse.rs +++ b/reid/src/ast/parse.rs @@ -191,10 +191,11 @@ where ), expr.0 .1, ), - ExpressionKind::Accessed(value_expr, index_name) => Expression( + ExpressionKind::Accessed(value_expr, index_name, range) => Expression( ExpressionKind::Accessed( Box::new(apply_inner(PrimaryExpression(*value_expr.clone()), fun)), index_name.clone(), + *range, ), expr.0 .1, ), @@ -399,9 +400,9 @@ impl Parse for PrimaryExpression { ); } ValueIndex::Dot(val) => match val { - DotIndexKind::StructValueIndex(name) => { + DotIndexKind::StructValueIndex(name, range) => { expr = Expression( - ExpressionKind::Accessed(Box::new(expr), name), + ExpressionKind::Accessed(Box::new(expr), name, range), stream.get_range().unwrap(), ); } @@ -818,9 +819,10 @@ impl Parse for StructExpression { let Some(Token::Identifier(name)) = stream.next() else { return Err(stream.expected_err("struct identifier")?); }; + stream.expect(Token::BraceOpen)?; let named_list = stream.parse::>()?; - let fields = named_list.0.into_iter().map(|f| (f.0, f.1)).collect(); + let fields = named_list.0.into_iter().map(|f| (f.0, f.1, f.2)).collect(); stream.expect(Token::BraceClose)?; @@ -897,7 +899,7 @@ impl Parse for ArrayValueIndex { #[derive(Debug, Clone)] pub enum DotIndexKind { - StructValueIndex(String), + StructValueIndex(String, TokenRange), FunctionCall(FunctionCallExpression), } @@ -913,7 +915,7 @@ impl Parse for DotIndexKind { is_macro: false, })) } else { - Ok(Self::StructValueIndex(name)) + Ok(Self::StructValueIndex(name, stream.get_range().unwrap())) } } else { return Err(stream.expected_err("struct index (number)")?); diff --git a/reid/src/ast/process.rs b/reid/src/ast/process.rs index 58171aa..32a144e 100644 --- a/reid/src/ast/process.rs +++ b/reid/src/ast/process.rs @@ -375,13 +375,14 @@ impl ast::Expression { struct_init .fields .iter() - .map(|(n, e)| (n.clone(), e.process(module_id))) + .map(|(n, e, r)| (n.clone(), e.process(module_id), r.as_meta(module_id))) .collect(), ), - ast::ExpressionKind::Accessed(expression, name) => mir::ExprKind::Accessed( + ast::ExpressionKind::Accessed(expression, name, name_range) => mir::ExprKind::Accessed( Box::new(expression.process(module_id)), mir::TypeKind::Vague(mir::VagueType::Unknown), name.clone(), + name_range.as_meta(module_id), ), ast::ExpressionKind::Borrow(expr, mutable) => { mir::ExprKind::Borrow(Box::new(expr.process(module_id)), *mutable) diff --git a/reid/src/ast/token_stream.rs b/reid/src/ast/token_stream.rs index 607b16f..829f08f 100644 --- a/reid/src/ast/token_stream.rs +++ b/reid/src/ast/token_stream.rs @@ -226,8 +226,8 @@ impl std::ops::Add for TokenRange { fn add(self, rhs: Self) -> Self::Output { TokenRange { - start: self.start.min(rhs.start), - end: self.end.min(rhs.end), + start: self.start.min(rhs.start).min(rhs.end), + end: self.end.max(rhs.end).max(rhs.start), } } } diff --git a/reid/src/codegen/allocator.rs b/reid/src/codegen/allocator.rs index df3ae1d..2598e49 100644 --- a/reid/src/codegen/allocator.rs +++ b/reid/src/codegen/allocator.rs @@ -133,7 +133,7 @@ impl mir::Expression { allocated.extend(expr.allocate(scope)); allocated.extend(idx.allocate(scope)); } - mir::ExprKind::Accessed(expression, _, _) => { + mir::ExprKind::Accessed(expression, ..) => { allocated.extend(expression.allocate(scope)); } mir::ExprKind::Array(expressions) => { @@ -159,7 +159,7 @@ impl mir::Expression { .unwrap(); allocated.push(Allocation(self.1, ty, allocation)); - for (field_name, expression) in items { + for (field_name, expression, _) in items { allocated.extend(expression.allocate(scope)); let (_, ty) = expression.return_type(&Default::default(), scope.mod_id).unwrap(); diff --git a/reid/src/codegen/mod.rs b/reid/src/codegen/mod.rs index 2a1fa52..4262400 100644 --- a/reid/src/codegen/mod.rs +++ b/reid/src/codegen/mod.rs @@ -1160,7 +1160,7 @@ impl mir::Expression { TypeKind::Array(Box::new(elem_ty_kind), instr_list.len() as u64), )) } - mir::ExprKind::Accessed(expression, type_kind, field) => { + mir::ExprKind::Accessed(expression, type_kind, field, _) => { let struct_val = expression.codegen(scope, &state.load(false))?.unwrap(); let TypeKind::CodegenPtr(inner) = &struct_val.1 else { @@ -1222,7 +1222,7 @@ impl mir::Expression { .unwrap() .maybe_location(&mut scope.block, location.clone()); - for (field_n, exp) in items { + for (field_n, exp, _) in items { let gep_n = format!("{}.{}.gep", name, field_n); let store_n = format!("{}.{}.store", name, field_n); let i = indices.clone().find(|(_, f)| f.0 == *field_n).unwrap().0; diff --git a/reid/src/mir/fmt.rs b/reid/src/mir/fmt.rs index 5917790..966e7c6 100644 --- a/reid/src/mir/fmt.rs +++ b/reid/src/mir/fmt.rs @@ -279,9 +279,9 @@ impl Display for ExprKind { let mut state = Default::default(); let mut inner_f = PadAdapter::wrap(f, &mut state); let mut iter = items.iter(); - if let Some((name, expr)) = iter.next() { + if let Some((name, expr, _)) = iter.next() { write!(inner_f, "\n{}: {}", name, expr)?; - while let Some((name, expr)) = iter.next() { + while let Some((name, expr, _)) = iter.next() { writeln!(inner_f, ",")?; write!(inner_f, "{}: {}", name, expr)?; } @@ -289,7 +289,7 @@ impl Display for ExprKind { } f.write_char('}') } - ExprKind::Accessed(expression, type_kind, name) => { + ExprKind::Accessed(expression, type_kind, name, _) => { Display::fmt(&expression, f)?; write_access(f, name)?; write!(f, "<{}>", type_kind) diff --git a/reid/src/mir/implement.rs b/reid/src/mir/implement.rs index bcb8c43..0e8daa8 100644 --- a/reid/src/mir/implement.rs +++ b/reid/src/mir/implement.rs @@ -405,7 +405,7 @@ impl Expression { TypeKind::Array(Box::new(first.1), expressions.len() as u64), )) } - Accessed(_, type_kind, _) => Ok((ReturnKind::Soft, type_kind.clone())), + Accessed(_, type_kind, ..) => Ok((ReturnKind::Soft, type_kind.clone())), Struct(name, _) => Ok(( ReturnKind::Soft, TypeKind::CustomType(CustomTypeKey(name.clone(), mod_id)), @@ -437,7 +437,7 @@ impl Expression { match &self.0 { ExprKind::Variable(var_ref) => Some(var_ref), ExprKind::Indexed(lhs, _, _) => lhs.backing_var(), - ExprKind::Accessed(lhs, _, _) => lhs.backing_var(), + ExprKind::Accessed(lhs, ..) => lhs.backing_var(), ExprKind::Borrow(expr, _) => expr.backing_var(), ExprKind::Deref(expr) => expr.backing_var(), ExprKind::Block(block) => block.backing_var(), diff --git a/reid/src/mir/linker.rs b/reid/src/mir/linker.rs index eb5aeb5..1b4c992 100644 --- a/reid/src/mir/linker.rs +++ b/reid/src/mir/linker.rs @@ -459,7 +459,7 @@ impl<'map> Pass for LinkerPass<'map> { super::ExprKind::Indexed(.., type_kind, _) => { *type_kind = type_kind.update_imported(extern_types, mod_id) } - super::ExprKind::Accessed(.., type_kind, _) => { + super::ExprKind::Accessed(.., type_kind, _, _) => { *type_kind = type_kind.update_imported(extern_types, mod_id) } super::ExprKind::BinOp(.., type_kind) => *type_kind = type_kind.update_imported(extern_types, mod_id), diff --git a/reid/src/mir/mod.rs b/reid/src/mir/mod.rs index c061722..094e0ef 100644 --- a/reid/src/mir/mod.rs +++ b/reid/src/mir/mod.rs @@ -262,9 +262,9 @@ pub struct Import(pub Vec, pub Metadata); pub enum ExprKind { Variable(NamedVariableRef), Indexed(Box, TypeKind, Box), - Accessed(Box, TypeKind, String), + Accessed(Box, TypeKind, String, Metadata), Array(Vec), - Struct(String, Vec<(String, Expression)>), + Struct(String, Vec<(String, Expression, Metadata)>), Literal(Literal), BinOp(BinaryOperator, Box, Box, TypeKind), FunctionCall(FunctionCall), diff --git a/reid/src/mir/pass.rs b/reid/src/mir/pass.rs index 8d2ce5d..57fff34 100644 --- a/reid/src/mir/pass.rs +++ b/reid/src/mir/pass.rs @@ -585,7 +585,7 @@ impl Expression { } } ExprKind::Struct(_, items) => { - for (_, expr) in items { + for (_, expr, _) in items { expr.pass(pass, state, scope, mod_id)?; } } diff --git a/reid/src/mir/typecheck/typecheck.rs b/reid/src/mir/typecheck/typecheck.rs index a7c1c6b..67dbc29 100644 --- a/reid/src/mir/typecheck/typecheck.rs +++ b/reid/src/mir/typecheck/typecheck.rs @@ -596,7 +596,7 @@ impl Expression { } } } - ExprKind::Accessed(expression, type_kind, field_name) => { + ExprKind::Accessed(expression, type_kind, field_name, _) => { // Resolve expected type let expected_ty = type_kind.resolve_ref(typerefs); @@ -640,7 +640,7 @@ impl Expression { HashSet::new() }; - for (field_name, field_expr) in items { + for (field_name, field_expr, _) in items { // Get expected type, or error if field does not exist let expected_ty = state.or_else( struct_def diff --git a/reid/src/mir/typecheck/typeinference.rs b/reid/src/mir/typecheck/typeinference.rs index b602575..c14baf0 100644 --- a/reid/src/mir/typecheck/typeinference.rs +++ b/reid/src/mir/typecheck/typeinference.rs @@ -526,7 +526,7 @@ impl Expression { } } } - ExprKind::Accessed(expression, type_kind, field_name) => { + ExprKind::Accessed(expression, type_kind, field_name, _) => { let expr_ty = expression.infer_types(state, type_refs)?; // Check that the resolved type is at least a struct, no