From 10579e2ad29ced705ccc71f93e3a03e8cc483f8e Mon Sep 17 00:00:00 2001 From: Jesse Brault Date: Thu, 27 Aug 2026 11:39:39 -0500 Subject: [PATCH] Fix String adding without needing to add trait machinery (yet). --- dmc-lib/src/lib.rs | 5 +- dmc-lib/src/lowering/mod.rs | 16 ++--- dmc-lib/src/lowering/util.rs | 23 ++++++-- .../src/semantic_analysis/collect_types.rs | 16 +++-- .../semantic_analysis/resolve_types/mod.rs | 4 +- .../resolve_types/type_analysis.rs | 59 +++++++++++++++---- 6 files changed, 90 insertions(+), 33 deletions(-) diff --git a/dmc-lib/src/lib.rs b/dmc-lib/src/lib.rs index e0acdea..cf2c674 100644 --- a/dmc-lib/src/lib.rs +++ b/dmc-lib/src/lib.rs @@ -105,7 +105,10 @@ impl SyntheticFunctionSession { Statement::Let(let_statement) => { let ir_variable_info = IrVariableInfo::new( let_statement.declared_name_owned(), - to_ir_type_info(self.ctx.get_type_info_for_node(let_statement.node_id())), + to_ir_type_info( + &self.ctx, + self.ctx.get_type_info_for_node(let_statement.node_id()), + ), ); let ir_stack_frame_variable_id = self .env diff --git a/dmc-lib/src/lowering/mod.rs b/dmc-lib/src/lowering/mod.rs index 05ed512..3b96360 100644 --- a/dmc-lib/src/lowering/mod.rs +++ b/dmc-lib/src/lowering/mod.rs @@ -70,7 +70,7 @@ pub fn lower_to_ir_synthetic_function( let type_info_id = session.ctx.nodes_to_type_infos()[&expression_statement.expression().node_id()]; let type_info = &session.ctx.type_infos()[type_info_id]; - return_type_info_to_ir_type_info(type_info) + return_type_info_to_ir_type_info(session.ctx(), type_info) } }; @@ -275,7 +275,7 @@ fn lower_to_ir_function(function: &Function, ctx: &AnalysisContext) -> IrFunctio storage_env.take_parameters(), storage_env.ir_stack_frame_variables.clone(), storage_env.ir_free_variables.clone(), - return_type_info_to_ir_type_info(return_type_info), + return_type_info_to_ir_type_info(ctx, return_type_info), blocks, ) } @@ -290,7 +290,7 @@ fn lower_to_ir_parameters( let parameter_type_info = &ctx.type_infos()[parameter_type_info_id]; fn_ctx.storage_env_mut().new_parameter_for( parameter.declared_name(), - to_ir_type_info(parameter_type_info), + to_ir_type_info(ctx, parameter_type_info), ctx.nodes_to_symbols()[¶meter.node_id()], ); } @@ -349,7 +349,7 @@ fn lower_to_ir_let_statement( .unwrap_or_else(|| { fn_ctx.storage_env_mut().new_free_variable_for( let_statement.declared_name(), - to_ir_type_info(type_info), + to_ir_type_info(ctx, type_info), symbol_id, ) }); @@ -384,7 +384,7 @@ fn lower_to_ir_expression_statement( let result_type_info = &ctx.type_infos()[result_type_info_id]; let t_var_ir_variable_id = fn_ctx .storage_env_mut() - .new_t_var(to_ir_type_info(result_type_info)); + .new_t_var(to_ir_type_info(ctx, result_type_info)); let ir_statement = IrStatement::Assign(IrAssign::new(t_var_ir_variable_id, ir_operation)); fn_ctx.current_block_statements.push(ir_statement); @@ -482,7 +482,7 @@ fn lower_expression_to_ir_expression( let result_type_info = &ctx.type_infos()[result_type_info_id]; let destination_ir_variable = fn_ctx .storage_env_mut() - .new_t_var(to_ir_type_info(result_type_info)); + .new_t_var(to_ir_type_info(ctx, result_type_info)); // make assign statement to destination temp var let ir_assign = IrAssign::new(destination_ir_variable.clone(), ir_operation); @@ -506,7 +506,7 @@ fn lower_expression_to_ir_expression( let result_type_info = &ctx.type_infos()[result_type_info_id]; let destination_ir_variable = fn_ctx .storage_env_mut() - .new_t_var(to_ir_type_info(result_type_info)); + .new_t_var(to_ir_type_info(ctx, result_type_info)); let ir_assign = IrAssign::new(destination_ir_variable.clone(), ir_operation); // push the statement which does the multiply by negative one @@ -524,7 +524,7 @@ fn lower_expression_to_ir_expression( let return_type_info = &ctx.type_infos()[return_type_info_id]; let t_var_ir_variable = fn_ctx .storage_env_mut() - .new_t_var(to_ir_type_info(return_type_info)); + .new_t_var(to_ir_type_info(ctx, return_type_info)); // assign call to temp var, return temp var expression let ir_operation = IrOperation::Call(ir_call); diff --git a/dmc-lib/src/lowering/util.rs b/dmc-lib/src/lowering/util.rs index 37b1ff8..08e973b 100644 --- a/dmc-lib/src/lowering/util.rs +++ b/dmc-lib/src/lowering/util.rs @@ -1,9 +1,17 @@ use crate::ir::ir_type_info::IrTypeInfo; +use crate::semantic_analysis::analysis_context::AnalysisContext; use crate::semantic_analysis::type_info::TypeInfo; -pub fn to_ir_type_info(sa_type_info: &TypeInfo) -> IrTypeInfo { +pub fn to_ir_type_info(ctx: &AnalysisContext, sa_type_info: &TypeInfo) -> IrTypeInfo { match sa_type_info { - TypeInfo::String => IrTypeInfo::String, + TypeInfo::Instance(instance_type_info) => { + let symbol = &ctx.symbols()[instance_type_info.class_symbol_id()]; + if symbol.unwrap_class_symbol().fqn() == "core::String" { + IrTypeInfo::String + } else { + todo!("Non-string Instance types") + } + } TypeInfo::Int => IrTypeInfo::Int, TypeInfo::Double => IrTypeInfo::Double, TypeInfo::Void => IrTypeInfo::Void, @@ -13,12 +21,15 @@ pub fn to_ir_type_info(sa_type_info: &TypeInfo) -> IrTypeInfo { } } -pub fn return_type_info_to_ir_type_info(return_type_info: &TypeInfo) -> Option { +pub fn return_type_info_to_ir_type_info( + ctx: &AnalysisContext, + return_type_info: &TypeInfo, +) -> Option { match return_type_info { - TypeInfo::String | TypeInfo::Int | TypeInfo::Double => { - Some(to_ir_type_info(return_type_info)) + TypeInfo::Instance(_) | TypeInfo::Int | TypeInfo::Double => { + Some(to_ir_type_info(ctx, return_type_info)) } TypeInfo::Void => None, - _ => panic!(), + _ => panic!("BUG! Unknown return_type_info: {:?}", return_type_info), } } diff --git a/dmc-lib/src/semantic_analysis/collect_types.rs b/dmc-lib/src/semantic_analysis/collect_types.rs index 113d242..0474707 100644 --- a/dmc-lib/src/semantic_analysis/collect_types.rs +++ b/dmc-lib/src/semantic_analysis/collect_types.rs @@ -21,7 +21,7 @@ fn collect_types_function(function: &Function, ctx: &mut AnalysisContext) { let return_type_info = match function.return_type() { None => TypeInfo::Void, - Some(type_use) => declared_name_to_type_info(type_use.declared_name()), + Some(type_use) => declared_name_to_type_info(ctx, type_use.declared_name()), }; let return_type_info_id = ctx.insert_type_info(return_type_info); @@ -35,10 +35,16 @@ fn collect_types_function(function: &Function, ctx: &mut AnalysisContext) { ctx.associate_node_and_symbol_to_type(function.node_id(), function_type_info_id); } -fn declared_name_to_type_info(declared_name: &str) -> TypeInfo { +fn declared_name_to_type_info(ctx: &AnalysisContext, declared_name: &str) -> TypeInfo { match declared_name { "Any" => TypeInfo::Any, - "String" => TypeInfo::String, + "String" => { + // todo: resolve this like a normal instance type + let symbol_id = ctx + .find_symbol_by_fqn("core::String") + .expect("Missing core::String from ctx"); + ctx.type_infos()[symbol_id].clone() + } "Int" => TypeInfo::Int, "Double" => TypeInfo::Double, "Void" => TypeInfo::Void, @@ -52,7 +58,7 @@ fn collect_and_get_parameter_type_info_ids( ) -> Vec { let mut parameter_type_info_ids: Vec = Vec::new(); for parameter in parameters { - let type_info = declared_name_to_type_info(parameter.type_use().declared_name()); + let type_info = declared_name_to_type_info(ctx, parameter.type_use().declared_name()); let type_info_id = ctx.insert_type_info(type_info); parameter_type_info_ids.push(type_info_id); @@ -67,7 +73,7 @@ fn collect_types_extern_function(extern_function: &ExternFunction, ctx: &mut Ana collect_and_get_parameter_type_info_ids(extern_function.parameters(), ctx); let return_type_info = - declared_name_to_type_info(extern_function.return_type().declared_name()); + declared_name_to_type_info(ctx, extern_function.return_type().declared_name()); let return_type_info_id = ctx.insert_type_info(return_type_info); let function_type_info = TypeInfo::Function(FunctionTypeInfo::new( diff --git a/dmc-lib/src/semantic_analysis/resolve_types/mod.rs b/dmc-lib/src/semantic_analysis/resolve_types/mod.rs index 66df52e..0682a90 100644 --- a/dmc-lib/src/semantic_analysis/resolve_types/mod.rs +++ b/dmc-lib/src/semantic_analysis/resolve_types/mod.rs @@ -177,9 +177,9 @@ fn resolve_types_binary_expression( let lhs_type_info = ctx.get_type_info_for_node(binary_expression.lhs().node_id()); let rhs_type_info = ctx.get_type_info_for_node(binary_expression.rhs().node_id()); - if are_binary_op_compatible(binary_expression.op(), lhs_type_info, rhs_type_info) { + if are_binary_op_compatible(ctx, binary_expression.op(), lhs_type_info, rhs_type_info) { let result_type_info = - binary_op_result(binary_expression.op(), lhs_type_info, rhs_type_info); + binary_op_result(ctx, binary_expression.op(), lhs_type_info, rhs_type_info); ctx.insert_type_info_for_node(result_type_info, binary_expression.node_id()); } else { let op_name = match binary_expression.op() { diff --git a/dmc-lib/src/semantic_analysis/resolve_types/type_analysis.rs b/dmc-lib/src/semantic_analysis/resolve_types/type_analysis.rs index 8937476..ea53ae5 100644 --- a/dmc-lib/src/semantic_analysis/resolve_types/type_analysis.rs +++ b/dmc-lib/src/semantic_analysis/resolve_types/type_analysis.rs @@ -2,13 +2,18 @@ use crate::ast::binary_expression::BinaryOperation; use crate::semantic_analysis::analysis_context::AnalysisContext; use crate::semantic_analysis::type_info::TypeInfo; -pub fn are_binary_op_compatible(op: &BinaryOperation, left: &TypeInfo, right: &TypeInfo) -> bool { +pub fn are_binary_op_compatible( + ctx: &AnalysisContext, + op: &BinaryOperation, + left: &TypeInfo, + right: &TypeInfo, +) -> bool { match op { BinaryOperation::Multiply | BinaryOperation::Divide | BinaryOperation::Modulo | BinaryOperation::Subtract => are_numbers(left, right), - BinaryOperation::Add => are_numbers_or_strings(left, right), + BinaryOperation::Add => are_numbers_or_strings(ctx, left, right), BinaryOperation::LeftShift | BinaryOperation::RightShift | BinaryOperation::BitwiseAnd @@ -25,21 +30,35 @@ fn are_numbers(t0: &TypeInfo, t1: &TypeInfo) -> bool { is_number(t0) && is_number(t1) } -fn are_numbers_or_strings(t0: &TypeInfo, t1: &TypeInfo) -> bool { - (is_number(t0) || matches!(t0, TypeInfo::String)) - && (is_number(t1) || matches!(t1, TypeInfo::String)) +fn are_numbers_or_strings(ctx: &AnalysisContext, t0: &TypeInfo, t1: &TypeInfo) -> bool { + (is_number(t0) || is_string(ctx, t0)) && (is_number(t1) || is_string(ctx, t1)) +} + +fn is_string(ctx: &AnalysisContext, type_info: &TypeInfo) -> bool { + match type_info { + TypeInfo::Instance(instance_type_info) => { + let class_symbol = &ctx.symbols()[instance_type_info.class_symbol_id()]; + class_symbol.unwrap_class_symbol().fqn() == "core::String" + } + _ => false, + } } fn are_ints(t0: &TypeInfo, t1: &TypeInfo) -> bool { matches!(t0, TypeInfo::Int) && matches!(t1, TypeInfo::Int) } -pub fn binary_op_result(op: &BinaryOperation, left: &TypeInfo, right: &TypeInfo) -> TypeInfo { +pub fn binary_op_result( + ctx: &AnalysisContext, + op: &BinaryOperation, + left: &TypeInfo, + right: &TypeInfo, +) -> TypeInfo { match op { BinaryOperation::Multiply => numbers_binary_result(left, right), BinaryOperation::Divide => TypeInfo::Double, // okay for now BinaryOperation::Modulo => numbers_binary_result(left, right), // same properties as multiplication - BinaryOperation::Add => add_result(left, right), + BinaryOperation::Add => add_result(ctx, left, right), BinaryOperation::Subtract => numbers_binary_result(left, right), BinaryOperation::LeftShift | BinaryOperation::RightShift @@ -67,22 +86,40 @@ fn numbers_binary_result(left: &TypeInfo, right: &TypeInfo) -> TypeInfo { } } -fn add_result(left: &TypeInfo, right: &TypeInfo) -> TypeInfo { +fn add_result(ctx: &AnalysisContext, left: &TypeInfo, right: &TypeInfo) -> TypeInfo { match left { + TypeInfo::Instance(left_instance_type_info) => { + if is_string(ctx, left) { + TypeInfo::Instance(left_instance_type_info.clone()) + } else { + todo!("Adding with non-String, non-number types") + } + } TypeInfo::Int => match right { + TypeInfo::Instance(right_instance_type_info) => { + if is_string(ctx, right) { + TypeInfo::Instance(right_instance_type_info.clone()) + } else { + todo!("Adding with non-String, non-number types") + } + } TypeInfo::Int => TypeInfo::Int, TypeInfo::Double => TypeInfo::Double, - TypeInfo::String => TypeInfo::String, TypeInfo::__Error => TypeInfo::__Error, _ => panic!(), }, TypeInfo::Double => match right { + TypeInfo::Instance(right_instance_type_info) => { + if is_string(ctx, right) { + TypeInfo::Instance(right_instance_type_info.clone()) + } else { + todo!("Adding with non-String, non-number types") + } + } TypeInfo::Int | TypeInfo::Double => TypeInfo::Double, - TypeInfo::String => TypeInfo::String, TypeInfo::__Error => TypeInfo::__Error, _ => panic!(), }, - TypeInfo::String => TypeInfo::String, TypeInfo::__Error => TypeInfo::__Error, _ => panic!(), }