Releases: carthage-software/mago
Mago 1.0.0-rc.11
This release focuses on reducing false positives, improving type system accuracy, performance optimizations, and introducing new linter rules.
New Features
Linter
-
New
property-namerule (#703)
Added a new linter rule to enforce consistent property naming conventions across your codebase. -
New
use-specific-assertionsrule
Introduced a new rule that encourages using specific assertion methods (e.g.,assertTrue,assertNull) instead of genericassertEquals/assertSamewith literal values for better clarity and intent.
Analyzer
- Type narrowing for symbol existence checks
The analyzer now properly narrows types based on symbol and member existence checks likefunction_exists(),method_exists(),property_exists(), anddefined(). This eliminates false positives when conditionally using symbols after checking their existence.
Bug Fixes
Analyzer
-
Fixed false positives for class-string comparisons and static variable initialization
Resolved issues where the analyzer incorrectly flagged valid code involving class-string type comparisons and static variable initialization patterns. -
Fixed false positive for
count()comparison on non-empty-list
The analyzer no longer incorrectly reports issues when comparing the count of anon-empty-listwith integer values. -
Fixed list type preservation when narrowing with
is_array()
Usingis_array()on a union type containing a list no longer incorrectly loses the list type information. -
Fixed interface method resolution for
__callStatic
The analyzer now only reports interface implementation issues when resolving actual methods, not when resolving magic__callStaticcalls. -
Fixed invalid array access assignment value checking
Improved detection of invalid values being assigned through array access expressions.
Reconciler
- Fixed list type narrowing preserving assertion element types
Type narrowing on list types now correctly preserves the element type assertions, preventing false positives in generic list operations.
Docblock
- Fixed
@methodtag withstaticreturn type
The docblock parser now correctly handles@methodtags that specifystaticas their return type.
Linter
- Made
strict-assertionsrule less strict
Thestrict-assertionsrule has been adjusted to reduce noise while still catching problematic assertion patterns.
WASM
- Matched analyzer default settings
The WASM build now uses the same default analyzer settings as the native build for consistent behavior.
Reporting
- Fixed duplicate issue collection
Removed unnecessary duplicate checking when collecting issues, improving performance and correctness.
Performance Improvements
-
Optimized type combiner
Significant performance improvements to the type combination logic, reducing analysis time for codebases with complex type operations. -
Lowered analysis thresholds
Adjusted internal thresholds for formula complexity and algebra operations to improve analysis speed on large codebases without sacrificing accuracy. -
Early return optimization for pragma collection
Added early return when no pragmas are present, avoiding unnecessary processing.
Build Improvements
- Profile-Guided Optimization (PGO) for Tier 1 targets
Release binaries for macOS and Windows are now built with PGO, resulting in 5-15% performance improvements.
Full Changelog: 1.0.0-rc.10...1.0.0-rc.11
Mago 1.0.0-rc.10
Mago 1.0.0-rc.10
This release focuses on reducing false positives across multiple analysis scenarios, improving type system accuracy, and enhancing PHP compatibility.
Bug Fixes
Analyzer
- Fixed impossible type assertion false positive when comparing interfaces - a class can implement multiple interfaces, so
Foocan beBarat runtime (#707) - Corrected template resolution regression affecting PSL and other libraries using generic parameters from class-strings
- Fixed false positive when checking
$value === []on non-null or mixed types (#701) - Resolved false positive
unimplemented-abstract-property-hookincorrectly reported on interfaces - Infer
Iteratorkey/value types fromkey()andcurrent()method return types - Support
floatandarray-keyin string concatenation with improved__toStringtrait detection - Fixed callable-to-array reconciliation and interface throwable checks in catch blocks
- Added missing
$_COOKIEsuperglobal
Codex
- Resolved false positive redundant condition for integer range identity comparisons (#706)
- Fixed trait
selftype resolution to use intersection with@require-implements/@require-extendsconstraints
Prelude
- Fixed
call_user_funcandsprintfstubs withStringablesupport
Improvements
Composer
- Added PHP 8.5 and 8.6 as compatible versions (#699)
Full Changelog: 1.0.0-rc.9...1.0.0-rc.10
Mago 1.0.0-rc.9
Bug Fixes
- Fixed stack overflow when analyzing projects with complex generic types - Analysis of certain codebases (including tempest-framework) would crash with a stack overflow due to infinite recursion in type expansion. Added cycle detection to prevent recursive expansion loops while preserving correct type resolution.
Full Changelog: 1.0.0-rc.8...1.0.0-rc.9
Mago 1.0.0-rc.8
Overview
This release brings significant analyzer enhancements including full property hooks support, unused template parameter detection, and improved type assertion analysis. The linter gains a new variable-name rule, and the prelude is updated with MongoDB, Redis, and URI extension stubs.
Features
Analyzer
- Unused Template Parameter Detection: The analyzer now detects and reports unused template parameters on classes, interfaces, traits, functions, and methods
- Impossible Type Assertion Detection: Added detection for impossible type assertions in
@assertannotations, helping catch logical errors in assertion docblocks - Negation Operator Validation: The analyzer now validates operand types for the negation (
-) operator, catching type errors early
Codex
- Full Property Hooks Support: Complete implementation of PHP 8.4 property hooks, including type inference, visibility checks, and backed property reference validation
- Full
properties-of<T>Support: Theproperties-of<T>type is now fully implemented with proper visibility filtering (public-properties-of<T>,protected-properties-of<T>,private-properties-of<T>)
Linter
- New
variable-nameRule: Enforces consistent variable naming conventions (snake_case or camelCase) with configurable options for parameter checking and promoted property exclusion (#695)
Bug Fixes
Analyzer
- Fixed handling of by-reference values in array literals
- Prevented duplicate catch type errors by inlining the avoid-catching-error heuristic check (#696)
- Redundant negated type assertions (e.g.,
!is_string()on anint) are now reported as warnings instead of impossible errors - Removed incorrect assertion from
fclose()stub
Linter
- The
literal-named-argumentrule now skips the first argument by default, as it's typically self-explanatory. A newcheck-first-argumentoption preserves the original behavior (#694)
Playground
- Fixed an issue where shared playground URLs would immediately lose their state upon loading
Documentation
- Replaced outdated PSR-12 references with PER Coding Style (PER-CS) (#698)
Prelude Updates
- New Extension Stubs: Added stubs for MongoDB, Redis, and URI extensions
- Updated Stubs: Synced DOM, Intl, Reflection, and Standard extension stubs with phpstorm-stubs
Full Changelog: 1.0.0-rc.7...1.0.0-rc.8
Mago 1.0.0-rc.7
Features
Type System
- Added support for
int-mask<1, 2, 3>andint-mask-of<Foo::*>types - Added support for
literal-floattype
Analyzer
- Added support for exception filtering
Playground
- Added online playground for trying Mago in the browser ( mago.carthage.software/playground )
Bug Fixes
Formatter
- Fixed indentation for flattened binary chains with trailing comments
- Fixed idempotence issue with elvis operator in arrow function bodies
Analyzer
- Fixed template constraint resolution to use inferred types instead of declared constraints (#676)
- Fixed type assertions for mixed variables in if statements
- Fixed yoda style handling in assertion scrapper
Codex
- Fixed expansion state not being reset after expanding
Linter
- Fixed
literal-named-argumentrule to ignore variadic functions
Prelude
- Fixed multiple PHP stub docblocks
- Added return type to
ReflectionNamedType::getNamemethod (#673)
CLI
- Updated
initcommand to match the latest configuration schema
WASM
- Fixed duplicate issues reported by both linter and analyzer
- Fixed timing being enabled in wasm builds
Improvements
Performance
- Improved type expander and comparator performance
- Improved metadata populator performance
- Refactored codex to use bitflags for TUnion properties
CLI
- Standardized exit codes
Full Changelog: 1.0.0-rc.6...1.0.0-rc.7
Mago 1.0.0-rc.6
Bug Fixes
Analyzer
- Use constant
REQUEST_TIMEfor$_SERVERto ensure deterministic error messages for baseline matching (#669) - Consider template constraints when checking int/float disjointness (#659)
- Mark
$_SESSIONsuperglobal as possibly undefined (#670) - Allow array destructuring on
ArrayAccessimplementations (#671) - Consider
possibly_undefinedwhen checking redundant nullsafe operator (#672) - Resolve array access type using only matching keys from union index type (#666)
- Check parent classes for pseudo methods to prevent false positive
missing-magic-method(#667)
Codex
- Sort docblock inheritance by hierarchy depth to ensure parents are processed first (#663)
- Resolve templates when inheriting assertions from parent methods (#660)
- Infer arithmetic operations as
int|floatinstead ofmixed(#664) - Treat arrays with required keys as non-empty in containment check (#665)
Semantics & Formatter
- Require arrow functions on RHS of
|>to be parenthesized (#662)
Improvements
Baseline
- Introduced a new loose baseline variant as the default format, which is more resilient to code changes. The loose format matches issues by
(file, code, message)tuple with occurrence counts, making baselines stable even when line numbers shift. The previous strict format (exact line matching) remains available via configuration. (#492)
Full Changelog: 1.0.0-rc.5...1.0.0-rc.6
Mago 1.0.0-rc.5
Bug Fixes
Syntax
- Fixed parsing of integers prefixed with 0 to correctly interpret them as octal numbers
Analyzer
- Fixed type narrowing for in_array and Psl\Iter\contains (#658)
- Fixed assertion scrapping for in_array and Psl\Iter\contains
- Fixed int/float disjointness handling in conditional type narrowing (#656)
Codex
- Fixed child native return types to take precedence over parent docblock types (#657)
Improvements
PHP 8.5 Support
- Semicolon as a switch case separator is now deprecated for PHP >= 8.5
CLI
- Removed deprecated --no-color flag (use --colors never instead)
Internal
- Refactored codex populator into modular subcomponents
Full Changelog: 1.0.0-rc.4...1.0.0-rc.5
Mago 1.0.0-rc.4
Features
Partial Function Application (RFC)
Mago now fully supports PHP 8.6's Partial Function Application RFC, enabling first-class callable creation using placeholder syntax. You can use positional (?), named (name: ?), and variadic (...) placeholders to create closures from existing functions and methods, with full type inference and validation to ensure type safety across your partial applications.
PHP Version Support
- Added support for PHP 8.5, which was released just days ago
- Switched minimum supported PHP version from 7.4 to 8.0
Looking Ahead to PHP 8.6
This release demonstrates Mago's unique capability to stay ahead of the PHP ecosystem. While PHP 8.6 won't be released for another year and the Partial Function Application RFC hasn't even been merged into PHP yet, Mago already provides full support for this feature. By controlling our entire stack, from parser to analyzer, we can implement and validate upcoming PHP features much faster than traditional tools, giving developers early access to write future-proof code with confidence.
Linter
- New
no-redundant-yield-fromrule to identify unnecessaryyield fromexpressions that can be simplified
Bug Fixes
Analyzer
- Fixed incorrect parameter type mapping when using named placeholders that reorder parameters in partial function application
- Corrected false positives when real methods are documented with
@methodannotations in child classes for return type refinement - Fixed variable invalidation logic to properly invalidate descendant variables when passed by reference
- Resolved trait constant access issues when using
self,static, and$thiskeywords - Suppressed redundant unused statement issues in test contexts
- Disabled reporting of
#[Override]attribute issues before PHP 8.3 - Corrected impossible condition detection when comparing
numericandarray-keytypes - Eliminated invalid and redundant auto-fix suggestions
- Fixed
array_merge()result computation when using empty arrays as arguments
Codex
- Improved docblock inheritance logic to respect explicit return types in child classes instead of inheriting parent types
- Enhanced overall docblock inheritance handling with better resolution rules
Database
- Corrected path normalization for Windows systems during test execution
- Improved pattern specificity resolution for path and include conflicts
- Fixed file logical name usage when updating files during watch mode
Linter
- Prevented false positives in
no-redundant-mathrule for float division operations - Disabled
sensitive-parameterrule for PHP versions below 8.2 - Fixed incorrect static closure suggestions when nested closures reference
$this
Formatter
- Preserved parentheses around constant access expressions in
instanceofbinary operations
Docblock
- Added support for multiple spaces after colons in callable type annotations
Collector
- Disabled reporting of unfulfilled expectations during incremental analysis to reduce noise
Installation
- Fixed installation script incorrectly exiting successfully when the download server is unavailable
Improvements
Syntax
- Tagged
Expression,Statement, andNodeenums as#[non_exhaustive]for future compatibility
Full Changelog: 1.0.0-rc.3...1.0.0-rc.4
Mago 1.0.0-rc.3
Mago 1.0.0-rc.3
🤩 Features
💻 CLI
--retain-codeoption: Filter reported issues by specific codes (e.g.,--retain-code semantics --retain-code invalid-argument). Unlike--onlyin lint, this runs all checks but filters the
output
✨ Formatter
- Method sorting: Add option to sort class methods based on name, visibility, and other modifiers
🐛 Bug Fixes
🎯 Type System
- Variance-aware inheritdoc: Respect contravariance for parameters (allow child to widen types) and covariance for return types (allow child to narrow types) when inheriting docblock types (closes
#629) - Better type narrowing: Narrow mixed to array types after
isset()checks on nested array access - Nullsafe operator: Propagate nullsafe operator short-circuit through entire expression chains
- Promoted properties: Parse inline
@vardocblocks on promoted constructor properties - Trait
selftypes: Supportselfparameter types in closures defined in trait methods - Array operations: Preserve non-empty flag in array addition and
array_merge()type inference - Type expansion: Correct type expansion logic for specialized type parameters
🔧 Linter
- str-contains rule: Add support for negation pattern (
strpos === false→!str_contains). Only provide fixes for strict equality (===and!==) to prevent unsafe replacements. Report warnings for loose equality (==,!=,<>) due tostrposreturning 0 at position 0 (closes #494)
📚 Prelude
- mbstring functions : Correct return types for encoding functions (closes #628)
🎨 Improvements
📁 Database
- Path handling: Prioritize includes over paths, and add support for path and include patterns (closes #327)
Full Changelog: 1.0.0-rc.2...1.0.0-rc.3