From a87b4efaf01e1ea71f11585fcfbfbf4cd05983e2 Mon Sep 17 00:00:00 2001 From: Jesse Brault Date: Sat, 29 Aug 2026 20:35:29 -0500 Subject: [PATCH] Work on type resolution, WIP. --- dmc-lib/src/ast/class.rs | 32 +++++ dmc-lib/src/ast/constructor.rs | 22 +++- dmc-lib/src/ast/expression.rs | 4 + dmc-lib/src/ast/field.rs | 4 + dmc-lib/src/ast/instance_self.rs | 24 ++++ dmc-lib/src/ast/mod.rs | 1 + dmc-lib/src/intrinsics.rs | 5 +- dmc-lib/src/ir/ir_allocate.rs | 5 + dmc-lib/src/ir/ir_operation.rs | 4 +- dmc-lib/src/ir/ir_statement.rs | 2 - dmc-lib/src/ir/ir_type_info.rs | 13 ++ dmc-lib/src/lowering/mod.rs | 73 ++++++++++- dmc-lib/src/lowering/util.rs | 9 +- dmc-lib/src/parser.rs | 9 ++ .../analysis_context/helpers.rs | 8 +- .../semantic_analysis/analysis_context/mod.rs | 15 ++- .../src/semantic_analysis/collect_scopes.rs | 90 +++++++++++-- .../src/semantic_analysis/collect_symbols.rs | 120 +++++++++++++++++- .../src/semantic_analysis/collect_types.rs | 98 +++++++++++++- dmc-lib/src/semantic_analysis/mod.rs | 1 + .../src/semantic_analysis/resolve_names.rs | 13 ++ .../semantic_analysis/resolve_types/mod.rs | 72 +++++++++++ .../resolve_types/type_analysis.rs | 10 +- dmc-lib/src/semantic_analysis/symbol.rs | 36 +++++- .../type_analysis/collect.rs | 25 ++++ .../semantic_analysis/type_analysis/infer.rs | 1 + .../semantic_analysis/type_analysis/mod.rs | 3 + .../type_analysis/resolve.rs | 1 + dmc-lib/src/semantic_analysis/type_info.rs | 65 +++++++++- e2e-tests/src/lib.rs | 6 +- 30 files changed, 719 insertions(+), 52 deletions(-) create mode 100644 dmc-lib/src/ast/instance_self.rs create mode 100644 dmc-lib/src/semantic_analysis/type_analysis/collect.rs create mode 100644 dmc-lib/src/semantic_analysis/type_analysis/infer.rs create mode 100644 dmc-lib/src/semantic_analysis/type_analysis/mod.rs create mode 100644 dmc-lib/src/semantic_analysis/type_analysis/resolve.rs diff --git a/dmc-lib/src/ast/class.rs b/dmc-lib/src/ast/class.rs index f364c51..c7c4aa5 100644 --- a/dmc-lib/src/ast/class.rs +++ b/dmc-lib/src/ast/class.rs @@ -36,4 +36,36 @@ impl Class { functions, } } + + pub fn node_id(&self) -> NodeId { + self.node_id + } + + pub fn declared_name(&self) -> &str { + &self.declared_name + } + + pub fn declared_name_owned(&self) -> Rc { + self.declared_name.clone() + } + + pub fn declared_name_source_range(&self) -> &SourceRange { + &self.declared_name_source_range + } + + pub fn generic_parameters(&self) -> &[GenericParameter] { + &self.generic_parameters + } + + pub fn constructor(&self) -> Option<&Constructor> { + self.constructor.as_ref() + } + + pub fn fields(&self) -> &[Field] { + &self.fields + } + + pub fn functions(&self) -> &[Function] { + &self.functions + } } diff --git a/dmc-lib/src/ast/constructor.rs b/dmc-lib/src/ast/constructor.rs index 2938f10..d7430b2 100644 --- a/dmc-lib/src/ast/constructor.rs +++ b/dmc-lib/src/ast/constructor.rs @@ -5,11 +5,10 @@ use crate::source_range::SourceRange; pub struct Constructor { node_id: NodeId, - is_public: bool, ctor_keyword_source_range: SourceRange, + is_public: bool, parameters: Vec, statements: Vec, - scope_id: Option, } impl Constructor { @@ -22,14 +21,29 @@ impl Constructor { ) -> Self { Self { node_id, - is_public, ctor_keyword_source_range, + is_public, parameters, statements, - scope_id: None, } } + pub fn node_id(&self) -> NodeId { + self.node_id + } + + pub fn ctor_keyword_source_range(&self) -> &SourceRange { + &self.ctor_keyword_source_range + } + + pub fn is_public(&self) -> bool { + self.is_public + } + + pub fn parameters(&self) -> &[Parameter] { + &self.parameters + } + pub fn statements(&self) -> &[Statement] { &self.statements } diff --git a/dmc-lib/src/ast/expression.rs b/dmc-lib/src/ast/expression.rs index 7271402..c137b1b 100644 --- a/dmc-lib/src/ast/expression.rs +++ b/dmc-lib/src/ast/expression.rs @@ -3,6 +3,7 @@ use crate::ast::binary_expression::BinaryExpression; use crate::ast::call::Call; use crate::ast::double_literal::DoubleLiteral; use crate::ast::identifier::Identifier; +use crate::ast::instance_self::InstanceSelf; use crate::ast::integer_literal::IntegerLiteral; use crate::ast::negative_expression::NegativeExpression; use crate::ast::path::Path; @@ -18,6 +19,7 @@ pub enum Expression { Integer(IntegerLiteral), Double(DoubleLiteral), String(StringLiteral), + InstanceSelf(InstanceSelf), } impl Expression { @@ -31,6 +33,7 @@ impl Expression { Expression::Integer(integer_literal) => integer_literal.node_id(), Expression::Double(double_literal) => double_literal.node_id(), Expression::String(string_literal) => string_literal.node_id(), + Expression::InstanceSelf(instance_self) => instance_self.node_id(), } } @@ -44,6 +47,7 @@ impl Expression { Expression::Integer(integer_literal) => integer_literal.source_range(), Expression::Double(double_literal) => double_literal.source_range(), Expression::String(string_literal) => string_literal.source_range(), + Expression::InstanceSelf(instance_self) => instance_self.source_range(), } } } diff --git a/dmc-lib/src/ast/field.rs b/dmc-lib/src/ast/field.rs index ee5a9f5..8ea887e 100644 --- a/dmc-lib/src/ast/field.rs +++ b/dmc-lib/src/ast/field.rs @@ -51,6 +51,10 @@ impl Field { &self.declared_name_source_range } + pub fn declared_type(&self) -> Option<&TypeUse> { + self.declared_type.as_ref().map(|t| &**t) + } + pub fn initializer(&self) -> Option<&Expression> { self.initializer.as_ref().map(Box::as_ref) } diff --git a/dmc-lib/src/ast/instance_self.rs b/dmc-lib/src/ast/instance_self.rs new file mode 100644 index 0000000..0f98799 --- /dev/null +++ b/dmc-lib/src/ast/instance_self.rs @@ -0,0 +1,24 @@ +use crate::ast::NodeId; +use crate::source_range::SourceRange; + +pub struct InstanceSelf { + node_id: NodeId, + source_range: SourceRange, +} + +impl InstanceSelf { + pub fn new(node_id: NodeId, source_range: SourceRange) -> Self { + Self { + node_id, + source_range, + } + } + + pub fn node_id(&self) -> NodeId { + self.node_id + } + + pub fn source_range(&self) -> &SourceRange { + &self.source_range + } +} diff --git a/dmc-lib/src/ast/mod.rs b/dmc-lib/src/ast/mod.rs index 0df3de2..70ab33e 100644 --- a/dmc-lib/src/ast/mod.rs +++ b/dmc-lib/src/ast/mod.rs @@ -12,6 +12,7 @@ pub mod field; pub mod function; pub mod generic_parameter; pub mod identifier; +pub mod instance_self; pub mod integer_literal; pub mod let_statement; pub mod negative_expression; diff --git a/dmc-lib/src/intrinsics.rs b/dmc-lib/src/intrinsics.rs index c492a85..81dc850 100644 --- a/dmc-lib/src/intrinsics.rs +++ b/dmc-lib/src/intrinsics.rs @@ -1,6 +1,6 @@ use crate::semantic_analysis::analysis_context::AnalysisContext; use crate::semantic_analysis::scope::ScopeId; -use crate::semantic_analysis::symbol::{ClassSymbol, FunctionSymbol, Symbol}; +use crate::semantic_analysis::symbol::{ClassSymbol, FunctionSymbol, FunctionType, Symbol}; use crate::semantic_analysis::type_info::{FunctionTypeInfo, InstanceTypeInfo, TypeInfo}; use std::collections::HashMap; @@ -10,7 +10,7 @@ pub fn add_primitive_symbols_and_type_infos(ctx: &mut AnalysisContext, global_sc None, "core::String::len".into(), true, - true, + FunctionType::InstanceMethod, )); let string_len_symbol_id = ctx .try_insert_symbol_in_scope(string_len_symbol, global_scope_id) @@ -24,6 +24,7 @@ pub fn add_primitive_symbols_and_type_infos(ctx: &mut AnalysisContext, global_sc None, "core::String".into(), true, + None, HashMap::new(), string_class_methods, )); diff --git a/dmc-lib/src/ir/ir_allocate.rs b/dmc-lib/src/ir/ir_allocate.rs index 3d02c12..47a23ab 100644 --- a/dmc-lib/src/ir/ir_allocate.rs +++ b/dmc-lib/src/ir/ir_allocate.rs @@ -1,3 +1,4 @@ +use crate::ir::register_allocation::{VrCollector, VrUser}; use std::fmt::{Display, Formatter}; use std::rc::Rc; @@ -25,3 +26,7 @@ impl Display for IrAllocate { write!(f, "alloc {}", self.class_fqn) } } + +impl VrUser for IrAllocate { + fn vr_uses(&self, _vrs: &mut VrCollector) {} +} diff --git a/dmc-lib/src/ir/ir_operation.rs b/dmc-lib/src/ir/ir_operation.rs index 12db7d4..0daf8db 100644 --- a/dmc-lib/src/ir/ir_operation.rs +++ b/dmc-lib/src/ir/ir_operation.rs @@ -5,9 +5,7 @@ use crate::ir::ir_expression::IrExpression; use crate::ir::ir_get_field_ref::IrGetFieldRef; use crate::ir::ir_get_field_ref_mut::IrGetFieldRefMut; use crate::ir::ir_read_field::IrReadField; -use crate::ir::ir_variable::IrVariableId; use crate::ir::register_allocation::{VrCollector, VrUser}; -use std::collections::HashSet; use std::fmt::{Display, Formatter}; #[derive(Debug)] @@ -58,7 +56,7 @@ impl VrUser for IrOperation { IrOperation::Load(ir_expression) => ir_expression.vr_uses(vrs), IrOperation::Binary(ir_binary) => ir_binary.vr_uses(vrs), IrOperation::Call(ir_call) => ir_call.vr_uses(vrs), - IrOperation::Allocate(_) => {} + IrOperation::Allocate(ir_allocate) => ir_allocate.vr_uses(vrs), } } } diff --git a/dmc-lib/src/ir/ir_statement.rs b/dmc-lib/src/ir/ir_statement.rs index b55913c..5b62e9c 100644 --- a/dmc-lib/src/ir/ir_statement.rs +++ b/dmc-lib/src/ir/ir_statement.rs @@ -2,9 +2,7 @@ use crate::ir::ir_assign::IrAssign; use crate::ir::ir_call::IrCall; use crate::ir::ir_return::IrReturn; use crate::ir::ir_set_field::IrSetField; -use crate::ir::ir_variable::IrVariableId; use crate::ir::register_allocation::{VrCollector, VrUser}; -use std::collections::HashSet; #[derive(Debug)] pub enum IrStatement { diff --git a/dmc-lib/src/ir/ir_type_info.rs b/dmc-lib/src/ir/ir_type_info.rs index 35123d5..6990b29 100644 --- a/dmc-lib/src/ir/ir_type_info.rs +++ b/dmc-lib/src/ir/ir_type_info.rs @@ -1,9 +1,11 @@ use std::fmt::{Display, Formatter}; +use std::rc::Rc; pub type IrTypeInfoId = usize; #[derive(Clone, Debug)] pub enum IrTypeInfo { + Instance(IrInstanceTypeInfo), String, Int, Double, @@ -15,3 +17,14 @@ impl Display for IrTypeInfo { write!(f, "{:?}", self) } } + +#[derive(Clone, Debug)] +pub struct IrInstanceTypeInfo { + class_fqn: Rc, +} + +impl IrInstanceTypeInfo { + pub fn new(class_fqn: Rc) -> Self { + Self { class_fqn } + } +} diff --git a/dmc-lib/src/lowering/mod.rs b/dmc-lib/src/lowering/mod.rs index 3b96360..2043302 100644 --- a/dmc-lib/src/lowering/mod.rs +++ b/dmc-lib/src/lowering/mod.rs @@ -10,6 +10,7 @@ use crate::ast::expression_statement::ExpressionStatement; use crate::ast::function::Function; use crate::ast::let_statement::LetStatement; use crate::ast::statement::Statement; +use crate::ir::ir_allocate::IrAllocate; use crate::ir::ir_assign::IrAssign; use crate::ir::ir_binary_operation::{IrBinaryOperation, IrBinaryOperator}; use crate::ir::ir_block::{IrBlock, IrBlockId}; @@ -25,7 +26,7 @@ use crate::ir::ir_variable::IrVariable; use crate::ir::ir_variable::{IrFreeVariables, IrStackFrameVariables, IrVariableInfo}; use crate::lowering::util::{return_type_info_to_ir_type_info, to_ir_type_info}; use crate::semantic_analysis::analysis_context::AnalysisContext; -use crate::semantic_analysis::symbol::{Symbol, SymbolId}; +use crate::semantic_analysis::symbol::{FunctionType, Symbol, SymbolId}; use crate::semantic_analysis::type_info::TypeInfo; use std::collections::HashMap; use std::ops::Neg; @@ -458,6 +459,9 @@ fn lower_expression_to_ir_operation( Expression::String(string_literal) => { IrOperation::Load(IrExpression::String(string_literal.content().into())) } + Expression::InstanceSelf(instance_self) => { + todo!() + } } } @@ -559,6 +563,7 @@ fn lower_expression_to_ir_expression( Expression::Integer(integer_literal) => IrExpression::Int(integer_literal.value()), Expression::Double(double_literal) => IrExpression::Double(double_literal.value()), Expression::String(string_literal) => IrExpression::String(string_literal.content().into()), + Expression::InstanceSelf(instance_self) => todo!(), } } @@ -570,9 +575,71 @@ fn lower_to_ir_call( let callee_symbol_id = ctx.nodes_to_symbols()[&call.callee().node_id()]; let callee_symbol = &ctx.symbols()[callee_symbol_id]; match callee_symbol { + Symbol::Class(class_symbol) => { + match class_symbol.constructor_symbol_id() { + Some(constructor_symbol_id) => { + let constructor_symbol = ctx + .symbols() + .get(constructor_symbol_id) + .expect(&format!( + "Could not get constructor symbol for class {}", + class_symbol.fqn() + )) + .unwrap_function_symbol(); + let constructor_type_info_id = ctx + .symbols_to_type_infos() + .get(&constructor_symbol_id) + .expect(&format!( + "Could not get constructor type info id for class {}", + class_symbol.fqn() + )); + let constructor_type_info = + ctx.type_infos()[*constructor_type_info_id].unwrap_constructor(); + + // get instance type info + let instance_type_info = ctx + .type_infos() + .get(constructor_type_info.instance_self_type_id()) + .expect(&format!( + "Could not get instance type info for class {}", + class_symbol.fqn() + )); + let ir_type_info = to_ir_type_info(ctx, instance_type_info); + + // allocate a new object of this class + let ir_allocate_operation = + IrOperation::Allocate(IrAllocate::new(class_symbol.fqn_owned())); + let object_destination = fn_ctx.storage_env_mut().new_t_var(ir_type_info); + let ir_assign = + IrAssign::new(object_destination.clone(), ir_allocate_operation); + fn_ctx + .current_block_statements + .push(IrStatement::Assign(ir_assign)); + + // arguments + let mut arguments = vec![IrExpression::Variable(object_destination)]; + for argument in call.arguments() { + arguments.push(lower_expression_to_ir_expression(argument, ctx, fn_ctx)); + } + + // call constructor + IrCall::new( + constructor_symbol.fqn_owned(), + arguments, + constructor_symbol.is_extern(), + ) + } + None => { + todo!() + } + } + } Symbol::Function(function_symbol) => { let mut arguments = Vec::new(); - if function_symbol.is_method() { + if matches!( + function_symbol.function_type(), + FunctionType::InstanceMethod + ) { let this = match call.callee() { Expression::Path(path) => { lower_expression_to_ir_expression(path.base(), ctx, fn_ctx) @@ -600,6 +667,6 @@ fn lower_to_ir_call( function_symbol.is_extern(), ) } - _ => panic!("Expected function symbol"), + _ => panic!("Expected function symbol, found {:?}", callee_symbol), } } diff --git a/dmc-lib/src/lowering/util.rs b/dmc-lib/src/lowering/util.rs index 08e973b..d2a66fb 100644 --- a/dmc-lib/src/lowering/util.rs +++ b/dmc-lib/src/lowering/util.rs @@ -1,15 +1,16 @@ -use crate::ir::ir_type_info::IrTypeInfo; +use crate::ir::ir_type_info::{IrInstanceTypeInfo, IrTypeInfo}; use crate::semantic_analysis::analysis_context::AnalysisContext; use crate::semantic_analysis::type_info::TypeInfo; pub fn to_ir_type_info(ctx: &AnalysisContext, sa_type_info: &TypeInfo) -> IrTypeInfo { match sa_type_info { TypeInfo::Instance(instance_type_info) => { - let symbol = &ctx.symbols()[instance_type_info.class_symbol_id()]; - if symbol.unwrap_class_symbol().fqn() == "core::String" { + let class_symbol = + &ctx.symbols()[instance_type_info.class_symbol_id()].unwrap_class_symbol(); + if class_symbol.fqn() == "core::String" { IrTypeInfo::String } else { - todo!("Non-string Instance types") + IrTypeInfo::Instance(IrInstanceTypeInfo::new(class_symbol.fqn_owned())) } } TypeInfo::Int => IrTypeInfo::Int, diff --git a/dmc-lib/src/parser.rs b/dmc-lib/src/parser.rs index e078166..dcf7d39 100644 --- a/dmc-lib/src/parser.rs +++ b/dmc-lib/src/parser.rs @@ -14,6 +14,7 @@ use crate::ast::field::Field; use crate::ast::function::Function; use crate::ast::generic_parameter::GenericParameter; use crate::ast::identifier::Identifier; +use crate::ast::instance_self::InstanceSelf; use crate::ast::integer_literal::IntegerLiteral; use crate::ast::let_statement::LetStatement; use crate::ast::negative_expression::NegativeExpression; @@ -1112,6 +1113,14 @@ impl<'a> Parser<'a> { source_range, ))) } + TokenKind::SelfKw => { + let source_range = SourceRange::new(current.start(), current.end()); + self.advance(); + Some(Expression::InstanceSelf(InstanceSelf::new( + self.next_node_id(), + source_range, + ))) + } _ => unreachable!("Unreachable token type found: {:?}", current.kind()), } } diff --git a/dmc-lib/src/semantic_analysis/analysis_context/helpers.rs b/dmc-lib/src/semantic_analysis/analysis_context/helpers.rs index 91c7813..cfa6769 100644 --- a/dmc-lib/src/semantic_analysis/analysis_context/helpers.rs +++ b/dmc-lib/src/semantic_analysis/analysis_context/helpers.rs @@ -7,12 +7,18 @@ pub fn get_name_for_type<'ctx>(type_info: &TypeInfo, ctx: &'ctx AnalysisContext) TypeInfo::Function(_function_type_info) => { todo!() } + TypeInfo::Constructor(_constructor_type_info) => { + todo!() + } + TypeInfo::TypeConstructor(type_constructor_info) => { + let class_symbol = &ctx.symbols()[type_constructor_info.class_symbol_id()]; + class_symbol.declared_name() + } TypeInfo::Instance(instance_type_info) => { let class_symbol_id = instance_type_info.class_symbol_id(); let class_symbol = &ctx.symbols()[class_symbol_id]; class_symbol.declared_name() } - TypeInfo::String => "String", TypeInfo::Int => "Int", TypeInfo::Double => "Double", TypeInfo::Void => "Void", diff --git a/dmc-lib/src/semantic_analysis/analysis_context/mod.rs b/dmc-lib/src/semantic_analysis/analysis_context/mod.rs index 5c25ae2..4d0b61a 100644 --- a/dmc-lib/src/semantic_analysis/analysis_context/mod.rs +++ b/dmc-lib/src/semantic_analysis/analysis_context/mod.rs @@ -174,7 +174,7 @@ impl AnalysisContext { &mut self, to_insert: Symbol, owner_node_id: NodeId, - ) -> Result<(), Diagnostic> { + ) -> 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 @@ -187,7 +187,7 @@ impl AnalysisContext { } else { let symbol_id = self.insert_symbol_in_scope(*node_scope_id, to_insert); self.associate_node_to_symbol(owner_node_id, symbol_id); - Ok(()) + Ok(symbol_id) } } @@ -255,10 +255,15 @@ impl AnalysisContext { self.type_infos.len() - 1 } - pub fn insert_type_info_for_node(&mut self, type_info: TypeInfo, node_id: NodeId) { + pub fn insert_type_info_for_node( + &mut self, + type_info: TypeInfo, + node_id: NodeId, + ) -> TypeInfoId { self.type_infos.push(type_info); - self.nodes_to_type_infos - .insert(node_id, self.type_infos.len() - 1); + let type_info_id = self.type_infos.len() - 1; + self.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) { diff --git a/dmc-lib/src/semantic_analysis/collect_scopes.rs b/dmc-lib/src/semantic_analysis/collect_scopes.rs index f5e4fcf..e080187 100644 --- a/dmc-lib/src/semantic_analysis/collect_scopes.rs +++ b/dmc-lib/src/semantic_analysis/collect_scopes.rs @@ -1,16 +1,21 @@ use crate::ast::assign_statement::AssignStatement; use crate::ast::binary_expression::BinaryExpression; use crate::ast::call::Call; +use crate::ast::class::Class; use crate::ast::compilation_unit::CompilationUnit; +use crate::ast::constructor::Constructor; use crate::ast::expression::Expression; use crate::ast::expression_statement::ExpressionStatement; use crate::ast::extern_function::ExternFunction; +use crate::ast::field::Field; use crate::ast::function::Function; use crate::ast::identifier::Identifier; +use crate::ast::instance_self::InstanceSelf; use crate::ast::let_statement::LetStatement; use crate::ast::negative_expression::NegativeExpression; use crate::ast::path::Path; use crate::ast::statement::Statement; +use crate::ast::type_use::TypeUse; use crate::semantic_analysis::analysis_context::AnalysisContext; pub fn collect_scopes_compilation_unit( @@ -24,6 +29,9 @@ pub fn collect_scopes_compilation_unit( for extern_function in compilation_unit.extern_functions() { collect_scopes_extern_function(extern_function, ctx); } + for class in compilation_unit.classes() { + collect_scopes_class(class, ctx); + } ctx.pop_scope(); // compilation_unit } @@ -38,13 +46,8 @@ fn collect_scopes_function(function: &Function, ctx: &mut AnalysisContext) { for parameter in function.parameters() { ctx.associate_node_to_current_scope(parameter.node_id()); } - match function.return_type() { - None => { - // no-op - } - Some(type_use) => { - ctx.associate_node_to_current_scope(type_use.node_id()); - } + if let Some(type_use) = function.return_type() { + collect_scopes_type_use(type_use, ctx); } // push block scope for body @@ -67,10 +70,74 @@ fn collect_scopes_extern_function(extern_function: &ExternFunction, ctx: &mut An for parameter in extern_function.parameters() { ctx.associate_node_to_current_scope(parameter.node_id()); } - ctx.associate_node_to_current_scope(extern_function.return_type().node_id()); + collect_scopes_type_use(extern_function.return_type(), ctx); ctx.pop_scope(); // parameters } +fn collect_scopes_class(class: &Class, ctx: &mut AnalysisContext) { + // associate class with current scope + ctx.associate_node_to_current_scope(class.node_id()); + + ctx.push_scope("class_scope"); + + if let Some(constructor) = class.constructor() { + collect_scopes_constructor(constructor, ctx); + } + + for field in class.fields() { + collect_scopes_field(field, ctx); + } + + for function in class.functions() { + collect_scopes_function(function, ctx); + } + + ctx.pop_scope(); +} + +// Generally, this is very similar to the process for functions above +fn collect_scopes_constructor(constructor: &Constructor, ctx: &mut AnalysisContext) { + // associate constructor to current scope + ctx.associate_node_to_current_scope(constructor.node_id()); + + // push ctor params scope + ctx.push_scope("ctor_parameters"); + + // parameters' scope + for parameter in constructor.parameters() { + ctx.associate_node_to_current_scope(parameter.node_id()); + } + + // block scope for body + ctx.push_scope("ctor_body"); + + for statement in constructor.statements() { + collect_scopes_statement(statement, ctx); + } + + ctx.pop_scope(); // body + ctx.pop_scope(); // parameters +} + +fn collect_scopes_field(field: &Field, ctx: &mut AnalysisContext) { + // associate field with current scope + ctx.associate_node_to_current_scope(field.node_id()); + + // if typed, associate scope + if let Some(type_use) = field.declared_type() { + collect_scopes_type_use(type_use, ctx); + } + + // if initializer, associate scope + if let Some(initializer) = field.initializer() { + collect_scopes_expression(initializer, ctx); + } +} + +fn collect_scopes_type_use(type_use: &TypeUse, ctx: &mut AnalysisContext) { + ctx.associate_node_to_current_scope(type_use.node_id()); +} + pub fn collect_scopes_statement(statement: &Statement, ctx: &mut AnalysisContext) { match statement { Statement::Let(let_statement) => collect_scopes_let_statement(let_statement, ctx), @@ -120,6 +187,9 @@ fn collect_scopes_expression(expression: &Expression, ctx: &mut AnalysisContext) Expression::Integer(_) => {} Expression::Double(_) => {} Expression::String(_) => {} + Expression::InstanceSelf(instance_self) => { + collect_scopes_instance_self(instance_self, ctx); + } } } @@ -153,3 +223,7 @@ fn collect_scopes_path(path: &Path, ctx: &mut AnalysisContext) { fn collect_scopes_identifier(identifier: &Identifier, ctx: &mut AnalysisContext) { ctx.associate_node_to_current_scope(identifier.node_id()); } + +fn collect_scopes_instance_self(instance_self: &InstanceSelf, ctx: &mut AnalysisContext) { + ctx.associate_node_to_current_scope(instance_self.node_id()); +} diff --git a/dmc-lib/src/semantic_analysis/collect_symbols.rs b/dmc-lib/src/semantic_analysis/collect_symbols.rs index cde4c54..ee010ec 100644 --- a/dmc-lib/src/semantic_analysis/collect_symbols.rs +++ b/dmc-lib/src/semantic_analysis/collect_symbols.rs @@ -1,10 +1,16 @@ +use crate::ast::class::Class; use crate::ast::compilation_unit::CompilationUnit; +use crate::ast::constructor::Constructor; use crate::ast::extern_function::ExternFunction; +use crate::ast::field::Field; use crate::ast::function::Function; use crate::ast::parameter::Parameter; use crate::diagnostic::Diagnostics; use crate::semantic_analysis::analysis_context::AnalysisContext; -use crate::semantic_analysis::symbol::{FunctionSymbol, ParameterSymbol, Symbol}; +use crate::semantic_analysis::symbol::{ + ClassSymbol, FieldSymbol, FunctionSymbol, FunctionType, ParameterSymbol, Symbol, SymbolId, +}; +use std::collections::HashMap; pub struct SymbolCollectionResult(pub Diagnostics); @@ -15,13 +21,22 @@ pub fn collect_symbols_compilation_unit( let mut diagnostics = Diagnostics::new(); for function in compilation_unit.functions() { - collect_symbols_function(function, analysis_context, &mut diagnostics); + collect_symbols_function( + function, + analysis_context, + &mut diagnostics, + FunctionType::Function, + ); } for extern_function in compilation_unit.extern_functions() { collect_symbols_extern_function(extern_function, analysis_context, &mut diagnostics); } + for class in compilation_unit.classes() { + collect_symbols_class(class, analysis_context, &mut diagnostics); + } + SymbolCollectionResult(diagnostics) } @@ -29,6 +44,7 @@ fn collect_symbols_function( function: &Function, ctx: &mut AnalysisContext, diagnostics: &mut Diagnostics, + function_type: FunctionType, ) { let fqn = ctx.resolve_fqn(&function.declared_name()).into(); @@ -38,7 +54,7 @@ fn collect_symbols_function( Some(function.declared_name_source_range()), fqn, false, - false, + function_type, )); // insert @@ -71,7 +87,7 @@ fn collect_symbols_extern_function( Some(extern_function.declared_name_source_range()), fqn, true, - false, + FunctionType::Function, )); // insert function symbol @@ -87,6 +103,102 @@ fn collect_symbols_extern_function( } } +fn collect_symbols_class(class: &Class, ctx: &mut AnalysisContext, diagnostics: &mut Diagnostics) { + // Symbols for fields + // Ctor symbol (maybe just a function symbol?) + // Recurse on methods + // Class symbol for self + + let mut field_symbol_ids = HashMap::new(); + for field in class.fields() { + collect_symbols_field(field, ctx, diagnostics); + let maybe_field_symbol_id = ctx.nodes_to_symbols().get(&field.node_id()); + match maybe_field_symbol_id { + Some(field_symbol_id) => { + field_symbol_ids.insert(field.declared_name_owned(), *field_symbol_id); + } + None => {} + } + } + + let constructor_symbol_id = if let Some(constructor) = class.constructor() { + collect_symbols_constructor(constructor, ctx, diagnostics); + let maybe_constructor_symbol_id = ctx.nodes_to_symbols().get(&constructor.node_id()); + match maybe_constructor_symbol_id { + Some(constructor_symbol_id) => Some(*constructor_symbol_id), + None => None, + } + } else { + None + }; + + let mut method_symbol_ids = HashMap::new(); + for function in class.functions() { + collect_symbols_function(function, ctx, diagnostics, FunctionType::InstanceMethod); + let maybe_method_symbol_id = ctx.nodes_to_symbols().get(&function.node_id()); + match maybe_method_symbol_id { + Some(method_symbol_id) => { + method_symbol_ids.insert(function.declared_name_owned(), *method_symbol_id); + } + None => {} + } + } + + let class_symbol = Symbol::Class(ClassSymbol::new( + class.declared_name_owned(), + Some(class.declared_name_source_range().clone()), + ctx.resolve_fqn(&class.declared_name()).into(), + false, + constructor_symbol_id, + field_symbol_ids, + method_symbol_ids, + )); + + match ctx.try_insert_associate_symbol_in_node_scope(class_symbol, class.node_id()) { + Ok(_) => {} + Err(diagnostic) => { + diagnostics.push(diagnostic); + } + } +} + +fn collect_symbols_field(field: &Field, ctx: &mut AnalysisContext, diagnostics: &mut Diagnostics) { + let field_symbol = Symbol::Field(FieldSymbol::new( + field.declared_name_owned(), + Some(field.declared_name_source_range().clone()), + )); + match ctx.try_insert_associate_symbol_in_node_scope(field_symbol, field.node_id()) { + Ok(_) => {} + Err(diagnostic) => { + diagnostics.push(diagnostic); + } + } +} + +fn collect_symbols_constructor( + constructor: &Constructor, + ctx: &mut AnalysisContext, + diagnostics: &mut Diagnostics, +) { + for parameter in constructor.parameters() { + collect_symbols_parameter(parameter, ctx, diagnostics); + } + + let function_symbol = Symbol::Function(FunctionSymbol::new( + "__ctor__".into(), + Some(constructor.ctor_keyword_source_range().clone()), + ctx.resolve_fqn("__ctor__").into(), + false, + FunctionType::Constructor, + )); + match ctx.try_insert_associate_symbol_in_node_scope(function_symbol, constructor.node_id()) { + Ok(_) => {} + Err(diagnostic) => { + diagnostics.push(diagnostic); + } + } +} + fn collect_symbols_parameter( parameter: &Parameter, ctx: &mut AnalysisContext, diff --git a/dmc-lib/src/semantic_analysis/collect_types.rs b/dmc-lib/src/semantic_analysis/collect_types.rs index 0474707..6b5e279 100644 --- a/dmc-lib/src/semantic_analysis/collect_types.rs +++ b/dmc-lib/src/semantic_analysis/collect_types.rs @@ -1,9 +1,15 @@ +use crate::ast::class::Class; use crate::ast::compilation_unit::CompilationUnit; +use crate::ast::constructor::Constructor; use crate::ast::extern_function::ExternFunction; use crate::ast::function::Function; use crate::ast::parameter::Parameter; use crate::semantic_analysis::analysis_context::AnalysisContext; -use crate::semantic_analysis::type_info::{FunctionTypeInfo, TypeInfo, TypeInfoId}; +use crate::semantic_analysis::symbol::SymbolId; +use crate::semantic_analysis::type_info::{ + ConstructorTypeInfo, FunctionTypeInfo, InstanceTypeInfo, TypeConstructorInfo, TypeInfo, + TypeInfoId, +}; pub fn collect_types(compilation_unit: &CompilationUnit, ctx: &mut AnalysisContext) { for function in compilation_unit.functions() { @@ -13,6 +19,10 @@ pub fn collect_types(compilation_unit: &CompilationUnit, ctx: &mut AnalysisConte for extern_function in compilation_unit.extern_functions() { collect_types_extern_function(extern_function, ctx); } + + for class in compilation_unit.classes() { + collect_types_class(class, ctx); + } } fn collect_types_function(function: &Function, ctx: &mut AnalysisContext) { @@ -21,7 +31,16 @@ fn collect_types_function(function: &Function, ctx: &mut AnalysisContext) { let return_type_info = match function.return_type() { None => TypeInfo::Void, - Some(type_use) => declared_name_to_type_info(ctx, type_use.declared_name()), + Some(type_use) => get_intrinsic_type(type_use.declared_name()).unwrap_or_else(|| { + let symbol_id = ctx + .nodes_to_symbols() + .get(&type_use.node_id()) + .expect(&format!( + "Could not get symbol id for type_use {}", + type_use.declared_name() + )); + resolve_type(ctx, *symbol_id) + }), }; let return_type_info_id = ctx.insert_type_info(return_type_info); @@ -35,6 +54,21 @@ fn collect_types_function(function: &Function, ctx: &mut AnalysisContext) { ctx.associate_node_and_symbol_to_type(function.node_id(), function_type_info_id); } +fn get_intrinsic_type(declared_name: &str) -> Option { + match declared_name { + "Any" => Some(TypeInfo::Any), + "Void" => Some(TypeInfo::Void), + "Int" => Some(TypeInfo::Int), + "Double" => Some(TypeInfo::Double), + _ => None, + } +} + +fn resolve_type(ctx: &AnalysisContext, symbol_id: SymbolId) -> TypeInfo { + todo!() +} + +#[deprecated] fn declared_name_to_type_info(ctx: &AnalysisContext, declared_name: &str) -> TypeInfo { match declared_name { "Any" => TypeInfo::Any, @@ -48,7 +82,9 @@ fn declared_name_to_type_info(ctx: &AnalysisContext, declared_name: &str) -> Typ "Int" => TypeInfo::Int, "Double" => TypeInfo::Double, "Void" => TypeInfo::Void, - _ => TypeInfo::__Error, + _ => { + panic!() + } } } @@ -86,3 +122,59 @@ fn collect_types_extern_function(extern_function: &ExternFunction, ctx: &mut Ana ctx.associate_node_and_symbol_to_type(extern_function.node_id(), function_type_info_id); } + +fn collect_types_class(class: &Class, ctx: &mut AnalysisContext) { + let self_instance_type_info = TypeInfo::Instance(InstanceTypeInfo::new( + *ctx.nodes_to_symbols() + .get(&class.node_id()) + .expect(&format!( + "Could not find class symbol for {} {}", + class.node_id(), + class.declared_name() + )), + )); + let self_instance_type_info_id = ctx.insert_type_info(self_instance_type_info); + + let constructor_type_info_id = if let Some(constructor) = class.constructor() { + Some(collect_types_constructor( + constructor, + ctx, + self_instance_type_info_id, + )) + } else { + None + }; + + // todo: fields, methods + + // Self type constructor + let type_constructor_type_info = TypeInfo::TypeConstructor(TypeConstructorInfo::new( + ctx.nodes_to_symbols()[&class.node_id()], + constructor_type_info_id, + )); + let type_constructor_type_info_id = ctx.insert_type_info(type_constructor_type_info); + ctx.associate_node_and_symbol_to_type(class.node_id(), type_constructor_type_info_id); +} + +fn collect_types_constructor( + constructor: &Constructor, + ctx: &mut AnalysisContext, + self_type_info_id: TypeInfoId, +) -> TypeInfoId { + let mut parameter_type_info_ids: Vec = Vec::new(); + for parameter in constructor.parameters() { + let type_info = declared_name_to_type_info(ctx, parameter.type_use().declared_name()); + let type_info_id = ctx.insert_type_info(type_info); + ctx.associate_node_and_symbol_to_type(parameter.node_id(), type_info_id); + parameter_type_info_ids.push(type_info_id); + } + + let constructor_type_info = TypeInfo::Constructor(ConstructorTypeInfo::new( + self_type_info_id, + parameter_type_info_ids, + )); + + let constructor_type_info_id = ctx.insert_type_info(constructor_type_info); + ctx.associate_node_and_symbol_to_type(constructor.node_id(), constructor_type_info_id); + constructor_type_info_id +} diff --git a/dmc-lib/src/semantic_analysis/mod.rs b/dmc-lib/src/semantic_analysis/mod.rs index 9c9f2c8..ce7cfb9 100644 --- a/dmc-lib/src/semantic_analysis/mod.rs +++ b/dmc-lib/src/semantic_analysis/mod.rs @@ -25,6 +25,7 @@ mod resolve_names; mod resolve_types; pub mod scope; pub mod symbol; +pub mod type_analysis; pub mod type_info; pub fn analyze_compilation_unit( diff --git a/dmc-lib/src/semantic_analysis/resolve_names.rs b/dmc-lib/src/semantic_analysis/resolve_names.rs index ffa6f13..d2949e5 100644 --- a/dmc-lib/src/semantic_analysis/resolve_names.rs +++ b/dmc-lib/src/semantic_analysis/resolve_names.rs @@ -7,6 +7,7 @@ use crate::ast::expression_statement::ExpressionStatement; use crate::ast::extern_function::ExternFunction; use crate::ast::function::Function; use crate::ast::identifier::Identifier; +use crate::ast::instance_self::InstanceSelf; use crate::ast::let_statement::LetStatement; use crate::ast::negative_expression::NegativeExpression; use crate::ast::parameter::Parameter; @@ -205,6 +206,9 @@ fn resolve_names_expression( Expression::Integer(_) => {} Expression::Double(_) => {} Expression::String(_) => {} + Expression::InstanceSelf(instance_self) => { + resolve_names_instance_self(instance_self, ctx, diagnostics, phase); + } } } @@ -270,3 +274,12 @@ fn resolve_names_identifier( } } } + +fn resolve_names_instance_self( + instance_self: &InstanceSelf, + ctx: &mut AnalysisContext, + diagnostics: &mut Diagnostics, + phase: ExpressionResolutionPhase, +) { + todo!() +} diff --git a/dmc-lib/src/semantic_analysis/resolve_types/mod.rs b/dmc-lib/src/semantic_analysis/resolve_types/mod.rs index 0682a90..e5940b8 100644 --- a/dmc-lib/src/semantic_analysis/resolve_types/mod.rs +++ b/dmc-lib/src/semantic_analysis/resolve_types/mod.rs @@ -7,6 +7,7 @@ use crate::ast::compilation_unit::CompilationUnit; use crate::ast::expression::Expression; use crate::ast::function::Function; use crate::ast::identifier::Identifier; +use crate::ast::instance_self::InstanceSelf; use crate::ast::let_statement::LetStatement; use crate::ast::negative_expression::NegativeExpression; use crate::ast::parameter::Parameter; @@ -163,6 +164,9 @@ fn resolve_types_expression( string_literal.node_id(), ); } + Expression::InstanceSelf(instance_self) => { + resolve_types_instance_self(instance_self, ctx); + } } } @@ -251,6 +255,70 @@ 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) => { + let class_symbol = + ctx.symbols()[type_constructor_info.class_symbol_id()].unwrap_class_symbol(); + match class_symbol.constructor_symbol_id() { + Some(constructor_symbol_id) => { + let constructor_type_info_id = + ctx.symbols_to_type_infos()[&constructor_symbol_id]; + let constructor_type_info = ctx + .type_infos() + .get(constructor_type_info_id) + .expect(&format!( + "Cannot get constructor type info for {}", + get_name_for_type(callee_type_info, ctx) + )) + .unwrap_constructor(); + + // check arguments length + let arguments = call.arguments(); + if arguments.len() != constructor_type_info.parameter_type_ids().len() { + todo!("Report wrong number of constructor args") + } + + // check each argument type + let parameter_type_ids = constructor_type_info.parameter_type_ids(); + if arguments.len() == parameter_type_ids.len() { + for i in 0..parameter_type_ids.len() { + let argument_type_info = + ctx.get_type_info_for_node(arguments[i].node_id()); + let parameter_type_info = + ctx.get_type_info_by_id(parameter_type_ids[i]); + if !can_assign_right_to_left( + parameter_type_info, + argument_type_info, + ctx, + ) { + let parameter_type_name = + get_name_for_type(parameter_type_info, ctx); + let argument_type_name = get_name_for_type(argument_type_info, ctx); + let message = format!( + "Incompatible types: cannot assign {} to {}", + argument_type_name, parameter_type_name + ); + let diagnostic = Diagnostic::new( + &message, + arguments[i].source_range().start(), + arguments[i].source_range().end(), + ); + diagnostics.push(diagnostic); + } + } + } + + // set return type of call to be the "return" type of the constructor + ctx.associate_node_to_type( + call.node_id(), + constructor_type_info.instance_self_type_id(), + ); + } + None => { + // Default, no-arg constructor + // check zero args + } + } + } TypeInfo::Function(function_type_info) => { // check arguments length let arguments = call.arguments(); @@ -389,3 +457,7 @@ fn resolve_types_identifier(identifier: &Identifier, ctx: &mut AnalysisContext) let type_info_id = ctx.lookup_type_for_node_via_symbol(identifier.node_id()); ctx.associate_node_to_type(identifier.node_id(), type_info_id); } + +fn resolve_types_instance_self(instance_self: &InstanceSelf, ctx: &mut AnalysisContext) { + todo!() +} 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 ea53ae5..1d10a11 100644 --- a/dmc-lib/src/semantic_analysis/resolve_types/type_analysis.rs +++ b/dmc-lib/src/semantic_analysis/resolve_types/type_analysis.rs @@ -147,16 +147,18 @@ pub fn can_assign_right_to_left(left: &TypeInfo, right: &TypeInfo, ctx: &Analysi TypeInfo::Function(_) => { panic!() } + TypeInfo::Constructor(_) => { + panic!() + } + TypeInfo::TypeConstructor(_) => { + panic!() + } TypeInfo::Instance(left_instance_type_info) => match right { TypeInfo::Instance(right_instance_type_info) => { left_instance_type_info.can_assign_from(right_instance_type_info, ctx) } _ => false, }, - TypeInfo::String => match right { - TypeInfo::String => true, - _ => false, - }, TypeInfo::Int => match right { TypeInfo::Int => true, _ => false, diff --git a/dmc-lib/src/semantic_analysis/symbol.rs b/dmc-lib/src/semantic_analysis/symbol.rs index ac88b49..3dbfc01 100644 --- a/dmc-lib/src/semantic_analysis/symbol.rs +++ b/dmc-lib/src/semantic_analysis/symbol.rs @@ -51,6 +51,13 @@ impl Symbol { _ => panic!("Attempt to unwrap {:?} as ClassSymbol", self), } } + + pub fn unwrap_function_symbol(&self) -> &FunctionSymbol { + match self { + Symbol::Function(function_symbol) => function_symbol, + _ => panic!("Attempt to unwrap {:?} as FunctionSymbol", self), + } + } } #[derive(Debug)] @@ -59,6 +66,7 @@ pub struct ClassSymbol { source_range: Option, fqn: Rc, is_extern: bool, + constructor_symbol_id: Option, field_symbol_ids: HashMap, SymbolId>, method_symbol_ids: HashMap, SymbolId>, } @@ -69,6 +77,7 @@ impl ClassSymbol { source_range: Option, fqn: Rc, is_extern: bool, + constructor_symbol_id: Option, field_symbol_ids: HashMap, SymbolId>, method_symbol_ids: HashMap, SymbolId>, ) -> Self { @@ -77,6 +86,7 @@ impl ClassSymbol { source_range, fqn, is_extern, + constructor_symbol_id, field_symbol_ids, method_symbol_ids, } @@ -98,10 +108,18 @@ impl ClassSymbol { &self.fqn } + pub fn fqn_owned(&self) -> Rc { + self.fqn.clone() + } + pub fn can_assign_from(&self, right: &ClassSymbol, _ctx: &AnalysisContext) -> bool { self.fqn == right.fqn // eventually, this will check inheritance logic, etc. } + pub fn constructor_symbol_id(&self) -> Option { + self.constructor_symbol_id + } + pub fn field_symbol_ids(&self) -> &HashMap, SymbolId> { &self.field_symbol_ids } @@ -138,13 +156,21 @@ impl FieldSymbol { } } +#[derive(Debug)] +pub enum FunctionType { + Function, + Constructor, + InstanceMethod, + StaticMethod, +} + #[derive(Debug)] pub struct FunctionSymbol { declared_name: Rc, declared_name_source_range: Option, fqn: Rc, is_extern: bool, - is_method: bool, + function_type: FunctionType, } impl FunctionSymbol { @@ -153,14 +179,14 @@ impl FunctionSymbol { declared_name_source_range: Option, fqn: Rc, is_extern: bool, - is_method: bool, + function_type: FunctionType, ) -> Self { Self { declared_name, declared_name_source_range, fqn, is_extern, - is_method, + function_type, } } @@ -188,8 +214,8 @@ impl FunctionSymbol { self.is_extern } - pub fn is_method(&self) -> bool { - self.is_method + pub fn function_type(&self) -> &FunctionType { + &self.function_type } } diff --git a/dmc-lib/src/semantic_analysis/type_analysis/collect.rs b/dmc-lib/src/semantic_analysis/type_analysis/collect.rs new file mode 100644 index 0000000..2e21aa3 --- /dev/null +++ b/dmc-lib/src/semantic_analysis/type_analysis/collect.rs @@ -0,0 +1,25 @@ +use crate::ast::class::Class; +use crate::ast::compilation_unit::CompilationUnit; +use crate::semantic_analysis::analysis_context::AnalysisContext; +use crate::semantic_analysis::type_info::{InstanceTypeInfo, TypeInfo}; + +pub fn collect_types(compilation_unit: &CompilationUnit, ctx: &mut AnalysisContext) { + for class in compilation_unit.classes() { + collect_types_class(class, ctx); + } +} + +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 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) +} diff --git a/dmc-lib/src/semantic_analysis/type_analysis/infer.rs b/dmc-lib/src/semantic_analysis/type_analysis/infer.rs new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/dmc-lib/src/semantic_analysis/type_analysis/infer.rs @@ -0,0 +1 @@ + diff --git a/dmc-lib/src/semantic_analysis/type_analysis/mod.rs b/dmc-lib/src/semantic_analysis/type_analysis/mod.rs new file mode 100644 index 0000000..5978e5f --- /dev/null +++ b/dmc-lib/src/semantic_analysis/type_analysis/mod.rs @@ -0,0 +1,3 @@ +mod collect; +mod infer; +mod resolve; diff --git a/dmc-lib/src/semantic_analysis/type_analysis/resolve.rs b/dmc-lib/src/semantic_analysis/type_analysis/resolve.rs new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/dmc-lib/src/semantic_analysis/type_analysis/resolve.rs @@ -0,0 +1 @@ + diff --git a/dmc-lib/src/semantic_analysis/type_info.rs b/dmc-lib/src/semantic_analysis/type_info.rs index ab8dbb3..eba36ad 100644 --- a/dmc-lib/src/semantic_analysis/type_info.rs +++ b/dmc-lib/src/semantic_analysis/type_info.rs @@ -7,14 +7,31 @@ pub type TypeInfoId = usize; pub enum TypeInfo { Any, Function(FunctionTypeInfo), + Constructor(ConstructorTypeInfo), + TypeConstructor(TypeConstructorInfo), Instance(InstanceTypeInfo), - String, Int, Double, Void, __Error, } +impl TypeInfo { + pub fn unwrap_constructor(&self) -> &ConstructorTypeInfo { + match self { + TypeInfo::Constructor(constructor_type_info) => constructor_type_info, + _ => panic!("Attempt to unwrap {:?} as Constructor", self), + } + } + + pub fn unwrap_type_constructor(&self) -> &TypeConstructorInfo { + match self { + TypeInfo::TypeConstructor(type_constructor_info) => type_constructor_info, + _ => panic!("Attempt to unwrap {:?} as TypeConstructor", self), + } + } +} + #[derive(Clone, Debug)] pub struct FunctionTypeInfo { parameter_type_info_ids: Vec, @@ -48,6 +65,52 @@ impl FunctionTypeInfo { } } +#[derive(Clone, Debug)] +pub struct ConstructorTypeInfo { + instance_self_type_id: TypeInfoId, + parameter_type_ids: Vec, +} + +impl ConstructorTypeInfo { + pub fn new(instance_self_type_id: TypeInfoId, parameter_type_ids: Vec) -> Self { + Self { + instance_self_type_id, + parameter_type_ids, + } + } + + pub fn instance_self_type_id(&self) -> TypeInfoId { + self.instance_self_type_id + } + + pub fn parameter_type_ids(&self) -> &[TypeInfoId] { + &self.parameter_type_ids + } +} + +#[derive(Clone, Debug)] +pub struct TypeConstructorInfo { + class_symbol_id: SymbolId, + constructor_type_info_id: Option, +} + +impl TypeConstructorInfo { + pub fn new(class_symbol_id: SymbolId, constructor_type_info_id: Option) -> Self { + Self { + class_symbol_id, + constructor_type_info_id, + } + } + + pub fn class_symbol_id(&self) -> SymbolId { + self.class_symbol_id + } + + pub fn constructor_type_info_id(&self) -> Option { + self.constructor_type_info_id + } +} + #[derive(Clone, Debug)] pub struct InstanceTypeInfo { class_symbol_id: SymbolId, diff --git a/e2e-tests/src/lib.rs b/e2e-tests/src/lib.rs index 1761f24..dde145d 100644 --- a/e2e-tests/src/lib.rs +++ b/e2e-tests/src/lib.rs @@ -182,10 +182,10 @@ mod e2e_tests { let context = prepare_context( " class Foo - mut bar = 21 + bar: Int - ctor(_bar: Int) - bar = _bar + pub ctor(bar: Int) + self.bar = bar end end