Description
The following code fails codegen during LLVM's module validation on Crystal 1.16.0, but works fine in 1.15.1:
fallback = nil.as({Int32} | Nil)
ary = [] of {String}
ary.find(fallback) { }
Error message (compiler backtrace is irrelevant):
Module validation failed: PHI node operands are not the same type as the result!
%60 = phi ptr [ zeroinitializer, %exit7 ], [ %13, %then9 ], [ %139, %exit33 ], !dbg !26
The regression was triggered by the implementation of Indexable#find
from #15589, which overrides Enumerable#find
. (This should probably not be an override when there's no offset
parameter, but that's a different topic: #15671)
The change in #find
itself is not relevant. It just made this codegen error visible.
Reduced:
def foo(x, &)
return nil.as?({Int32}?) if x
yield
{""}
end
foo(1) {}
Module validation failed: PHI node operands are not the same type as the result!
%37 = phi ptr [ zeroinitializer, %exit ], [ %5, %else ], !dbg !11
Without yield
there's a similar validation error:
def bar(x)
return nil.as?({Int32}?) if x
{""}
end
bar(1)
Load operand must be a pointer.
%36 = load %"(Tuple(Int32 | String) | Nil)", %Nil zeroinitializer, align 8, !dbg !19
I suspect they're different symptoms of the same issue.
The return type of both variants is Tuple(Int32 | String) | Nil
.
Maybe merging the tuple types Tuple(Int32)
and Tuple(String)
into Tuple(Int32 |String)
is causing havoc?
This bug was first discovered by @BlobCodes on https://gitlab.com/BlobCodes/pipelinecr/-/jobs/9734877094 and reported on Discord.