static inline int sig_match_simple(jl_value_t **args, size_t n, jl_value_t **sig, int va, size_t lensig) { // NOTE: This function is a performance hot spot!! size_t i; if (va) lensig -= 1; for (i = 0; i < lensig; i++) { jl_value_t *decl = sig[i]; jl_value_t *a = args[i]; if (decl == (jl_value_t*)jl_any_type || ((jl_value_t*)jl_typeof(a) == decl)) { /* we are only matching concrete types here, and those types are hash-consed, so pointer comparison should work. */ continue; } jl_value_t *unw = jl_is_unionall(decl) ? ((jl_unionall_t*)decl)->body : decl; if (jl_is_type_type(unw) && jl_is_type(a)) { jl_value_t *tp0 = jl_tparam0(unw); if (jl_is_typevar(tp0)) { // in the case of Type{_}, the types don't have to match exactly. // this is cached as `Type{T} where T`. if (((jl_tvar_t*)tp0)->ub != (jl_value_t*)jl_any_type && !jl_subtype(a, ((jl_tvar_t*)tp0)->ub)) return 0; } else { if (a != tp0) { if (jl_typeof(a) != jl_typeof(tp0)) return 0; jl_datatype_t *da = (jl_datatype_t*)a; jl_datatype_t *dt = (jl_datatype_t*)tp0; while (jl_is_unionall(da)) da = (jl_datatype_t*)((jl_unionall_t*)da)->body; while (jl_is_unionall(dt)) dt = (jl_datatype_t*)((jl_unionall_t*)dt)->body; if (jl_is_datatype(da) && jl_is_datatype(dt) && da->name != dt->name) return 0; if (!jl_types_equal(a, tp0)) return 0; } } } else { return 0; } } if (va) { jl_value_t *decl = sig[i]; if (jl_vararg_kind(decl) == JL_VARARG_INT) { if (n-i != jl_unbox_long(jl_tparam1(decl))) return 0; } jl_value_t *t = jl_unwrap_vararg(decl); for(; i < n; i++) { if (!jl_isa(args[i], t)) return 0; } return 1; } return 1; }
static int has_unions(jl_value_t *type) { type = jl_unwrap_unionall(type); int i; for (i = 0; i < jl_nparams(type); i++) { jl_value_t *t = jl_tparam(type, i); if (jl_is_uniontype(t) || (jl_is_vararg_type(t) && jl_is_uniontype(jl_unwrap_vararg(t)))) return 1; } return 0; }
JL_DLLEXPORT size_t jl_static_show_func_sig(JL_STREAM *s, jl_value_t *type) { jl_value_t *ftype = (jl_value_t*)jl_first_argument_datatype(type); if (ftype == NULL) return jl_static_show(s, type); size_t n = 0; if (jl_nparams(ftype)==0 || ftype == ((jl_datatype_t*)ftype)->name->wrapper) { n += jl_printf(s, "%s", jl_symbol_name(((jl_datatype_t*)ftype)->name->mt->name)); } else { n += jl_printf(s, "(::"); n += jl_static_show(s, ftype); n += jl_printf(s, ")"); } // TODO: better way to show method parameters type = jl_unwrap_unionall(type); if (!jl_is_datatype(type)) { n += jl_printf(s, " "); n += jl_static_show(s, type); return n; } size_t tl = jl_nparams(type); n += jl_printf(s, "("); size_t i; for (i = 1; i < tl; i++) { jl_value_t *tp = jl_tparam(type, i); if (i != tl - 1) { n += jl_static_show(s, tp); n += jl_printf(s, ", "); } else { if (jl_is_vararg_type(tp)) { n += jl_static_show(s, jl_unwrap_vararg(tp)); n += jl_printf(s, "..."); } else { n += jl_static_show(s, tp); } } } n += jl_printf(s, ")"); return n; }
static void jl_typemap_level_insert_(jl_typemap_level_t *cache, jl_typemap_entry_t *newrec, int8_t offs, const struct jl_typemap_info *tparams) { jl_value_t *ttypes = jl_unwrap_unionall((jl_value_t*)newrec->sig); size_t l = jl_field_count(ttypes); // compute the type at offset `offs` into `sig`, which may be a Vararg jl_value_t *t1 = NULL; int isva = 0; if (l <= offs + 1) { t1 = jl_tparam(ttypes, l - 1); if (jl_is_vararg_type(t1)) { isva = 1; t1 = jl_unwrap_vararg(t1); } else if (l <= offs) { t1 = NULL; } } else if (l > offs) { t1 = jl_tparam(ttypes, offs); } // If the type at `offs` is Any, put it in the Any list if (t1 && jl_is_any(t1)) { jl_typemap_insert_generic(&cache->any, (jl_value_t*)cache, newrec, (jl_value_t*)jl_any_type, offs+1, tparams); return; } // Don't put Varargs in the optimized caches (too hard to handle in lookup and bp) if (t1 && !isva) { // if t1 != jl_typetype_type and the argument is Type{...}, this // method has specializations for singleton kinds and we use // the table indexed for that purpose. if (t1 != (jl_value_t*)jl_typetype_type && jl_is_type_type(t1)) { jl_value_t *a0 = jl_tparam0(t1); if (jl_typemap_array_insert_(&cache->targ, a0, newrec, (jl_value_t*)cache, 1, offs, tparams)) return; } if (jl_typemap_array_insert_(&cache->arg1, t1, newrec, (jl_value_t*)cache, 0, offs, tparams)) return; } jl_typemap_list_insert_(&cache->linear, (jl_value_t*)cache, newrec, tparams); }
// this is the general entry point for looking up a type in the cache // as a subtype, or with type_equal jl_typemap_entry_t *jl_typemap_assoc_by_type(union jl_typemap_t ml_or_cache, jl_value_t *types, jl_svec_t **penv, int8_t subtype, int8_t offs, size_t world, size_t max_world_mask) { if (jl_typeof(ml_or_cache.unknown) == (jl_value_t*)jl_typemap_level_type) { jl_typemap_level_t *cache = ml_or_cache.node; // called object is the primary key for constructors, otherwise first argument jl_value_t *ty = NULL; jl_value_t *ttypes = jl_unwrap_unionall((jl_value_t*)types); assert(jl_is_datatype(ttypes)); size_t l = jl_field_count(ttypes); int isva = 0; // compute the type at offset `offs` into `types`, which may be a Vararg if (l <= offs + 1) { ty = jl_tparam(ttypes, l - 1); if (jl_is_vararg_type(ty)) { ty = jl_unwrap_vararg(ty); isva = 1; } else if (l <= offs) { ty = NULL; } } else if (l > offs) { ty = jl_tparam(ttypes, offs); } // If there is a type at offs, look in the optimized caches if (!subtype) { if (ty && jl_is_any(ty)) return jl_typemap_assoc_by_type(cache->any, types, penv, subtype, offs + 1, world, max_world_mask); if (isva) // in lookup mode, want to match Vararg exactly, not as a subtype ty = NULL; } if (ty) { if (jl_is_type_type(ty)) { jl_value_t *a0 = jl_tparam0(ty); if (cache->targ.values != (void*)jl_nothing && jl_is_datatype(a0)) { union jl_typemap_t ml = mtcache_hash_lookup(&cache->targ, a0, 1, offs); if (ml.unknown != jl_nothing) { jl_typemap_entry_t *li = jl_typemap_assoc_by_type(ml, types, penv, subtype, offs + 1, world, max_world_mask); if (li) return li; } } if (!subtype && is_cache_leaf(a0)) return NULL; } if (cache->arg1.values != (void*)jl_nothing && jl_is_datatype(ty)) { union jl_typemap_t ml = mtcache_hash_lookup(&cache->arg1, ty, 0, offs); if (ml.unknown != jl_nothing) { jl_typemap_entry_t *li = jl_typemap_assoc_by_type(ml, types, penv, subtype, offs + 1, world, max_world_mask); if (li) return li; } } if (!subtype && is_cache_leaf(ty)) return NULL; } // Always check the list (since offs doesn't always start at 0) if (subtype) { jl_typemap_entry_t *li = jl_typemap_assoc_by_type_(cache->linear, types, penv, world, max_world_mask); if (li) return li; return jl_typemap_assoc_by_type(cache->any, types, penv, subtype, offs + 1, world, max_world_mask); } else { return jl_typemap_lookup_by_type_(cache->linear, types, world, max_world_mask); } } else { return subtype ? jl_typemap_assoc_by_type_(ml_or_cache.leaf, types, penv, world, max_world_mask) : jl_typemap_lookup_by_type_(ml_or_cache.leaf, types, world, max_world_mask); } }