Skip to content

!~ is compiled as !(a =~ b) and never dispatched, so a user-defined #!~ is dead code #663

Closed

Description

@tannevaled

MRI sends :!~ as a method; rbgo compiles a !~ b into !(a =~ b) and inlines the ! the same way, so a definition of #!~ is never reached.

class C
  def !~(o); "custom !~"; end
  def =~(o); "positive"; end
end
p(C.new !~ /x/)
MRI 4.0.5   "custom !~"
rbgo        false          # it ran #=~ and negated the result

Object#!~ is a real method in Ruby (rb_obj_not_match, object.c), documented as overridable, and BasicObject exposes it. Anything that defines it — a matcher object, a null object, a DSL — silently loses the definition here.

How it surfaced

While fixing the conformance shim (#655 / #660). The shim now spells !~ out on its ShouldProxy so x.should !~ /re/ asserts the negative match, which is correct under MRI. Under rbgo the definition is dead code, so those 11 sites in core/exception/full_message_spec.rb still run the positive =~ assertion — the inverse of what the spec wrote.

So this is currently a hole in the measuring instrument as well as in the VM: 11 assertions there mean the opposite of what they say, and no change to the shim can reach it.

What it needs

a !~ b must compile to a send of :!~ with Object#!~ providing the default !(a =~ b), rather than the compiler synthesising the negation. That is internal/compiler plus an Object#!~ in the builtins — and while in there, the same question is worth asking of != and unary !, which MRI also dispatches (rb_obj_not, rb_obj_not_equal) and which rbgo may be inlining for the same reason.

Found by the agent that landed #660, which reported it as a divergence it could not reach from the shim rather than leaving the 11 sites silently inverted.

Activity

  1. added a commit that references this issue on Sep 26, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions