# This file is a part of Julia. License is MIT: https://julialang.org/license using Base.Test Foo_module = :Foo4b3a94a1a081a8cb Foo2_module = :F2oo4b3a94a1a081a8cb FooBase_module = :FooBase4b3a94a1a081a8cb @eval module ConflictingBindings export $Foo_module, $FooBase_module $Foo_module = 232 $FooBase_module = 9134 end using .ConflictingBindings # this environment variable would affect some error messages being tested below # so we disable it for the tests below withenv( "JULIA_DEBUG_LOADING" => nothing ) do dir = mktempdir() dir2 = mktempdir() insert!(LOAD_PATH, 1, dir) insert!(Base.LOAD_CACHE_PATH, 1, dir) try Foo_file = joinpath(dir, "$Foo_module.jl") Foo2_file = joinpath(dir, "$Foo2_module.jl") FooBase_file = joinpath(dir, "$FooBase_module.jl") write(FooBase_file, """ __precompile__(true) module $FooBase_module import Base: hash, > struct fmpz end struct typeA end >(x::fmpz, y::Int) = Base.cmp(x, y) > 0 function hash(a::typeA, h::UInt) d = den(a) return h end end """) write(Foo2_file, """ __precompile__(true) module $Foo2_module export override override(x::Integer) = 2 override(x::AbstractFloat) = Float64(override(1)) end """) write(Foo_file, """ __precompile__(true) module $Foo_module using $FooBase_module, $FooBase_module.typeA import $Foo2_module: $Foo2_module, override import $FooBase_module.hash struct typeB y::typeA end hash(x::typeB) = hash(x.y) # test that docs get reconnected @doc "foo function" foo(x) = x + 1 include_dependency("foo.jl") include_dependency("foo.jl") module Bar @doc "bar function" bar(x) = x + 2 include_dependency("bar.jl") end # test for creation of some reasonably complicated type struct MyType{T} end const t17809s = Any[ Tuple{ Type{Ptr{MyType{i}}}, Array{Ptr{MyType{MyType{:sym}()}}(0), 0}, Val{Complex{Int}(1, 2)}, Val{3}, Val{nothing}} for i = 0:25] # test that types and methods get reconnected correctly # issue 16529 (adding a method to a type with no instances) (::Task)(::UInt8, ::UInt16, ::UInt32) = 2 # issue 16471 (capturing references to a kwfunc) Base.Test.@test_throws ErrorException Core.kwfunc(Base.nothing) Base.nothing(::UInt8, ::UInt16, ::UInt32; x = 52) = x const nothingkw = Core.kwfunc(Base.nothing) # issue 16908 (some complicated types and external method definitions) abstract type CategoricalPool{T, R <: Integer, V} end abstract type CategoricalValue{T, R <: Integer} end struct NominalPool{T, R <: Integer, V} <: CategoricalPool{T, R, V} index::Vector{T} invindex::Dict{T, R} order::Vector{R} ordered::Vector{T} valindex::Vector{V} end struct NominalValue{T, R <: Integer} <: CategoricalValue{T, R} level::R pool::NominalPool{T, R, NominalValue{T, R}} end struct OrdinalValue{T, R <: Integer} <: CategoricalValue{T, R} level::R pool::NominalPool{T, R, NominalValue{T, R}} end (::Union{Type{NominalValue}, Type{OrdinalValue}})() = 1 (::Union{Type{NominalValue{T}}, Type{OrdinalValue{T}}}){T}() = 2 (::Type{Vector{NominalValue{T, R}}}){T, R}() = 3 (::Type{Vector{NominalValue{T, T}}}){T}() = 4 (::Type{Vector{NominalValue{Int, Int}}})() = 5 # more tests for method signature involving a complicated type # issue 18343 struct Pool18343{R, V} valindex::Vector{V} end struct Value18343{T, R} pool::Pool18343{R, Value18343{T, R}} end Base.convert{S}(::Type{Nullable{S}}, ::Value18343{Nullable}) = 2 Base.convert(::Type{Nullable{Value18343}}, ::Value18343{Nullable}) = 2 Base.convert{T}(::Type{Ref}, ::Value18343{T}) = 3 let some_method = @which Base.include("string") # global const some_method // FIXME: support for serializing a direct reference to an external Method not implemented global const some_linfo = ccall(:jl_specializations_get_linfo, Ref{Core.MethodInstance}, (Any, Any, Any, UInt), some_method, Tuple{typeof(Base.include), String}, Core.svec(), typemax(UInt)) end g() = override(1.0) Base.Test.@test g() === 2.0 # compile this end """) @test_throws ErrorException Core.kwfunc(Base.nothing) # make sure `nothing` didn't have a kwfunc (which would invalidate the attempted test) # Issue #12623 @test __precompile__(true) === nothing # Issue #21307 Base.require(Foo2_module) @eval let Foo2_module = $(QuoteNode(Foo2_module)), # use @eval to see the results of loading the compile Foo = getfield(Main, Foo2_module) Foo.override(::Int) = 'a' Foo.override(::Float32) = 'b' end Base.require(Foo_module) @eval let Foo_module = $(QuoteNode(Foo_module)), # use @eval to see the results of loading the compile Foo = getfield(Main, Foo_module) @test Foo.foo(17) == 18 @test Foo.Bar.bar(17) == 19 # Issue #21307 @test Foo.g() === 97.0 @test Foo.override(1.0e0) == Float64('a') @test Foo.override(1.0f0) == 'b' @test Foo.override(UInt(1)) == 2 end cachefile = joinpath(dir, "$Foo_module.ji") # use _require_from_serialized to ensure that the test fails if # the module doesn't reload from the image: @test_warn "WARNING: replacing module $Foo_module." begin @test isa(Base._require_from_serialized(myid(), Foo_module, cachefile, #=broadcast-load=#false), Array{Any,1}) end let Foo = getfield(Main, Foo_module) @test_throws MethodError Foo.foo(17) # world shouldn't be visible yet end @eval let Foo_module = $(QuoteNode(Foo_module)), # use @eval to see the results of loading the compile Foo2_module = $(QuoteNode(Foo2_module)), FooBase_module = $(QuoteNode(FooBase_module)), Foo = getfield(Main, Foo_module), dir = $(QuoteNode(dir)), cachefile = $(QuoteNode(cachefile)), Foo_file = $(QuoteNode(Foo_file)) @test Foo.foo(17) == 18 @test Foo.Bar.bar(17) == 19 # Issue #21307 @test Foo.g() === 97.0 @test Foo.override(1.0e0) == Float64('a') @test Foo.override(1.0f0) == 'b' @test Foo.override(UInt(1)) == 2 # issue #12284: @test stringmime("text/plain", Base.Docs.doc(Foo.foo)) == "foo function\n" @test stringmime("text/plain", Base.Docs.doc(Foo.Bar.bar)) == "bar function\n" modules, deps, required_modules = Base.parse_cache_header(cachefile) @test modules == Dict(Foo_module => Base.module_uuid(Foo)) @test map(x -> x[1], sort(deps)) == [Foo_file, joinpath(dir, "bar.jl"), joinpath(dir, "foo.jl")] modules, deps1 = Base.cache_dependencies(cachefile) @test modules == Dict(s => Base.module_uuid(getfield(Foo, s)) for s in [:Base, :Core, Foo2_module, FooBase_module, :Main]) @test deps == deps1 @test current_task()(0x01, 0x4000, 0x30031234) == 2 @test nothing(0x01, 0x4000, 0x30031234) == 52 @test nothing(0x01, 0x4000, 0x30031234; x = 9142) == 9142 @test Foo.nothingkw === Core.kwfunc(Base.nothing) @test Foo.NominalValue() == 1 @test Foo.OrdinalValue() == 1 @test Foo.NominalValue{Int}() == 2 @test Foo.OrdinalValue{Int}() == 2 let T = Vector{Foo.NominalValue{Int}} @test isa(T(), T) end @test Vector{Foo.NominalValue{Int32, Int64}}() == 3 @test Vector{Foo.NominalValue{UInt, UInt}}() == 4 @test Vector{Foo.NominalValue{Int, Int}}() == 5 @test all(i -> Foo.t17809s[i + 1] === Tuple{ Type{Ptr{Foo.MyType{i}}}, Array{Ptr{Foo.MyType{Foo.MyType{:sym}()}}(0), 0}, Val{Complex{Int}(1, 2)}, Val{3}, Val{nothing}}, 0:25) some_method = @which Base.include("string") some_linfo = ccall(:jl_specializations_get_linfo, Ref{Core.MethodInstance}, (Any, Any, Any, UInt), some_method, Tuple{typeof(Base.include), String}, Core.svec(), typemax(UInt)) @test Foo.some_linfo::Core.MethodInstance === some_linfo PV = Foo.Value18343{Nullable}.body.types[1] VR = PV.types[1].parameters[1] @test PV.types[1] === Array{VR,1} @test pointer_from_objref(PV.types[1]) === pointer_from_objref(PV.types[1].parameters[1].types[1].types[1]) @test PV === PV.types[1].parameters[1].types[1] @test pointer_from_objref(PV) === pointer_from_objref(PV.types[1].parameters[1].types[1]) end Baz_file = joinpath(dir, "Baz.jl") write(Baz_file, """ __precompile__(false) module Baz end """) @test_warn "ERROR: LoadError: Declaring __precompile__(false) is not allowed in files that are being precompiled.\nStacktrace:\n [1] __precompile__" try Base.compilecache("Baz") # from __precompile__(false) error("__precompile__ disabled test failed") catch exc isa(exc, ErrorException) || rethrow(exc) !isempty(search(exc.msg, "__precompile__(false)")) && rethrow(exc) end # Issue #12720 FooBar1_file = joinpath(dir, "FooBar1.jl") write(FooBar1_file, """ __precompile__(true) module FooBar1 using FooBar end """) sleep(2) # give FooBar and FooBar1 different timestamps, in reverse order too FooBar_file = joinpath(dir, "FooBar.jl") write(FooBar_file, """ __precompile__(true) module FooBar end """) Base.compilecache("FooBar") @test isfile(joinpath(dir, "FooBar.ji")) @test !Base.stale_cachefile(FooBar_file, joinpath(dir, "FooBar.ji")) @test !isdefined(Main, :FooBar) @test !isdefined(Main, :FooBar1) relFooBar_file = joinpath(dir, "subfolder", "..", "FooBar.jl") @test Base.stale_cachefile(relFooBar_file, joinpath(dir, "FooBar.ji")) == !is_windows() # `..` is not a symlink on Windows mkdir(joinpath(dir, "subfolder")) @test !Base.stale_cachefile(relFooBar_file, joinpath(dir, "FooBar.ji")) @eval using FooBar fb_uuid = Base.module_uuid(Main.FooBar) sleep(2); touch(FooBar_file) insert!(Base.LOAD_CACHE_PATH, 1, dir2) @test Base.stale_cachefile(FooBar_file, joinpath(dir, "FooBar.ji")) @eval using FooBar1 @test !isfile(joinpath(dir2, "FooBar.ji")) @test !isfile(joinpath(dir, "FooBar1.ji")) @test isfile(joinpath(dir2, "FooBar1.ji")) @test Base.stale_cachefile(FooBar_file, joinpath(dir, "FooBar.ji")) @test !Base.stale_cachefile(FooBar1_file, joinpath(dir2, "FooBar1.ji")) @test fb_uuid == Base.module_uuid(Main.FooBar) fb_uuid1 = Base.module_uuid(Main.FooBar1) @test fb_uuid != fb_uuid1 @test_warn "WARNING: replacing module FooBar." reload("FooBar") @test fb_uuid != Base.module_uuid(Main.FooBar) @test fb_uuid1 == Base.module_uuid(Main.FooBar1) fb_uuid = Base.module_uuid(Main.FooBar) @test isfile(joinpath(dir2, "FooBar.ji")) @test Base.stale_cachefile(FooBar_file, joinpath(dir, "FooBar.ji")) @test !Base.stale_cachefile(FooBar1_file, joinpath(dir2, "FooBar1.ji")) @test !Base.stale_cachefile(FooBar_file, joinpath(dir2, "FooBar.ji")) @test_warn "WARNING: replacing module FooBar1." reload("FooBar1") @test fb_uuid == Base.module_uuid(Main.FooBar) @test fb_uuid1 != Base.module_uuid(Main.FooBar1) @test isfile(joinpath(dir2, "FooBar.ji")) @test isfile(joinpath(dir2, "FooBar1.ji")) @test Base.stale_cachefile(FooBar_file, joinpath(dir, "FooBar.ji")) @test !Base.stale_cachefile(FooBar_file, joinpath(dir2, "FooBar.ji")) @test !Base.stale_cachefile(FooBar1_file, joinpath(dir2, "FooBar1.ji")) # test behavior of precompile modules that throw errors write(FooBar_file, """ __precompile__(true) module FooBar error("break me") end """) @test_warn "ERROR: LoadError: break me\nStacktrace:\n [1] error" try Base.require(:FooBar) error("\"LoadError: break me\" test failed") catch exc isa(exc, ErrorException) || rethrow(exc) !isempty(search(exc.msg, "ERROR: LoadError: break me")) && rethrow(exc) end # Test transitive dependency for #21266 FooBarT_file = joinpath(dir, "FooBarT.jl") write(FooBarT_file, """ __precompile__(true) module FooBarT end """) FooBarT1_file = joinpath(dir, "FooBarT1.jl") write(FooBarT1_file, """ __precompile__(true) module FooBarT1 using FooBarT end """) FooBarT2_file = joinpath(dir, "FooBarT2.jl") write(FooBarT2_file, """ __precompile__(true) module FooBarT2 using FooBarT1 end """) Base.compilecache("FooBarT2") write(FooBarT1_file, """ __precompile__(true) module FooBarT1 end """) rm(FooBarT_file) @test Base.stale_cachefile(FooBarT2_file, joinpath(dir2, "FooBarT2.ji")) @test Base.require(:FooBarT2) === nothing finally splice!(Base.LOAD_CACHE_PATH, 1:2) splice!(LOAD_PATH, 1) rm(dir, recursive=true) rm(dir2, recursive=true) end # test --compilecache=no command line option let dir = mktempdir(), Time_module = :Time4b3a94a1a081a8cb try write(joinpath(dir, "$Time_module.jl"), """ module $Time_module __precompile__(true) time = Base.time() end """) eval(quote insert!(LOAD_PATH, 1, $(dir)) insert!(Base.LOAD_CACHE_PATH, 1, $(dir)) Base.compilecache(:Time4b3a94a1a081a8cb) end) exename = `$(Base.julia_cmd()) --precompiled=yes --startup-file=no` testcode = """ insert!(LOAD_PATH, 1, $(repr(dir))) insert!(Base.LOAD_CACHE_PATH, 1, $(repr(dir))) using $Time_module getfield($Time_module, :time) """ t1_yes = readchomp(`$exename --compilecache=yes -E $(testcode)`) t2_yes = readchomp(`$exename --compilecache=yes -E $(testcode)`) @test t1_yes == t2_yes t1_no = readchomp(`$exename --compilecache=no -E $(testcode)`) t2_no = readchomp(`$exename --compilecache=no -E $(testcode)`) @test t1_no != t2_no @test parse(Float64, t1_no) < parse(Float64, t2_no) finally splice!(Base.LOAD_CACHE_PATH, 1) splice!(LOAD_PATH, 1) rm(dir, recursive=true) end end # test loading a package with conflicting namespace let dir = mktempdir() Test_module = :Test6c92f26 try write(joinpath(dir, "Iterators.jl"), """ module Iterators __precompile__(true) end """) write(joinpath(dir, "$Test_module.jl"), """ module $Test_module __precompile__(true) using Iterators end """) testcode = """ insert!(LOAD_PATH, 1, $(repr(dir))) insert!(Base.LOAD_CACHE_PATH, 1, $(repr(dir))) using $Test_module """ exename = `$(Base.julia_cmd()) --startup-file=no` let fname = tempname() try @test readchomp(pipeline(`$exename -E $(testcode)`, stderr=fname)) == "nothing" @test Test.ismatch_warn("WARNING: replacing module $Test_module.\n", readstring(fname)) finally rm(fname, force=true) end end # Loading $Test_module from the cache should not bring `Base.Iterators` # into `Main`, since that would lead to a namespace conflict with # the module `Iterators` defined above. let fname = tempname() try @test readchomp(pipeline(`$exename -E $(testcode)`, stderr=fname)) == "nothing" # e.g `@test_nowarn` @test Test.ismatch_warn(r"^(?!.)"s, readstring(fname)) finally rm(fname, force=true) end end finally rm(dir, recursive=true) end end let dir = mktempdir() try insert!(LOAD_PATH, 1, dir) insert!(Base.LOAD_CACHE_PATH, 1, dir) loaded_modules = Channel{Symbol}(32) callback = (mod::Symbol) -> put!(loaded_modules, mod) push!(Base.package_callbacks, callback) Test1_module = :Teste4095a81 Test2_module = :Teste4095a82 Test3_module = :Teste4095a83 write(joinpath(dir, "$(Test1_module).jl"), """ module $(Test1_module) __precompile__(true) end """) Base.compilecache("$(Test1_module)") write(joinpath(dir, "$(Test2_module).jl"), """ module $(Test2_module) __precompile__(true) using $(Test1_module) end """) Base.compilecache("$(Test2_module)") @test !Base.isbindingresolved(Main, Test2_module) Base.require(Test2_module) @test Base.isbindingresolved(Main, Test2_module) @test take!(loaded_modules) == Test1_module @test take!(loaded_modules) == Test2_module write(joinpath(dir, "$(Test3_module).jl"), """ module $(Test3_module) using $(Test3_module) end """) Base.require(Test3_module) @test take!(loaded_modules) == Test3_module finally pop!(Base.package_callbacks) splice!(Base.LOAD_CACHE_PATH, 1) splice!(LOAD_PATH, 1) rm(dir, recursive=true) end end let module_name = string("a",randstring()) insert!(LOAD_PATH, 1, pwd()) file_name = string(module_name, ".jl") sleep(2); touch(file_name) code = """module $(module_name)\nend\n""" write(file_name, code) reload(module_name) @test isa(eval(Main, Symbol(module_name)), Module) deleteat!(LOAD_PATH,1) rm(file_name) end # Issue #19960 let # ideally this would test with workers on a remote host that does not have access to the master node filesystem for loading # can simulate this for local workers by using relative load paths on master node that are not valid on workers # so addprocs before changing directory to temp directory, otherwise workers will inherit temp working directory test_workers = addprocs(1) temp_path = mktempdir() save_cwd = pwd() cd(temp_path) load_path = mktempdir(temp_path) load_cache_path = mktempdir(temp_path) unshift!(LOAD_PATH, basename(load_path)) unshift!(Base.LOAD_CACHE_PATH, basename(load_cache_path)) ModuleA = :Issue19960A ModuleB = :Issue19960B write(joinpath(load_path, "$ModuleA.jl"), """ __precompile__(true) module $ModuleA export f f() = myid() end """) write(joinpath(load_path, "$ModuleB.jl"), """ __precompile__(true) module $ModuleB using $ModuleA export g g() = f() end """) try @eval using $ModuleB for wid in test_workers @test remotecall_fetch(g, wid) == wid end finally shift!(LOAD_PATH) shift!(Base.LOAD_CACHE_PATH) cd(save_cwd) rm(temp_path, recursive=true) rmprocs(test_workers) end end end # !withenv