Skip to content

Commit

Permalink
Throw error for an ambiguous call
Browse files Browse the repository at this point in the history
  • Loading branch information
timholy committed May 1, 2016
1 parent 41d0c8b commit 57979cc
Show file tree
Hide file tree
Showing 7 changed files with 106 additions and 36 deletions.
3 changes: 2 additions & 1 deletion src/builtins.c
Original file line number Diff line number Diff line change
Expand Up @@ -948,7 +948,8 @@ static void jl_check_type_tuple(jl_value_t *t, jl_sym_t *name, const char *ctx)
JL_CALLABLE(jl_f_applicable)
{
JL_NARGSV(applicable, 1);
return jl_method_lookup(jl_gf_mtable(args[0]), args, nargs, 1) != NULL ?
jl_typemap_entry_t *m;
return jl_method_lookup(jl_gf_mtable(args[0]), args, nargs, 1, &m) != NULL ?
jl_true : jl_false;
}

Expand Down
4 changes: 3 additions & 1 deletion src/codegen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1096,12 +1096,14 @@ void *jl_get_llvmf(jl_tupletype_t *tt, bool getwrapper, bool getdeclarations)
if (tt != NULL) {
linfo = jl_get_specialization1(tt);
if (linfo == NULL) {
jl_typemap_entry_t *m;
linfo = jl_method_lookup_by_type(
((jl_datatype_t*)jl_tparam0(tt))->name->mt, tt, 0, 0);
((jl_datatype_t*)jl_tparam0(tt))->name->mt, tt, 0, 0, &m);
if (linfo == NULL) {
JL_GC_POP();
return NULL;
}
check_ambig_call(m, tt);
}
}
if (linfo == NULL) {
Expand Down
68 changes: 46 additions & 22 deletions src/gf.c
Original file line number Diff line number Diff line change
Expand Up @@ -681,26 +681,28 @@ static jl_lambda_info_t *cache_method(jl_methtable_t *mt, union jl_typemap_t *ca
return newmeth;
}

static jl_lambda_info_t *jl_mt_assoc_by_type(jl_methtable_t *mt, jl_datatype_t *tt, int cache, int inexact)
static jl_lambda_info_t *jl_mt_assoc_by_type(jl_methtable_t *mt, jl_datatype_t *tt, int cache, int inexact, jl_typemap_entry_t **m)
{
jl_typemap_entry_t *m = NULL;
*m = NULL;
jl_svec_t *env = jl_emptysvec;
jl_method_t *func = NULL;
jl_tupletype_t *sig = NULL;
JL_GC_PUSH4(&env, &m, &func, &sig);
JL_GC_PUSH4(&env, m, &func, &sig);

m = jl_typemap_assoc_by_type(mt->defs, tt, &env, inexact, 1, 0);
if (m == NULL) {
*m = jl_typemap_assoc_by_type(mt->defs, tt, &env, inexact, 1, 0);
if (*m == NULL) {
JL_GC_POP();
return NULL;
}

sig = join_tsig(tt, m->sig);
sig = join_tsig(tt, (*m)->sig);
jl_lambda_info_t *nf;
if (!cache)
nf = jl_get_specialized(m->func.method, sig, env);
else
nf = cache_method(mt, &mt->cache, (jl_value_t*)mt, sig, tt, m, env);
nf = jl_get_specialized((*m)->func.method, sig, env);
else {
check_ambig_call(*m, tt); // if ambiguous, don't insert into cache
nf = cache_method(mt, &mt->cache, (jl_value_t*)mt, sig, tt, *m, env);
}
JL_GC_POP();
return nf;
}
Expand Down Expand Up @@ -958,32 +960,34 @@ jl_tupletype_t *arg_type_tuple(jl_value_t **args, size_t nargs)
}

jl_lambda_info_t *jl_method_lookup_by_type(jl_methtable_t *mt, jl_tupletype_t *types,
int cache, int inexact)
int cache, int inexact,
jl_typemap_entry_t **m)
{
jl_typemap_entry_t *m = jl_typemap_assoc_by_type(mt->cache, types, NULL, 0, 1, jl_cachearg_offset(mt));
*m = jl_typemap_assoc_by_type(mt->cache, types, NULL, 0, 1, jl_cachearg_offset(mt));
jl_lambda_info_t *sf;
if (m) {
sf = m->func.linfo;
if (*m) {
sf = (*m)->func.linfo;
}
else {
if (jl_is_leaf_type((jl_value_t*)types)) cache=1;
sf = jl_mt_assoc_by_type(mt, types, cache, inexact);
sf = jl_mt_assoc_by_type(mt, types, cache, inexact, m);
}
return sf;
}

JL_DLLEXPORT int jl_method_exists(jl_methtable_t *mt, jl_tupletype_t *types)
{
return jl_method_lookup_by_type(mt, types, 0, 0) != NULL;
jl_typemap_entry_t *m;
return jl_method_lookup_by_type(mt, types, 0, 0, &m) != NULL;
}

jl_lambda_info_t *jl_method_lookup(jl_methtable_t *mt, jl_value_t **args, size_t nargs, int cache)
jl_lambda_info_t *jl_method_lookup(jl_methtable_t *mt, jl_value_t **args, size_t nargs, int cache, jl_typemap_entry_t **m)
{
jl_lambda_info_t *sf = jl_typemap_assoc_exact(mt->cache, args, nargs, jl_cachearg_offset(mt));
jl_lambda_info_t *sf = jl_typemap_assoc_exact(mt->cache, args, nargs, jl_cachearg_offset(mt), m);
if (sf == NULL) {
jl_tupletype_t *tt = arg_type_tuple(args, nargs);
JL_GC_PUSH1(&tt);
sf = jl_mt_assoc_by_type(mt, tt, cache, 0);
sf = jl_mt_assoc_by_type(mt, tt, cache, 0, m);
JL_GC_POP();
}
return sf;
Expand Down Expand Up @@ -1019,13 +1023,16 @@ jl_lambda_info_t *jl_get_specialization1(jl_tupletype_t *types)
// most of the time sf is rooted in mt, but if the method is staged it may
// not be the case
JL_GC_PUSH1(&sf);
jl_typemap_entry_t *m;
JL_TRY {
sf = jl_method_lookup_by_type(mt, types, 1, 1);
sf = jl_method_lookup_by_type(mt, types, 1, 1, &m);
} JL_CATCH {
goto not_found;
}
if (sf == NULL || sf->code == NULL || sf->inInference)
goto not_found;
if (m->ambig != jl_nothing)
check_ambig_call(m, types);
if (sf->functionObjectsDecls.functionObject == NULL) {
if (sf->fptr != NULL)
goto not_found;
Expand All @@ -1043,6 +1050,19 @@ JL_DLLEXPORT void jl_compile_hint(jl_tupletype_t *types)
(void)jl_get_specialization1(types);
}

void check_ambig_call(jl_typemap_entry_t *m, jl_tupletype_t *types)
{
if (m->ambig == jl_nothing)
return;
for (size_t i = 0; i < jl_array_len(m->ambig); i++) {
jl_typemap_entry_t *mambig = (jl_typemap_entry_t*)jl_cellref(m->ambig, i);
if (jl_type_intersection((jl_value_t*)mambig->sig,
(jl_value_t*)types) != (jl_value_t*)jl_bottom_type) {
jl_error("ambiguous");
}
}
}

// add type of `f` to front of argument tuple type
jl_tupletype_t *jl_argtype_with_function(jl_function_t *f, jl_tupletype_t *types)
{
Expand Down Expand Up @@ -1482,7 +1502,8 @@ JL_DLLEXPORT jl_value_t *jl_apply_generic(jl_value_t **args, uint32_t nargs)
if no generic match, use the concrete one even if inexact
otherwise instantiate the generic method and use it
*/
jl_lambda_info_t *mfunc = jl_typemap_assoc_exact(mt->cache, args, nargs, jl_cachearg_offset(mt));
jl_typemap_entry_t *m;
jl_lambda_info_t *mfunc = jl_typemap_assoc_exact(mt->cache, args, nargs, jl_cachearg_offset(mt), &m);

jl_tupletype_t *tt = NULL;
if (mfunc == NULL) {
Expand All @@ -1491,7 +1512,7 @@ JL_DLLEXPORT jl_value_t *jl_apply_generic(jl_value_t **args, uint32_t nargs)
// if running inference overwrites this particular method, it becomes
// unreachable from the method table, so root mfunc.
JL_GC_PUSH2(&tt, &mfunc);
mfunc = jl_mt_assoc_by_type(mt, tt, 1, 0);
mfunc = jl_mt_assoc_by_type(mt, tt, 1, 0, &m);

if (mfunc == NULL) {
#ifdef JL_TRACE
Expand All @@ -1503,6 +1524,8 @@ JL_DLLEXPORT jl_value_t *jl_apply_generic(jl_value_t **args, uint32_t nargs)
// unreachable
}
}
if (m->ambig != jl_nothing)
check_ambig_call(m, tt);
#ifdef JL_TRACE
if (traceen)
jl_printf(JL_STDOUT, " at %s:%d\n", jl_symbol_name(mfunc->file), mfunc->line);
Expand Down Expand Up @@ -1561,10 +1584,11 @@ jl_value_t *jl_gf_invoke(jl_tupletype_t *types0, jl_value_t **args, size_t nargs
// next look for or create a specialization of this definition.

jl_lambda_info_t *mfunc;
jl_typemap_entry_t *tm;
if (m->func.method->invokes.unknown == NULL)
mfunc = NULL;
else
mfunc = jl_typemap_assoc_exact(m->func.method->invokes, args, nargs, jl_cachearg_offset(mt));
mfunc = jl_typemap_assoc_exact(m->func.method->invokes, args, nargs, jl_cachearg_offset(mt), &tm);
if (mfunc == NULL) {
tt = arg_type_tuple(args, nargs);
if (m->tvars != jl_emptysvec) {
Expand Down
8 changes: 5 additions & 3 deletions src/julia_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -215,9 +215,11 @@ void jl_lambda_info_set_ast(jl_lambda_info_t *li, jl_value_t *ast);

jl_lambda_info_t *jl_get_unspecialized(jl_lambda_info_t *method);
jl_lambda_info_t *jl_method_lookup_by_type(jl_methtable_t *mt, jl_tupletype_t *types,
int cache, int inexact);
jl_lambda_info_t *jl_method_lookup(jl_methtable_t *mt, jl_value_t **args, size_t nargs, int cache);
int cache, int inexact,
jl_typemap_entry_t **m);
jl_lambda_info_t *jl_method_lookup(jl_methtable_t *mt, jl_value_t **args, size_t nargs, int cache, jl_typemap_entry_t **m);
jl_value_t *jl_gf_invoke(jl_tupletype_t *types, jl_value_t **args, size_t nargs);
void check_ambig_call(jl_typemap_entry_t *m, jl_tupletype_t *types);

jl_array_t *jl_lam_args(jl_expr_t *l);
jl_array_t *jl_lam_vinfo(jl_expr_t *l);
Expand Down Expand Up @@ -563,7 +565,7 @@ jl_typemap_entry_t *jl_typemap_insert(union jl_typemap_t *cache, jl_value_t *par

jl_typemap_entry_t *jl_typemap_assoc_by_type(union jl_typemap_t ml_or_cache, jl_tupletype_t *types, jl_svec_t **penv,
int8_t subtype_inexact__sigseq_useenv, int8_t subtype, int8_t offs);
jl_lambda_info_t *jl_typemap_assoc_exact(union jl_typemap_t ml_or_cache, jl_value_t **args, size_t n, int8_t offs);
jl_lambda_info_t *jl_typemap_assoc_exact(union jl_typemap_t ml_or_cache, jl_value_t **args, size_t n, int8_t offs, jl_typemap_entry_t **m);

typedef int (*jl_typemap_visitor_fptr)(jl_typemap_entry_t *l, void *closure);
int jl_typemap_visitor(union jl_typemap_t a, jl_typemap_visitor_fptr fptr, void *closure);
Expand Down
25 changes: 17 additions & 8 deletions src/typemap.c
Original file line number Diff line number Diff line change
Expand Up @@ -623,9 +623,10 @@ jl_typemap_entry_t *jl_typemap_assoc_by_type(union jl_typemap_t ml_or_cache, jl_
jl_typemap_lookup_by_type_(ml, types, subtype_inexact__sigseq_useenv);
}

jl_lambda_info_t *jl_typemap_assoc_exact(union jl_typemap_t ml_or_cache, jl_value_t **args, size_t n, int8_t offs)
jl_lambda_info_t *jl_typemap_assoc_exact(union jl_typemap_t ml_or_cache, jl_value_t **args, size_t n, int8_t offs, jl_typemap_entry_t **m)
{
// NOTE: This function is a huge performance hot spot!!
*m = NULL;
jl_typemap_entry_t *ml;
if (jl_typeof(ml_or_cache.unknown) == (jl_value_t*)jl_typemap_level_type) {
jl_typemap_level_t *cache = ml_or_cache.node;
Expand All @@ -635,7 +636,7 @@ jl_lambda_info_t *jl_typemap_assoc_exact(union jl_typemap_t ml_or_cache, jl_valu
assert(jl_is_datatype(ty));
if (ty == (jl_value_t*)jl_datatype_type && cache->targ != (void*)jl_nothing) {
ml_or_cache = mtcache_hash_lookup(cache->targ, a1, 1, offs);
jl_lambda_info_t *li = jl_typemap_assoc_exact(ml_or_cache, args, n, offs+1);
jl_lambda_info_t *li = jl_typemap_assoc_exact(ml_or_cache, args, n, offs+1, m);
if (li)
return li;
}
Expand All @@ -646,26 +647,32 @@ jl_lambda_info_t *jl_typemap_assoc_exact(union jl_typemap_t ml_or_cache, jl_valu
jl_value_t *a0 = args[1-offs];
jl_value_t *t0 = (jl_value_t*)jl_typeof(a0);
if (ml_or_cache.leaf->next==(void*)jl_nothing && n==2 && jl_datatype_nfields(ml_or_cache.leaf->sig)==2 &&
jl_tparam(ml_or_cache.leaf->sig, 1 - offs) == t0)
return ml_or_cache.leaf->func.linfo;
jl_tparam(ml_or_cache.leaf->sig, 1 - offs) == t0) {
*m = ml_or_cache.leaf;
return (*m)->func.linfo;
}
if (n==3) {
// some manually-unrolled common special cases
jl_value_t *a2 = args[2];
if (!jl_is_tuple(a2)) { // issue #6426
jl_typemap_entry_t *mn = ml_or_cache.leaf;
if (jl_datatype_nfields(mn->sig)==3 &&
jl_tparam(mn->sig,1-offs)==t0 &&
jl_tparam(mn->sig,2)==(jl_value_t*)jl_typeof(a2))
jl_tparam(mn->sig,2)==(jl_value_t*)jl_typeof(a2)) {
*m = mn;
return mn->func.linfo;
}
mn = mn->next;
if (mn!=(void*)jl_nothing && jl_datatype_nfields(mn->sig)==3 &&
jl_tparam(mn->sig,1-offs)==t0 &&
jl_tparam(mn->sig,2)==(jl_value_t*)jl_typeof(a2))
jl_tparam(mn->sig,2)==(jl_value_t*)jl_typeof(a2)) {
*m = mn;
return mn->func.linfo;
}
}
}
}
jl_lambda_info_t *li = jl_typemap_assoc_exact(ml_or_cache, args, n, offs+1);
jl_lambda_info_t *li = jl_typemap_assoc_exact(ml_or_cache, args, n, offs+1, m);
if (li)
return li;
}
Expand Down Expand Up @@ -700,8 +707,10 @@ jl_lambda_info_t *jl_typemap_assoc_exact(union jl_typemap_t ml_or_cache, jl_valu
break;
}
}
if (i == l)
if (i == l) {
*m = ml;
return ml->func.linfo;
}
}
}
ml = ml->next;
Expand Down
32 changes: 32 additions & 0 deletions test/ambiguous.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# DO NOT CHANGE LINE NUMBERS BELOW
@noinline foo(x, y) = 1
@noinline foo(x::Integer, y) = 2
@noinline foo(x, y::Integer) = 3
@noinline foo(x::Int, y::Int) = 4
@noinline foo(x::Number, y) = 5
# END OF LINE NUMBER SENSITIVITY

ambigs = Any[[], [3], [2,5], [], [3]]

mt = methods(foo)
tm = mt.defs

getline(tm) = tm.func.line - 1

while tm != nothing
ln = getline(tm)
atarget = ambigs[ln]
if isempty(atarget)
@test tm.ambig == nothing
else
aln = Int[getline(a) for a in tm.ambig]
@test sort(aln) == atarget
end
tm = tm.next
end

@test foo("hi", "there") == 1
@test foo(3.1, 3.2) == 5
@test foo(3, 4) == 4
@test_throws ErrorException foo(0x03, 4)
@test_throws ErrorException foo(0x03, 4) # test that not inserted into cache
2 changes: 1 addition & 1 deletion test/choosetests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ function choosetests(choices = [])
"markdown", "base64", "serialize", "misc", "threads",
"enums", "cmdlineargs", "i18n", "workspace", "libdl", "int",
"checked", "intset", "floatfuncs", "compile", "parallel", "inline",
"boundscheck", "error"
"boundscheck", "error", "ambiguous"
]

if Base.USE_GPL_LIBS
Expand Down

0 comments on commit 57979cc

Please sign in to comment.