Bug #2402
closedsuper in instance_eval
Description
instance_eval
のブロック内でsuper
を呼ぶと、instance_eval
で変更された
self
に対してsuper
の呼び出しを行ってしまうようです。
defiant:build$ cat t.rb
class Foo
def foo
p self
end
end
class Bar < Foo
def foo
x = Object.new
x.instance_eval do
super
end
end
end
Bar.new.foo
defiant:build$ ./ruby-trunk.1124 -v t.rb
ruby 1.9.2dev (2009-11-24 trunk 25909) [i686-linux]
#<Object:0x8590f6c>
Foo#foo
が呼ばれるのにself
がObject
という、ちょっとおかしなことになっています。
ちょっと自信がありませんが、一応パッチを添付します。
Files
Updated by shugo (Shugo Maeda) about 15 years ago
特異クラス定義でsuper
した時はNoMethodError
になるようです。
defiant:build$ cat t2.rb
class Foo
def foo
p self
end
end
class Bar < Foo
def foo
x = Object.new
class << x
super
end
end
end
Bar.new.foo
defiant:build$ ./ruby-trunk.1124 -v t2.rb
ruby 1.9.2dev (2009-11-24 trunk 25909) [i686-linux]
t2.rb:11:in `singletonclass': super called outside of method (NoMethodError)
from t2.rb:10:in `foo'
from t2.rb:16:in `<main>'
1.8ではFoo#foo
が呼ばれます。
defiant:build$ ruby-1_8 -v t2.rb
ruby 1.8.8dev (2009-10-22 revision 25430) [i686-linux]
#<Bar:0xb7ea443c>
参考までに他の処理系では以下のような挙動でした。
defiant:build$ ir -v t2.rb
IronRuby 0.9.1.0 on .NET 2.0.0.0
#<Bar:0x0000056>
defiant:build$ jruby -v t2.rb
jruby 1.5.0.dev (ruby 1.8.7 patchlevel 174) (2009-11-12 421150b) (Java HotSpot(TM) Client VM 1.6.0_16) [i386-java]
#<Class:#<Object:0x180cf2a>>
defiant:build$ rbx -v t2.rb
rubinius 0.13.0-dev (1.8.7 e614007b 2009-11-06) [i686-pc-linux-gnu]
An exception occurred running t2.rb
No method 'bytecode' on an instance of NilClass. (NoMethodError)
それぞれ個性があって面白いですね。
個人的には例外でもいいんじゃないかなと思いますが、1.9のinstance_eval
での
super
や、JRubyの特異クラス定義でのsuper
のように、変なレシーバでsuper
が
呼ばれてしまうのはまずいんじゃないかと思います。
Updated by ujihisa (Tatsuhiro Ujihisa) about 15 years ago
- Status changed from Open to Assigned
- Assignee set to matz (Yukihiro Matsumoto)
Updated by mame (Yusuke Endoh) over 14 years ago
- Assignee changed from matz (Yukihiro Matsumoto) to ko1 (Koichi Sasada)
遠藤です。
instance_eval
のブロック内でsuper
を呼ぶと、instance_eval
で変更された
self
に対してsuper
の呼び出しを行ってしまうようです。
再現しました。以下で SEGV することも確認しました。
class MyArray < Array
def reverse
"foo".instance_eval do
super
end
end
end
MyArray.new([1,2,3]).reverse
パッチも見ました。速度劣化は気になりますが、正しいと思います。
vm_search_superclass
を追ってみたところ、recv
が必要になるのは、
現在のコンテキストが include
された module
に所属するメソッドの
場合 (ICLASS
) だけのようですので、その時まで recv
の同定を遅延
させると、速度劣化も気にならなくなるかもと思います。
ただ、その辺の修正は [ruby-dev:40959] の修正の後にやったほうが
いい予感がするので、最適化は後にして、とりあえずこの問題は前田
さんのパッチで close するのがいいと思います。
--
Yusuke Endoh mame@tsg.ne.jp
Updated by ko1 (Koichi Sasada) over 14 years ago
パッチは全然見てないのですが,遠藤さんが良いと仰ってるので良いのではないかと思います.
Updated by mame (Yusuke Endoh) over 14 years ago
- Target version set to 2.0.0
遠藤です。
[Bug #2502] [Bug #3136] あたりで super の修正は後回しにしようということに
なり、r28043 でとりあえずの対策をしたので、1.9.x にします。
--
Yusuke Endoh mame@tsg.ne.jp
Updated by nahi (Hiroshi Nakamura) over 13 years ago
- Target version changed from 2.0.0 to 1.9.3
Updated by ko1 (Koichi Sasada) over 13 years ago
- Target version changed from 1.9.3 to 2.0.0
すみません,1.9.4 送りで....
Updated by shugo (Shugo Maeda) over 12 years ago
- Status changed from Assigned to Closed
- % Done changed from 0 to 100
This issue was solved with changeset r36640.
Shugo, thank you for reporting this issue.
Your contribution to Ruby is greatly appreciated.
May Ruby be with you.
- internal.h, class.c, eval.c, insns.def: find the appropriate
receiver for super called in instance_eval. If such a receiver is
not found, raise NoMethodError. [ruby-dev:39772] [Bug #2402]
Updated by shugo (Shugo Maeda) over 12 years ago
- Status changed from Closed to Open
Reopened the issue because r36640 is reverted by r36795.
Updated by ko1 (Koichi Sasada) about 12 years ago
- Priority changed from Normal to 5
shugo-san
これ,どういう話でしたっけ.
Updated by shugo (Shugo Maeda) about 12 years ago
ko1 (Koichi Sasada) wrote:
shugo-san
これ,どういう話でしたっけ.
instance_evalの中でsuperを呼んだ時に正しいレシーバを見つけるために r36640 で外側のフレームを辿る
ようにしたのですが、 Bug #6907 の問題があったので r36795 でrevertしました。
現状はNotImplementedErrorがraiseされますが、こういうケースでsuperが呼べないのを仕様ということに
するなら(selfのtypeがおかしいという意味で)TypeErrorが妥当ですかねえ。
Updated by shugo (Shugo Maeda) about 12 years ago
shugo (Shugo Maeda) wrote:
instance_evalの中でsuperを呼んだ時に正しいレシーバを見つけるために r36640 で外側のフレームを辿る
ようにしたのですが、 Bug #6907 の問題があったので r36795 でrevertしました。現状はNotImplementedErrorがraiseされますが、こういうケースでsuperが呼べないのを仕様ということに
するなら(selfのtypeがおかしいという意味で)TypeErrorが妥当ですかねえ。
一点補足すると、1.8ではinstance_evalではフレームのselfは変えずにrb_evalの引数だけ変えているみたいなので
instance_evalの中でsuperした時もちゃんと元のselfが使われるようですが、このためだけにselfを二重に持つのは
何だかなあという気がしています。
でもorphanなProcからsuperを呼んだ時とかを考えると他の方法を思い付きません。
Updated by tarui (Masaya Tarui) about 12 years ago
- Status changed from Open to Assigned
Updated by shugo (Shugo Maeda) almost 12 years ago
- Assignee changed from ko1 (Koichi Sasada) to matz (Yukihiro Matsumoto)
まつもとさん、この件どうしましょうか?
個人的にはinstance_evalの中でsuperを呼ぶのはかなり特殊なケースだと思うので、
TypeErrorでよいように思いますが。
Updated by shugo (Shugo Maeda) almost 12 years ago
- Category set to core
shugo (Shugo Maeda) wrote:
まつもとさん、この件どうしましょうか?
個人的にはinstance_evalの中でsuperを呼ぶのはかなり特殊なケースだと思うので、
TypeErrorでよいように思いますが。
まつもとさん、いかがでしょうか。
再度まとめると、以下のようにinstance_eval
中でsuper
を呼ぶと、super
で
呼び出した先のクラス・モジュールとself
の整合性が取れなくなるため、
現状では、NotImplementedError
が発生します。
class Bar < Foo
def foo
x = Object.new
x.instance_eval do
super
end
end
end
NotImplementedError
なのは、将来1.8と同様に動くように実装するという意図だと
思いますが、次の点からこの場合はエラーでもよいのではないかと考えています。
- 1.8とインタプリタの構造が異なるため、上記のコードを動くようにするには実装コストも
実行コストもかかる。- 制御フレームを辿ってもとの
self
を見つける修正を試みましたが、orphanなProc
から
super
を呼んだ時などに問題がありました。
- 制御フレームを辿ってもとの
- 現状エラーが発生するが、誰も困っていなさそう。
ただ、この場合はエラーになるのが仕様ということにするのであれば、NotImplementedError
は
不適切なので、TypeError
(self
と呼び出し先メソッドのクラスが不整合という意味)などの他の
例外を発生させるようにしてはどうでしょうか。
Updated by matz (Yukihiro Matsumoto) almost 12 years ago
うーん、では、禁止でいいですよ。
Matz.
Updated by shugo (Shugo Maeda) almost 12 years ago
- Status changed from Assigned to Closed
This issue was solved with changeset r38761.
Shugo, thank you for reporting this issue.
Your contribution to Ruby is greatly appreciated.
May Ruby be with you.
- vm_insnhelper.c (vm_search_super_method): raise a TypeError
instead of a NotImplementError if self is not an instance of the
current class. [ruby-dev:39772] [Bug #2402]
Updated by nobu (Nobuyoshi Nakada) about 9 years ago
- Description updated (diff)
Updated by shugo (Shugo Maeda) about 9 years ago
- Related to Bug #11636: super in instance_eval in a method defined in a module is invoked with a wrong receiver added