Skip to content

Commit 1887c81

Browse files
Add fallback if __crystal_raise_cast_failed is missing (#15762)
Co-authored-by: Julien Portalier <[email protected]>
1 parent 534d41a commit 1887c81

File tree

1 file changed

+47
-17
lines changed

1 file changed

+47
-17
lines changed

src/compiler/crystal/codegen/codegen.cr

Lines changed: 47 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)