Skip to content

Commit f6e3799

Browse files
Stephan SahmStephan Sahm
authored andcommitted
fixed promote_type inference for special MethodAmbiguitiy failure
also added further tests
1 parent ff4458f commit f6e3799

2 files changed

Lines changed: 43 additions & 13 deletions

File tree

src/promote_type.jl

Lines changed: 27 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -59,36 +59,51 @@ Base.promote_rule(::Type{Identity}, ::Type{Either}) = Either
5959

6060
# As a workaround, we overload `promote_type` to deal with our symmetric case
6161
function Base.promote_type(::Type{Either{L1, R1}}, ::Type{Either{L2, R2}}) where {L1, R1, L2, R2}
62-
Base.@_inline_meta
6362
T = Either{L1, R1}
6463
S = Either{L2, R2}
65-
# we use typeintersect, as we get an Either for the non-fitting site,
66-
# thanks to Base.promote_rule(::Type{Either{L1, R1}}, ::Type{Either{L2, R2}}) where {L1, R1, L2, R2} = Either
67-
typeintersect(promote_rule(T, S), promote_rule(S, T))
64+
either_promote_type_fix(T, S)
6865
end
6966

7067
function Base.promote_type(::Type{Either{<:Any, R1}}, ::Type{Either{<:Any, R2}}) where {R1, R2}
71-
Base.@_inline_meta
7268
T = Either{<:Any, R1}
7369
S = Either{<:Any, R2}
74-
# we use typeintersect, as we get an Either for the non-fitting site,
75-
# thanks to Base.promote_rule(::Type{Either{<:Any, R1}}, ::Type{Either{<:Any, R2}}) where {R1, R2} = Either
76-
typeintersect(promote_rule(T, S), promote_rule(S, T))
70+
either_promote_type_fix(T, S)
7771
end
7872

7973
function Base.promote_type(::Type{Either{L1, <:Any}}, ::Type{Either{L2, <:Any}}) where {L1, L2}
80-
Base.@_inline_meta
8174
T = Either{L1, <:Any}
8275
S = Either{L2, <:Any}
83-
# we use typeintersect, as we get an Either for the non-fitting site,
84-
# thanks to Base.promote_rule(::Type{Either{L1, <:Any}}, ::Type{Either{L2, <:Any}}) where {L1, L2} = Either
85-
typeintersect(promote_rule(T, S), promote_rule(S, T))
76+
either_promote_type_fix(T, S)
77+
end
78+
79+
function either_promote_type_fix(T, S)
80+
# In addition we need to check for MethodAmbiguities, as we cannot resolve them on one side, we just ignore them
81+
a = @TryCatch MethodError promote_rule(T, S)
82+
b = @TryCatch MethodError promote_rule(S, T)
83+
84+
if isexception(a) && isexception(b)
85+
error("Could not `promote_type{T=$T, S=$S}`, as both `promote_rule(T, S)` and `promote_rule(S, T)` result in
86+
MethodErrors: $a, $b.")
87+
elseif issuccess(a) && issuccess(b)
88+
# We use typeintersect, as we get an Either for the non-fitting site,
89+
# thanks to
90+
# * Base.promote_rule(::Type{Either{L1, R1}}, ::Type{Either{L2, R2}}) where {L1, R1, L2, R2} = Either
91+
# * Base.promote_rule(::Type{Either{<:Any, R1}}, ::Type{Either{<:Any, R2}}) where {R1, R2} = Either
92+
# * Base.promote_rule(::Type{Either{L1, <:Any}}, ::Type{Either{L2, <:Any}}) where {L1, L2} = Either
93+
typeintersect(a[], b[])
94+
elseif issuccess(a)
95+
a[]
96+
else
97+
b[]
98+
end
8699
end
87100

88101
# we need to be cautious here, as we cannot dispatch on Type{<:Either{<:Any, R}} or similar, because R might not be defined
89102
Base.promote_rule(::Type{Either{L, R}}, ::Type{Either{L, R}}) where {L, R} = Either{L, R}
90103
Base.promote_rule(::Type{Either{L1, R}}, ::Type{Either{L2, R}}) where {L1, R, L2 <: L1} = Either{L1, R}
91104
Base.promote_rule(::Type{Either{L, R1}}, ::Type{Either{L, R2}}) where {L, R1, R2 <: R1} = Either{L, R1}
105+
Base.promote_rule(::Type{Either{L1, R1}}, ::Type{Either{L2, R2}}) where {L1, R1, L2 <: L1, R2} = Either{L1, <:Any}
106+
Base.promote_rule(::Type{Either{L2, R1}}, ::Type{Either{L1, R2}}) where {L1, R1, L2, R2 <: R1} = Either{<:Any, R1}
92107
Base.promote_rule(::Type{Either{L1, R1}}, ::Type{Either{L2, R2}}) where {L1, R1, L2 <: L1, R2 <: R1} = Either{L1, R1}
93108
Base.promote_rule(::Type{Either{L2, R1}}, ::Type{Either{L1, R2}}) where {L1, R1, L2 <: L1, R2 <: R1} = Either{L1, R1}
94109

test/promote_type.jl

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -153,18 +153,33 @@ using DataTypesBasic
153153
# ---------------
154154

155155
@test promote_type(Either{String, Integer}, Either{String, Integer}) == Either{String, Integer}
156-
@test promote_type(Either{AbstractString, Integer}, Either{String, Number}) == Either{AbstractString, Number}
156+
@test promote_type(Either{Integer, AbstractString}, Either{Integer, String}) == Either{Integer, AbstractString}
157157
@test promote_type(Either{Integer, AbstractString}, Either{Number, String}) == Either{Number, AbstractString}
158+
@test promote_type(Either{AbstractString, Integer}, Either{String, Integer}) == Either{AbstractString, Integer}
159+
@test promote_type(Either{AbstractString, Integer}, Either{String, Number}) == Either{AbstractString, Number}
160+
@test promote_type(Either{Number, String}, Either{Integer, AbstractString}) == Either{Number, AbstractString}
161+
162+
@test promote_type(Either{Integer, AbstractString}, Either{Integer, Bool}) == Either{Integer, <:Any}
163+
@test promote_type(Either{Integer, AbstractString}, Either{Number, Bool}) == Either{Number, <:Any}
164+
@test promote_type(Either{Integer, String}, Either{String, String}) == Either{<:Any, String}
165+
@test promote_type(Either{Integer, AbstractString}, Either{String, String}) == Either{<:Any, AbstractString}
158166

167+
@test promote_type(Either{<:Any, Integer}, Either{<:Any, Integer}) == Either{<:Any, Integer}
159168
@test promote_type(Either{<:Any, Integer}, Either{<:Any, Number}) == Either{<:Any, Number}
169+
@test promote_type(Either{String, <:Any}, Either{String, <:Any}) == Either{String, <:Any}
160170
@test promote_type(Either{String, <:Any}, Either{AbstractString, <:Any}) == Either{AbstractString, <:Any}
161171
@test promote_type(Either, Either) == Either
162172

163173
@test Base.promote_typejoin(Either{Int, String}, Either{Int, String}) == Either{Int, String}
174+
164175
@test Base.promote_typejoin(Either{Int, String}, Either{Number, String}) == Either{<:Any, String}
165176
@test Base.promote_typejoin(Either{Number, String}, Either{Int, String}) == Either{<:Any, String}
166177
@test Base.promote_typejoin(Either{Number, String}, Either{Int, AbstractString}) == Either
167178

179+
@test Base.promote_typejoin(Either{String, Int}, Either{String, Number}) == Either{String, <:Any}
180+
@test Base.promote_typejoin(Either{String, Number}, Either{String, Int}) == Either{String, <:Any}
181+
@test Base.promote_typejoin(Either{String, Number}, Either{AbstractString, Int}) == Either
182+
168183
@test Base.promote_typejoin(Either{Int, <:Any}, Either{Int, <:Any}) == Either{Int, <:Any}
169184
@test Base.promote_typejoin(Either{Int, <:Any}, Either{Number, <:Any}) == Either
170185
@test Base.promote_typejoin(Either{Number, <:Any}, Either{Int, <:Any}) == Either

0 commit comments

Comments
 (0)