diff --git a/crates/prometeu-compiler/src/building/output.rs b/crates/prometeu-compiler/src/building/output.rs index 9a151b54..d6d2b46b 100644 --- a/crates/prometeu-compiler/src/building/output.rs +++ b/crates/prometeu-compiler/src/building/output.rs @@ -245,7 +245,13 @@ pub fn compile_project( for (module_path, parsed) in &parsed_files { let ms = module_symbols_map.get(module_path).unwrap(); + // Ensure primitive names are interned before creating resolver/bootstrap + { + let primitives = ["int", "bool", "float", "string", "bounded", "void"]; + for p in primitives { interner.intern(p); } + } let mut resolver = Resolver::new(ms, &module_provider, &interner); + resolver.bootstrap_types(&interner); resolver.resolve(&parsed.arena, parsed.root)?; // Capture imported symbols diff --git a/crates/prometeu-compiler/src/frontends/pbs/mod.rs b/crates/prometeu-compiler/src/frontends/pbs/mod.rs index 3fa6db85..df9f5ea4 100644 --- a/crates/prometeu-compiler/src/frontends/pbs/mod.rs +++ b/crates/prometeu-compiler/src/frontends/pbs/mod.rs @@ -60,8 +60,14 @@ impl Frontend for PbsFrontend { let mut resolver = Resolver::new(&module_symbols, &EmptyProvider, &interner); // Step 3: Resolve and type expressions - let mut interner_mut = file_manager.interner_mut(); - resolver.bootstrap_types(&mut interner_mut); + // Ensure primitives are interned in the shared FileManager interner + { + let inter = file_manager.interner_mut(); + let primitives = ["int", "bool", "float", "string", "bounded", "void"]; + for p in primitives { inter.intern(p); } + } + let inter_ro = file_manager.interner(); + resolver.bootstrap_types(inter_ro); resolver.resolve(&parsed.arena, parsed.root)?; let imported_symbols = resolver.imported_symbols; diff --git a/crates/prometeu-compiler/src/frontends/pbs/resolver.rs b/crates/prometeu-compiler/src/frontends/pbs/resolver.rs index e73f0261..e9c54d1e 100644 --- a/crates/prometeu-compiler/src/frontends/pbs/resolver.rs +++ b/crates/prometeu-compiler/src/frontends/pbs/resolver.rs @@ -46,10 +46,10 @@ impl<'a> Resolver<'a> { } } - pub fn bootstrap_types(&mut self, interner: &mut NameInterner) { + pub fn bootstrap_types(&mut self, interner: &NameInterner) { let primitive_names = ["int", "bool", "float", "string", "bounded", "void"]; for name in primitive_names { - let name_id = interner.intern(name); + let name_id = interner.get(name).expect("primitive name not interned"); let type_id = self.type_arena.intern_type(TypeKind::Primitive { name: name_id }); self.primitives.insert(name.to_string(), type_id); } @@ -66,6 +66,40 @@ impl<'a> Resolver<'a> { } }; + // Step 0: Populate symbol_arena with top-level symbols for global lookup + for (name, sym) in &self.current_module.type_symbols.symbols { + self.symbol_arena.insert(crate::analysis::symbols::Symbol { + name: *name, + kind: match sym.kind { + SymbolKind::Function => crate::analysis::symbols::SymbolKind::Function, + SymbolKind::Service => crate::analysis::symbols::SymbolKind::Service, + SymbolKind::Struct => crate::analysis::symbols::SymbolKind::Struct, + SymbolKind::Contract => crate::analysis::symbols::SymbolKind::Contract, + SymbolKind::ErrorType => crate::analysis::symbols::SymbolKind::ErrorType, + SymbolKind::Local => crate::analysis::symbols::SymbolKind::Local, + }, + exported: sym.visibility == Visibility::Pub, + module: 0, + decl_span: sym.span, + }); + } + for (name, sym) in &self.current_module.value_symbols.symbols { + self.symbol_arena.insert(crate::analysis::symbols::Symbol { + name: *name, + kind: match sym.kind { + SymbolKind::Function => crate::analysis::symbols::SymbolKind::Function, + SymbolKind::Service => crate::analysis::symbols::SymbolKind::Service, + SymbolKind::Struct => crate::analysis::symbols::SymbolKind::Struct, + SymbolKind::Contract => crate::analysis::symbols::SymbolKind::Contract, + SymbolKind::ErrorType => crate::analysis::symbols::SymbolKind::ErrorType, + SymbolKind::Local => crate::analysis::symbols::SymbolKind::Local, + }, + exported: sym.visibility == Visibility::Pub, + module: 0, + decl_span: sym.span, + }); + } + // Step 1: Process imports to populate imported_symbols for imp in &file.imports { if let NodeKind::Import(imp_node) = arena.kind(*imp) { @@ -73,6 +107,40 @@ impl<'a> Resolver<'a> { } } + // Add imported symbols to symbol_arena too + for (name, sym) in &self.imported_symbols.type_symbols.symbols { + self.symbol_arena.insert(crate::analysis::symbols::Symbol { + name: *name, + kind: match sym.kind { + SymbolKind::Function => crate::analysis::symbols::SymbolKind::Function, + SymbolKind::Service => crate::analysis::symbols::SymbolKind::Service, + SymbolKind::Struct => crate::analysis::symbols::SymbolKind::Struct, + SymbolKind::Contract => crate::analysis::symbols::SymbolKind::Contract, + SymbolKind::ErrorType => crate::analysis::symbols::SymbolKind::ErrorType, + SymbolKind::Local => crate::analysis::symbols::SymbolKind::Local, + }, + exported: sym.visibility == Visibility::Pub, + module: 0, // Should be target module + decl_span: sym.span, + }); + } + for (name, sym) in &self.imported_symbols.value_symbols.symbols { + self.symbol_arena.insert(crate::analysis::symbols::Symbol { + name: *name, + kind: match sym.kind { + SymbolKind::Function => crate::analysis::symbols::SymbolKind::Function, + SymbolKind::Service => crate::analysis::symbols::SymbolKind::Service, + SymbolKind::Struct => crate::analysis::symbols::SymbolKind::Struct, + SymbolKind::Contract => crate::analysis::symbols::SymbolKind::Contract, + SymbolKind::ErrorType => crate::analysis::symbols::SymbolKind::ErrorType, + SymbolKind::Local => crate::analysis::symbols::SymbolKind::Local, + }, + exported: sym.visibility == Visibility::Pub, + module: 0, // Should be target module + decl_span: sym.span, + }); + } + // Step 2: Resolve all top-level declarations for decl in &file.decls { self.resolve_node(arena, *decl); @@ -260,14 +328,8 @@ impl<'a> Resolver<'a> { _ => {} } } - NodeKind::TypeName(n) => { - self.resolve_identifier(n.name, arena.span(node), Namespace::Type); - } - NodeKind::TypeApp(n) => { - self.resolve_identifier(n.base, arena.span(node), Namespace::Type); - for arg in &n.args { - self.resolve_type_ref(arena, *arg); - } + NodeKind::TypeName(_) | NodeKind::TypeApp(_) => { + self.resolve_type_ref(arena, node); } NodeKind::ConstructorDecl(n) => self.resolve_constructor_decl(arena, node, n), NodeKind::ConstantDecl(n) => self.resolve_node(arena, n.value), @@ -469,20 +531,134 @@ impl<'a> Resolver<'a> { self.resolve_node(arena, n.init); 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); + if let Some(sid) = sym_id { + self.node_to_symbol.bind_node(id, sid); + if let Some(tid) = ty_id { + self.type_facts.set_symbol_type(sid, tid); + } } } fn resolve_type_ref(&mut self, arena: &AstArena, node: NodeId) -> Option { - self.resolve_node(arena, node); - + let type_id = self.lower_type_node(arena, node); + if let Some(tid) = type_id { + self.type_facts.set_node_type(node, tid); + } + type_id + } + + fn lower_type_node(&mut self, arena: &AstArena, node: NodeId) -> Option { match arena.kind(node) { NodeKind::TypeName(n) => { let name = self.interner.resolve(n.name); - self.primitives.get(name).copied() + if let Some(prim) = self.primitives.get(name) { + return Some(*prim); + } + + // Resolve struct/type symbol + if let Some((_sym, sym_id)) = self.lookup_with_id(n.name, Namespace::Type) { + // Try to find if this symbol is a type symbol that can be converted to TypeId + // For now, we only have TypeKind::Struct + if let Some(sid) = sym_id { + let kind = TypeKind::Struct { sym: sid }; + return Some(self.type_arena.intern_type(kind)); + } else { + // sym_id is None, but _sym exists. This means it's a built-in or something not in analysis arena yet. + // But for Struct resolution we need a SymbolId. + // If it's a built-in it should have been handled by self.primitives. + } + } + + // If not found in current or imports, maybe it's a symbol from another module not yet in SymbolArena? + // Actually, lookup_with_id checks imported_symbols too. + + self.diagnostics.push(Diagnostic { + level: DiagnosticLevel::Error, + code: Some("E_TYPE_UNKNOWN_TYPE".to_string()), + message: format!("Unknown type: {}", name), + span: Some(arena.span(node)), + }); + None + } + NodeKind::TypeApp(n) => { + let base_name = self.interner.resolve(n.base); + match base_name { + "optional" => { + if n.args.len() != 1 { + self.diagnostics.push(Diagnostic { + level: DiagnosticLevel::Error, + code: Some("E_TYPE_INVALID_ARGS".to_string()), + message: "optional expects exactly 1 argument".to_string(), + span: Some(arena.span(node)), + }); + return None; + } + let inner = self.lower_type_node(arena, n.args[0])?; + Some(self.type_arena.intern_type(TypeKind::Optional { inner })) + } + "result" => { + if n.args.len() != 2 { + self.diagnostics.push(Diagnostic { + level: DiagnosticLevel::Error, + code: Some("E_TYPE_INVALID_ARGS".to_string()), + message: "result expects exactly 2 arguments".to_string(), + span: Some(arena.span(node)), + }); + return None; + } + let ok = self.lower_type_node(arena, n.args[0])?; + let err = self.lower_type_node(arena, n.args[1])?; + Some(self.type_arena.intern_type(TypeKind::Result { ok, err })) + } + "array" => { + if n.args.len() < 1 || n.args.len() > 2 { + self.diagnostics.push(Diagnostic { + level: DiagnosticLevel::Error, + code: Some("E_TYPE_INVALID_ARGS".to_string()), + message: "array or array[N] expects 1 or 2 arguments".to_string(), + span: Some(arena.span(node)), + }); + return None; + } + let inner = self.lower_type_node(arena, n.args[0])?; + let len = if n.args.len() == 2 { + match arena.kind(n.args[1]) { + NodeKind::IntLit(lit) => Some(lit.value as u32), + _ => { + self.diagnostics.push(Diagnostic { + level: DiagnosticLevel::Error, + code: Some("E_TYPE_INVALID_ARGS".to_string()), + message: "Array length must be an integer literal".to_string(), + span: Some(arena.span(n.args[1])), + }); + None + } + } + } else { + None + }; + Some(self.type_arena.intern_type(TypeKind::Array { inner, len })) + } + _ => { + self.diagnostics.push(Diagnostic { + level: DiagnosticLevel::Error, + code: Some("E_TYPE_UNKNOWN_TYPE".to_string()), + message: format!("Unknown generic type: {}", base_name), + span: Some(arena.span(node)), + }); + None + } + } + } + _ => { + self.diagnostics.push(Diagnostic { + level: DiagnosticLevel::Error, + code: Some("E_TYPE_NOT_A_TYPE".to_string()), + message: "Expected a type node".to_string(), + span: Some(arena.span(node)), + }); + None } - _ => None, } } @@ -545,7 +721,19 @@ impl<'a> Resolver<'a> { // 2 & 3. file-private and module symbols if let Some(sym) = table.get(name) { - return Some((sym.clone(), None)); + // Se encontrarmos no módulo atual, tentamos achar o SymbolId correspondente na symbol_arena + let sym_id = self.symbol_arena.symbols.iter().enumerate().find(|(_, s)| { + s.name == sym.name && s.kind == match sym.kind { + SymbolKind::Function => crate::analysis::symbols::SymbolKind::Function, + SymbolKind::Service => crate::analysis::symbols::SymbolKind::Service, + SymbolKind::Struct => crate::analysis::symbols::SymbolKind::Struct, + SymbolKind::Contract => crate::analysis::symbols::SymbolKind::Contract, + SymbolKind::ErrorType => crate::analysis::symbols::SymbolKind::ErrorType, + SymbolKind::Local => crate::analysis::symbols::SymbolKind::Local, + } + }).map(|(i, _)| SymbolId(i as u32)); + + return Some((sym.clone(), sym_id)); } // 4. imported symbols @@ -555,7 +743,18 @@ impl<'a> Resolver<'a> { &self.imported_symbols.value_symbols }; if let Some(sym) = imp_table.get(name) { - return Some((sym.clone(), None)); + let sym_id = self.symbol_arena.symbols.iter().enumerate().find(|(_, s)| { + s.name == sym.name && s.kind == match sym.kind { + SymbolKind::Function => crate::analysis::symbols::SymbolKind::Function, + SymbolKind::Service => crate::analysis::symbols::SymbolKind::Service, + SymbolKind::Struct => crate::analysis::symbols::SymbolKind::Struct, + SymbolKind::Contract => crate::analysis::symbols::SymbolKind::Contract, + SymbolKind::ErrorType => crate::analysis::symbols::SymbolKind::ErrorType, + SymbolKind::Local => crate::analysis::symbols::SymbolKind::Local, + } + }).map(|(i, _)| SymbolId(i as u32)); + + return Some((sym.clone(), sym_id)); } // 5. Fallback for constructor calls: check Type namespace if looking for a Value @@ -896,7 +1095,7 @@ mod tests { let c = -1; } "; - let (parsed, _, interner) = setup_test(source); + let (parsed, _, mut 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 }; @@ -906,9 +1105,11 @@ mod tests { fn get_module_symbols(&self, _path: &str) -> Option<&ModuleSymbols> { None } } - let mut interner_for_bootstrap = interner.clone(); + // Ensure primitives are interned for bootstrap + for p in ["int", "bool", "float", "string", "bounded", "void"] { interner.intern(p); } + let interner_for_bootstrap = interner.clone(); let mut resolver = Resolver::new(&ms, &EmptyProvider, &interner); - resolver.bootstrap_types(&mut interner_for_bootstrap); + resolver.bootstrap_types(&interner); resolver.resolve(&parsed.arena, parsed.root).expect("Resolution failed"); // Verify types in TypeFacts using format_type for easier assertion @@ -955,7 +1156,7 @@ mod tests { let y = x; } "; - let (parsed, _, interner) = setup_test(source); + let (parsed, _, mut 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 }; @@ -965,9 +1166,10 @@ mod tests { fn get_module_symbols(&self, _path: &str) -> Option<&ModuleSymbols> { None } } - let mut interner_for_bootstrap = interner.clone(); + for p in ["int", "bool", "float", "string", "bounded", "void"] { interner.intern(p); } + let interner_for_bootstrap = interner.clone(); let mut resolver = Resolver::new(&ms, &EmptyProvider, &interner); - resolver.bootstrap_types(&mut interner_for_bootstrap); + resolver.bootstrap_types(&interner); resolver.resolve(&parsed.arena, parsed.root).expect("Resolution failed"); use crate::analysis::types::format_type; @@ -1002,7 +1204,7 @@ mod tests { let b = a; } "; - let (parsed, _, interner) = setup_test(source); + let (parsed, _, mut 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 }; @@ -1012,9 +1214,10 @@ mod tests { fn get_module_symbols(&self, _path: &str) -> Option<&ModuleSymbols> { None } } - let mut interner_for_bootstrap = interner.clone(); + for p in ["int", "bool", "float", "string", "bounded", "void"] { interner.intern(p); } + let interner_for_bootstrap = interner.clone(); let mut resolver = Resolver::new(&ms, &EmptyProvider, &interner); - resolver.bootstrap_types(&mut interner_for_bootstrap); + resolver.bootstrap_types(&interner); resolver.resolve(&parsed.arena, parsed.root).expect("Resolution failed"); use crate::analysis::types::format_type; @@ -1041,4 +1244,77 @@ mod tests { assert!(found_a_ref, "Reference to a in let b = a not found or not typed"); } + + #[test] + fn test_lower_type_node_complex() { + let source = " + declare struct MyType {} + fn main() { + let x: optional = 1; + let y: result = 2; + let z: array[10] = 3; + let w: MyType = 4; + } + "; + let (parsed, _, mut 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 } + } + + for p in ["int", "bool", "float", "string", "bounded", "void"] { interner.intern(p); } + let interner_for_bootstrap = interner.clone(); + let mut resolver = Resolver::new(&ms, &EmptyProvider, &interner); + resolver.bootstrap_types(&interner); + resolver.resolve(&parsed.arena, parsed.root).expect("Resolution failed"); + + use crate::analysis::types::format_type; + + let mut found_x = false; + let mut found_y = false; + let mut found_z = false; + let mut found_w = 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 { + let name = interner.resolve(n.name); + let sym_id = resolver.node_to_symbol.get(id).expect(&format!("Node {:?} should be bound to a symbol", kind)); + let ty_id = resolver.type_facts.get_symbol_type(sym_id).expect("Symbol should have type"); + + match name { + "x" => { + assert_eq!(format_type(ty_id, &resolver.type_arena, &interner_for_bootstrap, None), "optional"); + found_x = true; + } + "y" => { + assert_eq!(format_type(ty_id, &resolver.type_arena, &interner_for_bootstrap, None), "result"); + found_y = true; + } + "z" => { + assert_eq!(format_type(ty_id, &resolver.type_arena, &interner_for_bootstrap, None), "array[10]"); + found_z = true; + } + "w" => { + // MyType is a struct. Since we don't pass symbols to format_type in this test, it should be struct#ID + let formatted = format_type(ty_id, &resolver.type_arena, &interner_for_bootstrap, None); + assert!(formatted.starts_with("struct#"), "Formatted type should be struct#ID, got {}", formatted); + found_w = true; + } + _ => {} + } + } + } + + assert!(found_x); + assert!(found_y); + assert!(found_z); + assert!(found_w); + } }