Open wolfgang371 opened 10 months ago
this is a slightly smaller version
ERROR_CODE_PROPERTIES = {current_code: 0}
macro assert(invariant)
{% ERROR_CODE_PROPERTIES[:current_code] = 1 %}
raise("error code #{ERROR_CODE_PROPERTIES[:current_code]}")
end
class X
def initialize
end
def do(&)
assert(false)
end
end
x = X.new
x.do {}
x.do {}
(the original issue comes from https://forum.crystal-lang.org/t/compiler-support-on-production-ready-error-codes/6087)
In:
def raise(x)
while true; end
end
FOO = {x: 0}
def foo(&)
{% FOO[:x] = 1 %}
FOO[:x]
end
foo {}
foo {}
The LLVM IR for the code that initializes FOO
is:
define void @"~FOO:init"() !dbg !18 {
entry:
call void @"*raise<String>:NoReturn"(ptr @"'can't execute `{x: ...'")
unreachable
}
And indeed running the snippet with DUMP=1
prints FOO = ::raise("can't execute `{x: 1}` at /home/quinton/crystal/crystal/usr/test.cr:5:7")
. This only happens if #foo
takes a block and is called more than once. So it looks like the constant initializer is not typed after it is modified (this explains why we need a definition for ::raise
in order for the snippet to compile using the empty prelude).
... gives...
(showing up on both 1.9.2 and 1.10.1, Ubuntu 18.04)