New type analysis WIP.

This commit is contained in:
Jesse Brault 2026-09-04 21:14:12 -05:00
parent d07135b3c6
commit 21fa082b44
11 changed files with 267 additions and 99 deletions

View File

@ -10,7 +10,7 @@ pub fn get_name_for_type<'ctx>(type_info: &TypeInfo, ctx: &'ctx AnalysisContext)
TypeInfo::Constructor(_constructor_type_info) => { TypeInfo::Constructor(_constructor_type_info) => {
todo!() todo!()
} }
TypeInfo::TypeConstructor(type_constructor_info) => { TypeInfo::Class(type_constructor_info) => {
let class_symbol = &ctx.symbols()[type_constructor_info.class_symbol_id()]; let class_symbol = &ctx.symbols()[type_constructor_info.class_symbol_id()];
class_symbol.declared_name() class_symbol.declared_name()
} }

View File

@ -6,12 +6,13 @@ use crate::diagnostic_factories::symbol_not_found;
use crate::semantic_analysis::diagnostic_helpers::symbol_already_declared; use crate::semantic_analysis::diagnostic_helpers::symbol_already_declared;
use crate::semantic_analysis::scope::{Scope, ScopeId}; use crate::semantic_analysis::scope::{Scope, ScopeId};
use crate::semantic_analysis::symbol::{Symbol, SymbolId}; 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 crate::source_range::SourceRange;
use std::collections::HashMap; use std::collections::HashMap;
use std::rc::Rc; use std::rc::Rc;
pub struct AnalysisContext { #[derive(Debug, Clone)]
struct AnalysisState {
fqn_stack: Vec<Rc<str>>, fqn_stack: Vec<Rc<str>>,
scopes: Vec<Scope>, scopes: Vec<Scope>,
current_scope_id: Option<ScopeId>, current_scope_id: Option<ScopeId>,
@ -23,8 +24,8 @@ pub struct AnalysisContext {
nodes_to_type_infos: HashMap<NodeId, TypeInfoId>, nodes_to_type_infos: HashMap<NodeId, TypeInfoId>,
} }
impl AnalysisContext { impl Default for AnalysisState {
pub fn new() -> Self { fn default() -> Self {
Self { Self {
fqn_stack: Vec::new(), fqn_stack: Vec::new(),
scopes: Vec::new(), scopes: Vec::new(),
@ -37,101 +38,129 @@ impl AnalysisContext {
nodes_to_type_infos: HashMap::new(), nodes_to_type_infos: HashMap::new(),
} }
} }
}
pub struct AnalysisContext {
state: Box<AnalysisState>,
previous_state: Option<Box<AnalysisState>>,
}
impl AnalysisContext {
pub fn new() -> Self {
Self {
state: AnalysisState::default().into(),
previous_state: None,
}
}
pub fn commit(&mut self) { pub fn commit(&mut self) {
todo!() self.previous_state = Some(self.state.clone());
} }
pub fn rollback(&mut self) { pub fn rollback(&mut self) {
todo!() self.state = self.previous_state.take().unwrap_or_default();
} }
#[deprecated]
pub fn symbols(&self) -> &[Symbol] { pub fn symbols(&self) -> &[Symbol] {
&self.symbols &self.state.symbols
} }
#[deprecated]
pub fn nodes_to_symbols(&self) -> &HashMap<NodeId, SymbolId> { pub fn nodes_to_symbols(&self) -> &HashMap<NodeId, SymbolId> {
&self.nodes_to_symbols &self.state.nodes_to_symbols
} }
#[deprecated]
pub fn type_infos(&self) -> &[TypeInfo] { pub fn type_infos(&self) -> &[TypeInfo] {
&self.type_infos &self.state.type_infos
} }
#[deprecated]
pub fn symbols_to_type_infos(&self) -> &HashMap<SymbolId, TypeInfoId> { pub fn symbols_to_type_infos(&self) -> &HashMap<SymbolId, TypeInfoId> {
&self.symbols_to_type_infos &self.state.symbols_to_type_infos
} }
#[deprecated]
pub fn nodes_to_type_infos(&self) -> &HashMap<NodeId, TypeInfoId> { pub fn nodes_to_type_infos(&self) -> &HashMap<NodeId, TypeInfoId> {
&self.nodes_to_type_infos &self.state.nodes_to_type_infos
} }
pub fn push_fqn_part(&mut self, part: Rc<str>) { pub fn push_fqn_part(&mut self, part: Rc<str>) {
self.fqn_stack.push(part); self.state.fqn_stack.push(part);
} }
pub fn pop_fqn_part(&mut self) { pub fn pop_fqn_part(&mut self) {
self.fqn_stack.pop(); self.state.fqn_stack.pop();
} }
pub fn resolve_fqn(&self, suffix: &str) -> String { 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.push(suffix.into());
fqn.join("::") 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 { 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 {} is not a valid index of self.scopes",
scope_id scope_id
)) ))
} }
fn get_scope_mut(&mut self, scope_id: ScopeId) -> &mut Scope { 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 {} is not a valid index of self.scopes",
scope_id scope_id
)) ))
} }
fn get_current_scope(&self) -> &Scope { /// Pushes a new `Scope` on top of the scope stack, returning the `ScopeId` for the newly pushed
self.get_scope(self.current_scope_id.expect("current_scope_id is None")) /// scope.
} pub fn push_scope(&mut self, _debug_name: &str) -> ScopeId {
let scope = Scope::new(self.state.current_scope_id);
fn get_current_scope_mut(&mut self) -> &mut Scope { self.state.scopes.push(scope);
self.get_scope_mut(self.current_scope_id.expect("current_scope_id is None")) self.state.current_scope_id = Some(self.state.scopes.len() - 1);
self.state.current_scope_id.unwrap()
} }
pub fn pop_scope(&mut self) { 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) { 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, 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 /// Inserts the given symbol into the Scope corresponding to the given ScopeId.
/// level operation and alternate methods should be preferred.**
/// ///
/// Danger: If a symbol already exists in the corresponding Scope with the same declared name, /// ## Panics
/// it will be overwritten, leading to dangling symbols/symbol ids. /// - 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 { fn insert_symbol_in_scope(&mut self, scope_id: ScopeId, symbol: Symbol) -> SymbolId {
// get declared name // get declared name
let declared_name = symbol.declared_name_owned(); 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 // push the symbol
self.symbols.push(symbol); self.state.symbols.push(symbol);
let symbol_id = self.symbols.len() - 1; let symbol_id = self.state.symbols.len() - 1;
// put it in scope // put it in scope
self.get_scope_mut(scope_id) self.get_scope_mut(scope_id)
@ -140,28 +169,46 @@ impl AnalysisContext {
symbol_id 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) { 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| { 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 {} is not a valid index of self.symbols",
symbol_id symbol_id
)) ))
}) })
} }
/// Use this function only when there is no node associated with the symbol. Otherwise use /// Inserts the given `Symbol` into the scope identified by `scope_id`.
/// `try_insert_symbol_in_node_scope`. ///
/// ## 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( pub fn try_insert_symbol_in_scope(
&mut self, &mut self,
to_insert: Symbol, to_insert: Symbol,
scope_id: ScopeId, scope_id: ScopeId,
) -> Result<SymbolId, Diagnostic> { ) -> Result<SymbolId, Diagnostic> {
let scope = self.get_scope(scope_id); 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)) Err(symbol_already_declared(already_declared, &to_insert))
} else { } else {
let symbol_id = self.insert_symbol_in_scope(scope_id, to_insert); 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( pub fn try_insert_associate_symbol_in_node_scope(
&mut self, &mut self,
to_insert: Symbol, to_insert: Symbol,
owner_node_id: NodeId, owner_node_id: NodeId,
) -> Result<SymbolId, Diagnostic> { ) -> Result<SymbolId, Diagnostic> {
let node_scope_id = self.nodes_to_scopes.get(&owner_node_id).expect(&format!( let node_scope_id = self
"owner_node_id {} is not in self.nodes_to_scopes", .state
owner_node_id .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); let node_scope = self.get_scope(*node_scope_id);
if let Some(already_declared) = 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)) Err(symbol_already_declared(already_declared, &to_insert))
} else { } 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( fn get_symbol_id_by_declared_name_in_node_scope(
&self, &self,
node_id: NodeId, node_id: NodeId,
declared_name: &str, declared_name: &str,
) -> Option<SymbolId> { ) -> Option<SymbolId> {
let scope_id = self let scope_id = self
.state
.nodes_to_scopes .nodes_to_scopes
.get(&node_id) .get(&node_id)
.expect(&format!("node_id {} has no associated scope", node_id)); .expect(&format!("node_id {} has no associated scope", node_id));
@ -204,6 +275,8 @@ impl AnalysisContext {
scope.get_symbol_id(declared_name) 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) { pub fn associate_node_with_self_symbol(&mut self, node_id: NodeId, declared_name: &str) {
let symbol_id = self let symbol_id = self
.get_symbol_id_by_declared_name_in_node_scope(node_id, declared_name) .get_symbol_id_by_declared_name_in_node_scope(node_id, declared_name)
@ -221,6 +294,7 @@ impl AnalysisContext {
node_source_range: &SourceRange, node_source_range: &SourceRange,
) -> Result<(), Diagnostic> { ) -> Result<(), Diagnostic> {
let scope_id = self let scope_id = self
.state
.nodes_to_scopes .nodes_to_scopes
.get(&node_id) .get(&node_id)
.expect(&format!("node_id {} has no associated scope", 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 { pub fn insert_type_info(&mut self, type_info: TypeInfo) -> TypeInfoId {
self.type_infos.push(type_info); self.state.type_infos.push(type_info);
self.type_infos.len() - 1 self.state.type_infos.len() - 1
} }
#[deprecated]
pub fn insert_type_info_for_node( pub fn insert_type_info_for_node(
&mut self, &mut self,
type_info: TypeInfo, type_info: TypeInfo,
node_id: NodeId, node_id: NodeId,
) -> TypeInfoId { ) -> TypeInfoId {
self.type_infos.push(type_info); self.state.type_infos.push(type_info);
let type_info_id = self.type_infos.len() - 1; let type_info_id = self.state.type_infos.len() - 1;
self.nodes_to_type_infos.insert(node_id, type_info_id); self.state.nodes_to_type_infos.insert(node_id, type_info_id);
type_info_id type_info_id
} }
pub fn associate_symbol_to_type(&mut self, symbol_id: SymbolId, type_info_id: TypeInfoId) { 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) { pub fn associate_node_and_symbol_to_type(&mut self, node_id: NodeId, type_info_id: TypeInfoId) {
let symbol_id = self let symbol_id = self
.state
.nodes_to_symbols .nodes_to_symbols
.get(&node_id) .get(&node_id)
.expect(&format!("node_id {} has no associated symbol", node_id)); .expect(&format!("node_id {} has no associated symbol", node_id));
self.associate_symbol_to_type(*symbol_id, type_info_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 { pub fn get_type_info_id_for_node(&self, node_id: NodeId) -> TypeInfoId {
*self *self
.state
.nodes_to_type_infos .nodes_to_type_infos
.get(&node_id) .get(&node_id)
.expect(&format!("node_id {} has no associated type", 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 { 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); let type_info_id = self.get_type_info_id_for_node(node_id);
self.type_infos self.state
.type_infos
.get(type_info_id) .get(type_info_id)
.expect(&format!("invalid type_info_id {}", 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 { pub fn get_type_info_by_id(&self, type_info_id: TypeInfoId) -> &TypeInfo {
self.type_infos self.state
.type_infos
.get(type_info_id) .get(type_info_id)
.expect(&format!("invalid type_info_id {}", 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) { 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 { pub fn lookup_type_for_node_via_symbol(&self, node_id: NodeId) -> TypeInfoId {
let symbol_id = self let symbol_id = self
.state
.nodes_to_symbols .nodes_to_symbols
.get(&node_id) .get(&node_id)
.expect(&format!("node_id {} has no associated symbol", 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!( let symbol_type_info_id = self
"symbol_id {} has no associated type_info", .state
symbol_id .symbols_to_type_infos
)); .get(symbol_id)
.expect(&format!(
"symbol_id {} has no associated type_info",
symbol_id
));
*symbol_type_info_id *symbol_type_info_id
} }
pub fn find_symbol_by_fqn(&self, fqn: &str) -> Option<SymbolId> { pub fn find_symbol_by_fqn(&self, fqn: &str) -> Option<SymbolId> {
// This is quite naive and probably very slow; we will certainly use trees of HashMaps (or // 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. // 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 { match symbol {
Symbol::Class(class_symbol) => { Symbol::Class(class_symbol) => {
if class_symbol.fqn() == fqn { if class_symbol.fqn() == fqn {
@ -335,4 +422,43 @@ impl AnalysisContext {
} }
None None
} }
pub fn get_symbol_id(&self, node_id: NodeId) -> Option<SymbolId> {
self.state.nodes_to_scopes.get(&node_id).cloned()
}
pub fn make_class_type(
&mut self,
class_symbol_id: SymbolId,
constructor_symbol_id: Option<SymbolId>,
) -> 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!()
}
} }

View File

@ -7,8 +7,7 @@ use crate::ast::parameter::Parameter;
use crate::semantic_analysis::analysis_context::AnalysisContext; use crate::semantic_analysis::analysis_context::AnalysisContext;
use crate::semantic_analysis::symbol::SymbolId; use crate::semantic_analysis::symbol::SymbolId;
use crate::semantic_analysis::type_info::{ use crate::semantic_analysis::type_info::{
ConstructorTypeInfo, FunctionTypeInfo, InstanceTypeInfo, TypeConstructorInfo, TypeInfo, ClassTypeInfo, ConstructorTypeInfo, FunctionTypeInfo, InstanceTypeInfo, TypeInfo, TypeInfoId,
TypeInfoId,
}; };
pub fn collect_types(compilation_unit: &CompilationUnit, ctx: &mut AnalysisContext) { 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 // todo: fields, methods
// Self type constructor // 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()], ctx.nodes_to_symbols()[&class.node_id()],
constructor_type_info_id, constructor_type_info_id,
)); ));

View File

@ -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()); let callee_type_info = ctx.get_type_info_for_node(call.callee().node_id());
match callee_type_info { match callee_type_info {
TypeInfo::TypeConstructor(type_constructor_info) => { TypeInfo::Class(type_constructor_info) => {
let class_symbol = let class_symbol =
ctx.symbols()[type_constructor_info.class_symbol_id()].unwrap_class_symbol(); ctx.symbols()[type_constructor_info.class_symbol_id()].unwrap_class_symbol();
match class_symbol.constructor_symbol_id() { match class_symbol.constructor_symbol_id() {

View File

@ -150,7 +150,7 @@ pub fn can_assign_right_to_left(left: &TypeInfo, right: &TypeInfo, ctx: &Analysi
TypeInfo::Constructor(_) => { TypeInfo::Constructor(_) => {
panic!() panic!()
} }
TypeInfo::TypeConstructor(_) => { TypeInfo::Class(_) => {
panic!() panic!()
} }
TypeInfo::Instance(left_instance_type_info) => match right { TypeInfo::Instance(left_instance_type_info) => match right {

View File

@ -4,6 +4,7 @@ use std::rc::Rc;
pub type ScopeId = usize; pub type ScopeId = usize;
#[derive(Debug, Clone)]
pub struct Scope { pub struct Scope {
parent_id: Option<ScopeId>, parent_id: Option<ScopeId>,
symbols: HashMap<Rc<str>, SymbolId>, symbols: HashMap<Rc<str>, SymbolId>,
@ -21,6 +22,10 @@ impl Scope {
self.parent_id 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<str>, symbol_id: SymbolId) { pub fn insert_symbol(&mut self, declared_name: Rc<str>, symbol_id: SymbolId) {
self.symbols.insert(declared_name, symbol_id); self.symbols.insert(declared_name, symbol_id);
} }

View File

@ -5,7 +5,7 @@ use std::rc::Rc;
pub type SymbolId = usize; pub type SymbolId = usize;
#[derive(Debug)] #[derive(Debug, Clone)]
pub enum Symbol { pub enum Symbol {
Class(ClassSymbol), Class(ClassSymbol),
Field(FieldSymbol), Field(FieldSymbol),
@ -60,7 +60,7 @@ impl Symbol {
} }
} }
#[derive(Debug)] #[derive(Debug, Clone)]
pub struct ClassSymbol { pub struct ClassSymbol {
declared_name: Rc<str>, declared_name: Rc<str>,
source_range: Option<SourceRange>, source_range: Option<SourceRange>,
@ -129,7 +129,7 @@ impl ClassSymbol {
} }
} }
#[derive(Debug)] #[derive(Debug, Clone)]
pub struct FieldSymbol { pub struct FieldSymbol {
declared_name: Rc<str>, declared_name: Rc<str>,
declared_name_source_range: Option<SourceRange>, declared_name_source_range: Option<SourceRange>,
@ -156,7 +156,7 @@ impl FieldSymbol {
} }
} }
#[derive(Debug)] #[derive(Debug, Clone)]
pub enum FunctionType { pub enum FunctionType {
Function, Function,
Constructor, Constructor,
@ -164,7 +164,7 @@ pub enum FunctionType {
StaticMethod, StaticMethod,
} }
#[derive(Debug)] #[derive(Debug, Clone)]
pub struct FunctionSymbol { pub struct FunctionSymbol {
declared_name: Rc<str>, declared_name: Rc<str>,
declared_name_source_range: Option<SourceRange>, declared_name_source_range: Option<SourceRange>,
@ -219,7 +219,7 @@ impl FunctionSymbol {
} }
} }
#[derive(Debug)] #[derive(Debug, Clone)]
pub struct ParameterSymbol { pub struct ParameterSymbol {
name: Rc<str>, name: Rc<str>,
source_range: Option<SourceRange>, source_range: Option<SourceRange>,
@ -243,7 +243,7 @@ impl ParameterSymbol {
} }
} }
#[derive(Debug)] #[derive(Debug, Clone)]
pub struct VariableSymbol { pub struct VariableSymbol {
name: Rc<str>, name: Rc<str>,
source_range: Option<SourceRange>, source_range: Option<SourceRange>,

View File

@ -10,16 +10,14 @@ pub fn collect_types(compilation_unit: &CompilationUnit, ctx: &mut AnalysisConte
} }
fn collect_types_class(class: &Class, ctx: &mut AnalysisContext) { fn collect_types_class(class: &Class, ctx: &mut AnalysisContext) {
let class_symbol_id = *ctx let maybe_constructor_type_info_id = class
.nodes_to_symbols() .constructor()
.get(&class.node_id()) .and_then(|constructor| ctx.get_symbol_id(constructor.node_id()));
.expect(&format!(
"Could not find class symbol for {} {}",
class.node_id(),
class.declared_name()
));
let self_instance_type_info = TypeInfo::Instance(InstanceTypeInfo::new(class_symbol_id)); let class_symbol_id = ctx.get_symbol_id(class.node_id()).expect(&format!(
let self_instance_type_info_id = ctx.insert_type_info(self_instance_type_info); "Could not find symbol for {} {}",
ctx.associate_symbol_to_type(class_symbol_id, self_instance_type_info_id) class.node_id(),
class.declared_name()
));
ctx.make_class_type(class_symbol_id, maybe_constructor_type_info_id);
} }

View File

@ -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 collect;
mod infer; mod infer;
mod resolve; 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);
}

View File

@ -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!()
}

View File

@ -6,9 +6,9 @@ pub type TypeInfoId = usize;
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub enum TypeInfo { pub enum TypeInfo {
Any, Any,
Function(FunctionTypeInfo), Class(ClassTypeInfo),
Constructor(ConstructorTypeInfo), Constructor(ConstructorTypeInfo),
TypeConstructor(TypeConstructorInfo), Function(FunctionTypeInfo),
Instance(InstanceTypeInfo), Instance(InstanceTypeInfo),
Int, Int,
Double, Double,
@ -24,9 +24,9 @@ impl TypeInfo {
} }
} }
pub fn unwrap_type_constructor(&self) -> &TypeConstructorInfo { pub fn unwrap_class(&self) -> &ClassTypeInfo {
match self { 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), _ => panic!("Attempt to unwrap {:?} as TypeConstructor", self),
} }
} }
@ -89,16 +89,16 @@ impl ConstructorTypeInfo {
} }
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct TypeConstructorInfo { pub struct ClassTypeInfo {
class_symbol_id: SymbolId, class_symbol_id: SymbolId,
constructor_type_info_id: Option<TypeInfoId>, constructor_symbol_id: Option<SymbolId>,
} }
impl TypeConstructorInfo { impl ClassTypeInfo {
pub fn new(class_symbol_id: SymbolId, constructor_type_info_id: Option<TypeInfoId>) -> Self { pub fn new(class_symbol_id: SymbolId, constructor_symbol_id: Option<SymbolId>) -> Self {
Self { Self {
class_symbol_id, class_symbol_id,
constructor_type_info_id, constructor_symbol_id,
} }
} }
@ -106,8 +106,8 @@ impl TypeConstructorInfo {
self.class_symbol_id self.class_symbol_id
} }
pub fn constructor_type_info_id(&self) -> Option<TypeInfoId> { pub fn constructor_type_info_id(&self) -> Option<SymbolId> {
self.constructor_type_info_id self.constructor_symbol_id
} }
} }