Skip to content

Commit 9612115

Browse files
NHDalynickrobinson251vtjnash
authored
Fix nospecializing Functions in Union{Nothing,Function} params (#59327)
Fixes #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 5acfa3b commit 9612115

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
@@ -1217,14 +1217,9 @@ static void jl_compilation_sig(
12171217
int notcalled_func = (i_arg > 0 && i_arg <= 8 && !(definition->called & (1 << (i_arg - 1))) &&
12181218
!jl_has_free_typevars(decl_i) &&
12191219
jl_subtype(elt, (jl_value_t*)jl_function_type));
1220-
if (notcalled_func && (type_i == (jl_value_t*)jl_any_type ||
1221-
type_i == (jl_value_t*)jl_function_type ||
1222-
(jl_is_uniontype(type_i) && // Base.Callable
1223-
((((jl_uniontype_t*)type_i)->a == (jl_value_t*)jl_function_type &&
1224-
((jl_uniontype_t*)type_i)->b == (jl_value_t*)jl_type_type) ||
1225-
(((jl_uniontype_t*)type_i)->b == (jl_value_t*)jl_function_type &&
1226-
((jl_uniontype_t*)type_i)->a == (jl_value_t*)jl_type_type))))) {
1227-
// and attempt to despecialize types marked Function, Callable, or Any
1220+
if (notcalled_func && (jl_subtype((jl_value_t*)jl_function_type, type_i))) {
1221+
// and attempt to despecialize types marked as a supertype of Function (i.e.
1222+
// Function, Callable, Any, or a Union{Function, T})
12281223
// when called with a subtype of Function but is not called
12291224
if (!*newparams) *newparams = jl_svec_copy(tt->parameters);
12301225
jl_svecset(*newparams, i, (jl_value_t*)jl_function_type);
@@ -1450,15 +1445,9 @@ JL_DLLEXPORT int jl_isa_compileable_sig(
14501445
int notcalled_func = (i_arg > 0 && i_arg <= 8 && !(definition->called & (1 << (i_arg - 1))) &&
14511446
!jl_has_free_typevars(decl_i) &&
14521447
jl_subtype(elt, (jl_value_t*)jl_function_type));
1453-
if (notcalled_func && (type_i == (jl_value_t*)jl_any_type ||
1454-
type_i == (jl_value_t*)jl_function_type ||
1455-
(jl_is_uniontype(type_i) && // Base.Callable
1456-
((((jl_uniontype_t*)type_i)->a == (jl_value_t*)jl_function_type &&
1457-
((jl_uniontype_t*)type_i)->b == (jl_value_t*)jl_type_type) ||
1458-
(((jl_uniontype_t*)type_i)->b == (jl_value_t*)jl_function_type &&
1459-
((jl_uniontype_t*)type_i)->a == (jl_value_t*)jl_type_type))))) {
1460-
// and attempt to despecialize types marked Function, Callable, or Any
1461-
// when called with a subtype of Function but is not called
1448+
if (notcalled_func && jl_subtype((jl_value_t*)jl_function_type, type_i)) {
1449+
// and attempt to despecialize types marked as a supertype of Function (i.e.
1450+
// Function, Callable, Any, or a Union{Function, T})
14621451
if (elt == (jl_value_t*)jl_function_type)
14631452
continue;
14641453
JL_GC_POP();

test/core.jl

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

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

247303
# issue #20511
248304
f20511(x::DataType) = 0

0 commit comments

Comments
 (0)