Skip to content

Commit 59eb9f9

Browse files
authored
remove Core._apply Builtin (#39115)
We can emulate this deprecated function, until we delete it in v2. This in turn revealed some missing error checks, which we also add. Fixes #39113
1 parent fa14d0b commit 59eb9f9

File tree

15 files changed

+48
-68
lines changed

15 files changed

+48
-68
lines changed

base/boot.jl

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -803,4 +803,7 @@ Integer(x::Union{Float16, Float32, Float64}) = Int(x)
803803
# The internal jl_parse which will call into Core._parse if not `nothing`.
804804
_parse = nothing
805805

806+
# support for deprecated uses of internal _apply function
807+
_apply(x...) = Core._apply_iterate(Main.Base.iterate, x...)
808+
806809
ccall(:jl_set_istopmod, Cvoid, (Any, Bool), Core, true)

base/compiler/abstractinterpretation.jl

Lines changed: 6 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -577,13 +577,7 @@ end
577577

578578
# simulate iteration protocol on container type up to fixpoint
579579
function abstract_iteration(interp::AbstractInterpreter, @nospecialize(itft), @nospecialize(itertype), sv::InferenceState)
580-
if !isdefined(Main, :Base) || !isdefined(Main.Base, :iterate) || !isconst(Main.Base, :iterate)
581-
return Any[Vararg{Any}], nothing
582-
end
583-
if itft === nothing
584-
iteratef = getfield(Main.Base, :iterate)
585-
itft = Const(iteratef)
586-
elseif isa(itft, Const)
580+
if isa(itft, Const)
587581
iteratef = itft.val
588582
else
589583
return Any[Vararg{Any}], nothing
@@ -595,6 +589,7 @@ function abstract_iteration(interp::AbstractInterpreter, @nospecialize(itft), @n
595589
# Return Bottom if this is not an iterator.
596590
# WARNING: Changes to the iteration protocol must be reflected here,
597591
# this is not just an optimization.
592+
# TODO: this doesn't realize that Array, SimpleVector, Tuple, and NamedTuple do not use the iterate protocol
598593
stateordonet === Bottom && return Any[Bottom], AbstractIterationInfo(CallMeta[CallMeta(Bottom, info)])
599594
valtype = statetype = Bottom
600595
ret = Any[]
@@ -658,7 +653,7 @@ function abstract_apply(interp::AbstractInterpreter, @nospecialize(itft), @nospe
658653
aftw = widenconst(aft)
659654
if !isa(aft, Const) && (!isType(aftw) || has_free_typevars(aftw))
660655
if !isconcretetype(aftw) || (aftw <: Builtin)
661-
add_remark!(interp, sv, "Core._apply called on a function of a non-concrete type")
656+
add_remark!(interp, sv, "Core._apply_iterate called on a function of a non-concrete type")
662657
# bail now, since it seems unlikely that abstract_call will be able to do any better after splitting
663658
# this also ensures we don't call abstract_call_gf_by_type below on an IntrinsicFunction or Builtin
664659
return CallMeta(Any, false)
@@ -805,7 +800,8 @@ function abstract_call_builtin(interp::AbstractInterpreter, f::Builtin, fargs::U
805800
end
806801
rt = builtin_tfunction(interp, f, argtypes[2:end], sv)
807802
if f === getfield && isa(fargs, Vector{Any}) && la == 3 && isa(argtypes[3], Const) && isa(argtypes[3].val, Int) && argtypes[2] Tuple
808-
cti, _ = precise_container_type(interp, nothing, argtypes[2], sv)
803+
# TODO: why doesn't this use the getfield_tfunc?
804+
cti, _ = precise_container_type(interp, iterate, argtypes[2], sv)
809805
idx = argtypes[3].val
810806
if 1 <= idx <= length(cti)
811807
rt = unwrapva(cti[idx])
@@ -923,11 +919,7 @@ function abstract_call_known(interp::AbstractInterpreter, @nospecialize(f),
923919
la = length(argtypes)
924920

925921
if isa(f, Builtin)
926-
if f === _apply
927-
ft = argtype_by_index(argtypes, 2)
928-
ft === Bottom && return CallMeta(Bottom, false)
929-
return abstract_apply(interp, nothing, ft, argtype_tail(argtypes, 3), sv, max_methods)
930-
elseif f === _apply_iterate
922+
if f === _apply_iterate
931923
itft = argtype_by_index(argtypes, 2)
932924
ft = argtype_by_index(argtypes, 3)
933925
(itft === Bottom || ft === Bottom) && return CallMeta(Bottom, false)

base/compiler/compiler.jl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
# This file is a part of Julia. License is MIT: https://julialang.org/license
22

3-
getfield(getfield(Main, :Core), :eval)(getfield(Main, :Core), :(baremodule Compiler
3+
getfield(Core, :eval)(Core, :(baremodule Compiler
44

55
using Core.Intrinsics, Core.IR
66

77
import Core: print, println, show, write, unsafe_write, stdout, stderr,
8-
_apply, _apply_iterate, svec, apply_type, Builtin, IntrinsicFunction,
8+
_apply_iterate, svec, apply_type, Builtin, IntrinsicFunction,
99
MethodInstance, CodeInstance, MethodMatch
1010

1111
const getproperty = Core.getfield

base/compiler/optimize.jl

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -326,19 +326,19 @@ function statement_cost(ex::Expr, line::Int, src::CodeInfo, sptypes::Vector{Any}
326326
# The efficiency of operations like a[i] and s.b
327327
# depend strongly on whether the result can be
328328
# inferred, so check the type of ex
329-
if f === Main.Core.getfield || f === Main.Core.tuple
329+
if f === Core.getfield || f === Core.tuple
330330
# we might like to penalize non-inferrability, but
331331
# tuple iteration/destructuring makes that impossible
332332
# return plus_saturate(argcost, isknowntype(extyp) ? 1 : params.inline_nonleaf_penalty)
333333
return 0
334-
elseif f === Main.Core.isa
334+
elseif f === Core.isa
335335
# If we're in a union context, we penalize type computations
336336
# on union types. In such cases, it is usually better to perform
337337
# union splitting on the outside.
338338
if union_penalties && isa(argextype(ex.args[2], src, sptypes, slottypes), Union)
339339
return params.inline_nonleaf_penalty
340340
end
341-
elseif (f === Main.Core.arrayref || f === Main.Core.const_arrayref) && length(ex.args) >= 3
341+
elseif (f === Core.arrayref || f === Core.const_arrayref) && length(ex.args) >= 3
342342
atyp = argextype(ex.args[3], src, sptypes, slottypes)
343343
return isknowntype(atyp) ? 4 : error_path ? params.inline_error_path_cost : params.inline_nonleaf_penalty
344344
end

base/compiler/ssair/inlining.jl

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -573,7 +573,7 @@ function batch_inline!(todo::Vector{Pair{Int, Any}}, ir::IRCode, linetable::Vect
573573
return ir
574574
end
575575

576-
# This assumes the caller has verified that all arguments to the _apply call are Tuples.
576+
# This assumes the caller has verified that all arguments to the _apply_iterate call are Tuples.
577577
function rewrite_apply_exprargs!(ir::IRCode, todo::Vector{Pair{Int, Any}}, idx::Int,
578578
argexprs::Vector{Any}, atypes::Vector{Any}, arginfos::Vector{Any},
579579
arg_start::Int, et::Union{EdgeTracker, Nothing}, caches::Union{InferenceCaches, Nothing},
@@ -909,7 +909,7 @@ end
909909
function inline_apply!(ir::IRCode, todo::Vector{Pair{Int, Any}}, idx::Int, sig::Signature,
910910
et, caches, params::OptimizationParams)
911911
stmt = ir.stmts[idx][:inst]
912-
while sig.f === Core._apply || sig.f === Core._apply_iterate
912+
while sig.f === Core._apply_iterate
913913
info = ir.stmts[idx][:info]
914914
if isa(info, UnionSplitApplyCallInfo)
915915
if length(info.infos) != 1
@@ -923,7 +923,7 @@ function inline_apply!(ir::IRCode, todo::Vector{Pair{Int, Any}}, idx::Int, sig::
923923
@assert info === nothing || info === false
924924
new_info = info = nothing
925925
end
926-
arg_start = sig.f === Core._apply ? 2 : 3
926+
arg_start = 3
927927
atypes = sig.atypes
928928
if arg_start > length(atypes)
929929
return nothing
@@ -1010,7 +1010,7 @@ function process_simple!(ir::IRCode, todo::Vector{Pair{Int, Any}}, idx::Int, sta
10101010
sig = call_sig(ir, stmt)
10111011
sig === nothing && return nothing
10121012

1013-
# Handle _apply
1013+
# Handle _apply_iterate
10141014
sig = inline_apply!(ir, todo, idx, sig, state.et, state.caches, state.params)
10151015
sig === nothing && return nothing
10161016

base/compiler/types.jl

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -102,14 +102,14 @@ struct InferenceParams
102102
# before computing the set of matching methods
103103
MAX_UNION_SPLITTING::Int
104104
# the maximum number of union-tuples to swap / expand
105-
# when inferring a call to _apply
105+
# when inferring a call to _apply_iterate
106106
MAX_APPLY_UNION_ENUM::Int
107107

108108
# parameters limiting large (tuple) types
109109
TUPLE_COMPLEXITY_LIMIT_DEPTH::Int
110110

111-
# when attempting to inlining _apply, abort the optimization if the tuple
112-
# contains more than this many elements
111+
# when attempting to inline _apply_iterate, abort the optimization if the
112+
# tuple contains more than this many elements
113113
MAX_TUPLE_SPLAT::Int
114114

115115
function InferenceParams(;

src/builtin_proto.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ extern "C" {
2222
DECLARE_BUILTIN(throw); DECLARE_BUILTIN(is);
2323
DECLARE_BUILTIN(typeof); DECLARE_BUILTIN(sizeof);
2424
DECLARE_BUILTIN(issubtype); DECLARE_BUILTIN(isa);
25-
DECLARE_BUILTIN(_apply); DECLARE_BUILTIN(_apply_pure);
25+
DECLARE_BUILTIN(_apply_pure);
2626
DECLARE_BUILTIN(_call_latest); DECLARE_BUILTIN(_apply_iterate);
2727
DECLARE_BUILTIN(_call_in_world);
2828
DECLARE_BUILTIN(isdefined); DECLARE_BUILTIN(nfields);

src/builtins.c

Lines changed: 4 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -525,7 +525,7 @@ STATIC_INLINE void _grow_to(jl_value_t **root, jl_value_t ***oldargs, jl_svec_t
525525

526526
static jl_function_t *jl_iterate_func JL_GLOBALLY_ROOTED;
527527

528-
static jl_value_t *do_apply(jl_value_t *F, jl_value_t **args, uint32_t nargs, jl_value_t *iterate)
528+
static jl_value_t *do_apply( jl_value_t **args, uint32_t nargs, jl_value_t *iterate)
529529
{
530530
jl_function_t *f = args[0];
531531
if (nargs == 2) {
@@ -567,12 +567,7 @@ static jl_value_t *do_apply(jl_value_t *F, jl_value_t **args, uint32_t nargs, jl
567567
}
568568
}
569569
if (extra && iterate == NULL) {
570-
if (jl_iterate_func == NULL) {
571-
jl_iterate_func = jl_get_function(jl_top_module, "iterate");
572-
if (jl_iterate_func == NULL)
573-
jl_undefined_var_error(jl_symbol("iterate"));
574-
}
575-
iterate = jl_iterate_func;
570+
jl_undefined_var_error(jl_symbol("iterate"));
576571
}
577572
// allocate space for the argument array and gc roots for it
578573
// based on our previous estimates
@@ -696,13 +691,7 @@ static jl_value_t *do_apply(jl_value_t *F, jl_value_t **args, uint32_t nargs, jl
696691
JL_CALLABLE(jl_f__apply_iterate)
697692
{
698693
JL_NARGSV(_apply_iterate, 2);
699-
return do_apply(F, args+1, nargs-1, args[0]);
700-
}
701-
702-
JL_CALLABLE(jl_f__apply)
703-
{
704-
JL_NARGSV(_apply, 1);
705-
return do_apply(F, args, nargs, NULL);
694+
return do_apply(args + 1, nargs - 1, args[0]);
706695
}
707696

708697
// this is like `_apply`, but with quasi-exact checks to make sure it is pure
@@ -720,7 +709,7 @@ JL_CALLABLE(jl_f__apply_pure)
720709
// and `promote` works better this way
721710
size_t last_age = ptls->world_age;
722711
ptls->world_age = jl_world_counter;
723-
ret = jl_f__apply(NULL, args, nargs);
712+
ret = do_apply(args, nargs, NULL);
724713
ptls->world_age = last_age;
725714
ptls->in_pure_callback = last_in;
726715
}
@@ -1578,7 +1567,6 @@ void jl_init_primitives(void) JL_GC_DISABLED
15781567

15791568
// internal functions
15801569
jl_builtin_apply_type = add_builtin_func("apply_type", jl_f_apply_type);
1581-
jl_builtin__apply = add_builtin_func("_apply", jl_f__apply);
15821570
jl_builtin__apply_iterate = add_builtin_func("_apply_iterate", jl_f__apply_iterate);
15831571
jl_builtin__expr = add_builtin_func("_expr", jl_f__expr);
15841572
jl_builtin_svec = add_builtin_func("svec", jl_f_svec);

src/codegen.cpp

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -838,7 +838,6 @@ static const std::map<jl_fptr_args_t, JuliaFunction*> builtin_func_map = {
838838
{ &jl_f_isa, new JuliaFunction{"jl_f_isa", get_func_sig, get_func_attrs} },
839839
{ &jl_f_typeassert, new JuliaFunction{"jl_f_typeassert", get_func_sig, get_func_attrs} },
840840
{ &jl_f_ifelse, new JuliaFunction{"jl_f_ifelse", get_func_sig, get_func_attrs} },
841-
{ &jl_f__apply, new JuliaFunction{"jl_f__apply", get_func_sig, get_func_attrs} },
842841
{ &jl_f__apply_iterate, new JuliaFunction{"jl_f__apply_iterate", get_func_sig, get_func_attrs} },
843842
{ &jl_f__apply_pure, new JuliaFunction{"jl_f__apply_pure", get_func_sig, get_func_attrs} },
844843
{ &jl_f__call_latest, new JuliaFunction{"jl_f__call_latest", get_func_sig, get_func_attrs} },
@@ -2684,13 +2683,11 @@ static bool emit_builtin_call(jl_codectx_t &ctx, jl_cgval_t *ret, jl_value_t *f,
26842683
}
26852684
}
26862685

2687-
else if (((f == jl_builtin__apply && nargs == 2) ||
2688-
(f == jl_builtin__apply_iterate && nargs == 3)) && ctx.vaSlot > 0) {
2689-
int arg_start = f == jl_builtin__apply ? 2 : 3;
2690-
// turn Core._apply(f, Tuple) ==> f(Tuple...) using the jlcall calling convention if Tuple is the va allocation
2691-
if (LoadInst *load = dyn_cast_or_null<LoadInst>(argv[arg_start].V)) {
2686+
else if ((f == jl_builtin__apply_iterate && nargs == 3) && ctx.vaSlot > 0) {
2687+
// turn Core._apply_iterate(iter, f, Tuple) ==> f(Tuple...) using the jlcall calling convention if Tuple is the va allocation
2688+
if (LoadInst *load = dyn_cast_or_null<LoadInst>(argv[3].V)) {
26922689
if (load->getPointerOperand() == ctx.slots[ctx.vaSlot].boxroot && ctx.argArray) {
2693-
Value *theF = boxed(ctx, argv[arg_start-1]);
2690+
Value *theF = boxed(ctx, argv[2]);
26942691
Value *nva = emit_n_varargs(ctx);
26952692
#ifdef _P64
26962693
nva = ctx.builder.CreateTrunc(nva, T_int32);

src/module.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -623,6 +623,8 @@ JL_DLLEXPORT jl_value_t *jl_get_global(jl_module_t *m, jl_sym_t *var)
623623

624624
JL_DLLEXPORT void jl_set_global(jl_module_t *m JL_ROOTING_ARGUMENT, jl_sym_t *var, jl_value_t *val JL_ROOTED_ARGUMENT)
625625
{
626+
JL_TYPECHK(jl_set_global, module, (jl_value_t*)m);
627+
JL_TYPECHK(jl_set_global, symbol, (jl_value_t*)var);
626628
jl_binding_t *bp = jl_get_binding_wr(m, var, 1);
627629
JL_GC_PROMISE_ROOTED(bp);
628630
jl_checked_assignment(bp, val);

src/staticdata.c

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ extern "C" {
3030
// TODO: put WeakRefs on the weak_refs list during deserialization
3131
// TODO: handle finalizers
3232

33-
#define NUM_TAGS 145
33+
#define NUM_TAGS 144
3434

3535
// An array of references that need to be restored from the sysimg
3636
// This is a manually constructed dual of the gvars array, which would be produced by codegen for Julia code, for C.
@@ -175,7 +175,6 @@ jl_value_t **const*const get_tags(void) {
175175
INSERT_TAG(jl_builtin_issubtype);
176176
INSERT_TAG(jl_builtin_isa);
177177
INSERT_TAG(jl_builtin_typeassert);
178-
INSERT_TAG(jl_builtin__apply);
179178
INSERT_TAG(jl_builtin__apply_iterate);
180179
INSERT_TAG(jl_builtin_isdefined);
181180
INSERT_TAG(jl_builtin_nfields);
@@ -235,7 +234,7 @@ void *native_functions;
235234
// This is a manually constructed dual of the fvars array, which would be produced by codegen for Julia code, for C.
236235
static const jl_fptr_args_t id_to_fptrs[] = {
237236
&jl_f_throw, &jl_f_is, &jl_f_typeof, &jl_f_issubtype, &jl_f_isa,
238-
&jl_f_typeassert, &jl_f__apply, &jl_f__apply_iterate, &jl_f__apply_pure,
237+
&jl_f_typeassert, &jl_f__apply_iterate, &jl_f__apply_pure,
239238
&jl_f__call_latest, &jl_f__call_in_world, &jl_f_isdefined,
240239
&jl_f_tuple, &jl_f_svec, &jl_f_intrinsic_call, &jl_f_invoke_kwsorter,
241240
&jl_f_getfield, &jl_f_setfield, &jl_f_fieldtype, &jl_f_nfields,

src/toplevel.c

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -45,15 +45,13 @@ JL_DLLEXPORT void jl_add_standard_imports(jl_module_t *m)
4545
// create a new top-level module
4646
void jl_init_main_module(void)
4747
{
48-
if (jl_main_module != NULL)
49-
jl_error("Main module already initialized.");
50-
48+
assert(jl_main_module == NULL);
5149
jl_main_module = jl_new_module(jl_symbol("Main"));
5250
jl_main_module->parent = jl_main_module;
5351
jl_set_const(jl_main_module, jl_symbol("Core"),
5452
(jl_value_t*)jl_core_module);
55-
jl_set_global(jl_core_module, jl_symbol("Main"),
56-
(jl_value_t*)jl_main_module);
53+
jl_set_const(jl_core_module, jl_symbol("Main"),
54+
(jl_value_t*)jl_main_module);
5755
}
5856

5957
static jl_function_t *jl_module_get_initializer(jl_module_t *m JL_PROPAGATES_ROOT)

stdlib/InteractiveUtils/src/macros.jl

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -153,12 +153,12 @@ function gen_call_with_extracted_types(__module__, fcn, ex0, kws=Expr[])
153153
exret = Expr(:none)
154154
if ex.head === :call
155155
if any(e->(isa(e, Expr) && e.head === :(...)), ex0.args) &&
156-
(ex.args[1] === GlobalRef(Core,:_apply) ||
157-
ex.args[1] === GlobalRef(Base,:_apply))
156+
(ex.args[1] === GlobalRef(Core,:_apply_iterate) ||
157+
ex.args[1] === GlobalRef(Base,:_apply_iterate))
158158
# check for splatting
159-
exret = Expr(:call, ex.args[1], fcn,
160-
Expr(:tuple, esc(ex.args[2]),
161-
Expr(:call, typesof, map(esc, ex.args[3:end])...)))
159+
exret = Expr(:call, ex.args[2], fcn,
160+
Expr(:tuple, esc(ex.args[3]),
161+
Expr(:call, typesof, map(esc, ex.args[4:end])...)))
162162
else
163163
exret = Expr(:call, fcn, esc(ex.args[1]),
164164
Expr(:call, typesof, map(esc, ex.args[2:end])...), kws...)

test/compiler/inference.jl

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -855,7 +855,7 @@ end
855855
aa20704(x) = x(nothing)
856856
@test code_typed(aa20704, (typeof(a20704),))[1][1].pure
857857

858-
#issue #21065, elision of _apply when splatted expression is not effect_free
858+
#issue #21065, elision of _apply_iterate when splatted expression is not effect_free
859859
function f21065(x,y)
860860
println("x=$x, y=$y")
861861
return x, y
@@ -865,7 +865,7 @@ function test_no_apply(expr::Expr)
865865
return all(test_no_apply, expr.args)
866866
end
867867
function test_no_apply(ref::GlobalRef)
868-
return ref.mod != Core || ref.name !== :_apply
868+
return ref.mod != Core || ref.name !== :_apply_iterate
869869
end
870870
test_no_apply(::Any) = true
871871
@test all(test_no_apply, code_typed(g21065, Tuple{Int,Int})[1].first.code)
@@ -2041,6 +2041,7 @@ T27078 = Vector{Vector{T}} where T
20412041
# issue #28070
20422042
g28070(f, args...) = f(args...)
20432043
@test @inferred g28070(Core._apply, Base.:/, (1.0, 1.0)) == 1.0
2044+
@test @inferred g28070(Core._apply_iterate, Base.iterate, Base.:/, (1.0, 1.0)) == 1.0
20442045

20452046
# issue #28079
20462047
struct Foo28079 end
@@ -2298,9 +2299,9 @@ end
22982299

22992300
@test @inferred(g28955((1,), 1.0)) === Bool
23002301

2301-
# Test that inlining can look through repeated _applys
2302+
# Test that inlining can look through repeated _apply_iterates
23022303
foo_inlining_apply(args...) = ccall(:jl_, Nothing, (Any,), args[1])
2303-
bar_inlining_apply() = Core._apply(Core._apply, (foo_inlining_apply,), ((1,),))
2304+
bar_inlining_apply() = Core._apply_iterate(iterate, Core._apply_iterate, (iterate,), (foo_inlining_apply,), ((1,),))
23042305
let ci = code_typed(bar_inlining_apply, Tuple{})[1].first
23052306
@test length(ci.code) == 2
23062307
@test ci.code[1].head == :foreigncall

test/compiler/inline.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -175,7 +175,7 @@ end
175175
# 2 for now because the compiler leaves a GotoNode around
176176
@test_broken length(code_typed(f_ifelse, (String,))[1][1].code) <= 2
177177

178-
# Test that inlining of _apply properly hits the inference cache
178+
# Test that inlining of _apply_iterate properly hits the inference cache
179179
@noinline cprop_inline_foo1() = (1, 1)
180180
@noinline cprop_inline_foo2() = (2, 2)
181181
function cprop_inline_bar(x...)

0 commit comments

Comments
 (0)