diff --git a/dmc-lib/src/ast/assign_statement.rs b/dmc-lib/src/ast/assign_statement.rs index 3eb3f22..17a094e 100644 --- a/dmc-lib/src/ast/assign_statement.rs +++ b/dmc-lib/src/ast/assign_statement.rs @@ -1,13 +1,17 @@ -use crate::ast::NamesTable; use crate::ast::expression::Expression; -use crate::ast::helpers::insert_resolved_names_into; +use crate::ast::helpers::{insert_resolved_names_into, insert_resolved_types_into}; use crate::ast::ir_builder::IrBuilder; use crate::ast::ir_util::get_or_init_mut_field_pointer_variable; +use crate::ast::{NodesToSymbols, NodesToTypes, SymbolsToTypes}; use crate::diagnostic::{Diagnostic, Diagnostics, SecondaryLabel}; +use crate::diagnostic_factories::{ + destination_must_be_mutable, mismatched_assign_types, must_be_l_value, +}; use crate::error_codes::{ASSIGN_LHS_IMMUTABLE, ASSIGN_MISMATCHED_TYPES, ASSIGN_NO_L_VALUE}; use crate::ir::ir_assign::IrAssign; use crate::ir::ir_set_field::IrSetField; use crate::ir::ir_statement::IrStatement; +use crate::source_range::SourceRange; use crate::symbol::class_symbol::ClassSymbol; use crate::symbol::expressible_symbol::ExpressibleSymbol; use crate::symbol_table::SymbolTable; @@ -37,9 +41,12 @@ impl AssignStatement { self.value.init_scopes(symbol_table, container_scope); } - pub fn resolve_names_static(&self, symbol_table: &SymbolTable) -> (NamesTable, Diagnostics) { + pub fn resolve_names_static( + &self, + symbol_table: &SymbolTable, + ) -> (NodesToSymbols, Diagnostics) { let mut diagnostics = Diagnostics::new(); - let mut names_table = NamesTable::new(); + let mut names_table = NodesToSymbols::new(); for expression in [self.destination.as_ref(), self.value.as_ref()] { let (ns, mut ds) = expression.resolve_names_static(symbol_table); @@ -57,9 +64,9 @@ impl AssignStatement { symbol_table: &SymbolTable, self_class_symbol: &ClassSymbol, initialized_fields: &mut HashSet>, - ) -> (NamesTable, Diagnostics) { + ) -> (NodesToSymbols, Diagnostics) { let mut diagnostics = Diagnostics::new(); - let mut names_table = NamesTable::new(); + let mut names_table = NodesToSymbols::new(); { let (ns, mut ds) = self @@ -84,6 +91,24 @@ impl AssignStatement { (names_table, diagnostics) } + pub fn resolve_names_method( + &self, + symbol_table: &SymbolTable, + self_class_symbol: &ClassSymbol, + ) -> (NodesToSymbols, Diagnostics) { + let mut diagnostics = Diagnostics::new(); + let mut names_table = NodesToSymbols::new(); + + for expression in [self.destination.as_ref(), self.value.as_ref()] { + let (ns, mut ds) = expression.resolve_names_method(symbol_table, self_class_symbol); + insert_resolved_names_into(ns, &mut names_table); + diagnostics.append(&mut ds); + } + + (names_table, diagnostics) + } + + #[deprecated] pub fn check_constructor_local_names( &self, symbol_table: &SymbolTable, @@ -100,6 +125,7 @@ impl AssignStatement { .collect() } + #[deprecated] pub fn check_method_local_names( &self, symbol_table: &SymbolTable, @@ -116,6 +142,7 @@ impl AssignStatement { .collect() } + #[deprecated] pub fn check_static_fn_local_names(&self, symbol_table: &SymbolTable) -> Vec { [ self.destination.check_static_fn_local_names(symbol_table), @@ -126,6 +153,79 @@ impl AssignStatement { .collect() } + pub fn resolve_types( + &self, + nodes_to_symbols: &NodesToSymbols, + symbols_to_types: &SymbolsToTypes, + ) -> (NodesToTypes, Diagnostics) { + let mut diagnostics = Diagnostics::new(); + let mut nodes_to_types = NodesToTypes::new(); + + { + let (nts, mut ds) = self.value.resolve_types(nodes_to_symbols, symbols_to_types); + insert_resolved_types_into(nts, &mut nodes_to_types); + diagnostics.append(&mut ds); + } + + { + let (nts, mut ds) = self + .destination + .resolve_types(nodes_to_symbols, symbols_to_types); + insert_resolved_types_into(nts, &mut nodes_to_types); + diagnostics.append(&mut ds); + } + + // check that destination is L value, mutable, and assignable + match &*self.destination { + // must be identifier (for now) + Expression::Identifier(identifier) => { + let expressible_symbol = nodes_to_symbols + .get(&identifier.node_id()) + .unwrap() + .unwrap_expressible_symbol(); + let is_mut = match &expressible_symbol { + ExpressibleSymbol::Field(field_symbol) => field_symbol.is_mut(), + ExpressibleSymbol::Variable(variable_symbol) => variable_symbol.is_mut(), + _ => false, + }; + + // check mut + if !is_mut { + diagnostics.push(destination_must_be_mutable( + self.destination.source_range(), + expressible_symbol.source_range(), + )); + } + + let maybe_expressible_symbol_source_range = + expressible_symbol.source_range().cloned(); + + let lhs_type = symbols_to_types + .get(&expressible_symbol.into_symbol()) + .unwrap(); + let rhs_type = nodes_to_types.get(&self.value.node_id()).unwrap(); + + // check assignable + if !lhs_type.is_assignable_from(rhs_type) { + diagnostics.push(mismatched_assign_types( + rhs_type, + lhs_type, + &SourceRange::new( + self.destination.source_range().start(), + self.value.source_range().end(), + ), + maybe_expressible_symbol_source_range.as_ref(), + )); + } + } + _ => { + diagnostics.push(must_be_l_value(self.destination.source_range())); + } + } + + (nodes_to_types, diagnostics) + } + pub fn type_check( &mut self, symbol_table: &SymbolTable, diff --git a/dmc-lib/src/ast/binary_expression.rs b/dmc-lib/src/ast/binary_expression.rs index 50e64fd..d6e7d4d 100644 --- a/dmc-lib/src/ast/binary_expression.rs +++ b/dmc-lib/src/ast/binary_expression.rs @@ -1,7 +1,7 @@ -use crate::ast::NamesTable; use crate::ast::expression::Expression; -use crate::ast::helpers::insert_resolved_names_into; +use crate::ast::helpers::{insert_resolved_names_into, insert_resolved_types_into}; use crate::ast::ir_builder::IrBuilder; +use crate::ast::{NodeId, NodesToSymbols, NodesToTypes, SymbolsToTypes}; use crate::diagnostic::{Diagnostic, Diagnostics}; use crate::error_codes::BINARY_INCOMPATIBLE_TYPES; use crate::ir::ir_assign::IrAssign; @@ -33,6 +33,7 @@ pub enum BinaryOperation { } pub struct BinaryExpression { + node_id: NodeId, lhs: Box, rhs: Box, op: BinaryOperation, @@ -42,12 +43,14 @@ pub struct BinaryExpression { impl BinaryExpression { pub fn new( + node_id: NodeId, lhs: Expression, rhs: Expression, op: BinaryOperation, source_range: SourceRange, ) -> Self { Self { + node_id, lhs: lhs.into(), rhs: rhs.into(), op, @@ -56,6 +59,10 @@ impl BinaryExpression { } } + pub fn node_id(&self) -> NodeId { + self.node_id + } + pub fn lhs(&self) -> &Expression { &self.lhs } @@ -81,9 +88,12 @@ impl BinaryExpression { self.rhs.init_scopes(symbol_table, container_scope); } - pub fn resolve_names_static(&self, symbol_table: &SymbolTable) -> (NamesTable, Diagnostics) { + pub fn resolve_names_static( + &self, + symbol_table: &SymbolTable, + ) -> (NodesToSymbols, Diagnostics) { let mut diagnostics = Diagnostics::new(); - let mut names_table = NamesTable::new(); + let mut names_table = NodesToSymbols::new(); for expression in [self.lhs.as_ref(), self.rhs.as_ref()] { let (ns, mut ds) = expression.resolve_names_static(symbol_table); @@ -98,9 +108,9 @@ impl BinaryExpression { &self, symbol_table: &SymbolTable, self_class_symbol: &ClassSymbol, - ) -> (NamesTable, Diagnostics) { + ) -> (NodesToSymbols, Diagnostics) { let mut diagnostics = Diagnostics::new(); - let mut names_table = NamesTable::new(); + let mut names_table = NodesToSymbols::new(); for expression in [self.lhs.as_ref(), self.rhs.as_ref()] { let (ns, mut ds) = expression.resolve_names_field_init(symbol_table, self_class_symbol); @@ -115,9 +125,9 @@ impl BinaryExpression { &self, symbol_table: &SymbolTable, self_class_symbol: &ClassSymbol, - ) -> (NamesTable, Diagnostics) { + ) -> (NodesToSymbols, Diagnostics) { let mut diagnostics = Diagnostics::new(); - let mut names_table = NamesTable::new(); + let mut names_table = NodesToSymbols::new(); for expression in [self.lhs.as_ref(), self.rhs.as_ref()] { let (ns, mut ds) = expression.resolve_names_ctor(symbol_table, self_class_symbol); @@ -128,6 +138,24 @@ impl BinaryExpression { (names_table, diagnostics) } + pub fn resolve_names_method( + &self, + symbol_table: &SymbolTable, + self_class_symbol: &ClassSymbol, + ) -> (NodesToSymbols, Diagnostics) { + let mut diagnostics = Diagnostics::new(); + let mut names_table = NodesToSymbols::new(); + + for expression in [self.lhs.as_ref(), self.rhs.as_ref()] { + let (ns, mut ds) = expression.resolve_names_method(symbol_table, self_class_symbol); + insert_resolved_names_into(ns, &mut names_table); + diagnostics.append(&mut ds); + } + + (names_table, diagnostics) + } + + #[deprecated] pub fn check_field_initializer_names( &self, symbol_table: &SymbolTable, @@ -144,6 +172,7 @@ impl BinaryExpression { .collect() } + #[deprecated] pub fn check_constructor_local_names( &self, symbol_table: &SymbolTable, @@ -160,6 +189,7 @@ impl BinaryExpression { .collect() } + #[deprecated] pub fn check_method_local_names( &self, symbol_table: &SymbolTable, @@ -176,6 +206,7 @@ impl BinaryExpression { .collect() } + #[deprecated] pub fn check_static_fn_local_names(&self, symbol_table: &SymbolTable) -> Vec { [ self.lhs.check_static_fn_local_names(symbol_table), @@ -186,6 +217,124 @@ impl BinaryExpression { .collect() } + fn resolve_op_result( + &self, + nodes_to_types: &NodesToTypes, + op_compatibility_check: impl Fn(&TypeInfo, &TypeInfo) -> bool, + get_op_result: impl Fn(&TypeInfo, &TypeInfo) -> TypeInfo, + lazy_diagnostic_message: impl Fn(&TypeInfo, &TypeInfo) -> String, + ) -> (TypeInfo, Diagnostics) { + let lhs_type_info = nodes_to_types.get(&self.lhs.node_id()).unwrap(); + let rhs_type_info = nodes_to_types.get(&self.rhs.node_id()).unwrap(); + + if op_compatibility_check(lhs_type_info, rhs_type_info) { + let op_result = get_op_result(lhs_type_info, rhs_type_info); + (op_result, Diagnostics::new()) + } else { + let mut diagnostics = Diagnostics::new(); + diagnostics.push( + Diagnostic::new( + &lazy_diagnostic_message(lhs_type_info, rhs_type_info), + self.source_range.start(), + self.source_range.end(), + ) + .with_error_code(BINARY_INCOMPATIBLE_TYPES), + ); + (TypeInfo::PlaceholderError, diagnostics) + } + } + + pub fn resolve_types( + &self, + nodes_to_symbols: &NodesToSymbols, + symbols_to_types: &SymbolsToTypes, + ) -> (NodesToTypes, Diagnostics) { + let mut diagnostics = Diagnostics::new(); + let mut nodes_to_types = NodesToTypes::new(); + + { + let (nts, mut ds) = self.lhs.resolve_types(nodes_to_symbols, symbols_to_types); + insert_resolved_types_into(nts, &mut nodes_to_types); + diagnostics.append(&mut ds); + } + + { + let (nts, mut ds) = self.rhs.resolve_types(nodes_to_symbols, symbols_to_types); + insert_resolved_types_into(nts, &mut nodes_to_types); + diagnostics.append(&mut ds); + } + + { + let (result_type_info, mut ds) = match &self.op { + BinaryOperation::Multiply => self.resolve_op_result( + &nodes_to_types, + |lhs, rhs| lhs.can_multiply(rhs), + |lhs, rhs| lhs.multiply_result(rhs), + |lhs, rhs| format!("Incompatible types: cannot multiply {} by {}", lhs, rhs), + ), + BinaryOperation::Divide => self.resolve_op_result( + &nodes_to_types, + |lhs, rhs| lhs.can_divide(rhs), + |lhs, rhs| lhs.divide_result(rhs), + |lhs, rhs| format!("Incompatible types: cannot divide {} by {}", lhs, rhs), + ), + BinaryOperation::Modulo => self.resolve_op_result( + &nodes_to_types, + |lhs, rhs| lhs.can_modulo(rhs), + |lhs, rhs| lhs.modulo_result(rhs), + |lhs, rhs| format!("Incompatible types: cannot modulo {} by {}", lhs, rhs), + ), + BinaryOperation::Add => self.resolve_op_result( + &nodes_to_types, + |lhs, rhs| lhs.can_add(rhs), + |lhs, rhs| lhs.add_result(rhs), + |lhs, rhs| format!("Incompatible types: cannot add {} and {}", lhs, rhs), + ), + BinaryOperation::Subtract => self.resolve_op_result( + &nodes_to_types, + |lhs, rhs| lhs.can_subtract(rhs), + |lhs, rhs| lhs.subtract_result(rhs), + |lhs, rhs| format!("Incompatible types: cannot subtract {} from {}", rhs, lhs), // n.b. order + ), + BinaryOperation::LeftShift => self.resolve_op_result( + &nodes_to_types, + |lhs, rhs| lhs.can_left_shift(rhs), + |lhs, rhs| lhs.left_shift_result(rhs), + |lhs, rhs| format!("Incompatible types: cannot left shift {} by {}", lhs, rhs), + ), + BinaryOperation::RightShift => self.resolve_op_result( + &nodes_to_types, + |lhs, rhs| lhs.can_right_shift(rhs), + |lhs, rhs| lhs.right_shift_result(rhs), + |lhs, rhs| format!("Incompatible types: cannot right shift {} by {}", lhs, rhs), + ), + BinaryOperation::BitwiseAnd => self.resolve_op_result( + &nodes_to_types, + |lhs, rhs| lhs.can_bitwise_and(rhs), + |lhs, rhs| lhs.bitwise_and_result(rhs), + |lhs, rhs| format!("Incompatible types: cannot bitwise-and {} by {}", lhs, rhs), + ), + BinaryOperation::BitwiseXor => self.resolve_op_result( + &nodes_to_types, + |lhs, rhs| lhs.can_bitwise_xor(rhs), + |lhs, rhs| lhs.bitwise_xor_result(rhs), + |lhs, rhs| format!("Incompatible types: cannot bitwise-xor {} by {}", lhs, rhs), + ), + BinaryOperation::BitwiseOr => self.resolve_op_result( + &nodes_to_types, + |lhs, rhs| lhs.can_bitwise_or(rhs), + |lhs, rhs| lhs.bitwise_or_result(rhs), + |lhs, rhs| format!("Incompatible types: cannot bitwise-or {} by {}", lhs, rhs), + ), + }; + + nodes_to_types.insert(self.node_id, result_type_info); + diagnostics.append(&mut ds); + } + + (nodes_to_types, diagnostics) + } + fn check_op( &mut self, symbol_table: &SymbolTable, diff --git a/dmc-lib/src/ast/call.rs b/dmc-lib/src/ast/call.rs index f2b6608..b9ff254 100644 --- a/dmc-lib/src/ast/call.rs +++ b/dmc-lib/src/ast/call.rs @@ -1,13 +1,16 @@ -use crate::ast::NamesTable; use crate::ast::expression::Expression; use crate::ast::fqn_util::fqn_parts_to_string; -use crate::ast::helpers::insert_resolved_names_into; +use crate::ast::helpers::{insert_resolved_names_into, insert_resolved_types_into}; use crate::ast::ir_builder::IrBuilder; +use crate::ast::{NodeId, NodesToSymbols, NodesToTypes, SymbolsToTypes}; use crate::diagnostic::{Diagnostic, Diagnostics}; -use crate::diagnostic_factories::class_has_no_constructor; +use crate::diagnostic_factories::{ + class_has_no_constructor, mismatched_types, receiver_not_callable, wrong_number_of_arguments, +}; use crate::ir::ir_call::IrCall; use crate::ir::ir_expression::IrExpression; use crate::source_range::SourceRange; +use crate::symbol::Symbol; use crate::symbol::callable_symbol::CallableSymbol; use crate::symbol::class_symbol::ClassSymbol; use crate::symbol::expressible_symbol::ExpressibleSymbol; @@ -16,20 +19,31 @@ use crate::type_info::TypeInfo; use crate::types_table::TypesTable; pub struct Call { + node_id: NodeId, callee: Box, arguments: Vec, source_range: SourceRange, } impl Call { - pub fn new(callee: Expression, arguments: Vec, source_range: SourceRange) -> Self { + pub fn new( + node_id: NodeId, + callee: Expression, + arguments: Vec, + source_range: SourceRange, + ) -> Self { Self { + node_id, callee: callee.into(), arguments, source_range, } } + pub fn node_id(&self) -> NodeId { + self.node_id + } + pub fn callee(&self) -> &Expression { &self.callee } @@ -45,9 +59,12 @@ impl Call { } } - pub fn resolve_names_static(&self, symbol_table: &SymbolTable) -> (NamesTable, Diagnostics) { + pub fn resolve_names_static( + &self, + symbol_table: &SymbolTable, + ) -> (NodesToSymbols, Diagnostics) { let mut diagnostics = Diagnostics::new(); - let mut names_table = NamesTable::new(); + let mut names_table = NodesToSymbols::new(); { let (ns, mut ds) = self.callee.resolve_names_static(symbol_table); @@ -68,9 +85,9 @@ impl Call { &self, symbol_table: &SymbolTable, self_class_symbol: &ClassSymbol, - ) -> (NamesTable, Diagnostics) { + ) -> (NodesToSymbols, Diagnostics) { let mut diagnostics = Diagnostics::new(); - let mut names_table = NamesTable::new(); + let mut names_table = NodesToSymbols::new(); { let (ns, mut ds) = self @@ -93,9 +110,9 @@ impl Call { &self, symbol_table: &SymbolTable, self_class_symbol: &ClassSymbol, - ) -> (NamesTable, Diagnostics) { + ) -> (NodesToSymbols, Diagnostics) { let mut diagnostics = Diagnostics::new(); - let mut names_table = NamesTable::new(); + let mut names_table = NodesToSymbols::new(); { let (ns, mut ds) = self @@ -114,6 +131,32 @@ impl Call { (names_table, diagnostics) } + pub fn resolve_names_method( + &self, + symbol_table: &SymbolTable, + self_class_symbol: &ClassSymbol, + ) -> (NodesToSymbols, Diagnostics) { + let mut diagnostics = Diagnostics::new(); + let mut nodes_to_symbols = NodesToSymbols::new(); + + { + let (ns, mut ds) = self + .callee + .resolve_names_method(symbol_table, self_class_symbol); + insert_resolved_names_into(ns, &mut nodes_to_symbols); + diagnostics.append(&mut ds); + } + + for argument in &self.arguments { + let (ns, mut ds) = argument.resolve_names_method(symbol_table, self_class_symbol); + insert_resolved_names_into(ns, &mut nodes_to_symbols); + diagnostics.append(&mut ds); + } + + (nodes_to_symbols, diagnostics) + } + + #[deprecated] pub fn check_field_initializer_names( &self, symbol_table: &SymbolTable, @@ -132,6 +175,7 @@ impl Call { diagnostics } + #[deprecated] pub fn check_constructor_local_names( &self, symbol_table: &SymbolTable, @@ -150,6 +194,7 @@ impl Call { diagnostics } + #[deprecated] pub fn check_method_local_names( &self, symbol_table: &SymbolTable, @@ -167,6 +212,7 @@ impl Call { diagnostics } + #[deprecated] pub fn check_static_fn_local_names(&self, symbol_table: &SymbolTable) -> Vec { let mut diagnostics: Vec = Vec::new(); for argument in &self.arguments { @@ -176,6 +222,88 @@ impl Call { diagnostics } + pub fn resolve_types( + &self, + nodes_to_symbols: &NodesToSymbols, + symbols_to_types: &SymbolsToTypes, + ) -> (NodesToTypes, Diagnostics) { + let mut diagnostics = Diagnostics::new(); + let mut nodes_to_types = NodesToTypes::new(); + + { + let (nts, mut ds) = self + .callee + .resolve_types(nodes_to_symbols, symbols_to_types); + insert_resolved_types_into(nts, &mut nodes_to_types); + diagnostics.append(&mut ds); + } + + for argument in &self.arguments { + let (nts, mut ds) = argument.resolve_types(nodes_to_symbols, symbols_to_types); + insert_resolved_types_into(nts, &mut nodes_to_types); + diagnostics.append(&mut ds); + } + + // get callee symbol and check that its callable + let callee_symbol = nodes_to_symbols.get(&self.callee.node_id()).unwrap(); + let callable_symbol = match callee_symbol { + Symbol::Class(class_symbol) => match class_symbol.constructor_symbol_owned() { + None => { + diagnostics.push(class_has_no_constructor( + class_symbol.declared_name(), + self.callee.source_range(), + )); + CallableSymbol::ErrorPlaceholder + } + Some(constructor_symbol) => CallableSymbol::Constructor(constructor_symbol), + }, + Symbol::Function(function_symbol) => CallableSymbol::Function(function_symbol.clone()), + _ => { + diagnostics.push(receiver_not_callable( + symbols_to_types.get(&callee_symbol).unwrap(), + self.callee.source_range(), + )); + CallableSymbol::ErrorPlaceholder + } + }; + + let parameter_symbols = callable_symbol.parameters(); + + // check args length + if parameter_symbols.len() != self.arguments().len() { + diagnostics.push(wrong_number_of_arguments( + self.source_range(), + parameter_symbols.len(), + self.arguments().len(), + )); + } + + // check arg types + for i in 0..parameter_symbols.len() { + let parameter_symbol = parameter_symbols[i].clone(); + let argument = if i < self.arguments.len() { + &self.arguments[i] + } else { + continue; + }; + let parameter_type_info = symbols_to_types + .get(&Symbol::Parameter(parameter_symbol)) + .unwrap(); + let argument_type_info = nodes_to_types.get(&argument.node_id()).unwrap(); + if !parameter_type_info.is_assignable_from(argument_type_info) { + diagnostics.push(mismatched_types( + parameter_type_info, + argument_type_info, + argument.source_range(), + )); + } + } + + // TODO: insert self type (i.e., the return type of the call) + + (nodes_to_types, diagnostics) + } + pub fn type_check( &mut self, symbol_table: &SymbolTable, @@ -303,6 +431,7 @@ impl Call { .constructor_return_types() .get(&constructor_symbol) .unwrap(), + CallableSymbol::ErrorPlaceholder => unreachable!(), } } @@ -335,6 +464,7 @@ impl Call { arguments, false, ), + CallableSymbol::ErrorPlaceholder => unreachable!(), } } diff --git a/dmc-lib/src/ast/class.rs b/dmc-lib/src/ast/class.rs index 4cd4b84..8b735c2 100644 --- a/dmc-lib/src/ast/class.rs +++ b/dmc-lib/src/ast/class.rs @@ -11,7 +11,7 @@ use crate::ast::helpers::{ resolve_ctor_name, }; use crate::ast::statement::Statement; -use crate::ast::{NamesTable, NodeId}; +use crate::ast::{NodeId, NodesToSymbols}; use crate::diagnostic::{Diagnostic, Diagnostics}; use crate::error_codes::{FIELD_MULTIPLE_INIT, FIELD_UNINIT}; use crate::ir::ir_class::{IrClass, IrField}; @@ -94,7 +94,7 @@ impl Class { symbol_table.pop_scope(); } - pub fn make_symbols(&self, fqn_context: &FqnContext) -> Vec { + pub fn declared_symbols(&self, fqn_context: &FqnContext) -> Vec { let mut all_symbols: Vec = Vec::new(); let mut generic_parameter_symbols = Vec::new(); @@ -133,7 +133,7 @@ impl Class { let mut function_symbols = Vec::new(); for function in &self.functions { let (function_symbol, mut symbols) = - function.make_symbols(&class_body_fqn_context, true); + function.declared_symbols(&class_body_fqn_context, true); all_symbols.append(&mut symbols); function_symbols.push(function_symbol); } @@ -154,9 +154,9 @@ impl Class { all_symbols } - pub fn resolve_names(&self, symbol_table: &mut SymbolTable) -> (NamesTable, Diagnostics) { + pub fn resolve_names(&self, symbol_table: &mut SymbolTable) -> (NodesToSymbols, Diagnostics) { let mut diagnostics = Diagnostics::new(); - let mut names_table = NamesTable::new(); + let mut names_table = NodesToSymbols::new(); for generic_parameter in &self.generic_parameters { let (ns, mut ds) = generic_parameter.resolve_names(symbol_table); diff --git a/dmc-lib/src/ast/compilation_unit.rs b/dmc-lib/src/ast/compilation_unit.rs index e58b1b1..ba8c375 100644 --- a/dmc-lib/src/ast/compilation_unit.rs +++ b/dmc-lib/src/ast/compilation_unit.rs @@ -2,15 +2,17 @@ use crate::ast::class::Class; use crate::ast::extern_function::ExternFunction; use crate::ast::fqn_context::FqnContext; use crate::ast::function::Function; -use crate::ast::helpers::{collect_diagnostics_into_mut, insert_resolved_types_into}; -use crate::ast::{NamesTable, ResolvedTypes}; +use crate::ast::helpers::{ + collect_diagnostics_into_mut, insert_declared_types_into, insert_resolved_types_into, +}; +use crate::ast::{NodesToSymbols, NodesToTypes, SymbolsToTypes}; use crate::compile_pipeline::FileId; use crate::diagnostic::{Diagnostic, Diagnostics}; use crate::ir::ir_class::IrClass; use crate::ir::ir_function::IrFunction; use crate::symbol::Symbol; -use crate::symbol_table::util::try_insert_symbols_into; use crate::symbol_table::SymbolTable; +use crate::symbol_table::util::try_insert_symbols_into; use crate::types_table::TypesTable; use crate::{diagnostics_result, handle_diagnostics}; @@ -62,20 +64,20 @@ impl CompilationUnit { symbol_table.pop_scope(); } - pub fn gather_unordered_symbols(&self) -> Vec { + pub fn declared_symbols(&self) -> Vec { let fqn_context = FqnContext::new(); [ self.classes .iter() - .flat_map(|class| class.make_symbols(&fqn_context)) + .flat_map(|class| class.declared_symbols(&fqn_context)) .collect::>(), self.extern_functions .iter() - .flat_map(|function| function.make_symbols(&fqn_context).1) + .flat_map(|function| function.declared_symbols(&fqn_context).1) .collect(), self.functions .iter() - .flat_map(|function| function.make_symbols(&fqn_context, false).1) + .flat_map(|function| function.declared_symbols(&fqn_context, false).1) .collect(), ] .into_iter() @@ -92,24 +94,24 @@ impl CompilationUnit { let fqn_context = FqnContext::new(); for class in &self.classes { handle_diagnostics!( - try_insert_symbols_into(class.make_symbols(&fqn_context), symbol_table), + try_insert_symbols_into(class.declared_symbols(&fqn_context), symbol_table), diagnostics ); } for function in &self.functions { - let (_, symbols) = function.make_symbols(&fqn_context, false); + let (_, symbols) = function.declared_symbols(&fqn_context, false); handle_diagnostics!(try_insert_symbols_into(symbols, symbol_table), diagnostics); } for extern_function in &self.extern_functions { - let (_, symbols) = extern_function.make_symbols(&fqn_context); + let (_, symbols) = extern_function.declared_symbols(&fqn_context); handle_diagnostics!(try_insert_symbols_into(symbols, symbol_table), diagnostics); } diagnostics_result!(diagnostics) } - pub fn resolve_names(&self, symbol_table: &mut SymbolTable) -> (NamesTable, Diagnostics) { + pub fn resolve_names(&self, symbol_table: &mut SymbolTable) -> (NodesToSymbols, Diagnostics) { let mut diagnostics = Diagnostics::new(); - let mut names_table = NamesTable::new(); + let mut names_table = NodesToSymbols::new(); for function in &self.functions { let (ns, mut ds) = function.resolve_names_static(symbol_table); @@ -156,19 +158,41 @@ impl CompilationUnit { diagnostics_result!(diagnostics) } - pub fn resolve_types(&self, names_table: &NamesTable) -> (ResolvedTypes, Diagnostics) { + /// Associate each declared symbol with a TypeInfo. + pub fn declared_types(&self, names_table: &NodesToSymbols) -> (SymbolsToTypes, Diagnostics) { let mut diagnostics = Diagnostics::new(); - let mut resolved_types = ResolvedTypes::new(); + let mut declared_types = SymbolsToTypes::new(); for function in &self.functions { - let (ts, mut ds) = todo!(); - insert_resolved_types_into(ts, &mut resolved_types); + let (dts, mut ds) = function.declared_types(names_table); + insert_declared_types_into(dts, &mut declared_types); diagnostics.append(&mut ds); } - - (resolved_types, diagnostics) + + (declared_types, diagnostics) } - + + /// Resolve types of all nodes that have an implicit (perhaps not declared) type, checking that + /// things are assignable, etc., along the way. + pub fn resolve_types( + &self, + names_table: &NodesToSymbols, + symbols_to_types: &SymbolsToTypes, + ) -> (SymbolsToTypes, NodesToTypes, Diagnostics) { + let mut diagnostics = Diagnostics::new(); + let mut resolved_types = NodesToTypes::new(); + let mut symbols_to_types = symbols_to_types.clone(); + + for function in &self.functions { + let (sts, nts, mut ds) = function.resolve_types(names_table, &symbols_to_types); + insert_declared_types_into(sts, &mut symbols_to_types); + insert_resolved_types_into(nts, &mut resolved_types); + diagnostics.append(&mut ds); + } + + (symbols_to_types, resolved_types, diagnostics) + } + #[deprecated] pub fn gather_types_into( &self, @@ -192,6 +216,7 @@ impl CompilationUnit { diagnostics_result!(diagnostics) } + #[deprecated] pub fn type_check( &mut self, symbol_table: &SymbolTable, @@ -220,6 +245,10 @@ impl CompilationUnit { diagnostics_result!(diagnostics) } + pub fn lower(&self, resolved_types: &NodesToTypes) -> (Vec, Vec) { + todo!() + } + pub fn to_ir( &self, symbol_table: &SymbolTable, diff --git a/dmc-lib/src/ast/constructor.rs b/dmc-lib/src/ast/constructor.rs index 4e24135..60b9f31 100644 --- a/dmc-lib/src/ast/constructor.rs +++ b/dmc-lib/src/ast/constructor.rs @@ -1,4 +1,4 @@ -use crate::ast::NamesTable; +use crate::ast::NodesToSymbols; use crate::ast::field::Field; use crate::ast::fqn_context::FqnContext; use crate::ast::fqn_util::fqn_parts_to_string; @@ -103,9 +103,9 @@ impl Constructor { symbol_table: &mut SymbolTable, self_class_symbol: &ClassSymbol, initialized_fields: &mut HashSet>, - ) -> (NamesTable, Diagnostics) { + ) -> (NodesToSymbols, Diagnostics) { let mut diagnostics = Diagnostics::new(); - let mut names_table = NamesTable::new(); + let mut names_table = NodesToSymbols::new(); for parameter in &self.parameters { let (ns, mut ds) = parameter.resolve_names(symbol_table); diff --git a/dmc-lib/src/ast/double_literal.rs b/dmc-lib/src/ast/double_literal.rs index b743fb3..f6b4e4a 100644 --- a/dmc-lib/src/ast/double_literal.rs +++ b/dmc-lib/src/ast/double_literal.rs @@ -1,22 +1,29 @@ +use crate::ast::NodeId; use crate::source_range::SourceRange; use crate::type_info::TypeInfo; pub struct DoubleLiteral { + node_id: NodeId, value: f64, source_range: SourceRange, type_info: &'static TypeInfo, } impl DoubleLiteral { - pub fn new(value: f64, source_range: SourceRange) -> Self { + pub fn new(node_id: NodeId, value: f64, source_range: SourceRange) -> Self { const TYPE_INFO: TypeInfo = TypeInfo::Double; Self { + node_id, value, source_range, type_info: &TYPE_INFO, } } + pub fn node_id(&self) -> NodeId { + self.node_id + } + pub fn value(&self) -> f64 { self.value } diff --git a/dmc-lib/src/ast/expression.rs b/dmc-lib/src/ast/expression.rs index 3b12b44..e3fc047 100644 --- a/dmc-lib/src/ast/expression.rs +++ b/dmc-lib/src/ast/expression.rs @@ -1,4 +1,3 @@ -use crate::ast::NamesTable; use crate::ast::binary_expression::BinaryExpression; use crate::ast::call::Call; use crate::ast::double_literal::DoubleLiteral; @@ -7,6 +6,7 @@ use crate::ast::integer_literal::IntegerLiteral; use crate::ast::ir_builder::IrBuilder; use crate::ast::negative_expression::NegativeExpression; use crate::ast::string_literal::StringLiteral; +use crate::ast::{NodeId, NodesToSymbols, NodesToTypes, SymbolsToTypes}; use crate::diagnostic::{Diagnostic, Diagnostics}; use crate::ir::ir_assign::IrAssign; use crate::ir::ir_expression::IrExpression; @@ -32,6 +32,18 @@ pub enum Expression { } impl Expression { + pub fn node_id(&self) -> NodeId { + match self { + Expression::Binary(binary_expression) => binary_expression.node_id(), + Expression::Negative(negative_expression) => negative_expression.node_id(), + Expression::Call(call) => call.node_id(), + Expression::Identifier(identifier) => identifier.node_id(), + Expression::Integer(integer_literal) => integer_literal.node_id(), + Expression::Double(double_literal) => double_literal.node_id(), + Expression::String(string_literal) => string_literal.node_id(), + } + } + pub fn init_scopes(&mut self, symbol_table: &mut SymbolTable, container_scope: usize) { match self { Expression::Binary(binary_expression) => { @@ -50,7 +62,10 @@ impl Expression { } } - pub fn resolve_names_static(&self, symbol_table: &SymbolTable) -> (NamesTable, Diagnostics) { + pub fn resolve_names_static( + &self, + symbol_table: &SymbolTable, + ) -> (NodesToSymbols, Diagnostics) { match self { Expression::Binary(binary_expression) => { binary_expression.resolve_names_static(symbol_table) @@ -60,7 +75,7 @@ impl Expression { } Expression::Call(call) => call.resolve_names_static(symbol_table), Expression::Identifier(identifier) => identifier.resolve_name_static(symbol_table), - _ => (NamesTable::new(), Diagnostics::new()), + _ => (NodesToSymbols::new(), Diagnostics::new()), } } @@ -68,7 +83,7 @@ impl Expression { &self, symbol_table: &SymbolTable, self_class_symbol: &ClassSymbol, - ) -> (NamesTable, Diagnostics) { + ) -> (NodesToSymbols, Diagnostics) { match self { Expression::Binary(binary_expression) => { binary_expression.resolve_names_field_init(symbol_table, self_class_symbol) @@ -82,7 +97,7 @@ impl Expression { Expression::Identifier(identifier) => { identifier.resolve_name_field_init(symbol_table, self_class_symbol) } - _ => (NamesTable::new(), Diagnostics::new()), + _ => (NodesToSymbols::new(), Diagnostics::new()), } } @@ -90,7 +105,7 @@ impl Expression { &self, symbol_table: &SymbolTable, self_class_symbol: &ClassSymbol, - ) -> (NamesTable, Diagnostics) { + ) -> (NodesToSymbols, Diagnostics) { match self { Expression::Binary(binary_expression) => { binary_expression.resolve_names_ctor(symbol_table, self_class_symbol) @@ -102,10 +117,31 @@ impl Expression { Expression::Identifier(identifier) => { identifier.resolve_name_ctor(symbol_table, self_class_symbol) } - _ => (NamesTable::new(), Diagnostics::new()), + _ => (NodesToSymbols::new(), Diagnostics::new()), } } + pub fn resolve_names_method( + &self, + symbol_table: &SymbolTable, + self_class_symbol: &ClassSymbol, + ) -> (NodesToSymbols, Diagnostics) { + match self { + Expression::Binary(binary_expression) => { + binary_expression.resolve_names_method(symbol_table, self_class_symbol) + } + Expression::Negative(negative_expression) => { + negative_expression.resolve_names_method(symbol_table, self_class_symbol) + } + Expression::Call(call) => call.resolve_names_method(symbol_table, self_class_symbol), + Expression::Identifier(identifier) => { + identifier.resolve_name_method(symbol_table, self_class_symbol) + } + _ => (NodesToSymbols::new(), Diagnostics::new()), + } + } + + #[deprecated] pub fn check_field_initializer_names( &self, symbol_table: &SymbolTable, @@ -134,6 +170,7 @@ impl Expression { } } + #[deprecated] pub fn check_constructor_destination_names( &self, symbol_table: &SymbolTable, @@ -162,6 +199,7 @@ impl Expression { } } + #[deprecated] pub fn check_constructor_local_names( &self, symbol_table: &SymbolTable, @@ -190,6 +228,7 @@ impl Expression { } } + #[deprecated] pub fn check_method_local_names( &self, symbol_table: &SymbolTable, @@ -216,6 +255,7 @@ impl Expression { } } + #[deprecated] pub fn check_static_fn_local_names(&self, symbol_table: &SymbolTable) -> Vec { match self { Expression::Binary(binary_expression) => { @@ -244,6 +284,43 @@ impl Expression { } } + pub fn resolve_types( + &self, + nodes_to_symbols: &NodesToSymbols, + symbols_to_types: &SymbolsToTypes, + ) -> (NodesToTypes, Diagnostics) { + match self { + Expression::Binary(binary_expression) => { + binary_expression.resolve_types(nodes_to_symbols, symbols_to_types) + } + Expression::Negative(negative_expression) => { + negative_expression.resolve_types(nodes_to_symbols, symbols_to_types) + } + Expression::Call(call) => call.resolve_types(nodes_to_symbols, symbols_to_types), + Expression::Identifier(identifier) => { + identifier.resolve_type(nodes_to_symbols, symbols_to_types) + } + Expression::Integer(integer_literal) => { + let mut resolved_types = NodesToTypes::new(); + resolved_types.insert( + integer_literal.node_id(), + integer_literal.type_info().clone(), + ); + (resolved_types, Diagnostics::new()) + } + Expression::Double(double_literal) => { + let mut resolved_types = NodesToTypes::new(); + resolved_types.insert(double_literal.node_id(), double_literal.type_info().clone()); + (resolved_types, Diagnostics::new()) + } + Expression::String(string_literal) => { + let mut resolved_types = NodesToTypes::new(); + resolved_types.insert(string_literal.node_id(), string_literal.type_info().clone()); + (resolved_types, Diagnostics::new()) + } + } + } + pub fn type_check( &mut self, symbol_table: &SymbolTable, diff --git a/dmc-lib/src/ast/expression_statement.rs b/dmc-lib/src/ast/expression_statement.rs index 65f82a6..58a083c 100644 --- a/dmc-lib/src/ast/expression_statement.rs +++ b/dmc-lib/src/ast/expression_statement.rs @@ -1,6 +1,6 @@ -use crate::ast::NamesTable; use crate::ast::expression::Expression; use crate::ast::ir_builder::IrBuilder; +use crate::ast::{NodeId, NodesToSymbols, NodesToTypes, SymbolsToTypes}; use crate::diagnostic::{Diagnostic, Diagnostics}; use crate::ir::ir_return::IrReturn; use crate::ir::ir_statement::IrStatement; @@ -10,12 +10,14 @@ use crate::type_info::TypeInfo; use crate::types_table::TypesTable; pub struct ExpressionStatement { + node_id: NodeId, expression: Box, } impl ExpressionStatement { - pub fn new(expression: Expression) -> Self { + pub fn new(node_id: NodeId, expression: Expression) -> Self { Self { + node_id, expression: expression.into(), } } @@ -28,7 +30,10 @@ impl ExpressionStatement { self.expression.init_scopes(symbol_table, container_scope); } - pub fn resolve_names_static(&self, symbol_table: &SymbolTable) -> (NamesTable, Diagnostics) { + pub fn resolve_names_static( + &self, + symbol_table: &SymbolTable, + ) -> (NodesToSymbols, Diagnostics) { self.expression.resolve_names_static(symbol_table) } @@ -36,11 +41,21 @@ impl ExpressionStatement { &self, symbol_table: &SymbolTable, self_class_symbol: &ClassSymbol, - ) -> (NamesTable, Diagnostics) { + ) -> (NodesToSymbols, Diagnostics) { self.expression .resolve_names_ctor(symbol_table, self_class_symbol) } + pub fn resolve_names_method( + &self, + symbol_table: &SymbolTable, + self_class_symbol: &ClassSymbol, + ) -> (NodesToSymbols, Diagnostics) { + self.expression + .resolve_names_method(symbol_table, self_class_symbol) + } + + #[deprecated] pub fn check_constructor_local_names( &self, symbol_table: &SymbolTable, @@ -50,6 +65,7 @@ impl ExpressionStatement { .check_constructor_local_names(symbol_table, class_symbol) } + #[deprecated] pub fn check_method_local_names( &self, symbol_table: &SymbolTable, @@ -59,10 +75,30 @@ impl ExpressionStatement { .check_method_local_names(symbol_table, class_symbol) } + #[deprecated] pub fn check_static_fn_local_names(&self, symbol_table: &SymbolTable) -> Vec { self.expression.check_static_fn_local_names(symbol_table) } + pub fn resolve_types( + &self, + nodes_to_symbols: &NodesToSymbols, + symbols_to_types: &SymbolsToTypes, + ) -> (NodesToTypes, Diagnostics) { + let (mut nodes_to_types, diagnostics) = self + .expression + .resolve_types(nodes_to_symbols, symbols_to_types); + + // add self for last-statement type checking + let expression_type_info = nodes_to_types + .get(&self.expression.node_id()) + .cloned() + .unwrap(); + nodes_to_types.insert(self.node_id, expression_type_info); + + (nodes_to_types, diagnostics) + } + pub fn type_check( &mut self, symbol_table: &SymbolTable, diff --git a/dmc-lib/src/ast/extern_function.rs b/dmc-lib/src/ast/extern_function.rs index d7ee0dd..8480f0b 100644 --- a/dmc-lib/src/ast/extern_function.rs +++ b/dmc-lib/src/ast/extern_function.rs @@ -4,7 +4,7 @@ use crate::ast::helpers::{ }; use crate::ast::parameter::Parameter; use crate::ast::type_use::TypeUse; -use crate::ast::{NamesTable, NodeId}; +use crate::ast::{NodeId, NodesToSymbols}; use crate::diagnostic::{Diagnostic, Diagnostics}; use crate::source_range::SourceRange; use crate::symbol::Symbol; @@ -60,7 +60,7 @@ impl ExternFunction { symbol_table.pop_scope(); } - pub fn make_symbols(&self, fqn_context: &FqnContext) -> (Rc, Vec) { + pub fn declared_symbols(&self, fqn_context: &FqnContext) -> (Rc, Vec) { let mut all_symbols: Vec = Vec::new(); let mut parameter_symbols = Vec::new(); @@ -80,9 +80,12 @@ impl ExternFunction { (function_symbol, all_symbols) } - pub fn resolve_names_static(&self, symbol_table: &SymbolTable) -> (NamesTable, Diagnostics) { + pub fn resolve_names_static( + &self, + symbol_table: &SymbolTable, + ) -> (NodesToSymbols, Diagnostics) { let mut diagnostics = Diagnostics::new(); - let mut names_table = NamesTable::new(); + let mut names_table = NodesToSymbols::new(); resolve_parameter_names_into( &self.parameters, diff --git a/dmc-lib/src/ast/field.rs b/dmc-lib/src/ast/field.rs index f4ed690..801690c 100644 --- a/dmc-lib/src/ast/field.rs +++ b/dmc-lib/src/ast/field.rs @@ -1,4 +1,4 @@ -use crate::ast::NamesTable; +use crate::ast::NodesToSymbols; use crate::ast::expression::Expression; use crate::ast::helpers::insert_resolved_names_into; use crate::ast::type_use::TypeUse; @@ -85,8 +85,8 @@ impl Field { &self, symbol_table: &SymbolTable, class_symbol: &ClassSymbol, - ) -> (NamesTable, Diagnostics) { - let mut names_table = NamesTable::new(); + ) -> (NodesToSymbols, Diagnostics) { + let mut names_table = NodesToSymbols::new(); let mut diagnostics = Diagnostics::new(); if let Some(type_use) = &self.declared_type { diff --git a/dmc-lib/src/ast/function.rs b/dmc-lib/src/ast/function.rs index 571cd64..7e37fe4 100644 --- a/dmc-lib/src/ast/function.rs +++ b/dmc-lib/src/ast/function.rs @@ -2,13 +2,14 @@ use crate::ast::fqn_context::FqnContext; use crate::ast::fqn_util::fqn_parts_to_string; use crate::ast::helpers::{ collect_diagnostics_into_enumerated_mut, collect_diagnostics_into_mut, - collect_parameter_symbols_into, resolve_parameter_names_into, + collect_parameter_symbols_into, insert_declared_types_into, insert_resolved_names_into, + insert_resolved_types_into, resolve_parameter_names_into, }; use crate::ast::ir_builder::IrBuilder; use crate::ast::parameter::Parameter; use crate::ast::statement::Statement; use crate::ast::type_use::TypeUse; -use crate::ast::{NamesTable, NodeId}; +use crate::ast::{NodeId, NodesToSymbols, NodesToTypes, SymbolsToTypes}; use crate::diagnostic::{Diagnostic, Diagnostics}; use crate::ir::ir_function::IrFunction; use crate::ir::ir_parameter::IrParameter; @@ -57,6 +58,10 @@ impl Function { } } + pub fn node_id(&self) -> NodeId { + self.node_id + } + pub fn declared_name(&self) -> &str { &self.declared_name } @@ -88,7 +93,8 @@ impl Function { symbol_table.pop_scope(); // function } - pub fn make_symbols( + /// Return value contains self FunctionSymbol followed by all symbols (including self symbol). + pub fn declared_symbols( &self, fqn_context: &FqnContext, is_method: bool, @@ -112,51 +118,58 @@ impl Function { (function_symbol, all_symbols) } - fn resolve_names_common(&self, symbol_table: &SymbolTable) -> (NamesTable, Diagnostics) { + fn resolve_names_common(&self, symbol_table: &SymbolTable) -> (NodesToSymbols, Diagnostics) { let mut diagnostics = Diagnostics::new(); - let mut names_table = NamesTable::new(); + let mut nodes_to_symbols = NodesToSymbols::new(); resolve_parameter_names_into( &self.parameters, symbol_table, - &mut names_table, + &mut nodes_to_symbols, &mut diagnostics, ); if let Some(type_use) = &self.return_type { let (ns, mut ds) = type_use.resolve_names(symbol_table); - for (node_id, symbol) in ns { - names_table.insert(node_id, symbol); - } + insert_resolved_names_into(ns, &mut nodes_to_symbols); diagnostics.append(&mut ds); } - (names_table, diagnostics) + (nodes_to_symbols, diagnostics) } pub fn resolve_names_static( &self, symbol_table: &mut SymbolTable, - ) -> (NamesTable, Diagnostics) { - let (mut names_table, mut diagnostics) = self.resolve_names_common(symbol_table); + ) -> (NodesToSymbols, Diagnostics) { + let (mut nodes_to_symbols, mut diagnostics) = self.resolve_names_common(symbol_table); for statement in &self.statements { let (ns, mut ds) = statement.resolve_names_static(symbol_table); - for (node_id, symbol) in ns { - names_table.insert(node_id, symbol); - } + insert_resolved_names_into(ns, &mut nodes_to_symbols); diagnostics.append(&mut ds); } - (names_table, diagnostics) + (nodes_to_symbols, diagnostics) } - pub fn resolve_names_method(&self, symbol_table: &SymbolTable) -> (NamesTable, Diagnostics) { - let (names_table, diagnostics) = self.resolve_names_common(symbol_table); + pub fn resolve_names_method( + &self, + symbol_table: &mut SymbolTable, + self_class_symbol: &ClassSymbol, + ) -> (NodesToSymbols, Diagnostics) { + let (mut nodes_to_symbols, mut diagnostics) = self.resolve_names_common(symbol_table); - (names_table, diagnostics) + for statement in &self.statements { + let (ns, mut ds) = statement.resolve_names_method(symbol_table, self_class_symbol); + insert_resolved_names_into(ns, &mut nodes_to_symbols); + diagnostics.append(&mut ds); + } + + (nodes_to_symbols, diagnostics) } + #[deprecated] pub fn check_names(&self, symbol_table: &SymbolTable) -> Vec { let mut diagnostics = Vec::new(); for parameter in &self.parameters { @@ -168,6 +181,7 @@ impl Function { diagnostics } + #[deprecated] pub fn analyze_method_local_names( &self, symbol_table: &mut SymbolTable, @@ -179,6 +193,7 @@ impl Function { .collect() } + #[deprecated] pub fn analyze_static_fn_local_names(&self, symbol_table: &mut SymbolTable) -> Vec { self.statements .iter() @@ -186,6 +201,41 @@ impl Function { .collect() } + pub fn declared_types(&self, names_table: &NodesToSymbols) -> (SymbolsToTypes, Diagnostics) { + let mut diagnostics = Diagnostics::new(); + let mut declared_types = SymbolsToTypes::new(); + + for parameter in &self.parameters { + let symbol = names_table.get(¶meter.node_id()).unwrap(); + let (type_info, mut ds) = parameter.declared_type(names_table); + declared_types.insert(symbol.clone(), type_info); + diagnostics.append(&mut ds); + } + + (declared_types, diagnostics) + } + + pub fn resolve_types( + &self, + nodes_to_symbols: &NodesToSymbols, + symbols_to_types: &SymbolsToTypes, + ) -> (SymbolsToTypes, NodesToTypes, Diagnostics) { + let mut diagnostics = Diagnostics::new(); + let mut nodes_to_types = NodesToTypes::new(); + let mut symbols_to_types = symbols_to_types.clone(); + + for statement in &self.statements { + let (sts, nts, mut ds) = statement.resolve_types(nodes_to_symbols, &symbols_to_types); + insert_declared_types_into(sts, &mut symbols_to_types); // merge! + insert_resolved_types_into(nts, &mut nodes_to_types); + diagnostics.append(&mut ds); + } + + // todo: check last statement for return type + + (symbols_to_types, nodes_to_types, 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()) diff --git a/dmc-lib/src/ast/generic_parameter.rs b/dmc-lib/src/ast/generic_parameter.rs index a2689db..9d5de25 100644 --- a/dmc-lib/src/ast/generic_parameter.rs +++ b/dmc-lib/src/ast/generic_parameter.rs @@ -1,4 +1,4 @@ -use crate::ast::NamesTable; +use crate::ast::NodesToSymbols; use crate::ast::helpers::insert_resolved_names_into; use crate::ast::type_use::TypeUse; use crate::diagnostic::{Diagnostic, Diagnostics}; @@ -49,9 +49,9 @@ impl GenericParameter { ) } - pub fn resolve_names(&self, symbol_table: &SymbolTable) -> (NamesTable, Diagnostics) { + pub fn resolve_names(&self, symbol_table: &SymbolTable) -> (NodesToSymbols, Diagnostics) { let mut diagnostics = Diagnostics::new(); - let mut names_table = NamesTable::new(); + let mut names_table = NodesToSymbols::new(); for type_use in &self.extends { let (ns, mut ds) = type_use.resolve_names(symbol_table); diff --git a/dmc-lib/src/ast/helpers.rs b/dmc-lib/src/ast/helpers.rs index 81e8df0..fb6de86 100644 --- a/dmc-lib/src/ast/helpers.rs +++ b/dmc-lib/src/ast/helpers.rs @@ -1,6 +1,6 @@ -use crate::ast::{NamesTable, ResolvedTypes}; use crate::ast::fqn_context::FqnContext; use crate::ast::parameter::Parameter; +use crate::ast::{NodesToSymbols, NodesToTypes, SymbolsToTypes}; use crate::diagnostic::{Diagnostic, Diagnostics}; use crate::diagnostics_result; use crate::symbol::Symbol; @@ -110,25 +110,31 @@ pub fn collect_parameter_symbols_into( pub fn resolve_parameter_names_into( parameters: &[Parameter], symbol_table: &SymbolTable, - names_table: &mut NamesTable, + nodes_to_symbols: &mut NodesToSymbols, diagnostics: &mut Diagnostics, ) { for parameter in parameters { let (ns, mut ds) = parameter.resolve_names(symbol_table); for (node_id, symbol) in ns { - names_table.insert(node_id, symbol); + nodes_to_symbols.insert(node_id, symbol); } diagnostics.append(&mut ds); } } -pub fn insert_resolved_names_into(source: NamesTable, destination: &mut NamesTable) { +pub fn insert_resolved_names_into(source: NodesToSymbols, destination: &mut NodesToSymbols) { for (node_id, symbol) in source { destination.insert(node_id, symbol); } } -pub fn insert_resolved_types_into(source: ResolvedTypes, destination: &mut ResolvedTypes) { +pub fn insert_declared_types_into(source: SymbolsToTypes, destination: &mut SymbolsToTypes) { + for (symbol, type_info) in source { + destination.insert(symbol, type_info); + } +} + +pub fn insert_resolved_types_into(source: NodesToTypes, destination: &mut NodesToTypes) { for (node_id, type_info) in source { destination.insert(node_id, type_info); } diff --git a/dmc-lib/src/ast/identifier.rs b/dmc-lib/src/ast/identifier.rs index 4d3ef1d..610adea 100644 --- a/dmc-lib/src/ast/identifier.rs +++ b/dmc-lib/src/ast/identifier.rs @@ -1,6 +1,6 @@ use crate::ast::ir_builder::IrBuilder; use crate::ast::ir_util::get_or_init_field_pointer_variable; -use crate::ast::{NamesTable, NodeId}; +use crate::ast::{NodeId, NodesToSymbols, NodesToTypes, SymbolsToTypes}; use crate::diagnostic::{Diagnostic, Diagnostics}; use crate::diagnostic_factories::{ cannot_reassign_immutable_field, not_assignable, outer_class_field_usage, @@ -43,6 +43,10 @@ impl Identifier { } } + pub fn node_id(&self) -> NodeId { + self.node_id + } + pub fn name(&self) -> &str { &self.name } @@ -55,9 +59,9 @@ impl Identifier { self.scope_id.unwrap() } - pub fn resolve_name_static(&self, symbol_table: &SymbolTable) -> (NamesTable, Diagnostics) { + pub fn resolve_name_static(&self, symbol_table: &SymbolTable) -> (NodesToSymbols, Diagnostics) { let mut diagnostics = Diagnostics::new(); - let mut names_table = NamesTable::new(); + let mut names_table = NodesToSymbols::new(); match symbol_table.find_expressible_symbol(self.scope_id.unwrap(), &self.name) { None => { @@ -75,9 +79,9 @@ impl Identifier { &self, symbol_table: &SymbolTable, self_class_symbol: &ClassSymbol, - ) -> (NamesTable, Diagnostics) { + ) -> (NodesToSymbols, Diagnostics) { let mut diagnostics = Diagnostics::new(); - let mut names_table = NamesTable::new(); + let mut names_table = NodesToSymbols::new(); let symbol = symbol_table.find_expressible_symbol(self.scope_id.unwrap(), &self.name); if let Some(symbol) = symbol { @@ -125,9 +129,9 @@ impl Identifier { &self, symbol_table: &SymbolTable, self_class_symbol: &ClassSymbol, - ) -> (NamesTable, Diagnostics) { + ) -> (NodesToSymbols, Diagnostics) { let mut diagnostics = Diagnostics::new(); - let mut names_table = NamesTable::new(); + let mut names_table = NodesToSymbols::new(); let symbol = symbol_table.find_expressible_symbol(self.scope_id.unwrap(), &self.name); if let Some(symbol) = symbol { @@ -173,9 +177,9 @@ impl Identifier { &self, symbol_table: &SymbolTable, initialized_fields: &mut HashSet>, - ) -> (NamesTable, Diagnostics) { + ) -> (NodesToSymbols, Diagnostics) { let mut diagnostics = Diagnostics::new(); - let mut names_table = NamesTable::new(); + let mut names_table = NodesToSymbols::new(); let symbol = symbol_table.find_expressible_symbol(self.scope_id.unwrap(), &self.name); if let Some(symbol) = symbol { @@ -217,11 +221,33 @@ impl Identifier { (names_table, diagnostics) } + pub fn resolve_name_method( + &self, + symbol_table: &SymbolTable, + _self_class_symbol: &ClassSymbol, // for future when we have paths? + ) -> (NodesToSymbols, Diagnostics) { + let mut diagnostics = Diagnostics::new(); + let mut nodes_to_symbols = NodesToSymbols::new(); + + let maybe_expressible_symbol = + symbol_table.find_expressible_symbol(self.scope_id.unwrap(), &self.name); + match maybe_expressible_symbol { + None => { + diagnostics.push(symbol_not_found(&self.name, &self.source_range)); + } + Some(expressible_symbol) => { + nodes_to_symbols.insert(self.node_id, expressible_symbol.into_symbol()); + } + } + + (nodes_to_symbols, diagnostics) + } + fn init_referring_to_class( &self, self_class_symbol: &ClassSymbol, class_symbol: &Rc, - names_table: &mut NamesTable, + names_table: &mut NodesToSymbols, diagnostics: &mut Diagnostics, ) { // Check against recursively constructing this class. @@ -254,7 +280,7 @@ impl Identifier { &self, self_class_symbol: &ClassSymbol, function_symbol: &Rc, - names_table: &mut NamesTable, + names_table: &mut NodesToSymbols, diagnostics: &mut Diagnostics, ) { if self_class_symbol @@ -356,6 +382,7 @@ impl Identifier { } } + #[deprecated] pub fn check_constructor_destination_name( &self, symbol_table: &SymbolTable, @@ -390,6 +417,7 @@ impl Identifier { } } + #[deprecated] pub fn check_constructor_local_name( &self, symbol_table: &SymbolTable, @@ -415,6 +443,7 @@ impl Identifier { } } + #[deprecated] pub fn check_method_local_name( &self, symbol_table: &SymbolTable, @@ -462,6 +491,7 @@ impl Identifier { } /// WARNING: this is not appropriate (yet) for class static functions. + #[deprecated] pub fn check_static_fn_local_name(&self, symbol_table: &SymbolTable) -> Option { if symbol_table .find_expressible_symbol(self.scope_id.unwrap(), &self.name) @@ -477,6 +507,20 @@ impl Identifier { &self.source_range } + pub fn resolve_type( + &self, + resolved_symbols: &NodesToSymbols, + resolved_symbol_type_infos: &SymbolsToTypes, + ) -> (NodesToTypes, Diagnostics) { + let self_symbol = resolved_symbols.get(&self.node_id).unwrap(); + let type_info = resolved_symbol_type_infos.get(self_symbol).unwrap(); + + let mut resolved_types = NodesToTypes::new(); + resolved_types.insert(self.node_id, type_info.clone()); + + (resolved_types, Diagnostics::new()) + } + pub fn type_info<'a>( &self, symbol_table: &SymbolTable, diff --git a/dmc-lib/src/ast/integer_literal.rs b/dmc-lib/src/ast/integer_literal.rs index 9729ad4..9105b1b 100644 --- a/dmc-lib/src/ast/integer_literal.rs +++ b/dmc-lib/src/ast/integer_literal.rs @@ -1,16 +1,19 @@ +use crate::ast::NodeId; use crate::source_range::SourceRange; use crate::type_info::TypeInfo; pub struct IntegerLiteral { + node_id: NodeId, value: i32, source_range: SourceRange, type_info: &'static TypeInfo, } impl IntegerLiteral { - pub fn new(value: i32, source_range: SourceRange) -> Self { + pub fn new(node_id: NodeId, value: i32, source_range: SourceRange) -> Self { const TYPE_INFO: TypeInfo = TypeInfo::Integer; Self { + node_id, value, source_range, type_info: &TYPE_INFO, @@ -21,6 +24,10 @@ impl IntegerLiteral { self.value } + pub fn node_id(&self) -> NodeId { + self.node_id + } + pub fn type_info(&self) -> &TypeInfo { &self.type_info } diff --git a/dmc-lib/src/ast/let_statement.rs b/dmc-lib/src/ast/let_statement.rs index edb8bf6..41fc426 100644 --- a/dmc-lib/src/ast/let_statement.rs +++ b/dmc-lib/src/ast/let_statement.rs @@ -1,7 +1,7 @@ -use crate::ast::NamesTable; use crate::ast::expression::Expression; -use crate::ast::helpers::insert_resolved_names_into; +use crate::ast::helpers::{insert_resolved_names_into, insert_resolved_types_into}; use crate::ast::ir_builder::IrBuilder; +use crate::ast::{NodeId, NodesToSymbols, NodesToTypes, SymbolsToTypes}; use crate::diagnostic::{Diagnostic, Diagnostics}; use crate::ir::ir_assign::IrAssign; use crate::ir::ir_statement::IrStatement; @@ -18,6 +18,7 @@ use std::cell::RefCell; use std::rc::Rc; pub struct LetStatement { + node_id: NodeId, declared_name: Rc, declared_name_source_range: SourceRange, is_mut: bool, @@ -27,12 +28,14 @@ pub struct LetStatement { impl LetStatement { pub fn new( + node_id: NodeId, declared_name: &str, declared_name_source_range: SourceRange, is_mut: bool, initializer: Expression, ) -> Self { Self { + node_id, declared_name: declared_name.into(), declared_name_source_range, is_mut, @@ -78,8 +81,8 @@ impl LetStatement { pub fn resolve_names_static( &self, symbol_table: &mut SymbolTable, - ) -> (NamesTable, Diagnostics) { - let mut names_table = NamesTable::new(); + ) -> (NodesToSymbols, Diagnostics) { + let mut names_table = NodesToSymbols::new(); let mut diagnostics = Diagnostics::new(); { @@ -99,15 +102,15 @@ impl LetStatement { &self, symbol_table: &mut SymbolTable, self_class_symbol: &ClassSymbol, - ) -> (NamesTable, Diagnostics) { - let mut names_table = NamesTable::new(); + ) -> (NodesToSymbols, Diagnostics) { + let mut nodes_to_symbols = NodesToSymbols::new(); let mut diagnostics = Diagnostics::new(); { let (ns, mut ds) = self .initializer .resolve_names_ctor(symbol_table, self_class_symbol); - insert_resolved_names_into(ns, &mut names_table); + insert_resolved_names_into(ns, &mut nodes_to_symbols); diagnostics.append(&mut ds); } @@ -115,9 +118,33 @@ impl LetStatement { diagnostics.push(diagnostic); } - (names_table, diagnostics) + (nodes_to_symbols, diagnostics) } + pub fn resolve_names_method( + &self, + symbol_table: &mut SymbolTable, + self_class_symbol: &ClassSymbol, + ) -> (NodesToSymbols, Diagnostics) { + let mut nodes_to_symbols = NodesToSymbols::new(); + let mut diagnostics = Diagnostics::new(); + + { + let (ns, mut ds) = self + .initializer + .resolve_names_method(symbol_table, self_class_symbol); + insert_resolved_names_into(ns, &mut nodes_to_symbols); + diagnostics.append(&mut ds); + } + + if let Some(diagnostic) = self.make_and_insert_variable_symbol(symbol_table) { + diagnostics.push(diagnostic); + } + + (nodes_to_symbols, diagnostics) + } + + #[deprecated] pub fn analyze_constructor_local_names( &self, symbol_table: &mut SymbolTable, @@ -136,6 +163,7 @@ impl LetStatement { diagnostics } + #[deprecated] pub fn analyze_method_local_names( &self, symbol_table: &mut SymbolTable, @@ -153,6 +181,7 @@ impl LetStatement { diagnostics } + #[deprecated] pub fn analyze_static_fn_local_names(&self, symbol_table: &mut SymbolTable) -> Vec { let mut diagnostics = Vec::new(); diagnostics.append(&mut self.initializer.check_static_fn_local_names(symbol_table)); @@ -162,17 +191,29 @@ impl LetStatement { diagnostics } - pub fn gather_local_type(&self, symbol_table: &SymbolTable, types_table: &mut TypesTable) { - 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); + pub fn resolve_types( + &self, + resolved_symbols: &NodesToSymbols, + resolved_symbol_type_infos: &SymbolsToTypes, + ) -> (SymbolsToTypes, NodesToTypes, Diagnostics) { + let mut diagnostics = Diagnostics::new(); + let mut resolved_types = NodesToTypes::new(); + + { + let (rts, mut ds) = self + .initializer + .resolve_types(resolved_symbols, resolved_symbol_type_infos); + insert_resolved_types_into(rts, &mut resolved_types); + diagnostics.append(&mut ds); + } + + let initializer_resolved_type = resolved_types.get(&self.initializer.node_id()).unwrap(); + let self_symbol = resolved_symbols.get(&self.node_id).unwrap(); + + let mut resolved_symbol_type_infos = resolved_symbol_type_infos.clone(); + resolved_symbol_type_infos.insert(self_symbol.clone(), initializer_resolved_type.clone()); + + (resolved_symbol_type_infos, resolved_types, diagnostics) } pub fn type_check( diff --git a/dmc-lib/src/ast/mod.rs b/dmc-lib/src/ast/mod.rs index 0156fba..1642753 100644 --- a/dmc-lib/src/ast/mod.rs +++ b/dmc-lib/src/ast/mod.rs @@ -1,6 +1,6 @@ use crate::symbol::Symbol; -use std::collections::HashMap; use crate::type_info::TypeInfo; +use std::collections::HashMap; pub mod assign_statement; pub mod binary_expression; @@ -31,5 +31,6 @@ pub mod string_literal; pub mod type_use; pub type NodeId = usize; -pub type NamesTable = HashMap; -pub type ResolvedTypes = HashMap; +pub type NodesToSymbols = HashMap; +pub type SymbolsToTypes = HashMap; +pub type NodesToTypes = HashMap; diff --git a/dmc-lib/src/ast/negative_expression.rs b/dmc-lib/src/ast/negative_expression.rs index df58463..8251bb9 100644 --- a/dmc-lib/src/ast/negative_expression.rs +++ b/dmc-lib/src/ast/negative_expression.rs @@ -1,7 +1,8 @@ -use crate::ast::NamesTable; use crate::ast::expression::Expression; use crate::ast::ir_builder::IrBuilder; +use crate::ast::{NodeId, NodesToSymbols, NodesToTypes, SymbolsToTypes}; use crate::diagnostic::{Diagnostic, Diagnostics}; +use crate::diagnostic_factories::unary_incompatible_type; use crate::ir::ir_assign::IrAssign; use crate::ir::ir_binary_operation::{IrBinaryOperation, IrBinaryOperator}; use crate::ir::ir_expression::IrExpression; @@ -17,20 +18,26 @@ use std::cell::RefCell; use std::rc::Rc; pub struct NegativeExpression { + node_id: NodeId, operand: Box, source_range: SourceRange, type_info: Option, } impl NegativeExpression { - pub fn new(operand: Expression, source_range: SourceRange) -> Self { + pub fn new(node_id: NodeId, operand: Expression, source_range: SourceRange) -> Self { Self { + node_id, operand: operand.into(), source_range, type_info: None, } } + pub fn node_id(&self) -> NodeId { + self.node_id + } + pub fn source_range(&self) -> &SourceRange { &self.source_range } @@ -47,7 +54,10 @@ impl NegativeExpression { self.operand.init_scopes(symbol_table, container_scope); } - pub fn resolve_names_static(&self, symbol_table: &SymbolTable) -> (NamesTable, Diagnostics) { + pub fn resolve_names_static( + &self, + symbol_table: &SymbolTable, + ) -> (NodesToSymbols, Diagnostics) { self.operand.resolve_names_static(symbol_table) } @@ -55,7 +65,7 @@ impl NegativeExpression { &self, symbol_table: &SymbolTable, self_class_symbol: &ClassSymbol, - ) -> (NamesTable, Diagnostics) { + ) -> (NodesToSymbols, Diagnostics) { self.operand .resolve_names_field_init(symbol_table, self_class_symbol) } @@ -64,11 +74,21 @@ impl NegativeExpression { &self, symbol_table: &SymbolTable, self_class_symbol: &ClassSymbol, - ) -> (NamesTable, Diagnostics) { + ) -> (NodesToSymbols, Diagnostics) { self.operand .resolve_names_ctor(symbol_table, self_class_symbol) } + pub fn resolve_names_method( + &self, + symbol_table: &SymbolTable, + self_class_symbol: &ClassSymbol, + ) -> (NodesToSymbols, Diagnostics) { + self.operand + .resolve_names_method(symbol_table, self_class_symbol) + } + + #[deprecated] pub fn check_field_initializer_names( &self, symbol_table: &SymbolTable, @@ -78,6 +98,7 @@ impl NegativeExpression { .check_field_initializer_names(symbol_table, class_symbol) } + #[deprecated] pub fn check_constructor_local_names( &self, symbol_table: &SymbolTable, @@ -87,6 +108,7 @@ impl NegativeExpression { .check_constructor_local_names(symbol_table, class_symbol) } + #[deprecated] pub fn check_method_local_names( &self, symbol_table: &SymbolTable, @@ -96,10 +118,35 @@ impl NegativeExpression { .check_method_local_names(symbol_table, class_symbol) } + #[deprecated] pub fn check_static_fn_local_names(&self, symbol_table: &SymbolTable) -> Vec { self.operand.check_static_fn_local_names(symbol_table) } + pub fn resolve_types( + &self, + nodes_to_symbols: &NodesToSymbols, + symbols_to_types: &SymbolsToTypes, + ) -> (NodesToTypes, Diagnostics) { + let (mut nodes_to_types, mut diagnostics) = self + .operand + .resolve_types(nodes_to_symbols, symbols_to_types); + + let type_info = nodes_to_types.get(&self.operand.node_id()).unwrap(); + if type_info.can_negate() { + nodes_to_types.insert(self.node_id, type_info.negate_result()); + } else { + diagnostics.push(unary_incompatible_type( + &self.source_range, + "negation", + type_info, + )); + nodes_to_types.insert(self.node_id, TypeInfo::PlaceholderError); + } + + (nodes_to_types, diagnostics) + } + pub fn type_check( &mut self, symbol_table: &SymbolTable, diff --git a/dmc-lib/src/ast/parameter.rs b/dmc-lib/src/ast/parameter.rs index 7e0e0fe..1fed46d 100644 --- a/dmc-lib/src/ast/parameter.rs +++ b/dmc-lib/src/ast/parameter.rs @@ -1,13 +1,15 @@ -use crate::ast::NamesTable; use crate::ast::type_use::TypeUse; +use crate::ast::{NodeId, NodesToSymbols}; use crate::diagnostic::{Diagnostic, Diagnostics}; use crate::source_range::SourceRange; use crate::symbol::parameter_symbol::ParameterSymbol; use crate::symbol_table::SymbolTable; +use crate::type_info::TypeInfo; use crate::types_table::TypesTable; use std::rc::Rc; pub struct Parameter { + node_id: NodeId, declared_name: Rc, declared_name_source_range: SourceRange, type_use: TypeUse, @@ -16,11 +18,13 @@ pub struct Parameter { impl Parameter { pub fn new( + node_id: NodeId, declared_name: &str, declared_name_source_range: SourceRange, type_use: TypeUse, ) -> Self { Self { + node_id, declared_name: declared_name.into(), declared_name_source_range, type_use, @@ -28,6 +32,10 @@ impl Parameter { } } + pub fn node_id(&self) -> NodeId { + self.node_id + } + pub fn declared_name(&self) -> &str { &self.declared_name } @@ -49,14 +57,16 @@ impl Parameter { ) } - pub fn resolve_names(&self, symbol_table: &SymbolTable) -> (NamesTable, Diagnostics) { + pub fn resolve_names(&self, symbol_table: &SymbolTable) -> (NodesToSymbols, Diagnostics) { self.type_use.resolve_names(symbol_table) } + #[deprecated] pub fn check_names(&self, symbol_table: &SymbolTable) -> Vec { self.type_use.check_names(symbol_table) } + #[deprecated] pub fn gather_types_into(&self, symbol_table: &SymbolTable, types_table: &mut TypesTable) { let type_info = self.type_use.type_info(symbol_table, types_table).clone(); let parameter_symbol = symbol_table @@ -67,6 +77,10 @@ impl Parameter { .insert(parameter_symbol, type_info); } + pub fn declared_type(&self, names_table: &NodesToSymbols) -> (TypeInfo, Diagnostics) { + self.type_use.declared_type(names_table) + } + pub fn type_check( &mut self, symbol_table: &SymbolTable, diff --git a/dmc-lib/src/ast/statement.rs b/dmc-lib/src/ast/statement.rs index 7f12da3..51c23b2 100644 --- a/dmc-lib/src/ast/statement.rs +++ b/dmc-lib/src/ast/statement.rs @@ -1,8 +1,8 @@ -use crate::ast::NamesTable; use crate::ast::assign_statement::AssignStatement; use crate::ast::expression_statement::ExpressionStatement; use crate::ast::ir_builder::IrBuilder; use crate::ast::let_statement::LetStatement; +use crate::ast::{NodesToSymbols, NodesToTypes, SymbolsToTypes}; use crate::diagnostic::{Diagnostic, Diagnostics}; use crate::symbol::class_symbol::ClassSymbol; use crate::symbol_table::SymbolTable; @@ -35,7 +35,7 @@ impl Statement { pub fn resolve_names_static( &self, symbol_table: &mut SymbolTable, - ) -> (NamesTable, Diagnostics) { + ) -> (NodesToSymbols, Diagnostics) { match self { Statement::Let(let_statement) => let_statement.resolve_names_static(symbol_table), Statement::Expression(expression_statement) => { @@ -52,7 +52,7 @@ impl Statement { symbol_table: &mut SymbolTable, self_class_symbol: &ClassSymbol, initialized_fields: &mut HashSet>, - ) -> (NamesTable, Diagnostics) { + ) -> (NodesToSymbols, Diagnostics) { match self { Statement::Let(let_statement) => { let_statement.resolve_names_ctor(symbol_table, self_class_symbol) @@ -68,6 +68,25 @@ impl Statement { } } + pub fn resolve_names_method( + &self, + symbol_table: &mut SymbolTable, + self_class_symbol: &ClassSymbol, + ) -> (NodesToSymbols, Diagnostics) { + match self { + Statement::Let(let_statement) => { + let_statement.resolve_names_method(symbol_table, self_class_symbol) + } + Statement::Expression(expression_statement) => { + expression_statement.resolve_names_method(symbol_table, self_class_symbol) + } + Statement::Assign(assign_statement) => { + assign_statement.resolve_names_method(symbol_table, self_class_symbol) + } + } + } + + #[deprecated] pub fn analyze_constructor_local_names( &self, symbol_table: &mut SymbolTable, @@ -86,6 +105,7 @@ impl Statement { } } + #[deprecated] pub fn analyze_method_local_names( &self, symbol_table: &mut SymbolTable, @@ -104,6 +124,7 @@ impl Statement { } } + #[deprecated] pub fn analyze_static_fn_local_names(&self, symbol_table: &mut SymbolTable) -> Vec { match self { Statement::Let(let_statement) => { @@ -118,6 +139,27 @@ impl Statement { } } + pub fn resolve_types( + &self, + nodes_to_symbols: &NodesToSymbols, + symbols_to_types: &SymbolsToTypes, + ) -> (SymbolsToTypes, NodesToTypes, Diagnostics) { + match self { + Statement::Let(let_statement) => { + let_statement.resolve_types(nodes_to_symbols, symbols_to_types) + } + Statement::Expression(expression_statement) => { + let (nts, ds) = + expression_statement.resolve_types(nodes_to_symbols, symbols_to_types); + (SymbolsToTypes::new(), nts, ds) + } + Statement::Assign(assign_statement) => { + let (nts, ds) = assign_statement.resolve_types(nodes_to_symbols, symbols_to_types); + (SymbolsToTypes::new(), nts, ds) + } + } + } + pub fn type_check( &mut self, symbol_table: &SymbolTable, diff --git a/dmc-lib/src/ast/string_literal.rs b/dmc-lib/src/ast/string_literal.rs index 5192684..67a900a 100644 --- a/dmc-lib/src/ast/string_literal.rs +++ b/dmc-lib/src/ast/string_literal.rs @@ -1,22 +1,29 @@ +use crate::ast::NodeId; use crate::source_range::SourceRange; use crate::type_info::TypeInfo; pub struct StringLiteral { + node_id: NodeId, content: String, source_range: SourceRange, type_info: &'static TypeInfo, } impl StringLiteral { - pub fn new(content: &str, source_range: SourceRange) -> Self { + pub fn new(node_id: NodeId, content: &str, source_range: SourceRange) -> Self { const TYPE_INFO: TypeInfo = TypeInfo::String; Self { + node_id, content: content.into(), source_range, type_info: &TYPE_INFO, } } + pub fn node_id(&self) -> NodeId { + self.node_id + } + pub fn content(&self) -> &str { &self.content } diff --git a/dmc-lib/src/ast/type_use.rs b/dmc-lib/src/ast/type_use.rs index cfd436a..1698a84 100644 --- a/dmc-lib/src/ast/type_use.rs +++ b/dmc-lib/src/ast/type_use.rs @@ -1,6 +1,6 @@ -use crate::ast::{NamesTable, NodeId}; +use crate::ast::{NodeId, NodesToSymbols}; use crate::diagnostic::{Diagnostic, Diagnostics}; -use crate::diagnostic_factories::symbol_not_found; +use crate::diagnostic_factories::{cannot_provide_generic_args_generic_type, symbol_not_found}; use crate::error_codes::INCORRECT_GENERIC_ARGUMENTS; use crate::source_range::SourceRange; use crate::symbol::type_symbol::TypeSymbol; @@ -46,7 +46,7 @@ impl TypeUse { } } - pub fn resolve_names(&self, symbol_table: &SymbolTable) -> (NamesTable, Diagnostics) { + pub fn resolve_names(&self, symbol_table: &SymbolTable) -> (NodesToSymbols, Diagnostics) { let mut diagnostics = Vec::new(); let mut resolved_names = HashMap::new(); @@ -75,6 +75,7 @@ impl TypeUse { (resolved_names, diagnostics) } + #[deprecated] pub fn check_names(&self, symbol_table: &SymbolTable) -> Vec { let mut diagnostics: Vec = Vec::new(); @@ -96,6 +97,7 @@ impl TypeUse { diagnostics } + #[deprecated] pub fn gather_types( &self, symbol_table: &SymbolTable, @@ -111,6 +113,36 @@ impl TypeUse { diagnostics_result!(diagnostics) } + pub fn declared_type(&self, names_table: &NodesToSymbols) -> (TypeInfo, Diagnostics) { + let mut diagnostics = Diagnostics::new(); + + let mut generic_argument_type_infos = Vec::new(); + for type_use in &self.generic_arguments { + let (type_info, mut ds) = type_use.declared_type(names_table); + generic_argument_type_infos.push(type_info); + diagnostics.append(&mut ds); + } + + let base_type_symbol = names_table.get(&self.node_id).unwrap().unwrap_type_symbol(); + + match base_type_symbol { + TypeSymbol::Class(class_symbol) => ( + TypeInfo::ParameterizedClass(class_symbol, generic_argument_type_infos), + diagnostics, + ), + TypeSymbol::GenericParameter(generic_parameter_symbol) => { + if generic_argument_type_infos.is_empty() { + (TypeInfo::GenericType(generic_parameter_symbol), diagnostics) + } else { + diagnostics.push(cannot_provide_generic_args_generic_type( + &self.declared_name_source_range, + )); + (TypeInfo::PlaceholderError, diagnostics) + } + } + } + } + pub fn type_info<'a>( &self, symbol_table: &SymbolTable, diff --git a/dmc-lib/src/compile_pipeline.rs b/dmc-lib/src/compile_pipeline.rs index e5fc5b6..81ce201 100644 --- a/dmc-lib/src/compile_pipeline.rs +++ b/dmc-lib/src/compile_pipeline.rs @@ -39,18 +39,39 @@ pub fn compile_compilation_units(inputs: &HashMap) -> Result<(), D // gather unordered symbols let all_symbols = compilation_units .values() - .flat_map(|compilation_unit| compilation_unit.gather_unordered_symbols()) + .flat_map(|compilation_unit| compilation_unit.declared_symbols()) .collect::>(); try_insert_symbols_into(all_symbols, &mut symbol_table)?; // now we can just finish each compilation unit, since we have the symbols let mut diagnostics = Vec::new(); for compilation_unit in compilation_units.values() { - let (resolved_names, mut ds) = compilation_unit.resolve_names(&mut symbol_table); + let (nodes_to_symbols, mut ds) = compilation_unit.resolve_names(&mut symbol_table); + + // in the future, we'll ideally be able to *actually* continue with the following steps + // instead of aborting here, but this needs to be tested :) if !ds.is_empty() { diagnostics.append(&mut ds); continue; } + + let (mut symbols_to_types, mut ds) = compilation_unit.declared_types(&nodes_to_symbols); + if !ds.is_empty() { + diagnostics.append(&mut ds); + continue; + } + + let (sts, resolved_types, mut ds) = + compilation_unit.resolve_types(&nodes_to_symbols, &symbols_to_types); + if !ds.is_empty() { + diagnostics.append(&mut ds); + continue; + } + + // merge + for (symbol, type_info) in sts { + symbols_to_types.insert(symbol, type_info); + } } Ok(()) diff --git a/dmc-lib/src/diagnostic_factories.rs b/dmc-lib/src/diagnostic_factories.rs index 2bfb695..a2fad33 100644 --- a/dmc-lib/src/diagnostic_factories.rs +++ b/dmc-lib/src/diagnostic_factories.rs @@ -1,11 +1,15 @@ use crate::diagnostic::{Diagnostic, SecondaryLabel}; use crate::error_codes::{ - ASSIGN_LHS_IMMUTABLE, CLASS_NO_CONSTRUCTOR, FIELD_NO_TYPE_OR_INIT, NOT_ASSIGNABLE, - OUTER_CLASS_FIELD_USED_IN_INIT, OUTER_CLASS_METHOD_USED_IN_INIT, SELF_CONSTRUCTOR_USED_IN_INIT, + ASSIGN_LHS_IMMUTABLE, ASSIGN_MISMATCHED_TYPES, ASSIGN_NO_L_VALUE, + CANNOT_PROVIDE_GENERIC_ARGS_GENERIC_TYPE, CLASS_NO_CONSTRUCTOR, FIELD_NO_TYPE_OR_INIT, + MISMATCHED_TYPES, NOT_ASSIGNABLE, OUTER_CLASS_FIELD_USED_IN_INIT, + OUTER_CLASS_METHOD_USED_IN_INIT, RECEIVER_NOT_CALLABLE, SELF_CONSTRUCTOR_USED_IN_INIT, SELF_FIELD_USED_IN_INIT, SELF_METHOD_USED_IN_INIT, SYMBOL_ALREADY_DECLARED, SYMBOL_NOT_FOUND, + UNARY_INCOMPATIBLE_TYPE, WRONG_NUMBER_OF_ARGUMENTS, }; use crate::source_range::SourceRange; use crate::symbol::Symbol; +use crate::type_info::TypeInfo; pub fn symbol_not_found(name: &str, source_range: &SourceRange) -> Diagnostic { Diagnostic::new( @@ -135,3 +139,135 @@ pub fn cannot_reassign_immutable_field(source_range: &SourceRange) -> Diagnostic ) .with_error_code(ASSIGN_LHS_IMMUTABLE) } + +pub fn cannot_provide_generic_args_generic_type(source_range: &SourceRange) -> Diagnostic { + Diagnostic::new( + "Cannot provide generic arguments to an already generic type.", + source_range.start(), + source_range.end(), + ) + .with_error_code(CANNOT_PROVIDE_GENERIC_ARGS_GENERIC_TYPE) +} + +pub fn must_be_l_value(source_range: &SourceRange) -> Diagnostic { + Diagnostic::new( + "Left-hand side of assign mut be an L value", + source_range.start(), + source_range.end(), + ) + .with_error_code(ASSIGN_NO_L_VALUE) +} + +pub fn destination_must_be_mutable( + source_range: &SourceRange, + secondary_source_range: Option<&SourceRange>, +) -> Diagnostic { + let secondary_label = secondary_source_range.map(|sr| { + SecondaryLabel::new( + sr.start(), + sr.end(), + Some("Destination declared here is immutable".to_string()), + ) + }); + + let mut diagnostic = Diagnostic::new( + "Destination is immutable and cannot be reassigned.", + source_range.start(), + source_range.end(), + ) + .with_error_code(ASSIGN_LHS_IMMUTABLE); + + if let Some(secondary_label) = secondary_label { + diagnostic = diagnostic.with_secondary_labels(&[secondary_label]) + } + + diagnostic +} + +pub fn mismatched_assign_types( + rhs_type: &TypeInfo, + lhs_type: &TypeInfo, + source_range: &SourceRange, + secondary_source_range: Option<&SourceRange>, +) -> Diagnostic { + let secondary_label = secondary_source_range.map(|sr| { + SecondaryLabel::new( + sr.start(), + sr.end(), + Some(format!( + "Destination declared here is of type {}.", + lhs_type + )), + ) + }); + + let mut diagnostic = Diagnostic::new( + &format!("Mismatched types: right-hand side of type {} is not assignable to left-hand side of type {}", rhs_type, lhs_type), + source_range.start(), + source_range.end(), + ) + .with_error_code(ASSIGN_MISMATCHED_TYPES); + + if let Some(secondary_label) = secondary_label { + diagnostic = diagnostic.with_secondary_labels(&[secondary_label]) + } + + diagnostic +} + +pub fn receiver_not_callable( + receiver_type_info: &TypeInfo, + source_range: &SourceRange, +) -> Diagnostic { + Diagnostic::new( + &format!("Receiver of type {} is not callable.", receiver_type_info), + source_range.start(), + source_range.end(), + ) + .with_error_code(RECEIVER_NOT_CALLABLE) +} + +pub fn wrong_number_of_arguments( + source_range: &SourceRange, + found: usize, + expected: usize, +) -> Diagnostic { + Diagnostic::new( + &format!( + "Wrong number of arguments: expected {} but found {}", + expected, found + ), + source_range.start(), + source_range.end(), + ) + .with_error_code(WRONG_NUMBER_OF_ARGUMENTS) +} + +pub fn mismatched_types( + expected_type_info: &TypeInfo, + found_type_info: &TypeInfo, + source_range: &SourceRange, +) -> Diagnostic { + Diagnostic::new( + &format!( + "Mismatched types; expected {} but found {}", + expected_type_info, found_type_info + ), + source_range.start(), + source_range.end(), + ) + .with_error_code(MISMATCHED_TYPES) +} + +pub fn unary_incompatible_type( + source_range: &SourceRange, + operator_name: &str, + type_info: &TypeInfo, +) -> Diagnostic { + Diagnostic::new( + &format!("Cannot apply {} to {}", operator_name, type_info), + source_range.start(), + source_range.end(), + ) + .with_error_code(UNARY_INCOMPATIBLE_TYPE) +} diff --git a/dmc-lib/src/error_codes.rs b/dmc-lib/src/error_codes.rs index 2e4e198..805c425 100644 --- a/dmc-lib/src/error_codes.rs +++ b/dmc-lib/src/error_codes.rs @@ -20,3 +20,8 @@ pub const OUTER_CLASS_METHOD_USED_IN_INIT: ErrorCode = 27; pub const FIELD_NO_TYPE_OR_INIT: ErrorCode = 28; pub const CLASS_NO_CONSTRUCTOR: ErrorCode = 29; pub const NOT_ASSIGNABLE: ErrorCode = 30; +pub const CANNOT_PROVIDE_GENERIC_ARGS_GENERIC_TYPE: ErrorCode = 31; +pub const RECEIVER_NOT_CALLABLE: ErrorCode = 32; +pub const WRONG_NUMBER_OF_ARGUMENTS: ErrorCode = 33; +pub const MISMATCHED_TYPES: ErrorCode = 34; +pub const UNARY_INCOMPATIBLE_TYPE: ErrorCode = 35; diff --git a/dmc-lib/src/parser.rs b/dmc-lib/src/parser.rs index 998534f..8c8a767 100644 --- a/dmc-lib/src/parser.rs +++ b/dmc-lib/src/parser.rs @@ -589,6 +589,7 @@ impl<'a> Parser<'a> { && let Some(type_use) = maybe_type_use { let parameter = Parameter::new( + self.next_node_id(), self.token_text(&identifier), SourceRange::new(identifier.start(), identifier.end()), type_use, @@ -952,6 +953,7 @@ impl<'a> Parser<'a> { if let Some(identifier) = maybe_identifier { let let_statement = LetStatement::new( + self.next_node_id(), self.token_text(&identifier), SourceRange::new(identifier.start(), identifier.end()), is_mut, @@ -974,7 +976,7 @@ impl<'a> Parser<'a> { (Statement::Assign(assign_statement), diagnostics) } else { ( - Statement::Expression(ExpressionStatement::new(base)), + Statement::Expression(ExpressionStatement::new(self.next_node_id(), base)), diagnostics, ) } @@ -1008,6 +1010,7 @@ impl<'a> Parser<'a> { let source_range = SourceRange::new(base.source_range().start(), rhs.source_range().end()); base = Expression::Binary(BinaryExpression::new( + self.next_node_id(), base, rhs, BinaryOperation::BitwiseOr, @@ -1030,6 +1033,7 @@ impl<'a> Parser<'a> { let source_range = SourceRange::new(base.source_range().start(), rhs.source_range().end()); base = Expression::Binary(BinaryExpression::new( + self.next_node_id(), base, rhs, BinaryOperation::BitwiseXor, @@ -1053,6 +1057,7 @@ impl<'a> Parser<'a> { let source_range = SourceRange::new(base.source_range().start(), rhs.source_range().end()); base = Expression::Binary(BinaryExpression::new( + self.next_node_id(), base, rhs, BinaryOperation::BitwiseAnd, @@ -1084,6 +1089,7 @@ impl<'a> Parser<'a> { let source_range = SourceRange::new(base.source_range().start(), rhs.source_range().end()); base = Expression::Binary(BinaryExpression::new( + self.next_node_id(), base, rhs, BinaryOperation::LeftShift, @@ -1103,6 +1109,7 @@ impl<'a> Parser<'a> { let source_range = SourceRange::new(base.source_range().start(), rhs.source_range().end()); base = Expression::Binary(BinaryExpression::new( + self.next_node_id(), base, rhs, BinaryOperation::RightShift, @@ -1133,6 +1140,7 @@ impl<'a> Parser<'a> { let source_range = SourceRange::new(base.source_range().start(), rhs.source_range().end()); base = Expression::Binary(BinaryExpression::new( + self.next_node_id(), base, rhs, BinaryOperation::Add, @@ -1147,6 +1155,7 @@ impl<'a> Parser<'a> { let source_range = SourceRange::new(base.source_range().start(), rhs.source_range().end()); base = Expression::Binary(BinaryExpression::new( + self.next_node_id(), base, rhs, BinaryOperation::Subtract, @@ -1176,6 +1185,7 @@ impl<'a> Parser<'a> { let source_range = SourceRange::new(base.source_range().start(), rhs.source_range().end()); base = Expression::Binary(BinaryExpression::new( + self.next_node_id(), base, rhs, BinaryOperation::Multiply, @@ -1190,6 +1200,7 @@ impl<'a> Parser<'a> { let source_range = SourceRange::new(base.source_range().start(), rhs.source_range().end()); base = Expression::Binary(BinaryExpression::new( + self.next_node_id(), base, rhs, BinaryOperation::Divide, @@ -1204,6 +1215,7 @@ impl<'a> Parser<'a> { let source_range = SourceRange::new(base.source_range().start(), rhs.source_range().end()); base = Expression::Binary(BinaryExpression::new( + self.next_node_id(), base, rhs, BinaryOperation::Modulo, @@ -1242,7 +1254,11 @@ impl<'a> Parser<'a> { let source_range = SourceRange::new(operator_token.start(), base.source_range().end()); match operator_token.kind() { TokenKind::Minus => { - base = Expression::Negative(NegativeExpression::new(base, source_range)); + base = Expression::Negative(NegativeExpression::new( + self.next_node_id(), + base, + source_range, + )); } _ => unreachable!(), } @@ -1281,6 +1297,7 @@ impl<'a> Parser<'a> { diagnostics.append(&mut self.advance()); ( Expression::Integer(IntegerLiteral::new( + self.next_node_id(), i32::from_str(raw).unwrap(), source_range, )), @@ -1293,6 +1310,7 @@ impl<'a> Parser<'a> { diagnostics.append(&mut self.advance()); ( Expression::Double(DoubleLiteral::new( + self.next_node_id(), f64::from_str(raw).unwrap(), source_range, )), @@ -1305,6 +1323,7 @@ impl<'a> Parser<'a> { diagnostics.append(&mut self.advance()); ( Expression::String(StringLiteral::new( + self.next_node_id(), &with_quotes[1..with_quotes.len() - 1], source_range, )), @@ -1352,7 +1371,10 @@ impl<'a> Parser<'a> { SourceRange::new(callee.source_range().start(), callee.source_range().end()) }; - (Call::new(callee, arguments, source_range), diagnostics) + ( + Call::new(self.next_node_id(), callee, arguments, source_range), + diagnostics, + ) } fn expression_list(&mut self) -> ParseResult> { diff --git a/dmc-lib/src/symbol/callable_symbol.rs b/dmc-lib/src/symbol/callable_symbol.rs index 7021e6c..91f5c52 100644 --- a/dmc-lib/src/symbol/callable_symbol.rs +++ b/dmc-lib/src/symbol/callable_symbol.rs @@ -6,6 +6,7 @@ use std::rc::Rc; pub enum CallableSymbol { Function(Rc), Constructor(Rc), + ErrorPlaceholder, } impl CallableSymbol { @@ -15,6 +16,7 @@ impl CallableSymbol { CallableSymbol::Constructor(constructor_symbol) => { constructor_symbol.parameters().to_vec() } + CallableSymbol::ErrorPlaceholder => Vec::new(), } } } diff --git a/dmc-lib/src/symbol/mod.rs b/dmc-lib/src/symbol/mod.rs index 409d740..6c428fe 100644 --- a/dmc-lib/src/symbol/mod.rs +++ b/dmc-lib/src/symbol/mod.rs @@ -1,10 +1,12 @@ use crate::source_range::SourceRange; use crate::symbol::class_symbol::ClassSymbol; use crate::symbol::constructor_symbol::ConstructorSymbol; +use crate::symbol::expressible_symbol::ExpressibleSymbol; use crate::symbol::field_symbol::FieldSymbol; use crate::symbol::function_symbol::FunctionSymbol; use crate::symbol::generic_parameter_symbol::GenericParameterSymbol; use crate::symbol::parameter_symbol::ParameterSymbol; +use crate::symbol::type_symbol::TypeSymbol; use crate::symbol::variable_symbol::VariableSymbol; use std::rc::Rc; @@ -19,7 +21,7 @@ pub mod parameter_symbol; pub mod type_symbol; pub mod variable_symbol; -#[derive(Eq, PartialEq, Hash)] +#[derive(Clone, Eq, PartialEq, Hash)] pub enum Symbol { Class(Rc), GenericParameter(Rc), @@ -76,4 +78,38 @@ impl Symbol { Symbol::Variable(variable_symbol) => Some(variable_symbol.declared_name_source_range()), } } + + pub fn unwrap_type_symbol(&self) -> TypeSymbol { + match self { + Symbol::Class(class_symbol) => TypeSymbol::Class(class_symbol.clone()), + Symbol::GenericParameter(generic_parameter_symbol) => { + TypeSymbol::GenericParameter(generic_parameter_symbol.clone()) + } + _ => panic!(), + } + } + + pub fn unwrap_expressible_symbol(&self) -> ExpressibleSymbol { + match self { + Symbol::Class(class_symbol) => ExpressibleSymbol::Class(class_symbol.clone()), + Symbol::Field(field_symbol) => ExpressibleSymbol::Field(field_symbol.clone()), + Symbol::Function(function_symbol) => { + ExpressibleSymbol::Function(function_symbol.clone()) + } + Symbol::Parameter(parameter_symbol) => { + ExpressibleSymbol::Parameter(parameter_symbol.clone()) + } + Symbol::Variable(variable_symbol) => { + ExpressibleSymbol::Variable(variable_symbol.clone()) + } + _ => panic!(), + } + } + + pub fn unwrap_function_symbol(&self) -> &Rc { + match self { + Symbol::Function(function_symbol) => function_symbol, + _ => panic!(), + } + } } diff --git a/dmc-lib/src/symbol/parameter_symbol.rs b/dmc-lib/src/symbol/parameter_symbol.rs index daadaa8..3b20621 100644 --- a/dmc-lib/src/symbol/parameter_symbol.rs +++ b/dmc-lib/src/symbol/parameter_symbol.rs @@ -1,4 +1,5 @@ use crate::source_range::SourceRange; +use crate::symbol::Symbol; use std::hash::{Hash, Hasher}; use std::rc::Rc; diff --git a/dmc-lib/src/type_info.rs b/dmc-lib/src/type_info.rs index 4c89a09..36b8dc7 100644 --- a/dmc-lib/src/type_info.rs +++ b/dmc-lib/src/type_info.rs @@ -11,9 +11,15 @@ pub enum TypeInfo { Double, String, Function(Rc), + + #[deprecated] Class(Rc), + + ParameterizedClass(Rc, Vec), GenericType(Rc), Void, + + PlaceholderError, } impl Display for TypeInfo { @@ -36,10 +42,23 @@ impl Display for TypeInfo { TypeInfo::Class(class_symbol) => { write!(f, "Class({:?})", class_symbol) } + TypeInfo::ParameterizedClass(class_symbol, arguments) => { + write!( + f, + "ParameterizedClass({:?}<{}>)", + class_symbol, + arguments + .iter() + .map(|a| a.to_string()) + .collect::>() + .join(", ") + ) + } TypeInfo::GenericType(generic_parameter_symbol) => { write!(f, "{}", generic_parameter_symbol.declared_name()) } TypeInfo::Void => write!(f, "Void"), + TypeInfo::PlaceholderError => write!(f, ""), } } } @@ -72,6 +91,16 @@ impl TypeInfo { TypeInfo::Class(other_class_symbol) => class_symbol == other_class_symbol, _ => false, }, + TypeInfo::ParameterizedClass(class_symbol, arguments) => match other { + TypeInfo::ParameterizedClass(other_class_symbol, other_arguments) => { + if arguments.is_empty() && other_arguments.is_empty() { + class_symbol == other_class_symbol + } else { + todo!() + } + } + _ => false, + }, TypeInfo::GenericType(generic_parameter_symbol) => { // if generic_parameter_symbol.extends().len() > 0 { // unimplemented!( @@ -83,6 +112,7 @@ impl TypeInfo { TypeInfo::Void => { matches!(other, TypeInfo::Void) } + TypeInfo::PlaceholderError => false, } }