diff --git a/base/Base.jl b/base/Base.jl index 63728fdba3e4e..f8df4047eb6fa 100644 --- a/base/Base.jl +++ b/base/Base.jl @@ -103,6 +103,17 @@ include("generator.jl") include("reflection.jl") include("options.jl") +# define invoke(f, T, args...; kwargs...), without kwargs wrapping +# to forward to invoke +function Core.kwcall(kwargs, ::typeof(invoke), f, T, args...) + @inline + # prepend kwargs and f to the invoked from the user + T = rewrap_unionall(Tuple{Any, Core.Typeof(f), (unwrap_unionall(T)::DataType).parameters...}, T) + return invoke(Core.kwcall, T, kwargs, f, args...) +end +# invoke does not have its own call cache, but kwcall for invoke does +typeof(invoke).name.mt.max_args = 3 # invoke, f, T, args... + # core operations & types include("promotion.jl") include("tuple.jl") diff --git a/base/boot.jl b/base/boot.jl index 85e50b626185f..80ef23cd0fd78 100644 --- a/base/boot.jl +++ b/base/boot.jl @@ -369,11 +369,11 @@ include(m::Module, fname::String) = ccall(:jl_load_, Any, (Any, Any), m, fname) eval(m::Module, @nospecialize(e)) = ccall(:jl_toplevel_eval_in, Any, (Any, Any), m, e) +# dispatch token indicating a kwarg (keyword sorter) call function kwcall end +# deprecated internal functions: kwfunc(@nospecialize(f)) = kwcall kwftype(@nospecialize(t)) = typeof(kwcall) -kwcall(kwargs, ::typeof(invoke), f, T, args...) = kwinvoke(kwargs, invoke, f, T, args...) -# invoke(f, T, args...; kwargs...) = kwinvoke(kwargs, invoke, f, T, args...) mutable struct Box contents::Any diff --git a/src/builtin_proto.h b/src/builtin_proto.h index d2fa595013d59..64e3fbd1af366 100644 --- a/src/builtin_proto.h +++ b/src/builtin_proto.h @@ -42,7 +42,6 @@ DECLARE_BUILTIN(is); DECLARE_BUILTIN(isa); DECLARE_BUILTIN(isdefined); DECLARE_BUILTIN(issubtype); -DECLARE_BUILTIN(kwinvoke); DECLARE_BUILTIN(modifyfield); DECLARE_BUILTIN(nfields); DECLARE_BUILTIN(setfield); diff --git a/src/builtins.c b/src/builtins.c index 8e56b25a2c6ca..323a42b91ca92 100644 --- a/src/builtins.c +++ b/src/builtins.c @@ -1359,50 +1359,6 @@ JL_CALLABLE(jl_f_invoke) return res; } -JL_CALLABLE(jl_f_kwinvoke) -{ - JL_NARGSV(invoke, 3); - jl_value_t *kwargs = args[0]; - // args[1] is `invoke` itself - jl_value_t *func = args[2]; - jl_value_t *argtypes = args[3]; - jl_value_t *kws = jl_kwcall_func; - JL_GC_PUSH1(&argtypes); - if (jl_is_tuple_type(argtypes)) { - // construct a tuple type for invoking a keyword sorter by putting the kw container type - // and the type of the function at the front. - size_t i, nt = jl_nparams(argtypes) + 2; - if (nt < jl_page_size/sizeof(jl_value_t*)) { - jl_value_t **types = (jl_value_t**)alloca(nt*sizeof(jl_value_t*)); - types[0] = (jl_value_t*)jl_namedtuple_type; - types[1] = jl_is_type(func) ? (jl_value_t*)jl_wrap_Type(func) : jl_typeof(func); - for (i = 2; i < nt; i++) - types[i] = jl_tparam(argtypes, i - 2); - argtypes = (jl_value_t*)jl_apply_tuple_type_v(types, nt); - } - else { - jl_svec_t *types = jl_alloc_svec_uninit(nt); - JL_GC_PUSH1(&types); - jl_svecset(types, 0, jl_namedtuple_type); - jl_svecset(types, 1, jl_is_type(func) ? (jl_value_t*)jl_wrap_Type(func) : jl_typeof(func)); - for (i = 2; i < nt; i++) - jl_svecset(types, i, jl_tparam(argtypes, i - 2)); - argtypes = (jl_value_t*)jl_apply_tuple_type(types); - JL_GC_POP(); - } - } - else { - // invoke will throw an error - } - args[0] = kws; - args[1] = argtypes; - args[2] = kwargs; - args[3] = func; - jl_value_t *res = jl_f_invoke(NULL, args, nargs); - JL_GC_POP(); - return res; -} - // Expr constructor for internal use ------------------------------------------ jl_expr_t *jl_exprn(jl_sym_t *head, size_t n) @@ -2011,7 +1967,6 @@ void jl_init_primitives(void) JL_GC_DISABLED // method table utils jl_builtin_applicable = add_builtin_func("applicable", jl_f_applicable); jl_builtin_invoke = add_builtin_func("invoke", jl_f_invoke); - jl_builtin_kwinvoke = add_builtin_func("kwinvoke", jl_f_kwinvoke); // internal functions jl_builtin_apply_type = add_builtin_func("apply_type", jl_f_apply_type); diff --git a/src/codegen.cpp b/src/codegen.cpp index 8477c3c9c1427..b00a07e664a68 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -1169,7 +1169,6 @@ static const auto &builtin_func_map() { { jl_f_svec_addr, new JuliaFunction{XSTR(jl_f_svec), get_func_sig, get_func_attrs} }, { jl_f_applicable_addr, new JuliaFunction{XSTR(jl_f_applicable), get_func_sig, get_func_attrs} }, { jl_f_invoke_addr, new JuliaFunction{XSTR(jl_f_invoke), get_func_sig, get_func_attrs} }, - { jl_f_kwinvoke_addr, new JuliaFunction{XSTR(jl_f_kwinvoke), get_func_sig, get_func_attrs} }, { jl_f_isdefined_addr, new JuliaFunction{XSTR(jl_f_isdefined), get_func_sig, get_func_attrs} }, { jl_f_getfield_addr, new JuliaFunction{XSTR(jl_f_getfield), get_func_sig, get_func_attrs} }, { jl_f_setfield_addr, new JuliaFunction{XSTR(jl_f_setfield), get_func_sig, get_func_attrs} }, diff --git a/src/staticdata.c b/src/staticdata.c index 0952331ba6354..c1ae4bb249b51 100644 --- a/src/staticdata.c +++ b/src/staticdata.c @@ -81,7 +81,7 @@ extern "C" { // TODO: put WeakRefs on the weak_refs list during deserialization // TODO: handle finalizers -#define NUM_TAGS 159 +#define NUM_TAGS 157 // An array of references that need to be restored from the sysimg // This is a manually constructed dual of the gvars array, which would be produced by codegen for Julia code, for C. @@ -251,7 +251,6 @@ jl_value_t **const*const get_tags(void) { INSERT_TAG(jl_builtin_apply_type); INSERT_TAG(jl_builtin_applicable); INSERT_TAG(jl_builtin_invoke); - INSERT_TAG(jl_builtin_kwinvoke); INSERT_TAG(jl_builtin__expr); INSERT_TAG(jl_builtin_ifelse); INSERT_TAG(jl_builtin__typebody); @@ -312,7 +311,7 @@ static const jl_fptr_args_t id_to_fptrs[] = { &jl_f_throw, &jl_f_is, &jl_f_typeof, &jl_f_issubtype, &jl_f_isa, &jl_f_typeassert, &jl_f__apply_iterate, &jl_f__apply_pure, &jl_f__call_latest, &jl_f__call_in_world, &jl_f__call_in_world_total, &jl_f_isdefined, - &jl_f_tuple, &jl_f_svec, &jl_f_intrinsic_call, &jl_f_kwinvoke, + &jl_f_tuple, &jl_f_svec, &jl_f_intrinsic_call, &jl_f_getfield, &jl_f_setfield, &jl_f_swapfield, &jl_f_modifyfield, &jl_f_replacefield, &jl_f_fieldtype, &jl_f_nfields, &jl_f_arrayref, &jl_f_const_arrayref, &jl_f_arrayset, &jl_f_arraysize, &jl_f_apply_type, diff --git a/test/reduce.jl b/test/reduce.jl index 68e0fbaf00fc0..84d93b12913e4 100644 --- a/test/reduce.jl +++ b/test/reduce.jl @@ -161,11 +161,13 @@ sum3(A) = reduce(plus, A) sum4(itr) = invoke(reduce, Tuple{Function, Any}, plus, itr) sum5(A) = reduce(plus, A; init=0) sum6(itr) = invoke(Core.kwcall, Tuple{NamedTuple{(:init,), Tuple{Int}}, typeof(reduce), Function, Any}, (init=0,), reduce, plus, itr) +sum61(itr) = invoke(reduce, Tuple{Function, Any}, init=0, plus, itr) sum7(A) = mapreduce(x->x, plus, A) sum8(itr) = invoke(mapreduce, Tuple{Function, Function, Any}, x->x, plus, itr) sum9(A) = mapreduce(x->x, plus, A; init=0) sum10(itr) = invoke(Core.kwcall, Tuple{NamedTuple{(:init,),Tuple{Int}}, typeof(mapreduce), Function, Function, Any}, (init=0,), mapreduce, x->x, plus, itr) -for f in (sum2, sum5, sum6, sum9, sum10) +sum11(itr) = invoke(mapreduce, Tuple{Function, Function, Any}, init=0, x->x, plus, itr) +for f in (sum2, sum5, sum6, sum61, sum9, sum10, sum11) @test sum(z) == f(z) @test sum(Int[]) == f(Int[]) == 0 @test sum(Int[7]) == f(Int[7]) == 7