Project

General

Profile

Actions

Bug #16242

closed

Refinements method call to failed

Added by osyo (manga osyo) over 4 years ago. Updated over 4 years ago.

Status:
Closed
Assignee:
-
Target version:
-
ruby -v:
2.7.0
[ruby-core:95242]

Description

Refinements method call to failed with prepend.

No problem

module M
  # Methods that you want to call only within this context
  refine M do
    def refine_method
      "refine_method"
    end
  end
  using M

  def hoge
    # OK: `refine_method` calls the method
    refine_method
  end
end

class X
  include M
end

pp X.new.hoge
# => "refine_method"

Problem

  • If prepend another module, the search for refine_method fails
module OtherM
end

module M
  # Added prepend
  prepend OtherM

  refine M do
    def refine_method
      "refine_method"
    end
  end
  using M

  def hoge
    # Error: `hoge': undefined local variable or method `refine_method' for #<X:0x00007fa05a024390> (NameError)
    refine_method
  end
end

class X
  include M
end

# Error
pp X.new.hoge

Environment

Reproduced in the following environment.

RUBY_VERSION  # => "2.7.0"
RUBY_REVISION # => "02dfa0f16361c498e0f529054b00e3e09730892b"
RUBY_PLATFORM # => "x86_64-darwin17"

You can also confirm that it is reproduced here.
https://wandbox.org/permlink/I6tQesDRntT7JZqB


Related issues 1 (0 open1 closed)

Related to Ruby master - Bug #13446: refinements with prepend for module has strange behaviorClosednobu (Nobuyoshi Nakada)Actions
Actions #1

Updated by osyo (manga osyo) over 4 years ago

  • Description updated (diff)
Actions #2

Updated by wanabe (_ wanabe) over 4 years ago

  • Related to Bug #13446: refinements with prepend for module has strange behavior added

Updated by jeremyevans0 (Jeremy Evans) over 4 years ago

This issue is specific to modules that are refined and use prepend. The reason it does not work:

  1. Refining a module or class that prepends other modules places the refinements in the class itself and not the origin iclass.

  2. Inclusion of a module that prepends other modules skips the module itself, including only iclasses for the prepended modules and the origin iclass.

Those two behaviors combined meant that the method table for the refined methods for the included module never ends up in the method lookup chain for the class including the module.

Fix this by not skipping the module itself when the module is included (see https://github.com/ruby/ruby/pull/2550). This requires some code rearranging in rb_include_class_new to make sure the correct method tables and origin settings are used for the created iclass.

As origin iclasses shouldn't be exposed to Ruby, this also requires skipping modules that have origin iclasses in Module#ancestors (classes that have origin iclasses were already skipped).

Actions #4

Updated by osyo (manga osyo) over 4 years ago

  • Description updated (diff)

Updated by osyo (manga osyo) over 4 years ago

Its greated!!
Thanks jeremy :)
I will read pull request.

Actions #6

Updated by jeremyevans (Jeremy Evans) over 4 years ago

  • Status changed from Open to Closed

Applied in changeset git|5069c5f5214ce68df8b3954321ad9114c5368dc3.


Honor refinements for modules that prepend other modules

This previously did not work, and the reason it did not work is
that:

  1. Refining a module or class that prepends other modules places
    the refinements in the class itself and not the origin iclass.

  2. Inclusion of a module that prepends other modules skips the
    module itself, including only iclasses for the prepended modules
    and the origin iclass.

Those two behaviors combined meant that the method table for the
refined methods for the included module never ends up in the
method lookup chain for the class including the module.

Fix this by not skipping the module itself when the module is
included. This requires some code rearranging in
rb_include_class_new to make sure the correct method tables and
origin settings are used for the created iclass.

As origin iclasses shouldn't be exposed to Ruby, this also
requires skipping modules that have origin iclasses in
Module#ancestors (classes that have origin iclasses were already
skipped).

Fixes [Bug #16242]

Actions

Also available in: Atom PDF

Like0
Like0Like0Like0Like0Like0Like0