包含模块时 __callee__ 的意外值 – 这是 Ruby 错误吗?

Unexpected value of __callee__ when including a module – is this a Ruby bug?

当通过 alias_method 创建的方法调用时,__callee__ 忽略旧方法的名称(此处 xxx),return 忽略新方法的名称方法,如下:

class Foo
  def xxx() __callee__ end
  alias_method :foo, :xxx
end

Foo.new.foo # => :foo

即使 xxx 是从超类继承的,这种行为仍然存在:

class Sup
  def xxx() __callee__ end
end

class Bar < Sup
  alias_method :bar, :xxx
end

Bar.new.bar # => :bar

鉴于以上两者,我希望当通过模块包含 xxx 时,同样的行为会发生。然而,事实并非如此:

module Mod
  def xxx() __callee__ end
end

class Baz
  include Mod
  alias_method :baz, :xxx
end

Baz.new.baz # => :xxx

我希望 return 的值为 :baz,而不是 :xxx


以上代码是使用Ruby 2.3.1p112 执行的。这是 __callee__ 实现中的错误吗?或者 alias_method?如果不是,谁能解释为什么模块包含的行为不同?


更新 1

我已经 posted this to the Ruby bug tracker 尝试提出一个答案。


更新 2

显然,我 not the only one to be surprised by this issue. I wonder whether Revision 50728 (which was meant to solve Bug 11046: __callee__ returns incorrect method name in orphan proc) 可能是相关的。

您可以在 Ruby 的内核模块中看到 __callee____method__ 之间的区别。

不同之处在于分别调用了 prev_frame_callee()prev_frame_func()。我在 http://rxr.whitequark.org/mri/source/eval.c

找到了这些函数定义

简而言之,Foo 和 Bar 立即调用别名方法 foo 和 bar(它们是 xxx 的名称),而 Baz 必须找到 Mod 并从 Mod 调用 xxx。 __method__ 查找原始被调用方法的 id,而 __callee__ 查找最接近 __callee__ 调用的被调用方法的 id。这在第 848 到 906 行的 eval.c 中更好地看到:在类似于 <something> -> called_id<something> -> def->original_id.[=21= 的 return 调用中寻找两种方法的区别]

另外,如果你看1.9.3版本的Kernel,你会发现这两种方法本来是一样的。因此,在某些时候,两者之间发生了有目的的变化。

这是一个错误,已于 3 天前关闭 with this note:

Seems fixed by r56592.