Fix String adding without needing to add trait machinery (yet).

This commit is contained in:
Jesse Brault 2026-08-27 11:39:39 -05:00
parent f0f377e44e
commit 10579e2ad2
6 changed files with 90 additions and 33 deletions

View File

@ -105,7 +105,10 @@ impl SyntheticFunctionSession {
Statement::Let(let_statement) => { Statement::Let(let_statement) => {
let ir_variable_info = IrVariableInfo::new( let ir_variable_info = IrVariableInfo::new(
let_statement.declared_name_owned(), 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 let ir_stack_frame_variable_id = self
.env .env

View File

@ -70,7 +70,7 @@ pub fn lower_to_ir_synthetic_function(
let type_info_id = let type_info_id =
session.ctx.nodes_to_type_infos()[&expression_statement.expression().node_id()]; session.ctx.nodes_to_type_infos()[&expression_statement.expression().node_id()];
let type_info = &session.ctx.type_infos()[type_info_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.take_parameters(),
storage_env.ir_stack_frame_variables.clone(), storage_env.ir_stack_frame_variables.clone(),
storage_env.ir_free_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, blocks,
) )
} }
@ -290,7 +290,7 @@ fn lower_to_ir_parameters(
let parameter_type_info = &ctx.type_infos()[parameter_type_info_id]; let parameter_type_info = &ctx.type_infos()[parameter_type_info_id];
fn_ctx.storage_env_mut().new_parameter_for( fn_ctx.storage_env_mut().new_parameter_for(
parameter.declared_name(), parameter.declared_name(),
to_ir_type_info(parameter_type_info), to_ir_type_info(ctx, parameter_type_info),
ctx.nodes_to_symbols()[&parameter.node_id()], ctx.nodes_to_symbols()[&parameter.node_id()],
); );
} }
@ -349,7 +349,7 @@ fn lower_to_ir_let_statement(
.unwrap_or_else(|| { .unwrap_or_else(|| {
fn_ctx.storage_env_mut().new_free_variable_for( fn_ctx.storage_env_mut().new_free_variable_for(
let_statement.declared_name(), let_statement.declared_name(),
to_ir_type_info(type_info), to_ir_type_info(ctx, type_info),
symbol_id, symbol_id,
) )
}); });
@ -384,7 +384,7 @@ fn lower_to_ir_expression_statement(
let result_type_info = &ctx.type_infos()[result_type_info_id]; let result_type_info = &ctx.type_infos()[result_type_info_id];
let t_var_ir_variable_id = fn_ctx let t_var_ir_variable_id = fn_ctx
.storage_env_mut() .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)); let ir_statement = IrStatement::Assign(IrAssign::new(t_var_ir_variable_id, ir_operation));
fn_ctx.current_block_statements.push(ir_statement); 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 result_type_info = &ctx.type_infos()[result_type_info_id];
let destination_ir_variable = fn_ctx let destination_ir_variable = fn_ctx
.storage_env_mut() .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 // make assign statement to destination temp var
let ir_assign = IrAssign::new(destination_ir_variable.clone(), ir_operation); 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 result_type_info = &ctx.type_infos()[result_type_info_id];
let destination_ir_variable = fn_ctx let destination_ir_variable = fn_ctx
.storage_env_mut() .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); let ir_assign = IrAssign::new(destination_ir_variable.clone(), ir_operation);
// push the statement which does the multiply by negative one // 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 return_type_info = &ctx.type_infos()[return_type_info_id];
let t_var_ir_variable = fn_ctx let t_var_ir_variable = fn_ctx
.storage_env_mut() .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 // assign call to temp var, return temp var expression
let ir_operation = IrOperation::Call(ir_call); let ir_operation = IrOperation::Call(ir_call);

View File

@ -1,9 +1,17 @@
use crate::ir::ir_type_info::IrTypeInfo; use crate::ir::ir_type_info::IrTypeInfo;
use crate::semantic_analysis::analysis_context::AnalysisContext;
use crate::semantic_analysis::type_info::TypeInfo; 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 { 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::Int => IrTypeInfo::Int,
TypeInfo::Double => IrTypeInfo::Double, TypeInfo::Double => IrTypeInfo::Double,
TypeInfo::Void => IrTypeInfo::Void, 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<IrTypeInfo> { pub fn return_type_info_to_ir_type_info(
ctx: &AnalysisContext,
return_type_info: &TypeInfo,
) -> Option<IrTypeInfo> {
match return_type_info { match return_type_info {
TypeInfo::String | TypeInfo::Int | TypeInfo::Double => { TypeInfo::Instance(_) | TypeInfo::Int | TypeInfo::Double => {
Some(to_ir_type_info(return_type_info)) Some(to_ir_type_info(ctx, return_type_info))
} }
TypeInfo::Void => None, TypeInfo::Void => None,
_ => panic!(), _ => panic!("BUG! Unknown return_type_info: {:?}", return_type_info),
} }
} }

View File

@ -21,7 +21,7 @@ fn collect_types_function(function: &Function, ctx: &mut AnalysisContext) {
let return_type_info = match function.return_type() { let return_type_info = match function.return_type() {
None => TypeInfo::Void, 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); 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); 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 { match declared_name {
"Any" => TypeInfo::Any, "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, "Int" => TypeInfo::Int,
"Double" => TypeInfo::Double, "Double" => TypeInfo::Double,
"Void" => TypeInfo::Void, "Void" => TypeInfo::Void,
@ -52,7 +58,7 @@ fn collect_and_get_parameter_type_info_ids(
) -> Vec<TypeInfoId> { ) -> Vec<TypeInfoId> {
let mut parameter_type_info_ids: Vec<TypeInfoId> = Vec::new(); let mut parameter_type_info_ids: Vec<TypeInfoId> = Vec::new();
for parameter in parameters { 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); let type_info_id = ctx.insert_type_info(type_info);
parameter_type_info_ids.push(type_info_id); 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); collect_and_get_parameter_type_info_ids(extern_function.parameters(), ctx);
let return_type_info = 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 return_type_info_id = ctx.insert_type_info(return_type_info);
let function_type_info = TypeInfo::Function(FunctionTypeInfo::new( let function_type_info = TypeInfo::Function(FunctionTypeInfo::new(

View File

@ -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 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()); 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 = 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()); ctx.insert_type_info_for_node(result_type_info, binary_expression.node_id());
} else { } else {
let op_name = match binary_expression.op() { let op_name = match binary_expression.op() {

View File

@ -2,13 +2,18 @@ use crate::ast::binary_expression::BinaryOperation;
use crate::semantic_analysis::analysis_context::AnalysisContext; use crate::semantic_analysis::analysis_context::AnalysisContext;
use crate::semantic_analysis::type_info::TypeInfo; 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 { match op {
BinaryOperation::Multiply BinaryOperation::Multiply
| BinaryOperation::Divide | BinaryOperation::Divide
| BinaryOperation::Modulo | BinaryOperation::Modulo
| BinaryOperation::Subtract => are_numbers(left, right), | 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::LeftShift
| BinaryOperation::RightShift | BinaryOperation::RightShift
| BinaryOperation::BitwiseAnd | BinaryOperation::BitwiseAnd
@ -25,21 +30,35 @@ fn are_numbers(t0: &TypeInfo, t1: &TypeInfo) -> bool {
is_number(t0) && is_number(t1) is_number(t0) && is_number(t1)
} }
fn are_numbers_or_strings(t0: &TypeInfo, t1: &TypeInfo) -> bool { fn are_numbers_or_strings(ctx: &AnalysisContext, t0: &TypeInfo, t1: &TypeInfo) -> bool {
(is_number(t0) || matches!(t0, TypeInfo::String)) (is_number(t0) || is_string(ctx, t0)) && (is_number(t1) || is_string(ctx, t1))
&& (is_number(t1) || matches!(t1, TypeInfo::String)) }
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 { fn are_ints(t0: &TypeInfo, t1: &TypeInfo) -> bool {
matches!(t0, TypeInfo::Int) && matches!(t1, TypeInfo::Int) 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 { match op {
BinaryOperation::Multiply => numbers_binary_result(left, right), BinaryOperation::Multiply => numbers_binary_result(left, right),
BinaryOperation::Divide => TypeInfo::Double, // okay for now BinaryOperation::Divide => TypeInfo::Double, // okay for now
BinaryOperation::Modulo => numbers_binary_result(left, right), // same properties as multiplication 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::Subtract => numbers_binary_result(left, right),
BinaryOperation::LeftShift BinaryOperation::LeftShift
| BinaryOperation::RightShift | 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 { 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::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::Int => TypeInfo::Int,
TypeInfo::Double => TypeInfo::Double, TypeInfo::Double => TypeInfo::Double,
TypeInfo::String => TypeInfo::String,
TypeInfo::__Error => TypeInfo::__Error, TypeInfo::__Error => TypeInfo::__Error,
_ => panic!(), _ => panic!(),
}, },
TypeInfo::Double => match right { 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::Int | TypeInfo::Double => TypeInfo::Double,
TypeInfo::String => TypeInfo::String,
TypeInfo::__Error => TypeInfo::__Error, TypeInfo::__Error => TypeInfo::__Error,
_ => panic!(), _ => panic!(),
}, },
TypeInfo::String => TypeInfo::String,
TypeInfo::__Error => TypeInfo::__Error, TypeInfo::__Error => TypeInfo::__Error,
_ => panic!(), _ => panic!(),
} }