From b5489e7e69b86c2bf382ad3cbf58b2d91953fd76 Mon Sep 17 00:00:00 2001 From: Quinton Miller Date: Tue, 2 Apr 2024 16:53:21 +0800 Subject: [PATCH] Fix `Hash#update` when default block also adds given key --- spec/std/hash_spec.cr | 11 +++++++++++ src/hash.cr | 4 +++- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/spec/std/hash_spec.cr b/spec/std/hash_spec.cr index 85a3ad2833f8..c4c251cb2ba0 100644 --- a/spec/std/hash_spec.cr +++ b/spec/std/hash_spec.cr @@ -271,6 +271,17 @@ describe "Hash" do h[3000].should eq(3000 + 42) end + it "doesn't create a duplicate key, if key does not exist and default block adds the given key (#14416)" do + h = Hash(String, Int32).new do |h, new_key| + h[new_key] = 1 + new_key.size + end + + h.update("new key") { |v| v * 6 } + h.size.should eq(1) + h["new key"].should eq(7 * 6) + end + it "inserts a new entry using the default value as input, if key does not exist" do h = Hash(String, Int32).new(2) diff --git a/src/hash.cr b/src/hash.cr index 38ea694cb421..e32254bc59cf 100644 --- a/src/hash.cr +++ b/src/hash.cr @@ -1144,7 +1144,9 @@ class Hash(K, V) entry.value elsif block = @block default_value = block.call(self, key) - insert_new(key, yield default_value) + + # NOTE: can't use `#insert_new` as `block` might add arbitrary keys + upsert(key, yield default_value) default_value else raise KeyError.new "Missing hash key: #{key.inspect}"