@@ -1494,7 +1494,7 @@ module Crystal
14941494 cond cmp, matches_block, doesnt_match_block
14951495
14961496 position_at_end doesnt_match_block
1497- codegen_raise_cast_failed(type_id, to_type, node)
1497+ codegen_raise_cast_failed(last_value, type_id, obj_type , to_type, node)
14981498
14991499 position_at_end matches_block
15001500 @last = downcast last_value, resulting_type, obj_type, true
@@ -1504,6 +1504,29 @@ module Crystal
15041504 false
15051505 end
15061506
1507+ # fallback for stdlib before 1.16.2 when using a 1.16.2 or later compiler
1508+ def type_cast_exception_call (from_type, to_type, node, var_name)
1509+ pieces = [
1510+ StringLiteral .new(" Cast from " ).at(node),
1511+ Call .new(Var .new(var_name).at(node), " class" ).at(node),
1512+ StringLiteral .new(" to #{ to_type } failed" ).at(node),
1513+ ] of ASTNode
1514+
1515+ if location = node.location
1516+ pieces << StringLiteral .new(" , at #{ location.expanded_location } :#{ location.line_number } " ).at(node)
1517+ end
1518+
1519+ ex = Call .new(Path .global(" TypeCastError" ).at(node), " new" , StringInterpolation .new(pieces).at(node)).at(node)
1520+ call = Call .global(" raise" , ex).at(node)
1521+ call = @program .normalize(call)
1522+
1523+ meta_vars = MetaVars .new
1524+ meta_vars[var_name] = MetaVar .new(var_name, type: from_type)
1525+ visitor = MainVisitor .new(@program , meta_vars)
1526+ @program .visit_main call, visitor: visitor
1527+ call
1528+ end
1529+
15071530 def visit (node : NilableCast )
15081531 request_value(node.obj)
15091532
@@ -1559,26 +1582,33 @@ module Crystal
15591582 end
15601583 end
15611584
1562- def codegen_raise_cast_failed (type_id, to_type, node)
1585+ def codegen_raise_cast_failed (value, type_id, obj_type , to_type, node)
15631586 location = node.location
15641587 set_current_debug_location(location) if location && @debug .line_numbers?
15651588
1566- func = crystal_raise_cast_failed_fun
1567- call_args = [
1568- cast_to_void_pointer(type_id_to_class_name(type_id)),
1569- cast_to_void_pointer(build_string_constant(to_type.to_s)),
1570- location ? cast_to_void_pointer(build_string_constant(location.expanded_location.to_s)) : llvm_context.void_pointer.null,
1571- ] of LLVM ::Value
1572-
1573- if (rescue_block = @rescue_block )
1574- invoke_out_block = new_block " invoke_out"
1575- invoke func, call_args, invoke_out_block, rescue_block
1576- position_at_end invoke_out_block
1589+ if func = crystal_raise_cast_failed_fun
1590+ call_args = [
1591+ cast_to_void_pointer(type_id_to_class_name(type_id)),
1592+ cast_to_void_pointer(build_string_constant(to_type.to_s)),
1593+ location ? cast_to_void_pointer(build_string_constant(location.expanded_location.to_s)) : llvm_context.void_pointer.null,
1594+ ] of LLVM ::Value
1595+
1596+ if (rescue_block = @rescue_block )
1597+ invoke_out_block = new_block " invoke_out"
1598+ invoke func, call_args, invoke_out_block, rescue_block
1599+ position_at_end invoke_out_block
1600+ else
1601+ call func, call_args
1602+ end
1603+
1604+ unreachable
15771605 else
1578- call func, call_args
1606+ # fallback for stdlib before 1.16.2 when using a 1.16.2 or later compiler
1607+ temp_var_name = @program .new_temp_var_name
1608+ context.vars[temp_var_name] = LLVMVar .new(value, obj_type, already_loaded: true )
1609+ accept type_cast_exception_call(obj_type, to_type, node, temp_var_name)
1610+ context.vars.delete temp_var_name
15791611 end
1580-
1581- unreachable
15821612 end
15831613
15841614 def type_id_to_class_name (type_id )
@@ -2357,7 +2387,7 @@ module Crystal
23572387 if raise_cast_failed_fun = @raise_cast_failed_fun
23582388 check_main_fun RAISE_CAST_FAILED_NAME , raise_cast_failed_fun
23592389 else
2360- raise Error .new( " Missing __crystal_raise_cast_failed function, either use std-lib's prelude or define it " )
2390+ nil
23612391 end
23622392 end
23632393
0 commit comments