Commit 97c9e6b0 authored by KOBAYASHI Shuji's avatar KOBAYASHI Shuji

Fix `include`, `prepend` and `extend` to frozen object

parent cf697240
...@@ -1070,8 +1070,8 @@ include_module_at(mrb_state *mrb, struct RClass *c, struct RClass *ins_pos, stru ...@@ -1070,8 +1070,8 @@ include_module_at(mrb_state *mrb, struct RClass *c, struct RClass *ins_pos, stru
MRB_API void MRB_API void
mrb_include_module(mrb_state *mrb, struct RClass *c, struct RClass *m) mrb_include_module(mrb_state *mrb, struct RClass *c, struct RClass *m)
{ {
int changed = include_module_at(mrb, c, find_origin(c), m, 1); mrb_check_frozen(mrb, c);
if (changed < 0) { if (include_module_at(mrb, c, find_origin(c), m, 1) < 0) {
mrb_raise(mrb, E_ARGUMENT_ERROR, "cyclic include detected"); mrb_raise(mrb, E_ARGUMENT_ERROR, "cyclic include detected");
} }
} }
...@@ -1082,6 +1082,7 @@ mrb_prepend_module(mrb_state *mrb, struct RClass *c, struct RClass *m) ...@@ -1082,6 +1082,7 @@ mrb_prepend_module(mrb_state *mrb, struct RClass *c, struct RClass *m)
struct RClass *origin; struct RClass *origin;
int changed = 0; int changed = 0;
mrb_check_frozen(mrb, c);
if (!(c->flags & MRB_FL_CLASS_IS_PREPENDED)) { if (!(c->flags & MRB_FL_CLASS_IS_PREPENDED)) {
origin = (struct RClass*)mrb_obj_alloc(mrb, MRB_TT_ICLASS, c); origin = (struct RClass*)mrb_obj_alloc(mrb, MRB_TT_ICLASS, c);
origin->flags |= MRB_FL_CLASS_IS_ORIGIN | MRB_FL_CLASS_IS_INHERITED; origin->flags |= MRB_FL_CLASS_IS_ORIGIN | MRB_FL_CLASS_IS_INHERITED;
......
...@@ -240,6 +240,9 @@ assert('Kernel#extend', '15.3.1.3.13') do ...@@ -240,6 +240,9 @@ assert('Kernel#extend', '15.3.1.3.13') do
assert_true a.respond_to?(:test_method) assert_true a.respond_to?(:test_method)
assert_false b.respond_to?(:test_method) assert_false b.respond_to?(:test_method)
assert_raise(FrozenError) { Object.new.freeze.extend(Test4ExtendModule) }
assert_raise(FrozenError, TypeError) { :sym.extend(Test4ExtendModule) }
end end
assert('Kernel#extend works on toplevel', '15.3.1.3.13') do assert('Kernel#extend works on toplevel', '15.3.1.3.13') do
......
...@@ -59,6 +59,7 @@ assert('Module#append_features', '15.2.2.4.10') do ...@@ -59,6 +59,7 @@ assert('Module#append_features', '15.2.2.4.10') do
end end
assert_equal Test4AppendFeatures2, Test4AppendFeatures2.const_get(:Const4AppendFeatures2) assert_equal Test4AppendFeatures2, Test4AppendFeatures2.const_get(:Const4AppendFeatures2)
assert_raise(FrozenError) { Module.new.append_features Class.new.freeze }
end end
assert('Module#attr NameError') do assert('Module#attr NameError') do
...@@ -275,6 +276,18 @@ assert('Module#const_missing', '15.2.2.4.22') do ...@@ -275,6 +276,18 @@ assert('Module#const_missing', '15.2.2.4.22') do
assert_equal 42, Test4ConstMissing.const_get(:ConstDoesntExist) assert_equal 42, Test4ConstMissing.const_get(:ConstDoesntExist)
end end
assert('Module#extend_object', '15.2.2.4.25') do
cls = Class.new
mod = Module.new { def foo; end }
a = cls.new
b = cls.new
mod.extend_object(b)
assert_false a.respond_to?(:foo)
assert_true b.respond_to?(:foo)
assert_raise(FrozenError) { mod.extend_object(cls.new.freeze) }
assert_raise(FrozenError, TypeError) { mod.extend_object(1) }
end
assert('Module#include', '15.2.2.4.27') do assert('Module#include', '15.2.2.4.27') do
module Test4Include module Test4Include
Const4Include = 42 Const4Include = 42
...@@ -288,6 +301,7 @@ assert('Module#include', '15.2.2.4.27') do ...@@ -288,6 +301,7 @@ assert('Module#include', '15.2.2.4.27') do
assert_equal 42, Test4Include2.const_get(:Const4Include) assert_equal 42, Test4Include2.const_get(:Const4Include)
assert_equal Test4Include2, Test4Include2.include_result assert_equal Test4Include2, Test4Include2.include_result
assert_raise(FrozenError) { Module.new.freeze.include Test4Include }
end end
assert('Module#include?', '15.2.2.4.28') do assert('Module#include?', '15.2.2.4.28') do
...@@ -398,6 +412,15 @@ assert('Module#define_method') do ...@@ -398,6 +412,15 @@ assert('Module#define_method') do
end end
end end
assert 'Module#prepend_features' do
mod = Module.new { def m; :mod end }
cls = Class.new { def m; :cls end }
assert_equal :cls, cls.new.m
mod.prepend_features(cls)
assert_equal :mod, cls.new.m
assert_raise(FrozenError) { Module.new.prepend_features(Class.new.freeze) }
end
# @!group prepend # @!group prepend
assert('Module#prepend') do assert('Module#prepend') do
module M0 module M0
...@@ -632,6 +655,10 @@ end ...@@ -632,6 +655,10 @@ end
# end # end
# end; # end;
#end #end
assert 'Module#prepend to frozen class' do
assert_raise(FrozenError) { Class.new.freeze.prepend Module.new }
end
# @!endgroup prepend # @!endgroup prepend
assert('Module#to_s') do assert('Module#to_s') do
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment