All notable changes to this project will be documented in this file.
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
- An extension that integrates
@report_opt
with Cthulhu (#648) reportkey
for trimming multiple reports that resolve to the same runtime-dispatch caller/callee pair (#648)
report_opt
no longer raises reports from callees onthrow
code path when theskip_unoptimized_throw_blocks::Bool=true
configuration is enabled (#643).
analyze_from_definitions
can now be specified asentry_point_name::Symbol
to make JET's top-level analyses start analysis using the interpreted method signature whose name is equal toentry_point_name
as the analysis entry point. For example, when analyzing a script that specifies its entry point using the new@main
special macro, you can specifyreport_file(script_name; analyze_from_definitions=:main)
to automatically start the analysis from themain(args)
function.
- Made some adjustments to the warning text in the README.
- A simple logo badge for JET.jl is now available (thanks to @MilesCranmer!).
You can add the line
[![](https://img.shields.io/badge/%F0%9F%9B%A9%EF%B8%8F_tested_with-JET.jl-233f9a)](https://github.com/aviatesk/JET.jl)
to your package's README to display the logo image that shows your package uses JET.jl for code quality checks (#635). - JET's top-level analyses such as
report_package
andreport_file
can now handle the newpublic
keyword that is introduced in v1.11. (#637)
- Fixed the issue where the line numbers of methods whose locations were revised by Revise were not being updated (#513).
- A new configuration
stacktrace_types_limit::Union{Nothing,Int}=nothing
has been added. It's turned on by default and limits deeply nested types when JET prints reports. If you prefer the old behavior, setstacktrace_types_limit=0
(#601).
- Revise.jl-related features are now implemented as a package extension, so in order to use
watch_file
, you need to load Revise.jl into your session first (#624, #625). - The compatibility with LoweredCodeUtils has been raised to version 2.4 and later, so it's
now possible to use the latest version of Revise with JET again. Additionally, the
top-level statement selection algorithm internally used by top-level analysis functions
like
report_file
has been significantly improved.
report_package
now supports theusing Module: Inner.object
syntax (#554, #555).- Various internal improvements.
- Changed the default
toplevel_logger
configuration fortest_package
tonothing
.test_package
no longer emits logs like[toplevel-info] analyzing from top-level definitions (xxx/yyy)
(#550).
- Fixed the default
ignore_missing_comparison
configuration forreport_package
.
- Fixed
report_package
so that it does not produce noisy error reports from reducing on potentially empty collections.
- Made the
(x == y)::Union{Missing,Bool} → Any
widening behavior forreport_package
(that was added in #542) configurable. Specifyreport_package("TargetPkg", ignore_missing_comparison=false)
ifTargetPkg
handlesmissing
(#547).
- Generalized the
(x == y)::Union{Missing,Bool} → Any
widening behavior forreport_package
that was added in #542 to other comparison operators (e.g.in
) (#545).
-
JET now ignores the possibility of a poorly-inferred
x == y
call returningmissing
during thereport_package
analysis. Refer to issue #542 for reasons justifying this behavior. Essentially,report_package
often relies on poor input argument type information at the beginning of analysis, leading to noisy error reports for function definitions like:struct MyToken end ismytoken(x) = x == MyToken() ? true : false
This error is arguably just noise when the target package does not handle
missing
.report_package
is designed as an entry point for easy analysis, even at the cost of accuracy, so it is not sound from the beginning. Hence, it might be beneficial to simply ignore such noise.However note that in interactive entry points like
report_call
, where concrete input argument types are available, this behavior should be turned off. This is because, if the code, when given specific input argument types, results in aUnion{Bool,Missing}
possibility, it likely signifies an inferrability issue or the code really needs to handlemissing
(#541, #542).
report_package
now supports theusing MyPkg
syntax (without specifying relative module path...
) from inner modules ofMyPkg
(#539, #540).
report_call
andreport_opt
can now analyzemi::MethodInstance
. This feature allows JET to analyze method instances collected byMethodAnalysis.methodinstances
. See the documentation for the details. (#510)- This CHANGELOG.md has been added and will be updated (#536).
- JET's tree-like view, which represents inference stacktrace leading to each error point,
now closely resembles the stacktrace displayed by Julia Base upon exception.
The new view should be more intuitive for general users and additionally, the type
information of arguments of each frame are nicely truncated, as in Julia Base.
Before
julia> @report_call sum([]) ═════ 1 possible error found ═════ ┌ @ reducedim.jl:996 Base.:(var"#sum#821")(:, pairs(NamedTuple()), #self#, a) │┌ @ reducedim.jl:996 Base._sum(a, dims) ││┌ @ reducedim.jl:1000 Base.:(var"#_sum#823")(pairs(NamedTuple()), #self#, a, _3) │││┌ @ reducedim.jl:1000 Base._sum(identity, a, :) ││││┌ @ reducedim.jl:1001 Base.:(var"#_sum#824")(pairs(NamedTuple()), #self#, f, a, _4) │││││┌ @ reducedim.jl:1001 mapreduce(f, Base.add_sum, a) ││││││┌ @ reducedim.jl:357 Base.:(var"#mapreduce#814")(:, Base._InitialValue(), #self#, f, op, A) │││││││┌ @ reducedim.jl:357 Base._mapreduce_dim(f, op, init, A, dims) ││││││││┌ @ reducedim.jl:365 Base._mapreduce(f, op, IndexStyle(A), A) │││││││││┌ @ reduce.jl:432 Base.mapreduce_empty_iter(f, op, A, Base.IteratorEltype(A)) ││││││││││┌ @ reduce.jl:380 Base.reduce_empty_iter(Base.MappingRF(f, op), itr, ItrEltype) │││││││││││┌ @ reduce.jl:384 Base.reduce_empty(op, eltype(itr)) ││││││││││││┌ @ reduce.jl:361 Base.mapreduce_empty(op.f, op.rf, T) │││││││││││││┌ @ reduce.jl:372 Base.reduce_empty(op, T) ││││││││││││││┌ @ reduce.jl:352 Base.reduce_empty(+, T) │││││││││││││││┌ @ reduce.jl:343 zero(T) ││││││││││││││││┌ @ missing.jl:106 Base.throw(Base.MethodError(zero, tuple(Base.Any))) │││││││││││││││││ MethodError: no method matching zero(::Type{Any}): Base.throw(Base.MethodError(zero, tuple(Base.Any)::Tuple{DataType})::MethodError) ││││││││││││││││└──────────────────
After
(#524)julia> @report_call sum([]) ═════ 1 possible error found ═════ ┌ sum(a::Vector{Any}) @ Base ./reducedim.jl:996 │┌ sum(a::Vector{Any}; dims::Colon, kw::@Kwargs{}) @ Base ./reducedim.jl:996 ││┌ _sum(a::Vector{Any}, ::Colon) @ Base ./reducedim.jl:1000 │││┌ _sum(a::Vector{Any}, ::Colon; kw::@Kwargs{}) @ Base ./reducedim.jl:1000 ││││┌ _sum(f::typeof(identity), a::Vector{Any}, ::Colon) @ Base ./reducedim.jl:1001 │││││┌ _sum(f::typeof(identity), a::Vector{Any}, ::Colon; kw::@Kwargs{}) @ Base ./reducedim.jl:1001 ││││││┌ mapreduce(f::typeof(identity), op::typeof(Base.add_sum), A::Vector{Any}) @ Base ./reducedim.jl:357 │││││││┌ mapreduce(f::typeof(identity), op::typeof(Base.add_sum), A::Vector{Any}; dims::Colon, init::Base._InitialValue) @ Base ./reducedim.jl:357 ││││││││┌ _mapreduce_dim(f::typeof(identity), op::typeof(Base.add_sum), ::Base._InitialValue, A::Vector{Any}, ::Colon) @ Base ./reducedim.jl:365 │││││││││┌ _mapreduce(f::typeof(identity), op::typeof(Base.add_sum), ::IndexLinear, A::Vector{Any}) @ Base ./reduce.jl:432 ││││││││││┌ mapreduce_empty_iter(f::typeof(identity), op::typeof(Base.add_sum), itr::Vector{Any}, ItrEltype::Base.HasEltype) @ Base ./reduce.jl:380 │││││││││││┌ reduce_empty_iter(op::Base.MappingRF{typeof(identity), typeof(Base.add_sum)}, itr::Vector{Any}, ::Base.HasEltype) @ Base ./reduce.jl:384 ││││││││││││┌ reduce_empty(op::Base.MappingRF{typeof(identity), typeof(Base.add_sum)}, ::Type{Any}) @ Base ./reduce.jl:361 │││││││││││││┌ mapreduce_empty(::typeof(identity), op::typeof(Base.add_sum), T::Type{Any}) @ Base ./reduce.jl:372 ││││││││││││││┌ reduce_empty(::typeof(Base.add_sum), ::Type{Any}) @ Base ./reduce.jl:352 │││││││││││││││┌ reduce_empty(::typeof(+), ::Type{Any}) @ Base ./reduce.jl:343 ││││││││││││││││┌ zero(::Type{Any}) @ Base ./missing.jl:106 │││││││││││││││││ MethodError: no method matching zero(::Type{Any}): Base.throw(Base.MethodError(zero, tuple(Base.Any)::Tuple{DataType})::MethodError) ││││││││││││││││└────────────────────
- A predicate function that is specified as the
function_filter
configuration now takes a function object instead of its type. For instance, the following codeshould now be written:myfilter(@nospecialize ft) = !( ft === typeof(Base.mapreduce_empty) || ft === typeof(Base.reduce_empty)) @test_opt function_filter=myfilter func(args...)
(#507).myfilter(@nospecialize f) = !( f === Base.mapreduce_empty || f === Base.reduce_empty) @test_opt function_filter=myfilter func(args...)
- Dropped the support for Julia 1.8. JET now supports Julia 1.9 and above (#527).
report_and_watch_file
has been removed. Usewatch_file
instead.
- Concrete evaluation is now enabled within JET's error analysis. This fixes numerous false positive error reports, and leads to faster analysis speed (#529, #523, #522).
report_package
no longer reports error from methods that are intentionally designed to throw, e.g.(#532, #477).@noinline raise_error(x::T) where T = error(lazy"Missing interface implementation for $T")
report_package
no longer reports error from methods with keyword arguments that don't have default values, e.g.(#532, #478).struct Bar x end Bar(; x) = Bar(x)
- Fixed false error report from
Base.aligned_sizeof
(#512, #514, JuliaLang/julia#49801). - The optimization analysis has been adjusted to prevent skipping the reporting of runtime dispatches within non-compileable but inlineable frames (#526).
- The sound error analysis mode has been fixed and now reports if there are any unanalyzed function calls, which typically occur due to excessive matching methods (#533).
report_file
can now handle parameterized type alias definitions (#534).- Extensive refactoring and cleanup has been carried out.