-
Notifications
You must be signed in to change notification settings - Fork 5.5k
Ensure origins of included, prepended, and refined modules #3140
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
a0b1888 to
10f320c
Compare
|
I've added 3 more patches to this. The original patch only fixed Enumerable, Comparable, and Kernel, but the same issues that apply to this affect all modules. The first added patch fixes various issues when a module is included
The second added patches fixes Module#initialize_copy to handle module B; end
class A
def b; 2 end
prepend B
end
a = A.dup.new
class A
def b; 1 end
end
p a.bPrinted 1 instead of 2. This is because the super chain for The B iclasses would not be modified, so the includer entry would be This modifies things so that if the class/module has an origin, The third added patch strengthens the check in vm_search_super_method. |
c1bdf1d to
2053fbf
Compare
|
I'm going to back off the latest patch for now, as it appears to cause problems on mingw at least. It's also a feature improvement and not strictly a bug fix. |
fc31d62 to
4c225a2
Compare
enum.c
Outdated
| #define rb_intern(str) rb_intern_const(str) | ||
|
|
||
| rb_mEnumerable = rb_define_module("Enumerable"); | ||
| rb_ensure_origin(rb_mEnumerable); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this still needed? This is a bit uneasy for me because it looks ad-hoc. And as far as I understand, your patch now ensures the existence of origin whenever the module is include'ed, and the three modules (Enumerable, Comperable, and Kernel) are always include'ed, so I guess they are no longer needed. In fact, the test passes without these calls to rb_ensure_origin().
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, these are no longer needed after the second patch. I'll add another commit to remove them.
|
I went through your patch. As far as I understand, the main part of this patch (1) separates origin from module not only when it is As I wrote in my review, I'm afraid if ad-hoc calls to |
|
@mame You understand correctly. The changes to Module#dup and Marshal were made to fix bugs that ensuring origins exposed in the tests. These aren't issues introduced by the changes. All bugs in Module#dup and Marshal would affect modules that are prepended in older versions of Ruby. |
|
Only failing check is AppVeyor, which had problems with git and didn't run the tests. AppVeyor seems to have general problems if a pull request is not directly based on current master. |
|
@nobu could you help us? it is tough to understand the issue and proposed code for me... |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Seems fine.
Copying superclass tree feels somewhat heavy, but I don't have better ideas.
class.c
Outdated
| rb_bug("non iclass between module/class and origin"); | ||
| } | ||
| clone_p = class_alloc(RBASIC(p)->flags, RBASIC(p)->klass); | ||
| if (prev_clone_p) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This check would not be necessary if prev_clone_p is initialized to clone, unless I miss something.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree. I'll make this change.
class.c
Outdated
| RCLASS_SET_SUPER(clone, RCLASS_SUPER(orig)); | ||
| } | ||
| else { | ||
| VALUE p = RCLASS_SUPER(orig); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A space at the EOL.
class.c
Outdated
| RCLASS_CONST_TBL(clone_p) = RCLASS_CONST_TBL(p); | ||
| RCLASS_IV_TBL(clone_p) = RCLASS_IV_TBL(p); | ||
| RCLASS_EXT(clone_p)->allocator = RCLASS_EXT(p)->allocator; | ||
| if (RB_TYPE_P(clone, T_CLASS)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A space here, too.
compar.c
Outdated
|
|
||
| #include "id.h" | ||
| #include "internal.h" | ||
| #include "internal/class.h" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this line needed?
Seems nothing changes...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This and the enum.c change was needed in the first commit, but is not needed any more. I'll push a rebased version that removes these.
enum.c
Outdated
|
|
||
| #include "id.h" | ||
| #include "internal.h" | ||
| #include "internal/class.h" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same as compar.c.
This fixes various issues when a module is included in or prepended to a module or class, and then refined, or refined and then included or prepended to a module or class. Implement by renaming ensure_origin to rb_ensure_origin, making it non-static, and calling it when refining a module. Fix Module#initialize_copy to handle origins correctly. Previously, Module#initialize_copy did not handle origins correctly. For example, this code: ```ruby module B; end class A def b; 2 end prepend B end a = A.dup.new class A def b; 1 end end p a.b ``` Printed 1 instead of 2. This is because the super chain for a.singleton_class was: ``` a.singleton_class A.dup B(iclass) B(iclass origin) A(origin) # not A.dup(origin) ``` The B iclasses would not be modified, so the includer entry would be still be set to A and not A.dup. This modifies things so that if the class/module has an origin, all iclasses between the class/module and the origin are duplicated and have the correct includer entry set, and the correct origin is created. This requires other changes to make sure all tests still pass: * rb_undef_methods_from doesn't automatically handle classes with origins, so pass it the origin for Comparable when undefing methods in Complex. This fixed a failure in the Complex tests. * When adding a method, the method cache was not cleared correctly if klass has an origin. Clear the method cache for the klass before switching to the origin of klass. This fixed failures in the autoload tests related to overridding require, without breaking the optimization tests. Also clear the method cache for both the module and origin when removing a method. * Module#include? is fixed to skip origin iclasses. * Refinements are fixed to use the origin class of the module that has an origin. * RCLASS_REFINED_BY_ANY is removed as it was only used in a single place and is no longer needed. * Marshal#dump is fixed to skip iclass origins. * rb_method_entry_make is fixed to handled overridden optimized methods for modules that have origins. Fixes [Bug #16852]
e46f2c6 to
d6a7b7c
Compare
This fixes cases where the modules are refined and included into
other modules or classes.
Implement by renaming ensure_origin to rb_ensure_origin, making it
non-static, and calling it directly after Enumerable, Comparable,
and Kernel are created.
This requires a couple of other changes:
rb_undef_methods_from doesn't automatically handle classes with
origins, so pass it the origin for Comparable when undefing
methods in Complex. This fixed a failure in the Complex tests.
When adding a method, the method cache was not be cleared
correctly if klass has an origin. Clear the method cache for
the klass before switching to the origin of klass. This fixed
failures in the autoload tests related to overridding require,
without breaking the optimization tests.
Potentially, this approach could work for other modules (possibly
all modules), but this commit focuses on modules that are included
by default in core classes and are reasonably likely targets for
refinement.
Fixes [Bug #16852]