github carthage-software/mago 1.16.0
Mago 1.16.0

6 hours ago

Mago 1.16.0

Mago 1.16.0 is a significant release focused on analyzer accuracy. This release fixes over 20 false positives across loop analysis, type narrowing, integer range tracking, switch fall-through handling, and comparison assertions. It also adds new features including duplicate enum value detection, argument validation hooks for setcookie, session_set_save_handler, and session_set_cookie_params, and improved return type inference for min, max, abs, and array_reverse.

✨ Features

Analyzer

  • Detect duplicate enum values: The analyzer now reports an error when a backed enum has multiple cases with the same value (#1475, #1478)
  • Argument validation for setcookie / setrawcookie: When the 3rd argument is an array (options form), additional positional arguments are now flagged as errors (#1467, #1492)
  • Argument validation for session_set_save_handler: Validates both the object form (1-2 args) and callable form (6-9 args), reporting errors for mismatched argument counts (#1468)
  • Argument validation for session_set_cookie_params: When the 1st argument is an array, extra arguments are now flagged as errors (#1468)
  • Improved min / max / abs return types: Multi-argument min and max calls now return precise integer range types, and a new abs provider returns non-negative ranges (#1477, #1480)

🐛 Bug Fixes

Analyzer

  • Fixed false positives in loop analysis: Resolved multiple issues where the analyzer incorrectly flagged conditions inside loops as impossible, including accumulative operations like $total += $delta (#1491, #1493, #1499)
  • Fixed condition side effects lost in if-statements: Post-increment expressions like $n++ inside if-conditions had their side effects discarded when the if-body always exited, causing false "impossible condition" reports (#1504)
  • Fixed non-comparison loop conditions: Assignment-based loop conditions like while ($row = func()) were incorrectly treated as always-true, causing variables modified inside the loop to lose their pre-loop values (#1505)
  • Fixed switch fall-through type tracking: Variables modified in fall-through switch cases now correctly preserve types from both direct-entry and fall-through paths (#1490)
  • Fixed switch cases after default treated as unreachable: Cases placed after the default clause are no longer incorrectly flagged (#1484, #1485)
  • Fixed integer range narrowing in comparisons: Range bounds from non-literal types (e.g., non-negative-int) on the secondary variable in less-than comparisons no longer produce incorrect type narrowing when negated (#1503)
  • Fixed count() === N not narrowing empty arrays: Empty arrays without generic parameters are now correctly removed when reconciling exact count assertions (#1506)
  • Fixed loose equality narrowing to never: Loose equality (==) with strings no longer incorrectly narrows numeric types to never (#1488)
  • Fixed closure parameter null stripping: Inferred null types on closure parameters are no longer incorrectly removed when no explicit type hint is present (#1489)
  • Fixed instanceof self / instanceof static: These expressions are now properly resolved for type computation (#1464)
  • Fixed increment/decrement on never producing mixed: Operations on never types now correctly propagate never instead of falling back to mixed (#1502)
  • Fixed numeric in string concatenation: The numeric type is now accepted in string concatenation operations (#1500)
  • Fixed integer range precision in loops: Bitwise and shift operations inside loops no longer unnecessarily widen integer ranges (#1499)
  • Fixed isset return type: isset() now returns true instead of bool when all checked values are definitely set, and array keys are marked as definite after loops that always enter (#1486, #1493)
  • Fixed loop integer widening: Variables with integer ranges that grow uniformly across loop iterations are now properly widened to prevent false impossible-condition reports (#1493)

Formatter

  • Fixed stdin formatting memory issue: The source database is no longer populated when formatting from stdin (#1483)
  • Fixed conditional expression comment placement: Comments in conditional (ternary) expressions are now placed correctly (#1465)

Prelude

  • Fixed array_reverse return type: Non-list arrays (e.g., array<string, int>) now correctly preserve their key type instead of being narrowed to list<V> (#1466)
  • Fixed non-positive-int type mapping: Was incorrectly mapped to positive-int due to a copy-paste error (#1479)
  • Removed false @deprecated on mb_scrub: The function is not deprecated in PHP (#1476, #1481)
  • Fixed getrusage function signature: Corrected the return type to match PHP documentation (#1501)
  • Fixed iconv mode parameter: Corrected the mode parameter type to int<0, 3> (#1497)
  • Fixed openssl_pkey_get_details return type: Made all keys optional since algorithm-specific keys are only present for their key type
  • Consolidated session_set_save_handler stub: Merged duplicate declarations into a single signature with union types (#1468)
  • Consolidated session_set_cookie_params stub: Merged duplicate declarations into a single signature (#1468)

Codex

  • Improved integer bitwise operations: Bitwise AND with a non-negative mask now correctly produces a bounded non-negative result (#1499)

📖 Documentation

  • Added Run On Save as alternative formatter: Documented the Run On Save VS Code extension as an alternative to format-on-save (#1469)
  • Removed outdated Docker limitations: The limitations section was removed from the Docker recipe page as the issues have been resolved (#1438)

🏗️ Internal

  • Updated dependencies
  • Fixed clippy warnings
  • Updated sponsors list

🙏 Thank You

Contributors

A huge thank you to everyone who contributed code to this release:

Issue Reporters

Thank you to everyone who reported issues that shaped this release:


Full Changelog: 1.15.3...1.16.0

Don't miss a new mago release

NewReleases is sending notifications on new releases.