How to Use JET.jl

Note

JET's analysis entry points follow the naming conventions below:

  • report_xxx: runs analysis, and then prints the collected error points
  • analyze_xxx: just runs analysis, and returns the final state of the analysis

The report_xxx entries are for general users, while analyze_xxx is mainly for internal usages or debugging purposes.

Entry Points into Analysis

JET can analyze your "top-level" code. This means you can just give your Julia file or code to JET and get error reports. report_file, report_and_watch_file, report_package and report_text are the main entry points for that.

JET will analyze your code "half-statically" – JET will selectively interpret "top-level definitions" (like a function definition) and try to simulate Julia's top-level code execution, while it tries to avoid executing any other parts of code like function calls, but analyze them using abstract interpretation (this is a part where JET "statically" analyzes your code). If you're interested in how JET selects "top-level definitions", please see JET.virtual_process.

Warning

Because JET will actually interpret "top-level definitions" in your code, it certainly runs your code. So we should note that JET can cause some side effects from your code; for example JET will try to expand all the macros used in your code, and so the side effects involved with macro expansions will also happen in JET's analysis process.

JET.report_fileFunction
report_file([io::IO = stdout],
            filename::AbstractString;
            jetconfigs...) -> res::ReportResult

Analyzes filename, prints the collected error reports to the io stream, and finally returns res::ReportResult

  • res.included_files::Set{String}: files analyzed by JET
  • res.any_reported::Bool: indicates if there was any error point reported

This function will look for .JET.toml configuration file in the directory of filename, and search up the file tree until any .JET.toml is (or isn't) found. When found, the configurations specified in the file will overwrite the given jetconfigs. See Configuration File for more details.

Tip

When you want to analyze your package, but any file using it isn't available, the analyze_from_definitions option can be useful (see ToplevelConfig's analyze_from_definitions option).
For example, JET can analyze JET itself like below:

# from the root directory of JET.jl
julia> report_file("src/JET";
                   analyze_from_definitions = true)

See also: report_package

Note

This function will enable the toplevel_logger configuration by default with the default logging level. You can still explicitly specify and configure it:

report_file(args...;
            toplevel_logger = nothing, # suppress toplevel logger
            jetconfigs...) # other configurations

See Logging Configurations for more details.

source
JET.report_and_watch_fileFunction
report_and_watch_file([io::IO = stdout],
                      filename::AbstractString;
                      jetconfigs...)

Watches filename and keeps re-triggering analysis with report_file on code update. JET will try to analyze all the included files reachable from filename, and it will re-trigger analysis if there is code update detected in any of the included files.

This function internally uses Revise.jl to track code updates. Revise also offers possibilities to track changes in files that are not directly analyzed by JET, or even changes in Base files. See Watch Configurations for more details.

See also: report_file

source
JET.report_packageFunction
report_package([io::IO = stdout],
               package::Union{AbstractString,Module};
               jetconfigs...) -> res::ReportResult

Analyzes package in the same way as report_file with the option analyze_from_definitions=true. See report_file for details. package can be either a module or a string. In the latter case it must be the name of a package in your current environment.

report_package([io::IO = stdout];
               jetconfigs...) -> res::ReportResult

Like above but analyzes the package in the current project.

See also: report_file

source
JET.report_textFunction
report_text([io::IO = stdout],
            text::AbstractString,
            filename::AbstractString = "top-level";
            jetconfigs...) -> res::ReportResult

Analyzes text, prints the collected error reports to the io stream, and finally returns res::ReportResult

  • res.included_files::Set{String}: files analyzed by JET
  • res.any_reported::Bool: indicates if there was any error point reported
source

Testing, Interactive Usage

There are utilities for checking JET analysis in a running Julia session like REPL or such.

JET.report_callFunction
report_call(f, types = Tuple{}; jetconfigs...) -> result_type::Any

Analyzes the generic function call with the given type signature, and then prints collected error points to stdout, and finally returns the result type of the call.

source
JET.@report_callMacro
@report_call [jetconfigs...] f(args...)

Evaluates the arguments to the function call, determines its types, and then calls report_call on the resulting expression. As with @code_typed and its family, any of JET configurations can be given as the optional arguments like this:

# reports `rand(::Type{Bool})` with `aggressive_constant_propagation` configuration turned off
julia> @report_call aggressive_constant_propagation=false rand(Bool)
source
JET.analyze_callFunction
analyze_call(f, types = Tuple{}; jetconfigs...) -> (interp::JETInterpreter, frame::Union{InferenceFrame,Nothing})

Analyzes the generic function call with the given type signature, and returns:

  • interp::JETInterpreter: contains analyzed error reports and such
  • frame::Union{InferenceFrame,Nothing}: the final state of the abstract interpretation, or nothing if f is a generator and the code generation failed
source
JET.@analyze_callMacro
@analyze_call [jetconfigs...] f(args...)

Evaluates the arguments to the function call, determines its types, and then calls analyze_call on the resulting expression. As with @code_typed and its family, any of JET configurations can be given as the optional arguments like this:

# analyzes `rand(::Type{Bool})` with `aggressive_constant_propagation` configuration turned off
julia> @analyze_call aggressive_constant_propagation=false rand(Bool)
source