654 lines
22 KiB
Julia
654 lines
22 KiB
Julia
# This file is a part of Julia. License is MIT: https://julialang.org/license
|
|
|
|
# code_native / code_llvm (issue #8239)
|
|
# It's hard to really test these, but just running them should be
|
|
# sufficient to catch segfault bugs.
|
|
|
|
module ReflectionTest
|
|
using Base.Test
|
|
|
|
function test_ast_reflection(freflect, f, types)
|
|
@test !isempty(freflect(f, types))
|
|
nothing
|
|
end
|
|
|
|
function test_bin_reflection(freflect, f, types)
|
|
iob = IOBuffer()
|
|
freflect(iob, f, types)
|
|
str = String(take!(iob))
|
|
@test !isempty(str)
|
|
nothing
|
|
end
|
|
|
|
function test_code_reflection(freflect, f, types, tester)
|
|
tester(freflect, f, types)
|
|
tester(freflect, f, (types.parameters...))
|
|
nothing
|
|
end
|
|
|
|
function test_code_reflections(tester, freflect)
|
|
test_code_reflection(freflect, ismatch,
|
|
Tuple{Regex, AbstractString}, tester) # abstract type
|
|
test_code_reflection(freflect, +, Tuple{Int, Int}, tester) # leaftype signature
|
|
test_code_reflection(freflect, +,
|
|
Tuple{Array{Float32}, Array{Float32}}, tester) # incomplete types
|
|
test_code_reflection(freflect, Module, Tuple{}, tester) # Module() constructor (transforms to call)
|
|
test_code_reflection(freflect, Array{Int64}, Tuple{Array{Int32}}, tester) # with incomplete types
|
|
test_code_reflection(freflect, muladd, Tuple{Float64, Float64, Float64}, tester)
|
|
end
|
|
|
|
test_code_reflections(test_ast_reflection, code_lowered)
|
|
test_code_reflections(test_ast_reflection, code_typed)
|
|
test_code_reflections(test_bin_reflection, code_llvm)
|
|
test_code_reflections(test_bin_reflection, code_native)
|
|
|
|
# Issue #16326
|
|
mktemp() do f, io
|
|
OLDSTDOUT = STDOUT
|
|
redirect_stdout(io)
|
|
@test try @code_native map(abs, rand(3)); true; catch false; end
|
|
redirect_stdout(OLDSTDOUT)
|
|
nothing
|
|
end
|
|
|
|
end # module ReflectionTest
|
|
|
|
# code_warntype
|
|
module WarnType
|
|
using Base.Test
|
|
|
|
function warntype_hastag(f, types, tag)
|
|
iob = IOBuffer()
|
|
code_warntype(iob, f, types)
|
|
str = String(take!(iob))
|
|
return !isempty(search(str, tag))
|
|
end
|
|
|
|
pos_stable(x) = x > 0 ? x : zero(x)
|
|
pos_unstable(x) = x > 0 ? x : 0
|
|
|
|
tag = Base.have_color ? Base.error_color() : "UNION"
|
|
@test warntype_hastag(pos_unstable, Tuple{Float64}, tag)
|
|
@test !warntype_hastag(pos_stable, Tuple{Float64}, tag)
|
|
|
|
mutable struct Stable{T,N}
|
|
A::Array{T,N}
|
|
end
|
|
mutable struct Unstable{T}
|
|
A::Array{T}
|
|
end
|
|
Base.getindex(A::Stable, i) = A.A[i]
|
|
Base.getindex(A::Unstable, i) = A.A[i]
|
|
|
|
tag = Base.have_color ? Base.error_color() : "ARRAY{FLOAT64,N}"
|
|
@test warntype_hastag(getindex, Tuple{Unstable{Float64},Int}, tag)
|
|
@test !warntype_hastag(getindex, Tuple{Stable{Float64,2},Int}, tag)
|
|
@test warntype_hastag(getindex, Tuple{Stable{Float64},Int}, tag)
|
|
|
|
# Make sure emphasis is not used for other functions
|
|
tag = Base.have_color ? Base.error_color() : "ANY"
|
|
iob = IOBuffer()
|
|
show(iob, expand(:(x->x^2)))
|
|
str = String(take!(iob))
|
|
@test isempty(search(str, tag))
|
|
|
|
# Make sure non used variables are not emphasized
|
|
has_unused() = (a = rand(5))
|
|
@test !warntype_hastag(has_unused, Tuple{}, tag)
|
|
@test warntype_hastag(has_unused, Tuple{}, "<optimized out>")
|
|
|
|
module ImportIntrinsics15819
|
|
# Make sure changing the lookup path of an intrinsic doesn't break
|
|
# the heuristic for type instability warning.
|
|
import Core.Intrinsics: sqrt_llvm, bitcast
|
|
# Use import
|
|
sqrt15819(x::Float64) = bitcast(Float64, sqrt_llvm(x))
|
|
# Use fully qualified name
|
|
sqrt15819(x::Float32) = bitcast(Float32, Core.Intrinsics.sqrt_llvm(x))
|
|
end
|
|
foo11122(x) = @fastmath x - 1.0
|
|
|
|
# issue #11122, #13568 and #15819
|
|
@test !warntype_hastag(+, Tuple{Int,Int}, tag)
|
|
@test !warntype_hastag(-, Tuple{Int,Int}, tag)
|
|
@test !warntype_hastag(*, Tuple{Int,Int}, tag)
|
|
@test !warntype_hastag(/, Tuple{Int,Int}, tag)
|
|
@test !warntype_hastag(foo11122, Tuple{Float32}, tag)
|
|
@test !warntype_hastag(foo11122, Tuple{Float64}, tag)
|
|
@test !warntype_hastag(foo11122, Tuple{Int}, tag)
|
|
@test !warntype_hastag(sqrt, Tuple{Int}, tag)
|
|
@test !warntype_hastag(sqrt, Tuple{Float64}, tag)
|
|
@test !warntype_hastag(^, Tuple{Float64,Int32}, tag)
|
|
@test !warntype_hastag(^, Tuple{Float32,Int32}, tag)
|
|
@test !warntype_hastag(ImportIntrinsics15819.sqrt15819, Tuple{Float64}, tag)
|
|
@test !warntype_hastag(ImportIntrinsics15819.sqrt15819, Tuple{Float32}, tag)
|
|
|
|
end
|
|
|
|
# isbits
|
|
|
|
@test !isbits(Array{Int})
|
|
@test isbits(Float32)
|
|
@test isbits(Int)
|
|
@test !isbits(AbstractString)
|
|
@test isbits(Tuple{Int, Vararg{Int, 2}})
|
|
@test !isbits(Tuple{Int, Vararg{Int}})
|
|
@test !isbits(Tuple{Integer, Vararg{Int, 2}})
|
|
@test isbits(Tuple{Int, Vararg{Any, 0}})
|
|
@test isbits(Tuple{Vararg{Any, 0}})
|
|
|
|
# issue #16670
|
|
@test isleaftype(Tuple{Int, Vararg{Int, 2}})
|
|
@test !isleaftype(Tuple{Integer, Vararg{Int, 2}})
|
|
@test !isleaftype(Tuple{Int, Vararg{Int}})
|
|
@test isleaftype(Type{Tuple{Integer, Vararg{Int}}})
|
|
@test isleaftype(Type{Vector})
|
|
|
|
# issue #10165
|
|
i10165(::Type) = 0
|
|
i10165{T,n}(::Type{AbstractArray{T,n}}) = 1
|
|
@test i10165(AbstractArray{Int,n} where n) == 0
|
|
@test which(i10165, Tuple{Type{AbstractArray{Int,n} where n},}).sig == Tuple{typeof(i10165),Type}
|
|
|
|
# fullname
|
|
@test fullname(Base) == (:Base,)
|
|
@test fullname(Base.Pkg) == (:Base, :Pkg)
|
|
|
|
const a_const = 1
|
|
not_const = 1
|
|
@test isconst(:a_const) == true
|
|
@test isconst(Base, :pi) == true
|
|
@test isconst(:pi) == true
|
|
@test isconst(:not_const) == false
|
|
@test isconst(:is_not_defined) == false
|
|
|
|
@test isimmutable(1) == true
|
|
@test isimmutable([]) == false
|
|
|
|
## find bindings tests
|
|
@test ccall(:jl_get_module_of_binding, Any, (Any, Any), Base, :sin)==Base
|
|
|
|
# For curmod_*
|
|
include("testenv.jl")
|
|
|
|
module TestMod7648
|
|
using Base.Test
|
|
import Base.convert
|
|
import ..curmod_name, ..curmod
|
|
export a9475, foo9475, c7648, foo7648, foo7648_nomethods, Foo7648
|
|
|
|
const c7648 = 8
|
|
d7648 = 9
|
|
const f7648 = 10
|
|
foo7648(x) = x
|
|
function foo7648_nomethods end
|
|
mutable struct Foo7648 end
|
|
|
|
module TestModSub9475
|
|
using Base.Test
|
|
using ..TestMod7648
|
|
import ..curmod_name
|
|
export a9475, foo9475
|
|
a9475 = 5
|
|
b9475 = 7
|
|
foo9475(x) = x
|
|
let
|
|
@test Base.binding_module(:a9475) == current_module()
|
|
@test Base.binding_module(:c7648) == TestMod7648
|
|
@test Base.module_name(current_module()) == :TestModSub9475
|
|
@test Base.fullname(current_module()) == (curmod_name..., :TestMod7648,
|
|
:TestModSub9475)
|
|
@test Base.module_parent(current_module()) == TestMod7648
|
|
end
|
|
end # module TestModSub9475
|
|
|
|
using .TestModSub9475
|
|
|
|
let
|
|
@test Base.binding_module(:d7648) == current_module()
|
|
@test Base.binding_module(:a9475) == TestModSub9475
|
|
@test Base.module_name(current_module()) == :TestMod7648
|
|
@test Base.module_parent(current_module()) == curmod
|
|
end
|
|
end # module TestMod7648
|
|
|
|
let
|
|
@test Base.binding_module(TestMod7648, :d7648) == TestMod7648
|
|
@test Base.binding_module(TestMod7648, :a9475) == TestMod7648.TestModSub9475
|
|
@test Base.binding_module(TestMod7648.TestModSub9475, :b9475) == TestMod7648.TestModSub9475
|
|
@test Set(names(TestMod7648))==Set([:TestMod7648, :a9475, :foo9475, :c7648, :foo7648, :foo7648_nomethods, :Foo7648])
|
|
@test Set(names(TestMod7648, true)) == Set([:TestMod7648, :TestModSub9475, :a9475, :foo9475, :c7648, :d7648, :f7648,
|
|
:foo7648, Symbol("#foo7648"), :foo7648_nomethods, Symbol("#foo7648_nomethods"),
|
|
:Foo7648, :eval, Symbol("#eval")])
|
|
@test Set(names(TestMod7648, true, true)) == Set([:TestMod7648, :TestModSub9475, :a9475, :foo9475, :c7648, :d7648, :f7648,
|
|
:foo7648, Symbol("#foo7648"), :foo7648_nomethods, Symbol("#foo7648_nomethods"),
|
|
:Foo7648, :eval, Symbol("#eval"), :convert, :curmod_name, :curmod])
|
|
@test isconst(TestMod7648, :c7648)
|
|
@test !isconst(TestMod7648, :d7648)
|
|
end
|
|
|
|
let
|
|
using .TestMod7648
|
|
@test Base.binding_module(:a9475) == TestMod7648.TestModSub9475
|
|
@test Base.binding_module(:c7648) == TestMod7648
|
|
@test Base.function_name(foo7648) == :foo7648
|
|
@test Base.function_module(foo7648, (Any,)) == TestMod7648
|
|
@test Base.function_module(foo7648) == TestMod7648
|
|
@test Base.function_module(foo7648_nomethods) == TestMod7648
|
|
@test Base.function_module(foo9475, (Any,)) == TestMod7648.TestModSub9475
|
|
@test Base.function_module(foo9475) == TestMod7648.TestModSub9475
|
|
@test Base.datatype_module(Foo7648) == TestMod7648
|
|
@test Base.datatype_name(Foo7648) == :Foo7648
|
|
@test basename(functionloc(foo7648, (Any,))[1]) == "reflection.jl"
|
|
@test first(methods(TestMod7648.TestModSub9475.foo7648)) == @which foo7648(5)
|
|
@test TestMod7648 == @which foo7648
|
|
@test TestMod7648.TestModSub9475 == @which a9475
|
|
end
|
|
|
|
@test_throws ArgumentError which(===, Tuple{Int, Int})
|
|
@test_throws ArgumentError code_typed(===, Tuple{Int, Int})
|
|
@test_throws ArgumentError code_llvm(===, Tuple{Int, Int})
|
|
@test_throws ArgumentError code_native(===, Tuple{Int, Int})
|
|
@test_throws ArgumentError Base.return_types(===, Tuple{Int, Int})
|
|
|
|
module TestingExported
|
|
using Base.Test
|
|
import Base.isexported
|
|
global this_is_not_defined
|
|
export this_is_not_defined
|
|
@test_throws ErrorException which(:this_is_not_defined)
|
|
@test_throws ErrorException @which this_is_not_defined
|
|
@test_throws ErrorException which(:this_is_not_exported)
|
|
@test isexported(current_module(), :this_is_not_defined)
|
|
@test !isexported(current_module(), :this_is_not_exported)
|
|
const a_value = 1
|
|
@test which(:a_value) == current_module()
|
|
@test !isexported(current_module(), :a_value)
|
|
end
|
|
|
|
# issue #13264
|
|
@test isa((@which vcat(1...)), Method)
|
|
|
|
# issue #13464
|
|
let t13464 = "hey there sailor"
|
|
try
|
|
@which t13464[1,1] = (1.0,true)
|
|
error("unexpected")
|
|
catch err13464
|
|
@test startswith(err13464.msg, "expression is not a function call, or is too complex")
|
|
end
|
|
end
|
|
|
|
# PR 13825
|
|
let ex = :(a + b)
|
|
@test string(ex) == "a + b"
|
|
ex.typ = Integer
|
|
@test string(ex) == "(a + b)::Integer"
|
|
end
|
|
foo13825{T, N}(::Array{T,N}, ::Array, ::Vector) = nothing
|
|
@test startswith(string(first(methods(foo13825))),
|
|
"foo13825(::Array{T,N}, ::Array, ::Array{T,1} where T)")
|
|
|
|
mutable struct TLayout
|
|
x::Int8
|
|
y::Int16
|
|
z::Int32
|
|
end
|
|
tlayout = TLayout(5,7,11)
|
|
@test fieldnames(tlayout) == fieldnames(TLayout) == [:x, :y, :z]
|
|
@test [(fieldoffset(TLayout,i), fieldname(TLayout,i), fieldtype(TLayout,i)) for i = 1:nfields(TLayout)] ==
|
|
[(0, :x, Int8), (2, :y, Int16), (4, :z, Int32)]
|
|
@test_throws BoundsError fieldtype(TLayout, 0)
|
|
@test_throws BoundsError fieldname(TLayout, 0)
|
|
@test_throws BoundsError fieldoffset(TLayout, 0)
|
|
@test_throws BoundsError fieldtype(TLayout, 4)
|
|
@test_throws BoundsError fieldname(TLayout, 4)
|
|
@test_throws BoundsError fieldoffset(TLayout, 4)
|
|
|
|
@test fieldtype(Tuple{Vararg{Int8}}, 1) === Int8
|
|
@test fieldtype(Tuple{Vararg{Int8}}, 10) === Int8
|
|
@test_throws BoundsError fieldtype(Tuple{Vararg{Int8}}, 0)
|
|
|
|
@test fieldnames((1,2,3)) == fieldnames(NTuple{3, Int}) == [fieldname(NTuple{3, Int}, i) for i = 1:3] == [1, 2, 3]
|
|
@test_throws BoundsError fieldname(NTuple{3, Int}, 0)
|
|
@test_throws BoundsError fieldname(NTuple{3, Int}, 4)
|
|
|
|
import Base: isstructtype, type_alignment, return_types
|
|
@test !isstructtype(Union{})
|
|
@test !isstructtype(Union{Int,Float64})
|
|
@test !isstructtype(Int)
|
|
@test isstructtype(TLayout)
|
|
@test type_alignment(UInt16) == 2
|
|
@test type_alignment(TLayout) == 4
|
|
let rts = return_types(TLayout)
|
|
@test length(rts) >= 3 # general constructor, specific constructor, and call-to-convert adapter(s)
|
|
@test all(rts .== TLayout)
|
|
end
|
|
|
|
# issue #15447
|
|
@noinline function f15447(s, a)
|
|
if s
|
|
return a
|
|
else
|
|
nb = 0
|
|
return nb
|
|
end
|
|
end
|
|
@test functionloc(f15447)[2] > 0
|
|
|
|
# issue #14346
|
|
@noinline function f14346(id, mask, limit)
|
|
if id <= limit && mask[id]
|
|
return true
|
|
end
|
|
end
|
|
@test functionloc(f14346)[2] == @__LINE__-4
|
|
|
|
# test jl_get_llvm_fptr. We test functions both in and definitely not in the system image
|
|
definitely_not_in_sysimg() = nothing
|
|
for (f, t) in Any[(definitely_not_in_sysimg, Tuple{}),
|
|
(Base.:+, Tuple{Int, Int})]
|
|
meth = which(f, t)
|
|
tt = Tuple{typeof(f), t.parameters...}
|
|
env = (ccall(:jl_match_method, Any, (Any, Any), tt, meth.sig))[2]
|
|
world = typemax(UInt)
|
|
linfo = ccall(:jl_specializations_get_linfo, Ref{Core.MethodInstance}, (Any, Any, Any, UInt), meth, tt, env, world)
|
|
params = Base.CodegenParams()
|
|
llvmf = ccall(:jl_get_llvmf_decl, Ptr{Void}, (Any, UInt, Bool, Base.CodegenParams), linfo::Core.MethodInstance, world, true, params)
|
|
@test llvmf != C_NULL
|
|
@test ccall(:jl_get_llvm_fptr, Ptr{Void}, (Ptr{Void},), llvmf) != C_NULL
|
|
end
|
|
|
|
module MacroTest
|
|
export @macrotest
|
|
macro macrotest(x::Int, y::Symbol) end
|
|
macro macrotest(x::Int, y::Int)
|
|
nothing #This is here because of #15280
|
|
end
|
|
end
|
|
|
|
let
|
|
using .MacroTest
|
|
a = 1
|
|
m = getfield(current_module(), Symbol("@macrotest"))
|
|
@test which(m, Tuple{Int,Symbol})==@which @macrotest 1 a
|
|
@test which(m, Tuple{Int,Int})==@which @macrotest 1 1
|
|
|
|
@test first(methods(m,Tuple{Int, Int}))==@which MacroTest.@macrotest 1 1
|
|
@test functionloc(@which @macrotest 1 1) == @functionloc @macrotest 1 1
|
|
end
|
|
|
|
# issue #15714
|
|
# show variable names for slots and suppress spurious type warnings
|
|
function f15714(array_var15714)
|
|
for index_var15714 in eachindex(array_var15714)
|
|
array_var15714[index_var15714] += 0
|
|
end
|
|
end
|
|
|
|
function g15714(array_var15714)
|
|
for index_var15714 in eachindex(array_var15714)
|
|
array_var15714[index_var15714] += 0
|
|
end
|
|
for index_var15714 in eachindex(array_var15714)
|
|
array_var15714[index_var15714] += 0
|
|
end
|
|
end
|
|
|
|
used_dup_var_tested15714 = false
|
|
used_unique_var_tested15714 = false
|
|
function test_typed_ast_printing(f::ANY, types::ANY, must_used_vars)
|
|
src, rettype = code_typed(f, types)[1]
|
|
dupnames = Set()
|
|
slotnames = Set()
|
|
for name in src.slotnames
|
|
if name in slotnames
|
|
push!(dupnames, name)
|
|
else
|
|
push!(slotnames, name)
|
|
end
|
|
end
|
|
# Make sure must_used_vars are in slotnames
|
|
for name in must_used_vars
|
|
@test name in slotnames
|
|
end
|
|
for str in (sprint(code_warntype, f, types),
|
|
stringmime("text/plain", src))
|
|
for var in must_used_vars
|
|
@test contains(str, string(var))
|
|
end
|
|
@test !contains(str, "Any")
|
|
@test !contains(str, "ANY")
|
|
# Check that we are not printing the bare slot numbers
|
|
for i in 1:length(src.slotnames)
|
|
name = src.slotnames[i]
|
|
if name in dupnames
|
|
@test contains(str, "_$i")
|
|
if name in must_used_vars
|
|
global used_dup_var_tested15714 = true
|
|
end
|
|
else
|
|
@test !contains(str, "_$i")
|
|
if name in must_used_vars
|
|
global used_unique_var_tested15714 = true
|
|
end
|
|
end
|
|
end
|
|
end
|
|
# Make sure printing an AST outside CodeInfo still works.
|
|
str = sprint(show, src.code)
|
|
# Check that we are printing the slot numbers when we don't have the context
|
|
# Use the variable names that we know should be present in the optimized AST
|
|
for i in 2:length(src.slotnames)
|
|
name = src.slotnames[i]
|
|
if name in must_used_vars
|
|
@test contains(str, "_$i")
|
|
end
|
|
end
|
|
end
|
|
test_typed_ast_printing(f15714, Tuple{Vector{Float32}},
|
|
[:array_var15714, :index_var15714])
|
|
test_typed_ast_printing(g15714, Tuple{Vector{Float32}},
|
|
[:array_var15714, :index_var15714])
|
|
@test used_dup_var_tested15714
|
|
@test used_unique_var_tested15714
|
|
|
|
let li = typeof(getfield).name.mt.cache.func::Core.MethodInstance,
|
|
lrepr = string(li),
|
|
mrepr = string(li.def),
|
|
lmime = stringmime("text/plain", li),
|
|
mmime = stringmime("text/plain", li.def)
|
|
|
|
@test lrepr == lmime == "MethodInstance for getfield(...)"
|
|
@test mrepr == mmime == "getfield(...) in Core"
|
|
end
|
|
|
|
|
|
# Linfo Tracing test
|
|
tracefoo(x, y) = x+y
|
|
didtrace = false
|
|
tracer(x::Ptr{Void}) = (@test isa(unsafe_pointer_to_objref(x), Core.MethodInstance); global didtrace = true; nothing)
|
|
ccall(:jl_register_method_tracer, Void, (Ptr{Void},), cfunction(tracer, Void, (Ptr{Void},)))
|
|
meth = which(tracefoo,Tuple{Any,Any})
|
|
ccall(:jl_trace_method, Void, (Any,), meth)
|
|
@test tracefoo(1, 2) == 3
|
|
ccall(:jl_untrace_method, Void, (Any,), meth)
|
|
@test didtrace
|
|
didtrace = false
|
|
@test tracefoo(1.0, 2.0) == 3.0
|
|
@test !didtrace
|
|
ccall(:jl_register_method_tracer, Void, (Ptr{Void},), C_NULL)
|
|
|
|
# Method Tracing test
|
|
methtracer(x::Ptr{Void}) = (@test isa(unsafe_pointer_to_objref(x), Method); global didtrace = true; nothing)
|
|
ccall(:jl_register_newmeth_tracer, Void, (Ptr{Void},), cfunction(methtracer, Void, (Ptr{Void},)))
|
|
tracefoo2(x, y) = x*y
|
|
@test didtrace
|
|
didtrace = false
|
|
tracefoo(x::Int64, y::Int64) = x*y
|
|
@test didtrace
|
|
didtrace = false
|
|
ccall(:jl_register_newmeth_tracer, Void, (Ptr{Void},), C_NULL)
|
|
|
|
# test for reflection over large method tables
|
|
for i = 1:100; @eval fLargeTable(::Val{$i}, ::Any) = 1; end
|
|
for i = 1:100; @eval fLargeTable(::Any, ::Val{$i}) = 2; end
|
|
fLargeTable(::Any...) = 3
|
|
@test length(methods(fLargeTable, Tuple{})) == 1
|
|
fLargeTable(::Complex, ::Complex) = 4
|
|
fLargeTable(::Union{Complex64, Complex128}...) = 5
|
|
@test length(methods(fLargeTable, Tuple{})) == 1
|
|
fLargeTable() = 4
|
|
@test length(methods(fLargeTable)) == 204
|
|
@test length(methods(fLargeTable, Tuple{})) == 1
|
|
@test fLargeTable(1im, 2im) == 4
|
|
@test fLargeTable(1.0im, 2.0im) == 5
|
|
@test_throws MethodError fLargeTable(Val{1}(), Val{1}())
|
|
@test fLargeTable(Val{1}(), 1) == 1
|
|
@test fLargeTable(1, Val{1}()) == 2
|
|
|
|
# issue #15280
|
|
function f15280(x) end
|
|
@test functionloc(f15280)[2] > 0
|
|
|
|
# bug found in #16850, Base.url with backslashes on Windows
|
|
function module_depth(from::Module, to::Module)
|
|
if from === to
|
|
return 0
|
|
else
|
|
return 1 + module_depth(from, module_parent(to))
|
|
end
|
|
end
|
|
function has_backslashes(mod::Module)
|
|
for n in names(mod, true, true)
|
|
isdefined(mod, n) || continue
|
|
Base.isdeprecated(mod, n) && continue
|
|
f = getfield(mod, n)
|
|
if isa(f, Module) && module_depth(Main, f) <= module_depth(Main, mod)
|
|
continue
|
|
end
|
|
h = has_backslashes(f)
|
|
isnull(h) || return h
|
|
end
|
|
return Nullable{Method}()
|
|
end
|
|
function has_backslashes(f::Function)
|
|
for m in methods(f)
|
|
h = has_backslashes(m)
|
|
isnull(h) || return h
|
|
end
|
|
return Nullable{Method}()
|
|
end
|
|
function has_backslashes(meth::Method)
|
|
if '\\' in string(meth.file)
|
|
return Nullable{Method}(meth)
|
|
else
|
|
return Nullable{Method}()
|
|
end
|
|
end
|
|
has_backslashes(x) = Nullable{Method}()
|
|
h16850 = has_backslashes(Base)
|
|
if is_windows()
|
|
if isnull(h16850)
|
|
warn("No methods found in Base with backslashes in file name, ",
|
|
"skipping test for Base.url")
|
|
else
|
|
@test !('\\' in Base.url(get(h16850)))
|
|
end
|
|
else
|
|
@test isnull(h16850)
|
|
end
|
|
|
|
# Adds test for PR #17636
|
|
let a = @code_typed 1 + 1
|
|
b = @code_lowered 1 + 1
|
|
@test isa(a, Pair{CodeInfo, DataType})
|
|
@test isa(b, CodeInfo)
|
|
@test isa(a[1].code, Array{Any,1})
|
|
@test isa(b.code, Array{Any,1})
|
|
|
|
function thing(a::Array, b::Real)
|
|
println("thing")
|
|
end
|
|
function thing(a::AbstractArray, b::Int)
|
|
println("blah")
|
|
end
|
|
@test_throws MethodError thing(rand(10), 1)
|
|
a = @code_typed thing(rand(10), 1)
|
|
b = @code_lowered thing(rand(10), 1)
|
|
@test length(a) == 0
|
|
@test length(b) == 0
|
|
end
|
|
|
|
mutable struct A18434
|
|
end
|
|
(::Type{A18434})(x; y=1) = 1
|
|
|
|
global counter18434 = 0
|
|
function get_A18434()
|
|
global counter18434
|
|
counter18434 += 1
|
|
return A18434
|
|
end
|
|
@which get_A18434()(1; y=2)
|
|
@test counter18434 == 1
|
|
@which get_A18434()(1, y=2)
|
|
@test counter18434 == 2
|
|
|
|
# PR #18888: code_typed shouldn't cache if not optimizing
|
|
let
|
|
world = typemax(UInt)
|
|
f18888() = return nothing
|
|
m = first(methods(f18888, Tuple{}))
|
|
@test m.specializations === nothing
|
|
ft = typeof(f18888)
|
|
|
|
code_typed(f18888, Tuple{}; optimize=false)
|
|
@test m.specializations !== nothing # uncached, but creates the specializations entry
|
|
code = Core.Inference.code_for_method(m, Tuple{ft}, Core.svec(), world, true)
|
|
@test !isdefined(code, :inferred)
|
|
|
|
code_typed(f18888, Tuple{}; optimize=true)
|
|
code = Core.Inference.code_for_method(m, Tuple{ft}, Core.svec(), world, true)
|
|
@test isdefined(code, :inferred)
|
|
end
|
|
|
|
# Issue #18883, code_llvm/code_native for generated functions
|
|
@generated f18883() = nothing
|
|
@test !isempty(sprint(code_llvm, f18883, Tuple{}))
|
|
@test !isempty(sprint(code_native, f18883, Tuple{}))
|
|
|
|
# PR #19964
|
|
@test isempty(subtypes(Float64))
|
|
|
|
# New reflection methods in 0.6
|
|
struct ReflectionExample{T<:AbstractFloat, N}
|
|
x::Tuple{T, N}
|
|
end
|
|
|
|
@test Base.isabstract(AbstractArray)
|
|
@test !Base.isabstract(ReflectionExample)
|
|
@test !Base.isabstract(Int)
|
|
|
|
@test Base.parameter_upper_bound(ReflectionExample, 1) === AbstractFloat
|
|
@test Base.parameter_upper_bound(ReflectionExample, 2) === Any
|
|
@test Base.parameter_upper_bound(ReflectionExample{T, N} where T where N <: Real, 2) === Real
|
|
|
|
let
|
|
wrapperT(T) = Base.typename(T).wrapper
|
|
@test @inferred wrapperT(ReflectionExample{Float64, Int64}) == ReflectionExample
|
|
@test @inferred wrapperT(ReflectionExample{Float64, N} where N) == ReflectionExample
|
|
@test @inferred wrapperT(ReflectionExample{T, Int64} where T) == ReflectionExample
|
|
@test @inferred wrapperT(ReflectionExample) == ReflectionExample
|
|
@test @inferred wrapperT(Union{ReflectionExample{Union{},1},ReflectionExample{Float64,1}}) == ReflectionExample
|
|
@test_throws ErrorException Base.typename(Union{Int, Float64})
|
|
end
|
|
|
|
# Issue #20086
|
|
abstract type A20086{T,N} end
|
|
struct B20086{T,N} <: A20086{T,N} end
|
|
@test subtypes(A20086) == [B20086]
|
|
@test subtypes(A20086{Int}) == [B20086{Int}]
|
|
@test subtypes(A20086{T,3} where T) == [B20086{T,3} where T]
|
|
@test subtypes(A20086{Int,3}) == [B20086{Int,3}]
|