From 4e8fa159c0e1d871deb53cde22855f8840db3dc0 Mon Sep 17 00:00:00 2001 From: Jesse Brault Date: Fri, 20 Mar 2026 20:39:03 -0500 Subject: [PATCH] Fewer tests failing. WIP. --- dmc-lib/src/ast/assign_statement.rs | 18 ++-- dmc-lib/src/ast/class.rs | 70 +++++++++---- dmc-lib/src/ast/compilation_unit.rs | 26 ++++- dmc-lib/src/ast/constructor.rs | 10 +- dmc-lib/src/ast/diagnostic_factories.rs | 15 ++- dmc-lib/src/ast/expression.rs | 4 +- dmc-lib/src/ast/extern_function.rs | 40 +++++-- dmc-lib/src/ast/field.rs | 133 ++++++++++++------------ dmc-lib/src/ast/function.rs | 26 ++++- dmc-lib/src/ast/generic_parameter.rs | 9 +- dmc-lib/src/ast/identifier.rs | 6 +- dmc-lib/src/ast/ir_util.rs | 7 +- dmc-lib/src/ast/let_statement.rs | 10 +- dmc-lib/src/ast/parameter.rs | 9 +- dmc-lib/src/ast/type_use.rs | 56 ++++++---- dmc-lib/src/error_codes.rs | 1 + dmc-lib/src/ir/ir_block.rs | 7 +- dmc-lib/src/symbol/field_symbol.rs | 22 +--- dmc-lib/src/symbol_table/mod.rs | 32 +++++- dmc-lib/src/type_info.rs | 27 ----- e2e-tests/src/lib.rs | 5 +- sketching/march_2026/traits_and_ints.dm | 47 +++++++++ 22 files changed, 382 insertions(+), 198 deletions(-) create mode 100644 sketching/march_2026/traits_and_ints.dm diff --git a/dmc-lib/src/ast/assign_statement.rs b/dmc-lib/src/ast/assign_statement.rs index 5f04377..1e951fa 100644 --- a/dmc-lib/src/ast/assign_statement.rs +++ b/dmc-lib/src/ast/assign_statement.rs @@ -202,8 +202,10 @@ impl AssignStatement { let ir_statement = match destination_symbol { ExpressibleSymbol::Field(field_symbol) => { + let field_type = types_table.field_types().get(&field_symbol).unwrap(); let mut_field_pointer_variable = - get_or_init_mut_field_pointer_variable(builder, &field_symbol).clone(); + get_or_init_mut_field_pointer_variable(builder, &field_symbol, field_type) + .clone(); let ir_set_field = IrSetField::new( &mut_field_pointer_variable, self.value @@ -240,10 +242,11 @@ mod tests { fn compile_up_to_type_check( compilation_unit: &mut CompilationUnit, symbol_table: &mut SymbolTable, - ) -> Result<(), Vec> { + ) -> Result> { compilation_unit.init_scopes(symbol_table); compilation_unit.gather_symbols_into(symbol_table)?; - compilation_unit.check_names(symbol_table) + compilation_unit.check_names(symbol_table)?; + compilation_unit.gather_types(symbol_table) } #[test] @@ -258,8 +261,7 @@ mod tests { ) .unwrap(); let mut symbol_table = SymbolTable::new(); - compile_up_to_type_check(&mut compilation_unit, &mut symbol_table)?; - let mut types_table = TypesTable::new(); + let mut types_table = compile_up_to_type_check(&mut compilation_unit, &mut symbol_table)?; let diagnostics = compilation_unit .type_check(&symbol_table, &mut types_table) .unwrap_err(); @@ -281,8 +283,7 @@ mod tests { ", )?; let mut symbol_table = SymbolTable::new(); - compile_up_to_type_check(&mut compilation_unit, &mut symbol_table)?; - let mut types_table = TypesTable::new(); + let mut types_table = compile_up_to_type_check(&mut compilation_unit, &mut symbol_table)?; let diagnostics = compilation_unit .type_check(&symbol_table, &mut types_table) .unwrap_err(); @@ -302,8 +303,7 @@ mod tests { ", )?; let mut symbol_table = SymbolTable::new(); - compile_up_to_type_check(&mut compilation_unit, &mut symbol_table)?; - let mut types_table = TypesTable::new(); + let mut types_table = compile_up_to_type_check(&mut compilation_unit, &mut symbol_table)?; let diagnostics = compilation_unit .type_check(&symbol_table, &mut types_table) .unwrap_err(); diff --git a/dmc-lib/src/ast/class.rs b/dmc-lib/src/ast/class.rs index 12b4a87..7d93ff6 100644 --- a/dmc-lib/src/ast/class.rs +++ b/dmc-lib/src/ast/class.rs @@ -12,7 +12,6 @@ use crate::diagnostic::Diagnostic; use crate::error_codes::{FIELD_MULTIPLE_INIT, FIELD_UNINIT}; use crate::ir::ir_class::{IrClass, IrField}; use crate::ir::ir_function::IrFunction; -use crate::ok_or_err_diagnostics; use crate::source_range::SourceRange; use crate::symbol::Symbol; use crate::symbol::class_symbol::ClassSymbol; @@ -21,6 +20,7 @@ use crate::symbol::variable_symbol::VariableSymbol; use crate::symbol_table::SymbolTable; use crate::type_info::TypeInfo; use crate::types_table::TypesTable; +use crate::{diagnostics_result, handle_diagnostics, ok_or_err_diagnostics}; use std::collections::{HashMap, HashSet}; use std::rc::Rc; @@ -64,8 +64,8 @@ impl Class { generic_parameter.init_scopes(symbol_table, class_scope); } - let class_body_scope = - symbol_table.push_class_scope(&format!("class_body_scope({})", self.declared_name)); + let class_body_scope = symbol_table + .push_class_body_scope(&format!("class_body_scope({})", self.declared_name)); for field in &mut self.fields { field.init_scopes(symbol_table, class_body_scope); @@ -93,8 +93,8 @@ impl Class { } let mut field_symbols = Vec::new(); - for field in &self.fields { - let symbol = Rc::new(field.make_symbol()); + for (field_index, field) in self.fields.iter().enumerate() { + let symbol = Rc::new(field.make_symbol(field_index)); all_symbols.push(Symbol::Field(symbol.clone())); field_symbols.push(symbol); } @@ -164,11 +164,15 @@ impl Class { diagnostics } - pub fn check_field_initializer_names(&self, symbol_table: &SymbolTable) -> Vec { - let class_symbol = symbol_table + fn get_class_symbol_owned(&self, symbol_table: &SymbolTable) -> Rc { + symbol_table .get_class_symbol(self.scope_id.unwrap(), &self.declared_name) .cloned() - .unwrap(); + .unwrap() + } + + pub fn check_field_initializer_names(&self, symbol_table: &SymbolTable) -> Vec { + let class_symbol = self.get_class_symbol_owned(symbol_table); self.fields .iter() .flat_map(|field| field.check_field_initializer_names(symbol_table, &class_symbol)) @@ -176,11 +180,7 @@ impl Class { } pub fn analyze_local_names(&self, symbol_table: &mut SymbolTable) -> Vec { - let class_symbol = symbol_table - .get_class_symbol(self.scope_id.unwrap(), &self.declared_name) - .cloned() - .unwrap(); - + let class_symbol = self.get_class_symbol_owned(symbol_table); let mut diagnostics: Vec = Vec::new(); if let Some(constructor) = &self.constructor { diagnostics.append(&mut constructor.analyze_local_names(symbol_table, &class_symbol)); @@ -192,9 +192,39 @@ impl Class { diagnostics } - fn type_check_generics(&mut self, symbol_table: &SymbolTable) -> Result<(), Vec> { + pub fn gather_types( + &self, + symbol_table: &SymbolTable, + types_table: &mut TypesTable, + ) -> Result<(), Vec> { + // instance type + let class_symbol = self.get_class_symbol_owned(symbol_table); + types_table + .class_instance_types_mut() + .insert(class_symbol.clone(), TypeInfo::ClassInstance(class_symbol)); + + let mut diagnostics = Vec::new(); + + // field types + for field in &self.fields { + handle_diagnostics!(field.gather_types(symbol_table, types_table), diagnostics); + } + + // function return types + for function in &self.functions { + function.gather_types(symbol_table, types_table); + } + + diagnostics_result!(diagnostics) + } + + fn type_check_generics( + &mut self, + symbol_table: &SymbolTable, + types_table: &TypesTable, + ) -> Result<(), Vec> { collect_diagnostics_mut(&mut self.generic_parameters, |gp| { - gp.type_check(symbol_table) + gp.type_check(symbol_table, types_table) }) } @@ -373,7 +403,7 @@ impl Class { symbol_table: &SymbolTable, types_table: &mut TypesTable, ) -> Result<(), Vec> { - self.type_check_generics(symbol_table)?; + self.type_check_generics(symbol_table, types_table)?; self.type_check_fields(symbol_table, types_table)?; self.type_check_constructor(symbol_table, types_table)?; self.type_check_functions(symbol_table, types_table)?; @@ -410,10 +440,14 @@ impl Class { self.fields .iter() .map(|field| { + let field_symbol = symbol_table + .get_field_symbol_owned(field.scope_id(), field.declared_name()) + .unwrap(); + let field_type = types_table.field_types().get(&field_symbol).unwrap(); IrField::new( field.declared_name().into(), - field.field_symbol().borrow().field_index(), - field.field_symbol().borrow().type_info().clone(), + field_symbol.field_index(), + field_type.clone(), ) }) .collect(), diff --git a/dmc-lib/src/ast/compilation_unit.rs b/dmc-lib/src/ast/compilation_unit.rs index a3f481c..008a633 100644 --- a/dmc-lib/src/ast/compilation_unit.rs +++ b/dmc-lib/src/ast/compilation_unit.rs @@ -8,7 +8,7 @@ use crate::ir::ir_class::IrClass; use crate::ir::ir_function::IrFunction; use crate::symbol_table::SymbolTable; use crate::types_table::TypesTable; -use crate::{diagnostics_result, handle_diagnostics}; +use crate::{diagnostics_result, handle_diagnostics, ok_or_err_diagnostics}; pub struct CompilationUnit { functions: Vec, @@ -95,6 +95,28 @@ impl CompilationUnit { diagnostics_result!(diagnostics) } + pub fn gather_types(&self, symbol_table: &SymbolTable) -> Result> { + let mut types_table = TypesTable::new(); + let mut diagnostics = Vec::new(); + + for class in &self.classes { + handle_diagnostics!( + class.gather_types(symbol_table, &mut types_table), + diagnostics + ); + } + + for function in &self.functions { + function.gather_types(symbol_table, &mut types_table); + } + + for extern_function in &self.extern_functions { + extern_function.gather_types(symbol_table, &mut types_table); + } + + ok_or_err_diagnostics!(types_table, diagnostics) + } + pub fn type_check( &mut self, symbol_table: &SymbolTable, @@ -110,7 +132,7 @@ impl CompilationUnit { collect_diagnostics_into_mut( &mut self.extern_functions, - |ef| ef.type_check(symbol_table), + |ef| ef.type_check(symbol_table, types_table), &mut diagnostics, ); diff --git a/dmc-lib/src/ast/constructor.rs b/dmc-lib/src/ast/constructor.rs index 4e28307..a58753d 100644 --- a/dmc-lib/src/ast/constructor.rs +++ b/dmc-lib/src/ast/constructor.rs @@ -121,7 +121,7 @@ impl Constructor { let parameters_diagnostics: Vec = self .parameters .iter_mut() - .map(|param| param.type_check(symbol_table)) + .map(|param| param.type_check(symbol_table, types_table)) .filter_map(Result::err) .flatten() .collect(); @@ -206,16 +206,20 @@ impl Constructor { // next, initialize fields that have an initializer in their declaration for field in fields { if let Some(initializer) = field.initializer() { + let field_symbol = symbol_table + .get_field_symbol_owned(field.scope_id(), field.declared_name()) + .unwrap(); + let field_type = types_table.field_types().get(&field_symbol).unwrap(); // get a mut ref to the field let ir_get_field_ref_mut = IrGetFieldRefMut::new( IrParameterOrVariable::Variable(self_variable.clone()), - field.field_symbol().borrow().field_index(), + field_symbol.field_index(), ); let field_mut_ref_variable_name: Rc = ir_builder.new_t_var().into(); let field_mut_ref_variable = Rc::new(RefCell::new(IrVariable::new_vr( field_mut_ref_variable_name.clone(), ir_builder.current_block().id(), - field.field_symbol().borrow().type_info(), + field_type, ))); let field_mut_ref_assign = IrAssign::new( field_mut_ref_variable.clone(), diff --git a/dmc-lib/src/ast/diagnostic_factories.rs b/dmc-lib/src/ast/diagnostic_factories.rs index 479d952..9768ca1 100644 --- a/dmc-lib/src/ast/diagnostic_factories.rs +++ b/dmc-lib/src/ast/diagnostic_factories.rs @@ -1,7 +1,8 @@ use crate::diagnostic::{Diagnostic, SecondaryLabel}; use crate::error_codes::{ - OUTER_CLASS_FIELD_USED_IN_INIT, OUTER_CLASS_METHOD_USED_IN_INIT, SELF_CONSTRUCTOR_USED_IN_INIT, - SELF_FIELD_USED_IN_INIT, SELF_METHOD_USED_IN_INIT, SYMBOL_ALREADY_DECLARED, SYMBOL_NOT_FOUND, + FIELD_NO_TYPE_OR_INIT, OUTER_CLASS_FIELD_USED_IN_INIT, OUTER_CLASS_METHOD_USED_IN_INIT, + SELF_CONSTRUCTOR_USED_IN_INIT, SELF_FIELD_USED_IN_INIT, SELF_METHOD_USED_IN_INIT, + SYMBOL_ALREADY_DECLARED, SYMBOL_NOT_FOUND, }; use crate::source_range::SourceRange; use crate::symbol::Symbol; @@ -15,6 +16,16 @@ pub fn symbol_not_found(name: &str, source_range: &SourceRange) -> Diagnostic { .with_error_code(SYMBOL_NOT_FOUND) } +pub fn field_has_no_type_or_init(name: &str, source_range: &SourceRange) -> Diagnostic { + Diagnostic::new( + &format!("Field {} has no declared type nor initializer.", name), + source_range.start(), + source_range.end(), + ) + .with_error_code(FIELD_NO_TYPE_OR_INIT) + .with_primary_label_message("Declare a type and/or an initializer.") +} + pub fn cannot_reference_field_in_init(name: &str, source_range: &SourceRange) -> Diagnostic { Diagnostic::new( &format!("Cannot reference field {} during initialization.", name), diff --git a/dmc-lib/src/ast/expression.rs b/dmc-lib/src/ast/expression.rs index 5f21cef..637e8fc 100644 --- a/dmc-lib/src/ast/expression.rs +++ b/dmc-lib/src/ast/expression.rs @@ -230,7 +230,7 @@ impl Expression { IrOperation::Load(IrExpression::String(string_literal.content().into())) } Expression::Identifier(identifier) => { - IrOperation::Load(identifier.ir_expression(builder, symbol_table)) + IrOperation::Load(identifier.ir_expression(builder, symbol_table, types_table)) } Expression::Negative(negative_expression) => { IrOperation::Load(negative_expression.to_ir(builder, symbol_table, types_table)) @@ -276,7 +276,7 @@ impl Expression { } } Expression::Identifier(identifier) => { - Some(identifier.ir_expression(builder, symbol_table)) + Some(identifier.ir_expression(builder, symbol_table, types_table)) } Expression::Integer(integer_literal) => { Some(IrExpression::Int(integer_literal.value())) diff --git a/dmc-lib/src/ast/extern_function.rs b/dmc-lib/src/ast/extern_function.rs index 9e0f451..c521a80 100644 --- a/dmc-lib/src/ast/extern_function.rs +++ b/dmc-lib/src/ast/extern_function.rs @@ -7,8 +7,8 @@ use crate::source_range::SourceRange; use crate::symbol::Symbol; use crate::symbol::function_symbol::FunctionSymbol; use crate::symbol_table::SymbolTable; +use crate::types_table::TypesTable; use crate::{diagnostics_result, handle_diagnostics}; -use std::cell::RefCell; use std::rc::Rc; pub struct ExternFunction { @@ -17,7 +17,6 @@ pub struct ExternFunction { parameters: Vec, return_type: TypeUse, scope_id: Option, - function_symbol: Option>>, } impl ExternFunction { @@ -26,14 +25,13 @@ impl ExternFunction { declared_name_source_range: SourceRange, parameters: Vec, return_type: TypeUse, - ) -> ExternFunction { - ExternFunction { + ) -> Self { + Self { declared_name: name.into(), declared_name_source_range, parameters, return_type, scope_id: None, - function_symbol: None, } } @@ -83,14 +81,28 @@ impl ExternFunction { diagnostics } + pub fn gather_types(&self, symbol_table: &SymbolTable, types_table: &mut TypesTable) { + let function_symbol = symbol_table + .get_function_symbol_owned(self.scope_id.unwrap(), self.declared_name()) + .unwrap(); + let resolved_return_type = self + .return_type + .type_info(symbol_table, types_table) + .clone(); + types_table + .function_return_types_mut() + .insert(function_symbol, resolved_return_type); + } + fn type_check_parameters( &mut self, symbol_table: &SymbolTable, + types_table: &TypesTable, diagnostics: &mut Vec, ) { collect_diagnostics_into_mut( &mut self.parameters, - |p| p.type_check(symbol_table), + |p| p.type_check(symbol_table, types_table), diagnostics, ); } @@ -98,16 +110,24 @@ impl ExternFunction { fn type_check_return_type( &mut self, symbol_table: &SymbolTable, + types_table: &TypesTable, diagnostics: &mut Vec, ) { - handle_diagnostics!(self.return_type.type_check(symbol_table), diagnostics); + handle_diagnostics!( + self.return_type.type_check(symbol_table, types_table), + diagnostics + ); } - pub fn type_check(&mut self, symbol_table: &SymbolTable) -> Result<(), Vec> { + pub fn type_check( + &mut self, + symbol_table: &SymbolTable, + types_table: &TypesTable, + ) -> Result<(), Vec> { let mut diagnostics: Vec = vec![]; - self.type_check_parameters(symbol_table, &mut diagnostics); - self.type_check_return_type(symbol_table, &mut diagnostics); + self.type_check_parameters(symbol_table, types_table, &mut diagnostics); + self.type_check_return_type(symbol_table, types_table, &mut diagnostics); diagnostics_result!(diagnostics) } diff --git a/dmc-lib/src/ast/field.rs b/dmc-lib/src/ast/field.rs index 9a29c94..a9a9581 100644 --- a/dmc-lib/src/ast/field.rs +++ b/dmc-lib/src/ast/field.rs @@ -1,3 +1,4 @@ +use crate::ast::diagnostic_factories::field_has_no_type_or_init; use crate::ast::expression::Expression; use crate::ast::type_use::TypeUse; use crate::diagnostic::Diagnostic; @@ -6,7 +7,6 @@ use crate::symbol::class_symbol::ClassSymbol; use crate::symbol::field_symbol::FieldSymbol; use crate::symbol_table::SymbolTable; use crate::types_table::TypesTable; -use std::cell::RefCell; use std::rc::Rc; pub struct Field { @@ -17,7 +17,6 @@ pub struct Field { declared_type: Option>, initializer: Option>, scope_id: Option, - field_symbol: Option>>, } impl Field { @@ -37,7 +36,6 @@ impl Field { declared_type: declared_type.map(Box::new), initializer: initializer.map(Box::new), scope_id: None, - field_symbol: None, } } @@ -67,12 +65,17 @@ impl Field { } } - pub fn make_symbol(&self) -> FieldSymbol { + pub fn scope_id(&self) -> usize { + self.scope_id.unwrap() + } + + pub fn make_symbol(&self, field_index: usize) -> FieldSymbol { FieldSymbol::new( &self.declared_name, self.declared_name_source_range.clone(), self.is_mut, self.scope_id.unwrap(), + field_index, ) } @@ -96,6 +99,41 @@ impl Field { } } + pub fn gather_types( + &self, + symbol_table: &SymbolTable, + types_table: &mut TypesTable, + ) -> Result<(), Vec> { + // self field + let field_symbol = symbol_table + .get_field_symbol_owned(self.scope_id.unwrap(), &self.declared_name) + .unwrap(); + match &self.declared_type { + Some(declared_type) => { + let resolved_type = declared_type.type_info(symbol_table, types_table).clone(); + types_table + .field_types_mut() + .insert(field_symbol, resolved_type); + } + None => match &self.initializer { + Some(initializer) => { + let initializer_type = initializer.type_info(symbol_table, types_table).clone(); + types_table + .field_types_mut() + .insert(field_symbol, initializer_type); + } + None => { + // this is an error + return Err(vec![field_has_no_type_or_init( + self.declared_name(), + self.declared_name_source_range(), + )]); + } + }, + } + Ok(()) + } + pub fn type_check( &mut self, symbol_table: &SymbolTable, @@ -104,7 +142,9 @@ impl Field { let mut diagnostics: Vec = vec![]; if let Some(type_use) = &mut self.declared_type { - if let Some(mut type_use_diagnostics) = type_use.type_check(symbol_table).err() { + if let Some(mut type_use_diagnostics) = + type_use.type_check(symbol_table, types_table).err() + { diagnostics.append(&mut type_use_diagnostics); } } @@ -121,68 +161,31 @@ impl Field { return Err(diagnostics); } - // Now check that types are assignable, and update field symbol's type info - let field_type_info = - match self.declared_type.as_ref() { - Some(type_use) => { - match self.initializer.as_ref() { - Some(initializer) => { - let initializer_type_info = - initializer.type_info(symbol_table, types_table); - let declared_type_info = type_use.type_info(); - if declared_type_info.is_assignable_from(initializer_type_info) { - declared_type_info - } else { - return Err(vec![ - Diagnostic::new( - &format!( - "Mismatched types: {} is not assignable to {}", - initializer_type_info, declared_type_info - ), - initializer.source_range().start(), - initializer.source_range().end(), - ) - .with_reporter(file!(), line!()), - ]); - } - } - None => { - // easy: the declared type - type_use.type_info() - } + // Now check that types are assignable + match self.declared_type.as_ref() { + Some(type_use) => match self.initializer.as_ref() { + Some(initializer) => { + let initializer_type_info = initializer.type_info(symbol_table, types_table); + let declared_type_info = type_use.type_info(symbol_table, types_table); + if declared_type_info.is_assignable_from(initializer_type_info) { + Ok(()) + } else { + Err(vec![ + Diagnostic::new( + &format!( + "Mismatched types: {} is not assignable to {}", + initializer_type_info, declared_type_info + ), + initializer.source_range().start(), + initializer.source_range().end(), + ) + .with_reporter(file!(), line!()), + ]) } } - None => { - // type is the initializer - match self.initializer.as_ref() { - Some(initializer) => initializer.type_info(symbol_table, types_table), - None => { - // this is an error - return Err(vec![Diagnostic::new( - "Field must have either a declared type or initializer, or both.", - self.declared_name_source_range.start(), - self.declared_name_source_range.end(), - ).with_reporter(file!(), line!())]); - } - } - } - }; - - // update field symbol's type info - self.field_symbol - .as_mut() - .unwrap() - .borrow_mut() - .set_type_info(field_type_info.clone()); - - if diagnostics.is_empty() { - Ok(()) - } else { - Err(diagnostics) + None => Ok(()), + }, + None => Ok(()), } } - - pub fn field_symbol(&self) -> &Rc> { - self.field_symbol.as_ref().unwrap() - } } diff --git a/dmc-lib/src/ast/function.rs b/dmc-lib/src/ast/function.rs index caec2f5..5fd78e5 100644 --- a/dmc-lib/src/ast/function.rs +++ b/dmc-lib/src/ast/function.rs @@ -137,6 +137,22 @@ impl Function { .collect() } + pub fn gather_types(&self, symbol_table: &SymbolTable, types_table: &mut TypesTable) { + let function_symbol = symbol_table + .get_function_symbol_owned(self.scope_id.unwrap(), self.declared_name()) + .unwrap(); + if let Some(type_use) = &self.return_type { + let resolved_return_type = type_use.type_info(symbol_table, types_table).clone(); + types_table + .function_return_types_mut() + .insert(function_symbol, resolved_return_type); + } else { + types_table + .function_return_types_mut() + .insert(function_symbol, TypeInfo::Void); + } + } + fn get_return_type_info( types_table: &TypesTable, function_symbol: &FunctionSymbol, @@ -152,11 +168,12 @@ impl Function { fn type_check_parameters( &mut self, symbol_table: &SymbolTable, + types_table: &TypesTable, diagnostics: &mut Vec, ) { collect_diagnostics_into_mut( &mut self.parameters, - |p| p.type_check(symbol_table), + |p| p.type_check(symbol_table, types_table), diagnostics, ) } @@ -165,10 +182,11 @@ impl Function { fn type_check_return_type( &mut self, symbol_table: &SymbolTable, + types_table: &TypesTable, diagnostics: &mut Vec, ) { if let Some(type_use) = &mut self.return_type { - handle_diagnostics!(type_use.type_check(symbol_table), diagnostics); + handle_diagnostics!(type_use.type_check(symbol_table, types_table), diagnostics); } } @@ -208,10 +226,10 @@ impl Function { .unwrap(); // parameters - self.type_check_parameters(symbol_table, &mut diagnostics); + self.type_check_parameters(symbol_table, types_table, &mut diagnostics); // return type - self.type_check_return_type(symbol_table, &mut diagnostics); + self.type_check_return_type(symbol_table, types_table, &mut diagnostics); // statements self.type_check_statements(symbol_table, types_table, &mut diagnostics, function_symbol); diff --git a/dmc-lib/src/ast/generic_parameter.rs b/dmc-lib/src/ast/generic_parameter.rs index a346c16..354c507 100644 --- a/dmc-lib/src/ast/generic_parameter.rs +++ b/dmc-lib/src/ast/generic_parameter.rs @@ -3,6 +3,7 @@ use crate::diagnostic::Diagnostic; use crate::source_range::SourceRange; use crate::symbol::generic_parameter_symbol::GenericParameterSymbol; use crate::symbol_table::SymbolTable; +use crate::types_table::TypesTable; use crate::{diagnostics_result, handle_diagnostics}; use std::cell::RefCell; use std::rc::Rc; @@ -52,11 +53,15 @@ impl GenericParameter { .collect() } - pub fn type_check(&mut self, symbol_table: &SymbolTable) -> Result<(), Vec> { + pub fn type_check( + &mut self, + symbol_table: &SymbolTable, + types_table: &TypesTable, + ) -> Result<(), Vec> { let mut diagnostics: Vec = vec![]; // check extends type uses for type_use in &mut self.extends { - handle_diagnostics!(type_use.type_check(symbol_table), diagnostics); + handle_diagnostics!(type_use.type_check(symbol_table, types_table), diagnostics); } diagnostics_result!(diagnostics) } diff --git a/dmc-lib/src/ast/identifier.rs b/dmc-lib/src/ast/identifier.rs index e2a16b7..7511f2b 100644 --- a/dmc-lib/src/ast/identifier.rs +++ b/dmc-lib/src/ast/identifier.rs @@ -234,6 +234,7 @@ impl Identifier { &self, builder: &mut IrBuilder, symbol_table: &SymbolTable, + types_table: &TypesTable, ) -> IrExpression { let expressible_symbol = symbol_table .find_expressible_symbol(self.scope_id.unwrap(), &self.name) @@ -243,14 +244,15 @@ impl Identifier { todo!() } ExpressibleSymbol::Field(field_symbol) => { + let field_type = types_table.field_types().get(&field_symbol).unwrap(); let read_destination = IrVariable::new_vr( builder.new_t_var().into(), builder.current_block().id(), - field_symbol.type_info(), + field_type, ); let read_destination_as_rc = Rc::new(RefCell::new(read_destination)); let ir_read_field = IrReadField::new( - get_or_init_field_pointer_variable(builder, &field_symbol).clone(), + get_or_init_field_pointer_variable(builder, &field_symbol, field_type).clone(), ); builder .current_block_mut() diff --git a/dmc-lib/src/ast/ir_util.rs b/dmc-lib/src/ast/ir_util.rs index 80eaa49..7ab9053 100644 --- a/dmc-lib/src/ast/ir_util.rs +++ b/dmc-lib/src/ast/ir_util.rs @@ -6,12 +6,14 @@ use crate::ir::ir_operation::IrOperation; use crate::ir::ir_statement::IrStatement; use crate::ir::ir_variable::IrVariable; use crate::symbol::field_symbol::FieldSymbol; +use crate::type_info::TypeInfo; use std::cell::RefCell; use std::rc::Rc; pub fn get_or_init_field_pointer_variable<'a>( builder: &'a mut IrBuilder, field_symbol: &Rc, + field_type: &TypeInfo, ) -> &'a Rc> { // This following should work because blocks are flat in the ir; if a variable is defined in the // ir block from this point forward, it's available to all subsequent blocks. @@ -22,7 +24,7 @@ pub fn get_or_init_field_pointer_variable<'a>( let field_ref_variable = IrVariable::new_vr( builder.new_t_var().into(), builder.current_block().id(), - field_symbol.type_info(), + field_type, ); let as_rc = Rc::new(RefCell::new(field_ref_variable)); let to_insert = as_rc.clone(); @@ -49,6 +51,7 @@ pub fn get_or_init_field_pointer_variable<'a>( pub fn get_or_init_mut_field_pointer_variable<'a>( builder: &'a mut IrBuilder, field_symbol: &Rc, + field_type: &TypeInfo, ) -> &'a Rc> { if !builder .field_mut_pointer_variables() @@ -57,7 +60,7 @@ pub fn get_or_init_mut_field_pointer_variable<'a>( let mut_field_pointer_variable = IrVariable::new_vr( builder.new_t_var().into(), builder.current_block().id(), - field_symbol.type_info(), + field_type, ); let as_rc = Rc::new(RefCell::new(mut_field_pointer_variable)); let to_insert = as_rc.clone(); diff --git a/dmc-lib/src/ast/let_statement.rs b/dmc-lib/src/ast/let_statement.rs index c93db3d..88dbdcc 100644 --- a/dmc-lib/src/ast/let_statement.rs +++ b/dmc-lib/src/ast/let_statement.rs @@ -128,13 +128,19 @@ impl LetStatement { pub fn type_check( &mut self, symbol_table: &SymbolTable, - types_table: &TypesTable, + types_table: &mut TypesTable, ) -> Result<(), Vec> { self.initializer.type_check(symbol_table, types_table)?; - let initializer_type_info = self.initializer.type_info(symbol_table, types_table); + let initializer_type_info = self + .initializer + .type_info(symbol_table, types_table) + .clone(); let variable_symbol = symbol_table .get_variable_symbol_owned(self.scope_id.unwrap(), &self.declared_name) .unwrap(); + types_table + .variable_types_mut() + .insert(variable_symbol, initializer_type_info); Ok(()) } diff --git a/dmc-lib/src/ast/parameter.rs b/dmc-lib/src/ast/parameter.rs index 9fcb18b..61b0079 100644 --- a/dmc-lib/src/ast/parameter.rs +++ b/dmc-lib/src/ast/parameter.rs @@ -3,6 +3,7 @@ use crate::diagnostic::Diagnostic; use crate::source_range::SourceRange; use crate::symbol::parameter_symbol::ParameterSymbol; use crate::symbol_table::SymbolTable; +use crate::types_table::TypesTable; use std::rc::Rc; pub struct Parameter { @@ -51,8 +52,12 @@ impl Parameter { self.type_use.check_names(symbol_table) } - pub fn type_check(&mut self, symbol_table: &SymbolTable) -> Result<(), Vec> { - self.type_use.type_check(symbol_table)?; + pub fn type_check( + &mut self, + symbol_table: &SymbolTable, + types_table: &TypesTable, + ) -> Result<(), Vec> { + self.type_use.type_check(symbol_table, types_table)?; Ok(()) } } diff --git a/dmc-lib/src/ast/type_use.rs b/dmc-lib/src/ast/type_use.rs index 266bea2..2c4727b 100644 --- a/dmc-lib/src/ast/type_use.rs +++ b/dmc-lib/src/ast/type_use.rs @@ -3,10 +3,11 @@ use crate::diagnostic::Diagnostic; use crate::error_codes::INCORRECT_GENERIC_ARGUMENTS; use crate::source_range::SourceRange; use crate::symbol::class_symbol::ClassSymbol; +use crate::symbol::type_symbol::TypeSymbol; use crate::symbol_table::SymbolTable; use crate::type_info::TypeInfo; +use crate::types_table::TypesTable; use crate::{diagnostics_result, handle_diagnostics, maybe_return_diagnostics}; -use std::cell::RefCell; use std::rc::Rc; pub struct TypeUse { @@ -14,7 +15,6 @@ pub struct TypeUse { declared_name_source_range: SourceRange, generic_arguments: Vec, scope_id: Option, - type_info: Option, } impl TypeUse { @@ -28,7 +28,6 @@ impl TypeUse { declared_name_source_range, generic_arguments, scope_id: None, - type_info: None, } } @@ -86,14 +85,11 @@ impl TypeUse { ) -> Result<(), Vec> { let mut diagnostics: Vec = vec![]; - if let Some(type_info) = TypeInfo::from_declared_name( - &self.declared_name, - self.scope_id.unwrap(), - symbol_table, - class_context, - ) { - self.type_info = Some(type_info); - } else { + if symbol_table + .find_type_symbol(self.scope_id.unwrap(), &self.declared_name) + .is_none() + { + // this is wonky let diagnostic = Diagnostic::new( &format!("Unable to resolve symbol {}", self.declared_name), self.declared_name_source_range.start(), @@ -113,10 +109,33 @@ impl TypeUse { diagnostics_result!(diagnostics) } - pub fn type_check(&mut self, _symbol_table: &SymbolTable) -> Result<(), Vec> { + pub fn type_info<'a>( + &self, + symbol_table: &SymbolTable, + types_table: &'a TypesTable, + ) -> &'a TypeInfo { + let type_symbol = symbol_table + .find_type_symbol(self.scope_id.unwrap(), self.declared_name()) + .unwrap(); + match type_symbol { + TypeSymbol::Class(class_symbol) => types_table + .class_instance_types() + .get(&class_symbol) + .unwrap(), + TypeSymbol::GenericParameter(generic_parameter_symbol) => { + todo!(); + } + } + } + + pub fn type_check( + &mut self, + symbol_table: &SymbolTable, + types_table: &TypesTable, + ) -> Result<(), Vec> { let mut diagnostics: Vec = vec![]; - match self.type_info() { + match self.type_info(symbol_table, types_table) { TypeInfo::ClassInstance(class_symbol) => { // check number of params/args match let generic_parameters = class_symbol.generic_parameters(); @@ -151,7 +170,7 @@ impl TypeUse { let diagnostic = Diagnostic::new( &format!( "Type {} does not accept generic arguments.", - self.type_info() + self.type_info(symbol_table, types_table) ), self.declared_name_source_range.start(), self.declared_name_source_range.end(), @@ -165,15 +184,14 @@ impl TypeUse { // recurse on generic arguments for generic_argument in &mut self.generic_arguments { - handle_diagnostics!(generic_argument.type_check(_symbol_table), diagnostics); + handle_diagnostics!( + generic_argument.type_check(symbol_table, types_table), + diagnostics + ); } diagnostics_result!(diagnostics) } - - pub fn type_info(&self) -> &TypeInfo { - self.type_info.as_ref().unwrap() - } } #[cfg(test)] diff --git a/dmc-lib/src/error_codes.rs b/dmc-lib/src/error_codes.rs index 9ccd8f4..b8ab053 100644 --- a/dmc-lib/src/error_codes.rs +++ b/dmc-lib/src/error_codes.rs @@ -15,3 +15,4 @@ pub const SELF_METHOD_USED_IN_INIT: ErrorCode = 24; pub const SELF_CONSTRUCTOR_USED_IN_INIT: ErrorCode = 25; pub const OUTER_CLASS_FIELD_USED_IN_INIT: ErrorCode = 26; pub const OUTER_CLASS_METHOD_USED_IN_INIT: ErrorCode = 27; +pub const FIELD_NO_TYPE_OR_INIT: ErrorCode = 28; diff --git a/dmc-lib/src/ir/ir_block.rs b/dmc-lib/src/ir/ir_block.rs index eb6bbf7..78933d7 100644 --- a/dmc-lib/src/ir/ir_block.rs +++ b/dmc-lib/src/ir/ir_block.rs @@ -124,7 +124,6 @@ mod tests { use crate::diagnostic::Diagnostic; use crate::parser::parse_compilation_unit; use crate::symbol_table::SymbolTable; - use crate::types_table::TypesTable; #[test] fn overlapping_assignments_bug_when_k_2() -> Result<(), Vec> { @@ -137,14 +136,14 @@ mod tests { let x = a + b + c end ", - ) - .unwrap(); + )?; + let mut symbol_table = SymbolTable::new(); - let mut types_table = TypesTable::new(); compilation_unit.init_scopes(&mut symbol_table); compilation_unit.gather_symbols_into(&mut symbol_table)?; compilation_unit.check_names(&mut symbol_table)?; + let mut types_table = compilation_unit.gather_types(&symbol_table)?; compilation_unit.type_check(&mut symbol_table, &mut types_table)?; let main = compilation_unit diff --git a/dmc-lib/src/symbol/field_symbol.rs b/dmc-lib/src/symbol/field_symbol.rs index fd11ded..576dc91 100644 --- a/dmc-lib/src/symbol/field_symbol.rs +++ b/dmc-lib/src/symbol/field_symbol.rs @@ -1,5 +1,4 @@ use crate::source_range::SourceRange; -use crate::type_info::TypeInfo; use std::hash::{Hash, Hasher}; use std::rc::Rc; @@ -8,8 +7,7 @@ pub struct FieldSymbol { declared_name_source_range: SourceRange, is_mut: bool, scope_id: usize, - type_info: Option, - field_index: Option, + field_index: usize, } impl FieldSymbol { @@ -18,14 +16,14 @@ impl FieldSymbol { declared_name_source_range: SourceRange, is_mut: bool, scope_id: usize, + field_index: usize, ) -> Self { Self { declared_name: declared_name.clone(), declared_name_source_range, is_mut, scope_id, - type_info: None, - field_index: None, + field_index, } } @@ -49,20 +47,8 @@ impl FieldSymbol { self.is_mut } - pub fn set_type_info(&mut self, type_info: TypeInfo) { - self.type_info = Some(type_info); - } - - pub fn type_info(&self) -> &TypeInfo { - self.type_info.as_ref().unwrap() - } - - pub fn set_field_index(&mut self, field_index: usize) { - self.field_index = Some(field_index); - } - pub fn field_index(&self) -> usize { - self.field_index.unwrap() + self.field_index } } diff --git a/dmc-lib/src/symbol_table/mod.rs b/dmc-lib/src/symbol_table/mod.rs index a3a944a..3a15b5b 100644 --- a/dmc-lib/src/symbol_table/mod.rs +++ b/dmc-lib/src/symbol_table/mod.rs @@ -165,8 +165,8 @@ impl SymbolTable { pub fn insert_constructor_symbol(&mut self, constructor_symbol: Rc) { match self.scope_mut(constructor_symbol.scope_id()) { - Scope::ClassBody(class_scope) => { - class_scope + Scope::ClassBody(class_body_scope) => { + class_body_scope .constructor_symbol_mut() .replace(constructor_symbol); } @@ -298,6 +298,16 @@ impl SymbolTable { } } + pub fn get_field_symbol_owned(&self, scope_id: usize, name: &str) -> Option> { + match self.scope(scope_id) { + Scope::ClassBody(class_body_scope) => class_body_scope + .field_symbols() + .get(name) + .map(|s| Rc::clone(s)), + _ => panic!("scope_id {} is not a ClassBodyScope", scope_id), + } + } + pub fn get_constructor_symbol(&self, scope_id: usize) -> Option<&ConstructorSymbol> { match self.scope(scope_id) { Scope::ClassBody(class_body_scope) => { @@ -320,6 +330,24 @@ impl SymbolTable { } } + pub fn get_function_symbol_owned( + &self, + scope_id: usize, + name: &str, + ) -> Option> { + match self.scope(scope_id) { + Scope::Module(module_scope) => module_scope + .function_symbols() + .get(name) + .map(|s| Rc::clone(s)), + Scope::ClassBody(class_body_scope) => class_body_scope + .function_symbols() + .get(name) + .map(|s| Rc::clone(s)), + _ => panic!("scope_id {} cannot contain Functions", scope_id), + } + } + pub fn get_parameter_symbol(&self, scope_id: usize, name: &str) -> Option<&ParameterSymbol> { match self.scope(scope_id) { Scope::Function(function_scope) => { diff --git a/dmc-lib/src/type_info.rs b/dmc-lib/src/type_info.rs index 93ee5f3..de28bfe 100644 --- a/dmc-lib/src/type_info.rs +++ b/dmc-lib/src/type_info.rs @@ -1,8 +1,6 @@ use crate::symbol::class_symbol::ClassSymbol; use crate::symbol::function_symbol::FunctionSymbol; use crate::symbol::generic_parameter_symbol::GenericParameterSymbol; -use crate::symbol::type_symbol::TypeSymbol; -use crate::symbol_table::SymbolTable; use std::fmt::{Display, Formatter}; use std::rc::Rc; @@ -55,31 +53,6 @@ fn are_numbers(left: &TypeInfo, right: &TypeInfo) -> bool { } impl TypeInfo { - pub fn from_declared_name( - declared_name: &str, - scope_id: usize, - symbol_table: &SymbolTable, - class_context: Option<&Rc>, - ) -> Option { - match declared_name { - "Any" => Some(TypeInfo::Any), - "Int" => Some(TypeInfo::Integer), - "Double" => Some(TypeInfo::Double), - "String" => Some(TypeInfo::String), - "Void" => Some(TypeInfo::Void), - "Self" => Some(TypeInfo::ClassInstance(class_context.cloned().unwrap())), - _ => match symbol_table.find_type_symbol(scope_id, declared_name) { - None => None, - Some(type_symbol) => match type_symbol { - TypeSymbol::Class(class_symbol) => Some(TypeInfo::ClassInstance(class_symbol)), - TypeSymbol::GenericParameter(generic_parameter_symbol) => { - Some(TypeInfo::GenericType(generic_parameter_symbol)) - } - }, - }, - } - } - pub fn is_assignable_from(&self, other: &TypeInfo) -> bool { match self { TypeInfo::Any => true, diff --git a/e2e-tests/src/lib.rs b/e2e-tests/src/lib.rs index ae38b2d..9e27b22 100644 --- a/e2e-tests/src/lib.rs +++ b/e2e-tests/src/lib.rs @@ -4,13 +4,12 @@ mod e2e_tests { use dmc_lib::diagnostic::Diagnostic; use dmc_lib::parser::parse_compilation_unit; use dmc_lib::symbol_table::SymbolTable; - use dmc_lib::types_table::TypesTable; use dvm_lib::vm::class::Class; use dvm_lib::vm::constant::{Constant, StringConstant}; use dvm_lib::vm::function::Function; use dvm_lib::vm::operand::Operand; use dvm_lib::vm::value::Value; - use dvm_lib::vm::{CallStack, DvmContext, call}; + use dvm_lib::vm::{call, CallStack, DvmContext}; use std::rc::Rc; const REGISTER_COUNT: usize = 8; @@ -37,11 +36,11 @@ mod e2e_tests { }; let mut symbol_table = SymbolTable::new(); - let mut types_table = TypesTable::new(); compilation_unit.init_scopes(&mut symbol_table); compilation_unit.gather_symbols_into(&mut symbol_table)?; compilation_unit.check_names(&mut symbol_table)?; + let mut types_table = compilation_unit.gather_types(&symbol_table)?; compilation_unit.type_check(&symbol_table, &mut types_table)?; let (ir_classes, mut ir_functions) = compilation_unit.to_ir(&symbol_table, &types_table); diff --git a/sketching/march_2026/traits_and_ints.dm b/sketching/march_2026/traits_and_ints.dm new file mode 100644 index 0000000..82fa521 --- /dev/null +++ b/sketching/march_2026/traits_and_ints.dm @@ -0,0 +1,47 @@ +trait Add + type Output = Self + + fn add(other: R) -> Self::Output +end + +intrinsic class Int end +intrinsic class Double end + +impl Add for Int + fn add(other: Self) -> Self + self + other + end +end + +impl Add for Int + type Output = Double + + fn add(other: Double) -> Double + self + other + end +end + +impl Add for Double + fn add(other: Self) -> Self + self + other + end +end + +impl Add for Double + fn add(other: Int) -> Self + self + other + end +end + +fn add_rough_pi(a: impl Add) -> Double = a + 3.14 + +fn concat, U>(a: T, b: U) -> T::Output + a + b +end + +fn main() + let x = add_rough_pi(3) + println(x) // 6.14 + let y = concat(1, 2) // 3 + let z = concat("Hello, ", "World!") // "Hello, World!" +end