From 5e16857315bf55307c5fc887ca6f03bfa0630a93 Mon Sep 17 00:00:00 2001 From: Marc-Andre Lafortune Date: Tue, 1 Sep 2020 21:22:20 -0400 Subject: Fix constant names set using const_set on a singleton class Fixes [Bug #14895] --- spec/ruby/core/module/const_set_spec.rb | 18 ++++++++++++++---- spec/ruby/core/module/name_spec.rb | 18 ++++++++++++++---- spec/ruby/language/module_spec.rb | 18 ++++++++++++++---- test/ruby/test_module.rb | 10 ++++++++-- variable.c | 17 +++++++++-------- 5 files changed, 59 insertions(+), 22 deletions(-) diff --git a/spec/ruby/core/module/const_set_spec.rb b/spec/ruby/core/module/const_set_spec.rb index 77a2e59a13..b537d3f133 100644 --- a/spec/ruby/core/module/const_set_spec.rb +++ b/spec/ruby/core/module/const_set_spec.rb @@ -20,10 +20,20 @@ describe "Module#const_set" do m.name.should == "ConstantSpecs::CS_CONST1000" end - it "does not set the name of a module scoped by an anonymous module" do - a, b = Module.new, Module.new - a.const_set :B, b - b.name.should be_nil + ruby_version_is ""..."3.0" do + it "does not set the name of a module scoped by an anonymous module" do + a, b = Module.new, Module.new + a.const_set :B, b + b.name.should be_nil + end + end + + ruby_version_is "3.0" do + it "sets the name of a module scoped by an anonymous module" do + a, b = Module.new, Module.new + a.const_set :B, b + b.name.should.end_with? '::B' + end end it "sets the name of contained modules when assigning a toplevel anonymous module" do diff --git a/spec/ruby/core/module/name_spec.rb b/spec/ruby/core/module/name_spec.rb index ae8037555b..ca9106a973 100644 --- a/spec/ruby/core/module/name_spec.rb +++ b/spec/ruby/core/module/name_spec.rb @@ -6,10 +6,20 @@ describe "Module#name" do Module.new.name.should be_nil end - it "is nil when assigned to a constant in an anonymous module" do - m = Module.new - m::N = Module.new - m::N.name.should be_nil + ruby_version_is ""..."3.0" do + it "is nil when assigned to a constant in an anonymous module" do + m = Module.new + m::N = Module.new + m::N.name.should be_nil + end + end + + ruby_version_is "3.0" do + it "is not nil when assigned to a constant in an anonymous module" do + m = Module.new + m::N = Module.new + m::N.name.should.end_with? '::N' + end end it "is not nil for a nested module created with the module keyword" do diff --git a/spec/ruby/language/module_spec.rb b/spec/ruby/language/module_spec.rb index 1b41e184bb..cbc7149359 100644 --- a/spec/ruby/language/module_spec.rb +++ b/spec/ruby/language/module_spec.rb @@ -69,10 +69,20 @@ describe "Assigning an anonymous module to a constant" do mod.name.should == "ModuleSpecs_CS1" end - it "does not set the name of a module scoped by an anonymous module" do - a, b = Module.new, Module.new - a::B = b - b.name.should be_nil + ruby_version_is ""..."3.0" do + it "does not set the name of a module scoped by an anonymous module" do + a, b = Module.new, Module.new + a::B = b + b.name.should be_nil + end + end + + ruby_version_is "3.0" do + it "sets the name of a module scoped by an anonymous module" do + a, b = Module.new, Module.new + a::B = b + b.name.should.end_with? '::B' + end end it "sets the name of contained modules when assigning a toplevel anonymous module" do diff --git a/test/ruby/test_module.rb b/test/ruby/test_module.rb index d2da384cbd..94e415b08c 100644 --- a/test/ruby/test_module.rb +++ b/test/ruby/test_module.rb @@ -767,13 +767,13 @@ class TestModule < Test::Unit::TestCase n = Module.new m.const_set(:N, n) assert_nil(m.name) - assert_nil(n.name) + assert_match(/::N$/, n.name) assert_equal([:N], m.constants) m.module_eval("module O end") assert_equal([:N, :O], m.constants.sort) m.module_eval("class C; end") assert_equal([:C, :N, :O], m.constants.sort) - assert_nil(m::N.name) + assert_match(/::N$/, m::N.name) assert_match(/\A#::O\z/, m::O.name) assert_match(/\A#::C\z/, m::C.name) self.class.const_set(:M, m) @@ -2724,6 +2724,12 @@ class TestModule < Test::Unit::TestCase assert_not_predicate m.clone(freeze: false), :frozen? end + def test_module_name_in_singleton_method + s = Object.new.singleton_class + mod = s.const_set(:Foo, Module.new) + assert_match(/::Foo$/, mod.name, '[Bug #14895]') + end + private def assert_top_method_is_private(method) diff --git a/variable.c b/variable.c index 26928ca0bc..3c3b689889 100644 --- a/variable.c +++ b/variable.c @@ -2854,14 +2854,15 @@ rb_const_set(VALUE klass, ID id, VALUE val) else { int parental_path_permanent; VALUE parental_path = classname(klass, &parental_path_permanent); - if (!NIL_P(parental_path)) { - if (parental_path_permanent && !val_path_permanent) { - set_namespace_path(val, build_const_path(parental_path, id)); - } - else if (!parental_path_permanent && NIL_P(val_path)) { - rb_ivar_set(val, tmp_classpath, build_const_path(parental_path, id)); - } - } + if (NIL_P(parental_path)) { + parental_path = rb_funcall(klass, rb_intern("to_s"), 0); + } + if (parental_path_permanent && !val_path_permanent) { + set_namespace_path(val, build_const_path(parental_path, id)); + } + else if (!parental_path_permanent && NIL_P(val_path)) { + rb_ivar_set(val, tmp_classpath, build_const_path(parental_path, id)); + } } } } -- cgit v1.2.3