Repository navigation
v0.13.0
JET v0.13.0
CHANGELOG
Added
-
Added support for Julia v1.14. JET now loads full functionality on Julia
1.14 instead of empty stubs. -
Added the
allow_unsupported_juliapreference, which loads full JET
functionality on unsupported Julia versions, e.g. nightly builds, without
the development features thatJET_DEV_MODEalso enables:LocalPreferences.toml
[JET] allow_unsupported_julia = true # previously `JET_DEV_MODE = true` was needed
JET emits a warning when it is loaded on an unsupported Julia version this
way, since it may not work correctly there. -
JETInterfacenow exportshas_problems, the predicate thatcall_test_ex
andfunc_testuse to decide whether an analysis result fails a test. -
Calls whose matching methods are ambiguous are now reported as
AmbiguousMethodErrorReportinstead ofMethodErrorReportsaying that no
matching method is found. For a union-split call, the ambiguous signatures
are reported separately from those without any matching method:k(::Int, ::Any) = 1 k(::Any, ::Int) = 2 m(x::Int) = k(x, x) # reported: ambiguous `k(::Int, ::Int)` n(x::Union{Int,String}) = k(x, x) # reported: ambiguous `k(::Int, ::Int)` # and no method for `k(::String, ::String)`
-
invokecalls that throwMethodErrorbecause no method matches the
specified signature are now reported asMethodErrorReportin the:basic
and:soundmodes, and those whose matching methods are ambiguous are
reported asAmbiguousMethodErrorReport:f(::Int) = 1 g(x) = invoke(f, Tuple{String}, x) # reported: no method for `f(::String)` h(x) = @invoke f(x::Integer) # reported: no method for `f(::Integer)` k(::Int, ::Any) = 1 k(::Any, ::Int) = 2 l(x) = @invoke k(x::Int, x::Int) # reported: ambiguous `k(::Int, ::Int)`
-
Top-level analysis now reports a
@testthat always fails, i.e. whose
expression is inferred to evaluate tofalseor to a non-boolean value, and
a@test_throwsthat always fails, i.e. whose expression is inferred to
throw only exceptions that do not match the expected one. The errors in the
expression of@test_throws, which is expected to throw, are no longer
reported:@testset "foo" begin x = nothing @test x isa Int # reported: always `false` end @testset "bar" begin y = rand((0, nothing)) @test y # reported: non-boolean `Union{Nothing, Int64}` end @testset "baz" begin @test_throws MethodError sin("x") # no longer reported @test_throws ArgumentError sin("x") # reported: throws `MethodError` end
@test_brokenand@test ex broken=trueare not reported, nor are the
tests in function bodies.@test falseis also reported, so use e.g.
error("unreachable")to mark code that should not be reached. The check of
@test_throwsis conservative: the exceptions inferred across function calls
are oftenAny, which matches any expected exception, and message patterns
are not checked.
Changed
-
Top-level processing now stops entirely at the first fatal parsing, macro
expansion, lowering, concrete execution, dependency, or include failure.
No later statements, modules, files, or definition analysis are processed.
Fatal results are displayed asTop-level analysis failed, with guidance
to fix the error and rerun the incomplete analysis.
VirtualProcessResult.toplevel_error_reportholds that single
ToplevelErrorReport, ornothingon success.get_reportson a
JETToplevelResultstill returns a vector: only the fatal error on failure,
or warnings followed by filtered inference reports on success. Module and
report_configfiltering apply only to inference reports; warnings are
retained, so successful results can contain a mix of report types. The
console output prints warnings before inference reports and omits the
"No errors detected" message when warnings are present. TheTest
integration (test_file,test_text,test_package) does not count
UnsupportedFeatureReports as failures, butParseWarningReports still
fail tests.[!WARNING]
Known limitation: forced interruption skips userfinallyblocks in
interpreted code, including during timeout, missing-concretization, and
fatal include failures. Concrete execution can leave the working directory
changed or locks held after analysis exits; its side effects are not rolled
back. -
Nonfatal JET warnings are stored in
VirtualProcessResult.toplevel_warning_reports, a
Vector{ToplevelWarningReport}, and are not also emitted as@warnlogs.
Parser warnings now produce nonfatalParseWarningReports. Unsupported
include(mapexpr, filename)andBase.include(mapexpr, mod, filename)calls
produceUnsupportedFeatureReports and analyze the included file without
applyingmapexpr, in the current or explicitly specified module,
respectively. -
The explanatory text of top-level reports is wrapped at 90 columns, or at
the terminal width when results are shown in a narrower REPL. Error
messages, stacktraces, and source excerpts are not wrapped. -
The
Top-level analysis failedheader is now highlighted in red. -
Top-level report messages now start with a summary, followed by a blank line
and the details. Errors from parsing, macro expansion, lowering, and concrete
execution are summarized with what JET was doing and the first line of the
error message, e.g.
JET could not execute this top-level code: UndefVarError: ..., and parser
diagnostics asSyntax error: ...orSyntax warning: ....
UnsupportedFeatureReports show a common summary above the description of
the unsupported feature, andRecursiveIncludeErrorReports list the include
chain. The VS Code integration keeps the summary on the first line of its
diagnostics. -
Report boxes are now closed with lines as wide as the widest message line in
them. Each inference report used to close only the box of its error frame
with a fixed-width line, leaving the boxes of its caller frames open. Now one
line closes every box that the next report does not share:g(x) = sin(x) h(x) = cos(x) f(x) = rand(Bool) ? g(x) : h(x) report_call(f, (String,))
═════ 2 possible errors found ═════ ┌ f(x::String) @ Main REPL[3]:1 │┌ g(x::String) @ Main REPL[1]:1 ││ no matching method found `sin(::String)`: sin(x::String) │└───────────────────────────────────────────────────────── │┌ h(x::String) @ Main REPL[2]:1 ││ no matching method found `cos(::String)`: cos(x::String) └┴─────────────────────────────────────────────────────────Previously, both reports ended with
│└────────────────────, leaving the
box offopen. Top-level report boxes, which ended at the right edge of
their section header, are sized the same way. -
Top-level analysis now analyzes test sets as if they were declared with
failfast=true, where a failing test aborts the test set, so it analyzes the
code after@test exassuming thatexistrue:@testset "foo" begin x = rand((0, nothing)) @test x isa Int sin(x) # no longer reported as `sin(::Nothing)`: `x` is an `Int` here end
The new
testset_failfastconfiguration controls this. With
testset_failfast=false, only the test sets that specifyfailfast=trueare
analyzed this way, together with the test sets nested in them and the files
included from them:# runtests.jl @testset "MyPkg" failfast=true begin @testset "foo" include("foo.jl") # the test sets in foo.jl are analyzed the same way end
Test sets that specify
failfast=falseand test sets of a custom type, e.g.
@testset MyTestSet ..., are analyzed as declared. Note that the code after a
test that always fails is not analyzed. Likewise, regardless of
testset_failfast, the code after@test_warn,@test_nowarn,@inferred,
and@testset let ... endis not analyzed if they always throw, since
Test.jl does not catch exceptions in them. The values of@test_warn,
@test_nowarn, and@inferredalso keep their inferred types, e.g.yof
y = @inferred parse(Int, "1")is inferred asIntinstead ofAny. -
VirtualFramehas the newpcfield, the index of the statement that the
frame points to in the code analyzed for itsMethodInstance, or0if the
frame does not point to a statement. Frames at different statements on the
same line are no longer equal:VirtualFrame(file, line, linfo, pc) # was `VirtualFrame(file, line, linfo)` first(report.vst).pc # the statement where `report` was found
Deprecated
-
The
print_toplevel_successandprint_inference_successconfigurations
are deprecated and will be removed in a future release. Passing either one
emitsBase.depwarn.print_toplevel_successnow has no effect; displayed
analysis results never printed its message.print_inference_successkeeps
working until its removal; useJET.has_problems(result)to check whether
an analysis result has problems. -
VirtualProcessResult.toplevel_error_reportsis deprecated and will be
removed in a future release. Access emitsBase.depwarnand returns a fresh
empty or one-elementVector;propertynameslists the property only when
private names are requested. Migrate totoplevel_error_report: replace
isempty(res.toplevel_error_reports)with
isnothing(res.toplevel_error_report)and use the singular report directly
when non-nothing. For a vector of reports from aJETToplevelResult, use
JET.get_reports(result)instead.
Fixed
-
Fixed top-level analysis crashing with an
AssertionErrorwhen a docstring
is attached to an expression that cannot be documented, such as anif
block. The analysis now stops with the error that Julia raises for such
code,cannot document the following expression. -
Fixed top-level analysis concretizing the code after a
tryblock, such as
aBase.ScopedValues.@withblock, within the block's exception handler and
dynamic scope when the block contains definitions. Such code could read the
scoped values set by the block, and an error thrown by it ran the code after
the block again. -
Fixed a
WARNING: Detected access to binding ... in a world prior to its definition worldmessage that top-level analysis (e.g.report_file) could
print when reading a constant declared earlier in the same top-level block,
such as aglobal constinside aletblock. -
Fixed a
WARNING: Detected access to binding ... in a world prior to its definition worldmessage thatreport_optcould print when reporting a
runtime dispatch to a function defined after JET was loaded. -
Fixed top-level analysis treating any function named
includeas Julia's
file loader instead of executing its body. Custom wrappers now run their
own logic, such as path transformations, before calls to the standard
includeare intercepted during recursive interpretation. -
Fixed printing of a report about an
includecall with arguments that no
includemethod accepts, such asinclude(Symbol("file.jl")), which threw
aTypeErrorinstead of showing theMethodError. -
Fixed reports about an
includecall, such as a failure to read the
included file or aRecursiveIncludeErrorReport, pointing to the first line
of the enclosing top-level statement when the call is inside a block or a
function. They now point to the line of theincludecall, or to the line
that calls the enclosing function when that function is defined in another
file. -
Fixed reports in code checked by Test.jl macros, such as the body of a
@testsetor a multi-line@testexpression, pointing to the first line of
the enclosing top-level statement since 0.12.1. They now point to the line
of the reported code. -
Fixed package analysis (e.g.
report_package) of a package that looks
itself up withpathof,pkgdir, orpkgversion, which returnednothing
for the analyzed package module and could stop the analysis:module MyPkg const SRCDIR = dirname(pathof(@__MODULE__)) # was a `MethodError` end
Base.PkgId(@__MODULE__)of the analyzed package module now differs from
that of the actual package, so lookups such as
Base.identify_package(Base.PkgId(@__MODULE__), name)fail. -
Fixed the loop bodies of
Threads.@threadsnot being analyzed on Julia
1.13.2 and later, where its tasks call the loop body through a dynamic
dispatch (JuliaLang/julia#63184). The loop body is now analyzed where
@threadsis used, andreport_optno longer reports that dynamic dispatch
inBase.Threads._threads_call:const g = Ref{Any}(1) helper(i) = i + g[] function f(n) Threads.@threads for i in 1:n helper(i) # `@report_opt f(10)` reports this runtime dispatch again end end
-
Fixed
joinon a tuple of unknown length, such as one created by splatting
a vector, being inferred to returnUnion{AnnotatedString{String},String}
rather thanString, which caused spurious reports for code that requires a
String(JuliaLang/julia#63999):report_call((Vector{String},)) do xs pointer(join((xs...,), ", ")) # no longer reported end
-
Fixed errors in the function run by a
Tasknot being reported when the
function had not been analyzed before, as when the task is created by
Task(f, reserved_stack):report_call() do t = Task(() -> sum("julia"), 0) # errors in `sum("julia")` now reported schedule(t) fetch(t) end
-
Fixed analysis crashing with
Could not find single target methodwhen a
Taskis created from a function whose type is not known, such as
f::Function:g(f::Function) = Task(f) report_call(g, (Function,)) # no longer throws
-
Fixed top-level analysis (e.g.
report_file) reporting a global variable as
not defined when the variable is exported after its assignment:x = rand(Bool) export x println(x) # was reported: `x` is not defined
-
Fixed the reports from a call being discarded by the constant propagation of
another call to the same function on the same line:foo(a) = a < 0 ? a + string(a) : a bar(x) = (foo(x), foo(1)) # the report from `foo(x)` was discarded report_call(bar, (Int,))
-
Fixed conversion intrinsics such as
bitcastbeing reported as called with
a non-primitive target type when the target type is aUnionof primitive
types:# was reported: bitcast: target type not a leaf primitive type report_call(signed, (Base.BitUnsigned,))
-
Fixed reports about
getfieldorsetfield!on a type object listing the
fields of that type instead of the fields of the type object itself, and
the analysis of field accesses throwing on a field name that is neither a
Symbolnor anInt, or on a tuple of unknown length:struct Foo; x::Int; end # now reported: type DataType has no field `y` report_call(() -> getfield(Foo, :y)) report_call(() -> getfield(Foo, "y")) # no longer throws
-
Fixed
Core.invokecalls with aCodeInstancebeing misclassified as invalid
invokecalls when the invoked code always throws. Callee diagnostics for
directCodeInstancecalls are not yet collected.
Merged pull requests:
- toplevel: Stop analysis at the first fatal error (#883) (@aviatesk)
- toplevel: Record definition locations in
SignatureInfo(#886) (@aviatesk) - print: Deprecate the success message configurations (#887) (@aviatesk)
- print: Summarize and wrap top-level report messages (#888) (@aviatesk)
- build(deps): bump dawidd6/action-download-artifact from 25 to 27 (#889) (@dependabot[bot])
- Look up callee bindings in the analysis world when building report signatures (#891) (@Beforerr)
- Fix root-anchored .gitignore entries (#892) (@Beforerr)
- toplevel: Exit the handlers and scopes entered by concretization (#893) (@aviatesk)
- toplevel: Narrow types after
@testin fail-fast test sets (#895) (@aviatesk) - Analyze test sets as fail-fast by default and report
@tests that always fail (#896) (@aviatesk) - toplevel: Concretize
Base.deprecatecalls (#897) (@aviatesk) - typeinfer: Analyze
Threads.@threadsloop bodies at call sites (#898) (@aviatesk) - toplevel: Keep binding states across partitions replaced by
export(#899) (@aviatesk) - Propagate exceptions in Test.jl macros and check exceptions of
@test_throws(#901) (@aviatesk) - jetanalyzer: Add overlay for
joinon tuples (#902) (@aviatesk) - toplevel: Skip native compilation of
precompilecalls (#903) (@aviatesk) - Support Julia v1.14 (#904) (@aviatesk)
- jetanalyzer: Skip
Uniontarget types in conversion checks (#905) (@aviatesk) - jetanalyzer: Report
MethodErrorfrominvokelookup failures (#906) (@aviatesk) - jetanalyzer: Report ambiguous method calls separately (#907) (@aviatesk)
Closed issues: