@@ -1490,7 +1490,7 @@ module Crystal
1490
1490
cond cmp, matches_block, doesnt_match_block
1491
1491
1492
1492
position_at_end doesnt_match_block
1493
- codegen_raise_cast_failed(type_id, to_type, node)
1493
+ codegen_raise_cast_failed(last_value, type_id, obj_type , to_type, node)
1494
1494
1495
1495
position_at_end matches_block
1496
1496
@last = downcast last_value, resulting_type, obj_type, true
@@ -1500,6 +1500,29 @@ module Crystal
1500
1500
false
1501
1501
end
1502
1502
1503
+ # fallback for stdlib before 1.16.2 when using a 1.16.2 or later compiler
1504
+ def type_cast_exception_call (from_type, to_type, node, var_name)
1505
+ pieces = [
1506
+ StringLiteral .new(" Cast from " ).at(node),
1507
+ Call .new(Var .new(var_name).at(node), " class" ).at(node),
1508
+ StringLiteral .new(" to #{ to_type } failed" ).at(node),
1509
+ ] of ASTNode
1510
+
1511
+ if location = node.location
1512
+ pieces << StringLiteral .new(" , at #{ location.expanded_location } :#{ location.line_number } " ).at(node)
1513
+ end
1514
+
1515
+ ex = Call .new(Path .global(" TypeCastError" ).at(node), " new" , StringInterpolation .new(pieces).at(node)).at(node)
1516
+ call = Call .global(" raise" , ex).at(node)
1517
+ call = @program .normalize(call)
1518
+
1519
+ meta_vars = MetaVars .new
1520
+ meta_vars[var_name] = MetaVar .new(var_name, type: from_type)
1521
+ visitor = MainVisitor .new(@program , meta_vars)
1522
+ @program .visit_main call, visitor: visitor
1523
+ call
1524
+ end
1525
+
1503
1526
def visit (node : NilableCast )
1504
1527
request_value(node.obj)
1505
1528
@@ -1555,26 +1578,33 @@ module Crystal
1555
1578
end
1556
1579
end
1557
1580
1558
- def codegen_raise_cast_failed (type_id, to_type, node)
1581
+ def codegen_raise_cast_failed (value, type_id, obj_type , to_type, node)
1559
1582
location = node.location
1560
1583
set_current_debug_location(location) if location && @debug .line_numbers?
1561
1584
1562
- func = crystal_raise_cast_failed_fun
1563
- call_args = [
1564
- cast_to_void_pointer(type_id_to_class_name(type_id)),
1565
- cast_to_void_pointer(build_string_constant(to_type.to_s)),
1566
- location ? cast_to_void_pointer(build_string_constant(location.expanded_location.to_s)) : llvm_context.void_pointer.null,
1567
- ] of LLVM ::Value
1568
-
1569
- if (rescue_block = @rescue_block )
1570
- invoke_out_block = new_block " invoke_out"
1571
- invoke func, call_args, invoke_out_block, rescue_block
1572
- position_at_end invoke_out_block
1585
+ if func = crystal_raise_cast_failed_fun
1586
+ call_args = [
1587
+ cast_to_void_pointer(type_id_to_class_name(type_id)),
1588
+ cast_to_void_pointer(build_string_constant(to_type.to_s)),
1589
+ location ? cast_to_void_pointer(build_string_constant(location.expanded_location.to_s)) : llvm_context.void_pointer.null,
1590
+ ] of LLVM ::Value
1591
+
1592
+ if (rescue_block = @rescue_block )
1593
+ invoke_out_block = new_block " invoke_out"
1594
+ invoke func, call_args, invoke_out_block, rescue_block
1595
+ position_at_end invoke_out_block
1596
+ else
1597
+ call func, call_args
1598
+ end
1599
+
1600
+ unreachable
1573
1601
else
1574
- call func, call_args
1602
+ # fallback for stdlib before 1.16.2 when using a 1.16.2 or later compiler
1603
+ temp_var_name = @program .new_temp_var_name
1604
+ context.vars[temp_var_name] = LLVMVar .new(value, obj_type, already_loaded: true )
1605
+ accept type_cast_exception_call(obj_type, to_type, node, temp_var_name)
1606
+ context.vars.delete temp_var_name
1575
1607
end
1576
-
1577
- unreachable
1578
1608
end
1579
1609
1580
1610
def type_id_to_class_name (type_id )
@@ -2353,7 +2383,7 @@ module Crystal
2353
2383
if raise_cast_failed_fun = @raise_cast_failed_fun
2354
2384
check_main_fun RAISE_CAST_FAILED_NAME , raise_cast_failed_fun
2355
2385
else
2356
- raise Error .new( " Missing __crystal_raise_cast_failed function, either use std-lib's prelude or define it " )
2386
+ nil
2357
2387
end
2358
2388
end
2359
2389
0 commit comments