Skip to content

Commit 20f97ec

Browse files
committed
Add fallback if __crystal_raise_cast_failed is missing
1 parent 5402259 commit 20f97ec

File tree

1 file changed

+46
-17
lines changed

1 file changed

+46
-17
lines changed

src/compiler/crystal/codegen/codegen.cr

Lines changed: 46 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,28 @@ module Crystal
15041504
false
15051505
end
15061506

1507+
def type_cast_exception_call(from_type, to_type, node, var_name)
1508+
pieces = [
1509+
StringLiteral.new("Cast from ").at(node),
1510+
Call.new(Var.new(var_name).at(node), "class").at(node),
1511+
StringLiteral.new(" to #{to_type} failed").at(node),
1512+
] of ASTNode
1513+
1514+
if location = node.location
1515+
pieces << StringLiteral.new(", at #{location.expanded_location}:#{location.line_number}").at(node)
1516+
end
1517+
1518+
ex = Call.new(Path.global("TypeCastError").at(node), "new", StringInterpolation.new(pieces).at(node)).at(node)
1519+
call = Call.global("raise", ex).at(node)
1520+
call = @program.normalize(call)
1521+
1522+
meta_vars = MetaVars.new
1523+
meta_vars[var_name] = MetaVar.new(var_name, type: from_type)
1524+
visitor = MainVisitor.new(@program, meta_vars)
1525+
@program.visit_main call, visitor: visitor
1526+
call
1527+
end
1528+
15071529
def visit(node : NilableCast)
15081530
request_value(node.obj)
15091531

@@ -1559,26 +1581,33 @@ module Crystal
15591581
end
15601582
end
15611583

1562-
def codegen_raise_cast_failed(type_id, to_type, node)
1584+
def codegen_raise_cast_failed(value, type_id, obj_type, to_type, node)
15631585
location = node.location
15641586
set_current_debug_location(location) if location && @debug.line_numbers?
15651587

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
1588+
if func = crystal_raise_cast_failed_fun
1589+
call_args = [
1590+
cast_to_void_pointer(type_id_to_class_name(type_id)),
1591+
cast_to_void_pointer(build_string_constant(to_type.to_s)),
1592+
location ? cast_to_void_pointer(build_string_constant(location.expanded_location.to_s)) : llvm_context.void_pointer.null,
1593+
] of LLVM::Value
1594+
1595+
if (rescue_block = @rescue_block)
1596+
invoke_out_block = new_block "invoke_out"
1597+
invoke func, call_args, invoke_out_block, rescue_block
1598+
position_at_end invoke_out_block
1599+
else
1600+
call func, call_args
1601+
end
1602+
1603+
unreachable
15771604
else
1578-
call func, call_args
1605+
# fallback for stdlib before 1.16.2 when using a 1.16.2 or later compiler
1606+
temp_var_name = @program.new_temp_var_name
1607+
context.vars[temp_var_name] = LLVMVar.new(value, obj_type, already_loaded: true)
1608+
accept type_cast_exception_call(obj_type, to_type, node, temp_var_name)
1609+
context.vars.delete temp_var_name
15791610
end
1580-
1581-
unreachable
15821611
end
15831612

15841613
def type_id_to_class_name(type_id)
@@ -2357,7 +2386,7 @@ module Crystal
23572386
if raise_cast_failed_fun = @raise_cast_failed_fun
23582387
check_main_fun RAISE_CAST_FAILED_NAME, raise_cast_failed_fun
23592388
else
2360-
raise Error.new("Missing __crystal_raise_cast_failed function, either use std-lib's prelude or define it")
2389+
nil
23612390
end
23622391
end
23632392

0 commit comments

Comments
 (0)