From 078b520c37aa30386926c5eaca5ba89a7252fc06 Mon Sep 17 00:00:00 2001 From: Michael Schimmel Date: Tue, 3 Mar 2026 15:51:47 +0100 Subject: [PATCH] Add type aliases for registries Introduces `GlobalFunctionRegistry` and `GlobalAnalyzedRegistry` type aliases to clarify the usage of `HashMap`s for storing global functions and their analyzed versions. This change also refactors the `LambdaCollector` and `Optimizer` to use these new aliases, improving code readability and maintainability. --- src/ast/compiler/bound_nodes.rs | 6 ++ src/ast/compiler/lambda_collector.rs | 9 +- src/ast/compiler/optimizer/engine.rs | 8 +- src/ast/compiler/specializer.rs | 6 +- src/ast/compiler/type_checker.rs | 122 +++++++++++++-------------- src/ast/environment.rs | 25 +++--- 6 files changed, 94 insertions(+), 82 deletions(-) diff --git a/src/ast/compiler/bound_nodes.rs b/src/ast/compiler/bound_nodes.rs index e7fbae9..e6e96a1 100644 --- a/src/ast/compiler/bound_nodes.rs +++ b/src/ast/compiler/bound_nodes.rs @@ -60,6 +60,9 @@ pub type BoundNode = Node, T>; /// Type alias for a node that has been fully type-checked. pub type TypedNode = BoundNode; +/// Type alias for the global function registry. +pub type GlobalFunctionRegistry = std::collections::HashMap>; + /// Metrics collected during the analysis phase. #[derive(Debug, Clone, PartialEq)] pub struct NodeMetrics { @@ -71,6 +74,9 @@ pub struct NodeMetrics { /// Type alias for a node that has been analyzed. pub type AnalyzedNode = BoundNode; +/// Type alias for the global analyzed function registry. +pub type GlobalAnalyzedRegistry = std::collections::HashMap>; + #[derive(Debug, Clone)] pub enum BoundKind { Nop, diff --git a/src/ast/compiler/lambda_collector.rs b/src/ast/compiler/lambda_collector.rs index ab97a16..41ad384 100644 --- a/src/ast/compiler/lambda_collector.rs +++ b/src/ast/compiler/lambda_collector.rs @@ -1,15 +1,16 @@ use crate::ast::compiler::bound_nodes::{Address, BoundKind, BoundNode, GlobalIdx}; use std::collections::HashMap; +use std::rc::Rc; /// A pass that collects all global function definitions (lambdas) into a registry. /// This allows the Specializer to retrieve the original AST of a function for monomorphization. pub struct LambdaCollector<'a, T> { - registry: &'a mut HashMap>, + registry: &'a mut HashMap>>, } impl<'a, T: Clone> LambdaCollector<'a, T> { /// Performs a full traversal of the AST and populates the provided registry. - pub fn collect(node: &BoundNode, registry: &'a mut HashMap>) { + pub fn collect(node: &BoundNode, registry: &'a mut HashMap>>) { let mut collector = Self { registry }; collector.visit(node); } @@ -32,7 +33,7 @@ impl<'a, T: Clone> LambdaCollector<'a, T> { if let BoundKind::Lambda { .. } = ¤t.kind { self.registry - .insert(*global_index, (*current).as_ref().clone()); + .insert(*global_index, Rc::new((**current).clone())); } } self.visit(value); @@ -48,7 +49,7 @@ impl<'a, T: Clone> LambdaCollector<'a, T> { if let BoundKind::Lambda { .. } = ¤t.kind { self.registry - .insert(*global_index, (*current).as_ref().clone()); + .insert(*global_index, Rc::new((**current).clone())); } } self.visit(value); diff --git a/src/ast/compiler/optimizer/engine.rs b/src/ast/compiler/optimizer/engine.rs index 4f240bd..006a7e4 100644 --- a/src/ast/compiler/optimizer/engine.rs +++ b/src/ast/compiler/optimizer/engine.rs @@ -1,4 +1,6 @@ -use crate::ast::compiler::bound_nodes::{Address, AnalyzedNode, BoundKind, GlobalIdx, UpvalueIdx}; +use crate::ast::compiler::bound_nodes::{ + Address, AnalyzedNode, BoundKind, GlobalAnalyzedRegistry, GlobalIdx, UpvalueIdx, +}; use crate::ast::nodes::Node; use crate::ast::types::{Purity, Value}; use crate::ast::vm::Closure; @@ -16,7 +18,7 @@ pub struct Optimizer { max_passes: usize, pub globals: Option>>>, pub global_purity: Option>>>, - pub lambda_registry: Option>>>, + pub lambda_registry: Option>>, } impl Optimizer { @@ -42,7 +44,7 @@ impl Optimizer { pub fn with_registry( mut self, - registry: Rc>>, + registry: Rc>, ) -> Self { self.lambda_registry = Some(registry); self diff --git a/src/ast/compiler/specializer.rs b/src/ast/compiler/specializer.rs index ab5983e..88d57e0 100644 --- a/src/ast/compiler/specializer.rs +++ b/src/ast/compiler/specializer.rs @@ -11,12 +11,12 @@ pub struct MonoCacheKey { pub arg_types: Vec, } -pub type CompileFunc = Rc Result<(Value, StaticType), String>>; +pub type CompileFunc = Rc, &[StaticType]) -> Result<(Value, StaticType), String>>; pub type RtlLookupFunc = Rc Option<(Value, StaticType)>>; pub trait FunctionRegistry { - fn resolve(&self, addr: Address) -> Option; - fn resolve_analyzed(&self, _addr: Address) -> Option { + fn resolve(&self, addr: Address) -> Option>; + fn resolve_analyzed(&self, _addr: Address) -> Option> { None } } diff --git a/src/ast/compiler/type_checker.rs b/src/ast/compiler/type_checker.rs index 369ff0c..678eba5 100644 --- a/src/ast/compiler/type_checker.rs +++ b/src/ast/compiler/type_checker.rs @@ -81,11 +81,11 @@ impl TypeChecker { pub fn check( &self, - node: BoundNode, + node: &BoundNode, arg_types: &[StaticType], diag: &mut Diagnostics, ) -> TypedNode { - match node.kind { + match &node.kind { BoundKind::Lambda { params, upvalues, @@ -94,7 +94,7 @@ impl TypeChecker { } => { // 1. Determine types of captured variables (Root lambdas have none) let mut upvalue_types = Vec::with_capacity(upvalues.len()); - for _ in &upvalues { + for _ in upvalues { upvalue_types.push(StaticType::Any); } @@ -111,14 +111,14 @@ impl TypeChecker { }; let params_typed = self.check_params( - params.as_ref().clone(), + params.as_ref(), &arg_tuple_ty, &mut lambda_ctx, diag, ); // 4. Check body with the new types - let body_typed = self.check_node((*body).clone(), &mut lambda_ctx, diag); + let body_typed = self.check_node(body, &mut lambda_ctx, diag); let ret_ty = body_typed.ty.clone(); // 5. Construct specialized function type @@ -130,12 +130,12 @@ impl TypeChecker { })); Node { - identity: node.identity, + identity: node.identity.clone(), kind: BoundKind::Lambda { params: Rc::new(params_typed), - upvalues, + upvalues: upvalues.clone(), body: Rc::new(body_typed), - positional_count, + positional_count: *positional_count, }, ty: fn_ty, } @@ -151,24 +151,24 @@ impl TypeChecker { ty: (), }), upvalues: vec![], - body: Rc::new(node), + body: Rc::new(node.clone()), positional_count: Some(0), }, ty: (), }; - self.check(virtual_lambda, &[], diag) + self.check(&virtual_lambda, &[], diag) } } } fn check_params( &self, - node: BoundNode, + node: &BoundNode, specialized_ty: &StaticType, ctx: &mut TypeContext, diag: &mut Diagnostics, ) -> TypedNode { - let (kind, ty) = match node.kind { + let (kind, ty) = match &node.kind { BoundKind::Define { name, addr, @@ -176,18 +176,18 @@ impl TypeChecker { captured_by, .. } => { - ctx.set_type(addr, specialized_ty.clone()); + ctx.set_type(*addr, specialized_ty.clone()); ( BoundKind::Define { - name, - addr, - kind: decl_kind, + name: name.clone(), + addr: *addr, + kind: *decl_kind, value: Box::new(Node { identity: node.identity.clone(), kind: BoundKind::Nop, ty: specialized_ty.clone(), }), - captured_by, + captured_by: captured_by.clone(), }, specialized_ty.clone(), ) @@ -202,7 +202,7 @@ impl TypeChecker { // or we could add a check here against existing type. ( BoundKind::Set { - addr, + addr: *addr, value: Box::new(Node { identity: node.identity.clone(), kind: BoundKind::Nop, @@ -230,7 +230,7 @@ impl TypeChecker { Some(node.identity.clone()), ); return Node { - identity: node.identity, + identity: node.identity.clone(), kind: BoundKind::Error, ty: StaticType::Error, }; @@ -240,11 +240,11 @@ impl TypeChecker { let mut typed_elements = Vec::new(); let mut elem_types = Vec::new(); - for (i, el) in elements.into_iter().enumerate() { + for (i, el) in elements.iter().enumerate() { let sub_ty = match specialized_ty { StaticType::Tuple(t) => t.get(i).cloned().unwrap_or(StaticType::Any), StaticType::Vector(inner, _) => (**inner).clone(), - StaticType::Matrix(inner, _) => (**inner).clone(), // Matrix flat iteration or row? Wait. Matrix destructuring logic is tricky. But for now let's focus on Record. + StaticType::Matrix(inner, _) => (**inner).clone(), StaticType::List(inner) => (**inner).clone(), StaticType::Record(layout) => layout .fields @@ -276,7 +276,7 @@ impl TypeChecker { }; Node { - identity: node.identity, + identity: node.identity.clone(), kind, ty, } @@ -284,16 +284,16 @@ impl TypeChecker { fn check_node( &self, - node: BoundNode, + node: &BoundNode, ctx: &mut TypeContext, diag: &mut Diagnostics, ) -> TypedNode { - let (kind, ty) = match node.kind { + let (kind, ty) = match &node.kind { BoundKind::Nop => (BoundKind::Nop, StaticType::Void), BoundKind::Constant(v) => { let ty = v.static_type(); - (BoundKind::Constant(v), ty) + (BoundKind::Constant(v.clone()), ty) } BoundKind::Define { @@ -303,27 +303,27 @@ impl TypeChecker { value, captured_by, } => { - let val_typed = self.check_node(*value, ctx, diag); + let val_typed = self.check_node(value, ctx, diag); let ty = val_typed.ty.clone(); - ctx.set_type(addr, ty.clone()); + ctx.set_type(*addr, ty.clone()); ( BoundKind::Define { name: name.clone(), - addr, - kind: decl_kind, + addr: *addr, + kind: *decl_kind, value: Box::new(val_typed), - captured_by, + captured_by: captured_by.clone(), }, ty, ) } BoundKind::Get { addr, name } => { - let ty = ctx.get_type(addr); + let ty = ctx.get_type(*addr); ( BoundKind::Get { - addr, + addr: *addr, name: name.clone(), }, ty, @@ -331,14 +331,14 @@ impl TypeChecker { } BoundKind::FieldAccessor(k) => { - (BoundKind::FieldAccessor(k), StaticType::FieldAccessor(k)) + (BoundKind::FieldAccessor(*k), StaticType::FieldAccessor(*k)) } BoundKind::GetField { rec, field } => { - let rec_typed = self.check_node(*rec, ctx, diag); + let rec_typed = self.check_node(rec, ctx, diag); let field_ty = match &rec_typed.ty { StaticType::Record(layout) => { - if let Some(idx) = layout.index_of(field) { + if let Some(idx) = layout.index_of(*field) { layout.fields[idx].1.clone() } else { diag.push_error( @@ -365,20 +365,20 @@ impl TypeChecker { ( BoundKind::GetField { rec: Box::new(rec_typed), - field, + field: *field, }, field_ty, ) } BoundKind::Set { addr, value } => { - let val_typed = self.check_node(*value, ctx, diag); + let val_typed = self.check_node(value, ctx, diag); let ty = val_typed.ty.clone(); - ctx.set_type(addr, ty.clone()); + ctx.set_type(*addr, ty.clone()); ( BoundKind::Set { - addr, + addr: *addr, value: Box::new(val_typed), }, ty, @@ -386,8 +386,8 @@ impl TypeChecker { } BoundKind::Destructure { pattern, value } => { - let val_typed = self.check_node(*value, ctx, diag); - let pat_typed = self.check_params(*pattern, &val_typed.ty, ctx, diag); + let val_typed = self.check_node(value, ctx, diag); + let pat_typed = self.check_params(pattern, &val_typed.ty, ctx, diag); let ty = val_typed.ty.clone(); ( BoundKind::Destructure { @@ -403,14 +403,14 @@ impl TypeChecker { then_br, else_br, } => { - let cond_typed = self.check_node(*cond, ctx, diag); - let then_typed = self.check_node(*then_br, ctx, diag); + let cond_typed = self.check_node(cond, ctx, diag); + let then_typed = self.check_node(then_br, ctx, diag); let mut else_typed = None; let mut final_ty = then_typed.ty.clone(); if let Some(e) = else_br { - let et = self.check_node(*e, ctx, diag); + let et = self.check_node(e, ctx, diag); // Basic type promotion: if types differ, fall back to Any if et.ty != final_ty { final_ty = StaticType::Any; @@ -447,7 +447,7 @@ impl TypeChecker { } // Specialized check for the lambda using the input types! - let typed_lambda = self.check(*lambda, &arg_types, diag); + let typed_lambda = self.check(lambda, &arg_types, diag); let ret_ty = if let StaticType::Function(sig) = &typed_lambda.ty { // If the lambda returns an Optional(T), the pipeline filters Void and stores T! @@ -490,7 +490,7 @@ impl TypeChecker { } => { // 1. Determine types of captured variables let mut upvalue_types = Vec::with_capacity(upvalues.len()); - for &addr in &upvalues { + for &addr in upvalues { upvalue_types.push(ctx.get_type(addr)); } @@ -500,7 +500,7 @@ impl TypeChecker { // 3. Check parameters and body let params_typed = self.check_params( - params.as_ref().clone(), + params.as_ref(), &StaticType::Any, &mut lambda_ctx, diag, @@ -509,7 +509,7 @@ impl TypeChecker { // Set current params type for 'again' validation lambda_ctx.current_params_ty = Some(params_typed.ty.clone()); - let body_typed = self.check_node((*body).clone(), &mut lambda_ctx, diag); + let body_typed = self.check_node(body, &mut lambda_ctx, diag); let ret_ty = body_typed.ty.clone(); // 4. Construct function type @@ -521,19 +521,19 @@ impl TypeChecker { ( BoundKind::Lambda { params: Rc::new(params_typed), - upvalues, + upvalues: upvalues.clone(), body: Rc::new(body_typed), - positional_count, + positional_count: *positional_count, }, fn_ty, ) } BoundKind::Call { callee, args } => { - let callee_typed = self.check_node(*callee, ctx, diag); + let callee_typed = self.check_node(callee, ctx, diag); // Manually check args (Tuple) to prevent Vector/Matrix promotion - let args_typed = if let BoundKind::Tuple { elements } = args.kind { + let args_typed = if let BoundKind::Tuple { elements } = &args.kind { let mut typed_elements = Vec::new(); let mut elem_types = Vec::new(); for e in elements { @@ -542,7 +542,7 @@ impl TypeChecker { typed_elements.push(t); } Node { - identity: args.identity, + identity: args.identity.clone(), kind: BoundKind::Tuple { elements: typed_elements, }, @@ -550,7 +550,7 @@ impl TypeChecker { } } else { // Should not happen as parser wraps args in Tuple, but fallback safely - self.check_node(*args, ctx, diag) + self.check_node(args, ctx, diag) }; let ret_ty = match callee_typed.ty.resolve_call(&args_typed.ty) { @@ -578,7 +578,7 @@ impl TypeChecker { BoundKind::Again { args } => { // Manually check args (Tuple) to prevent Vector/Matrix promotion - let args_typed = if let BoundKind::Tuple { elements } = args.kind { + let args_typed = if let BoundKind::Tuple { elements } = &args.kind { let mut typed_elements = Vec::new(); let mut elem_types = Vec::new(); for e in elements { @@ -587,14 +587,14 @@ impl TypeChecker { typed_elements.push(t); } Node { - identity: args.identity, + identity: args.identity.clone(), kind: BoundKind::Tuple { elements: typed_elements, }, ty: StaticType::Tuple(elem_types), } } else { - self.check_node(*args, ctx, diag) + self.check_node(args, ctx, diag) }; if let Some(expected_ty) = &ctx.current_params_ty @@ -660,7 +660,7 @@ impl TypeChecker { let mut typed_values = Vec::with_capacity(values.len()); let mut fields_ty = Vec::with_capacity(values.len()); - for (i, v) in values.into_iter().enumerate() { + for (i, v) in values.iter().enumerate() { let vt = self.check_node(v, ctx, diag); fields_ty.push((layout.fields[i].0, vt.ty.clone())); typed_values.push(vt); @@ -680,11 +680,11 @@ impl TypeChecker { original_call, bound_expanded, } => { - let expanded_typed = self.check_node(*bound_expanded, ctx, diag); + let expanded_typed = self.check_node(bound_expanded, ctx, diag); let ty = expanded_typed.ty.clone(); ( BoundKind::Expansion { - original_call, + original_call: original_call.clone(), bound_expanded: Box::new(expanded_typed), }, ty, @@ -705,7 +705,7 @@ impl TypeChecker { }; Node { - identity: node.identity, + identity: node.identity.clone(), kind, ty, } diff --git a/src/ast/environment.rs b/src/ast/environment.rs index 05fe95e..b4d9dfb 100644 --- a/src/ast/environment.rs +++ b/src/ast/environment.rs @@ -8,7 +8,10 @@ use std::cell::RefCell; use std::collections::HashMap; use std::rc::Rc; -use crate::ast::compiler::bound_nodes::{Address, AnalyzedNode, BoundKind, BoundNode, GlobalIdx}; +use crate::ast::compiler::bound_nodes::{ + Address, AnalyzedNode, BoundKind, BoundNode, GlobalAnalyzedRegistry, GlobalFunctionRegistry, + GlobalIdx, +}; use crate::ast::compiler::dumper::Dumper; use crate::ast::compiler::lambda_collector::LambdaCollector; use crate::ast::compiler::macros::{MacroEvaluator, MacroExpander, MacroRegistry}; @@ -69,8 +72,8 @@ pub struct Environment { pub global_types: Rc>>, pub global_purity: Rc>>, pub global_values: Rc>>, - pub function_registry: Rc>>, - pub typed_function_registry: Rc>>, + pub function_registry: Rc>, + pub typed_function_registry: Rc>, pub monomorph_cache: Rc>, pub debug_mode: bool, pub optimization: bool, @@ -79,19 +82,19 @@ pub struct Environment { } struct EnvFunctionRegistry { - registry: Rc>>, - analyzed_registry: Rc>>, + registry: Rc>, + analyzed_registry: Rc>, } impl FunctionRegistry for EnvFunctionRegistry { - fn resolve(&self, addr: Address) -> Option { + fn resolve(&self, addr: Address) -> Option> { if let Address::Global(idx) = addr { self.registry.borrow().get(&idx).cloned() } else { None } } - fn resolve_analyzed(&self, addr: Address) -> Option { + fn resolve_analyzed(&self, addr: Address) -> Option> { if let Address::Global(idx) = addr { self.analyzed_registry.borrow().get(&idx).cloned() } else { @@ -122,7 +125,7 @@ impl MacroEvaluator for RuntimeMacroEvaluator { let (bound_ast, captures) = Binder::bind_root(self.global_names.clone(), node, &mut diag)?; let bound_ast = crate::ast::compiler::captures::CapturePass::apply(bound_ast, &captures); let checker = TypeChecker::new(self.global_types.clone()); - let typed_ast = checker.check(bound_ast, &[], &mut diag); + let typed_ast = checker.check(&bound_ast, &[], &mut diag); if diag.has_errors() { return Err(diag @@ -316,7 +319,7 @@ impl Environment { LambdaCollector::collect(&bound_ast, &mut self.function_registry.borrow_mut()); let checker = TypeChecker::new(self.global_types.clone()); - let typed_ast = checker.check(bound_ast, &[], &mut diagnostics); + let typed_ast = checker.check(&bound_ast, &[], &mut diagnostics); CompilationResult { ast: Some(typed_ast), @@ -420,12 +423,12 @@ impl Environment { let optimization = self.optimization; let compiler = Rc::new( - move |func_template: BoundNode, + move |func_template: Rc, arg_types: &[StaticType]| -> Result<(Value, StaticType), String> { let mut diag = Diagnostics::new(); let checker = TypeChecker::new(global_types.clone()); - let retyped_ast = checker.check(func_template, arg_types, &mut diag); + let retyped_ast = checker.check(func_template.as_ref(), arg_types, &mut diag); if diag.has_errors() { return Err(diag