From 64a4fe7132934b15ad1272a63863aa1a3d005398 Mon Sep 17 00:00:00 2001
From: Martin Holters <martin.holters@hsu-hh.de>
Date: Mon, 20 Mar 2017 10:05:07 +0100
Subject: [PATCH 1/3] Use `typejoin` of the field types for `eltype` of
 heterogeneous `Tuple`s

---
 base/tuple.jl | 9 +++++++++
 test/tuple.jl | 7 ++++++-
 2 files changed, 15 insertions(+), 1 deletion(-)

diff --git a/base/tuple.jl b/base/tuple.jl
index b3799e57d6fba..e96e3ab06db97 100644
--- a/base/tuple.jl
+++ b/base/tuple.jl
@@ -63,6 +63,15 @@ first(t::Tuple) = t[1]
 
 eltype(::Type{Tuple{}}) = Bottom
 eltype(::Type{<:Tuple{Vararg{E}}}) where {E} = E
+function eltype(t::Type{<:Tuple})
+    @_pure_meta
+    t´ = unwrap_unionall(t)
+    r = Union{}
+    for ti in t´.parameters
+        r = typejoin(r, unwrapva(ti))
+    end
+    return rewrap_unionall(r, t)
+end
 
 # version of tail that doesn't throw on empty tuples (used in array indexing)
 safe_tail(t::Tuple) = tail(t)
diff --git a/test/tuple.jl b/test/tuple.jl
index 20ccbe348587c..8a2e3de09275b 100644
--- a/test/tuple.jl
+++ b/test/tuple.jl
@@ -65,8 +65,13 @@ end
 @test eltype((1,2,3)) === Int
 @test eltype((1.0,2.0,3.0)) <: AbstractFloat
 @test eltype((true, false)) === Bool
-@test eltype((1,2.0, false)) === Any
+@test eltype((1, 2.0, false)) === typejoin(Int, Float64, Bool)
 @test eltype(()) === Union{}
+@test eltype(Tuple{Int, Float64, Vararg{Bool}}) === typejoin(Int, Float64, Bool)
+@test eltype(Tuple{Int, T, Vararg{Bool}} where T <: AbstractFloat) ===
+    typejoin(Int, AbstractFloat, Bool)
+@test eltype(Tuple{Int, Bool, Vararg{T}} where T <: AbstractFloat) ===
+    typejoin(Int, AbstractFloat, Bool)
 
 begin
     local foo

From da53d717ebdcacef2f712b6cb9c8ba6bbf97b64e Mon Sep 17 00:00:00 2001
From: Martin Holters <martin.holters@hsu-hh.de>
Date: Mon, 20 Mar 2017 17:24:24 +0100
Subject: [PATCH 2/3] Move `rewrap_unionall` in `eltype(::Type{<:Tuple})`

---
 base/tuple.jl | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/base/tuple.jl b/base/tuple.jl
index e96e3ab06db97..ec4bcbf2434a4 100644
--- a/base/tuple.jl
+++ b/base/tuple.jl
@@ -68,9 +68,9 @@ function eltype(t::Type{<:Tuple})
     t´ = unwrap_unionall(t)
     r = Union{}
     for ti in t´.parameters
-        r = typejoin(r, unwrapva(ti))
+        r = typejoin(r, rewrap_unionall(unwrapva(ti), t))
     end
-    return rewrap_unionall(r, t)
+    return r
 end
 
 # version of tail that doesn't throw on empty tuples (used in array indexing)

From 4752d246105ec7c9114efa51fd15ce7cb4e950e9 Mon Sep 17 00:00:00 2001
From: Martin Holters <martin.holters@hsu-hh.de>
Date: Tue, 21 Mar 2017 08:51:57 +0100
Subject: [PATCH 3/3] Handle `Union` of `Tuple`s in `eltype(::Type{<:Tuple})`

---
 base/tuple.jl | 1 +
 test/tuple.jl | 1 +
 2 files changed, 2 insertions(+)

diff --git a/base/tuple.jl b/base/tuple.jl
index ec4bcbf2434a4..3b45f812fc0b6 100644
--- a/base/tuple.jl
+++ b/base/tuple.jl
@@ -65,6 +65,7 @@ eltype(::Type{Tuple{}}) = Bottom
 eltype(::Type{<:Tuple{Vararg{E}}}) where {E} = E
 function eltype(t::Type{<:Tuple})
     @_pure_meta
+    t isa Union && return typejoin(eltype(t.a), eltype(t.b))
     t´ = unwrap_unionall(t)
     r = Union{}
     for ti in t´.parameters
diff --git a/test/tuple.jl b/test/tuple.jl
index 8a2e3de09275b..70f08a30f667a 100644
--- a/test/tuple.jl
+++ b/test/tuple.jl
@@ -72,6 +72,7 @@ end
     typejoin(Int, AbstractFloat, Bool)
 @test eltype(Tuple{Int, Bool, Vararg{T}} where T <: AbstractFloat) ===
     typejoin(Int, AbstractFloat, Bool)
+@test eltype(Union{Tuple{Int, Float64}, Tuple{Vararg{Bool}}}) === typejoin(Int, Float64, Bool)
 
 begin
     local foo