Skip to content

Commit 93b89b9

Browse files
authored
reduce precompile() failure severity to a warning (#39905)
Many users (including Base) are calling `@assert`, despite that this is not what assert should be used to mark, for many reasons. This happened to also reveal a small number of errors, so also detect those (for fixing later). Refs: c0f9666#commitcomment-47782674
1 parent 3276c11 commit 93b89b9

File tree

5 files changed

+108
-86
lines changed

5 files changed

+108
-86
lines changed

base/compiler/abstractinterpretation.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -970,6 +970,7 @@ end
970970

971971
function abstract_call_builtin(interp::AbstractInterpreter, f::Builtin, fargs::Union{Nothing,Vector{Any}},
972972
argtypes::Vector{Any}, sv::InferenceState, max_methods::Int)
973+
@nospecialize f
973974
la = length(argtypes)
974975
if f === ifelse && fargs isa Vector{Any} && la == 4
975976
cnd = argtypes[2]

base/essentials.jl

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -483,19 +483,6 @@ sizeof(x) = Core.sizeof(x)
483483
# simple Array{Any} operations needed for bootstrap
484484
@eval setindex!(A::Array{Any}, @nospecialize(x), i::Int) = arrayset($(Expr(:boundscheck)), A, x, i)
485485

486-
"""
487-
precompile(f, args::Tuple{Vararg{Any}})
488-
489-
Compile the given function `f` for the argument tuple (of types) `args`, but do not execute it.
490-
"""
491-
function precompile(@nospecialize(f), args::Tuple)
492-
ccall(:jl_compile_hint, Int32, (Any,), Tuple{Core.Typeof(f), args...}) != 0
493-
end
494-
495-
function precompile(argt::Type)
496-
ccall(:jl_compile_hint, Int32, (Any,), argt) != 0
497-
end
498-
499486
"""
500487
esc(e)
501488

base/loading.jl

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1218,11 +1218,9 @@ function include_package_for_output(pkg::PkgId, input::String, depot_path::Vecto
12181218
end
12191219
end
12201220

1221-
@assert precompile(include_package_for_output, (PkgId,String,Vector{String},Vector{String},Vector{String},typeof(_concrete_dependencies),Nothing))
1222-
@assert precompile(include_package_for_output, (PkgId,String,Vector{String},Vector{String},Vector{String},typeof(_concrete_dependencies),String))
1223-
12241221
const PRECOMPILE_TRACE_COMPILE = Ref{String}()
12251222
function create_expr_cache(pkg::PkgId, input::String, output::String, concrete_deps::typeof(_concrete_dependencies), internal_stderr::IO = stderr, internal_stdout::IO = stdout)
1223+
@nospecialize internal_stderr internal_stdout
12261224
rm(output, force=true) # Remove file if it exists
12271225
depot_path = map(abspath, DEPOT_PATH)
12281226
dl_load_path = map(abspath, DL_LOAD_PATH)
@@ -1261,9 +1259,6 @@ function create_expr_cache(pkg::PkgId, input::String, output::String, concrete_d
12611259
return io
12621260
end
12631261

1264-
@assert precompile(create_expr_cache, (PkgId, String, String, typeof(_concrete_dependencies), typeof(stderr), typeof(stdout)))
1265-
@assert precompile(create_expr_cache, (PkgId, String, String, typeof(_concrete_dependencies), typeof(stderr), typeof(stdout)))
1266-
12671262
function compilecache_dir(pkg::PkgId)
12681263
entrypath, entryfile = cache_file_entry(pkg)
12691264
return joinpath(DEPOT_PATH[1], entrypath)
@@ -1294,6 +1289,7 @@ This can be used to reduce package load times. Cache files are stored in
12941289
for important notes.
12951290
"""
12961291
function compilecache(pkg::PkgId, internal_stderr::IO = stderr, internal_stdout::IO = stdout)
1292+
@nospecialize internal_stderr internal_stdout
12971293
path = locate_package(pkg)
12981294
path === nothing && throw(ArgumentError("$pkg not found during precompilation"))
12991295
return compilecache(pkg, path, internal_stderr, internal_stdout)
@@ -1302,6 +1298,7 @@ end
13021298
const MAX_NUM_PRECOMPILE_FILES = Ref(10)
13031299

13041300
function compilecache(pkg::PkgId, path::String, internal_stderr::IO = stderr, internal_stdout::IO = stdout)
1301+
@nospecialize internal_stderr internal_stdout
13051302
# decide where to put the resulting cache file
13061303
cachepath = compilecache_dir(pkg)
13071304

@@ -1810,3 +1807,23 @@ macro __DIR__()
18101807
_dirname = dirname(String(__source__.file::Symbol))
18111808
return isempty(_dirname) ? pwd() : abspath(_dirname)
18121809
end
1810+
1811+
"""
1812+
precompile(f, args::Tuple{Vararg{Any}})
1813+
1814+
Compile the given function `f` for the argument tuple (of types) `args`, but do not execute it.
1815+
"""
1816+
function precompile(@nospecialize(f), args::Tuple)
1817+
precompile(Tuple{Core.Typeof(f), args...})
1818+
end
1819+
1820+
function precompile(argt::Type)
1821+
if ccall(:jl_compile_hint, Int32, (Any,), argt) == 0
1822+
@warn "Inactive precompile statement" maxlog=100 form=argt _module=nothing _file=nothing _line=0
1823+
end
1824+
true
1825+
end
1826+
1827+
precompile(include_package_for_output, (PkgId, String, Vector{String}, Vector{String}, Vector{String}, typeof(_concrete_dependencies), Nothing))
1828+
precompile(include_package_for_output, (PkgId, String, Vector{String}, Vector{String}, Vector{String}, typeof(_concrete_dependencies), String))
1829+
precompile(create_expr_cache, (PkgId, String, String, typeof(_concrete_dependencies), IO, IO))

contrib/generate_precompile.jl

Lines changed: 82 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -17,32 +17,32 @@ DOWN_ARROW = "\e[B"
1717

1818
hardcoded_precompile_statements = """
1919
# used by Revise.jl
20-
@assert precompile(Tuple{typeof(Base.parse_cache_header), String})
21-
@assert precompile(Base.read_dependency_src, (String, String))
20+
precompile(Tuple{typeof(Base.parse_cache_header), String})
21+
precompile(Base.read_dependency_src, (String, String))
2222
2323
# used by Requires.jl
24-
@assert precompile(Tuple{typeof(get!), Type{Vector{Function}}, Dict{Base.PkgId,Vector{Function}}, Base.PkgId})
25-
@assert precompile(Tuple{typeof(haskey), Dict{Base.PkgId,Vector{Function}}, Base.PkgId})
26-
@assert precompile(Tuple{typeof(delete!), Dict{Base.PkgId,Vector{Function}}, Base.PkgId})
27-
@assert precompile(Tuple{typeof(push!), Vector{Function}, Function})
24+
precompile(Tuple{typeof(get!), Type{Vector{Function}}, Dict{Base.PkgId,Vector{Function}}, Base.PkgId})
25+
precompile(Tuple{typeof(haskey), Dict{Base.PkgId,Vector{Function}}, Base.PkgId})
26+
precompile(Tuple{typeof(delete!), Dict{Base.PkgId,Vector{Function}}, Base.PkgId})
27+
precompile(Tuple{typeof(push!), Vector{Function}, Function})
2828
2929
# miscellaneous
30-
@assert precompile(Tuple{typeof(Base.require), Base.PkgId})
31-
@assert precompile(Tuple{typeof(Base.recursive_prefs_merge), Base.Dict{String, Any}})
32-
@assert precompile(Tuple{typeof(isassigned), Core.SimpleVector, Int})
33-
@assert precompile(Tuple{typeof(getindex), Core.SimpleVector, Int})
34-
@assert precompile(Tuple{typeof(Base.Experimental.register_error_hint), Any, Type})
35-
@assert precompile(Tuple{typeof(Base.display_error), MethodError, Vector{Union{Ptr{Nothing}, Base.InterpreterIP}}})
36-
@assert precompile(Tuple{typeof(Base.display_error), ErrorException})
37-
@assert precompile(Tuple{typeof(Base.display_error), BoundsError})
38-
@assert precompile(Tuple{Core.kwftype(typeof(Type)), NamedTuple{(:sizehint,), Tuple{Int64}}, Type{IOBuffer}})
39-
@assert precompile(Base.CoreLogging.current_logger_for_env, (Base.CoreLogging.LogLevel, String, Module))
40-
@assert precompile(Base.CoreLogging.current_logger_for_env, (Base.CoreLogging.LogLevel, Symbol, Module))
30+
precompile(Tuple{typeof(Base.require), Base.PkgId})
31+
precompile(Tuple{typeof(Base.recursive_prefs_merge), Base.Dict{String, Any}})
32+
precompile(Tuple{typeof(isassigned), Core.SimpleVector, Int})
33+
precompile(Tuple{typeof(getindex), Core.SimpleVector, Int})
34+
precompile(Tuple{typeof(Base.Experimental.register_error_hint), Any, Type})
35+
precompile(Tuple{typeof(Base.display_error), MethodError, Vector{Union{Ptr{Nothing}, Base.InterpreterIP}}})
36+
precompile(Tuple{typeof(Base.display_error), ErrorException})
37+
precompile(Tuple{typeof(Base.display_error), BoundsError})
38+
precompile(Tuple{Core.kwftype(typeof(Type)), NamedTuple{(:sizehint,), Tuple{Int}}, Type{IOBuffer}})
39+
precompile(Base.CoreLogging.current_logger_for_env, (Base.CoreLogging.LogLevel, String, Module))
40+
precompile(Base.CoreLogging.current_logger_for_env, (Base.CoreLogging.LogLevel, Symbol, Module))
4141
"""
4242

4343
for T in (Float16, Float32, Float64), IO in (IOBuffer, IOContext{IOBuffer}, Base.TTY, IOContext{Base.TTY})
4444
global hardcoded_precompile_statements
45-
hardcoded_precompile_statements *= "@assert precompile(Tuple{typeof(show), $IO, $T})\n"
45+
hardcoded_precompile_statements *= "precompile(Tuple{typeof(show), $IO, $T})\n"
4646
end
4747

4848
repl_script = """
@@ -108,7 +108,7 @@ have_repl = haskey(Base.loaded_modules,
108108
Base.PkgId(Base.UUID("3fa0cd96-eef1-5676-8a61-b3b8758bbffb"), "REPL"))
109109
if have_repl
110110
hardcoded_precompile_statements *= """
111-
@assert precompile(Tuple{typeof(getproperty), REPL.REPLBackend, Symbol})
111+
precompile(Tuple{typeof(getproperty), REPL.REPLBackend, Symbol})
112112
"""
113113
end
114114

@@ -117,9 +117,9 @@ Distributed = get(Base.loaded_modules,
117117
nothing)
118118
if Distributed !== nothing
119119
hardcoded_precompile_statements *= """
120-
@assert precompile(Tuple{typeof(Distributed.remotecall),Function,Int,Module,Vararg{Any, 100}})
121-
@assert precompile(Tuple{typeof(Distributed.procs)})
122-
@assert precompile(Tuple{typeof(Distributed.finalize_ref), Distributed.Future})
120+
precompile(Tuple{typeof(Distributed.remotecall),Function,Int,Module,Vararg{Any, 100}})
121+
precompile(Tuple{typeof(Distributed.procs)})
122+
precompile(Tuple{typeof(Distributed.finalize_ref), Distributed.Future})
123123
"""
124124
# This is disabled because it doesn't give much benefit
125125
# and the code in Distributed is poorly typed causing many invalidations
@@ -164,9 +164,9 @@ FileWatching = get(Base.loaded_modules,
164164
nothing)
165165
if FileWatching !== nothing
166166
hardcoded_precompile_statements *= """
167-
@assert precompile(Tuple{typeof(FileWatching.watch_file), String, Float64})
168-
@assert precompile(Tuple{typeof(FileWatching.watch_file), String, Int})
169-
@assert precompile(Tuple{typeof(FileWatching._uv_hook_close), FileWatching.FileMonitor})
167+
precompile(Tuple{typeof(FileWatching.watch_file), String, Float64})
168+
precompile(Tuple{typeof(FileWatching.watch_file), String, Int})
169+
precompile(Tuple{typeof(FileWatching._uv_hook_close), FileWatching.FileMonitor})
170170
"""
171171
end
172172

@@ -184,33 +184,33 @@ Test = get(Base.loaded_modules,
184184
nothing)
185185
if Test !== nothing
186186
hardcoded_precompile_statements *= """
187-
@assert precompile(Tuple{typeof(Test.do_test), Test.ExecutionResult, Any})
188-
@assert precompile(Tuple{typeof(Test.testset_beginend), Tuple{String, Expr}, Expr, LineNumberNode})
189-
@assert precompile(Tuple{Type{Test.DefaultTestSet}, String})
190-
@assert precompile(Tuple{Type{Test.DefaultTestSet}, AbstractString})
191-
@assert precompile(Tuple{Core.kwftype(Type{Test.DefaultTestSet}), Any, Type{Test.DefaultTestSet}, AbstractString})
192-
@assert precompile(Tuple{typeof(Test.finish), Test.DefaultTestSet})
193-
@assert precompile(Tuple{typeof(Test.eval_test), Expr, Expr, LineNumberNode, Bool})
194-
@assert precompile(Tuple{typeof(Test._inferred), Expr, Module})
195-
@assert precompile(Tuple{typeof(Test.push_testset), Test.DefaultTestSet})
196-
@assert precompile(Tuple{typeof(Test.get_alignment), Test.DefaultTestSet, Int})
197-
@assert precompile(Tuple{typeof(Test.get_test_result), Any, Any})
198-
@assert precompile(Tuple{typeof(Test.do_test_throws), Test.ExecutionResult, Any, Any})
199-
@assert precompile(Tuple{typeof(Test.print_counts), Test.DefaultTestSet, Int, Int, Int, Int, Int, Int, Int})
200-
@assert precompile(Tuple{typeof(Test._check_testset), Type, Expr})
201-
@assert precompile(Tuple{typeof(Test.test_expr!), Any, Any})
202-
@assert precompile(Tuple{typeof(Test.test_expr!), Any, Any, Vararg{Any, 100}})
203-
@assert precompile(Tuple{typeof(Test.pop_testset)})
204-
@assert precompile(Tuple{typeof(Test.match_logs), Function, Tuple{Symbol, Regex}})
205-
@assert precompile(Tuple{typeof(Test.match_logs), Function, Tuple{String, Regex}})
206-
@assert precompile(Tuple{typeof(Base.CoreLogging.shouldlog), Test.TestLogger, Base.CoreLogging.LogLevel, Module, Symbol, Symbol})
207-
@assert precompile(Tuple{typeof(Base.CoreLogging.handle_message), Test.TestLogger, Base.CoreLogging.LogLevel, String, Module, Symbol, Symbol, String, Int})
208-
@assert precompile(Tuple{typeof(Core.kwfunc(Base.CoreLogging.handle_message)), typeof((exception=nothing,)), typeof(Base.CoreLogging.handle_message), Test.TestLogger, Base.CoreLogging.LogLevel, String, Module, Symbol, Symbol, String, Int})
209-
@assert precompile(Tuple{typeof(Test.detect_ambiguities), Any})
210-
@assert precompile(Tuple{typeof(Test.collect_test_logs), Function})
211-
@assert precompile(Tuple{typeof(Test.do_broken_test), Test.ExecutionResult, Any})
212-
@assert precompile(Tuple{typeof(Test.record), Test.DefaultTestSet, Union{Test.Error, Test.Fail}})
213-
@assert precompile(Tuple{typeof(Test.filter_errors), Test.DefaultTestSet})
187+
precompile(Tuple{typeof(Test.do_test), Test.ExecutionResult, Any})
188+
precompile(Tuple{typeof(Test.testset_beginend), Tuple{String, Expr}, Expr, LineNumberNode})
189+
precompile(Tuple{Type{Test.DefaultTestSet}, String})
190+
precompile(Tuple{Type{Test.DefaultTestSet}, AbstractString})
191+
precompile(Tuple{Core.kwftype(Type{Test.DefaultTestSet}), Any, Type{Test.DefaultTestSet}, AbstractString})
192+
precompile(Tuple{typeof(Test.finish), Test.DefaultTestSet})
193+
precompile(Tuple{typeof(Test.eval_test), Expr, Expr, LineNumberNode, Bool})
194+
precompile(Tuple{typeof(Test._inferred), Expr, Module})
195+
precompile(Tuple{typeof(Test.push_testset), Test.DefaultTestSet})
196+
precompile(Tuple{typeof(Test.get_alignment), Test.DefaultTestSet, Int})
197+
precompile(Tuple{typeof(Test.get_test_result), Any, Any})
198+
precompile(Tuple{typeof(Test.do_test_throws), Test.ExecutionResult, Any, Any})
199+
precompile(Tuple{typeof(Test.print_counts), Test.DefaultTestSet, Int, Int, Int, Int, Int, Int, Int})
200+
precompile(Tuple{typeof(Test._check_testset), Type, Expr})
201+
precompile(Tuple{typeof(Test.test_expr!), Any, Any})
202+
precompile(Tuple{typeof(Test.test_expr!), Any, Any, Vararg{Any, 100}})
203+
precompile(Tuple{typeof(Test.pop_testset)})
204+
precompile(Tuple{typeof(Test.match_logs), Function, Tuple{Symbol, Regex}})
205+
precompile(Tuple{typeof(Test.match_logs), Function, Tuple{String, Regex}})
206+
precompile(Tuple{typeof(Base.CoreLogging.shouldlog), Test.TestLogger, Base.CoreLogging.LogLevel, Module, Symbol, Symbol})
207+
precompile(Tuple{typeof(Base.CoreLogging.handle_message), Test.TestLogger, Base.CoreLogging.LogLevel, String, Module, Symbol, Symbol, String, Int})
208+
precompile(Tuple{typeof(Core.kwfunc(Base.CoreLogging.handle_message)), typeof((exception=nothing,)), typeof(Base.CoreLogging.handle_message), Test.TestLogger, Base.CoreLogging.LogLevel, String, Module, Symbol, Symbol, String, Int})
209+
precompile(Tuple{typeof(Test.detect_ambiguities), Any})
210+
precompile(Tuple{typeof(Test.collect_test_logs), Function})
211+
precompile(Tuple{typeof(Test.do_broken_test), Test.ExecutionResult, Any})
212+
precompile(Tuple{typeof(Test.record), Test.DefaultTestSet, Union{Test.Error, Test.Fail}})
213+
precompile(Tuple{typeof(Test.filter_errors), Test.DefaultTestSet})
214214
"""
215215
end
216216

@@ -219,7 +219,7 @@ Profile = get(Base.loaded_modules,
219219
nothing)
220220
if Profile !== nothing
221221
hardcoded_precompile_statements *= """
222-
@assert precompile(Tuple{typeof(Profile.tree!), Profile.StackFrameTree{UInt64}, Vector{UInt64}, Dict{UInt64, Vector{Base.StackTraces.StackFrame}}, Bool, Symbol})
222+
precompile(Tuple{typeof(Profile.tree!), Profile.StackFrameTree{UInt64}, Vector{UInt64}, Dict{UInt64, Vector{Base.StackTraces.StackFrame}}, Bool, Symbol})
223223
"""
224224
end
225225

@@ -350,32 +350,49 @@ function generate_precompile_statements()
350350
n_succeeded = 0
351351
include_time = @elapsed for statement in sort!(collect(statements))
352352
# println(statement)
353-
# The compiler has problem caching signatures with `Vararg{?, N}`. Replacing
354-
# N with a large number seems to work around it.
353+
# XXX: skip some that are broken. these are caused by issue #39902
354+
occursin("Tuple{Artifacts.var\"#@artifact_str\", LineNumberNode, Module, Any, Any}", statement) && continue
355+
occursin("Tuple{Base.Cartesian.var\"#@ncall\", LineNumberNode, Module, Int64, Any, Vararg{Any}}", statement) && continue
356+
occursin("Tuple{Base.Cartesian.var\"#@ncall\", LineNumberNode, Module, Int32, Any, Vararg{Any}}", statement) && continue
357+
occursin("Tuple{Base.Cartesian.var\"#@nloops\", LineNumberNode, Module, Any, Any, Any, Vararg{Any}}", statement) && continue
358+
occursin("Tuple{Core.var\"#@doc\", LineNumberNode, Module, Vararg{Any}}", statement) && continue
359+
# XXX: this is strange, as this isn't the correct representation of this
360+
occursin("typeof(Core.IntrinsicFunction)", statement) && continue
361+
# XXX: this is strange, as this method should not be getting compiled
362+
occursin(", Core.Compiler.AbstractInterpreter, ", statement) && continue
355363
try
356364
ps = Meta.parse(statement)
357-
if isexpr(ps, :call)
358-
if isexpr(ps.args[end], :curly)
359-
l = ps.args[end]
360-
if length(l.args) == 2 && l.args[1] == :Vararg
361-
push!(l.args, 100)
362-
end
365+
isexpr(ps, :call) || continue
366+
popfirst!(ps.args) # precompile(...)
367+
ps.head = :tuple
368+
l = ps.args[end]
369+
if (isexpr(l, :tuple) || isexpr(l, :curly)) && length(l.args) > 0 # Tuple{...} or (...)
370+
# XXX: precompile doesn't currently handle overloaded Vararg arguments very well.
371+
# Replacing N with a large number works around it.
372+
l = l.args[end]
373+
if isexpr(l, :curly) && length(l.args) == 2 && l.args[1] == :Vararg # Vararg{T}
374+
push!(l.args, 100) # form Vararg{T, 100} instead
363375
end
364376
end
365377
# println(ps)
366-
Core.eval(PrecompileStagingArea, ps)
378+
ps = Core.eval(PrecompileStagingArea, ps)
379+
# XXX: precompile doesn't currently handle overloaded nospecialize arguments very well.
380+
# Skipping them avoids the warning.
381+
ms = length(ps) == 1 ? Base._methods_by_ftype(ps[1], 1, Base.get_world_counter()) : Base.methods(ps...)
382+
ms isa Vector || continue
383+
precompile(ps...)
367384
n_succeeded += 1
368385
print("\rExecuting precompile statements... $n_succeeded/$(length(statements))")
369-
catch
386+
catch ex
370387
# See #28808
371-
# @error "Failed to precompile $statement"
388+
@warn "Failed to precompile expression" form=statement exception=ex _module=nothing _file=nothing _line=0
372389
end
373390
end
374391
println()
375392
if have_repl
376393
# Seems like a reasonable number right now, adjust as needed
377394
# comment out if debugging script
378-
@assert n_succeeded > 1200
395+
n_succeeded > 1200 || @warn "Only $n_succeeded precompile statements"
379396
end
380397

381398
tot_time = time_ns() - start_time

test/ambiguous.jl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ end
6666
## Other ways of accessing functions
6767
# Test that non-ambiguous cases work
6868
let io = IOBuffer()
69-
@test precompile(ambig, (Int, Int)) == true
69+
@test @test_logs precompile(ambig, (Int, Int))
7070
cf = @eval @cfunction(ambig, Int, (Int, Int))
7171
@test ccall(cf, Int, (Int, Int), 1, 2) == 4
7272
@test length(code_lowered(ambig, (Int, Int))) == 1
@@ -75,7 +75,7 @@ end
7575

7676
# Test that ambiguous cases fail appropriately
7777
let io = IOBuffer()
78-
@test precompile(ambig, (UInt8, Int)) == false
78+
@test @test_logs (:warn,) precompile(ambig, (UInt8, Int))
7979
cf = @eval @cfunction(ambig, Int, (UInt8, Int)) # test for a crash (doesn't throw an error)
8080
@test_throws(MethodError(ambig, (UInt8(1), Int(2)), get_world_counter()),
8181
ccall(cf, Int, (UInt8, Int), 1, 2))

0 commit comments

Comments
 (0)