From d90a2ac00d6d47b5447730eada07e33ce4f4ba95 Mon Sep 17 00:00:00 2001
From: Rafael Fourquet <fourquet.rafael@gmail.com>
Date: Mon, 13 Apr 2020 09:44:09 +0200
Subject: [PATCH 1/2] verbose replace for Tuple

---
 base/set.jl | 70 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 70 insertions(+)

diff --git a/base/set.jl b/base/set.jl
index b6c9765a0b6cc..b0c34af0cbec1 100644
--- a/base/set.jl
+++ b/base/set.jl
@@ -728,3 +728,73 @@ function _replace!(new::Callable, t::Set{T}, ::AbstractSet, count::Int) where {T
     end
     t
 end
+
+### replace for tuples
+
+@inline replace(f::Callable, t::Tuple{}, count::Int) = ()
+@inline replace(f::Callable, t::Tuple{Any}, count::Int) =
+    count == 0 ? t : (f(t[1]),)
+
+@inline replace(f::Callable, t::Tuple{Any,Any}, count::Int) =
+    if count >= 2
+        (f(t[1]), f(t[2]))
+    elseif count == 0
+        t
+    elseif count == 1
+        x = f(t[1])
+        x === t[1] ?
+            (x, f(t[2])) :
+            (x, t[2])
+    end
+
+@inline replace(f::Callable, t::Tuple{Any,Any,Any}, count::Int) =
+    if count >= 3
+        (f(t[1]), f(t[2]), f(t[3]))
+    elseif count == 0
+        t
+    else
+        x = f(t[1])
+        if x === t[1]
+            if count == 1
+                y = f(t[2])
+                y === t[2] ?
+                    (x, y, f(t[3])) :
+                    (x, y, t[3])
+            else # count == 2
+                (x, f(t[2]), f(t[3]))
+            end
+        elseif count == 1
+            (x, t[2], t[3])
+        else
+            y = f(t[2])
+            y === t[2] ?
+                (x, y, f(t[3])) :
+                (x, y, t[3])
+        end
+    end
+
+@inline replace(f::Callable, t::Tuple, count::Int) =
+    if count >= length(t)
+        map(f, t)
+    elseif count == 0
+        t
+    else
+        x = f(t[1])
+        (x, _replace(f, tail(t), count - !==(x, t[1]))...)
+    end
+
+@inline replace(f::Callable, t::Tuple; count::Integer=typemax(Int)) =
+    replace(f, t, check_count(count))
+
+function replace(t::Tuple, count::Int, old_new::Tuple{Vararg{Pair}})
+    @inline function new(x)
+        for o_n in old_new
+            isequal(first(o_n), x) && return last(o_n)
+        end
+        return x
+    end
+    replace(new, t, count)
+end
+
+replace(t::Tuple, old_new::Pair...; count::Integer=typemax(Int)) =
+    replace(t, check_count(count), old_new)

From aa7ce21358ecd2af80adee67dc66f1d652dd5ef3 Mon Sep 17 00:00:00 2001
From: Rafael Fourquet <fourquet.rafael@gmail.com>
Date: Wed, 28 Oct 2020 19:29:08 +0100
Subject: [PATCH 2/2] add replace methods for Tuple

---
 base/set.jl  | 61 ++++++++--------------------------------------------
 test/sets.jl |  6 ++++++
 2 files changed, 15 insertions(+), 52 deletions(-)

diff --git a/base/set.jl b/base/set.jl
index b0c34af0cbec1..a04bc106ed1da 100644
--- a/base/set.jl
+++ b/base/set.jl
@@ -731,70 +731,27 @@ end
 
 ### replace for tuples
 
-@inline replace(f::Callable, t::Tuple{}, count::Int) = ()
-@inline replace(f::Callable, t::Tuple{Any}, count::Int) =
-    count == 0 ? t : (f(t[1]),)
-
-@inline replace(f::Callable, t::Tuple{Any,Any}, count::Int) =
-    if count >= 2
-        (f(t[1]), f(t[2]))
-    elseif count == 0
-        t
-    elseif count == 1
-        x = f(t[1])
-        x === t[1] ?
-            (x, f(t[2])) :
-            (x, t[2])
-    end
-
-@inline replace(f::Callable, t::Tuple{Any,Any,Any}, count::Int) =
-    if count >= 3
-        (f(t[1]), f(t[2]), f(t[3]))
-    elseif count == 0
-        t
-    else
-        x = f(t[1])
-        if x === t[1]
-            if count == 1
-                y = f(t[2])
-                y === t[2] ?
-                    (x, y, f(t[3])) :
-                    (x, y, t[3])
-            else # count == 2
-                (x, f(t[2]), f(t[3]))
-            end
-        elseif count == 1
-            (x, t[2], t[3])
-        else
-            y = f(t[2])
-            y === t[2] ?
-                (x, y, f(t[3])) :
-                (x, y, t[3])
-        end
-    end
-
-@inline replace(f::Callable, t::Tuple, count::Int) =
-    if count >= length(t)
-        map(f, t)
-    elseif count == 0
+function _replace(f::Callable, t::Tuple, count::Int)
+    if count == 0 || isempty(t)
         t
     else
         x = f(t[1])
         (x, _replace(f, tail(t), count - !==(x, t[1]))...)
     end
+end
 
-@inline replace(f::Callable, t::Tuple; count::Integer=typemax(Int)) =
-    replace(f, t, check_count(count))
+replace(f::Callable, t::Tuple; count::Integer=typemax(Int)) =
+    _replace(f, t, check_count(count))
 
-function replace(t::Tuple, count::Int, old_new::Tuple{Vararg{Pair}})
-    @inline function new(x)
+function _replace(t::Tuple, count::Int, old_new::Tuple{Vararg{Pair}})
+    _replace(t, count) do x
+        @_inline_meta
         for o_n in old_new
             isequal(first(o_n), x) && return last(o_n)
         end
         return x
     end
-    replace(new, t, count)
 end
 
 replace(t::Tuple, old_new::Pair...; count::Integer=typemax(Int)) =
-    replace(t, check_count(count), old_new)
+    _replace(t, check_count(count), old_new)
diff --git a/test/sets.jl b/test/sets.jl
index 82f2a3b0aab6f..46854dae957c6 100644
--- a/test/sets.jl
+++ b/test/sets.jl
@@ -586,11 +586,14 @@ end
 @testset "replace! & replace" begin
     a = [1, 2, 3, 1]
     @test replace(x -> iseven(x) ? 2x : x, a) == [1, 4, 3, 1]
+    @test replace(x -> iseven(x) ? 2x : x, Tuple(a)) === (1, 4, 3, 1)
     @test replace!(x -> iseven(x) ? 2x : x, a) === a
     @test a == [1, 4, 3, 1]
     @test replace(a, 1=>0) == [0, 4, 3, 0]
+    @test replace(Tuple(a), 1=>0) === (0, 4, 3, 0)
     for count = (1, 0x1, big(1))
         @test replace(a, 1=>0, count=count) == [0, 4, 3, 1]
+        @test replace(Tuple(a), 1=>0, count=count) === (0, 4, 3, 1)
     end
     @test replace!(a, 1=>2) === a
     @test a == [2, 4, 3, 2]
@@ -615,6 +618,7 @@ end
 
     for count = (0, 0x0, big(0)) # count == 0 --> no replacements
         @test replace([1, 2], 1=>0, 2=>0; count) == [1, 2]
+        @test replace((1, 2), 1=>0, 2=>0; count) === (1, 2)
         for dict = (Dict(1=>2, 2=>3), IdDict(1=>2, 2=>3))
             @test replace(dict, (1=>2) => (1=>3); count) == dict
         end
@@ -668,7 +672,9 @@ end
 
     # test that isequal is used
     @test replace([NaN, 1.0], NaN=>0.0) == [0.0, 1.0]
+    @test replace((NaN, 1.0), NaN=>0.0) === (0.0, 1.0)
     @test replace([1, missing], missing=>0) == [1, 0]
+    @test replace((1, missing), missing=>0) === (1, 0)
 end
 
 @testset "⊆, ⊊, ⊈, ⊇, ⊋, ⊉, <, <=, issetequal" begin