From a0579f3606561a74e323f6193b9504c06845236c Mon Sep 17 00:00:00 2001 From: Jeremy Evans Date: Sat, 12 Oct 2019 01:02:51 -0700 Subject: Make prepending a refined module after inclusion not break refinements After the previous commit, this was still broken. The reason it was broken is that a refined module that hasn't been prepended to yet keeps the refined methods in the module's method table. When prepending, the module's method table is moved to the origin iclass, and then the refined methods are moved from the method table to a new method table in the module itself. Unfortunately, that means that if a class has included the module, prepending breaks the refinements, because when the methods are moved from the origin iclass method table to the module method table, they are removed from the method table from the iclass created when the module was included earlier. Fix this by always creating an origin class when including a module that has any refinements, even if the refinements are not currently used. I wasn't sure the best way to do that. The approach I choose was to use an object flag. The flag is set on the module when Module#refine is called, and if the flag is present when the module is included in another module or class, an origin iclass is created for the module. Fixes [Bug #13446] --- eval.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'eval.c') diff --git a/eval.c b/eval.c index 77b0efa0fc..7bcb5447b7 100644 --- a/eval.c +++ b/eval.c @@ -1542,6 +1542,9 @@ rb_mod_refine(VALUE module, VALUE klass) } ensure_class_or_module(klass); + if (RB_TYPE_P(klass, T_MODULE)) { + FL_SET(klass, RCLASS_REFINED_BY_ANY); + } CONST_ID(id_refinements, "__refinements__"); refinements = rb_attr_get(module, id_refinements); if (NIL_P(refinements)) { -- cgit v1.2.3