Skip to content

Commit 6018e5b

Browse files
committed
Add AmbiguousError and use it in codegen
1 parent c3bb876 commit 6018e5b

13 files changed

+217
-59
lines changed

base/base.jl

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,11 @@ type MethodError <: Exception
3434
args
3535
end
3636

37+
type AmbiguousError <: Exception
38+
args
39+
srcinfo
40+
end
41+
3742
type EOFError <: Exception end
3843

3944
type DimensionMismatch <: Exception

base/exports.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,7 @@ export
152152
Cwstring,
153153

154154
# Exceptions
155+
AmbiguousError,
155156
ArgumentError,
156157
DimensionMismatch,
157158
CapturedException,

base/reflection.jl

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -170,10 +170,11 @@ end
170170

171171
tt_cons(t::ANY, tup::ANY) = (@_pure_meta; Tuple{t, (isa(tup, Type) ? tup.parameters : tup)...})
172172

173-
code_lowered(f, t::ANY=Tuple) = map(m -> (m::Method).lambda_template, methods(f, t))
173+
code_lowered(f, t::ANY=Tuple) = map(m -> (m::Method).lambda_template, checked_methods(f, t))
174174

175175
# low-level method lookup functions used by the compiler
176176

177+
checkambiguity(tt::Type, m::Method) = ccall(:jl_list_call_ambiguities, Any, (Any, Any), tt, m)
177178
function _methods(f::ANY,t::ANY,lim)
178179
ft = isa(f,Type) ? Type{f} : typeof(f)
179180
if isa(t,Type)
@@ -249,6 +250,18 @@ function methods(f::ANY, t::ANY)
249250
return MethodList(Method[m[3] for m in _methods(f,t,-1)], typeof(f).name.mt)
250251
end
251252

253+
function checked_methods(f::ANY, t::ANY)
254+
ms = methods(f, t)
255+
tt = isa(t, DataType) ? Tuple{typeof(f), t.parameters...} : Tuple{typeof(f), t...}
256+
for m in ms
257+
srcinfo = checkambiguity(tt, m)
258+
if srcinfo != nothing
259+
throw(AmbiguousError(tt, srcinfo))
260+
end
261+
end
262+
ms
263+
end
264+
252265
methods(f::Builtin) = MethodList(Method[], typeof(f).name.mt)
253266

254267
function methods(f::ANY)
@@ -339,8 +352,14 @@ end
339352
function code_typed(f::ANY, types::ANY=Tuple; optimize=true)
340353
ccall(:jl_is_in_pure_context, Bool, ()) && error("code reflection cannot be used from generated functions")
341354
types = to_tuple_type(types)
355+
typesf = Tuple{typeof(f), types.parameters...}
342356
asts = []
343357
for x in _methods(f,types,-1)
358+
linfo = func_for_method_checked(x[3], types)
359+
srcinfo = checkambiguity(typesf, x[3])
360+
if srcinfo != nothing
361+
throw(AmbiguousError(typesf, srcinfo))
362+
end
344363
linfo = func_for_method_checked(x[3], types)
345364
if optimize
346365
(li, ty, inf) = Core.Inference.typeinf(linfo, x[1], x[2], true)

base/replutil.jl

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -247,6 +247,26 @@ end
247247
striptype{T}(::Type{T}) = T
248248
striptype(::Any) = nothing
249249

250+
function showerror(io::IO, ex::AmbiguousError)
251+
f = ex.args.parameters[1]
252+
args = ex.args.parameters[2:end]
253+
fname = string(f.name.name)[2:end]
254+
print(io, "AmbiguousError: ", fname, "(")
255+
for (i,a) in enumerate(args)
256+
print(io, "::", a)
257+
i == length(args) ? print(io, ")") : print(io, ", ")
258+
end
259+
print(io, " is ambiguous.")
260+
candidates = ex.srcinfo
261+
if candidates != true
262+
print(io, " Candidates:")
263+
for i = 1:2:length(candidates)
264+
print(io, "\n ", candidates[i], ":", candidates[i+1])
265+
end
266+
end
267+
nothing
268+
end
269+
250270
#Show an error by directly calling jl_printf.
251271
#Useful in Base submodule __init__ functions where STDERR isn't defined yet.
252272
function showerror_nostdio(err, msg::AbstractString)

src/alloc.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ jl_datatype_t *jl_errorexception_type=NULL;
5050
jl_datatype_t *jl_argumenterror_type;
5151
jl_datatype_t *jl_typeerror_type;
5252
jl_datatype_t *jl_methoderror_type;
53+
jl_datatype_t *jl_ambiguouserror_type;
5354
jl_datatype_t *jl_loaderror_type;
5455
jl_datatype_t *jl_initerror_type;
5556
jl_datatype_t *jl_undefvarerror_type;
@@ -476,6 +477,7 @@ static jl_lambda_info_t *jl_copy_lambda(jl_lambda_info_t *linfo)
476477
new_linfo->nargs = linfo->nargs;
477478
new_linfo->isva = linfo->isva;
478479
new_linfo->rettype = linfo->rettype;
480+
new_linfo->def = linfo->def;
479481
return new_linfo;
480482
}
481483

src/codegen.cpp

Lines changed: 57 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -352,6 +352,7 @@ static Function *jlthrow_func;
352352
static Function *jlerror_func;
353353
static Function *jltypeerror_func;
354354
static Function *jlundefvarerror_func;
355+
static Function *jlambiguouserror_func;
355356
static Function *jlboundserror_func;
356357
static Function *jluboundserror_func;
357358
static Function *jlvboundserror_func;
@@ -1094,7 +1095,7 @@ void *jl_get_llvmf(jl_tupletype_t *tt, bool getwrapper, bool getdeclarations)
10941095
jl_lambda_info_t *linfo = NULL;
10951096
JL_GC_PUSH2(&linfo, &tt);
10961097
if (tt != NULL) {
1097-
linfo = jl_get_specialization1(tt);
1098+
linfo = jl_checked_specialization1(tt);
10981099
if (linfo == NULL) {
10991100
jl_typemap_entry_t *entry;
11001101
linfo = jl_method_lookup_by_type(
@@ -1103,7 +1104,6 @@ void *jl_get_llvmf(jl_tupletype_t *tt, bool getwrapper, bool getdeclarations)
11031104
JL_GC_POP();
11041105
return NULL;
11051106
}
1106-
check_ambig_call(linfo->def, tt);
11071107
}
11081108
}
11091109
if (linfo == NULL) {
@@ -2687,6 +2687,19 @@ static jl_cgval_t emit_call_function_object(jl_lambda_info_t *li, const jl_cgval
26872687
expr_type(callexpr, ctx), ctx);
26882688
}
26892689

2690+
static void emit_ambiguous_call_error(jl_tupletype_t *tt, jl_array_t *ambiguities, jl_codectx_t *ctx)
2691+
{
2692+
//builder.SetInsertPoint(err);
2693+
#ifdef LLVM37
2694+
builder.CreateCall(prepare_call(jlambiguouserror_func), { literal_pointer_val((jl_value_t*)tt), literal_pointer_val((jl_value_t*)ambiguities) });
2695+
#else
2696+
builder.CreateCall2(prepare_call(jlambiguouserror_func), literal_pointer_val((jl_value_t*)tt), literal_pointer_val((jl_value_t*)ambiguities));
2697+
#endif
2698+
builder.CreateUnreachable();
2699+
BasicBlock *cont = BasicBlock::Create(jl_LLVMContext,"after_error",ctx->f);
2700+
builder.SetInsertPoint(cont);
2701+
}
2702+
26902703
static jl_cgval_t emit_call(jl_expr_t *ex, jl_codectx_t *ctx)
26912704
{
26922705
jl_value_t *expr = (jl_value_t*)ex;
@@ -2696,9 +2709,10 @@ static jl_cgval_t emit_call(jl_expr_t *ex, jl_codectx_t *ctx)
26962709
Value *theFptr = NULL;
26972710
jl_cgval_t result;
26982711
jl_value_t *aty = NULL;
2712+
jl_value_t *ambiguities = NULL;
26992713

27002714
jl_function_t *f = (jl_function_t*)static_eval(args[0], ctx, true);
2701-
JL_GC_PUSH2(&f, &aty);
2715+
JL_GC_PUSH3(&f, &aty, &ambiguities);
27022716
if (f != NULL) {
27032717
// function is a compile-time constant
27042718
if (jl_typeis(f, jl_intrinsic_type)) {
@@ -2738,30 +2752,39 @@ static jl_cgval_t emit_call(jl_expr_t *ex, jl_codectx_t *ctx)
27382752
jl_sprint(args[0]),
27392753
jl_sprint((jl_value_t*)aty));
27402754
}*/
2741-
jl_lambda_info_t *li = jl_get_specialization1((jl_tupletype_t*)aty);
2755+
jl_typemap_entry_t *entry;
2756+
jl_lambda_info_t *li = jl_get_specialization1((jl_tupletype_t*)aty, &entry);
27422757
if (li != NULL) {
2743-
assert(li->functionObjectsDecls.functionObject != NULL);
2744-
theFptr = (Value*)li->functionObjectsDecls.functionObject;
2745-
jl_cgval_t fval;
2746-
if (f != NULL) {
2747-
// TODO jb/functions: avoid making too many roots here
2748-
if (!jl_is_globalref(args[0]) && !jl_is_symbol(args[0]) &&
2749-
!jl_is_leaf_type(f)) {
2750-
if (ctx->linfo->def)
2751-
jl_add_linfo_root(ctx->linfo, f);
2752-
else // for toplevel thunks, just write the value back to the AST to root it
2753-
jl_cellset(ex->args, 0, f);
2754-
}
2755-
fval = mark_julia_const((jl_value_t*)f);
2758+
jl_method_t *m = li->def;
2759+
ambiguities = jl_list_call_ambiguities_((jl_tupletype_t*)aty, m);
2760+
if (ambiguities != jl_nothing) {
2761+
emit_ambiguous_call_error((jl_tupletype_t*)aty,
2762+
(jl_array_t*)ambiguities, ctx);
27562763
}
27572764
else {
2758-
fval = emit_expr(args[0], ctx);
2765+
assert(li->functionObjectsDecls.functionObject != NULL);
2766+
theFptr = (Value*)li->functionObjectsDecls.functionObject;
2767+
jl_cgval_t fval;
2768+
if (f != NULL) {
2769+
// TODO jb/functions: avoid making too many roots here
2770+
if (!jl_is_globalref(args[0]) && !jl_is_symbol(args[0]) &&
2771+
!jl_is_leaf_type(f)) {
2772+
if (ctx->linfo->def)
2773+
jl_add_linfo_root(ctx->linfo, f);
2774+
else // for toplevel thunks, just write the value back to the AST to root it
2775+
jl_cellset(ex->args, 0, f);
2776+
}
2777+
fval = mark_julia_const((jl_value_t*)f);
2778+
}
2779+
else {
2780+
fval = emit_expr(args[0], ctx);
2781+
}
2782+
if (ctx->linfo->def) // root this li in case it gets deleted from the cache in `f`
2783+
jl_add_linfo_root(ctx->linfo, (jl_value_t*)li);
2784+
result = emit_call_function_object(li, fval, theFptr, args, nargs, expr, ctx);
2785+
JL_GC_POP();
2786+
return result;
27592787
}
2760-
if (ctx->linfo->def) // root this li in case it gets deleted from the cache in `f`
2761-
jl_add_linfo_root(ctx->linfo, (jl_value_t*)li);
2762-
result = emit_call_function_object(li, fval, theFptr, args, nargs, expr, ctx);
2763-
JL_GC_POP();
2764-
return result;
27652788
}
27662789
}
27672790
}
@@ -3520,7 +3543,7 @@ static Function *gen_cfun_wrapper(jl_function_t *ff, jl_value_t *jlrettype, jl_t
35203543
jl_error("va_arg syntax not allowed for cfunction argument list");
35213544

35223545
const char *name = "cfunction";
3523-
jl_lambda_info_t *lam = jl_get_specialization1((jl_tupletype_t*)sigt);
3546+
jl_lambda_info_t *lam = jl_checked_specialization1((jl_tupletype_t*)sigt);
35243547
jl_value_t *astrt = (jl_value_t*)jl_any_type;
35253548
if (lam != NULL) {
35263549
name = jl_symbol_name(lam->def->name);
@@ -5198,6 +5221,16 @@ static void init_julia_llvm_env(Module *m)
51985221
jlundefvarerror_func->setDoesNotReturn();
51995222
add_named_global(jlundefvarerror_func, &jl_undefined_var_error);
52005223

5224+
std::vector<Type*> args2_ambiguouserror(0);
5225+
args2_ambiguouserror.push_back(T_pjlvalue);
5226+
args2_ambiguouserror.push_back(T_pjlvalue);
5227+
jlambiguouserror_func =
5228+
Function::Create(FunctionType::get(T_void, args2_ambiguouserror, false),
5229+
Function::ExternalLinkage,
5230+
"jl_ambiguous_call_error", m);
5231+
jlambiguouserror_func->setDoesNotReturn();
5232+
add_named_global(jlambiguouserror_func, &jl_ambiguous_call_error);
5233+
52015234
std::vector<Type*> args2_boundserrorv(0);
52025235
args2_boundserrorv.push_back(T_pjlvalue);
52035236
args2_boundserrorv.push_back(T_psize);

0 commit comments

Comments
 (0)