Skip to content

Commit 061a139

Browse files
NHDalynickrobinson251vtjnash
authored
Fix nospecializing Functions in Union{Nothing,Function} params (JuliaLang#59327) (#251)
Fixes JuliaLang#59326. Change the logic that decides not to specialize a function parameter based on whether or not the supplied argument is a Function, and that function is not used, so that it will still work if the SpecType is a Union{Function,Nothing} or any other union that contains a Function. The logic is changed from a hardcoded rule of `type_i == Function || type_i == Any || type_i == Base.Callable` to `type_i >: Function`. This covers all of the above cases, but also includes custom `Union{Function, T}` such as `Union{Function, Nothing}`. --------- Co-authored-by: Nick Robinson <[email protected]> Co-authored-by: Jameson Nash <[email protected]>
1 parent 0bd16ac commit 061a139

File tree

2 files changed

+62
-17
lines changed

2 files changed

+62
-17
lines changed

src/gf.c

Lines changed: 6 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -938,14 +938,9 @@ static void jl_compilation_sig(
938938
int notcalled_func = (i_arg > 0 && i_arg <= 8 && !(definition->called & (1 << (i_arg - 1))) &&
939939
!jl_has_free_typevars(decl_i) &&
940940
jl_subtype(elt, (jl_value_t*)jl_function_type));
941-
if (notcalled_func && (type_i == (jl_value_t*)jl_any_type ||
942-
type_i == (jl_value_t*)jl_function_type ||
943-
(jl_is_uniontype(type_i) && // Base.Callable
944-
((((jl_uniontype_t*)type_i)->a == (jl_value_t*)jl_function_type &&
945-
((jl_uniontype_t*)type_i)->b == (jl_value_t*)jl_type_type) ||
946-
(((jl_uniontype_t*)type_i)->b == (jl_value_t*)jl_function_type &&
947-
((jl_uniontype_t*)type_i)->a == (jl_value_t*)jl_type_type))))) {
948-
// and attempt to despecialize types marked Function, Callable, or Any
941+
if (notcalled_func && (jl_subtype((jl_value_t*)jl_function_type, type_i))) {
942+
// and attempt to despecialize types marked as a supertype of Function (i.e.
943+
// Function, Callable, Any, or a Union{Function, T})
949944
// when called with a subtype of Function but is not called
950945
if (!*newparams) *newparams = jl_svec_copy(tt->parameters);
951946
jl_svecset(*newparams, i, (jl_value_t*)jl_function_type);
@@ -1174,15 +1169,9 @@ JL_DLLEXPORT int jl_isa_compileable_sig(
11741169
int notcalled_func = (i_arg > 0 && i_arg <= 8 && !(definition->called & (1 << (i_arg - 1))) &&
11751170
!jl_has_free_typevars(decl_i) &&
11761171
jl_subtype(elt, (jl_value_t*)jl_function_type));
1177-
if (notcalled_func && (type_i == (jl_value_t*)jl_any_type ||
1178-
type_i == (jl_value_t*)jl_function_type ||
1179-
(jl_is_uniontype(type_i) && // Base.Callable
1180-
((((jl_uniontype_t*)type_i)->a == (jl_value_t*)jl_function_type &&
1181-
((jl_uniontype_t*)type_i)->b == (jl_value_t*)jl_type_type) ||
1182-
(((jl_uniontype_t*)type_i)->b == (jl_value_t*)jl_function_type &&
1183-
((jl_uniontype_t*)type_i)->a == (jl_value_t*)jl_type_type))))) {
1184-
// and attempt to despecialize types marked Function, Callable, or Any
1185-
// when called with a subtype of Function but is not called
1172+
if (notcalled_func && jl_subtype((jl_value_t*)jl_function_type, type_i)) {
1173+
// and attempt to despecialize types marked as a supertype of Function (i.e.
1174+
// Function, Callable, Any, or a Union{Function, T})
11861175
if (elt == (jl_value_t*)jl_function_type)
11871176
continue;
11881177
JL_GC_POP();

test/core.jl

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -233,6 +233,62 @@ k11840(::Type{Union{Tuple{Int32}, Tuple{Int64}}}) = '2'
233233
@test k11840(Tuple{Union{Int32, Int64}}) == '2'
234234
@test k11840(Union{Tuple{Int32}, Tuple{Int64}}) == '2'
235235

236+
# issue #59327
237+
@noinline f59327(f, x) = Any[f, x]
238+
g59327(x) = f59327(+, Any[x][1])
239+
g59327(1)
240+
@test any(
241+
mi->mi isa Core.MethodInstance && mi.specTypes == Tuple{typeof(f59327), Function, Int},
242+
methods(f59327)[1].specializations)
243+
244+
@noinline h59327(f::Union{Function, Nothing}, x) = Any[f, x]
245+
i59327(x) = h59327(+, Any[x][1])
246+
i59327(1)
247+
@test any(
248+
mi->mi isa Core.MethodInstance && mi.specTypes == Tuple{typeof(h59327), Function, Int},
249+
methods(h59327)[1].specializations)
250+
251+
@noinline j59327(f::Function, x) = Any[f, x]
252+
k59327(x) = j59327(+, Any[x][1])
253+
k59327(1)
254+
@test any(
255+
mi->mi isa Core.MethodInstance && mi.specTypes == Tuple{typeof(j59327), Function, Int},
256+
methods(j59327)[1].specializations
257+
)
258+
259+
@noinline l59327(f::Base.Callable, x) = Any[f, x]
260+
m59327(x) = l59327(+, Any[x][1])
261+
m59327(1)
262+
@test any(
263+
mi->mi isa Core.MethodInstance && mi.specTypes == Tuple{typeof(l59327), Function, Int},
264+
methods(l59327)[1].specializations
265+
)
266+
267+
# _do_ specialize if the signature has a `where`
268+
@noinline n59327(f::F, x) where F = Any[f, x]
269+
o59327(x) = n59327(+, Any[x][1])
270+
o59327(1)
271+
@test !any(
272+
mi->mi isa Core.MethodInstance && mi.specTypes == Tuple{typeof(n59327), Function, Int},
273+
methods(n59327)[1].specializations
274+
)
275+
@test any(
276+
mi->mi isa Core.MethodInstance && mi.specTypes == Tuple{typeof(n59327), typeof(+), Int},
277+
methods(n59327)[1].specializations
278+
)
279+
280+
# _do_ specialize if the signature is specific
281+
@noinline n59327(f::typeof(+), x) = Any[f, x]
282+
o59327(x) = n59327(+, Any[x][1])
283+
o59327(1)
284+
@test !any(
285+
mi->mi isa Core.MethodInstance && mi.specTypes == Tuple{typeof(n59327), Function, Int},
286+
methods(n59327)[1].specializations
287+
)
288+
@test any(
289+
mi->mi isa Core.MethodInstance && mi.specTypes == Tuple{typeof(n59327), typeof(+), Int},
290+
methods(n59327)[1].specializations
291+
)
236292

237293
# issue #20511
238294
f20511(x::DataType) = 0

0 commit comments

Comments
 (0)