Skip to content

Commit 6594acc

Browse files
authored
fix #30114, specificity transitivity errors in convert methods (#30160)
1 parent 49c4e09 commit 6594acc

File tree

4 files changed

+125
-39
lines changed

4 files changed

+125
-39
lines changed

NEWS.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,10 @@ Language changes
2020
to the `Core` module ([#29968]).
2121
* Using the same name for both a local variable and a static parameter is now an error instead
2222
of a warning ([#29429]).
23+
* Method signatures such as
24+
`f(::Type{T}, ::T) where {T <: X}` and
25+
`f(::Type{X}, ::Any)`
26+
are now considered ambiguous. Previously a bug caused the first one to be considered more specific ([#30160]).
2327

2428
Command-line option changes
2529
---------------------------

base/bitarray.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -504,6 +504,7 @@ reinterpret(B::BitArray, dims::NTuple{N,Int}) where {N} = reshape(B, dims)
504504

505505
if nameof(@__MODULE__) === :Base # avoid method overwrite
506506
(::Type{T})(x::T) where {T<:BitArray} = copy(x)
507+
BitArray(x::BitArray) = copy(x)
507508
end
508509

509510
"""

src/subtype.c

Lines changed: 61 additions & 38 deletions
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
@@ -2600,7 +2599,8 @@ static int tuple_morespecific(jl_datatype_t *cdt, jl_datatype_t *pdt, int invari
26002599
}
26012600

26022601
// Tuple{..., T} not more specific than Tuple{..., Vararg{S}} if S is diagonal
2603-
if (eqv && i == clen-1 && clen == plen && !cva && pva && jl_is_typevar(ce) && jl_is_typevar(pe) && !cdiag && pdiag)
2602+
if (!cms && i == clen-1 && clen == plen && !cva && pva && eq_msp(ce, pe, env) &&
2603+
jl_is_typevar(ce) && jl_is_typevar(pe) && !cdiag && pdiag)
26042604
return 0;
26052605

26062606
if (cms) some_morespecific = 1;
@@ -2692,24 +2692,23 @@ static int num_occurs(jl_tvar_t *v, jl_typeenv_t *env)
26922692
return 0;
26932693
}
26942694

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

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-
27132712
if (jl_is_tuple_type(a) && jl_is_tuple_type(b)) {
27142713
// When one is JL_VARARG_BOUND and the other has fixed length,
27152714
// allow the argument length to fix the tvar
@@ -2727,7 +2726,15 @@ static int type_morespecific_(jl_value_t *a, jl_value_t *b, int invariant, jl_ty
27272726
return tuple_morespecific((jl_datatype_t*)a, (jl_datatype_t*)b, invariant, env);
27282727
}
27292728

2729+
if (!invariant) {
2730+
if ((jl_datatype_t*)a == jl_any_type) return 0;
2731+
if ((jl_datatype_t*)b == jl_any_type && !jl_is_typevar(a)) return 1;
2732+
}
2733+
27302734
if (jl_is_uniontype(a)) {
2735+
if (jl_is_unionall(b)) {
2736+
HANDLE_UNIONALL_B;
2737+
}
27312738
// Union a is more specific than b if some element of a is more specific than b, but
27322739
// not vice-versa.
27332740
if (sub_msp(b, a, env))
@@ -2764,17 +2771,15 @@ static int type_morespecific_(jl_value_t *a, jl_value_t *b, int invariant, jl_ty
27642771
}
27652772

27662773
if (jl_is_uniontype(b)) {
2774+
if (jl_is_unionall(a)) {
2775+
HANDLE_UNIONALL_A;
2776+
}
27672777
jl_uniontype_t *u = (jl_uniontype_t*)b;
27682778
if (type_morespecific_(a, u->a, invariant, env) || type_morespecific_(a, u->b, invariant, env))
27692779
return !type_morespecific_(b, a, invariant, env);
27702780
return 0;
27712781
}
27722782

2773-
if (!invariant) {
2774-
if ((jl_datatype_t*)a == jl_any_type) return 0;
2775-
if ((jl_datatype_t*)b == jl_any_type) return 1;
2776-
}
2777-
27782783
if (jl_is_datatype(a) && jl_is_datatype(b)) {
27792784
jl_datatype_t *tta = (jl_datatype_t*)a, *ttb = (jl_datatype_t*)b;
27802785
// Type{Union{}} is more specific than other types, so TypeofBottom must be too
@@ -2796,13 +2801,20 @@ static int type_morespecific_(jl_value_t *a, jl_value_t *b, int invariant, jl_ty
27962801
for(size_t i=0; i < jl_nparams(tta); i++) {
27972802
jl_value_t *apara = jl_tparam(tta,i);
27982803
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))
2804+
int afree = jl_has_free_typevars(apara);
2805+
int bfree = jl_has_free_typevars(bpara);
2806+
if (!afree && !bfree && !jl_types_equal(apara, bpara))
28012807
return 0;
2802-
if (type_morespecific_(apara, bpara, 1, env))
2808+
if (type_morespecific_(apara, bpara, 1, env) && (jl_is_typevar(apara) || !afree || bfree))
28032809
ascore += 1;
2804-
else if (type_morespecific_(bpara, apara, 1, env))
2810+
else if (type_morespecific_(bpara, apara, 1, env) && (jl_is_typevar(bpara) || !bfree || afree))
28052811
bscore += 1;
2812+
else if (eq_msp(apara, bpara, env)) {
2813+
if (!afree && bfree)
2814+
ascore += 1;
2815+
else if (afree && !bfree)
2816+
bscore += 1;
2817+
}
28062818
if (jl_is_typevar(bpara) && !jl_is_typevar(apara) && !jl_is_type(apara))
28072819
ascore1 = 1;
28082820
else if (jl_is_typevar(apara) && !jl_is_typevar(bpara) && !jl_is_type(bpara))
@@ -2828,9 +2840,6 @@ static int type_morespecific_(jl_value_t *a, jl_value_t *b, int invariant, jl_ty
28282840
return 0;
28292841
return ascore > bscore || adiag > bdiag;
28302842
}
2831-
else if (invariant) {
2832-
return 0;
2833-
}
28342843
tta = tta->super; super = 1;
28352844
}
28362845
return 0;
@@ -2852,16 +2861,18 @@ static int type_morespecific_(jl_value_t *a, jl_value_t *b, int invariant, jl_ty
28522861
if (invariant) {
28532862
if (((jl_tvar_t*)a)->ub == jl_bottom_type)
28542863
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 {
2864+
if (!jl_has_free_typevars(b))
28612865
return 0;
2862-
}
2866+
if (eq_msp(((jl_tvar_t*)a)->ub, b, env))
2867+
return num_occurs((jl_tvar_t*)a, env) >= 2;
2868+
}
2869+
else {
2870+
// need `{T,T} where T` more specific than `{Any, Any}`
2871+
if (b == (jl_value_t*)jl_any_type && ((jl_tvar_t*)a)->ub == (jl_value_t*)jl_any_type &&
2872+
num_occurs((jl_tvar_t*)a, env) >= 2)
2873+
return 1;
28632874
}
2864-
return type_morespecific_((jl_value_t*)((jl_tvar_t*)a)->ub, b, 0, env);
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))
@@ -2873,12 +2884,24 @@ static int type_morespecific_(jl_value_t *a, jl_value_t *b, int invariant, jl_ty
28732884
if (type_morespecific_(a, ((jl_tvar_t*)b)->ub, 0, env) ||
28742885
eq_msp(a, ((jl_tvar_t*)b)->ub, env))
28752886
return num_occurs((jl_tvar_t*)b, env) < 2;
2887+
return 0;
28762888
}
28772889
else {
2890+
if (obviously_disjoint(a, ((jl_tvar_t*)b)->ub, 1))
2891+
return 0;
2892+
if (type_morespecific_(((jl_tvar_t*)b)->ub, a, 0, env))
2893+
return 0;
28782894
return 1;
28792895
}
28802896
}
2881-
return type_morespecific_(a, (jl_value_t*)((jl_tvar_t*)b)->ub, 0, env);
2897+
return type_morespecific_(a, ((jl_tvar_t*)b)->ub, 0, env);
2898+
}
2899+
2900+
if (jl_is_unionall(a)) {
2901+
HANDLE_UNIONALL_A;
2902+
}
2903+
if (jl_is_unionall(b)) {
2904+
HANDLE_UNIONALL_B;
28822905
}
28832906

28842907
return 0;

test/specificity.jl

Lines changed: 59 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -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},
@@ -240,3 +240,61 @@ 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+
# these are ambiguous
263+
@test !args_morespecific(Tuple{Type{T},T} where T<:BitArray,
264+
Tuple{Type{BitArray},Any})
265+
@test !args_morespecific(Tuple{Type{BitArray},Any},
266+
Tuple{Type{T},T} where T<:BitArray)
267+
268+
abstract type Domain{T} end
269+
270+
abstract type AbstractInterval{T} <: Domain{T} end
271+
272+
struct Interval{L,R,T} <: AbstractInterval{T}
273+
end
274+
275+
let A = Tuple{Type{Interval{:closed,:closed,T} where T}, Interval{:closed,:closed,T} where T},
276+
B = Tuple{Type{II}, AbstractInterval} where II<:(Interval{:closed,:closed,T} where T),
277+
C = Tuple{Type{AbstractInterval}, AbstractInterval}
278+
@test args_morespecific(A, B)
279+
@test !args_morespecific(B, C)
280+
@test !args_morespecific(A, C)
281+
end
282+
283+
let A = Tuple{Type{Domain}, Interval{L,R,T} where T} where R where L,
284+
B = Tuple{Type{II}, AbstractInterval} where II<:(Interval{:closed,:closed,T} where T),
285+
C = Tuple{Type{AbstractInterval{T}}, AbstractInterval{T}} where T
286+
@test !args_morespecific(A, B)
287+
@test args_morespecific(B, C)
288+
@test !args_morespecific(A, C)
289+
end
290+
291+
let A = Tuple{Type{AbstractInterval}, Interval{L,R,T} where T} where R where L,
292+
B = Tuple{Type{II}, AbstractInterval} where II<:(Interval{:closed,:closed,T} where T),
293+
C = Tuple{Type{AbstractInterval{T}}, AbstractInterval{T}} where T
294+
@test !args_morespecific(A, B)
295+
@test args_morespecific(B, C)
296+
@test args_morespecific(A, C)
297+
end
298+
299+
@test args_morespecific(Tuple{Type{Missing},Any},
300+
Tuple{Type{Union{Nothing, T}},Any} where T)

0 commit comments

Comments
 (0)