JL_DLLEXPORT int jl_args_morespecific(jl_value_t *a, jl_value_t *b) { int msp = jl_type_morespecific(a,b); int btv = jl_has_typevars(b); if (btv) { if (jl_type_match_morespecific(a,b) == (jl_value_t*)jl_false) { if (jl_has_typevars(a)) return 0; return msp; } if (jl_has_typevars(a)) { type_match_invariance_mask = 0; //int result = jl_type_match_morespecific(b,a) == (jl_value_t*)jl_false); // this rule seems to work better: int result = jl_type_match(b,a) == (jl_value_t*)jl_false; type_match_invariance_mask = 1; if (result) return 1; } int nmsp = jl_type_morespecific(b,a); if (nmsp == msp) return 0; } if (jl_has_typevars((jl_value_t*)a)) { int nmsp = jl_type_morespecific(b,a); if (nmsp && msp) return 1; if (!btv && jl_types_equal(a,b)) return 1; if (jl_type_match_morespecific(b,a) != (jl_value_t*)jl_false) return 0; } return msp; }
static jl_function_t *jl_mt_assoc_by_type(jl_methtable_t *mt, jl_tuple_t *tt, int cache) { jl_methlist_t *m = mt->defs; size_t nargs = tt->length; size_t i; jl_value_t *env = jl_false; while (m != NULL) { if (m->tvars!=jl_null) { env = jl_type_match((jl_value_t*)tt, (jl_value_t*)m->sig); if (env != (jl_value_t*)jl_false) break; } else if (jl_tuple_subtype(&jl_tupleref(tt,0), nargs, &jl_tupleref(m->sig,0), ((jl_tuple_t*)m->sig)->length, 0, 0)) { break; } m = m->next; } if (env == (jl_value_t*)jl_false) { if (m != NULL) { if (!cache) { return m->func; } return cache_method(mt, tt, m->func, (jl_tuple_t*)m->sig, jl_null); } return NULL; } jl_tuple_t *newsig=NULL; JL_GC_PUSH(&env, &newsig); assert(jl_is_tuple(env)); jl_tuple_t *tpenv = (jl_tuple_t*)env; // don't bother computing this if no arguments are tuples for(i=0; i < tt->length; i++) { if (jl_is_tuple(jl_tupleref(tt,i))) break; } if (i < tt->length) { newsig = (jl_tuple_t*)jl_instantiate_type_with((jl_type_t*)m->sig, &jl_tupleref(tpenv,0), tpenv->length/2); } else { newsig = (jl_tuple_t*)m->sig; } assert(jl_is_tuple(newsig)); jl_function_t *nf; if (!cache) nf = m->func; else nf = cache_method(mt, tt, m->func, newsig, tpenv); JL_GC_POP(); return nf; }
/* Method caches are divided into three parts: one for signatures where the first argument is a singleton kind (Type{Foo}), one indexed by the UID of the first argument's type in normal cases, and a fallback table of everything else. Note that the "primary key" is the type of the first *argument*, since there tends to be lots of variation there. The type of the 0th argument (the function) is always the same for most functions. */ static jl_typemap_entry_t *jl_typemap_assoc_by_type_(jl_typemap_entry_t *ml, jl_tupletype_t *types, int8_t inexact, jl_svec_t **penv) { size_t n = jl_field_count(types); while (ml != (void*)jl_nothing) { size_t lensig = jl_field_count(ml->sig); if (lensig == n || (ml->va && lensig <= n+1)) { int resetenv = 0, ismatch = 1; if (ml->simplesig != (void*)jl_nothing) { size_t lensimplesig = jl_field_count(ml->simplesig); int isva = lensimplesig > 0 && jl_is_vararg_type(jl_tparam(ml->simplesig, lensimplesig - 1)); if (lensig == n || (isva && lensimplesig <= n + 1)) ismatch = sig_match_by_type_simple(jl_svec_data(types->parameters), n, ml->simplesig, lensimplesig, isva); else ismatch = 0; } if (ismatch == 0) ; // nothing else if (ml->isleafsig) ismatch = sig_match_by_type_leaf(jl_svec_data(types->parameters), ml->sig, lensig); else if (ml->issimplesig) ismatch = sig_match_by_type_simple(jl_svec_data(types->parameters), n, ml->sig, lensig, ml->va); else if (ml->tvars == jl_emptysvec) ismatch = jl_tuple_subtype(jl_svec_data(types->parameters), n, ml->sig, 0); else if (penv == NULL) { ismatch = jl_type_match((jl_value_t*)types, (jl_value_t*)ml->sig) != (jl_value_t*)jl_false; } else { // TODO: this is missing the actual subtype test, // which works currently because types is typically a leaf tt, // or inexact is set (which then does a sort of subtype test via jl_types_equal) // but this isn't entirely general jl_value_t *ti = jl_lookup_match((jl_value_t*)types, (jl_value_t*)ml->sig, penv, ml->tvars); resetenv = 1; ismatch = (ti != (jl_value_t*)jl_bottom_type); if (ismatch) { // parametric methods only match if all typevars are matched by // non-typevars. size_t i, l; for (i = 0, l = jl_svec_len(*penv); i < l; i++) { if (jl_is_typevar(jl_svecref(*penv, i))) { if (inexact) { // "inexact" means the given type is compile-time, // where a failure to determine the value of a // static parameter is inconclusive. // this is issue #3182, see test/core.jl return INEXACT_ENTRY; } ismatch = 0; break; } } if (inexact) { // the compiler might attempt jl_get_specialization on e.g. // convert(::Type{Type{Int}}, ::DataType), which is concrete but might not // equal the run time type. in this case ti would be {Type{Type{Int}}, Type{Int}} // but tt would be {Type{Type{Int}}, DataType}. JL_GC_PUSH1(&ti); ismatch = jl_types_equal(ti, (jl_value_t*)types); JL_GC_POP(); if (!ismatch) return INEXACT_ENTRY; } } } if (ismatch) { size_t i, l; for (i = 0, l = jl_svec_len(ml->guardsigs); i < l; i++) { // see corresponding code in jl_typemap_assoc_exact if (jl_subtype((jl_value_t*)types, jl_svecref(ml->guardsigs, i), 0)) { ismatch = 0; break; } } if (ismatch) return ml; } if (resetenv) *penv = jl_emptysvec; } ml = ml->next; } return NULL; }