Skip to content

Inlay hints: variable types + parameter names (TypeHints facade)#1266

Draft
lukaszsamson wants to merge 27 commits into
masterfrom
inlay-hints
Draft

Inlay hints: variable types + parameter names (TypeHints facade)#1266
lukaszsamson wants to merge 27 commits into
masterfrom
inlay-hints

Conversation

@lukaszsamson

Copy link
Copy Markdown
Collaborator

Draft PR to run the CI matrix against the inlay-hints branch with the published elixir_sense pin (elixir-lsp/elixir_sense@c9f34e24 — its own matrix is green on 1.16–1.20, validating progressive enhancement).

Contents: textDocument/inlayHint provider (variable type hints incl. flow-sensitive read hints, parameter-name hints), consuming the ElixirSense.Core.TypeHints facade exclusively; minimumTrust setting over compiler/native/bestEffort trust ranks; runtime ELIXIR_LS_TYPE_INFERENCE kill switch; server e2e + compiled-ExCk-fixture + release-smoke test suites. Tracked in ELIXIR_LS_TYPES_FABLE.md.

Remaining release mechanics before un-drafting: flip the release-gate CI job to hard-fail, freeze defaults, land the VS Code extension schema/docs.

🤖 Generated with Claude Code

lukaszsamson and others added 26 commits June 7, 2026 19:54
Recovers the experimental LSP textDocument/inlayHint provider that renders
inferred variable types inline (InlayHintKind.type) on binding occurrences
(LHS of a match). Reconstructed from the 2025-10-02 design/implementation
session after the original branch was lost.

- New ElixirLS.LanguageServer.Providers.InlayHints (phase 1: variable type hints,
  with range/variable/label/depth budgets and elixirLS.inlayHints.variableTypes.enabled)
- Wire textDocument/inlayHint handler and advertise inlay_hint_provider capability
- Tests for variable hints, settings toggle, binding-vs-read positions
- Point :elixir_sense at the elixir-types type engine (local path dep) in all 3 apps
- INLINE_HINTS.md design doc + INLAY_HINTS_RECOVERY.md status notes

Known incomplete: variable-hint extraction returns empty against the current
elixir_sense branch (needs debugging); call parameter-name hints designed but
not yet implemented.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Adapts the provider to the new type-engine API instead of rendering shapes
locally.

- Delete the local render_shape/2; render via TypePresentation.render_hint/2,
  which resolves VarInfo.type through Binding (descriptor fallback), stays
  thunk-free, and skips uninformative term()/none()/unknown types.
- Binding occurrence = head of VarInfo.positions; reads (tail) are not
  annotated. Each destructured var is its own VarInfo, so every bound name is
  covered. showOnlyBindings=false opts into annotating reads.
- Labels carry the leading colon (": integer()"); provider keeps only the
  max-length truncation.
- Settings: inlayHints.variableTypes.{enabled, showOnlyBindings, maxLength}.
- Tests assert real engine output (integer/binary/tuple/map/list literals,
  %URI{} struct, fn arrow), plus suppression, binding-vs-read, settings,
  truncation. 14 tests, all passing against the elixir-types engine.

Richer precision (branch-narrowing, map/union, precise struct field types)
remains gated on the type engine and is intentionally not addressed here.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Implements the second inlay-hint case from the design: parameter names
rendered before each argument of a function call
(e.g. `Map.put(map: m, key: :k, value: v)`), kind `parameter`.

- Collect calls from the parsed AST (Parser.Context.ast), excluding def-heads
  and special forms/operators.
- Resolve MFA via Introspection.actual_mod_fun/6; parameter names from
  Metadata.get_function_signatures/3 (local) or Introspection.get_signatures/2
  (remote/stdlib), selecting the arity-matching signature (defaults handled).
- Compute per-argument columns from the Elixir tokenizer by matching the
  call's (…) and splitting top-level commas — robust against commas inside
  strings/sigils and fn/do blocks.
- Pipes shift the parameter window by one (piped value is implicit).
- Suppress an argument hint when its source text already equals the param name.
- Setting inlayHints.parameterNames.enabled (default true).

21 tests, all passing against the elixir-types engine. Richer type precision
(narrowing/union/struct-field types) remains engine-gated and untouched here.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ordering

Addresses review findings:

- P1: dynamic remote-call receivers (`mod.put(...)`, `factory().call(...)`) no
  longer crash the request. `module_of/1` returns `:error` for non-atom/alias
  receivers and the call is skipped; per-call resolution is also wrapped so one
  bad call can't fail the whole request.
- P2: filter calls to the requested line range *before* resolution/introspection
  /tokenizing, so viewport requests in large files don't process every call.
- P2: the server `textDocument/inlayHint` handler now skips non-Elixir files
  (.ex/.exs or language_id == "elixir"), mirroring sibling providers.
- P3: merge type + parameter hints and sort by position before the cap, so
  neither category starves the other and output is in document order.

Tests: dynamic-receiver no-crash, range filtering, document-order (24 total,
all passing). Updated the recovery doc (stale "designed only"/engine-gated
claims removed; guardrails and counts corrected). List rendering now reflects
the upgraded engine (`[1 | 2 | 3]`).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Mirrors the elixir-types changes elixir_sense made in its own providers, on
the elixir-ls forks:

- Hover: ElixirLS.LanguageServer.Providers.Hover.Docs now renders a variable's
  inferred type via TypePresentation.render_hint/2; hover.ex shows it as a
  "### Type" section.
- Completion: ElixirLS.Utils.CompletionEngine.match_map_fields/5 falls back to
  the inferred field type (TypePresentation.render/1) for map/struct fields
  without a declared @type, so field completions surface e.g. %{asdf: term()}
  or %MyStruct{}. Bare term()/none() are suppressed to avoid noise (a small,
  deliberate divergence from elixir_sense).

Tests: new hover "variable with inferred type"; updated completion_engine
field-completion expectations to the now-richer type_spec values. All affected
suites green (hover, completion provider, completion_engine, inlay).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Turn on the native Module.Types backend (use_elixir_types) in config/config.exs
so inlay hints, hover, and completion use set-theoretic type inference. On by
default; ELIXIR_LS_TYPE_INFERENCE=false disables it for A/B testing. Falls back
to the custom engine automatically when Module.Types is unavailable (< 1.19).

Update inlay-hint test expectations to native-mode rendering:
- tuple {:ok, 1} -> {:ok, integer()}
- list [1, 2, 3] -> [integer()]
- fn arg/return types inferred (float() | integer()); assert the stable prefix
  since the full arrow can exceed maxLength.

All affected suites green with native mode on (hover, completion provider,
completion_engine, inlay).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
`x = 1`, `s = "foo"`, `t = {:ok, 1}`, `m = %{…}`, `l = […]`, `%S{…}` render a
type that merely restates the source — pure noise. Suppress the variable type
hint when the match RHS is a literal value or literal data constructor
(number/string/atom/charlist/tuple/list/map/struct/bitstring); chained matches
(`a = b = 1`) propagate the inner RHS. Hints are kept for calls, operators,
`fn`, vars, and control-flow (`total = a + b` → `: integer()`).

The obvious-binding positions are collected from the AST (LHS pattern var
positions of literal-RHS matches) and filtered out before rendering. Hover is
unchanged (hovering is explicit, so showing a literal's type there is fine).

Tests reworked: literal-binding cases became suppression cases; kept-case and
binding/read/settings tests use non-literal RHS. inlay/hover/completion green.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
`=` is a match, so the type-evident value can be the RHS (`x = 1`,
`t = {:ok, 1}`) or the LHS (`%User{} = user`, common in function heads). Make
the obvious-value check symmetric: in `left = right`, if either side is a
literal/struct/map/list/tuple/bitstring, suppress the variables on the opposite
side. Collecting vars from the value side is harmless — those occurrences are
reads whose binding positions live elsewhere.

Adds a test for `def run(%URI{} = uri)` producing no hint for uri.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Inlay hints provider:
- Correct param-name labels with non-trailing defaults: defaulted params are
  dropped right-to-left for the called arity (verified: f(a, b \\ 1, c) called
  /2 binds {a, c})
- Clamp >1000-line ranges to the budget instead of returning zero hints
  (whole-document clients on large files)
- Codepoint (not grapheme) arithmetic for hint positions
- Labels/tooltips via TypePresentation.render_hint/3 max_length: — elided
  label, full type in the tooltip; provider-side byte/grapheme truncate removed
- @call_blocklist applies to local calls only; __MODULE__-prefixed receivers
  resolve from env instead of raising
- obvious_value? requires all-literal leaves ({:ok, compute()} keeps its hint)
- Single tokenize per request with tuple index and one-pass delimiter
  matching (was O(n^2) per call)

Server/config:
- ELIXIR_LS_TYPE_INFERENCE applied at runtime in language_server startup
  (config.exs alone is baked into releases)

Tests: 12 new inlay-hint tests; stale ported expectations updated for the
type-integration output (hover variable docs type field, completion field
type_spec rendering). Pre-existing locator/markdown failures documented in
ELIXIR_LS_TYPES_FABLE.md (status + deferred items, incl. the path-dep
repointing required before merge).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- New elixirLS.inlayHints.variableTypes.minimumTrust setting
  ("native" | "bestEffort", default "bestEffort"): "native" drops variable
  hints whose TypePresentation source is :shape (structural engine), keeping
  only compiler-descriptor-backed types; parameter-name hints unaffected
- One-time backend-status Logger.info on the first inlay-hint request:
  compiler-native / structural-disabled / structural-unavailable, derived
  from ElixirTypes.enabled?/available?
- Consumes render_hint/3 source field and literal widening from elixir_sense
  (hint labels show integer()/binary() instead of literal values)
- 11 new tests: literal-widening leakage guard, remote-call and destructuring
  hints, minimumTrust gating, param-hint independence with inference disabled,
  failure-mode robustness (nonexistent module)

51 inlay-hint tests passing; hover/docs/completion provider suites green
(345); format gate clean. Status tracked in ELIXIR_LS_TYPES_GPT.md /
ELIXIR_LS_TYPES_FABLE.md. The corresponding minimumTrust schema lives in
vscode-elixir-ls package.json (separate repo).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ts backlog

ELIXIR_LS_TYPES_FABLE.md is now the single prioritized backlog, merging the GPT
and Gemini second-round reviews with verification verdicts: per-hint
Binding.from_env confirmed (no batching); read-occurrence binding-type reuse
reframed as semantically correct + off by default; tooltip bloat bounded
(conditional + 1000-grapheme cap, lazy resolve premature); param parsing
improved but still string-based (pattern defaults silently drop hints);
clamp_range off-by-one (>= needed); server-level and ExCk e2e coverage
confirmed absent.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…tests

Layering: the provider no longer references ElixirSense.Core.Binding or
TypePresentation. One TypeHints.request_context per request (request-scoped
caches shared across all hints — kills the verified per-hint env/binding/
local-sigs rebuild); variable hints via type_hint_for_var/4; parameter names
via effective_params/4 (parse_param string-splitting deleted; pattern-match
defaults like `%{} = opts \\ %{}` now label `opts:` instead of dropping).

clamp_range: inclusive at-most-1000-lines window (off-by-one fixed,
boundary-tested).

New coverage:
- server_inlay_hints_test.exs (real Server GenServer): capability
  advertisement, full textDocument/inlayHint round-trip, sub-range scoping,
  exact UTF-16 positions for non-ASCII identifiers, cancellation robustness
- inlay_hints_integration_test.exs: compiled fixture beam on a tmp code path,
  remote-call binding hint, degradation without the fixture, minimumTrust
  interplay

362 tests green across inlay unit + integration + server e2e + hover/docs/
completion; format gate clean. Backlog status updated in
ELIXIR_LS_TYPES_FABLE.md.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- minimumTrust now supports compiler | native | bestEffort, filtered through
  TypeHints.trust_rank/1 over the refined sources (:native_exck >
  :native_inferred > :spec > :shape); unrecognized future source atoms fail
  safe to weakest (shown only under bestEffort)
- 23 new tests: overloaded ExCk fixture returns selected by argument type,
  struct-returning fixture, ExCk version-mismatch degradation (foreign checker
  tag), missing-chunk module, destructuring suppression policy locked in
  (%Struct{} = call() hints; {:ok, value} = call() hints value), minimumTrust
  matrix against observed source attribution (Enum.map binding classifies
  :native_exck in practice)

378 tests green across inlay unit + integration + server e2e + hover/docs/
completion; format gate clean. Status updated in ELIXIR_LS_TYPES_GPT.md.
The minimumTrust "compiler" schema value and README settings docs live in the
vscode-elixir-ls repo (uncommitted there).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- Unrecognized minimumTrust setting values (e.g. "strict") log a one-time
  warning per value listing the valid options, instead of silently behaving
  as the most permissive level; behavior still fails open to bestEffort
- minimum_rank computed once in config/1 with a rescue fallback (was per-hint
  and asymmetric with the source-side rescue)

Round-4 independent review otherwise verified the provider sound (context
scoping, piped-param math, range filtering, padding/kind spec compliance) and
closed the benchmark backlog item with data: native typing is 2.4x faster on
the hint path (802ms vs 1912ms full-document on a 1795-line module; 140ms vs
317ms for a 100-line viewport). Status in ELIXIR_LS_TYPES_FABLE.md.

380 provider tests green; format gate clean.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- Read occurrences (showOnlyBindings: false) route through the new
  TypeHints.type_hint_at/4 and show the type narrowed AT the read position
  (cond/guard narrowing verified: x inside is_integer(x) branch hints
  integer()); binding occurrences keep the binding-site path; minimumTrust
  applies to both; default users (bindings-only) see zero change
- occurrences/2 emits tagged {:binding, var} | {:read, name} tuples; obvious-
  value suppression remains binding-only by construction
- release-gate CI job rejects absolute local path deps in mix.exs/mix.lock
  (continue-on-error on this branch — the local elixir_sense worktree dep is
  intentional during development; flip to hard-fail at release)

385 tests green across inlay unit + integration + server e2e + hover/docs/
completion; format clean. Status in ELIXIR_LS_TYPES_FABLE.md.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- Integration coverage: dependency-chain fixtures (buffer -> A -> B with real
  ExCk chunks; fixture compilation needed debug_info enabled and on-disk beam
  re-load for ExCk path lookups — mechanism documented in the test), optional-
  key map returns, struct returns, stdlib overloads (Enum.at/2 vs /3,
  Keyword.get)
- Release smoke scaffold (:release_smoke tag, excluded by default): the
  no-absolute-path-deps assertion that documents the release blocker, an
  always-running companion asserting the local path dep IS currently present
  (flips loudly when the state changes), and the documented manual
  packaged-dependency check

397 provider tests green (2 smoke exclusions by design); format clean.
Status in ELIXIR_LS_TYPES_FABLE.md. The read-occurrence README docs live in
the vscode-elixir-ls repo (uncommitted there).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Replace the development-time local worktree path dependency with the git pin:
elixir-lsp/elixir_sense @ eeb32891 (claude/trusting-wu-d1f603 — the full types
integration: TypeHints facade, trust levels, three-marker map tails, improper
lists, ModuleResolver, apply parity). dep_versions.exs and mix.lock updated.

This resolves the P0 path-dep release blocker for CI purposes: the release-gate
job and the release-smoke companion test will now observe the git dep. CI can
exercise the full Elixir version matrix against the published dep to validate
progressive enhancement on < 1.20.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…n 1.16-1.20)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
# Conflicts:
#	dep_versions.exs
#	mix.lock
…ood guard

Real fixes:
- Parameter-name inlay hints were silently ABSENT on Elixir 1.16:
  :elixir_tokenizer.tokenize returns tokens in forward order on 1.16
  (5-tuple) but reverse order on 1.17+ (6-tuple); the unconditional reverse
  scrambled the delimiter stack so argument spans never resolved. Replaced
  with position-based ordering, version-independent
- markdown_utils: the :..// atom renders unquoted on the 1.20 formatter but
  quoted on 1.16 — no literal form passes --check-formatted on both;
  replaced with String.to_atom("..//")
- complete_test: charlists normalized to ~c sigils + line-break stability
  (1.16 and 1.20 formatters now both accept the file)
- Test isolation: ExCk fixture compiles crashed when a prior test left the
  LSP Tracer registered as a compiler tracer after its GenServer died —
  fixtures now compile with tracers stripped

1.18/1.19 runner kills root-caused as a LOG FLOOD (not a hang): the dep's
native typing logged ~178 multi-KB crash traces per run on unexpanded
Record/defguard/struct patterns (718 KB -> 33 KB after fix). Mitigated with
per-module Logger suppression in test_helper (a global :error floor broke 22
tests asserting window/logMessage flow); the dep-side root fix (of_head
non-pattern filtering) ships in the elixir_sense pin bumped here
(b65c4e4a, PR elixir-lsp/elixir_sense#334 — 18/18 green incl. all versions).

Version-gated test expectations: capability tiers are NOT uniform 1.18+ —
available?() (1.18+) for spec unions/provenance, available?(:expr) (1.19+)
for literal widening/fn returns, available?(:previous) (1.20) for
default-nil widening and fn argument inference; assertions gated per tier
without weakening 1.20.

Release smoke: the companion test flipped to assert the NEW state (git pin,
no absolute path dep) per its design.

Local matrix (apps/language_server): 1.16 and 1.17 green (full suite);
1.18/1.19 green except the 3 known pre-existing locator hangs; 1.20
unchanged; umbrella format green on 1.16 and 1.20.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…x — unblocks the locator hangs)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- elixir_range: drop dead || 1 fallbacks (lsp_position_to_elixir columns are
  always pos_integer per success typing — guard_fail)
- .dialyzer_ignore: the 1.16 tokenizer 5-tuple (and older 4-tuple) clauses in
  tokenize/1 are required at runtime on old Elixirs but appear dead against
  the 1.20 PLT (same class as the existing OTP-26 markdown_utils entry)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…tting

- module_of/2 hand-concatenated __aliases__ without consulting env.aliases,
  so aliased remote calls (alias Foo.Bar; Bar.fun(x)) resolved to the wrong
  module and parameter-name hints silently dropped — now delegates to
  ElixirSense.Core.ModuleResolver.resolve/2 (regression test added)
- split_arguments accumulates by prepend+reverse instead of O(K^2) appends
- documented that clean_identifier? rejecting leading underscores is
  deliberate display suppression (differs from the facade-side predicate
  on purpose)

103 inlay tests green; format gate clean.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds first-class LSP inlay hints support (variable type hints + parameter name hints) backed by the ElixirSense TypeHints facade, and wires it through the language server with extensive end-to-end and integration tests. It also introduces runtime/config toggles for ElixirSense native typing, and expands hover/completion to surface inferred types.

Changes:

  • Implement textDocument/inlayHint handling in the server and a new Providers.InlayHints implementation (variable type hints + parameter-name hints, range clamping, settings support).
  • Add broad automated coverage: server e2e tests, provider unit tests, compiled-fixture integration tests, and release-gate smoke tests.
  • Extend hover and completion output to include rendered inferred types (via TypePresentation) and adjust CI/release guardrails.

Reviewed changes

Copilot reviewed 20 out of 21 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
mix.lock Updates the pinned elixir_sense git ref.
dep_versions.exs Updates the tracked elixir_sense ref used by umbrella apps.
config/config.exs Adds config-time toggle for ElixirSense native typing via ELIXIR_LS_TYPE_INFERENCE.
apps/language_server/test/test_helper.exs Silences noisy ElixirSense degradation logs in tests; excludes :release_smoke by default.
apps/language_server/test/server_inlay_hints_test.exs New server-level e2e tests for textDocument/inlayHint (capability, range, unicode, cancellation).
apps/language_server/test/release_smoke_test.exs New release-gate smoke tests (absolute-path dep checks + placeholder release steps).
apps/language_server/test/providers/inlay_hints_test.exs New unit tests for variable-type and parameter-name hint behavior, settings, and robustness.
apps/language_server/test/providers/inlay_hints_integration_test.exs New integration tests compiling fixtures and validating degradation-safe behavior (incl. ExCk scenarios).
apps/language_server/test/providers/hover/docs_test.exs Updates variable hover docs expectations to include type.
apps/language_server/test/providers/hover_test.exs Adds hover test asserting inferred variable type is rendered.
apps/language_server/test/providers/completion/suggestions_test.exs Updates completion expectations for rendered type_spec, with version-gated widening behavior.
apps/language_server/lib/language_server/server.ex Registers InlayHints provider and adds request handler + capability advertisement.
apps/language_server/lib/language_server/providers/inlay_hints.ex New inlay-hints provider implementation (variable types + parameter names, settings, tokenization, range clamping).
apps/language_server/lib/language_server/providers/hover/docs.ex Adds type to variable docs using TypePresentation.render_hint/2.
apps/language_server/lib/language_server/providers/hover.ex Renders a “Type” section in variable hover markdown when available.
apps/language_server/lib/language_server/markdown_utils.ex Adjusts special-case parsing for ..///3 to be formatter-stable across Elixir versions.
apps/language_server/lib/language_server.ex Applies ELIXIR_LS_TYPE_INFERENCE at runtime (release-safe) by setting :elixir_sense, :use_elixir_types.
apps/elixir_ls_utils/test/complete_test.exs Updates completion-engine tests for new type_spec values; normalizes some charlist literals.
apps/elixir_ls_utils/lib/completion_engine.ex Uses TypePresentation to render inferred field types when no declared typespec exists.
.github/workflows/ci.yml Adds a “release gate” job checking for absolute path: "/..." deps (currently continue-on-error).
.dialyzer_ignore.exs Adds ignore for inlay hints tokenizer pattern matching across Elixir versions.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread config/config.exs
Comment on lines +32 to +35
config :elixir_sense,
use_elixir_types:
System.get_env("ELIXIR_LS_TYPE_INFERENCE", "true") |> String.downcase() != "false"

Comment on lines +9 to +13
They are intended to run against a CLEAN checkout with production deps (no
`path:` overrides) before cutting a release. Today most of them are excluded
because the workspace intentionally uses a local `path:` dep for
`elixir_sense` during development.

Comment thread .github/workflows/ci.yml
Comment on lines +12 to +16
# Release gate: absolute local path dependencies must never ship. This is
# EXPECTED to flag on the inlay-hints development branch (elixir_sense is a
# local worktree path dep during development) — continue-on-error keeps the
# branch green while documenting the blocker. Flip continue-on-error to
# false before release.
Comment on lines +231 to +245
type_section =
case Map.get(info, :type) do
type when is_binary(type) and type != "" ->
"""

### Type

```elixir
#{type}
```
"""

_ ->
""
end
Comment on lines +20 to +26
1. `no_absolute_path_deps` — asserts that no `mix.exs` file in the umbrella
tree contains `path: "/"` (an absolute-path dep). Today this test
DOCUMENTS A KNOWN RELEASE BLOCKER: the `elixir_sense` dep in
`apps/language_server/mix.exs` uses an absolute `path:` pointing to a
local worktree. The always-running companion test
(`path_dep_is_still_present`) asserts that the path dep IS present so the
suite notices when it is removed.
Comment on lines +431 to +436
# NOTE: `String.to_atom("..//")` rather than the literal `:..//` atom because
# the two supported formatters disagree on how to render that atom — Elixir
# 1.20 emits it unquoted (`:..//`) while 1.16 quotes it (`:"..//"`), so no
# single literal form is `mix format --check-formatted`-clean on both. The
# string form is left untouched by every formatter and yields the same atom.
defp get_module_fun_arity("..///3"), do: {Kernel, String.to_atom("..//"), 3}
…p elixir_sense pin

- module_of/2 passed the %State.Env{} struct to ModuleResolver.resolve/2,
  whose env type is an anonymous %{optional(:module), optional(:aliases)} map;
  a struct is not a subtype, so dialyzer flagged the call as never-succeeding
  (no_return). Pass %{module: env.module, aliases: env.aliases} — same fix as
  the elixir_sense-side ModuleResolver callers.
- Bump elixir_sense pin b3ad3c30 -> 53f8879d (review fixes incl. domain-key
  field_get crash fix, combinator/cache cleanups, test consolidation/trim).

Inlay suites 103 passed; format clean; dialyzer clean.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
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.

2 participants