Skip to content

Commit c4565ae

Browse files
committed
Rename dispatchtuple to indivisible_type
This is hopefully a more intuitive (type-semantic) notion of what a "dispatch tuple" is. Ideally, it makes two key properties more obvious: 1. indivisible types are either type-equal or disjoint with each other (T == U or T != U) - they are never partially overlapping 2. these signatures are always compilable since they are "maximally specific" This new definition should be mostly equivalent to the existing one for Tuples, and it extends the predicate to be be analogously defined over other DataTypes (e.g. `Int` / `Vector{Any}`, which are also indivisible)
1 parent 748775b commit c4565ae

17 files changed

+111
-61
lines changed

Compiler/src/abstractinterpretation.jl

+1-1
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,7 @@ function abstract_call_gf_by_type(interp::AbstractInterpreter, @nospecialize(fun
129129
local napplicable = length(applicable)
130130
for i = 1:napplicable
131131
local sig = applicable[i].match.spec_types
132-
if !isdispatchtuple(sig)
132+
if !isindivisibletype(sig)
133133
# only infer fully concrete call sites in top-level expressions (ignoring even isa_compileable_sig matches)
134134
add_remark!(interp, sv, "Refusing to infer non-concrete call site in top-level expression")
135135
return Future(CallMeta(Any, Any, Effects(), NoCallInfo()))

Compiler/src/ssair/inlining.jl

+2-2
Original file line numberDiff line numberDiff line change
@@ -1394,8 +1394,8 @@ function compute_inlining_cases(@nospecialize(info::CallInfo), flag::UInt32, sig
13941394
# We will emit an inline MethodError in this case, but that info already came inference, so we must already have the uncovered edge for it
13951395
end
13961396
elseif !isempty(cases)
1397-
# if we've not seen all candidates, union split is valid only for dispatch tuples
1398-
filter!(case::InliningCase->isdispatchtuple(case.sig), cases)
1397+
# if we've not seen all candidates, union split is valid only for indivisible (dispatch) tuples
1398+
filter!(case::InliningCase->isindivisibletype(case.sig), cases)
13991399
end
14001400
return cases, handled_all_cases, fully_covered, joint_effects
14011401
end

Compiler/src/typeinfer.jl

+1-1
Original file line numberDiff line numberDiff line change
@@ -361,7 +361,7 @@ function inline_cost_model(interp::AbstractInterpreter, result::InferenceResult,
361361
return MAX_INLINE_COST
362362
end
363363

364-
if declared_inline && isdispatchtuple(specTypes)
364+
if declared_inline && isindivisibletype(specTypes)
365365
# obey @inline declaration if a dispatch barrier would not help
366366
return MIN_INLINE_COST
367367
else

Compiler/test/inline.jl

+8-8
Original file line numberDiff line numberDiff line change
@@ -816,27 +816,27 @@ let src = code_typed((Union{Tuple{Int,Int,Int}, Vector{Int}},)) do xs
816816
@test count(isinvoke(:g42840), src.code) == 1
817817
end
818818

819-
# test single, non-dispatchtuple callsite inlining
819+
# test single, divisible (non-dispatchtuple) callsite inlining
820820

821-
@constprop :none @inline test_single_nondispatchtuple(@nospecialize(t)) =
821+
@constprop :none @inline test_single_divisible_type(@nospecialize(t)) =
822822
isa(t, DataType) && t.name === Type.body.name
823823
let
824824
src = code_typed1((Any,)) do x
825-
test_single_nondispatchtuple(x)
825+
test_single_divisible_type(x)
826826
end
827827
@test all(src.code) do @nospecialize x
828-
!(isinvoke(:test_single_nondispatchtuple, x) || iscall((src, test_single_nondispatchtuple), x))
828+
!(isinvoke(:test_single_divisible_type, x) || iscall((src, test_single_divisible_type), x))
829829
end
830830
end
831831

832-
@constprop :aggressive @inline test_single_nondispatchtuple(c, @nospecialize(t)) =
832+
@constprop :aggressive @inline test_single_divisible_type(c, @nospecialize(t)) =
833833
c && isa(t, DataType) && t.name === Type.body.name
834834
let
835835
src = code_typed1((Any,)) do x
836-
test_single_nondispatchtuple(true, x)
836+
test_single_divisible_type(true, x)
837837
end
838838
@test all(src.code) do @nospecialize(x)
839-
!(isinvoke(:test_single_nondispatchtuple, x) || iscall((src, test_single_nondispatchtuple), x))
839+
!(isinvoke(:test_single_divisible_type, x) || iscall((src, test_single_divisible_type), x))
840840
end
841841
end
842842

@@ -856,7 +856,7 @@ let
856856
@test invoke(Any[10]) === false
857857
end
858858

859-
# test union-split, non-dispatchtuple callsite inlining
859+
# test union-split, divisible (non-dispatchtuple) callsite inlining
860860

861861
@constprop :none @noinline abstract_unionsplit(@nospecialize x::Any) = Base.inferencebarrier(:Any)
862862
@constprop :none @noinline abstract_unionsplit(@nospecialize x::Number) = Base.inferencebarrier(:Number)

base/exports.jl

+1-1
Original file line numberDiff line numberDiff line change
@@ -818,7 +818,7 @@ export
818818
isprimitivetype,
819819
isstructtype,
820820
isconcretetype,
821-
isdispatchtuple,
821+
isindivisibletype,
822822
oftype,
823823
promote,
824824
promote_rule,

base/runtime_internals.jl

+14-3
Original file line numberDiff line numberDiff line change
@@ -856,7 +856,18 @@ meaning it could appear as a type signature in dispatch
856856
and has no subtypes (or supertypes) which could appear in a call.
857857
If `T` is not a type, then return `false`.
858858
"""
859-
isdispatchtuple(@nospecialize(t)) = (@_total_meta; isa(t, DataType) && (t.flags & 0x0004) == 0x0004)
859+
isdispatchtuple(@nospecialize(t)) = (@_total_meta; isa(t, DataType) && t.name === Tuple.name && (t.flags & 0x0004) == 0x0004)
860+
861+
"""
862+
isindivisibletype(T)
863+
864+
Determine whether type `T` is an indivisible type, meaning that `T′ <: T`
865+
implies `T′ == T` for any inhabited T′. This is a conservative under-
866+
approximation, so it may sometimes return `false` even when T is indivisible.
867+
868+
If `T` is not a type, then return `false`.
869+
"""
870+
isindivisibletype(@nospecialize(t)) = (@_total_meta; isa(t, DataType) && (t.flags & 0x0004) == 0x0004)
860871

861872
datatype_ismutationfree(dt::DataType) = (@_total_meta; (dt.flags & 0x0100) == 0x0100)
862873

@@ -905,7 +916,7 @@ isconcretedispatch(@nospecialize t) = isconcretetype(t) && !iskindtype(t)
905916

906917
using Core: has_free_typevars
907918

908-
# equivalent to isa(v, Type) && isdispatchtuple(Tuple{v}) || v === Union{}
919+
# equivalent to isa(v, Type) && isindivisibletype(Tuple{v}) || v === Union{}
909920
# and is thus perhaps most similar to the old (pre-1.0) `isconcretetype` query
910921
function isdispatchelem(@nospecialize v)
911922
return (v === Bottom) || (v === typeof(Bottom)) || isconcretedispatch(v) ||
@@ -1521,7 +1532,7 @@ function may_invoke_generator(mi::MethodInstance)
15211532
end
15221533
function may_invoke_generator(method::Method, @nospecialize(atype), sparams::SimpleVector)
15231534
# If we have complete information, we may always call the generator
1524-
isdispatchtuple(atype) && return true
1535+
isindivisibletype(atype) && return true
15251536

15261537
# We don't have complete information, but it is possible that the generator
15271538
# syntactically doesn't make use of the information we don't have. Check

base/staticdata.jl

+1-1
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ get_require_world() = unsafe_load(cglobal(:jl_require_world, UInt))
7575

7676
function gen_staged_sig(def::Method, mi::MethodInstance)
7777
isdefined(def, :generator) || return nothing
78-
isdispatchtuple(mi.specTypes) || return nothing
78+
isindivisibletype(mi.specTypes) || return nothing
7979
gen = Core.Typeof(def.generator)
8080
return Tuple{gen, UInt, Method, Vararg}
8181
## more precise method lookup, but more costly and likely not actually better?

doc/src/base/base.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -191,7 +191,7 @@ Base.typeintersect
191191
Base.promote_type
192192
Base.promote_rule
193193
Base.promote_typejoin
194-
Base.isdispatchtuple
194+
Base.isindivisibletype
195195
```
196196

197197
### Declared structure

src/datatype.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ jl_datatype_t *jl_new_uninitialized_datatype(void)
100100
jl_set_typetagof(t, jl_datatype_tag, 0);
101101
t->hash = 0;
102102
t->hasfreetypevars = 0;
103-
t->isdispatchtuple = 0;
103+
t->isindivisibletype = 0;
104104
t->isbitstype = 0;
105105
t->isprimitivetype = 0;
106106
t->zeroinit = 0;

src/gf.c

+15-15
Original file line numberDiff line numberDiff line change
@@ -1014,7 +1014,7 @@ static void jl_compilation_sig(
10141014
}
10151015
}
10161016
else if (jl_is_kind(elt)) {
1017-
// not triggered for isdispatchtuple(tt), this attempts to handle
1017+
// not triggered for isindivisibletype(tt), this attempts to handle
10181018
// some cases of adapting a random signature into a compilation signature
10191019
// if we get a kind, where we don't expect to accept one, widen it to something more expected (Type{T})
10201020
if (!(jl_subtype(elt, type_i) && !jl_subtype((jl_value_t*)jl_type_type, type_i))) {
@@ -1044,11 +1044,11 @@ static void jl_compilation_sig(
10441044
}
10451045

10461046
if (jl_types_equal(elt, (jl_value_t*)jl_type_type)) { // elt == Type{T} where T
1047-
// not triggered for isdispatchtuple(tt), this attempts to handle
1047+
// not triggered for isindivisibletype(tt), this attempts to handle
10481048
// some cases of adapting a random signature into a compilation signature
10491049
}
10501050
else if (!jl_is_datatype(elt) && jl_subtype(elt, (jl_value_t*)jl_type_type)) { // elt <: Type{T}
1051-
// not triggered for isdispatchtuple(tt), this attempts to handle
1051+
// not triggered for isindivisibletype(tt), this attempts to handle
10521052
// some cases of adapting a random signature into a compilation signature
10531053
if (!*newparams) *newparams = jl_svec_copy(tt->parameters);
10541054
jl_svecset(*newparams, i, jl_type_type);
@@ -1197,7 +1197,7 @@ JL_DLLEXPORT int jl_isa_compileable_sig(
11971197
if (definition->generator) {
11981198
// staged functions aren't optimized
11991199
// so assume the caller was intelligent about calling us
1200-
return (definition->isva ? np >= nargs - 1 : np == nargs) && type->isdispatchtuple;
1200+
return (definition->isva ? np >= nargs - 1 : np == nargs) && type->isindivisibletype;
12011201
}
12021202

12031203
// for varargs methods, only specialize up to max_args (>= nargs + 1).
@@ -1636,9 +1636,9 @@ static jl_method_instance_t *jl_mt_assoc_by_type(jl_methtable_t *mt JL_PROPAGATE
16361636
jl_method_match_t *matc = NULL;
16371637
JL_GC_PUSH2(&tt, &matc);
16381638
JL_LOCK(&mt->writelock);
1639-
assert(tt->isdispatchtuple || tt->hasfreetypevars);
1639+
assert(tt->isindivisibletype || tt->hasfreetypevars);
16401640
jl_method_instance_t *mi = NULL;
1641-
if (tt->isdispatchtuple) {
1641+
if (tt->isindivisibletype) {
16421642
jl_genericmemory_t *leafcache = jl_atomic_load_relaxed(&mt->leafcache);
16431643
jl_typemap_entry_t *entry = lookup_leafcache(leafcache, (jl_value_t*)tt, world);
16441644
if (entry)
@@ -3132,7 +3132,7 @@ JL_DLLEXPORT jl_value_t *jl_normalize_to_compilable_sig(jl_methtable_t *mt, jl_t
31323132
jl_methtable_t *kwmt = mt == jl_kwcall_mt ? jl_kwmethod_table_for(m->sig) : mt;
31333133
intptr_t max_varargs = get_max_varargs(m, kwmt, mt, NULL);
31343134
jl_compilation_sig(ti, env, m, max_varargs, &newparams);
3135-
int is_compileable = ((jl_datatype_t*)ti)->isdispatchtuple;
3135+
int is_compileable = ((jl_datatype_t*)ti)->isindivisibletype;
31363136
if (newparams) {
31373137
tt = (jl_datatype_t*)jl_apply_tuple_type(newparams, 1);
31383138
if (!is_compileable) {
@@ -3184,7 +3184,7 @@ JL_DLLEXPORT jl_method_instance_t *jl_method_match_to_mi(jl_method_match_t *matc
31843184
assert(mt != NULL);
31853185
if ((jl_value_t*)mt != jl_nothing) {
31863186
// get the specialization, possibly also caching it
3187-
if (mt_cache && ((jl_datatype_t*)ti)->isdispatchtuple) {
3187+
if (mt_cache && ((jl_datatype_t*)ti)->isindivisibletype) {
31883188
// Since we also use this presence in the cache
31893189
// to trigger compilation when producing `.ji` files,
31903190
// inject it there now if we think it will be
@@ -3334,7 +3334,7 @@ JL_DLLEXPORT void jl_compile_method_instance(jl_method_instance_t *mi, jl_tuplet
33343334
// In addition to full compilation of the compilation-signature, if `types` is more specific (e.g. due to nospecialize),
33353335
// also run inference now on the original `types`, since that may help us guide inference to find
33363336
// additional useful methods that should be compiled
3337-
//ALT: if (jl_is_datatype(types) && ((jl_datatype_t*)types)->isdispatchtuple && !jl_egal(mi->specTypes, types))
3337+
//ALT: if (jl_is_datatype(types) && ((jl_datatype_t*)types)->isindivisibletype && !jl_egal(mi->specTypes, types))
33383338
//ALT: if (jl_subtype(types, mi->specTypes))
33393339
if (types && !jl_subtype(mi->specTypes, (jl_value_t*)types)) {
33403340
jl_svec_t *tpenv2 = jl_emptysvec;
@@ -3882,7 +3882,7 @@ static int ml_matches_visitor(jl_typemap_entry_t *ml, struct typemap_intersectio
38823882
return 1;
38833883
}
38843884
jl_method_t *meth = ml->func.method;
3885-
if (closure->lim >= 0 && jl_is_dispatch_tupletype(meth->sig)) {
3885+
if (closure->lim >= 0 && jl_is_indivisible_type(meth->sig)) {
38863886
int replaced = 0;
38873887
// check if this is replaced, in which case we need to avoid double-counting it against the limit
38883888
// (although it will figure out later which one to keep and return)
@@ -4233,7 +4233,7 @@ static jl_value_t *ml_matches(jl_methtable_t *mt,
42334233

42344234
if (mt) {
42354235
// check the leaf cache if this type can be in there
4236-
if (((jl_datatype_t*)unw)->isdispatchtuple) {
4236+
if (((jl_datatype_t*)unw)->isindivisibletype) {
42374237
jl_genericmemory_t *leafcache = jl_atomic_load_relaxed(&mt->leafcache);
42384238
jl_typemap_entry_t *entry = lookup_leafcache(leafcache, (jl_value_t*)type, world);
42394239
if (entry) {
@@ -4266,12 +4266,12 @@ static jl_value_t *ml_matches(jl_methtable_t *mt,
42664266
}
42674267
}
42684268
// then check the full cache if it seems profitable
4269-
if (((jl_datatype_t*)unw)->isdispatchtuple) {
4269+
if (((jl_datatype_t*)unw)->isindivisibletype) {
42704270
jl_typemap_entry_t *entry = jl_typemap_assoc_by_type(jl_atomic_load_relaxed(&mt->cache), &search, jl_cachearg_offset(mt), /*subtype*/1);
4271-
if (entry && (((jl_datatype_t*)unw)->isdispatchtuple || entry->guardsigs == jl_emptysvec)) {
4271+
if (entry && (((jl_datatype_t*)unw)->isindivisibletype || entry->guardsigs == jl_emptysvec)) {
42724272
jl_method_instance_t *mi = entry->func.linfo;
42734273
jl_method_t *meth = mi->def.method;
4274-
if (!jl_is_unionall(meth->sig) && ((jl_datatype_t*)unw)->isdispatchtuple) {
4274+
if (!jl_is_unionall(meth->sig) && ((jl_datatype_t*)unw)->isindivisibletype) {
42754275
env.match.env = jl_emptysvec;
42764276
env.match.ti = unw;
42774277
}
@@ -4560,7 +4560,7 @@ static jl_value_t *ml_matches(jl_methtable_t *mt,
45604560
if (env.match.max_valid > max_world)
45614561
env.match.max_valid = max_world;
45624562
}
4563-
if (mt && cache_result && ((jl_datatype_t*)unw)->isdispatchtuple) { // cache_result parameter keeps this from being recursive
4563+
if (mt && cache_result && ((jl_datatype_t*)unw)->isindivisibletype) { // cache_result parameter keeps this from being recursive
45644564
if (len == 1 && !has_ambiguity) {
45654565
env.matc = (jl_method_match_t*)jl_array_ptr_ref(env.t, 0);
45664566
jl_method_t *meth = env.matc->method;

src/jltypes.c

+15-13
Original file line numberDiff line numberDiff line change
@@ -1839,24 +1839,24 @@ void jl_precompute_memoized_dt(jl_datatype_t *dt, int cacheable)
18391839
dt->hasfreetypevars = 0;
18401840
dt->maybe_subtype_of_cache = 1;
18411841
dt->isconcretetype = !dt->name->abstract;
1842-
dt->isdispatchtuple = istuple;
1842+
dt->isindivisibletype = (!dt->name->abstract && !jl_is_kind((jl_value_t*)dt)) || (dt->name == jl_type_typename);
18431843
size_t i, l = jl_nparams(dt);
18441844
for (i = 0; i < l; i++) {
18451845
jl_value_t *p = jl_tparam(dt, i);
1846-
if (!dt->hasfreetypevars) {
1847-
dt->hasfreetypevars = jl_has_free_typevars(p);
1848-
if (dt->hasfreetypevars)
1849-
dt->isconcretetype = 0;
1846+
if (!dt->hasfreetypevars && jl_has_free_typevars(p)) {
1847+
// XXX: this under-approximates type-indivisibility / type-concreteness in some
1848+
// conspicuous cases like (Tuple{T, Int} where T <: Int). Since these predicates
1849+
// are defined to be under-approximated, this is not a bug by itself, but this
1850+
// is something we may like to improve in the future
1851+
dt->hasfreetypevars = 1;
1852+
dt->isconcretetype = 0;
1853+
dt->isindivisibletype = 0;
18501854
}
18511855
if (istuple) {
18521856
if (dt->isconcretetype)
18531857
dt->isconcretetype = (jl_is_datatype(p) && ((jl_datatype_t*)p)->isconcretetype) || p == jl_bottom_type;
1854-
if (dt->isdispatchtuple) {
1855-
dt->isdispatchtuple = jl_is_datatype(p) &&
1856-
((!jl_is_kind(p) && ((jl_datatype_t*)p)->isconcretetype) ||
1857-
(p == (jl_value_t*)jl_typeofbottom_type) || // == Type{Union{}}, so needs to be consistent
1858-
(((jl_datatype_t*)p)->name == jl_type_typename && !((jl_datatype_t*)p)->hasfreetypevars));
1859-
}
1858+
if (dt->isindivisibletype)
1859+
dt->isindivisibletype = jl_is_datatype(p) && ((jl_datatype_t*)p)->isindivisibletype;
18601860
}
18611861
if (jl_is_vararg(p))
18621862
p = ((jl_vararg_t*)p)->T;
@@ -1871,7 +1871,7 @@ void jl_precompute_memoized_dt(jl_datatype_t *dt, int cacheable)
18711871
dt->maybe_subtype_of_cache = !p || maybe_subtype_of_cache(p, istuple) || !jl_has_free_typevars(p);
18721872
}
18731873
}
1874-
assert(dt->isconcretetype || dt->isdispatchtuple ? dt->maybe_subtype_of_cache : 1);
1874+
assert(dt->isconcretetype || dt->isindivisibletype ? dt->maybe_subtype_of_cache : 1);
18751875
if (dt->name == jl_type_typename) {
18761876
jl_value_t *p = jl_tparam(dt, 0);
18771877
if (!jl_is_type(p) && !jl_is_typevar(p)) // Type{v} has no subtypes, if v is not a Type
@@ -2986,7 +2986,7 @@ void jl_init_types(void) JL_GC_DISABLED
29862986
"instance",
29872987
"layout",
29882988
"hash",
2989-
"flags"); // "hasfreetypevars", "isconcretetype", "isdispatchtuple", "isbitstype", "zeroinit", "has_concrete_subtype", "maybe_subtype_of_cache"
2989+
"flags"); // "hasfreetypevars", "isconcretetype", "isindivisibletype", "isbitstype", "zeroinit", "has_concrete_subtype", "maybe_subtype_of_cache"
29902990
jl_datatype_type->types = jl_svec(8,
29912991
jl_typename_type,
29922992
jl_datatype_type,
@@ -3092,6 +3092,7 @@ void jl_init_types(void) JL_GC_DISABLED
30923092
jl_bottom_type = jl_gc_permobj(0, jl_typeofbottom_type, 0);
30933093
jl_set_typetagof(jl_bottom_type, jl_typeofbottom_tag, GC_OLD_MARKED);
30943094
jl_typeofbottom_type->instance = jl_bottom_type;
3095+
jl_typeofbottom_type->isindivisibletype = 1;
30953096

30963097
jl_unionall_type = jl_new_datatype(jl_symbol("UnionAll"), core, type_type, jl_emptysvec,
30973098
jl_perm_symsvec(2, "var", "body"),
@@ -3133,6 +3134,7 @@ void jl_init_types(void) JL_GC_DISABLED
31333134
// fix some miscomputed values, since we didn't know this was going to be a Tuple in jl_precompute_memoized_dt
31343135
jl_tuple_typename->wrapper = (jl_value_t*)jl_anytuple_type; // remove UnionAll wrappers
31353136
jl_anytuple_type->isconcretetype = 0;
3137+
jl_anytuple_type->isindivisibletype = 0;
31363138
jl_anytuple_type->maybe_subtype_of_cache = 0;
31373139
jl_anytuple_type->layout = NULL;
31383140

src/julia.h

+16-4
Original file line numberDiff line numberDiff line change
@@ -606,8 +606,20 @@ typedef struct _jl_datatype_t {
606606
// memoized properties (set on construction)
607607
uint32_t hash;
608608
uint16_t hasfreetypevars:1; // majority part of isconcrete computation
609-
uint16_t isconcretetype:1; // whether this type can have instances
610-
uint16_t isdispatchtuple:1; // aka isleaftupletype
609+
610+
// whether there is an object x such that T == typeof(x)
611+
//
612+
// in many cases this implies indivisibility, with the notable exception of singleton types
613+
// (`Type{T}`) which make, e.g., DataType a divisible type despite being concrete
614+
uint16_t isconcretetype:1; // conservative under-approximation (false implies nothing)
615+
616+
// whether T is an indivisible type (aka "leaf" type for tuples), i.e. T is "maximally-specific"
617+
// in the sense that for all inhabited T′, (T′ <: T) implies (T′ == T)
618+
//
619+
// if false, T may or may not be indivisible and may even be type-equal to another type which
620+
// has this flag set
621+
uint16_t isindivisibletype:1; // conservative under-approximation (false implies nothing)
622+
611623
uint16_t isbitstype:1; // relevant query for C-api and type-parameters
612624
uint16_t zeroinit:1; // if one or more fields requires zero-initialization
613625
uint16_t has_concrete_subtype:1; // If clear, no value will have this datatype
@@ -1875,9 +1887,9 @@ JL_DLLEXPORT const char *jl_typeof_str(jl_value_t *v) JL_NOTSAFEPOINT;
18751887
JL_DLLEXPORT int jl_type_morespecific(jl_value_t *a, jl_value_t *b);
18761888
JL_DLLEXPORT int jl_method_morespecific(jl_method_t *ma, jl_method_t *mb);
18771889

1878-
STATIC_INLINE int jl_is_dispatch_tupletype(jl_value_t *v) JL_NOTSAFEPOINT
1890+
STATIC_INLINE int jl_is_indivisible_type(jl_value_t *v) JL_NOTSAFEPOINT
18791891
{
1880-
return jl_is_datatype(v) && ((jl_datatype_t*)v)->isdispatchtuple;
1892+
return jl_is_datatype(v) && ((jl_datatype_t*)v)->isindivisibletype;
18811893
}
18821894

18831895
STATIC_INLINE int jl_is_concrete_type(jl_value_t *v) JL_NOTSAFEPOINT

src/precompile_utils.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -229,7 +229,7 @@ static int precompile_enq_all_specializations__(jl_typemap_entry_t *def, void *c
229229
jl_method_t *m = def->func.method;
230230
if (m->external_mt)
231231
return 1;
232-
if ((m->name == jl_symbol("__init__") || m->ccallable) && jl_is_dispatch_tupletype(m->sig)) {
232+
if ((m->name == jl_symbol("__init__") || m->ccallable) && jl_is_indivisible_type(m->sig)) {
233233
// ensure `__init__()` and @ccallables get strongly-hinted, specialized, and compiled
234234
jl_method_instance_t *mi = jl_specializations_get_linfo(m, m->sig, jl_emptysvec);
235235
jl_array_ptr_1d_push((jl_array_t*)closure, (jl_value_t*)mi);

0 commit comments

Comments
 (0)