@@ -1494,7 +1494,7 @@ module Crystal
1494
1494
cond cmp, matches_block, doesnt_match_block
1495
1495
1496
1496
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)
1498
1498
1499
1499
position_at_end matches_block
1500
1500
@last = downcast last_value, resulting_type, obj_type, true
@@ -1504,6 +1504,28 @@ module Crystal
1504
1504
false
1505
1505
end
1506
1506
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
+
1507
1529
def visit (node : NilableCast )
1508
1530
request_value(node.obj)
1509
1531
@@ -1559,26 +1581,33 @@ module Crystal
1559
1581
end
1560
1582
end
1561
1583
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)
1563
1585
location = node.location
1564
1586
set_current_debug_location(location) if location && @debug .line_numbers?
1565
1587
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
1577
1604
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
1579
1610
end
1580
-
1581
- unreachable
1582
1611
end
1583
1612
1584
1613
def type_id_to_class_name (type_id )
@@ -2357,7 +2386,7 @@ module Crystal
2357
2386
if raise_cast_failed_fun = @raise_cast_failed_fun
2358
2387
check_main_fun RAISE_CAST_FAILED_NAME , raise_cast_failed_fun
2359
2388
else
2360
- raise Error .new( " Missing __crystal_raise_cast_failed function, either use std-lib's prelude or define it " )
2389
+ nil
2361
2390
end
2362
2391
end
2363
2392
0 commit comments