From 21fa082b4491e83de43b47a830199b267ff626f2 Mon Sep 17 00:00:00 2001 From: Jesse Brault Date: Fri, 4 Sep 2026 21:14:12 -0500 Subject: [PATCH] New type analysis WIP. --- .../analysis_context/helpers.rs | 2 +- .../semantic_analysis/analysis_context/mod.rs | 254 +++++++++++++----- .../src/semantic_analysis/collect_types.rs | 5 +- .../semantic_analysis/resolve_types/mod.rs | 2 +- .../resolve_types/type_analysis.rs | 2 +- dmc-lib/src/semantic_analysis/scope.rs | 5 + dmc-lib/src/semantic_analysis/symbol.rs | 14 +- .../type_analysis/collect.rs | 20 +- .../semantic_analysis/type_analysis/mod.rs | 10 + .../type_analysis/resolve.rs | 30 +++ dmc-lib/src/semantic_analysis/type_info.rs | 22 +- 11 files changed, 267 insertions(+), 99 deletions(-) diff --git a/dmc-lib/src/semantic_analysis/analysis_context/helpers.rs b/dmc-lib/src/semantic_analysis/analysis_context/helpers.rs index cfa6769..ded7754 100644 --- a/dmc-lib/src/semantic_analysis/analysis_context/helpers.rs +++ b/dmc-lib/src/semantic_analysis/analysis_context/helpers.rs @@ -10,7 +10,7 @@ pub fn get_name_for_type<'ctx>(type_info: &TypeInfo, ctx: &'ctx AnalysisContext) TypeInfo::Constructor(_constructor_type_info) => { todo!() } - TypeInfo::TypeConstructor(type_constructor_info) => { + TypeInfo::Class(type_constructor_info) => { let class_symbol = &ctx.symbols()[type_constructor_info.class_symbol_id()]; class_symbol.declared_name() } diff --git a/dmc-lib/src/semantic_analysis/analysis_context/mod.rs b/dmc-lib/src/semantic_analysis/analysis_context/mod.rs index 4d0b61a..a2a295b 100644 --- a/dmc-lib/src/semantic_analysis/analysis_context/mod.rs +++ b/dmc-lib/src/semantic_analysis/analysis_context/mod.rs @@ -6,12 +6,13 @@ use crate::diagnostic_factories::symbol_not_found; use crate::semantic_analysis::diagnostic_helpers::symbol_already_declared; use crate::semantic_analysis::scope::{Scope, ScopeId}; use crate::semantic_analysis::symbol::{Symbol, SymbolId}; -use crate::semantic_analysis::type_info::{TypeInfo, TypeInfoId}; +use crate::semantic_analysis::type_info::{ClassTypeInfo, TypeInfo, TypeInfoId}; use crate::source_range::SourceRange; use std::collections::HashMap; use std::rc::Rc; -pub struct AnalysisContext { +#[derive(Debug, Clone)] +struct AnalysisState { fqn_stack: Vec>, scopes: Vec, current_scope_id: Option, @@ -23,8 +24,8 @@ pub struct AnalysisContext { nodes_to_type_infos: HashMap, } -impl AnalysisContext { - pub fn new() -> Self { +impl Default for AnalysisState { + fn default() -> Self { Self { fqn_stack: Vec::new(), scopes: Vec::new(), @@ -37,101 +38,129 @@ impl AnalysisContext { nodes_to_type_infos: HashMap::new(), } } +} + +pub struct AnalysisContext { + state: Box, + previous_state: Option>, +} + +impl AnalysisContext { + pub fn new() -> Self { + Self { + state: AnalysisState::default().into(), + previous_state: None, + } + } pub fn commit(&mut self) { - todo!() + self.previous_state = Some(self.state.clone()); } pub fn rollback(&mut self) { - todo!() + self.state = self.previous_state.take().unwrap_or_default(); } + #[deprecated] pub fn symbols(&self) -> &[Symbol] { - &self.symbols + &self.state.symbols } + #[deprecated] pub fn nodes_to_symbols(&self) -> &HashMap { - &self.nodes_to_symbols + &self.state.nodes_to_symbols } + #[deprecated] pub fn type_infos(&self) -> &[TypeInfo] { - &self.type_infos + &self.state.type_infos } + #[deprecated] pub fn symbols_to_type_infos(&self) -> &HashMap { - &self.symbols_to_type_infos + &self.state.symbols_to_type_infos } + #[deprecated] pub fn nodes_to_type_infos(&self) -> &HashMap { - &self.nodes_to_type_infos + &self.state.nodes_to_type_infos } pub fn push_fqn_part(&mut self, part: Rc) { - self.fqn_stack.push(part); + self.state.fqn_stack.push(part); } pub fn pop_fqn_part(&mut self) { - self.fqn_stack.pop(); + self.state.fqn_stack.pop(); } pub fn resolve_fqn(&self, suffix: &str) -> String { - let mut fqn = self.fqn_stack.clone(); + let mut fqn = self.state.fqn_stack.clone(); fqn.push(suffix.into()); fqn.join("::") } - pub fn push_scope(&mut self, _debug_name: &str) -> ScopeId { - let scope = Scope::new(self.current_scope_id); - self.scopes.push(scope); - self.current_scope_id = Some(self.scopes.len() - 1); - self.current_scope_id.unwrap() - } - fn get_scope(&self, scope_id: ScopeId) -> &Scope { - self.scopes.get(scope_id).expect(&format!( + self.state.scopes.get(scope_id).expect(&format!( "scope_id {} is not a valid index of self.scopes", scope_id )) } fn get_scope_mut(&mut self, scope_id: ScopeId) -> &mut Scope { - self.scopes.get_mut(scope_id).expect(&format!( + self.state.scopes.get_mut(scope_id).expect(&format!( "scope_id {} is not a valid index of self.scopes", scope_id )) } - fn get_current_scope(&self) -> &Scope { - self.get_scope(self.current_scope_id.expect("current_scope_id is None")) - } - - fn get_current_scope_mut(&mut self) -> &mut Scope { - self.get_scope_mut(self.current_scope_id.expect("current_scope_id is None")) + /// Pushes a new `Scope` on top of the scope stack, returning the `ScopeId` for the newly pushed + /// scope. + pub fn push_scope(&mut self, _debug_name: &str) -> ScopeId { + let scope = Scope::new(self.state.current_scope_id); + self.state.scopes.push(scope); + self.state.current_scope_id = Some(self.state.scopes.len() - 1); + self.state.current_scope_id.unwrap() } pub fn pop_scope(&mut self) { - self.current_scope_id = self.get_current_scope().parent_id(); + self.state.current_scope_id = self + .state + .current_scope_id + .and_then(|current_scope_id| self.state.scopes.get(current_scope_id)) + .and_then(|current_scope| current_scope.parent_id()) } + /// Designates the given `node_id` as belonging to the current scope. pub fn associate_node_to_current_scope(&mut self, node_id: NodeId) { - self.nodes_to_scopes.insert( + self.state.nodes_to_scopes.insert( node_id, - self.current_scope_id.expect("current_scope_id is None"), + self.state + .current_scope_id + .expect("current_scope_id is None"), ); } - /// Inserts the given symbol into the Scope corresponding to the given ScopeId. **This is a low - /// level operation and alternate methods should be preferred.** + /// Inserts the given symbol into the Scope corresponding to the given ScopeId. /// - /// Danger: If a symbol already exists in the corresponding Scope with the same declared name, - /// it will be overwritten, leading to dangling symbols/symbol ids. + /// ## Panics + /// - If the scope identified by `scope_id` already contains a symbol with the `declared_name` + /// obtained from the given `Symbol`. fn insert_symbol_in_scope(&mut self, scope_id: ScopeId, symbol: Symbol) -> SymbolId { // get declared name let declared_name = symbol.declared_name_owned(); + if self.get_scope(scope_id).has_symbol(symbol.declared_name()) { + panic!( + "Symbol with declared_name {} already exists in scope_id {}", + symbol.declared_name(), + scope_id + ); + } + // push the symbol - self.symbols.push(symbol); - let symbol_id = self.symbols.len() - 1; + self.state.symbols.push(symbol); + let symbol_id = self.state.symbols.len() - 1; // put it in scope self.get_scope_mut(scope_id) @@ -140,28 +169,46 @@ impl AnalysisContext { symbol_id } + /// Sets the symbol identified by `symbol_id` for the node identified by `node_id`. pub fn associate_node_to_symbol(&mut self, node_id: NodeId, symbol_id: SymbolId) { - self.nodes_to_symbols.insert(node_id, symbol_id); + self.state.nodes_to_symbols.insert(node_id, symbol_id); } - fn get_symbol_in_scope(&self, scope: &Scope, declared_name: &str) -> Option<&Symbol> { + /// Finds a symbol with a matching name to `declared_name` in the provided `Scope`. Returns an + /// `Option` maybe containing a reference to that `Symbol`. + /// + /// ## Panics + /// - If the `symbol_id` for the matching `Symbol` is not a valid index of `self.state.symbols`. + fn find_symbol_in_scope(&self, scope: &Scope, declared_name: &str) -> Option<&Symbol> { scope.get_symbol_id(declared_name).map(|symbol_id| { - self.symbols.get(symbol_id).expect(&format!( + self.state.symbols.get(symbol_id).expect(&format!( "symbol_id {} is not a valid index of self.symbols", symbol_id )) }) } - /// Use this function only when there is no node associated with the symbol. Otherwise use - /// `try_insert_symbol_in_node_scope`. + /// Inserts the given `Symbol` into the scope identified by `scope_id`. + /// + /// ## Examples + /// ```rust + /// use dmc_lib::semantic_analysis::analysis_context::AnalysisContext; + /// use dmc_lib::semantic_analysis::symbol::{Symbol, VariableSymbol}; + /// + /// let mut analysis_context = AnalysisContext::new(); + /// let scope_id = analysis_context.push_scope("some scope"); + /// let symbol = Symbol::Variable(VariableSymbol::new("my_variable".into(), None, false)); + /// let result = analysis_context.try_insert_symbol_in_scope(symbol, scope_id); + /// assert!(matches!(result, Ok(_))); + /// ``` pub fn try_insert_symbol_in_scope( &mut self, to_insert: Symbol, scope_id: ScopeId, ) -> Result { let scope = self.get_scope(scope_id); - if let Some(already_declared) = self.get_symbol_in_scope(scope, to_insert.declared_name()) { + if let Some(already_declared) = self.find_symbol_in_scope(scope, to_insert.declared_name()) + { Err(symbol_already_declared(already_declared, &to_insert)) } else { let symbol_id = self.insert_symbol_in_scope(scope_id, to_insert); @@ -170,18 +217,39 @@ impl AnalysisContext { } } + /// Inserts the given symbol into the scope belonging to the given node_id, and sets the node's + /// associated symbol id to the resultant symbol id. Returns `Ok(SymbolId)` if the insert was + /// successful, else `Err(Diagnostic)`. + /// + /// ## Examples + /// ```rust + /// use dmc_lib::semantic_analysis::analysis_context::AnalysisContext; + /// use dmc_lib::semantic_analysis::symbol::{Symbol, VariableSymbol}; + /// + /// let mut analysis_context = AnalysisContext::new(); + /// analysis_context.push_scope("some scope"); + /// let node_id = 0; + /// analysis_context.associate_node_to_current_scope(node_id); + /// let symbol = Symbol::Variable(VariableSymbol::new("my_variable".into(), None, false)); + /// let result = analysis_context.try_insert_associate_symbol_in_node_scope(symbol, node_id); + /// assert!(matches!(result, Ok(_))); + /// ``` pub fn try_insert_associate_symbol_in_node_scope( &mut self, to_insert: Symbol, owner_node_id: NodeId, ) -> Result { - let node_scope_id = self.nodes_to_scopes.get(&owner_node_id).expect(&format!( - "owner_node_id {} is not in self.nodes_to_scopes", - owner_node_id - )); + let node_scope_id = self + .state + .nodes_to_scopes + .get(&owner_node_id) + .expect(&format!( + "owner_node_id {} is not in self.state.nodes_to_scopes", + owner_node_id + )); let node_scope = self.get_scope(*node_scope_id); if let Some(already_declared) = - self.get_symbol_in_scope(node_scope, to_insert.declared_name()) + self.find_symbol_in_scope(node_scope, to_insert.declared_name()) { Err(symbol_already_declared(already_declared, &to_insert)) } else { @@ -191,12 +259,15 @@ impl AnalysisContext { } } + /// Gets the `SymbolId` of the node with the declared name in the containing scope of the node + /// with the given `NodeId`. fn get_symbol_id_by_declared_name_in_node_scope( &self, node_id: NodeId, declared_name: &str, ) -> Option { let scope_id = self + .state .nodes_to_scopes .get(&node_id) .expect(&format!("node_id {} has no associated scope", node_id)); @@ -204,6 +275,8 @@ impl AnalysisContext { scope.get_symbol_id(declared_name) } + /// Finds the symbol for the node with the given node id and declared name and sets the node's + /// symbol to that result. pub fn associate_node_with_self_symbol(&mut self, node_id: NodeId, declared_name: &str) { let symbol_id = self .get_symbol_id_by_declared_name_in_node_scope(node_id, declared_name) @@ -221,6 +294,7 @@ impl AnalysisContext { node_source_range: &SourceRange, ) -> Result<(), Diagnostic> { let scope_id = self + .state .nodes_to_scopes .get(&node_id) .expect(&format!("node_id {} has no associated scope", node_id)); @@ -250,37 +324,43 @@ impl AnalysisContext { } } + #[deprecated] pub fn insert_type_info(&mut self, type_info: TypeInfo) -> TypeInfoId { - self.type_infos.push(type_info); - self.type_infos.len() - 1 + self.state.type_infos.push(type_info); + self.state.type_infos.len() - 1 } + #[deprecated] pub fn insert_type_info_for_node( &mut self, type_info: TypeInfo, node_id: NodeId, ) -> TypeInfoId { - self.type_infos.push(type_info); - let type_info_id = self.type_infos.len() - 1; - self.nodes_to_type_infos.insert(node_id, type_info_id); + self.state.type_infos.push(type_info); + let type_info_id = self.state.type_infos.len() - 1; + self.state.nodes_to_type_infos.insert(node_id, type_info_id); type_info_id } pub fn associate_symbol_to_type(&mut self, symbol_id: SymbolId, type_info_id: TypeInfoId) { - self.symbols_to_type_infos.insert(symbol_id, type_info_id); + self.state + .symbols_to_type_infos + .insert(symbol_id, type_info_id); } pub fn associate_node_and_symbol_to_type(&mut self, node_id: NodeId, type_info_id: TypeInfoId) { let symbol_id = self + .state .nodes_to_symbols .get(&node_id) .expect(&format!("node_id {} has no associated symbol", node_id)); self.associate_symbol_to_type(*symbol_id, type_info_id); - self.nodes_to_type_infos.insert(node_id, type_info_id); + self.state.nodes_to_type_infos.insert(node_id, type_info_id); } pub fn get_type_info_id_for_node(&self, node_id: NodeId) -> TypeInfoId { *self + .state .nodes_to_type_infos .get(&node_id) .expect(&format!("node_id {} has no associated type", node_id)) @@ -288,37 +368,44 @@ impl AnalysisContext { pub fn get_type_info_for_node(&self, node_id: NodeId) -> &TypeInfo { let type_info_id = self.get_type_info_id_for_node(node_id); - self.type_infos + self.state + .type_infos .get(type_info_id) .expect(&format!("invalid type_info_id {}", type_info_id)) } pub fn get_type_info_by_id(&self, type_info_id: TypeInfoId) -> &TypeInfo { - self.type_infos + self.state + .type_infos .get(type_info_id) .expect(&format!("invalid type_info_id {}", type_info_id)) } pub fn associate_node_to_type(&mut self, node_id: NodeId, type_info_id: TypeInfoId) { - self.nodes_to_type_infos.insert(node_id, type_info_id); + self.state.nodes_to_type_infos.insert(node_id, type_info_id); } pub fn lookup_type_for_node_via_symbol(&self, node_id: NodeId) -> TypeInfoId { let symbol_id = self + .state .nodes_to_symbols .get(&node_id) .expect(&format!("node_id {} has no associated symbol", node_id)); - let symbol_type_info_id = self.symbols_to_type_infos.get(symbol_id).expect(&format!( - "symbol_id {} has no associated type_info", - symbol_id - )); + let symbol_type_info_id = self + .state + .symbols_to_type_infos + .get(symbol_id) + .expect(&format!( + "symbol_id {} has no associated type_info", + symbol_id + )); *symbol_type_info_id } pub fn find_symbol_by_fqn(&self, fqn: &str) -> Option { // This is quite naive and probably very slow; we will certainly use trees of HashMaps (or // structs with a HashMap and children) to represent the fqn hierarchy. - for (id, symbol) in self.symbols.iter().enumerate() { + for (id, symbol) in self.state.symbols.iter().enumerate() { match symbol { Symbol::Class(class_symbol) => { if class_symbol.fqn() == fqn { @@ -335,4 +422,43 @@ impl AnalysisContext { } None } + + pub fn get_symbol_id(&self, node_id: NodeId) -> Option { + self.state.nodes_to_scopes.get(&node_id).cloned() + } + + pub fn make_class_type( + &mut self, + class_symbol_id: SymbolId, + constructor_symbol_id: Option, + ) -> TypeInfoId { + if let Some(type_info_id) = self.state.symbols_to_type_infos.get(&class_symbol_id) { + *type_info_id + } else { + let type_info = + TypeInfo::Class(ClassTypeInfo::new(class_symbol_id, constructor_symbol_id)); + self.state.type_infos.push(type_info); + let type_info_id = self.state.type_infos.len() - 1; + self.state + .symbols_to_type_infos + .insert(class_symbol_id, type_info_id); + type_info_id + } + } + + pub fn resolve_type_info_id(&mut self, node_id: NodeId, declared_name: &str) -> TypeInfoId { + todo!() + } + + pub fn int_type(&mut self) -> &TypeInfoId { + todo!() + } + + pub fn double_type(&mut self) -> &TypeInfoId { + todo!() + } + + pub fn type_by_fqn(&mut self, fqn: &str) -> &TypeInfoId { + todo!() + } } diff --git a/dmc-lib/src/semantic_analysis/collect_types.rs b/dmc-lib/src/semantic_analysis/collect_types.rs index 6b5e279..f06e499 100644 --- a/dmc-lib/src/semantic_analysis/collect_types.rs +++ b/dmc-lib/src/semantic_analysis/collect_types.rs @@ -7,8 +7,7 @@ use crate::ast::parameter::Parameter; use crate::semantic_analysis::analysis_context::AnalysisContext; use crate::semantic_analysis::symbol::SymbolId; use crate::semantic_analysis::type_info::{ - ConstructorTypeInfo, FunctionTypeInfo, InstanceTypeInfo, TypeConstructorInfo, TypeInfo, - TypeInfoId, + ClassTypeInfo, ConstructorTypeInfo, FunctionTypeInfo, InstanceTypeInfo, TypeInfo, TypeInfoId, }; pub fn collect_types(compilation_unit: &CompilationUnit, ctx: &mut AnalysisContext) { @@ -148,7 +147,7 @@ fn collect_types_class(class: &Class, ctx: &mut AnalysisContext) { // todo: fields, methods // Self type constructor - let type_constructor_type_info = TypeInfo::TypeConstructor(TypeConstructorInfo::new( + let type_constructor_type_info = TypeInfo::Class(ClassTypeInfo::new( ctx.nodes_to_symbols()[&class.node_id()], constructor_type_info_id, )); diff --git a/dmc-lib/src/semantic_analysis/resolve_types/mod.rs b/dmc-lib/src/semantic_analysis/resolve_types/mod.rs index e5940b8..d0a903c 100644 --- a/dmc-lib/src/semantic_analysis/resolve_types/mod.rs +++ b/dmc-lib/src/semantic_analysis/resolve_types/mod.rs @@ -255,7 +255,7 @@ fn resolve_types_call(call: &Call, ctx: &mut AnalysisContext, diagnostics: &mut let callee_type_info = ctx.get_type_info_for_node(call.callee().node_id()); match callee_type_info { - TypeInfo::TypeConstructor(type_constructor_info) => { + TypeInfo::Class(type_constructor_info) => { let class_symbol = ctx.symbols()[type_constructor_info.class_symbol_id()].unwrap_class_symbol(); match class_symbol.constructor_symbol_id() { diff --git a/dmc-lib/src/semantic_analysis/resolve_types/type_analysis.rs b/dmc-lib/src/semantic_analysis/resolve_types/type_analysis.rs index 1d10a11..bb35600 100644 --- a/dmc-lib/src/semantic_analysis/resolve_types/type_analysis.rs +++ b/dmc-lib/src/semantic_analysis/resolve_types/type_analysis.rs @@ -150,7 +150,7 @@ pub fn can_assign_right_to_left(left: &TypeInfo, right: &TypeInfo, ctx: &Analysi TypeInfo::Constructor(_) => { panic!() } - TypeInfo::TypeConstructor(_) => { + TypeInfo::Class(_) => { panic!() } TypeInfo::Instance(left_instance_type_info) => match right { diff --git a/dmc-lib/src/semantic_analysis/scope.rs b/dmc-lib/src/semantic_analysis/scope.rs index 0dffcde..5dd26a4 100644 --- a/dmc-lib/src/semantic_analysis/scope.rs +++ b/dmc-lib/src/semantic_analysis/scope.rs @@ -4,6 +4,7 @@ use std::rc::Rc; pub type ScopeId = usize; +#[derive(Debug, Clone)] pub struct Scope { parent_id: Option, symbols: HashMap, SymbolId>, @@ -21,6 +22,10 @@ impl Scope { self.parent_id } + pub fn has_symbol(&self, declared_name: &str) -> bool { + self.symbols.contains_key(declared_name) + } + pub fn insert_symbol(&mut self, declared_name: Rc, symbol_id: SymbolId) { self.symbols.insert(declared_name, symbol_id); } diff --git a/dmc-lib/src/semantic_analysis/symbol.rs b/dmc-lib/src/semantic_analysis/symbol.rs index 3dbfc01..7d7e795 100644 --- a/dmc-lib/src/semantic_analysis/symbol.rs +++ b/dmc-lib/src/semantic_analysis/symbol.rs @@ -5,7 +5,7 @@ use std::rc::Rc; pub type SymbolId = usize; -#[derive(Debug)] +#[derive(Debug, Clone)] pub enum Symbol { Class(ClassSymbol), Field(FieldSymbol), @@ -60,7 +60,7 @@ impl Symbol { } } -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct ClassSymbol { declared_name: Rc, source_range: Option, @@ -129,7 +129,7 @@ impl ClassSymbol { } } -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct FieldSymbol { declared_name: Rc, declared_name_source_range: Option, @@ -156,7 +156,7 @@ impl FieldSymbol { } } -#[derive(Debug)] +#[derive(Debug, Clone)] pub enum FunctionType { Function, Constructor, @@ -164,7 +164,7 @@ pub enum FunctionType { StaticMethod, } -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct FunctionSymbol { declared_name: Rc, declared_name_source_range: Option, @@ -219,7 +219,7 @@ impl FunctionSymbol { } } -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct ParameterSymbol { name: Rc, source_range: Option, @@ -243,7 +243,7 @@ impl ParameterSymbol { } } -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct VariableSymbol { name: Rc, source_range: Option, diff --git a/dmc-lib/src/semantic_analysis/type_analysis/collect.rs b/dmc-lib/src/semantic_analysis/type_analysis/collect.rs index 2e21aa3..10eabe8 100644 --- a/dmc-lib/src/semantic_analysis/type_analysis/collect.rs +++ b/dmc-lib/src/semantic_analysis/type_analysis/collect.rs @@ -10,16 +10,14 @@ pub fn collect_types(compilation_unit: &CompilationUnit, ctx: &mut AnalysisConte } fn collect_types_class(class: &Class, ctx: &mut AnalysisContext) { - let class_symbol_id = *ctx - .nodes_to_symbols() - .get(&class.node_id()) - .expect(&format!( - "Could not find class symbol for {} {}", - class.node_id(), - class.declared_name() - )); + let maybe_constructor_type_info_id = class + .constructor() + .and_then(|constructor| ctx.get_symbol_id(constructor.node_id())); - let self_instance_type_info = TypeInfo::Instance(InstanceTypeInfo::new(class_symbol_id)); - let self_instance_type_info_id = ctx.insert_type_info(self_instance_type_info); - ctx.associate_symbol_to_type(class_symbol_id, self_instance_type_info_id) + let class_symbol_id = ctx.get_symbol_id(class.node_id()).expect(&format!( + "Could not find symbol for {} {}", + class.node_id(), + class.declared_name() + )); + ctx.make_class_type(class_symbol_id, maybe_constructor_type_info_id); } diff --git a/dmc-lib/src/semantic_analysis/type_analysis/mod.rs b/dmc-lib/src/semantic_analysis/type_analysis/mod.rs index 5978e5f..56ebac2 100644 --- a/dmc-lib/src/semantic_analysis/type_analysis/mod.rs +++ b/dmc-lib/src/semantic_analysis/type_analysis/mod.rs @@ -1,3 +1,13 @@ +use crate::ast::compilation_unit::CompilationUnit; +use crate::semantic_analysis::analysis_context::AnalysisContext; +use crate::semantic_analysis::type_analysis::collect::collect_types; +use crate::semantic_analysis::type_analysis::resolve::resolve_types; + mod collect; mod infer; mod resolve; + +pub fn analyze_types(compilation_unit: &CompilationUnit, analysis_context: &mut AnalysisContext) { + collect_types(compilation_unit, analysis_context); + resolve_types(compilation_unit, analysis_context); +} diff --git a/dmc-lib/src/semantic_analysis/type_analysis/resolve.rs b/dmc-lib/src/semantic_analysis/type_analysis/resolve.rs index 8b13789..372d79c 100644 --- a/dmc-lib/src/semantic_analysis/type_analysis/resolve.rs +++ b/dmc-lib/src/semantic_analysis/type_analysis/resolve.rs @@ -1 +1,31 @@ +use crate::ast::compilation_unit::CompilationUnit; +use crate::ast::function::Function; +use crate::ast::parameter::Parameter; +use crate::ast::type_use::TypeUse; +use crate::semantic_analysis::analysis_context::AnalysisContext; +pub fn resolve_types(compilation_unit: &CompilationUnit, ctx: &mut AnalysisContext) { + for function in compilation_unit.functions() { + resolve_types_function(function, ctx); + } + for extern_function in compilation_unit.extern_functions() {} + for class in compilation_unit.classes() {} +} + +fn resolve_types_function(function: &Function, ctx: &mut AnalysisContext) { + for parameter in function.parameters() { + resolve_types_parameter(parameter, ctx); + } + if let Some(return_type) = function.return_type() { + resolve_types_type_use(return_type, ctx); + } +} + +fn resolve_types_parameter(parameter: &Parameter, ctx: &mut AnalysisContext) { + resolve_types_type_use(parameter.type_use(), ctx); +} + +fn resolve_types_type_use(type_use: &TypeUse, ctx: &mut AnalysisContext) { + let type_info_id = ctx.resolve_type_info_id(type_use.node_id(), type_use.declared_name()); + todo!() +} diff --git a/dmc-lib/src/semantic_analysis/type_info.rs b/dmc-lib/src/semantic_analysis/type_info.rs index eba36ad..014d043 100644 --- a/dmc-lib/src/semantic_analysis/type_info.rs +++ b/dmc-lib/src/semantic_analysis/type_info.rs @@ -6,9 +6,9 @@ pub type TypeInfoId = usize; #[derive(Clone, Debug)] pub enum TypeInfo { Any, - Function(FunctionTypeInfo), + Class(ClassTypeInfo), Constructor(ConstructorTypeInfo), - TypeConstructor(TypeConstructorInfo), + Function(FunctionTypeInfo), Instance(InstanceTypeInfo), Int, Double, @@ -24,9 +24,9 @@ impl TypeInfo { } } - pub fn unwrap_type_constructor(&self) -> &TypeConstructorInfo { + pub fn unwrap_class(&self) -> &ClassTypeInfo { match self { - TypeInfo::TypeConstructor(type_constructor_info) => type_constructor_info, + TypeInfo::Class(type_constructor_info) => type_constructor_info, _ => panic!("Attempt to unwrap {:?} as TypeConstructor", self), } } @@ -89,16 +89,16 @@ impl ConstructorTypeInfo { } #[derive(Clone, Debug)] -pub struct TypeConstructorInfo { +pub struct ClassTypeInfo { class_symbol_id: SymbolId, - constructor_type_info_id: Option, + constructor_symbol_id: Option, } -impl TypeConstructorInfo { - pub fn new(class_symbol_id: SymbolId, constructor_type_info_id: Option) -> Self { +impl ClassTypeInfo { + pub fn new(class_symbol_id: SymbolId, constructor_symbol_id: Option) -> Self { Self { class_symbol_id, - constructor_type_info_id, + constructor_symbol_id, } } @@ -106,8 +106,8 @@ impl TypeConstructorInfo { self.class_symbol_id } - pub fn constructor_type_info_id(&self) -> Option { - self.constructor_type_info_id + pub fn constructor_type_info_id(&self) -> Option { + self.constructor_symbol_id } }