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