Skip to content

Format solver structs without String.Chars dispatch - #60

Merged
ericmj merged 1 commit into
mainfrom
direct-to-string
Oct 12, 2026
Merged

ericmj merged 1 commit into
mainfrom
direct-to-string

Conversation

@ericmj

@ericmj ericmj commented Oct 12, 2026

Copy link
Copy Markdown
Member

Hex vendors the solver into its archive as Hex.Solver. When a Mix project compiles, it prunes code paths, including archives, and then consolidates protocols, so the project's consolidated String.Chars has no impls for the solver's structs. A failed resolution after compile in the same VM, such as mix do compile + deps.get, raised Protocol.UndefinedError from Failure instead of explaining the conflict, and HEX_DEBUG_SOLVER logging raised the same way.

This calls each struct's to_string/1 directly when formatting, including in the Inspect impls and the debug logs. It adds to_string/1 to the Constraint protocol, since a constraint can be a Range, Union, Empty or Version. The String.Chars impls stay for library users. The new test traces String.Chars.to_string/1 while a failed solve is formatted and checks that it never receives a solver struct. It fails without the change.

I vendored this and #59 into Hex, together with the Hex fix that restores its code paths after compiling. In a project requiring jason ~> 99.0, mix do compile --no-deps-check + deps.get then printed the explanation, and with HEX_DEBUG_SOLVER=1 it printed the solver log. Without this change both raised. That was on Elixir 1.20.4 / OTP 29.1.1, and the Hex suite passed with the vendored copy.

Hex vendors the solver into its archive. Mix consolidates the project's
protocols during compile with code paths that exclude archives, so the
consolidated String.Chars has no impls for the solver structs.
Formatting a failed resolution in the same VM after compile
interpolated terms, package ranges and constraints and raised
Protocol.UndefinedError instead of explaining the failure.

Call each struct's to_string/1 directly, and add to_string/1 to the
Constraint protocol for constraints, which can be any of four structs.
The String.Chars impls stay for library users.
@ericmj
ericmj merged commit 45cf17f into main Oct 12, 2026
20 checks passed
@ericmj
ericmj deleted the direct-to-string branch October 12, 2026 22:56
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