Skip to main content

Release: 0.52 - Honest Output

Latest update

0.52.0 - Honest Output

Released 2026-09-19 · GitHub release

Error codes + phel explain + uniform stack traces, legacy php/new/php/->/php/:: dropped, pruned OPcache.

🎉 Added

  • phel explain <code> prints what an error code means, the smallest program that raises it, and the fix. The same text lives in docs/errors/. (#3266)
  • Runtime errors carry a code: PHEL400 not callable, PHEL401 arity, PHEL402 type, PHEL403 out of bounds, PHEL404 division by zero. (#3266)
  • --stack-trace on phel run, phel eval and phel repl. The collapse marker names the flag and the error log. (#3261)
  • BREAKING (PHP API, implementers only): CommandFacadeInterface::getRuntimeErrorReport() returns the runtime error report as a string, for hosts that print it themselves. (#3264)
  • Public API: Phel\Lang\PhelType, Shared\ByteSize, Shared\Performance\OpcacheFileCache, Shared\Performance\OpcacheFileCachePruner, PhelProjectDirectory::opcachePath() and ErrorCode::SUPERSEDED_FORM. (#2859 #3268 #3290)

🗑️ Removed

  • BREAKING: php/new, php/->, php/:: and set-var as source. Writing one is a PHEL012 error. Use (new \Foo arg), (.method obj arg) / (.-field obj), (\Foo/method arg) / \Foo/CONST, and (alter-var-root (var v) f). The compiler still emits all four, so generated PHP does not change, and macros that expand to them keep working. The rest of php/* stays. (#2859, ADR 0018)
  • BREAKING (PHP API): ErrorCode::INVALID_QUOTE, ErrorCode::INVALID_UNQUOTE and ErrorCode::INVALID_CHARACTER. Phel never raised them. (#3266)

🐛 Fixed

Compile errors:

  • Every compile error reports the same way: code, file and line, snippet, caret. Lexer errors (PHEL310), unclosed delimiters and redefined symbols (PHEL004) used to print the exception class, an internal file, or 31 frames. An unclosed delimiter names the line it opened on, a redefinition the line of the first one. (#3259 #3267 #3289)
  • Errors that had a code but never printed it now do: PHEL008 bindings, PHEL009 interfaces, PHEL010 recur, PHEL202 splice. (#3266)
  • A special form with too few arguments names the form and the shape it wants. It used to raise [PHEL403] Index out of bounds from inside PersistentList, or a bare AssertionError that zend.assertions=-1 hid. Same fix for a definterface method with no argument vector and a catch with no type or binding. (#3266 #3297)
  • Analyzer messages name Phel types: nil, not null. vector, not Collections\Vector\PersistentVector. (#3290)
  • (.-$foo o) explains the sigil rule instead of Cannot resolve symbol '.-$foo'. Diagnostics suggest the Clojure-style spelling, never php/:: or php/new. (#3300)
  • A compiler deprecation prints one stderr line naming the user's file. (#3262) Runtime errors:
  • An uncaught runtime error reads the same in phel run, phel eval and the REPL: message, at line, user frames, one collapse marker, a hint when one matches. (#3264)
  • An error raised inside the core library points its at line at the user's call, not the compiled cache. An uncaught ex-info prints its data map. (#3260)
  • A host object with no printer of its own prints as #<Class>, so a stack-trace frame no longer shows a sentence where an argument belongs. (#3265)
  • The error log is plain text. Each entry opens with a timestamp and the command, and the file rotates at 1 MiB into error.log.1. (#3269) Tooling:
  • phel lint reports a file that does not lex or parse and exits 1. It used to print "No lint issues found." and exit 0. (#3292)
  • phel test: the Form: line of a failed assertion shows the source form, not the evaluated value. (#3263)
  • phel test --parallel warms the bundled namespaces first. It re-runs a namespace only when its worker died, never for a compile error or a failing test. (#3271)
  • phel mutate and phel test --coverage collect coverage under pcov. A run that reaches no mutant scores 0 and fails --min-covered-msi. (#3270)
  • REPL: (exit) and (quit) end the session, and (exit <code>) sets the exit status. (#3272) OPcache file cache:
  • <phel-dir>/opcache stops growing without bound. phel cache:clear empties it, every run prunes stale system-id directories and orphaned .bin files, and phel doctor reports its size. (#3268)
  • Pruning no longer dies with UnexpectedValueException when another process removes a subdirectory mid-prune. (#3280)

👥 Contributors

@Chemaclass @DipakChaudhari @JesusValeraDev

Full Changelog: v0.51.0...v0.52.0

Downloads

v0.52.0


View release on GitHub