### Install and Use JET Source: https://github.com/aviatesk/jet.jl/blob/master/docs/src/tutorial.md Install the JET package using Julia's Pkg manager and import it into your session. ```julia-repl julia> using Pkg; Pkg.add("JET") [ some output elided ] julia> using JET ``` -------------------------------- ### Install and Analyze AbstractTrees Package Source: https://github.com/aviatesk/jet.jl/blob/master/README.md This snippet demonstrates how to activate a temporary environment, add the AbstractTrees package, and then use `report_package` to analyze it. It shows the initial analysis and potential errors found. ```julia-repl julia> using Pkg; Pkg.activate(; temp=true, io=devnull); Pkg.add("AbstractTrees"; io=devnull); julia> Pkg.status() Status `/private/var/folders/xh/6zzly9vx71v05_y67nm_s9_c0000gn/T/jl_h07K2m/Project.toml` [1520ce14] AbstractTrees v0.4.5 julia> using AbstractTrees julia> report_package(AbstractTrees) [toplevel-info] Analyzing top-level definition (progress: 256/256) [toplevel-info] Analyzed all top-level definitions (all: 256 | analyzed: 256 | cached: 0 | took: 7.116 sec) [ Info: tracking Base ═════ 7 possible errors found ═════ ┌ isroot(root::Any, x::Any) @ AbstractTrees /Users/aviatesk/.julia/packages/AbstractTrees/Ftf8W/src/base.jl:102 │ no matching method found `parent(::Any, ::Any)`: AbstractTrees.parent(root::Any, x::Any) └──────────────────── ┌ StableNode{T}(x::T, ch::Any) where T @ AbstractTrees /Users/aviatesk/.julia/packages/AbstractTrees/Ftf8W/src/base.jl:260 │┌ collect(::Type{StableNode{_A}} where _A, itr::Any) @ Base ./array.jl:641 ││┌ _collect(::Type{StableNode{_A}}, itr::Any, isz::Union{Base.HasLength, Base.HasShape}) where _A @ Base ./array.jl:643 │││┌ _array_for(::Type{StableNode{_A}} where _A, itr::Base.HasLength, isz::Any) @ Base ./array.jl:673 ││││┌ _similar_shape(itr::Base.HasLength, ::Base.HasLength) @ Base ./array.jl:657 │││││ no matching method found `length(::Base.HasLength)`: length(itr::Base.HasLength) ││││└──────────────────── ││││┌ _similar_shape(itr::Base.HasLength, ::Base.HasShape) @ Base ./array.jl:658 │││││┌ axes(A::Base.HasLength) @ Base ./abstractarray.jl:98 ││││││ no matching method found `size(::Base.HasLength)`: size(A::Base.HasLength) │││││└──────────────────── ┌ IndexNode(tree::Any) @ AbstractTrees /Users/aviatesk/.julia/packages/AbstractTrees/Ftf8W/src/indexing.jl:117 │ no matching method found `rootindex(::Any)`: rootindex(tree::Any) └──────────────────── ┌ parent(idx::IndexNode) @ AbstractTrees /Users/aviatesk/.julia/packages/AbstractTrees/Ftf8W/src/indexing.jl:127 │ no matching method found `parentindex(::Any, ::Any)`: pidx = parentindex((idx::IndexNode).tree::Any, (idx::IndexNode).index::Any) └──────────────────── ┌ nextsibling(idx::IndexNode) @ AbstractTrees /Users/aviatesk/.julia/packages/AbstractTrees/Ftf8W/src/indexing.jl:132 │ no matching method found `nextsiblingindex(::Any, ::Any)`: sidx = nextsiblingindex((idx::IndexNode).tree::Any, (idx::IndexNode).index::Any) └──────────────────── ┌ prevsibling(idx::IndexNode) @ AbstractTrees /Users/aviatesk/.julia/packages/AbstractTrees/Ftf8W/src/indexing.jl:137 │ no matching method found `prevsiblingindex(::Any, ::Any)`: sidx = prevsiblingindex((idx::IndexNode).tree::Any, (idx::IndexNode).index::Any) └──────────────────── ``` -------------------------------- ### Import JET.jl Source: https://github.com/aviatesk/jet.jl/blob/master/docs/src/optanalysis.md Import the JET.jl package to start using its analysis tools. ```julia using JET ``` -------------------------------- ### Demonstrate runtime errors Source: https://github.com/aviatesk/jet.jl/blob/master/docs/src/jetanalysis.md Examples of actual runtime errors that can occur, which JET aims to detect statically. ```julia sum("julia") # will lead to `MethodError: +(::Char, ::Char)` ``` ```julia sum("") # will lead to `MethodError: zero(Type{Char})` ``` -------------------------------- ### JET.jl Test File Structure Example Source: https://github.com/aviatesk/jet.jl/blob/master/AGENTS.md Demonstrates the structure of a test file in JET.jl, which should define an independent module space with a `test_` prefix. It includes necessary imports and organizes tests using `@testset`. ```julia module test_virtualprocess using Test # Each module space needs to explicitly declare the code needed for execution ... end # module test_virtualprocess ``` -------------------------------- ### Install JET.jl Package Source: https://github.com/aviatesk/jet.jl/blob/master/README.md Install the JET.jl package using the Julia package manager. This command adds the latest compatible version of JET to your environment. ```julia-repl using Pkg; Pkg.add("JET") ``` -------------------------------- ### Analyze package method instances Source: https://github.com/aviatesk/jet.jl/blob/master/docs/src/tutorial.md Get all compiled method instances for functions owned by a package using `methodinstances`. ```julia using MyPkg, JET, MethodAnalysis mis = methodinstances(MyPkg) # get all the compiled methodinstances for functions owned by the package ``` -------------------------------- ### Report Potentially Throwing Function with JET (Sound Mode) Source: https://github.com/aviatesk/jet.jl/blob/master/docs/src/jetanalysis.md In 'sound' mode, JET reports functions that may throw an exception, even if it's not known at compile time. This example shows reporting a function that throws for values other than a specific large integer. ```julia f(x) = x == 9873984732 ? nothing : throw("Bad value") using JET # hide @report_call f(1) @report_call mode=:sound f(1) ``` -------------------------------- ### Report Incorrect Tuple Indexing with JET Source: https://github.com/aviatesk/jet.jl/blob/master/docs/src/jetanalysis.md Use `@report_call` to analyze function calls and identify potential issues like incorrect indexing. This example shows a false negative with a tuple and highlights the need to check indices. ```julia get_fourth(x) = x[4] using JET # hide @report_call get_fourth((1,2,3)) @report_call get_fourth([1,2,3]) # NB: False negative! ``` -------------------------------- ### Detect Field Name Typo Source: https://github.com/aviatesk/jet.jl/blob/master/docs/src/jetanalysis.md This example shows how JET.jl identifies a `BoundsError` due to a typo in a field name (`my_feild` instead of `my_field`). Correcting typos in field access is crucial for avoiding runtime errors. ```julia struct Foo my_field end f(x) = x.my_feild; # NB: Typo! using JET # hide @report_call f(Foo(1)) ``` -------------------------------- ### Report Always Throwing Function with JET Source: https://github.com/aviatesk/jet.jl/blob/master/docs/src/jetanalysis.md JET's default behavior is to report functions that are known at compile time to always throw an uncaught exception. This example demonstrates reporting a function that throws based on an Integer input. ```julia f(x) = x isa Integer ? throw("Integer") : nothing; using JET # hide @report_call f(1) ``` -------------------------------- ### Report Exception Handling with JET (Sound Mode) Source: https://github.com/aviatesk/jet.jl/blob/master/docs/src/jetanalysis.md JET does not report errors for exceptions handled within a `try-catch` block by default. In 'sound' mode, however, it will report the potential throw even if caught. This example demonstrates this behavior. ```julia g() = throw(); f() = try g() catch nothing end; f() using JET # hide @report_call f() @report_call mode=:sound f() ``` -------------------------------- ### Hot fix function definition Source: https://github.com/aviatesk/jet.jl/blob/master/docs/src/jetanalysis.md Refine a function definition to accept a more general type, demonstrating how JET's analysis can be updated dynamically. This example shows fixing `bar` to accept `AbstractString`. ```julia # hot fix the definition of `bar` bar(s::AbstractString) = parse(Int, s) ``` -------------------------------- ### Analyze Deep Call Chains with @report_opt Source: https://github.com/aviatesk/jet.jl/blob/master/docs/src/tutorial.md JET can detect type instability several function calls deep within a call chain. This example shows instability detected about 10 function calls deep. ```julia-repl julia> @report_opt sum(Any[1]) ``` -------------------------------- ### JET.jl Interactive Optimization Analysis Entry Points Source: https://github.com/aviatesk/jet.jl/blob/master/docs/src/optanalysis.md Use `@report_opt` and `report_opt` for interactive optimization analysis, similar to JET's error analysis entry points. ```julia JET.@report_opt ``` ```julia JET.report_opt ``` -------------------------------- ### Run Specific Test File in JET.jl Source: https://github.com/aviatesk/jet.jl/blob/master/AGENTS.md Execute a specific test file, such as 'test_print.jl', using the Julia REPL. The `--startup-file=no` flag prevents loading unnecessary startup utilities for a cleaner execution environment. ```bash julia --startup-file=no -e 'using Test; @testset "test_print" include("test/ui/test_print.jl")' ``` -------------------------------- ### Apply Optimization Analysis to a Top-Level Script Source: https://github.com/aviatesk/jet.jl/blob/master/docs/src/optanalysis.md Use `report_file` with `analyzer = OptAnalyzer` to apply optimization analysis on a top-level script when default top-level entry points are not sufficient. ```julia report_file("path/to/file.jl"; analyzer = OptAnalyzer) ``` -------------------------------- ### Switching Analysis Modes with `mode` Source: https://github.com/aviatesk/jet.jl/blob/master/docs/src/jetanalysis.md Configure JET's analysis behavior using the `mode` option. Options include `:sound` for stricter analysis and `:typo` for detecting only typos. This allows tailoring analysis to specific needs. ```julia report_call(myifelse, (Integer, Int, Int)) # the sound analyzer doesn't permit such a case: it requires the type of a conditional value to be `Bool` strictly report_call(myifelse, (Integer, Int, Int); mode=:sound) ``` ```julia # the default analysis pass will report both problems: # - `undefsum` is not defined # - `sum(a::Vector{Any})` can throw when `a` is empty @report_call strange_sum([]) # the typo detection pass will only report the "typo" @report_call mode=:typo strange_sum([]) ``` -------------------------------- ### Selective Test Execution with TestRunner.jl Source: https://github.com/aviatesk/jet.jl/blob/master/AGENTS.md Demonstrates how to selectively execute specific `@testset`s from the command line using the `testrunner` executable. This allows for targeted testing without running the entire file or suite. ```bash testrunner --verbose test/test_virtualprocess "some_func" ``` -------------------------------- ### Analyze a script with a main function Source: https://github.com/aviatesk/jet.jl/blob/master/docs/src/tutorial.md Rewrite a command-line script to use a `main` function for better analysis with JET.jl. ```julia function main() a = parse(Int, first(ARGS)) b = parse(Int, last(ARGS)) println(a + b) end main() ``` -------------------------------- ### JET.jl Test Code Best Practices Source: https://github.com/aviatesk/jet.jl/blob/master/AGENTS.md Illustrates recommended practices for writing test code in JET.jl, including using `let`-blocks for variable scoping and avoiding `using`, `import`, and `struct` definitions within `@testset` blocks. ```julia module test_virtualprocess using Test # Each module space needs to explicitly declare the code needed for execution using JET: some_func function test_with() ... end function testcase_util(s::AbstractString) ... end function with_testcase(s::AbstractString) ... end @testset "some_func" begin let s = "..." ret = some_func(testcase_util(s)) @test test_with(ret) end let s = "..." ret = some_func(testcase_util(s)) @test test_with(ret) end # or `let` is unnecessary when testing with function scope with_testcase(s) do case ret = some_func(case) @test test_with(ret) end end end # module test_virtualprocess ``` -------------------------------- ### Run Entire JET.jl Test Suite Source: https://github.com/aviatesk/jet.jl/blob/master/AGENTS.md Execute the complete test suite for the JET project from the repository's root directory. This command ensures all tests are run. ```bash using Pkg Pkg.test() ``` -------------------------------- ### Analyze Call with Fullpath Configuration Source: https://github.com/aviatesk/jet.jl/blob/master/docs/src/config.md Use this to analyze a specific function call with the `fullpath` configuration enabled. This shows the full path of the analyzed code. ```julia @report_call fullpath=true sum("julia") ``` -------------------------------- ### Handle Nothing Return from findfirst Source: https://github.com/aviatesk/jet.jl/blob/master/docs/src/jetanalysis.md When `findfirst` might return `nothing`, explicitly check for it to avoid `MethodError`. This ensures type stability by handling the `nothing` case separately. ```julia function pos_after_tab(v::AbstractArray{UInt8}) p = findfirst(isequal(UInt8('\t')), v) if p === nothing # handle the nothing case return nothing else return p + 1 end end ``` ```julia using JET # hide @report_call pos_after_tab(codeunits("a\tb")) ``` -------------------------------- ### Analyze Call with Fullpath Configuration (Functional) Source: https://github.com/aviatesk/jet.jl/blob/master/docs/src/config.md This is an alternative way to analyze a function call with the `fullpath` configuration enabled, using a functional approach. ```julia report_call(sum, (String,); fullpath=true) ``` -------------------------------- ### JET.jl Optimization Analyzer Configuration Source: https://github.com/aviatesk/jet.jl/blob/master/docs/src/optanalysis.md JET.jl's optimization analysis can be configured using `OptAnalyzer`, in addition to general configurations. ```julia JET.OptAnalyzer ``` -------------------------------- ### JET.jl Test Integration for Optimization Analysis Source: https://github.com/aviatesk/jet.jl/blob/master/docs/src/optanalysis.md Integrate optimization analysis with the `Test` standard library using `@test_opt` and `test_opt`. ```julia JET.@test_opt ``` ```julia JET.test_opt ``` -------------------------------- ### Analyze Top-level Script with Target Modules Source: https://github.com/aviatesk/jet.jl/blob/master/docs/src/config.md Analyze a top-level script file while specifying the `target_modules` configuration. This is useful for controlling which modules are considered during analysis. ```julia report_file("path/to/file.jl"; target_modules = (Main,)) ``` -------------------------------- ### Report file analysis Source: https://github.com/aviatesk/jet.jl/blob/master/docs/src/tutorial.md Analyze an entire script file using `report_file`. This is equivalent to running `@report_call main()` if the script contains a `main()` call. ```julia report_file("my_script.jl") ``` -------------------------------- ### Analyze a custom function with JET Source: https://github.com/aviatesk/jet.jl/blob/master/docs/src/jetanalysis.md Define custom functions and then use `@report_call` to analyze them for potential errors. This demonstrates JET's ability to work with user-defined code. ```julia function foo(s0) a = [] for s in split(s0) push!(a, bar(s)) end return sum(a) end bar(s::String) = parse(Int, s) @report_call foo("1 2 3") ``` -------------------------------- ### Create a workload function for package analysis Source: https://github.com/aviatesk/jet.jl/blob/master/docs/src/tutorial.md Define a function that exercises the functionality of your package to improve JET.jl's analysis precision. ```julia function exercise_mypkg() data = MyPkg.load_data() transformed = MyPkg.transform_data(data) # [ etc ...] end ``` -------------------------------- ### Analyze whole packages with report_package Source: https://github.com/aviatesk/jet.jl/blob/master/docs/src/tutorial.md Use `report_package` to analyze all method definitions within a package. This function extracts method signatures and runs `report_call` on them, providing a less precise analysis than `@report_call` due to generic signatures. ```julia using JET report_package(BioSymbols) ``` -------------------------------- ### Define a function in REPL Source: https://github.com/aviatesk/jet.jl/blob/master/docs/src/tutorial.md Define a simple function in the Julia REPL for testing purposes. ```julia g(x) = first(x) + 1 ``` -------------------------------- ### Ascend Individual Inference Reports with Cthulhu Source: https://github.com/aviatesk/jet.jl/blob/master/docs/src/optanalysis.md Analyze individual inference failures by using the `ascend` function from Cthulhu. This helps trace the call chain leading to a specific runtime dispatch. ```julia using Cthulhu ascend(rpts[1]) ``` -------------------------------- ### Julia Module File Naming Convention Source: https://github.com/aviatesk/jet.jl/blob/master/AGENTS.md Use underscores for file names that define Julia modules to comply with identifier rules. This ensures compatibility with Julia's module system. ```julia test_virtualprocess.jl ``` -------------------------------- ### Analyze Runtime Dispatches with @report_opt Source: https://github.com/aviatesk/jet.jl/blob/master/docs/src/optanalysis.md Use the @report_opt macro to analyze a function call and report detected performance pitfalls, such as runtime dispatches caused by non-constant global variables. ```julia n = rand(Int); make_vals(n) = n ≥ 0 ? (zero(n):n) : (n:zero(n)); function sumup(f) # this function uses the non-constant global variable `n` here # and it makes every succeeding operations type-unstable vals = make_vals(n) s = zero(eltype(vals)) for v in vals s += f(v) end return s end; @report_opt sumup(sin) # runtime dispatches will be reported ``` -------------------------------- ### JET.jl Test Inclusion in runtests.jl Source: https://github.com/aviatesk/jet.jl/blob/master/AGENTS.md Shows how to include individual test files, like 'test_virtualprocess.jl', within the main 'test/runtests.jl' file. This allows for modular test execution. ```julia @testset "JET.jl" begin ... @testset "virtualprocess" include("test_virtualprocess.jl") ... end ``` -------------------------------- ### Basic Call Analysis with `@report_call` Source: https://github.com/aviatesk/jet.jl/blob/master/docs/src/jetanalysis.md Use `@report_call` for default error analysis. Specify `target_modules` to limit analysis scope. This is useful for initial error detection. ```julia @report_call target_modules=(@__MODULE__,) foo("1 2 3") ``` -------------------------------- ### Limit Analysis Scope with target_modules Source: https://github.com/aviatesk/jet.jl/blob/master/docs/src/optanalysis.md Use `@report_opt` with the `target_modules` configuration to focus analysis on specific modules, ignoring external function calls like `println`. ```julia # problem: when ∑1/n exceeds `x` ? function compute(x) r = 1 s = 0.0 n = 1 @time while r < x s += 1/n if s ≥ r # `println` call is full of runtime dispatches for good reasons # and we're not interested in type-instabilities within this call # since we know it's only called a few times println("round $r/$x has been finished") r += 1 end n += 1 end return n, s end @report_opt compute(30) # bunch of reports will be reported from the `println` call @report_opt target_modules=(@__MODULE__,) compute(30) # focus on what we wrote, and no error should be reported ``` -------------------------------- ### Analyzing Entire Files with `report_file` Source: https://github.com/aviatesk/jet.jl/blob/master/docs/src/jetanalysis.md Use `report_file` to perform static analysis on an entire Julia file. This function automatically extracts definitions and analyzes their usages, providing a comprehensive overview of potential issues. ```julia report_file(normpath(Base.pkgdir(JET), "demo.jl")) ``` -------------------------------- ### Filter Method Instances with JET.jl Source: https://github.com/aviatesk/jet.jl/blob/master/docs/src/tutorial.md Filter method instances to find those that produce reports from JET. Call `report_call(mi)` to inspect individual method instances. ```julia badmis = filter(mis) do mi !isempty(JET.get_reports(report_call(mi))) end ``` -------------------------------- ### Analyze AbstractTrees Package Ignoring External Errors Source: https://github.com/aviatesk/jet.jl/blob/master/README.md This snippet shows how to use `report_package` with the `target_modules` argument to focus the analysis specifically on the AbstractTrees module, ignoring errors from other modules like Base. This is useful for reducing noise in the analysis results. ```julia-repl julia> report_package(AbstractTrees; target_modules=(AbstractTrees,)) [toplevel-info] Skipped analysis for cached definition (256/256) [toplevel-info] Analyzed all top-level definitions (all: 256 | analyzed: 0 | cached: 256 | took: 0.036 sec) ═════ 5 possible errors found ═════ ┌ isroot(root::Any, x::Any) @ AbstractTrees /Users/aviatesk/.julia/packages/AbstractTrees/Ftf8W/src/base.jl:102 │ no matching method found `parent(::Any, ::Any)`: AbstractTrees.parent(root::Any, x::Any) └──────────────────── ┌ IndexNode(tree::Any) @ AbstractTrees /Users/aviatesk/.julia/packages/AbstractTrees/Ftf8W/src/indexing.jl:117 │ no matching method found `rootindex(::Any)`: rootindex(tree::Any) └──────────────────── ┌ parent(idx::IndexNode) @ AbstractTrees /Users/aviatesk/.julia/packages/AbstractTrees/Ftf8W/src/indexing.jl:127 │ no matching method found `parentindex(::Any, ::Any)`: pidx = parentindex((idx::IndexNode).tree::Any, (idx::IndexNode).index::Any) └──────────────────── ┌ nextsibling(idx::IndexNode) @ AbstractTrees /Users/aviatesk/.julia/packages/AbstractTrees/Ftf8W/src/indexing.jl:132 │ no matching method found `nextsiblingindex(::Any, ::Any)`: sidx = nextsiblingindex((idx::IndexNode).tree::Any, (idx::IndexNode).index::Any) └──────────────────── ┌ prevsibling(idx::IndexNode) @ AbstractTrees /Users/aviatesk/.julia/packages/AbstractTrees/Ftf8W/src/indexing.jl:137 │ no matching method found `prevsiblingindex(::Any, ::Any)`: sidx = prevsiblingindex((idx::IndexNode).tree::Any, (idx::IndexNode).index::Any) └──────────────────── ``` -------------------------------- ### Analyze Nested Type Instability Source: https://github.com/aviatesk/jet.jl/blob/master/docs/src/tutorial.md Demonstrates how JET analyzes nested type instabilities, including those hidden behind untyped global variables. Use `const` to reveal deeper instabilities. ```julia add_one_first(x) = first(x) + 1; func_var = add_one_first; f(x) = func_var(x); ``` ```julia-repl julia> @report_opt f(Any[1]) ``` ```julia const my_func_var = add_one_first; ``` ```julia f(x) = my_func_var(x) ``` ```julia-repl julia> @report_opt f(Any[1]) ``` -------------------------------- ### Report Optimization for Function with Argument Source: https://github.com/aviatesk/jet.jl/blob/master/docs/src/optanalysis.md Use `@report_opt` to analyze a function call with a passed-in function argument. This can help identify runtime dispatch issues. ```julia function sumup(f, n) vals = make_vals(n) s = zero(eltype(vals)) for v in vals # NOTE here we may get union type like `s::Union{Int,Float64}`, # but Julia can optimize away such small unions (thus no runtime dispatch) s += f(v) end return s end; @report_opt sumup(sin, rand(Int)) # now runtime dispatch free ! ``` -------------------------------- ### View Typed Code with Cthulhu Source: https://github.com/aviatesk/jet.jl/blob/master/docs/src/optanalysis.md After selecting an option in Cthulhu, you can view the type-annotated code, which highlights non-inferable arguments in red. ```julia sumup(f) @ Main REPL[7]:1 1 function sumup(f::Core.Const(sin))::Any 2 # this function uses the non-constant global variable `n` here 3 # and it makes every succeeding operations type-unstable 4 vals::Any = make_vals(n::Any)::Any 5 s::Any = zero(eltype(vals::Any)::Any)::Any 6 for v::Any in vals::Any::Any 7 (s::Any += f::Core.Const(sin)(v::Any)::Any)::Any 8 end 9 return s::Any 10 end Select a call to descend into or ↩ to ascend. [q]uit. [b]ookmark. ⋮ ``` -------------------------------- ### Conditional Logging with JET_DEV_MODE Source: https://github.com/aviatesk/jet.jl/blob/master/AGENTS.md Use the JET_DEV_MODE flag to conditionally enable verbose logging or debugging output. This prevents cluttering the log in production environments. ```julia if JET_DEV_MODE @info ... end ``` -------------------------------- ### Define a function for analysis Source: https://github.com/aviatesk/jet.jl/blob/master/docs/src/tutorial.md Define a simple function that will be used to demonstrate type instability detection. ```julia add_one_first(x) = first(x) + 1; ``` -------------------------------- ### Report Captured Variables in Closure Source: https://github.com/aviatesk/jet.jl/blob/master/docs/src/optanalysis.md Analyze functions that create closures capturing variables using `@report_opt`. This helps identify potential performance issues related to captured variables. ```julia function abmult(r::Int) if r < 0 r = -r end # the closure assigned to `f` make the variable `r` captured f = x -> x * r return f end; @report_opt abmult(42) ``` ```julia function abmult(r0::Int) # we can improve the type stability of the variable `r` like this, # but it is still captured r::Int = r0 if r < 0 r = -r end f = x -> x * r return f end; @report_opt abmult(42) ``` ```julia function abmult(r::Int) if r < 0 r = -r end # we can try to eliminate the capturing # and now this function would be the most performing f = let r = r x -> x * r end return f end; @report_opt abmult(42) ``` -------------------------------- ### Abstract Interpretation Cache Management Source: https://github.com/aviatesk/jet.jl/blob/master/docs/src/internals.md Details on how JET.jl manages caches for abstract interpretation results, including AnalysisResult, CachedAnalysisResult, and AnalysisToken. ```APIDOC ## How `AbstractAnalyzer` manages caches ```@docs JET.AnalysisResult JET.CachedAnalysisResult JET.AnalysisToken ``` ``` -------------------------------- ### Define a simple function for analysis Source: https://github.com/aviatesk/jet.jl/blob/master/docs/src/tutorial.md A simple Julia function definition that can be analyzed by JET.jl. ```julia first_plus_n(itr, n::Real) = first(itr) + n; ``` -------------------------------- ### Fixing `no matching method found` Errors Source: https://github.com/aviatesk/jet.jl/blob/master/docs/src/jetanalysis.md This error indicates a potential `MethodError` at runtime due to function calls with argument types that do not match any defined methods. Fix by resolving type mismatches in function calls. ```julia f(x::Integer) = x + one(x); g(x) = f(x); using JET # hide @report_call g(1.0) ``` -------------------------------- ### Assert Performance with @test_opt Source: https://github.com/aviatesk/jet.jl/blob/master/docs/src/optanalysis.md Use `@test_opt` to assert that a function call is free from performance pitfalls. It integrates with Julia's `Test` standard library. ```julia @test_opt sumup(cos) ``` ```julia @test_opt target_modules=(@__MODULE__,) compute(30) ``` ```julia using Test @testset "check type-stabilities" begin @test_opt sumup(cos) # should fail n = rand(Int) @test_opt sumup(cos, n) # should pass @test_opt target_modules=(@__MODULE__,) compute(30) # should pass @test_opt broken=true compute(30) # should pass with the "broken" annotation end ``` -------------------------------- ### Typeassert to Ensure Non-Nothing Return Source: https://github.com/aviatesk/jet.jl/blob/master/docs/src/jetanalysis.md Use a type assertion (`::Integer`) after `findfirst` to inform the compiler that `nothing` is not an expected return value for valid input. This helps JET.jl resolve potential `MethodError`s by asserting programmer intent. ```julia function pos_after_tab(v::AbstractArray{UInt8}) p = findfirst(isequal(UInt8('\t')), v)::Integer p + 1 end ``` ```julia @report_call pos_after_tab(codeunits("a\tb")) ``` -------------------------------- ### Split JET Report into Individual Inference Failures Source: https://github.com/aviatesk/jet.jl/blob/master/docs/src/optanalysis.md Use `JET.get_reports` to split a comprehensive report into individual inference failures for further analysis. Consider `unique(reportkey, rpts)` to trim long lists. ```julia report = @report_opt sumup(sin) rpts = JET.get_reports(report) ``` -------------------------------- ### Detect Undefined Variable Usage Source: https://github.com/aviatesk/jet.jl/blob/master/docs/src/jetanalysis.md This snippet demonstrates how JET.jl detects the usage of an undefined variable `foo` within a function. Ensure all used names are defined or passed as arguments. ```julia f(x) = foo(x) + 1; using JET # hide @report_call f(1) ``` -------------------------------- ### Detect Type Instability with @report_opt Source: https://github.com/aviatesk/jet.jl/blob/master/docs/src/tutorial.md Use the `@report_opt` macro to analyze a function call for type instabilities. It analyzes all the way down the function chain and only displays issues found. ```julia-repl julia> @report_opt add_one_first([1]) ``` ```julia-repl julia> @report_opt add_one_first(Any[1]) ``` -------------------------------- ### Function Call with Keyword Arguments (Implicit Semicolon) Source: https://github.com/aviatesk/jet.jl/blob/master/AGENTS.md Avoid calling functions with keyword arguments without an explicit semicolon, as it can reduce clarity compared to the explicit form. ```julia Position(line=i-1, character=m.match.offset-1) ``` -------------------------------- ### Splitting and Filtering Reports Source: https://github.com/aviatesk/jet.jl/blob/master/docs/src/internals.md Provides functionality to split and filter analysis reports from JETToplevelResult and JETCallResult for easier integration with other tools. ```APIDOC ### Splitting and filtering reports ```@docs JET.get_reports JET.reportkey ``` ``` -------------------------------- ### Detect Type Instability with @report_opt Source: https://github.com/aviatesk/jet.jl/blob/master/README.md Use the `@report_opt` macro to detect type instabilities in function calls, similar to `@code_warntype`. Note that dynamic dispatch can limit analysis. ```julia-repl @report_opt foldl(+, Any[]; init=0) ═════ 2 possible errors found ═════ ┌ kwcall(::@NamedTuple{init::Int64}, ::typeof(foldl), op::typeof(+), itr::Vector{Any}) @ Base ./reduce.jl:198 │┌ foldl(op::typeof(+), itr::Vector{Any}; kw::@Kwargs{init::Int64}) @ Base ./reduce.jl:198 ││┌ kwcall(::@NamedTuple{init::Int64}, ::typeof(mapfoldl), f::typeof(identity), op::typeof(+), itr::Vector{Any}) @ Base ./reduce.jl:175 │││┌ mapfoldl(f::typeof(identity), op::typeof(+), itr::Vector{Any}; init::Int64) @ Base ./reduce.jl:175 ││││┌ mapfoldl_impl(f::typeof(identity), op::typeof(+), nt::Int64, itr::Vector{Any}) @ Base ./reduce.jl:44 │││││┌ foldl_impl(op::Base.BottomRF{typeof(+)}, nt::Int64, itr::Vector{Any}) @ Base ./reduce.jl:48 ││││││┌ _foldl_impl(op::Base.BottomRF{typeof(+)}, init::Int64, itr::Vector{Any}) @ Base ./reduce.jl:58 │││││││┌ (::Base.BottomRF{typeof(+)})(acc::Int64, x::Any) @ Base ./reduce.jl:86 ││││││││ runtime dispatch detected: +(acc::Int64, x::Any)::Any │││││││└──────────────────── ││││││┌ _foldl_impl(op::Base.BottomRF{typeof(+)}, init::Int64, itr::Vector{Any}) @ Base ./reduce.jl:62 │││││││┌ (::Base.BottomRF{typeof(+)})(acc::Any, x::Any) @ Base ./reduce.jl:86 ││││││││ runtime dispatch detected: +(acc::Any, x::Any)::Any │││││││└──────────────────── ``` -------------------------------- ### Fixing `no matching method found (x/y union split)` Errors Source: https://github.com/aviatesk/jet.jl/blob/master/docs/src/jetanalysis.md Occurs when a variable inferred as a union type leads to a `MethodError` in one or more of its possible types. This requires careful handling of union types to ensure all branches are valid. ```julia struct Foo x::Union{Int, String} end # Errors if x.x isa String. # The compiler doesn't know if it's a String or Int f(x) = x.x + 1; using JET # hide @report_call f(Foo(1)) ``` ```julia function pos_after_tab(v::AbstractArray{UInt8}) # findfirst can return `nothing` on no match p = findfirst(isequal(UInt8('\t')), v) p + 1 end @report_call pos_after_tab(codeunits("a\tb")) ``` -------------------------------- ### Filter errors by targeting modules Source: https://github.com/aviatesk/jet.jl/blob/master/docs/src/tutorial.md Filter errors to only include those originating from specified modules using `target_modules`. Pass modules as a Tuple. ```julia @report_call target_modules=(@__MODULE__,) g(nothing) ``` -------------------------------- ### Detect Type Errors with @report_call Source: https://github.com/aviatesk/jet.jl/blob/master/README.md Use `@report_call` to detect type errors. This works best on type-stable code, so it's recommended to use `@report_opt` liberally beforehand. The output shows possible errors in function calls. ```julia-repl julia> @report_call foldl(+, Char[]) ═════ 2 possible errors found ═════ ┌ foldl(op::typeof(+), itr::Vector{Char}) @ Base ./reduce.jl:198 │┌ foldl(op::typeof(+), itr::Vector{Char}; kw::@Kwargs{}) @ Base ./reduce.jl:198 ││┌ mapfoldl(f::typeof(identity), op::typeof(+), itr::Vector{Char}) @ Base ./reduce.jl:175 │││┌ mapfoldl(f::typeof(identity), op::typeof(+), itr::Vector{Char}; init::Base._InitialValue) @ Base ./reduce.jl:175 ││││┌ mapfoldl_impl(f::typeof(identity), op::typeof(+), nt::Base._InitialValue, itr::Vector{Char}) @ Base ./reduce.jl:44 │││││┌ foldl_impl(op::Base.BottomRF{typeof(+)}, nt::Base._InitialValue, itr::Vector{Char}) @ Base ./reduce.jl:48 ││││││┌ _foldl_impl(op::Base.BottomRF{typeof(+)}, init::Base._InitialValue, itr::Vector{Char}) @ Base ./reduce.jl:62 │││││││┌ (::Base.BottomRF{typeof(+)})(acc::Char, x::Char) @ Base ./reduce.jl:86 ││││││││ no matching method found `+(::Char, ::Char)`: (op::Base.BottomRF{typeof(+)}).rf::typeof(+)(acc::Char, x::Char) │││││││└──────────────────── │││││┌ foldl_impl(op::Base.BottomRF{typeof(+)}, nt::Base._InitialValue, itr::Vector{Char}) @ Base ./reduce.jl:49 ││││││┌ reduce_empty_iter(op::Base.BottomRF{typeof(+)}, itr::Vector{Char}) @ Base ./reduce.jl:383 │││││││┌ reduce_empty_iter(op::Base.BottomRF{typeof(+)}, itr::Vector{Char}, ::Base.HasEltype) @ Base ./reduce.jl:384 ││││││││┌ reduce_empty(op::Base.BottomRF{typeof(+)}, ::Type{Char}) @ Base ./reduce.jl:360 │││││││││┌ reduce_empty(::typeof(+), ::Type{Char}) @ Base ./reduce.jl:343 ││││││││││ no matching method found `zero(::Type{Char})`: zero(T::Type{Char}) │││││││││└──────────────────── ``` -------------------------------- ### Filter errors using AnyFrameModule Source: https://github.com/aviatesk/jet.jl/blob/master/docs/src/tutorial.md Filter errors based on whether any function call in the callchain originates from a given module using `AnyFrameModule`. ```julia @report_call ignored_modules=(AnyFrameModule(Base),) g(nothing) ``` ```julia @report_call ignored_modules=(AnyFrameModule(@__MODULE__),) g(nothing) ``` -------------------------------- ### Top-level Analysis Functions Source: https://github.com/aviatesk/jet.jl/blob/master/docs/src/internals.md Functions related to performing top-level program analysis within JET.jl, including virtual process execution and module context virtualization. ```APIDOC ## Top-level Analysis ```@docs JET.virtual_process JET.VirtualProcessResult JET.virtualize_module_context JET.ConcreteInterpreter JET.partially_interpret! ``` ``` -------------------------------- ### Filter errors by ignoring modules Source: https://github.com/aviatesk/jet.jl/blob/master/docs/src/tutorial.md Filter out errors originating from specific modules using `ignored_modules`. Pass modules as a Tuple. ```julia @report_call ignored_modules=(Base,) g(nothing) ``` -------------------------------- ### Function Call with Keyword Arguments (Explicit Semicolon) Source: https://github.com/aviatesk/jet.jl/blob/master/AGENTS.md Prefer using an explicit semicolon before keyword arguments in function calls for improved clarity. This distinguishes keyword arguments from positional arguments. ```julia Position(; line=i-1, character=m.match.offset-1) ``` -------------------------------- ### Error Report Interface Source: https://github.com/aviatesk/jet.jl/blob/master/docs/src/internals.md Defines the interface for error reports used in JET.jl, including virtual frames, stack traces, signatures, and different types of inference errors. ```APIDOC ## Error Report Interface ```@docs JET.VirtualFrame JET.VirtualStackTrace JET.Signature JET.InferenceErrorReport JET.ToplevelErrorReport ``` ``` -------------------------------- ### Report potential errors in a function call Source: https://github.com/aviatesk/jet.jl/blob/master/docs/src/jetanalysis.md Use `@report_call` to statically analyze a function call and report any detected problems. This is analogous to `@code_typed` but focuses on error detection. ```julia @report_call sum("julia") ``` -------------------------------- ### Report call analysis on a function Source: https://github.com/aviatesk/jet.jl/blob/master/docs/src/tutorial.md Use @report_call to analyze a function for potential errors, such as type instability. ```julia @report_call g(nothing) ``` -------------------------------- ### Resolve Union{T, Nothing} Field Access Source: https://github.com/aviatesk/jet.jl/blob/master/docs/src/jetanalysis.md When accessing fields that can be `Union{T, Nothing}`, assign the field value to a local variable before checking for `nothing`. This helps the compiler correctly infer the type within conditional blocks, preventing potential `MethodError`s. ```julia mutable struct Foo x::Union{Int, Nothing} end function f(x) y = x.x if y === nothing nothing else y + 1 end end ``` ```julia @report_call f(Foo(1)) ``` -------------------------------- ### Analysis Result Types Source: https://github.com/aviatesk/jet.jl/blob/master/docs/src/internals.md Defines the types for analysis results at the top-level and call sites, namely JETToplevelResult and JETCallResult. ```APIDOC ## Analysis Result ```@docs JET.JETToplevelResult JET.JETCallResult ``` ``` -------------------------------- ### Testing Code Correctness with `@test_call` Source: https://github.com/aviatesk/jet.jl/blob/master/docs/src/jetanalysis.md Utilize `@test_call` within Julia's `Test` framework to assert that code is free from detectable problems. It supports standard `Test` options like `broken` and `skip`. ```julia @test_call target_modules=(@__MODULE__,) foo("1 2 3") ``` ```julia @testset "JET testset" begin @test_call target_modules=(@__MODULE__,) foo("1 2 3") # should pass test_call(myifelse, (Integer, Int, Int); mode=:sound) @test_call broken=true foo("1 2 3") # `broken` and `skip` options are supported @test foo("1 2 3") == 6 # of course other `Test` macros can be used in the same place end ``` -------------------------------- ### Analyze function calls with @report_call Source: https://github.com/aviatesk/jet.jl/blob/master/docs/src/tutorial.md Use `@report_call` to analyze function calls for potential type errors. This macro analyzes code on a type level, identifying errors that might not occur at runtime due to specific input values. ```julia @report_call sum(['a']) ``` ```julia @report_call sum([1]) ```