Skip to content

Commit 2a72d52

Browse files
committed
fix #30114, specificity transitivity errors in convert methods
1 parent e4f408e commit 2a72d52

File tree

5 files changed

+123
-49
lines changed

5 files changed

+123
-49
lines changed

base/compiler/compiler.jl

-1
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@ include(mod, x) = Core.include(mod, x)
2424

2525
# essential files and libraries
2626
include("essentials.jl")
27-
include("some.jl")
2827
include("ctypes.jl")
2928
include("generator.jl")
3029
include("reflection.jl")

base/missing.jl

+3-6
Original file line numberDiff line numberDiff line change
@@ -43,15 +43,12 @@ promote_rule(::Type{Union{Nothing, Missing, S}}, ::Type{T}) where {T,S} =
4343
Union{Nothing, Missing, promote_type(T, S)}
4444

4545
convert(::Type{Union{T, Missing}}, x::Union{T, Missing}) where {T} = x
46-
convert(::Type{Union{T, Missing}}, x) where {T} = convert(T, x)
46+
# To print more appropriate message than "T not defined"
47+
convert(::Type{Union{T, Missing}}, x) where {T} =
48+
@isdefined(T) ? convert(T, x) : throw(MethodError(convert, (Missing, x)))
4749
# To fix ambiguities
48-
convert(::Type{Missing}, ::Missing) = missing
4950
convert(::Type{Union{Nothing, Missing}}, x::Union{Nothing, Missing}) = x
5051
convert(::Type{Union{Nothing, Missing, T}}, x::Union{Nothing, Missing, T}) where {T} = x
51-
convert(::Type{Union{Nothing, Missing}}, x) =
52-
throw(MethodError(convert, (Union{Nothing, Missing}, x)))
53-
# To print more appropriate message than "T not defined"
54-
convert(::Type{Missing}, x) = throw(MethodError(convert, (Missing, x)))
5552

5653
# Comparison operators
5754
==(::Missing, ::Missing) = missing

base/some.jl

+2-3
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,8 @@ convert(::Type{Some{T}}, x::Some) where {T} = Some{T}(convert(T, x.value))
1919
convert(::Type{Union{Some{T}, Nothing}}, x::Some) where {T} = convert(Some{T}, x)
2020

2121
convert(::Type{Union{T, Nothing}}, x::Union{T, Nothing}) where {T} = x
22-
convert(::Type{Union{T, Nothing}}, x::Any) where {T} = convert(T, x)
23-
convert(::Type{Nothing}, x::Nothing) = nothing
24-
convert(::Type{Nothing}, x::Any) = throw(MethodError(convert, (Nothing, x)))
22+
convert(::Type{Union{T, Nothing}}, x::Any) where {T} =
23+
@isdefined(T) ? convert(T, x) : throw(MethodError(convert, (Nothing, x)))
2524

2625
function show(io::IO, x::Some)
2726
if get(io, :typeinfo, Any) == typeof(x)

src/subtype.c

+59-35
Original file line numberDiff line numberDiff line change
@@ -322,7 +322,7 @@ static int obviously_disjoint(jl_value_t *a, jl_value_t *b, int specificity)
322322
for(i=0; i < np; i++) {
323323
jl_value_t *ai = jl_tparam(ad,i);
324324
jl_value_t *bi = jl_tparam(bd,i);
325-
if (!istuple && specificity) {
325+
if (!istuple && specificity && jl_has_free_typevars(ai)) {
326326
// X{<:SomeDataType} and X{Union{Y,Z,...}} need to be disjoint to
327327
// avoid this transitivity problem:
328328
// A = Tuple{Type{LinearIndices{N,R}}, LinearIndices{N}} where {N,R}
@@ -2585,9 +2585,8 @@ static int tuple_morespecific(jl_datatype_t *cdt, jl_datatype_t *pdt, int invari
25852585
return 1;
25862586

25872587
int cms = type_morespecific_(ce, pe, invariant, env);
2588-
int eqv = !cms && eq_msp(ce, pe, env);
25892588

2590-
if (!cms && !eqv && !sub_msp(ce, pe, env)) {
2589+
if (!cms && !sub_msp(ce, pe, env)) {
25912590
/*
25922591
A bound vararg tuple can be more specific despite disjoint elements in order to
25932592
preserve transitivity. For example in
@@ -2599,6 +2598,8 @@ static int tuple_morespecific(jl_datatype_t *cdt, jl_datatype_t *pdt, int invari
25992598
return some_morespecific && cva && ckind == JL_VARARG_BOUND && num_occurs((jl_tvar_t*)jl_tparam1(jl_unwrap_unionall(clast)), env) > 1;
26002599
}
26012600

2601+
int eqv = !cms && eq_msp(ce, pe, env);
2602+
26022603
// Tuple{..., T} not more specific than Tuple{..., Vararg{S}} if S is diagonal
26032604
if (eqv && i == clen-1 && clen == plen && !cva && pva && jl_is_typevar(ce) && jl_is_typevar(pe) && !cdiag && pdiag)
26042605
return 0;
@@ -2692,24 +2693,23 @@ static int num_occurs(jl_tvar_t *v, jl_typeenv_t *env)
26922693
return 0;
26932694
}
26942695

2696+
#define HANDLE_UNIONALL_A \
2697+
jl_unionall_t *ua = (jl_unionall_t*)a; \
2698+
jl_typeenv_t newenv = { ua->var, 0x0, env }; \
2699+
newenv.val = (jl_value_t*)(intptr_t)count_occurs(ua->body, ua->var); \
2700+
return type_morespecific_(ua->body, b, invariant, &newenv)
2701+
2702+
#define HANDLE_UNIONALL_B \
2703+
jl_unionall_t *ub = (jl_unionall_t*)b; \
2704+
jl_typeenv_t newenv = { ub->var, 0x0, env }; \
2705+
newenv.val = (jl_value_t*)(intptr_t)count_occurs(ub->body, ub->var); \
2706+
return type_morespecific_(a, ub->body, invariant, &newenv)
2707+
26952708
static int type_morespecific_(jl_value_t *a, jl_value_t *b, int invariant, jl_typeenv_t *env)
26962709
{
26972710
if (a == b)
26982711
return 0;
26992712

2700-
if (jl_is_unionall(a)) {
2701-
jl_unionall_t *ua = (jl_unionall_t*)a;
2702-
jl_typeenv_t newenv = { ua->var, 0x0, env };
2703-
newenv.val = (jl_value_t*)(intptr_t)count_occurs(ua->body, ua->var);
2704-
return type_morespecific_(ua->body, b, invariant, &newenv);
2705-
}
2706-
if (jl_is_unionall(b)) {
2707-
jl_unionall_t *ub = (jl_unionall_t*)b;
2708-
jl_typeenv_t newenv = { ub->var, 0x0, env };
2709-
newenv.val = (jl_value_t*)(intptr_t)count_occurs(ub->body, ub->var);
2710-
return type_morespecific_(a, ub->body, invariant, &newenv);
2711-
}
2712-
27132713
if (jl_is_tuple_type(a) && jl_is_tuple_type(b)) {
27142714
// When one is JL_VARARG_BOUND and the other has fixed length,
27152715
// allow the argument length to fix the tvar
@@ -2728,6 +2728,9 @@ static int type_morespecific_(jl_value_t *a, jl_value_t *b, int invariant, jl_ty
27282728
}
27292729

27302730
if (jl_is_uniontype(a)) {
2731+
if (jl_is_unionall(b)) {
2732+
HANDLE_UNIONALL_B;
2733+
}
27312734
// Union a is more specific than b if some element of a is more specific than b, but
27322735
// not vice-versa.
27332736
if (sub_msp(b, a, env))
@@ -2764,6 +2767,9 @@ static int type_morespecific_(jl_value_t *a, jl_value_t *b, int invariant, jl_ty
27642767
}
27652768

27662769
if (jl_is_uniontype(b)) {
2770+
if (jl_is_unionall(a)) {
2771+
HANDLE_UNIONALL_A;
2772+
}
27672773
jl_uniontype_t *u = (jl_uniontype_t*)b;
27682774
if (type_morespecific_(a, u->a, invariant, env) || type_morespecific_(a, u->b, invariant, env))
27692775
return !type_morespecific_(b, a, invariant, env);
@@ -2772,7 +2778,7 @@ static int type_morespecific_(jl_value_t *a, jl_value_t *b, int invariant, jl_ty
27722778

27732779
if (!invariant) {
27742780
if ((jl_datatype_t*)a == jl_any_type) return 0;
2775-
if ((jl_datatype_t*)b == jl_any_type) return 1;
2781+
if ((jl_datatype_t*)b == jl_any_type && !jl_is_typevar(a)) return 1;
27762782
}
27772783

27782784
if (jl_is_datatype(a) && jl_is_datatype(b)) {
@@ -2796,13 +2802,20 @@ static int type_morespecific_(jl_value_t *a, jl_value_t *b, int invariant, jl_ty
27962802
for(size_t i=0; i < jl_nparams(tta); i++) {
27972803
jl_value_t *apara = jl_tparam(tta,i);
27982804
jl_value_t *bpara = jl_tparam(ttb,i);
2799-
if (!jl_has_free_typevars(apara) && !jl_has_free_typevars(bpara) &&
2800-
!jl_types_equal(apara, bpara))
2805+
int afree = jl_has_free_typevars(apara);
2806+
int bfree = jl_has_free_typevars(bpara);
2807+
if (!afree && !bfree && !jl_types_equal(apara, bpara))
28012808
return 0;
2802-
if (type_morespecific_(apara, bpara, 1, env))
2809+
if (type_morespecific_(apara, bpara, 1, env) && (jl_is_typevar(apara) || !afree || bfree))
28032810
ascore += 1;
2804-
else if (type_morespecific_(bpara, apara, 1, env))
2811+
else if (type_morespecific_(bpara, apara, 1, env) && (jl_is_typevar(bpara) || !bfree || afree))
28052812
bscore += 1;
2813+
else if (eq_msp(apara, bpara, env)) {
2814+
if (!afree && bfree)
2815+
ascore += 1;
2816+
else if (afree && !bfree)
2817+
bscore += 1;
2818+
}
28062819
if (jl_is_typevar(bpara) && !jl_is_typevar(apara) && !jl_is_type(apara))
28072820
ascore1 = 1;
28082821
else if (jl_is_typevar(apara) && !jl_is_typevar(bpara) && !jl_is_type(bpara))
@@ -2828,9 +2841,6 @@ static int type_morespecific_(jl_value_t *a, jl_value_t *b, int invariant, jl_ty
28282841
return 0;
28292842
return ascore > bscore || adiag > bdiag;
28302843
}
2831-
else if (invariant) {
2832-
return 0;
2833-
}
28342844
tta = tta->super; super = 1;
28352845
}
28362846
return 0;
@@ -2852,33 +2862,47 @@ static int type_morespecific_(jl_value_t *a, jl_value_t *b, int invariant, jl_ty
28522862
if (invariant) {
28532863
if (((jl_tvar_t*)a)->ub == jl_bottom_type)
28542864
return 1;
2855-
if (jl_has_free_typevars(b)) {
2856-
if (type_morespecific_(((jl_tvar_t*)a)->ub, b, 0, env) ||
2857-
eq_msp(((jl_tvar_t*)a)->ub, b, env))
2858-
return num_occurs((jl_tvar_t*)a, env) >= 2;
2859-
}
2860-
else {
2865+
if (eq_msp(((jl_tvar_t*)a)->ub, b, env))
2866+
return num_occurs((jl_tvar_t*)a, env) >= 2;
2867+
if (!jl_has_free_typevars(b))
28612868
return 0;
2862-
}
28632869
}
2864-
return type_morespecific_((jl_value_t*)((jl_tvar_t*)a)->ub, b, 0, env);
2870+
else {
2871+
// need `{T,T} where T` more specific than `{Any, Any}`
2872+
if (b == jl_any_type && ((jl_tvar_t*)a)->ub == jl_any_type && num_occurs((jl_tvar_t*)a, env) >= 2)
2873+
return 1;
2874+
}
2875+
return type_morespecific_(((jl_tvar_t*)a)->ub, b, 0, env);
28652876
}
28662877
if (jl_is_typevar(b)) {
28672878
if (!jl_is_type(a))
28682879
return 1;
28692880
if (invariant) {
28702881
if (((jl_tvar_t*)b)->ub == jl_bottom_type)
28712882
return 0;
2883+
if (eq_msp(a, ((jl_tvar_t*)b)->ub, env))
2884+
return num_occurs((jl_tvar_t*)b, env) < 2;
28722885
if (jl_has_free_typevars(a)) {
2873-
if (type_morespecific_(a, ((jl_tvar_t*)b)->ub, 0, env) ||
2874-
eq_msp(a, ((jl_tvar_t*)b)->ub, env))
2886+
if (type_morespecific_(a, ((jl_tvar_t*)b)->ub, 0, env))
28752887
return num_occurs((jl_tvar_t*)b, env) < 2;
2888+
return 0;
28762889
}
28772890
else {
2891+
if (obviously_disjoint(a, ((jl_tvar_t*)b)->ub, 1))
2892+
return 0;
2893+
if (type_morespecific_(((jl_tvar_t*)b)->ub, a, 0, env))
2894+
return 0;
28782895
return 1;
28792896
}
28802897
}
2881-
return type_morespecific_(a, (jl_value_t*)((jl_tvar_t*)b)->ub, 0, env);
2898+
return type_morespecific_(a, ((jl_tvar_t*)b)->ub, 0, env);
2899+
}
2900+
2901+
if (jl_is_unionall(a)) {
2902+
HANDLE_UNIONALL_A;
2903+
}
2904+
if (jl_is_unionall(b)) {
2905+
HANDLE_UNIONALL_B;
28822906
}
28832907

28842908
return 0;

test/specificity.jl

+59-4
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@ let
1616
@test !args_morespecific(b2, a)
1717
a = Tuple{Type{T1}, Ptr{T1}} where T1<:Integer
1818
b2 = Tuple{Type{T2}, Ptr{Integer}} where T2<:Integer
19-
@test !args_morespecific(a, b2)
20-
@test args_morespecific(b2, a)
19+
@test args_morespecific(a, b2)
20+
@test !args_morespecific(b2, a)
2121
end
2222

2323
# issue #11534
@@ -108,7 +108,7 @@ f17016(f, t::T_17016) = 0
108108
f17016(f, t1::Tuple) = 1
109109
@test f17016(0, (1,2,3)) == 0
110110

111-
@test args_morespecific(Tuple{Type{Any}, Any}, Tuple{Type{T}, Any} where T<:VecElement)
111+
@test !args_morespecific(Tuple{Type{Any}, Any}, Tuple{Type{T}, Any} where T<:VecElement)
112112
@test !args_morespecific((Tuple{Type{T}, Any} where T<:VecElement), Tuple{Type{Any}, Any})
113113

114114
@test !args_morespecific(Tuple{Type{T}, Tuple{Any, Vararg{Any, N} where N}} where T<:Tuple{Any, Vararg{Any, N} where N},
@@ -212,7 +212,7 @@ f27361(::M) where M <: Tuple{3} = nothing
212212
@test args_morespecific(Tuple{Core.TypeofBottom}, Tuple{DataType})
213213
@test args_morespecific(Tuple{Core.TypeofBottom}, Tuple{Type{<:Tuple}})
214214

215-
@test args_morespecific(Tuple{Type{Any}, Type}, Tuple{Type{T}, Type{T}} where T)
215+
@test args_morespecific(Tuple{Type{T}, Type{T}} where T, Tuple{Type{Any}, Type})
216216
@test !args_morespecific(Tuple{Type{Any}, Type}, Tuple{Type{T}, Type{T}} where T<:Union{})
217217

218218
# issue #22592
@@ -240,3 +240,58 @@ end
240240
@test args_morespecific(Tuple{Array,Int64}, Tuple{Array,Vararg{Int64,N}} where N)
241241
@test args_morespecific(Tuple{Array,Int64}, Tuple{Array,Vararg{Int64,N} where N})
242242
@test !args_morespecific(Tuple{Array,Int64}, Tuple{AbstractArray, Array})
243+
244+
# issue #30114
245+
let T1 = Tuple{Type{Tuple{Vararg{AbstractUnitRange{Int64},N} where N}},CartesianIndices{N,R} where R<:Tuple{Vararg{AbstractUnitRange{Int64},N}}} where N
246+
T2 = Tuple{Type{T},T} where T<:AbstractArray
247+
T3 = Tuple{Type{AbstractArray{T,N} where N},AbstractArray} where T
248+
T4 = Tuple{Type{AbstractArray{T,N}},AbstractArray{s57,N} where s57} where N where T
249+
@test !args_morespecific(T1, T2)
250+
@test !args_morespecific(T1, T3)
251+
@test !args_morespecific(T1, T4)
252+
@test args_morespecific(T2, T3)
253+
@test args_morespecific(T2, T4)
254+
end
255+
256+
@test !args_morespecific(Tuple{Type{Tuple{Vararg{AbstractUnitRange{Int64},N}}},} where N,
257+
Tuple{Type{Tuple{Vararg{AbstractUnitRange,N} where N}},})
258+
259+
@test args_morespecific(Tuple{Type{SubArray{T,2,P} where T}, Array{T}} where T where P,
260+
Tuple{Type{AbstractArray{T,N} where N},AbstractArray} where T)
261+
262+
@test args_morespecific(Tuple{Type{T},T} where T<:BitArray,
263+
Tuple{Type{BitArray},Any})
264+
265+
abstract type Domain{T} end
266+
267+
abstract type AbstractInterval{T} <: Domain{T} end
268+
269+
struct Interval{L,R,T} <: AbstractInterval{T}
270+
end
271+
272+
let A = Tuple{Type{Interval{:closed,:closed,T} where T}, Interval{:closed,:closed,T} where T},
273+
B = Tuple{Type{II}, AbstractInterval} where II<:(Interval{:closed,:closed,T} where T),
274+
C = Tuple{Type{AbstractInterval}, AbstractInterval}
275+
@test args_morespecific(A, B)
276+
@test !args_morespecific(B, C)
277+
@test !args_morespecific(A, C)
278+
end
279+
280+
let A = Tuple{Type{Domain}, Interval{L,R,T} where T} where R where L,
281+
B = Tuple{Type{II}, AbstractInterval} where II<:(Interval{:closed,:closed,T} where T),
282+
C = Tuple{Type{AbstractInterval{T}}, AbstractInterval{T}} where T
283+
@test !args_morespecific(A, B)
284+
@test args_morespecific(B, C)
285+
@test !args_morespecific(A, C)
286+
end
287+
288+
let A = Tuple{Type{AbstractInterval}, Interval{L,R,T} where T} where R where L,
289+
B = Tuple{Type{II}, AbstractInterval} where II<:(Interval{:closed,:closed,T} where T),
290+
C = Tuple{Type{AbstractInterval{T}}, AbstractInterval{T}} where T
291+
@test !args_morespecific(A, B)
292+
@test args_morespecific(B, C)
293+
@test args_morespecific(A, C)
294+
end
295+
296+
@test args_morespecific(Tuple{Type{Missing},Any},
297+
Tuple{Type{Union{Nothing, T}},Any} where T)

0 commit comments

Comments
 (0)