static jl_typemap_entry_t *jl_typemap_lookup_by_type_(jl_typemap_entry_t *ml, jl_tupletype_t *types, int8_t useenv) { while (ml != (void*)jl_nothing) { // TODO: more efficient if (sigs_eq((jl_value_t*)types, (jl_value_t*)ml->sig, useenv)) { return ml; } ml = ml->next; } return NULL; }
/* warn about ambiguous method priorities the relative priority of A and B is ambiguous if !subtype(A,B) && !subtype(B,A) && no corresponding tuple elements are disjoint. for example, (AbstractArray, AbstractMatrix) and (AbstractMatrix, AbstractArray) are ambiguous. however, (AbstractArray, AbstractMatrix, Foo) and (AbstractMatrix, AbstractArray, Bar) are fine since Foo and Bar are disjoint, so there would be no confusion over which one to call. There is also this kind of ambiguity: foo{T,S}(T, S) vs. foo(Any,Any) In this case jl_types_equal() is true, but one is jl_type_morespecific or jl_type_match_morespecific than the other. To check this, jl_types_equal_generic needs to be more sophisticated so (T,T) is not equivalent to (Any,Any). (TODO) */ static void check_ambiguous(jl_methlist_t *ml, jl_tuple_t *type, jl_tuple_t *sig, jl_sym_t *fname) { // we know !jl_args_morespecific(type, sig) if ((type->length==sig->length || (type->length==sig->length+1 && is_va_tuple(type)) || (type->length+1==sig->length && is_va_tuple(sig))) && !jl_args_morespecific((jl_value_t*)sig, (jl_value_t*)type)) { jl_value_t *isect = jl_type_intersection((jl_value_t*)type, (jl_value_t*)sig); if (isect == (jl_value_t*)jl_bottom_type) return; JL_GC_PUSH(&isect); jl_methlist_t *l = ml; while (l != NULL) { if (sigs_eq(isect, (jl_value_t*)l->sig)) goto done_chk_amb; // ok, intersection is covered l = l->next; } char *n = fname->name; jl_value_t *errstream = jl_get_global(jl_system_module, jl_symbol("stderr_stream")); JL_TRY { if (errstream) jl_set_current_output_stream_obj(errstream); ios_t *s = jl_current_output_stream(); ios_printf(s, "Warning: New definition %s", n); jl_show((jl_value_t*)type); ios_printf(s, " is ambiguous with %s", n); jl_show((jl_value_t*)sig); ios_printf(s, ".\n Make sure %s", n); jl_show(isect); ios_printf(s, " is defined first.\n"); } JL_CATCH { jl_raise(jl_exception_in_transit); } done_chk_amb: JL_GC_POP(); }
static void jl_typemap_list_insert_sorted(jl_typemap_entry_t **pml, jl_value_t *parent, jl_typemap_entry_t *newrec, const struct jl_typemap_info *tparams) { jl_typemap_entry_t *l, **pl; pl = pml; l = *pml; jl_value_t *pa = parent; while (l != (void*)jl_nothing) { if (!l->isleafsig) { // quickly ignore all of the leafsig entries (these were handled by caller) if (jl_args_morespecific((jl_value_t*)newrec->sig, (jl_value_t*)l->sig)) { if (l->simplesig == (void*)jl_nothing || newrec->simplesig != (void*)jl_nothing || !sigs_eq((jl_value_t*)l->sig, (jl_value_t*)newrec->sig, 1)) { // might need to insert multiple entries for a lookup differing only by their simplesig // when simplesig contains a kind // TODO: make this test more correct or figure out a better way to compute this break; } } } pl = &l->next; pa = (jl_value_t*)l; l = l->next; } JL_SIGATOMIC_BEGIN(); newrec->next = l; jl_gc_wb(newrec, l); *pl = newrec; jl_gc_wb(pa, newrec); // if this contains Union types, methods after it might actually be // more specific than it. we need to re-sort them. if (has_unions(newrec->sig)) { jl_value_t *item_parent = (jl_value_t*)newrec; jl_value_t *next_parent = 0; jl_typemap_entry_t *item = newrec->next, *next; jl_typemap_entry_t **pitem = &newrec->next, **pnext; while (item != (void*)jl_nothing) { pl = pml; l = *pml; pa = parent; next = item->next; pnext = &item->next; next_parent = (jl_value_t*)item; while (l != newrec->next) { if (jl_args_morespecific((jl_value_t*)item->sig, (jl_value_t*)l->sig)) { // reinsert item earlier in the list *pitem = next; jl_gc_wb(item_parent, next); item->next = l; jl_gc_wb(item, item->next); *pl = item; jl_gc_wb(pa, item); pnext = pitem; next_parent = item_parent; break; } pl = &l->next; pa = (jl_value_t*)l; l = l->next; } item = next; pitem = pnext; item_parent = next_parent; } } JL_SIGATOMIC_END(); return; }