mirror of
https://github.com/mruby/mruby
synced 2026-06-08 16:11:16 +00:00
mruby-compiler: fix bare nil? in if/unless to use self as receiver
The if/unless nil? optimization called codegen() on the call node's receiver, but a bare `nil?` is parsed as an FCALL whose receiver is NULL. codegen(NULL) emits OP_LOADNIL, so the JMPNIL was testing the literal nil instead of self, making `if nil?` always behave as `if nil.nil?` (always true) and `unless nil?` always skip its body. Load self when the receiver is implicit. Fixes #6874. Co-authored-by: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -3974,7 +3974,13 @@ codegen_if(codegen_scope *s, node *varnode, int val)
|
||||
mrb_sym sym_nil_p = MRB_SYM_Q(nil);
|
||||
if (call_n->method_name == sym_nil_p && callargs_empty(call_n->args)) {
|
||||
nil_p = TRUE;
|
||||
codegen(s, call_n->receiver, VAL);
|
||||
if (call_n->receiver) {
|
||||
codegen(s, call_n->receiver, VAL);
|
||||
}
|
||||
else {
|
||||
/* implicit receiver: bare `nil?` means `self.nil?` */
|
||||
gen_load_op1(s, OP_LOADSELF, VAL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -194,3 +194,29 @@ assert('register window of calls (#3783)') do
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
assert('bare `nil?` in if/unless uses self as receiver (#6874)') do
|
||||
klass = Class.new do
|
||||
def unless_form
|
||||
reached = false
|
||||
unless nil?
|
||||
reached = true
|
||||
end
|
||||
reached
|
||||
end
|
||||
|
||||
def if_form
|
||||
if nil?
|
||||
:yes
|
||||
else
|
||||
:no
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
assert_true klass.new.unless_form
|
||||
assert_equal :no, klass.new.if_form
|
||||
# Sanity: explicit literal nil receiver still optimized correctly.
|
||||
result = if nil.nil? then :yes else :no end
|
||||
assert_equal :yes, result
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user