Release: 0.52 - Honest Output
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 indocs/errors/. (#3266)- Runtime errors carry a code:
PHEL400not callable,PHEL401arity,PHEL402type,PHEL403out of bounds,PHEL404division by zero. (#3266) --stack-traceonphel run,phel evalandphel 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()andErrorCode::SUPERSEDED_FORM. (#2859 #3268 #3290)
🗑️ Removed
- BREAKING:
php/new,php/->,php/::andset-varas source. Writing one is aPHEL012error. 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 ofphp/*stays. (#2859, ADR 0018) - BREAKING (PHP API):
ErrorCode::INVALID_QUOTE,ErrorCode::INVALID_UNQUOTEandErrorCode::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:
PHEL008bindings,PHEL009interfaces,PHEL010recur,PHEL202splice. (#3266) - A special form with too few arguments names the form and the shape it wants. It used to raise
[PHEL403] Index out of boundsfrom insidePersistentList, or a bareAssertionErrorthatzend.assertions=-1hid. Same fix for adefinterfacemethod with no argument vector and acatchwith no type or binding. (#3266 #3297) - Analyzer messages name Phel types:
nil, notnull.vector, notCollections\Vector\PersistentVector. (#3290) (.-$foo o)explains the sigil rule instead ofCannot resolve symbol '.-$foo'. Diagnostics suggest the Clojure-style spelling, neverphp/::orphp/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 evaland the REPL: message,atline, user frames, one collapse marker, a hint when one matches. (#3264) - An error raised inside the core library points its
atline at the user's call, not the compiled cache. An uncaughtex-infoprints 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 lintreports 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: theForm:line of a failed assertion shows the source form, not the evaluated value. (#3263)phel test --parallelwarms 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 mutateandphel test --coveragecollect 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>/opcachestops growing without bound.phel cache:clearempties it, every run prunes stale system-id directories and orphaned.binfiles, andphel doctorreports its size. (#3268)- Pruning no longer dies with
UnexpectedValueExceptionwhen another process removes a subdirectory mid-prune. (#3280)
👥 Contributors
@Chemaclass @DipakChaudhari @JesusValeraDev
Full Changelog: v0.51.0...v0.52.0
Downloads
v0.52.0
- phel.phar (2.63 MB)