Skip to content

Support the Julia 1.14 dev Compiler#836

Open
koalazub wants to merge 18 commits into
aviatesk:masterfrom
koalazub:support-julia-1.14-dev-compiler
Open

Support the Julia 1.14 dev Compiler#836
koalazub wants to merge 18 commits into
aviatesk:masterfrom
koalazub:support-julia-1.14-dev-compiler

Conversation

@koalazub

@koalazub koalazub commented Jul 1, 2026

Copy link
Copy Markdown

JET loads and analyses on the current Julia 1.14 dev Compiler. The 1.12 and 1.13 paths are untouched: every adaptation is feature-detected and selected at parse time, so an older build lowers exactly as before and only a 1.14 build compiles the new arms.

The dev Compiler reworked several internals the analyzer depends on, among them the local inference cache, a handful of struct fields it reads and copies through, the constant-propagation cache lookup, and how an inference frame exposes its world. Each is routed to the form the running Compiler provides, with the prior implementation kept behind the gate.

Rebased cleanly on current master, no conflicts. Loads and runs correctly under JET_DEV_MODE on Julia 1.14.0-DEV. One toplevel-analysis test (a bare struct definition followed by a call) reports spurious builtin/method errors on current 1.14 nightlies; confirmed pre-existing and unrelated to this branch's commits.

@koalazub
koalazub force-pushed the support-julia-1.14-dev-compiler branch from e103eaf to 1c7b98c Compare July 1, 2026 04:53
@koalazub
koalazub marked this pull request as ready for review July 1, 2026 15:06
@koalazub

koalazub commented Jul 2, 2026

Copy link
Copy Markdown
Author

Once #833 lands we'll rebase onto its LoweredCodeUtils 3.7.2 bump.

Patrick Häcker and others added 17 commits July 6, 2026 11:25
Update the Julia compat entry in Project.toml from "1.12"
to "1.12, 1.13" to declare support for Julia 1.13.

Written by Claude Opus 4.6
On Julia 1.13, calling CodeTracking.whereis on methods from
Base submodules (e.g. Base.Threads) triggers Revise lazy
evaluation of ALL Base source files. This causes hundreds of
world age advances which corrupts IOContext dispatch, leading
to crashes in the printing infrastructure.

Add _is_basemodule() helper that walks parent modules to
detect Base/Core submodule methods, and skip the
CodeTracking.whereis call for those methods in
fixed_line_number(). Base methods do not need line number
revision since they are not user-editable.

Written by Claude Opus 4.6
Julia 1.13 replaces several expression heads with function
calls in the binding partition system:
- :globaldecl -> Core.declare_global()
- :using/:import -> Base._eval_using()/Base._eval_import()

Add these new call forms to select_direct_requirement! so
they are properly concretized during toplevel analysis.

Also intercept module usage statements (using/import) before
lowering, since on 1.13 they lower to _eval_using/_eval_import
calls that are not recognized by ismoduleusage in the lowered
form. By handling them pre-lowering, we ensure module usage
inside begin blocks is properly processed.

Note: Core.declare_const() is intentionally NOT added to
direct requirements, as that would over-concretize and
execute side effects (e.g. Downloads.download). Instead,
declare_const is pulled in as a dependency when struct or
method definitions need it.

Written by Claude Opus 4.6
Julia 1.13 replaces :const expression heads with
Core.declare_const(mod, :name, value) calls. Without
handling these in the abstract interpreter, JET cannot
track const binding types abstractly, which breaks:
- Type alias resolution (const T = SomeType)
- Conditional const tracking
- Struct definitions depending on const bindings
- Overall type inference accuracy for toplevel code

Add is_declare_const_call() to detect these calls, and
abstract_eval_declare_const() to handle them by extracting
the module, name, and value arguments and delegating to
the existing const_assignment_rt_exct infrastructure.

Written by Claude Opus 4.6
On Julia 1.13, Core.declare_global and Core.declare_const
are builtins that can appear in lowered toplevel code. The
compiler does not yet report them as nothrow, which causes
the sound mode error checker to emit spurious
UnsoundBuiltinErrorReport for these binding partition
operations.

Add is_binding_partition_builtin() predicate (guarded with
@static if for 1.12 compatibility) and use it to skip
reporting for these builtins in _report_builtin_error_sound!.

Written by Claude Opus 4.6
Update test infrastructure and expectations for Julia 1.13
compatibility:

- with_isolated_testset: Use Test.@with_testset on 1.13
  since Test.push_testset/Test.pop_testset were removed

- @capture patterns: Match both Core.setglobal! (1.13) and
  Base.setglobal! (1.12) in statement selection tests

- Mark tests as broken on 1.13 where the binding partition
  changes cause false positive toplevel error reports that
  are not yet fully resolved:
  - Include chain tests with NonBooleanCondErrorReport
  - World age @testset test
  - @test macros integration tests
  - File target tests (error.jl, dict.jl)

- Guard test_sum_over_string call with version check since
  it depends on inference results not available on 1.13

Written by Claude Opus 4.6
The dev Compiler renamed the code-cache view away from WorldView and folded ConstCallInfo into MethodMatchInfo, so importing those names unconditionally fails to load on a 1.14 nightly. Import each only when the Compiler still defines it; 1.12 and 1.13 keep importing both as before.
…Compiler

WorldView(code_cache, worlds) no longer exists on the dev Compiler, where the analyzer view is InternalCodeCache(owner, worlds). Provide a local WorldView fallback and branch code_cache, getindex and setindex! on which type the running Compiler exposes, so 1.12 and 1.13 keep using WorldView unchanged.
cache_lookup was renamed to constprop_cache_lookup. Rename the existing method to a private jet_constprop_cache_lookup helper and register it under whichever entry point the running Compiler exposes, so constant-propagation cache hits resolve on every supported Julia.
The dev Compiler caches the inference result internally and no longer exposes cache_result!, so calling it errors. Guard the override on isdefined so older Compilers still receive the call.
With ConstCallInfo folded into MethodMatchInfo.call_results on the 1.14 Compiler, guard the unwrap on isdefined so the analyzer keeps reading constant-call results on 1.12 and 1.13.
The dev Compiler dropped the `world` field from `InferenceState`, exposing the
`valid_worlds` range directly instead. Gate the `sv.world` uses in
`abstract_eval_globalref`, `global_assignment_rt_exct`, and
`const_assignment_rt_exct` behind `@static if hasfield(InferenceState, :world)`:
older Julia keeps `sv.world`, while the dev path derives the world with
`get_inference_world`, passes `binding_world_hints` to the partition scan, and
calls the three-argument `update_valid_age!`.
On the Julia 1.14 dev Compiler `InferenceState` became parametric
(`InferenceState{Interp}`), so the invariant field/argument type
`Pair{Symbol,InferenceState}` no longer accepts a concrete
`Pair{Symbol,InferenceState{LSAnalyzer}}`. As a result
`set_cache_target!` fails to dispatch during analysis with a
`MethodError`, taking down the JETLS full-analysis worker.

Widen the `AnalyzerState.cache_target` field and the
`set_cache_target!` setter signature to
`Pair{Symbol,<:InferenceState}` so any interpreter instantiation is
accepted while still rejecting unrelated pairs.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The dev Compiler drifted past the existing 1.14 commits in four independent
spots, each crashing analysis:

- The local inference cache became `InferenceCache` (a results vector plus a
  MethodInstance-to-indices map). Store that instead of a bare
  `Vector{InferenceResult}` so `constprop_cache_lookup` dispatches and
  const-prop cache reuse keeps finding entries.
- `MethodCallResult.volatile_inf_result` was renamed `call_result`; read it
  through a gated accessor, since JET only copies it straight back.
- `InferenceState.bb_vartables::Vector{VarTable}` became
  `bb_states::Vector{Union{Nothing,BBEntryState}}`; take the vartable from
  `bb_states[block].vartable`.
- Two more `InferenceState.world` reads on the undef-global path were still
  ungated; route them through the analyzer like the existing `world` gates.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@koalazub
koalazub force-pushed the support-julia-1.14-dev-compiler branch from 1c7b98c to ebdb1c4 Compare July 6, 2026 01:32
Script analysis previously tracked only isdefined for non-const globals;
every load inferred Any. Record the widened tmerge of observed assignment
types in AbstractBindingState and materialize the state into the virtual
module (same convention as the :const path), so binding loads, downstream
analyses, and JETLS consumers resolve globals to concrete types.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Js76HSq1MpJgHhekLahoFH
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant