mirror of
https://github.com/ruby/ruby.git
synced 2025-08-15 13:39:04 +02:00
Stop transitioning to UNDEF when undefining an instance variable
Cases like this: ```ruby obj = Object.new loop do obj.instance_variable_set(:@foo, 1) obj.remove_instance_variable(:@foo) end ``` can cause us to use many more shapes than we want (and even run out). This commit changes the code such that when an instance variable is removed, we'll walk up the shape tree, find the shape, then rebuild any child nodes that happened to be below the "targetted for removal" IV. This also requires moving any instance variables so that indexes derived from the shape tree will work correctly. Co-Authored-By: Jemma Issroff <jemmaissroff@gmail.com> Co-authored-by: John Hawthorn <jhawthorn@github.com>
This commit is contained in:
parent
f725bf358a
commit
edc7af48ac
Notes:
git
2022-12-07 17:57:31 +00:00
10 changed files with 152 additions and 88 deletions
22
marshal.c
22
marshal.c
|
@ -721,13 +721,23 @@ w_ivar_each(VALUE obj, st_index_t num, struct dump_call_arg *arg)
|
|||
struct w_ivar_arg ivarg = {arg, num};
|
||||
if (!num) return;
|
||||
rb_ivar_foreach(obj, w_obj_each, (st_data_t)&ivarg);
|
||||
if (ivarg.num_ivar) {
|
||||
rb_raise(rb_eRuntimeError, "instance variable removed from %"PRIsVALUE" instance",
|
||||
CLASS_OF(arg->obj));
|
||||
}
|
||||
|
||||
if (shape_id != rb_shape_get_shape_id(arg->obj)) {
|
||||
rb_raise(rb_eRuntimeError, "instance variable added to %"PRIsVALUE" instance",
|
||||
CLASS_OF(arg->obj));
|
||||
rb_shape_t * expected_shape = rb_shape_get_shape_by_id(shape_id);
|
||||
rb_shape_t * actual_shape = rb_shape_get_shape(arg->obj);
|
||||
|
||||
// If the shape tree got _shorter_ then we probably removed an IV
|
||||
// If the shape tree got longer, then we probably added an IV.
|
||||
// The exception message might not be accurate when someone adds and
|
||||
// removes the same number of IVs, but they will still get an exception
|
||||
if (rb_shape_depth(expected_shape) > rb_shape_depth(actual_shape)) {
|
||||
rb_raise(rb_eRuntimeError, "instance variable removed from %"PRIsVALUE" instance",
|
||||
CLASS_OF(arg->obj));
|
||||
}
|
||||
else {
|
||||
rb_raise(rb_eRuntimeError, "instance variable added to %"PRIsVALUE" instance",
|
||||
CLASS_OF(arg->obj));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue