From dd3501bb9580951623a9aa7c2f86f7c98f9d6b9c Mon Sep 17 00:00:00 2001
From: Akinori MUSHA <knu@idaemons.org>
Date: Thu, 17 Feb 2022 18:02:42 +0900
Subject: [PATCH] Make Set a builtin feature [Feature #16989]

---
 lib/set.rb       |  2 +-
 prelude.rb       |  9 +++++++++
 test/test_set.rb | 39 +++++++++++++++++++++++++++++++++++++++
 3 files changed, 49 insertions(+), 1 deletion(-)

diff --git a/lib/set.rb b/lib/set.rb
index 7832c848cf..852c13a534 100644
--- a/lib/set.rb
+++ b/lib/set.rb
@@ -854,7 +854,7 @@ module Enumerable
   # Needs to `require "set"` to use this method.
   def to_set(klass = Set, *args, &block)
     klass.new(self, *args, &block)
-  end
+  end unless method_defined?(:to_set)
 end
 
 autoload :SortedSet, "#{__dir__}/set/sorted_set"
diff --git a/prelude.rb b/prelude.rb
index b1e477a3ea..8fd6e6cb77 100644
--- a/prelude.rb
+++ b/prelude.rb
@@ -20,3 +20,12 @@ module Kernel
 
   private :pp
 end
+
+autoload :Set, 'set'
+
+module Enumerable
+  # Makes a set from the enumerable object with given arguments.
+  def to_set(klass = Set, *args, &block)
+    klass.new(self, *args, &block)
+  end
+end
diff --git a/test/test_set.rb b/test/test_set.rb
index b92930a445..83e28878a0 100644
--- a/test/test_set.rb
+++ b/test/test_set.rb
@@ -838,3 +838,42 @@ class TC_Enumerable < Test::Unit::TestCase
     assert_not_same set, set.to_set { |o| o }
   end
 end
+
+class TC_Set_Builtin < Test::Unit::TestCase
+  private def should_omit?
+    Gem::Version.new(RUBY_VERSION) < Gem::Version.new('3.2.0') ||
+      !File.exist?(File.expand_path('../prelude.rb', __dir__))
+  end
+
+  def test_Set
+    omit "skipping the test for the builtin Set" if should_omit?
+
+    assert_separately([], "#{<<~"begin;"}\n#{<<~'end;'}")
+    begin;
+      assert_nothing_raised do
+        set = Set.new([1, 2])
+        assert_equal('Set', set.class.name)
+      end
+    end;
+
+    assert_separately([], "#{<<~"begin;"}\n#{<<~'end;'}")
+    begin;
+      assert_nothing_raised do
+        set = Set[1, 2]
+        assert_equal('Set', set.class.name)
+      end
+    end;
+  end
+
+  def test_to_set
+    omit "skipping the test for the builtin Enumerable#to_set" if should_omit?
+
+    assert_separately([], "#{<<~"begin;"}\n#{<<~'end;'}")
+    begin;
+      assert_nothing_raised do
+        set = [1, 2].to_set
+        assert_equal('Set', set.class.name)
+      end
+    end;
+  end
+end