// f{<:Union{...}}(...) is a common pattern // and expanding the Union may give a leaf function static void _compile_all_tvar_union(jl_value_t *methsig) { if (!jl_is_unionall(methsig) && jl_is_leaf_type(methsig)) { // usually can create a specialized version of the function, // if the signature is already a leaftype if (jl_compile_hint((jl_tupletype_t*)methsig)) return; } int tvarslen = jl_subtype_env_size(methsig); jl_value_t *sigbody = methsig; jl_value_t **env; JL_GC_PUSHARGS(env, 2 * tvarslen); int *idx = (int*)alloca(sizeof(int) * tvarslen); int i; for (i = 0; i < tvarslen; i++) { assert(jl_is_unionall(sigbody)); idx[i] = 0; env[2 * i] = (jl_value_t*)((jl_unionall_t*)sigbody)->var; env[2 * i + 1] = jl_bottom_type; // initialize the list with Union{}, since T<:Union{} is always a valid option sigbody = ((jl_unionall_t*)sigbody)->body; } for (i = 0; i < tvarslen; /* incremented by inner loop */) { jl_value_t *sig; JL_TRY { // TODO: wrap in UnionAll for each tvar in env[2*i + 1] ? // currently doesn't matter much, since jl_compile_hint doesn't work on abstract types sig = (jl_value_t*)jl_instantiate_type_with(sigbody, env, tvarslen); } JL_CATCH { goto getnext; // sigh, we found an invalid type signature. should we warn the user? } assert(jl_is_tuple_type(sig)); if (sig == jl_bottom_type || tupletype_any_bottom(sig)) goto getnext; // signature wouldn't be callable / is invalid -- skip it if (jl_is_leaf_type(sig)) { if (jl_compile_hint((jl_tupletype_t*)sig)) goto getnext; // success } getnext: for (i = 0; i < tvarslen; i++) { jl_tvar_t *tv = (jl_tvar_t*)env[2 * i]; if (jl_is_uniontype(tv->ub)) { size_t l = jl_count_union_components(tv->ub); size_t j = idx[i]; if (j == l) { env[2 * i + 1] = jl_bottom_type; idx[i] = 0; } else { jl_value_t *ty = jl_nth_union_component(tv->ub, j); if (!jl_is_leaf_type(ty)) ty = (jl_value_t*)jl_new_typevar(tv->name, tv->lb, ty); env[2 * i + 1] = ty; idx[i] = j + 1; break; } } else { env[2 * i + 1] = (jl_value_t*)tv; } } } JL_GC_POP(); }
static jl_datatype_t* julia_type() { static jl_tvar_t* this_tvar = jl_new_typevar(jl_symbol("T"), (jl_value_t*)jl_bottom_type, (jl_value_t*)jl_any_type); return (jl_datatype_t*)jl_apply_type((jl_value_t*)jl_type_type, jl_svec1(jl_apply_type((jl_value_t*)jl_array_type, jl_svec2(this_tvar, jl_box_long(2))))); }