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

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

 class Foo def xxx() __callee__ end alias_method :foo, :xxx end Foo.new.foo # => :foo 

即使从超类inheritancexxx此行为也成立:

 class Sup def xxx() __callee__ end end class Bar  :bar 

考虑到上述两种情况,我预计当通过模块包含xxx时,相同的行为将成立。 但事实并非如此:

 module Mod def xxx() __callee__ end end class Baz include Mod alias_method :baz, :xxx end Baz.new.baz # => :xxx 

我希望返回值为:baz ,而不是:xxx


上面的代码是使用Ruby 2.3.1p112执行的。 这是__callee__实现中的__callee__吗? 或者也许是alias_method ? 如果没有,任何人都可以解释为什么模块包含行为不同?


更新1

我已将此发布到Ruby bug跟踪器 ,试图激起答案。


更新2

显然,我不是唯一一个对此问题感到惊讶的人。 我想知道修订版50728 (用于解决Bug __callee____callee__在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__查找最接近被调用方法的id到__callee__调用。 在eval.c中第848到906行可以更好地看到这一点:在返回调用上查找两个方法的区别,类似于 -> called_id vs -> def->original_id

此外,如果从版本1.9.3查看内核,您将看到两个方法最初是相同的。 所以,在某些时候,两者之间有一个有目的的变化。

这是一个错误,它在3天前以此笔记关闭:

似乎由r56592修复 。