github carthage-software/mago 1.24.0
Mago 1.24.0

21 hours ago

Mago 1.24.0

Mago 1.24.0 is mostly an analyzer-correctness release: recursive literal-scalar widening in by-reference out-types, wider mixed-operand detection on templated concatenations, and targeted fixes around isset / array_key_exists, list destructuring, iterable narrowing, and __call on non-final classes. It also adds a prefer-self-return-type linter rule with FQCN-to-use autofix, match-arm => alignment in the formatter, and a service memory fix that takes mago lint --fix --unsafe on Drupal core from ~11.6 GB RSS down to 748 MB.

New: mago-twig-syntax. A lossless Twig 3 lexer, AST, and parser published to crates.io. Not wired into the Mago binary yet: the plan is Twig support across the linter, formatter, and possibly the analyzer (#303), then Blade (#304). Twig is the testing ground for multi-language support; once that plumbing is confident, adding Blade should be much cheaper.

✨ Features

Linter

  • prefer-self-return-type: new rule suggesting self instead of the declaring class name in method return types. (#1442, 9081ce8)
  • FQCN autofix with use-statement synthesis: no-fully-qualified-global-* fixers now insert a matching use at the top of the file. (#555, #1645, d16e16c)
  • string-style handles single-quoted strings: fixer now converts 'foo' to "foo" when the chosen style requires it. (#1674, b33a57b)

Formatter

  • Align assignment-like match arms: column-align => across arms in match expressions, matching assignment alignment. (#1642, 34e0277)

Codex

  • Detect class_exists-guarded stubs as polyfills: user definitions are preferred over guarded fallbacks on merge. (0748989)

Prelude

  • Iterator on Generator: stub now reflects that Generator implements Iterator. (e115682)
  • ArrayAccess on DOMNodeList: stub reflects the interface exposed by the extension. (7efae17)

🐛 Bug Fixes

Analyzer

  • Recursive literal-scalar widening in by-reference out-types: widens through arrays, iterables, generics, and conditionals. (#1686, 1575f1e)
  • Baseline literal-scalar widening in by-reference out-types: initial fix for single-level literal tightening on param-out. (#1678, 45926da)
  • Reject mixed and union-shaped templates as concat operands: T as mixed and mixed-scalar unions now surface mixed-operand. (a55b321)
  • Namespaced global-fallback calls pass function-casing check: \Foo\bar() no longer misfires on global fallback. (#1680, f61f57d)
  • Reject incompatible parameter defaults; gate implicit-null on PHP < 9.0: catches value/default-type mismatches. (#1682, f04aefb)
  • Narrow isset / array_key_exists to false on provably missing keys: fixes inconsistent impossible-condition warnings. (#1679, 434f11e)
  • Skip no-boolean-literal-comparison on synthetic match-arm binaries: fixer no longer produces invalid code for match arms. (#1681, 67ea13e)
  • Only hard-error on missing __call when the class-like is final: non-final classes keep PHPUnit-style magic method calls working. (#1676, 6953e8e)
  • Respect list siblings when reporting undefined array keys: fixes wrong undefined-string-array-index on list destructuring. (#1668, 2f248e8)
  • Don't corrupt locals when array-index narrowing drops every variant: fixes false undefined-string-array-index positives. (#1669, 90f9c5d)
  • Preserve type parameters when narrowing iterable/array: generic arguments survive through iterable narrowing. (f815bcc)

Codex

  • Disjoint literal class-string and string in identity check: fixes an incorrect subtype relation. (#1677, 0fed110)
  • Hold alias-expansion guard across recursive calls: prevents stack overflow on deeply aliased type graphs. (58afef6)
  • Prioritize user polyfills over builtins and external definitions: user-written class_exists-guarded stubs win. (c3d7eb2)
  • Narrow iterable<mixed, V> key to array-key against an array container: fixes over-wide key propagation. (ed712ba)

Syntax

  • Reject & reference prefix outside legal positions: catches previously-accepted syntax errors. (#1683, 53800a6)

Formatter

  • Avoid inlining nested single-element array-like arguments: fixes regression where nested [[$x]] got collapsed wrong. (#1672, #1673, de78a1f)

CLI

  • Handle spaces in binary path: Composer wrapper and self-invocation no longer drop arguments on paths containing spaces. (#1471, 38baca6)

Service

  • Reset arena between apply_fixes batches: bounds memory during --fix --unsafe; Drupal-core run peak goes from ~11.6 GB RSS to 748 MB. (#1670, 8b551dc)

🏗️ Internal

Twig

  • Normalize path separators in fixture exclusion check: fixes a Windows CI failure in mago-twig-syntax tests. (ec890a3)
  • Exclude twig-syntax test fixtures from typos check: removes CI noise from vendored upstream Twig content. (a0eb189)

Syntax

  • Remove Option from LiteralString::kind: every literal string now carries a concrete kind. (#1675, 2fb1377)

Linter

  • Drop constant_fqn_key in favor of ascii_lowercase_constant_name_atom: removes a dead helper. (067fa34)
  • Drop stagger logic from text-edit; fix edit-order invariants: simplifies the batch fixer. (363e231)

🙏 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.23.1...1.24.0

Don't miss a new mago release

NewReleases is sending notifications on new releases.