Skip to content

Commit 16c2651

Browse files
Merge branch 'release/1.16' into changelog/1.16.2
2 parents 515bf95 + 8ba2caf commit 16c2651

File tree

13 files changed

+135
-68
lines changed

13 files changed

+135
-68
lines changed

.github/workflows/mingw-w64.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ jobs:
5959
shell: msys2 {0}
6060
working-directory: ./shards
6161
run: |
62-
make install PREFIX="$(pwd)/../crystal"
62+
make install PREFIX="$(pwd)/../crystal" SHARDS=false
6363
# FIXME: remove after crystal-lang/shards#668
6464
ldd bin/shards.exe | grep -iv ' => /c/windows/system32' | sed 's/.* => //; s/ (.*//' | xargs -t -i /usr/bin/install -m 0755 '{}' "$(pwd)/../crystal/bin/"
6565

.github/workflows/win.yml

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -23,13 +23,6 @@ jobs:
2323
- name: Enable Developer Command Prompt
2424
uses: ilammy/msvc-dev-cmd@0b201ec74fa43914dc39ae48a89fd1d8cb592756 # v1.13.0
2525

26-
- name: Set up Cygwin
27-
uses: cygwin/cygwin-install-action@f61179d72284ceddc397ed07ddb444d82bf9e559 # v5
28-
with:
29-
packages: make
30-
install-dir: C:\cygwin64
31-
add-to-path: false
32-
3326
- name: Download Crystal source
3427
uses: actions/checkout@v4
3528

@@ -48,6 +41,13 @@ jobs:
4841
libs/yaml.lib
4942
libs/xml2.lib
5043
key: win-libs-${{ hashFiles('.github/workflows/win.yml', 'etc/win-ci/*.ps1') }}-msvc
44+
- name: Set up Cygwin
45+
if: steps.cache-libs.outputs.cache-hit != 'true'
46+
uses: cygwin/cygwin-install-action@f61179d72284ceddc397ed07ddb444d82bf9e559 # v5
47+
with:
48+
packages: make
49+
install-dir: C:\cygwin64
50+
add-to-path: false
5151
- name: Build libgc
5252
if: steps.cache-libs.outputs.cache-hit != 'true'
5353
run: .\etc\win-ci\build-gc.ps1 -BuildTree deps\gc -Version 8.2.8 -AtomicOpsVersion 7.8.2
@@ -102,13 +102,6 @@ jobs:
102102
- name: Enable Developer Command Prompt
103103
uses: ilammy/msvc-dev-cmd@0b201ec74fa43914dc39ae48a89fd1d8cb592756 # v1.13.0
104104

105-
- name: Set up Cygwin
106-
uses: cygwin/cygwin-install-action@f61179d72284ceddc397ed07ddb444d82bf9e559 # v5
107-
with:
108-
packages: make
109-
install-dir: C:\cygwin64
110-
add-to-path: false
111-
112105
- name: Download Crystal source
113106
uses: actions/checkout@v4
114107

@@ -136,6 +129,13 @@ jobs:
136129
dlls/yaml.dll
137130
dlls/libxml2.dll
138131
key: win-dlls-${{ hashFiles('.github/workflows/win.yml', 'etc/win-ci/*.ps1') }}-msvc
132+
- name: Set up Cygwin
133+
if: steps.cache-dlls.outputs.cache-hit != 'true'
134+
uses: cygwin/cygwin-install-action@f61179d72284ceddc397ed07ddb444d82bf9e559 # v5
135+
with:
136+
packages: make
137+
install-dir: C:\cygwin64
138+
add-to-path: false
139139
- name: Build libgc
140140
if: steps.cache-dlls.outputs.cache-hit != 'true'
141141
run: .\etc\win-ci\build-gc.ps1 -BuildTree deps\gc -Version 8.2.8 -AtomicOpsVersion 7.8.2 -Dynamic

etc/win-ci/build-iconv.ps1

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ rm libiconv.tar.gz
1414

1515
Run-InDirectory $BuildTree {
1616
$env:CHERE_INVOKING = 1
17+
[System.IO.File]::WriteAllText("src\Makefile.in", [System.IO.File]::ReadAllText("src\Makefile.in").Replace("chmod 777 .", "true"))
18+
1719
& 'C:\cygwin64\bin\bash.exe' --login "$PSScriptRoot\cygwin-build-iconv.sh" "$Version" "$(if ($Dynamic) { 1 })"
1820
if (-not $?) {
1921
Write-Host "Error: Failed to build libiconv" -ForegroundColor Red

spec/compiler/semantic/reference_storage_spec.cr

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,4 +69,14 @@ describe "Semantic: ReferenceStorage" do
6969
MyRef(Foo).new.u
7070
CRYSTAL
7171
end
72+
73+
it "adds ReferenceStorage to Value.subclasses once (#15677)" do
74+
assert_type(<<-CRYSTAL) { bool }
75+
@[Primitive(:ReferenceStorageType)]
76+
struct ReferenceStorage(T) < Value
77+
end
78+
79+
{{ Value.subclasses.select(&.<=(ReferenceStorage)).size == 1 ? true : nil }}
80+
CRYSTAL
81+
end
7282
end

spec/std/humanize_spec.cr

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -301,6 +301,7 @@ describe Int do
301301
it { assert_prints 1099511627776.humanize_bytes(format: Int::BinaryPrefixFormat::JEDEC), "1.0TB" }
302302
it { assert_prints 1125899906842624.humanize_bytes(format: Int::BinaryPrefixFormat::JEDEC), "1.0PB" }
303303
it { assert_prints 1152921504606846976.humanize_bytes(format: Int::BinaryPrefixFormat::JEDEC), "1.0EB" }
304+
it { assert_prints 1.humanize_bytes(format: Int::BinaryPrefixFormat::JEDEC, unit_separator: '\u2009'), "1\u2009B" }
304305
it { assert_prints 1152921504606846976.humanize_bytes(format: Int::BinaryPrefixFormat::JEDEC, unit_separator: '\u2009'), "1.0\u2009EB" }
305306

306307
it { assert_prints 1024.humanize_bytes(format: Int::BinaryPrefixFormat::IEC), "1.0kiB" }

src/compiler/crystal/codegen/codegen.cr

Lines changed: 79 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,16 @@ require "./llvm_builder_helper"
77
require "./abi/*"
88

99
module Crystal
10-
MAIN_NAME = "__crystal_main"
11-
RAISE_NAME = "__crystal_raise"
12-
RAISE_OVERFLOW_NAME = "__crystal_raise_overflow"
13-
MALLOC_NAME = "__crystal_malloc64"
14-
MALLOC_ATOMIC_NAME = "__crystal_malloc_atomic64"
15-
REALLOC_NAME = "__crystal_realloc64"
16-
GET_EXCEPTION_NAME = "__crystal_get_exception"
17-
ONCE_INIT = "__crystal_once_init"
18-
ONCE = "__crystal_once"
10+
MAIN_NAME = "__crystal_main"
11+
RAISE_NAME = "__crystal_raise"
12+
RAISE_OVERFLOW_NAME = "__crystal_raise_overflow"
13+
RAISE_CAST_FAILED_NAME = "__crystal_raise_cast_failed"
14+
MALLOC_NAME = "__crystal_malloc64"
15+
MALLOC_ATOMIC_NAME = "__crystal_malloc_atomic64"
16+
REALLOC_NAME = "__crystal_realloc64"
17+
GET_EXCEPTION_NAME = "__crystal_get_exception"
18+
ONCE_INIT = "__crystal_once_init"
19+
ONCE = "__crystal_once"
1920

2021
class Program
2122
def run(code, filename : String? = nil, debug = Debug::Default)
@@ -265,6 +266,7 @@ module Crystal
265266
@malloc_atomic_fun : LLVMTypedFunction?
266267
@realloc_fun : LLVMTypedFunction?
267268
@raise_overflow_fun : LLVMTypedFunction?
269+
@raise_cast_failed_fun : LLVMTypedFunction?
268270
@c_malloc_fun : LLVMTypedFunction?
269271
@c_realloc_fun : LLVMTypedFunction?
270272

@@ -470,7 +472,7 @@ module Crystal
470472
case node.name
471473
when MALLOC_NAME, MALLOC_ATOMIC_NAME, REALLOC_NAME, RAISE_NAME,
472474
@codegen.personality_name, GET_EXCEPTION_NAME, RAISE_OVERFLOW_NAME,
473-
ONCE_INIT, ONCE
475+
RAISE_CAST_FAILED_NAME, ONCE_INIT, ONCE
474476
@codegen.accept node
475477
end
476478

@@ -1488,11 +1490,7 @@ module Crystal
14881490
cond cmp, matches_block, doesnt_match_block
14891491

14901492
position_at_end doesnt_match_block
1491-
1492-
temp_var_name = @program.new_temp_var_name
1493-
context.vars[temp_var_name] = LLVMVar.new(last_value, obj_type, already_loaded: true)
1494-
accept type_cast_exception_call(obj_type, to_type, node, temp_var_name)
1495-
context.vars.delete temp_var_name
1493+
codegen_raise_cast_failed(type_id, to_type, node)
14961494

14971495
position_at_end matches_block
14981496
@last = downcast last_value, resulting_type, obj_type, true
@@ -1548,28 +1546,6 @@ module Crystal
15481546
false
15491547
end
15501548

1551-
def type_cast_exception_call(from_type, to_type, node, var_name)
1552-
pieces = [
1553-
StringLiteral.new("Cast from ").at(node),
1554-
Call.new(Var.new(var_name).at(node), "class").at(node),
1555-
StringLiteral.new(" to #{to_type} failed").at(node),
1556-
] of ASTNode
1557-
1558-
if location = node.location
1559-
pieces << StringLiteral.new(", at #{location.expanded_location}:#{location.line_number}").at(node)
1560-
end
1561-
1562-
ex = Call.new(Path.global("TypeCastError").at(node), "new", StringInterpolation.new(pieces).at(node)).at(node)
1563-
call = Call.global("raise", ex).at(node)
1564-
call = @program.normalize(call)
1565-
1566-
meta_vars = MetaVars.new
1567-
meta_vars[var_name] = MetaVar.new(var_name, type: from_type)
1568-
visitor = MainVisitor.new(@program, meta_vars)
1569-
@program.visit_main call, visitor: visitor
1570-
call
1571-
end
1572-
15731549
def cant_pass_closure_to_c_exception_call
15741550
@cant_pass_closure_to_c_exception_call ||= begin
15751551
call = Call.global("raise", StringLiteral.new("passing a closure to C is not allowed")).at(UNKNOWN_LOCATION)
@@ -1579,6 +1555,63 @@ module Crystal
15791555
end
15801556
end
15811557

1558+
def codegen_raise_cast_failed(type_id, to_type, node)
1559+
location = node.location
1560+
set_current_debug_location(location) if location && @debug.line_numbers?
1561+
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
1573+
else
1574+
call func, call_args
1575+
end
1576+
1577+
unreachable
1578+
end
1579+
1580+
def type_id_to_class_name(type_id)
1581+
fun_name = "~type_id_to_class_name"
1582+
func = typed_fun?(@main_mod, fun_name) || create_type_id_to_class_name_fun(fun_name)
1583+
func = check_main_fun fun_name, func
1584+
call func, type_id
1585+
end
1586+
1587+
# See also: `#create_metaclass_fun`
1588+
def create_type_id_to_class_name_fun(name)
1589+
in_main do
1590+
define_main_function(name, [llvm_context.int32], llvm_type(@program.string)) do |func|
1591+
set_internal_fun_debug_location(func, name)
1592+
1593+
arg = func.params.first
1594+
1595+
current_block = insert_block
1596+
1597+
cases = {} of LLVM::Value => LLVM::BasicBlock
1598+
@program.llvm_id.@ids.each do |type, (_, type_id)|
1599+
block = new_block "type_#{type_id}"
1600+
cases[int32(type_id)] = block
1601+
position_at_end block
1602+
ret build_string_constant(type.to_s)
1603+
end
1604+
1605+
otherwise = new_block "otherwise"
1606+
position_at_end otherwise
1607+
unreachable
1608+
1609+
position_at_end current_block
1610+
@builder.switch arg, otherwise, cases
1611+
end
1612+
end
1613+
end
1614+
15821615
def visit(node : IsA)
15831616
codegen_type_filter node, &.filter_by(node.const.type)
15841617
end
@@ -2315,6 +2348,15 @@ module Crystal
23152348
end
23162349
end
23172350

2351+
def crystal_raise_cast_failed_fun
2352+
@raise_cast_failed_fun ||= typed_fun?(@main_mod, RAISE_CAST_FAILED_NAME)
2353+
if raise_cast_failed_fun = @raise_cast_failed_fun
2354+
check_main_fun RAISE_CAST_FAILED_NAME, raise_cast_failed_fun
2355+
else
2356+
raise Error.new("Missing __crystal_raise_cast_failed function, either use std-lib's prelude or define it")
2357+
end
2358+
end
2359+
23182360
# Fallbacks to libc malloc and realloc when the expected __crystal_*
23192361
# functions aren't defined (e.g. empty prelude). We only use them in tests
23202362
# that don't require the prelude, so they don't require the GC.

src/compiler/crystal/semantic/top_level_visitor.cr

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ class Crystal::TopLevelVisitor < Crystal::SemanticVisitor
120120
when node.splat_index
121121
node.raise "BUG: Expected ReferenceStorageType to have no splat parameter"
122122
end
123-
type = GenericReferenceStorageType.new @program, scope, name, @program.value, type_vars
123+
type = GenericReferenceStorageType.new @program, scope, name, @program.value, type_vars, false
124124
type.declare_instance_var("@type_id", @program.int32)
125125
type.can_be_stored = false
126126
end

src/crystal/system/win32/file_descriptor.cr

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -519,11 +519,11 @@ private module ConsoleUtils
519519
@@read_requests = Deque(ReadRequest).new
520520
@@bytes_read = Deque(Int32).new
521521
@@mtx = ::Thread::Mutex.new
522-
{% if flag?(:execution_context) %}
523-
@@reader_thread = ::Fiber::ExecutionContext::Isolated.new("READER-LOOP") { reader_loop }
524-
{% else %}
525-
@@reader_thread = ::Thread.new { reader_loop }
526-
{% end %}
522+
523+
# Start a dedicated thread to block on reads from the console. Doesn't need an
524+
# isolated execution context because there's no fiber communication (only
525+
# thread communication) and only blocking I/O within the thread.
526+
@@reader_thread = ::Thread.new { reader_loop }
527527

528528
private def self.reader_loop
529529
while true

src/crystal/tracing.cr

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ module Crystal
106106
end
107107

108108
def write(value : Time::Span) : Nil
109-
write(value.seconds * Time::NANOSECONDS_PER_SECOND + value.nanoseconds)
109+
write(value.seconds &* Time::NANOSECONDS_PER_SECOND &+ value.nanoseconds)
110110
end
111111

112112
def write(value : Bool) : Nil

src/fiber/execution_context/isolated.cr

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,9 +191,12 @@ module Fiber::ExecutionContext
191191
def wait : Nil
192192
if @running
193193
node = Fiber::PointerLinkedListNode.new(Fiber.current)
194+
194195
@mutex.synchronize do
195196
@wait_list.push(pointerof(node)) if @running
196197
end
198+
199+
Fiber.suspend
197200
end
198201

199202
if exception = @exception

src/humanize.cr

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -326,17 +326,17 @@ struct Int
326326
#
327327
# See `Number#humanize` for more details on the behaviour and arguments.
328328
def humanize_bytes(io : IO, precision : Int = 3, separator = '.', *, significant : Bool = true, unit_separator = nil, format : BinaryPrefixFormat = :IEC) : Nil
329-
humanize(io, precision, separator, nil, base: 1024, significant: significant) do |magnitude|
329+
humanize(io, precision, separator, nil, base: 1024, significant: significant, unit_separator: unit_separator) do |magnitude|
330330
magnitude = Number.prefix_index(magnitude)
331331

332332
prefix = Number.si_prefix(magnitude)
333333
if prefix.nil?
334334
unit = "B"
335335
else
336336
if format.iec?
337-
unit = "#{unit_separator}#{prefix}iB"
337+
unit = "#{prefix}iB"
338338
else
339-
unit = "#{unit_separator}#{prefix.upcase}B"
339+
unit = "#{prefix.upcase}B"
340340
end
341341
end
342342
{magnitude, unit, magnitude > 0}

src/kernel.cr

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -599,6 +599,12 @@ end
599599
{% end %}
600600

601601
{% unless flag?(:interpreted) || flag?(:wasm32) %}
602+
{% if flag?(:execution_context) %}
603+
Fiber::ExecutionContext.init_default_context
604+
{% else %}
605+
Crystal::Scheduler.init
606+
{% end %}
607+
602608
# load debug info on start up of the program is executed with CRYSTAL_LOAD_DEBUG_INFO=1
603609
# this will make debug info available on print_frame that is used by Crystal's segfault handler
604610
#
@@ -608,12 +614,6 @@ end
608614
Exception::CallStack.load_debug_info if ENV["CRYSTAL_LOAD_DEBUG_INFO"]? == "1"
609615
Exception::CallStack.setup_crash_handler
610616

611-
{% if flag?(:execution_context) %}
612-
Fiber::ExecutionContext.init_default_context
613-
{% else %}
614-
Crystal::Scheduler.init
615-
{% end %}
616-
617617
{% if flag?(:win32) %}
618618
Crystal::System::Process.start_interrupt_loop
619619
{% else %}

src/raise.cr

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -301,4 +301,13 @@ end
301301
def __crystal_raise_cast_failed(obj, type_name : String, location : String)
302302
raise TypeCastError.new("Cast from #{obj.class} to #{type_name} failed, at #{location}")
303303
end
304+
{% else %}
305+
# :nodoc:
306+
fun __crystal_raise_cast_failed(from_type : Void*, to_type : Void*, location : Void*) : NoReturn
307+
if location
308+
raise TypeCastError.new("Cast from #{from_type.as(String)} to #{to_type.as(String)} failed, at #{location.as(String)}")
309+
else
310+
raise TypeCastError.new("Cast from #{from_type.as(String)} to #{to_type.as(String)} failed")
311+
end
312+
end
304313
{% end %}

0 commit comments

Comments
 (0)