diff --git a/src/StabilityCheck.jl b/src/StabilityCheck.jl index b0620e6ff..554943ad5 100644 --- a/src/StabilityCheck.jl +++ b/src/StabilityCheck.jl @@ -21,7 +21,7 @@ export @stable, @stable!, @stable!_nop, SkippedUnionAlls, UnboundedUnionAlls, SkipMandatory, Stb, Uns, UConstr, UConstrExist, AnyParam, VarargParam, TcFail, OutOfFuel, GenericMethod, - SearchCfg, build_typesdb_scfg, default_scfg, + SearchCfg, build_typesdb_scfg, default_scfg, trace_scfg, # Utils split_method # mostly for testing @@ -124,6 +124,11 @@ is_stable_method(m::Method, scfg :: SearchCfg = default_scfg) :: StCheck = begin @debug "is_stable_method: $m" global stepCount = 0 + # trace TS checks and store to a file + if scfg.trace_checks + fchecks = open("checks", "a") + end + # preemptively load types DB if available: we may need to sample # unbounded exists any minute if scfg.typesDBcfg.use_types_db @@ -142,12 +147,14 @@ is_stable_method(m::Method, scfg :: SearchCfg = default_scfg) :: StCheck = begin # Step 2a: run type inference with the input type even if abstract # and party if we're concrete @debug "is_stable_method: check against signature (2a)" - try - if is_stable_call(func, sig_types) - return Stb(1) + if ! scfg.trace_checks # we don't want the shortcut if we're in the tracing mode + try + if is_stable_call(func, sig_types) + return Stb(1) + end + catch e + return TcFail(sig_types, e) end - catch e - return TcFail(sig_types, e) end # Shortcut: @@ -187,6 +194,8 @@ is_stable_method(m::Method, scfg :: SearchCfg = default_scfg) :: StCheck = begin # the actual stability check try + scfg.trace_checks && + print_check(fchecks, m, ts) if ! is_stable_call(func, ts) push!(unst, ts) if scfg.failfast @@ -194,10 +203,14 @@ is_stable_method(m::Method, scfg :: SearchCfg = default_scfg) :: StCheck = begin end end catch e + scfg.trace_checks && + close(fchecks) return TcFail(ts, e) end end + scfg.trace_checks && + close(fchecks) result isa OutOfFuel && return result return if isempty(unst) diff --git a/src/types.jl b/src/types.jl index b6d4faf3e..d01351f0f 100644 --- a/src/types.jl +++ b/src/types.jl @@ -122,6 +122,9 @@ Base.@kwdef struct SearchCfg typesDBcfg :: TypesDBCfg = TypesDBCfg() # ^--- Parameters of the types DB. + + trace_checks :: Bool = false +# ^-- create a file recording all type stability checks of a method end # @@ -131,6 +134,8 @@ default_scfg = SearchCfg() fast_scfg = SearchCfg(fuel=30) +trace_scfg = SearchCfg(trace_checks=true) + build_typesdb_scfg(inFile = intypesCsvFileDefault; sample_count :: Int = 100000) = begin tdbFull = typesDB(inFile) sampleCountActual = min(length(tdbFull),sample_count) diff --git a/src/utils.jl b/src/utils.jl index e5158ce75..e34818784 100644 --- a/src/utils.jl +++ b/src/utils.jl @@ -134,3 +134,10 @@ is_module_nested(m::Module, outer::Module) :: Bool = begin m = parentmodule(m) end end + +# Print type stability check in a form of pseudo-method declaration +print_check(io, m::Method, @nospecialize(types)) = begin + print(io, "function $(m.name)(") + print(io, join(map(t->"::$t", types), ", ")) + println(io, ")") +end diff --git a/test/runtests.jl b/test/runtests.jl index 866379843..90916ae1e 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -92,39 +92,42 @@ unstable_funion(x::Bool, y::Union{TwoSubtypes, Bool}) = if x 1 else "" end # Tests # +test_scfg = default_scfg + @testset "Simple stable " begin - t1 = is_stable_method(@which add1s(1)) + global test_scfg + t1 = is_stable_method((@which add1s(1)), test_scfg) @test isa(t1, Stb) - @test isa(is_stable_method(@which plus2s(1,1)) , Stb) - @test isa(is_stable_method(@which add1typcase(1)), OutOfFuel) + @test isa(is_stable_method((@which plus2s(1,1)), test_scfg) , Stb) + @test isa(is_stable_method((@which add1typcase(1)), test_scfg), OutOfFuel) # cf. Note: generic methods - #@test isa(is_stable_method(@which rational_plusi(1//1,1//1)) , Stb) + #@test isa(is_stable_method((@which rational_plusi(1//1,1//1)), test_scfg) , Stb) - @test isa(is_stable_method(@which add1c(1.0 + 1.0im)) , Stb) + @test isa(is_stable_method((@which add1c(1.0 + 1.0im)), test_scfg) , Stb) end @testset "Simple out-of-fuel " begin - t1 = is_stable_method(@which add1i(1)) + t1 = is_stable_method((@which add1i(1)), test_scfg) @test isa(t1, OutOfFuel) # @test length(t1.skipexist) == 1 && # contains("$t1.skipexist", "SentinelArrays.ChainedVectorIndex") # SentinelArrays.ChainedVectorIndex comes from CSV, which we depend upon for # reporting. Would be nice to factor out reporting - @test isa(is_stable_method(@which plus2i(1,1)) , OutOfFuel) - @test isa(is_stable_method(@which add1typcase(1)), OutOfFuel) + @test isa(is_stable_method((@which plus2i(1,1)), test_scfg) , OutOfFuel) + @test isa(is_stable_method((@which add1typcase(1)), test_scfg), OutOfFuel) # cf. Note: generic methods - #@test isa(is_stable_method(@which rational_plusi(1//1,1//1)) , Stb) + #@test isa(is_stable_method((@which rational_plusi(1//1,1//1)), test_scfg) , Stb) end @testset "Simple unstable " begin - @test isa(is_stable_method(@which add1n(1)), UConstr) - @test isa(is_stable_method(@which plus2n(1,1)), UConstr) - @test isa(is_stable_method(@which trivial_unstable(1)), Uns) - res = is_stable_method(@which trivial_unstable2(true, SubtypeA())) + @test isa(is_stable_method((@which add1n(1)), test_scfg), UConstr) + @test isa(is_stable_method((@which plus2n(1,1)), test_scfg), UConstr) + @test isa(is_stable_method((@which trivial_unstable(1)), test_scfg), Uns) + res = is_stable_method((@which trivial_unstable2(true, SubtypeA())), test_scfg) @test res isa Uns # && # TODO: fix the test by switching failfast off and uncomment # length(res.fails) == 2 && @@ -134,16 +137,16 @@ end # cf. Note: generic methods # Alos, this used to fail when abstract instantiations are ON # (compare to the similar test in the "stable" examples) - #@test isa(is_stable_method((@which rational_plusi(1//1,1//1)), SearchCfg(abstract_args=true)), Stb) + #@test isa(is_stable_method(((@which rational_plusi(1//1,1//1)), test_scfg), SearchCfg(abstract_args=true)), Stb) # TODO: not sure why this one lives under unstable, needs investigation: - # @test isa(is_stable_method((@which add1c(1.0 + 1.0im)), SearchCfg(abstract_args=true)) , OutOfFuel) + # @test isa(is_stable_method(((@which add1c(1.0 + 1.0im)), test_scfg), SearchCfg(abstract_args=true)) , OutOfFuel) end @testset "Unions " begin - res = is_stable_method(@which stable_funion(true, true)) + res = is_stable_method((@which stable_funion(true, true)), test_scfg) @test res isa Stb - res = is_stable_method(@which unstable_funion(true, true)) + res = is_stable_method((@which unstable_funion(true, true)), test_scfg) @test res isa Uns # && # TODO: fix the test by switching failfast off and uncomment # length(res.fails) == 3 && @@ -154,24 +157,24 @@ end @testset "Special (Any, Varargs, Generic)" begin f(x)=x - @test is_stable_method(@which f(2)) == AnyParam() + @test is_stable_method((@which f(2)), test_scfg) == AnyParam() g(x...)=x[1] - @test is_stable_method(@which g(2)) == VarargParam() + @test is_stable_method((@which g(2)), test_scfg) == VarargParam() gen(x::T) where T = 1 - @test is_stable_method(@which gen(1)) == GenericMethod() + @test is_stable_method((@which gen(1)), test_scfg) == GenericMethod() end @testset "Fuel " begin g(x::Int)=2 - @test isa(is_stable_method((@which g(2)), SearchCfg(fuel=1)) , Stb) + @test isa(is_stable_method(((@which g(2))), SearchCfg(fuel=1)) , Stb) h(x::Integer)=x - res = is_stable_method((@which h(2)), SearchCfg(fuel=1)) + res = is_stable_method(((@which h(2))), SearchCfg(fuel=1)) @test res == OutOfFuel() # Instantiations fuel k(x::Complex{T} where T<:Integer)=x+1 - t3 = is_stable_method((@which k(1+1im)), SearchCfg(fuel=1)) + t3 = is_stable_method(((@which k(1+1im))), SearchCfg(fuel=1)) @test t3 isa OutOfFuel # && # TODO: decide if the rest is needed # length(t3.skipexist) == 2 && # one for TooManyInst and @@ -290,15 +293,14 @@ end # See also "Special (Any, Varargs, Generic)" testset above. # typesdb_cfg = build_typesdb_scfg("merged-small.csv") - @test is_stable_method((@which id1(1)), typesdb_cfg) isa Stb + @test is_stable_method(((@which id1(1))), typesdb_cfg) isa Stb myplus(x,y)=x+y - res = is_stable_method((@which myplus(1,2)), typesdb_cfg) + res = is_stable_method(((@which myplus(1,2))), typesdb_cfg) @test res isa Stb uns(x)=if x>1; x+1; else x+1.0 end - resUns = is_stable_method((@which uns(1)), typesdb_cfg) - @info resUns + resUns = is_stable_method(((@which uns(1))), typesdb_cfg) @test resUns isa Uns end