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.
- Even when JET fails to be loaded on nightly versions, stub functions mimicking JET’s API are now defined. These stubs raise an error with an appropriate message when executed. (#688, #689)
- JET is now able to show multiple syntax errors at once, e.g.,
multisyntaxerrors.jl
function f(W,X,Y) s = 0 for i = 1:10 s += g(W[i]*f(X[end-1] + Y[end÷2+]), W[i+1]*f(X[end-2] + Y[end÷2]) +, W[i+2]*f(X[end-3] + Y[end÷2-3])) end return s end
(#687)julia> report_file("multisyntaxerrors.jl") [...] ═════ 2 toplevel errors found ═════ ┌ @ multisyntaxerrors.jl:4 │ # Error @ multisyntaxerrors.jl:4:42 │ for i = 1:10 │ s += g(W[i]*f(X[end-1] + Y[end÷2+]), │ # ╙ ── unexpected `]` └────────────────────── ┌ @ multisyntaxerrors.jl:5 │ # Error @ multisyntaxerrors.jl:5:47 │ s += g(W[i]*f(X[end-1] + Y[end÷2+]), │ W[i+1]*f(X[end-2] + Y[end÷2]) +, │ # ╙ ── unexpected `,` └──────────────────────
- JET.jl now will not be loaded on nightly version by default. This ensures that JETremains
at least loadable on nightly builds, where JET's compatibility is not guaranteed.
If you want to load JET on a nightly version, set the
JET_DEV_MODE
configuration of Preferences.jl totrue
and load it as usual (#684, #686). - JET now fully uses JuliaSyntax.jl for reporting syntax errors (#685).
- Added
include_callback
to the virtual process, allowing custom callback logic during code inclusion (#683).
- Includes internal updates.
- Fixed a broadcasting-related issue in
@report_call
(which caused false error reports) by allowing concrete evaluation fortypejoin
(#669, #670).
- Fixed an exception thrown by
report_package
on Julia 1.11.1 (#668).
- The improved statement selection logic implemented in v0.9.9 is now ported to [email protected], so that it can shared by JET.jl and Revise.jl.
- Added reference documentation on JET’s analysis report-splitting feature (#652).
- Implemented an improved control-flow graph analysis and statement selection logic, enhancing JET’s top-level analysis accuracy (#654).
- 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)
- Updated dependencies, made minor refactorings.
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 imagethat 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.