Skip to content

release: 2026-06-18#763

Merged
aviatesk merged 96 commits into
releasefrom
releases/2026-06-18
Jun 18, 2026
Merged

release: 2026-06-18#763
aviatesk merged 96 commits into
releasefrom
releases/2026-06-18

Conversation

@aviatesk

@aviatesk aviatesk commented Jun 18, 2026

Copy link
Copy Markdown
Owner

This PR releases version 2026-06-18.

Checklist

  • release / Test JETLS.jl with release environment
  • release / test_app / Test jetls serve
  • release / test_app / Test jetls check
  • release / test_app / Test jetls schema
  • release / check_schemas / Check schemas are up to date

Post-merge

  • The releases/2026-06-18 branch can be deleted after merging
  • CHANGELOG.md will be automatically updated on master

github-actions Bot and others added 30 commits June 3, 2026 13:02
…ange`

`M'` parses as `K"'"` but JL lowers it to `call(adjoint, M)`. Without
explicit dispatch, the default `tmerge` over the byte range pulled in
the `Const(adjoint)` callee globalref planted alongside the result,
surfacing `Union{typeof(adjoint), Adjoint{…}}` instead of the user-
visible `Adjoint{…}`. Group `K"'"` with `K"call"` / `K"dotcall"` /
`K"tuple"` so `type_for_call` picks the last `K"call"` at the range.
Split formatting guidance into code, Markdown, and commit-message sections. Clarify that automated formatters and editor-integrated formatting tools should not be used unless explicitly requested.
Move shared agent skills from `.claude/skills` to `.agents/skills` so
Codex and other compatible agents can discover them.

Update the commit skill to reference `AGENTS.md` for repository git
operation rules, and remove obsolete `.claude` ignore entries.

Co-Authored-By: GPT-5.5 <noreply@openai.com>
Clarify log and error messages around invalid diagnostic codes.
The messages now distinguish non-string `code` values from codes
that are strings but are not registered.

Co-Authored-By: GPT-5.5 <noreply@openai.com>
Rename short loop temporaries in private AST helpers.

Make recursive child handling easier to follow without changing behavior.

Co-Authored-By: GPT-5.5 <noreply@openai.com>
Add a skill that lets Zed's built-in coding agent prefer faster LSP
diagnostics for self check diagnostics while falling back to
`./scripts/selfcheck.sh` when needed.

Clarify `AGENTS.md` so self diagnostics are described in an
editor-integration-agnostic way with `./scripts/selfcheck.sh` as
the standard command.
Add project-local `run-test` and `write-test` skills for JETLS test
workflows. The `run-test` skill documents focused test selection and
TestRunner usage, while `write-test` captures the project's test file
structure and LSP handler test patterns.

Trim `AGENTS.md` to keep only the high-level test policy and link to the
new skills for detailed workflows.
Condense several `AGENTS.md` guardrails while keeping their intent. The
updated notes keep the function signature, comment, user-edit, and git
operation policies easier to scan for coding agents.
Clarify the type annotation dispatch table.

Trim test comments to focus on regression intent.

Avoid repeating implementation flow in test explanations.

Co-Authored-By: GPT-5.5 <noreply@openai.com>
Avoid calling `Base.type_depth_limit` when type strings already satisfy the depth or width limit. This reduces allocation on the common no-op path used by type inlay hint labels.

Add tests that cover no-op truncation and short strings that still need depth limiting.

Co-Authored-By: GPT-5.5 <noreply@openai.com>
Simplify  by checking , abstract types, and  parameters directly instead of nesting the logic under an outer  guard.
Add inference-based type inlay hints alongside the existing block-end
hints. Expressions, bindings, calls, definitions, branches, and loop
variables can now show compact inferred type labels inline.

The feature supports lazy tooltip resolution through
`inlayHint/resolve`, so expensive full type strings are computed only
when the client asks for tooltip details. Type hint labels are cached
per request to avoid repeated compact rendering.

Expose the `[inlay_hint] types` configuration and document the new
behavior, including example screenshots and schema updates.
Route request caller token lookup through `cancellable_token_impl` so `cancellable_token` has a stable `Union{Nothing,CancellableToken}` return type.
Add a new live diagnostic that warns when a method declares a static
parameter that does not appear in the type of any function parameter,
e.g. `f(::T) where {T,S} = S`, mirroring the warning Julia itself
emits when evaluating such a method definition.

JuliaLowering used to reject these cases with a `LoweringError`,
which JETLS surfaced as a `lowering/error` diagnostic. That error was
removed in JuliaLang/julia#62048 (f913a6065f) since Julia proper only
warns about them, so JETLS now carries the check itself as a
dedicated warning-severity diagnostic.

The analysis runs on the scope-resolved tree (`st3`/`ctx3`): it
matches the signature metadata `JL.method_def_expr` generates
(`svec(svec(arg_types...), svec(sparams...), source_location)`) and
checks whether each static parameter's `BindingId` occurs in the
arg-types subtree, with bound references constraining only earlier
declarations, mirroring `JL.select_used_typevars`. Working on lowered
code makes the check macro-expansion aware, keeps quoted method
templates inert, and covers anonymous functions and callable structs
uniformly. Diagnostics are anchored at the `where`-clause identifier
via binding provenance, and reports are deduplicated across the
multiple methods lowering generates for keyword and optional
arguments.

Also moves `is_core_svec_call` from `Closure2Opaque` to
`src/utils/ast.jl` (adding `is_core_ref`) so the diagnostic and the
closure rewrite share it.

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
A top-level function with default positional arguments or keyword
arguments lowers to multiple `K"method"`s for its (global) binding, so
`collect_multi_method_bindings` marked it as multi-method, and the
kwarg-closure reachability propagation then tagged every single-method
closure defined in its body. The OC rewrite was thus skipped for those
closures, sending them down the synthetic-struct path where body
inference collapses, e.g.:

    function withcls(x::Float64, _b::Bool=false)
        y = rand()
        r = callback(x) do x::Float64
            x + y # `y` annotated as `Any`
        end
        r
    end

Multi-method globals never go through synthetic-struct closure
conversion, so closures referenced from their bodies don't need the
tagging. Restrict the propagation worklist seeds to closure bindings.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Use `JL.SyntaxList` for the method search input.

Assert `BindingId.var_id` as `JL.IdTag` before comparing.

This keeps the closure-to-opaque rewrite easier to analyze.
A lambda body consisting of exactly one expression makes the wrapper
`K"block"` share that expression's byte range, and the first-wins
registration in `collect_provenance_indexes` let the wrapper claim the
`surface_kind_index` slot. `get_type_for_range` then missed the
dedicated lookup strategy and fell into `tmerge_at_range`, merging
loop scaffolding into the user-visible result, e.g. the comprehension
in

    get!(() -> Any[Any for _ in 1:n], d, key)

annotated as a union of `Vector{Any}`, iteration state tuples,
`LinearIndices`, and friends.

Let the surface kinds that `get_type_for_range` dispatches on take
precedence over generic wrappers within one byte range. This also
fixes the synthesized `*` callee of juxtaposed literals (`f(x) = 2x`)
leaking into queries at the body's range.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
`Base.invoke_in_world` calls are dynamic and infer as `Any`; assert
their `String` results to keep downstream code precisely typed.
Narrow the compatible LoweredCodeUtils range in Project.toml to avoid
newer unsupported releases.
aviatesk and others added 28 commits June 15, 2026 02:02
These functions all operate on stage-3 (post-scope-resolution) lowered
trees, so name the parameters `st3`/`blk3` to match the `st3` convention
used across the analysis code rather than the generic `ex`/`blk`.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Replace the scattered ad-hoc patterns for reading a node's `name_val`
attribute (`hasproperty`/`JS.hasattr` guards, `get(node, :name_val, …)`,
`isa AbstractString` checks, the local `extract_name_val`) with three
intent-revealing accessors defined in `utils/ast.jl`:

- `has_name_val(st)`  — the presence predicate
- `get_name_val(st, default=nothing)` — `Union{String,Nothing}`, for
  sites where the attribute is genuinely optional
- `name_val(st)` — `String`, for sites where the kind invariant
  guarantees presence (e.g. `K"Identifier"`, lowered symbolic nodes)

Also drops the now-redundant `_validate_logmsg_kw` helper, folding its
single call site inline. Pure refactor: no behavior change.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add `var_id(st) = st.var_id::JL.IdTag` alongside the `name_val` helpers
and route the scattered `node.var_id` / `node.var_id::JL.IdTag` reads
through it. Every site is already guarded by a `K"BindingId"` kind
check, so the asserting (non-optional) accessor is all that's needed.

Conflicting `var_id` locals in cfg-analysis are renamed to `vid` to
avoid shadowing the new accessor. Pure refactor: no behavior change.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Continue the attribute-access cleanup with a few small, behavior-neutral
touch-ups:

- Standardize `hasproperty(st, :attr)` to `JS.hasattr(st, :attr)` for
  the `:type` / `:lambda_bindings` presence checks (TypeAnnotation, diagnostic).
- Tighten `:value` reads to `::String` / `isa String` and drop the now-
  redundant `String(...)` re-conversions (document-symbol, ast).
- Replace the manual `hasattr(:syntax_flags) && has_flags(...)` guard in
  `is_open_tuple` with `JS.has_flags(node, …)`, which folds in the
  missing-attribute default (inlay-hint).
- Collapse single-expression `@something begin … end` blocks (rename).
Quick-fix code actions (removing unused variables, sorting imports,
fixing ambiguous soft scope, deleting ranges) now appear ahead of the
kindless actions (test runner, macro expansion) in the response, so
the most relevant fixes surface first in clients that preserve the
server's ordering.

Reorder the two action-collecting blocks so the quickfix block runs
first. Because `wants_kindless_actions` is only true when `only ===
nothing` (which also makes `wants_quickfix_actions` true), the kindless
block always runs after quickfix actions have been accumulated. Its
`get_file_info` failure path previously returned `null` unconditionally,
which would now discard those accumulated quickfix actions; rework it so
the `nothing` (file cache unavailable) case skips only the kindless
actions and still returns the quickfix actions, which are derived from
the request's diagnostics and do not depend on the file cache. The
cancellation path still returns the `ResponseError`.
The soft-scope quick fix was marked as preferred, which could cause
editors to apply `global` automatically even when it is not the best
intent-preserving choice.

Stop setting `isPreferred` for this code action and update the test to
expect the field to be unset.
Add a `build_inferred_context_for_tree` entry point for callers that
already resolved the lowerable top-level tree. This lets type inlay
hints and completion reuse the selected tree instead of routing through
a byte-range lookup.

The new helper owns the declaration-only skip policy and the existing
inferred-context cache behavior. `build_inferred_context_for_range` now
only locates the tree and delegates to it.

Focused tests cover cache reuse, declaration-only forms, type inlay
request filtering, type annotation content, and property completion.
Add a "Show inferred type annotations" code action on any lowerable
top-level form. It opens a read-only view of the form with JETLS's
inferred types spliced into the source as explicit `::T` annotations —
parameter uses, intermediate results, and the return value — so the
inferred types can be read inline without hovering.

The view reuses the type-inlay-hint machinery: it collects the same hints
(with truncation disabled for full types) and splices their labels into
the form's source via a shared `apply_inlay_hints` helper, now also used
by the inlay-hint tests. It is served through the existing code-view
infrastructure (`jetls-type-annotation` scheme, `textDocumentContent`
with a temp-file fallback).

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Update the macro expansion code-view docs to use nested `@assert` and `@isdefined` examples. This makes the difference between the single-call expansion and recursive top-level expansion visible.

The single-call example now leaves `@isdefined` in the result, while the top-level example uses a more realistic `selected_value` function and shows `@isdefined` recursively expanded.

Tests were not run because this is a documentation-only change.
Type inlay hints previously dropped every `Core.Const` result.
This meant const-propagated local expressions such as
`sin(x)` after `x = 42` could show no hint, even though the
widened type was useful.

Allow non-literal `Core.Const` values to be widened and shown as type
hints. Literal syntax and const bindings to `Type`, `Function`, or
`Module` still stay hidden to avoid `typeof(sin)`-style noise.

Tests cover const-propagated expressions and the now-visible
`Nothing` or constructor-call results.

Co-Authored-By: GPT-5.5 <noreply@openai.com>
Type inlay hints now show extra detail for values whose inferred
lattice element carries more information than the displayed widened
type. Lazy tooltip resolution exposes that internal element below a
separator, while eager tooltips keep showing only the widened type.
Flat long type names are now middle-truncated so labels do not
collapse to `::`.

The implementation keeps labels based on `widenconst`, resolves the
extended lattice element only through lazy tooltip data, and falls
back to a diagnostic tooltip note when showing the element itself
fails.

Tests cover const-propagated tooltip details, `show` failures, and
flat type-name truncation.

Co-Authored-By: GPT-5.5 <noreply@openai.com>
Type inlay hint labels show the widened type, which can hide useful
inference details such as `Core.Const` values. When clients support
lazy tooltip resolution, resolved type hint tooltips now include the
original inferred lattice element below a separator.

The eager tooltip path still shows only the widened type. Lazy
resolution recomputes the source range type and tries to display the
extended lattice element, falling back to a short note with
`typeof(typ)` when `show` fails.

Tests cover const-propagated tooltip details and `show` failure
fallbacks.

Co-Authored-By: GPT-5.5 <noreply@openai.com>
* inlay-hint: Show const-propagated type hints

Type inlay hints previously dropped every `Core.Const` result.
This meant const-propagated local expressions such as
`sin(x)` after `x = 42` could show no hint, even though the
widened type was useful.

Allow non-literal `Core.Const` values to be widened and shown as type
hints. Literal syntax and const bindings to `Type`, `Function`, or
`Module` still stay hidden to avoid `typeof(sin)`-style noise.

Tests cover const-propagated expressions and the now-visible
`Nothing` or constructor-call results.

Co-Authored-By: GPT-5.5 <noreply@openai.com>

* inlay-hint: Show inferred lattice tooltip details

Type inlay hints now show extra detail for values whose inferred
lattice element carries more information than the displayed widened
type. Lazy tooltip resolution exposes that internal element below a
separator, while eager tooltips keep showing only the widened type.
Flat long type names are now middle-truncated so labels do not
collapse to `::`.

The implementation keeps labels based on `widenconst`, resolves the
extended lattice element only through lazy tooltip data, and falls
back to a diagnostic tooltip note when showing the element itself
fails.

Tests cover const-propagated tooltip details, `show` failures, and
flat type-name truncation.

Co-Authored-By: GPT-5.5 <noreply@openai.com>

* inlay-hint: Add lattice details to type tooltips

Type inlay hint labels show the widened type, which can hide useful
inference details such as `Core.Const` values. When clients support
lazy tooltip resolution, resolved type hint tooltips now include the
original inferred lattice element below a separator.

The eager tooltip path still shows only the widened type. Lazy
resolution recomputes the source range type and tries to display the
extended lattice element, falling back to a short note with
`typeof(typ)` when `show` fails.

Tests cover const-propagated tooltip details and `show` failure
fallbacks.

Co-Authored-By: GPT-5.5 <noreply@openai.com>

---------

Co-authored-by: GPT-5.5 <noreply@openai.com>
Removing the type instability around the `JS.has_flags` pattern.
Hover headers now show inferred extended lattice elements as Julia
comments when the displayed type has been widened. This surfaces
cases like `Core.Const(...)` without replacing the concise type
header.

The lattice rendering helper is shared with type inlay tooltip
details, with a separate comment formatter for hover.
`Core.PartialOpaque` remains hidden in hover lattice details so
closure hovers keep the user-facing arrow signature instead of
exposing `OpaqueClosure` internals.

Co-authored-by: GPT-5.5 <noreply@openai.com>
Hovering an unannotated local closure parameter could show noisy
`Core.OpaqueClosure` internals instead of the call-site-refined
argument type. For example, `f = z -> ...; f(rand())` now reports
`z :: Float64` at the parameter position.

Index refined opaque-closure argument types by both the closure
surface range and its lowered body range, so `get_type_for_range`
can answer parameter binding ranges directly. Type inlay hints now
use the same range query instead of the exported
`get_oc_argtypes_for_range` helper, which is removed.

Co-authored-by: GPT-5.5 <noreply@openai.com>
Hover and other type-aware features inside local closure bodies could
show widened capture types even when the closure call result used
constant propagation. For example, a captured `Some{Any}` value could
appear as `Some{Any}` in the closure body instead of retaining its
`PartialStruct` field detail.

Keep the eager `check=false` opaque-closure body annotation pending
until the eager call continuation runs. While pending, `finishinfer!`
records the last body frame for the freshly materialized
opaque-closure method, so a const-prop companion frame wins over
the regular frame when it exists.

This relies on re-lowering materializing fresh opaque-closure methods
for each TypeAnnotation pass. The eager `check=false` call therefore
runs fresh body inference: the regular body `finishinfer!` completes
before the `abstract_call_opaque_closure` continuation, and const-prop'
inference, when triggered there, also completes before the outer
`Future` continuation consumes the pending state. A true cache hit
would not run `finishinfer!`, so there would be no body frame to
annotate; in that case the pending entry is simply consumed.

Added a `TypeAnnotation` regression test covering captured `Some{Any}`
field detail inside an untyped local closure.

Co-authored-by: GPT-5.5 <noreply@openai.com>
When JETLS runs with `JETLS_DEV_MODE=true`, files matched by
`analysis_overrides` log "Analysis module overridden" every time the
fallback module lookup runs before full analysis has populated the
analysis cache. Opening JETLS itself can therefore emit many duplicate
messages for the same source file.

Limit that dev log with `maxlog=1` and set `_id=path` so the suppression
is per file instead of global to the call site.

Validated with selfcheck diagnostics for `src/utils/pkg.jl`; unrelated
warnings remain in other worktrees/files.

Co-Authored-By: GPT-5.5 <noreply@openai.com>
`lowering/undef-local-var` could report false positives when a local was
protected by a negated `@isdefined` guard. For example, code that
assigned `y` before `if !(@isdefined(y)); y = ...; end` could still
look maybe undefined at a later use.

Teach the CFG undef analysis to propagate `@isdefined` facts with branch
polarity. The analysis now flips facts through `!`, propagates facts
across `&&` true branches, and propagates facts across `||` false
branches, then emits the existing `:isdefined` hint on the branch
where definedness is guaranteed.

Added focused CFG and lowering diagnostic tests covering unknown-length
iteration before a negated `@isdefined` guard, including a
`cnd || !(@isdefined(y))` condition.

Co-authored-by: GPT-5.5 <noreply@openai.com>
JETLS previously reported `lowering/unused-assignment` on phantom struct
type parameters such as `struct MyVal{T} end`, even though introducing
a type parameter without fields that mention it is valid Julia code.

Filter unused-assignment diagnostics whose provenance points at a
`struct` type parameter declaration and has no user-written assignment
expression. This leaves the CFG dead-store analysis unchanged and
suppresses only the user-facing false positive.

Added lowering diagnostic coverage for immutable and mutable phantom
type parameters, including bounded parameters and partially phantom
parameter lists.

Co-authored-by: GPT-5.5 <noreply@openai.com>
@aviatesk
aviatesk merged commit 5643648 into release Jun 18, 2026
10 checks passed
@aviatesk
aviatesk deleted the releases/2026-06-18 branch June 18, 2026 03:01
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