@@ -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,29 @@ module Crystal
1504
1504
false
1505
1505
end
1506
1506
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
+
1507
1530
def visit (node : NilableCast )
1508
1531
request_value(node.obj)
1509
1532
@@ -1559,26 +1582,33 @@ module Crystal
1559
1582
end
1560
1583
end
1561
1584
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)
1563
1586
location = node.location
1564
1587
set_current_debug_location(location) if location && @debug .line_numbers?
1565
1588
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
1577
1605
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
1579
1611
end
1580
-
1581
- unreachable
1582
1612
end
1583
1613
1584
1614
def type_id_to_class_name (type_id )
@@ -2357,7 +2387,7 @@ module Crystal
2357
2387
if raise_cast_failed_fun = @raise_cast_failed_fun
2358
2388
check_main_fun RAISE_CAST_FAILED_NAME , raise_cast_failed_fun
2359
2389
else
2360
- raise Error .new( " Missing __crystal_raise_cast_failed function, either use std-lib's prelude or define it " )
2390
+ nil
2361
2391
end
2362
2392
end
2363
2393
0 commit comments