From 20f97ec4d00f44faafd1ecc35859179be34a2069 Mon Sep 17 00:00:00 2001 From: Quinton Miller Date: Sat, 10 May 2025 22:03:20 +0800 Subject: [PATCH 1/2] Add fallback if `__crystal_raise_cast_failed` is missing --- src/compiler/crystal/codegen/codegen.cr | 63 ++++++++++++++++++------- 1 file changed, 46 insertions(+), 17 deletions(-) diff --git a/src/compiler/crystal/codegen/codegen.cr b/src/compiler/crystal/codegen/codegen.cr index 90099d1d38fe..7e65f5038b95 100644 --- a/src/compiler/crystal/codegen/codegen.cr +++ b/src/compiler/crystal/codegen/codegen.cr @@ -1494,7 +1494,7 @@ module Crystal cond cmp, matches_block, doesnt_match_block position_at_end doesnt_match_block - codegen_raise_cast_failed(type_id, to_type, node) + codegen_raise_cast_failed(last_value, type_id, obj_type, to_type, node) position_at_end matches_block @last = downcast last_value, resulting_type, obj_type, true @@ -1504,6 +1504,28 @@ module Crystal false end + def type_cast_exception_call(from_type, to_type, node, var_name) + pieces = [ + StringLiteral.new("Cast from ").at(node), + Call.new(Var.new(var_name).at(node), "class").at(node), + StringLiteral.new(" to #{to_type} failed").at(node), + ] of ASTNode + + if location = node.location + pieces << StringLiteral.new(", at #{location.expanded_location}:#{location.line_number}").at(node) + end + + ex = Call.new(Path.global("TypeCastError").at(node), "new", StringInterpolation.new(pieces).at(node)).at(node) + call = Call.global("raise", ex).at(node) + call = @program.normalize(call) + + meta_vars = MetaVars.new + meta_vars[var_name] = MetaVar.new(var_name, type: from_type) + visitor = MainVisitor.new(@program, meta_vars) + @program.visit_main call, visitor: visitor + call + end + def visit(node : NilableCast) request_value(node.obj) @@ -1559,26 +1581,33 @@ module Crystal end end - def codegen_raise_cast_failed(type_id, to_type, node) + def codegen_raise_cast_failed(value, type_id, obj_type, to_type, node) location = node.location set_current_debug_location(location) if location && @debug.line_numbers? - func = crystal_raise_cast_failed_fun - call_args = [ - cast_to_void_pointer(type_id_to_class_name(type_id)), - cast_to_void_pointer(build_string_constant(to_type.to_s)), - location ? cast_to_void_pointer(build_string_constant(location.expanded_location.to_s)) : llvm_context.void_pointer.null, - ] of LLVM::Value - - if (rescue_block = @rescue_block) - invoke_out_block = new_block "invoke_out" - invoke func, call_args, invoke_out_block, rescue_block - position_at_end invoke_out_block + if func = crystal_raise_cast_failed_fun + call_args = [ + cast_to_void_pointer(type_id_to_class_name(type_id)), + cast_to_void_pointer(build_string_constant(to_type.to_s)), + location ? cast_to_void_pointer(build_string_constant(location.expanded_location.to_s)) : llvm_context.void_pointer.null, + ] of LLVM::Value + + if (rescue_block = @rescue_block) + invoke_out_block = new_block "invoke_out" + invoke func, call_args, invoke_out_block, rescue_block + position_at_end invoke_out_block + else + call func, call_args + end + + unreachable else - call func, call_args + # fallback for stdlib before 1.16.2 when using a 1.16.2 or later compiler + temp_var_name = @program.new_temp_var_name + context.vars[temp_var_name] = LLVMVar.new(value, obj_type, already_loaded: true) + accept type_cast_exception_call(obj_type, to_type, node, temp_var_name) + context.vars.delete temp_var_name end - - unreachable end def type_id_to_class_name(type_id) @@ -2357,7 +2386,7 @@ module Crystal if raise_cast_failed_fun = @raise_cast_failed_fun check_main_fun RAISE_CAST_FAILED_NAME, raise_cast_failed_fun else - raise Error.new("Missing __crystal_raise_cast_failed function, either use std-lib's prelude or define it") + nil end end From 51615d7bc9877ab127adc49243326c66373c9152 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20M=C3=BCller?= Date: Mon, 12 May 2025 15:32:21 +0200 Subject: [PATCH 2/2] Update src/compiler/crystal/codegen/codegen.cr Co-authored-by: Julien Portalier --- src/compiler/crystal/codegen/codegen.cr | 1 + 1 file changed, 1 insertion(+) diff --git a/src/compiler/crystal/codegen/codegen.cr b/src/compiler/crystal/codegen/codegen.cr index 7e65f5038b95..07153e3a7789 100644 --- a/src/compiler/crystal/codegen/codegen.cr +++ b/src/compiler/crystal/codegen/codegen.cr @@ -1504,6 +1504,7 @@ module Crystal false end + # fallback for stdlib before 1.16.2 when using a 1.16.2 or later compiler def type_cast_exception_call(from_type, to_type, node, var_name) pieces = [ StringLiteral.new("Cast from ").at(node),