From acd74d57ff90aeb65cf7bcc05caf451ce4284a03 Mon Sep 17 00:00:00 2001 From: bQUARKz Date: Wed, 4 Feb 2026 20:09:44 +0000 Subject: [PATCH] pr 05.e --- .../src/frontends/pbs/resolver.rs | 197 +++++++++++++++--- test-cartridges/canonical/golden/program.pbc | Bin 3727 -> 3727 bytes 2 files changed, 173 insertions(+), 24 deletions(-) diff --git a/crates/prometeu-compiler/src/frontends/pbs/resolver.rs b/crates/prometeu-compiler/src/frontends/pbs/resolver.rs index aee051e4..e73f0261 100644 --- a/crates/prometeu-compiler/src/frontends/pbs/resolver.rs +++ b/crates/prometeu-compiler/src/frontends/pbs/resolver.rs @@ -1,3 +1,4 @@ +use crate::analysis::symbols::{SymbolArena, SymbolId, NodeToSymbol}; use crate::analysis::types::{TypeArena, TypeFacts, TypeId, TypeKind}; use crate::common::diagnostics::{Diagnostic, DiagnosticBundle, DiagnosticLevel}; use crate::common::spans::Span; @@ -14,11 +15,13 @@ pub struct Resolver<'a> { interner: &'a NameInterner, module_provider: &'a dyn ModuleProvider, current_module: &'a ModuleSymbols, - scopes: Vec>, + scopes: Vec)>>, pub imported_symbols: ModuleSymbols, diagnostics: Vec, pub type_arena: TypeArena, pub type_facts: TypeFacts, + pub symbol_arena: crate::analysis::symbols::SymbolArena, + pub node_to_symbol: crate::analysis::symbols::NodeToSymbol, primitives: HashMap, } @@ -37,6 +40,8 @@ impl<'a> Resolver<'a> { diagnostics: Vec::new(), type_arena: TypeArena::new(), type_facts: TypeFacts::new(), + symbol_arena: SymbolArena::new(), + node_to_symbol: NodeToSymbol::new(), primitives: HashMap::new(), } } @@ -152,7 +157,13 @@ impl<'a> Resolver<'a> { NodeKind::Call(n) => { if let NodeKind::Ident(id) = arena.kind(n.callee) { if !self.is_builtin(id.name, Namespace::Value) { - let value_sym = self.lookup_identifier(id.name, Namespace::Value); + let (value_sym, sym_id) = match self.lookup_with_id(id.name, Namespace::Value) { + Some((sym, id)) => (Some(sym), id), + None => (None, None), + }; + if let Some(sid) = sym_id { + self.node_to_symbol.bind_node(n.callee, sid); + } if value_sym.is_none() && self.lookup_identifier(id.name, Namespace::Type).is_none() { // TODO: Resolver for v0 allows unresolved call targets (e.g. constructors via prelude) } @@ -304,10 +315,14 @@ impl<'a> Resolver<'a> { } } NodeKind::Ident(n) => { - let _sym = self.resolve_identifier(n.name, arena.span(node), Namespace::Value); - // For v0 bootstrap, if we found a local variable, we don't know its type yet (no inference) - // but if we had a way to track symbol types, we'd use it here. - // For now, we only type literals and simple operators. + if let Some((_sym, Some(sym_id))) = self.lookup_with_id(n.name, Namespace::Value) { + self.node_to_symbol.bind_node(node, sym_id); + if let Some(ty) = self.type_facts.get_symbol_type(sym_id) { + self.type_facts.set_node_type(node, ty); + } + } else { + self.resolve_identifier(n.name, arena.span(node), Namespace::Value); + } } NodeKind::IntLit(_) => { if let Some(id) = self.primitives.get("int") { @@ -353,8 +368,14 @@ impl<'a> Resolver<'a> { fn resolve_fn_decl(&mut self, arena: &AstArena, _id: NodeId, n: &FnDeclNodeArena) { self.enter_scope(); for param in &n.params { - self.resolve_type_ref(arena, param.ty); - self.define_local(param.name, param.span, SymbolKind::Local); + let ty_id = self.resolve_type_ref(arena, param.ty); + let sym_id = self.define_local(param.name, param.span, SymbolKind::Local); + if let (Some(tid), Some(sid)) = (ty_id, sym_id) { + self.type_facts.set_symbol_type(sid, tid); + // O node do Ident do parâmetro na declaração também pode ser vinculado + // Mas o ParamNodeArena não tem um NodeId direto no AST que represente o Ident do parâmetro. + // O `param.name` é NameId. + } } if let Some(ret) = n.ret { self.resolve_type_ref(arena, ret); @@ -440,15 +461,29 @@ impl<'a> Resolver<'a> { } fn resolve_let_stmt(&mut self, arena: &AstArena, id: NodeId, n: &LetStmtNodeArena) { - if let Some(ty) = n.ty { - self.resolve_type_ref(arena, ty); - } + let ty_id = if let Some(ty) = n.ty { + self.resolve_type_ref(arena, ty) + } else { + None + }; self.resolve_node(arena, n.init); - self.define_local(n.name, arena.span(id), SymbolKind::Local); + let sym_id = self.define_local(n.name, arena.span(id), SymbolKind::Local); + + if let (Some(tid), Some(sid)) = (ty_id, sym_id) { + self.type_facts.set_symbol_type(sid, tid); + } } - fn resolve_type_ref(&mut self, arena: &AstArena, node: NodeId) { + fn resolve_type_ref(&mut self, arena: &AstArena, node: NodeId) -> Option { self.resolve_node(arena, node); + + match arena.kind(node) { + NodeKind::TypeName(n) => { + let name = self.interner.resolve(n.name); + self.primitives.get(name).copied() + } + _ => None, + } } fn resolve_identifier(&mut self, name: NameId, span: Span, namespace: Namespace) -> Option { @@ -489,11 +524,15 @@ impl<'a> Resolver<'a> { } fn lookup_identifier(&self, name: NameId, namespace: Namespace) -> Option { + self.lookup_with_id(name, namespace).map(|(sym, _)| sym) + } + + fn lookup_with_id(&self, name: NameId, namespace: Namespace) -> Option<(Symbol, Option)> { // 1. local bindings if namespace == Namespace::Value { for scope in self.scopes.iter().rev() { - if let Some(sym) = scope.get(&name) { - return Some(sym.clone()); + if let Some(pair) = scope.get(&name) { + return Some(pair.clone()); } } } @@ -506,7 +545,7 @@ impl<'a> Resolver<'a> { // 2 & 3. file-private and module symbols if let Some(sym) = table.get(name) { - return Some(sym.clone()); + return Some((sym.clone(), None)); } // 4. imported symbols @@ -516,19 +555,19 @@ impl<'a> Resolver<'a> { &self.imported_symbols.value_symbols }; if let Some(sym) = imp_table.get(name) { - return Some(sym.clone()); + return Some((sym.clone(), None)); } // 5. Fallback for constructor calls: check Type namespace if looking for a Value if namespace == Namespace::Value { if let Some(sym) = self.current_module.type_symbols.get(name) { if sym.kind == SymbolKind::Struct { - return Some(sym.clone()); + return Some((sym.clone(), None)); } } if let Some(sym) = self.imported_symbols.type_symbols.get(name) { if sym.kind == SymbolKind::Struct { - return Some(sym.clone()); + return Some((sym.clone(), None)); } } } @@ -536,7 +575,7 @@ impl<'a> Resolver<'a> { None } - fn define_local(&mut self, name: NameId, span: Span, kind: SymbolKind) { + fn define_local(&mut self, name: NameId, span: Span, kind: SymbolKind) -> Option { let scope = self.scopes.last_mut().expect("No scope to define local"); // Check for collision in Type namespace at top-level? @@ -552,7 +591,7 @@ impl<'a> Resolver<'a> { ), span: Some(span), }); - return; + return None; } if scope.contains_key(&name) { @@ -562,8 +601,9 @@ impl<'a> Resolver<'a> { message: format!("Duplicate local variable '{}'", self.interner.resolve(name)), span: Some(span), }); + None } else { - scope.insert(name, Symbol { + let symbol = Symbol { name, kind, namespace: Namespace::Value, @@ -572,7 +612,22 @@ impl<'a> Resolver<'a> { is_host: false, span, origin: None, + }; + + // Criar símbolo na symbol_arena (análise global) + let sym_id = self.symbol_arena.insert(crate::analysis::symbols::Symbol { + name, + kind: match kind { + SymbolKind::Local => crate::analysis::symbols::SymbolKind::Local, + _ => crate::analysis::symbols::SymbolKind::Value, + }, + exported: false, + module: 0, // TODO + decl_span: span, }); + + scope.insert(name, (symbol, Some(sym_id))); + Some(sym_id) } } @@ -626,7 +681,6 @@ mod tests { fn setup_test(source: &str) -> (ParsedAst, usize, NameInterner) { let mut fm = FileManager::new(); let file_id = fm.add(PathBuf::from("test.pbs"), source.to_string()); - let mut interner = fm.interner().clone(); let mut parser = parser::Parser::new(source, file_id, fm.interner_mut()); let parsed = parser.parse_file().expect("Parsing failed"); (parsed, file_id, fm.interner().clone()) @@ -842,7 +896,7 @@ mod tests { let c = -1; } "; - let (parsed, _, mut interner) = setup_test(source); + let (parsed, _, interner) = setup_test(source); let mut collector = SymbolCollector::new(&interner); let (ts, vs) = collector.collect(&parsed.arena, parsed.root).unwrap(); let ms = ModuleSymbols { type_symbols: ts, value_symbols: vs }; @@ -892,4 +946,99 @@ mod tests { assert!(found_b, "Binary == node not found"); assert!(found_c, "Unary - node not found"); } + + #[test] + fn test_hover_let_annotated_type() { + let source = " + fn main() { + let x: int = 10; + let y = x; + } + "; + let (parsed, _, interner) = setup_test(source); + let mut collector = SymbolCollector::new(&interner); + let (ts, vs) = collector.collect(&parsed.arena, parsed.root).unwrap(); + let ms = ModuleSymbols { type_symbols: ts, value_symbols: vs }; + + struct EmptyProvider; + impl ModuleProvider for EmptyProvider { + fn get_module_symbols(&self, _path: &str) -> Option<&ModuleSymbols> { None } + } + + let mut interner_for_bootstrap = interner.clone(); + let mut resolver = Resolver::new(&ms, &EmptyProvider, &interner); + resolver.bootstrap_types(&mut interner_for_bootstrap); + resolver.resolve(&parsed.arena, parsed.root).expect("Resolution failed"); + + use crate::analysis::types::format_type; + + let mut found_y_ref = false; + + for i in 0..parsed.arena.nodes.len() { + let id = NodeId(i as u32); + let kind = parsed.arena.kind(id); + + if let NodeKind::LetStmt(n) = kind { + if interner.resolve(n.name) == "y" { + let init_id = n.init; + if let NodeKind::Ident(ident) = parsed.arena.kind(init_id) { + if interner.resolve(ident.name) == "x" { + let ty = resolver.type_facts.get_node_type(init_id).expect("Ident x should have type"); + assert_eq!(format_type(ty, &resolver.type_arena, &interner_for_bootstrap, None), "int"); + found_y_ref = true; + } + } + } + } + } + + assert!(found_y_ref, "Reference to x in let y = x not found or not typed"); + } + + #[test] + fn test_hover_param_type() { + let source = " + fn foo(a: int) { + let b = a; + } + "; + let (parsed, _, interner) = setup_test(source); + let mut collector = SymbolCollector::new(&interner); + let (ts, vs) = collector.collect(&parsed.arena, parsed.root).unwrap(); + let ms = ModuleSymbols { type_symbols: ts, value_symbols: vs }; + + struct EmptyProvider; + impl ModuleProvider for EmptyProvider { + fn get_module_symbols(&self, _path: &str) -> Option<&ModuleSymbols> { None } + } + + let mut interner_for_bootstrap = interner.clone(); + let mut resolver = Resolver::new(&ms, &EmptyProvider, &interner); + resolver.bootstrap_types(&mut interner_for_bootstrap); + resolver.resolve(&parsed.arena, parsed.root).expect("Resolution failed"); + + use crate::analysis::types::format_type; + + let mut found_a_ref = false; + + for i in 0..parsed.arena.nodes.len() { + let id = NodeId(i as u32); + let kind = parsed.arena.kind(id); + + if let NodeKind::LetStmt(n) = kind { + if interner.resolve(n.name) == "b" { + let init_id = n.init; + if let NodeKind::Ident(ident) = parsed.arena.kind(init_id) { + if interner.resolve(ident.name) == "a" { + let ty = resolver.type_facts.get_node_type(init_id).expect("Ident a should have type"); + assert_eq!(format_type(ty, &resolver.type_arena, &interner_for_bootstrap, None), "int"); + found_a_ref = true; + } + } + } + } + } + + assert!(found_a_ref, "Reference to a in let b = a not found or not typed"); + } } diff --git a/test-cartridges/canonical/golden/program.pbc b/test-cartridges/canonical/golden/program.pbc index 666448e9c82fd9759bc1514ce6c916eaa9193fac..b06b91caaacaf4416129e782584fa51dc847ec21 100644 GIT binary patch delta 47 wcmeB|?U&tadA