Skip to content
Permalink
Browse files

merge revision(s) 67217: [Backport #15658]

	The combination of non-Symbol keys and Symbol keys is now allowed again

	Revert r64358.  [Bug #15658]

git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/branches/ruby_2_6@67220 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
  • Loading branch information...
nurse committed Mar 11, 2019
1 parent 50a334d commit dca69588f4a46e1ecc94eeb9e01efc8cd7cb82e4
Showing with 64 additions and 139 deletions.
  1. +11 −2 NEWS
  2. +10 −34 class.c
  3. +17 −12 spec/ruby/language/block_spec.rb
  4. +13 −78 spec/ruby/language/method_spec.rb
  5. +12 −12 test/-ext-/test_scan_args.rb
  6. +1 −1 version.h
13 NEWS
@@ -35,8 +35,6 @@ sufficient information, see the ChangeLog file or Redmine
(1...).each {|index| block } # infinite loop from index 1
ary.zip(1..) {|elem, index| block } # ary.each.with_index(1) { }

* Non-Symbol keys in a keyword arguments hash cause an exception.

* The "shadowing outer local variable" warning is removed. [Feature #12490]

You can now write the following without warning:
@@ -48,6 +46,9 @@ sufficient information, see the ChangeLog file or Redmine

* The flip-flop syntax is deprecated. [Feature #5400]

* Non-Symbol keys in a keyword arguments hash was prohibited at 2.6.0, but
now allowed again. [Bug #15658]

=== Core classes updates (outstanding ones only)

[Array]
@@ -571,6 +572,7 @@ sufficient information, see the ChangeLog file or Redmine

=== Stdlib compatibility issues (excluding feature bug fixes)

<<<<<<< .working

This comment has been minimized.

Copy link
@krzysiek1507

krzysiek1507 Mar 11, 2019

merge conflict @nurse

This comment has been minimized.

Copy link
@nurse

nurse Mar 11, 2019

Author Member

Thanks! I fixed it at c96e0f6!

* These standard libraries have been promoted to default gems.

* e2mmap
@@ -588,6 +590,13 @@ sufficient information, see the ChangeLog file or Redmine
* thwait
* tracer

||||||| .merge-left.r67216
profile.rb, Profiler__::

* Removed from standard library. No one maintains it from Ruby 2.0.0.

=======
>>>>>>> .merge-right.r67217
[BigDecimal]

* The following methods are removed.
44 class.c
@@ -1801,57 +1801,33 @@ unknown_keyword_error(VALUE hash, const ID *table, int keywords)
rb_keyword_error("unknown", rb_hash_keys(hash));
}

struct extract_keywords {
VALUE kwdhash, nonsymkey;
};

static int
separate_symbol(st_data_t key, st_data_t value, st_data_t arg)
{
struct extract_keywords *argp = (struct extract_keywords *)arg;
VALUE k = (VALUE)key, v = (VALUE)value;

if (argp->kwdhash) {
if (UNLIKELY(!SYMBOL_P(k))) {
argp->nonsymkey = k;
return ST_STOP;
}
}
else if (SYMBOL_P(k)) {
if (UNLIKELY(argp->nonsymkey != Qundef)) {
argp->kwdhash = Qnil;
return ST_STOP;
}
argp->kwdhash = rb_hash_new();
}
else {
if (argp->nonsymkey == Qundef)
argp->nonsymkey = k;
return ST_CONTINUE;
}
rb_hash_aset(argp->kwdhash, k, v);
VALUE *kwdhash = (VALUE *)arg;
if (!SYMBOL_P(key)) kwdhash++;
if (!*kwdhash) *kwdhash = rb_hash_new();
rb_hash_aset(*kwdhash, (VALUE)key, (VALUE)value);
return ST_CONTINUE;
}

VALUE
rb_extract_keywords(VALUE *orighash)
{
struct extract_keywords arg = {0, Qundef};
VALUE parthash[2] = {0, 0};
VALUE hash = *orighash;

if (RHASH_EMPTY_P(hash)) {
*orighash = 0;
return hash;
}
rb_hash_foreach(hash, separate_symbol, (st_data_t)&arg);
if (arg.kwdhash) {
if (arg.nonsymkey != Qundef) {
rb_raise(rb_eArgError, "non-symbol key in keyword arguments: %+"PRIsVALUE,
arg.nonsymkey);
}
*orighash = 0;
rb_hash_foreach(hash, separate_symbol, (st_data_t)&parthash);
*orighash = parthash[1];
if (parthash[1] && RBASIC_CLASS(hash) != rb_cHash) {
RBASIC_SET_CLASS(parthash[1], RBASIC_CLASS(hash));
}
return arg.kwdhash;
return parthash[0];
}

int
@@ -49,7 +49,20 @@ def m(a) yield a end
result.should == [1, 2, [], 3, 2, {x: 9}]
end

it "calls #to_hash on the argument" do
it "assigns symbol keys from a Hash to keyword arguments" do
result = m(["a" => 1, a: 10]) { |a=nil, **b| [a, b] }
result.should == [{"a" => 1}, a: 10]
end

it "assigns symbol keys from a Hash returned by #to_hash to keyword arguments" do
obj = mock("coerce block keyword arguments")
obj.should_receive(:to_hash).and_return({"a" => 1, b: 2})

result = m([obj]) { |a=nil, **b| [a, b] }
result.should == [{"a" => 1}, b: 2]
end

it "calls #to_hash on the argument but does not use the result when no keywords are present" do
obj = mock("coerce block keyword arguments")
obj.should_receive(:to_hash).and_return({"a" => 1, "b" => 2})

@@ -58,17 +71,9 @@ def m(a) yield a end
end

describe "when non-symbol keys are in a keyword arguments Hash" do
ruby_version_is ""..."2.6" do
it "separates non-symbol keys and symbol keys" do
result = m(["a" => 10, b: 2]) { |a=nil, **b| [a, b] }
result.should == [{"a" => 10}, {b: 2}]
end
end

ruby_version_is "2.6" do
it "raises an ArgumentError" do
lambda {m(["a" => 1, a: 10]) { |a=nil, **b| [a, b] }}.should raise_error(ArgumentError)
end
it "separates non-symbol keys and symbol keys" do
result = m(["a" => 10, b: 2]) { |a=nil, **b| [a, b] }
result.should == [{"a" => 10}, {b: 2}]
end
end

@@ -849,12 +849,7 @@ def m(a=1, b:) [a, b] end

m(b: 2).should == [1, 2]
m(2, b: 1).should == [2, 1]
ruby_version_is ""..."2.6" do
m("a" => 1, b: 2).should == [{"a" => 1}, 2]
end
ruby_version_is "2.6" do
lambda {m("a" => 1, b: 2)}.should raise_error(ArgumentError)
end
m("a" => 1, b: 2).should == [{"a" => 1}, 2]
end

evaluate <<-ruby do
@@ -864,12 +859,7 @@ def m(a=1, b: 2) [a, b] end
m().should == [1, 2]
m(2).should == [2, 2]
m(b: 3).should == [1, 3]
ruby_version_is ""..."2.6" do
m("a" => 1, b: 2).should == [{"a" => 1}, 2]
end
ruby_version_is "2.6" do
lambda {m("a" => 1, b: 2)}.should raise_error(ArgumentError)
end
m("a" => 1, b: 2).should == [{"a" => 1}, 2]
end

evaluate <<-ruby do
@@ -878,12 +868,7 @@ def m(a=1, **) a end

m().should == 1
m(2, a: 1, b: 0).should == 2
ruby_version_is ""..."2.6" do
m("a" => 1, a: 2).should == {"a" => 1}
end
ruby_version_is "2.6" do
lambda {m("a" => 1, a: 2)}.should raise_error(ArgumentError)
end
m("a" => 1, a: 2).should == {"a" => 1}
end

evaluate <<-ruby do
@@ -929,12 +914,7 @@ def m(*, a:) a end

m(a: 1).should == 1
m(1, 2, a: 3).should == 3
ruby_version_is ""..."2.6" do
m("a" => 1, a: 2).should == 2
end
ruby_version_is "2.6" do
lambda {m("a" => 1, a: 2)}.should raise_error(ArgumentError)
end
m("a" => 1, a: 2).should == 2
end

evaluate <<-ruby do
@@ -943,12 +923,7 @@ def m(*a, b:) [a, b] end

m(b: 1).should == [[], 1]
m(1, 2, b: 3).should == [[1, 2], 3]
ruby_version_is ""..."2.6" do
m("a" => 1, b: 2).should == [[{"a" => 1}], 2]
end
ruby_version_is "2.6" do
lambda {m("a" => 1, b: 2)}.should raise_error(ArgumentError)
end
m("a" => 1, b: 2).should == [[{"a" => 1}], 2]
end

evaluate <<-ruby do
@@ -959,12 +934,7 @@ def m(*, a: 1) a end
m(1, 2).should == 1
m(a: 2).should == 2
m(1, a: 2).should == 2
ruby_version_is ""..."2.6" do
m("a" => 1, a: 2).should == 2
end
ruby_version_is "2.6" do
lambda {m("a" => 1, a: 2)}.should raise_error(ArgumentError)
end
m("a" => 1, a: 2).should == 2
end

evaluate <<-ruby do
@@ -973,12 +943,7 @@ def m(*a, b: 1) [a, b] end

m().should == [[], 1]
m(1, 2, 3, b: 4).should == [[1, 2, 3], 4]
ruby_version_is ""..."2.6" do
m("a" => 1, b: 2).should == [[{"a" => 1}], 2]
end
ruby_version_is "2.6" do
lambda {m("a" => 1, b: 2)}.should raise_error(ArgumentError)
end
m("a" => 1, b: 2).should == [[{"a" => 1}], 2]

a = mock("splat")
a.should_not_receive(:to_ary)
@@ -1009,12 +974,7 @@ def m(*a, **) a end

m().should == []
m(1, 2, 3, a: 4, b: 5).should == [1, 2, 3]
ruby_version_is ""..."2.6" do
m("a" => 1, a: 1).should == [{"a" => 1}]
end
ruby_version_is "2.6" do
lambda {m("a" => 1, a: 1)}.should raise_error(ArgumentError)
end
m("a" => 1, a: 1).should == [{"a" => 1}]
m(1, **{a: 2}).should == [1]

h = mock("keyword splat")
@@ -1028,12 +988,7 @@ def m(*, **k) k end

m().should == {}
m(1, 2, 3, a: 4, b: 5).should == {a: 4, b: 5}
ruby_version_is ""..."2.6" do
m("a" => 1, a: 1).should == {a: 1}
end
ruby_version_is "2.6" do
lambda {m("a" => 1, a: 1)}.should raise_error(ArgumentError)
end
m("a" => 1, a: 1).should == {a: 1}

h = mock("keyword splat")
h.should_receive(:to_hash).and_return({a: 1})
@@ -1047,22 +1002,12 @@ def m(a = nil, **k) [a, k] end
m().should == [nil, {}]
m("a" => 1).should == [{"a" => 1}, {}]
m(a: 1).should == [nil, {a: 1}]
ruby_version_is ""..."2.6" do
m("a" => 1, a: 1).should == [{"a" => 1}, {a: 1}]
end
ruby_version_is "2.6" do
lambda {m("a" => 1, a: 1)}.should raise_error(ArgumentError)
end
m("a" => 1, a: 1).should == [{"a" => 1}, {a: 1}]
m({ "a" => 1 }, a: 1).should == [{"a" => 1}, {a: 1}]
m({a: 1}, {}).should == [{a: 1}, {}]

h = {"a" => 1, b: 2}
ruby_version_is ""..."2.6" do
m(h).should == [{"a" => 1}, {b: 2}]
end
ruby_version_is "2.6" do
lambda {m(h)}.should raise_error(ArgumentError)
end
m(h).should == [{"a" => 1}, {b: 2}]
h.should == {"a" => 1, b: 2}

h = {"a" => 1}
@@ -1082,12 +1027,7 @@ def m(a = nil, **k) [a, k] end

h = mock("keyword splat")
h.should_receive(:to_hash).and_return({"a" => 1, a: 2})
ruby_version_is ""..."2.6" do
m(h).should == [{"a" => 1}, {a: 2}]
end
ruby_version_is "2.6" do
lambda {m(h)}.should raise_error(ArgumentError)
end
m(h).should == [{"a" => 1}, {a: 2}]
end

evaluate <<-ruby do
@@ -1101,12 +1041,7 @@ def m(*a, **k) [a, k] end

m("a" => 1).should == [[{"a" => 1}], {}]
m(a: 1).should == [[], {a: 1}]
ruby_version_is ""..."2.6" do
m("a" => 1, a: 1).should == [[{"a" => 1}], {a: 1}]
end
ruby_version_is "2.6" do
lambda {m("a" => 1, a: 1)}.should raise_error(ArgumentError)
end
m("a" => 1, a: 1).should == [[{"a" => 1}], {a: 1}]
m({ "a" => 1 }, a: 1).should == [[{"a" => 1}], {a: 1}]
m({a: 1}, {}).should == [[{a: 1}], {}]
m({a: 1}, {"a" => 1}).should == [[{a: 1}, {"a" => 1}], {}]

0 comments on commit dca6958

Please sign in to comment.
You can’t perform that action at this time.