Mago 1.7.0
This release introduces new type system features, improved type inference for built-in functions, a new linter rule, and numerous bug fixes for the analyzer, formatter, and type system. A significant internal effort also went into reducing dependencies and binary size.
✨ Features
Type System
uppercase-stringandnon-empty-uppercase-stringtypes: Full support for these PHPDoc types in type syntax, codex, and analyzer. This resolves cascading errors when these types were previously unrecognized (#1057)
Analyzer
-
Return type providers for
min()andmax(): These functions now return precise types based on their arguments (#1074) -
array_filter()callback parameter type inference: The analyzer now respects themodeargument (ARRAY_FILTER_USE_KEY,ARRAY_FILTER_USE_BOTH) when inferring closure parameter types, fixing incorrectmixedinference for callback parameters (#1031) -
Switch statement fallthrough analysis: The analyzer now correctly recognizes that non-terminating code paths in a
caseblock fall through to the next case. Acasewith a conditionalreturnfollowed by a case that always returns is no longer flagged asmissing-return-statement(#1081)
Linter
no-redundant-issetrule: New rule that detects redundant arguments inisset()calls. For example, inisset($a, $a['key'], $a['key']['nested']), the first two checks are redundant becauseisseton a nested access implicitly checks all parent accesses (#769)
CLI
--ignore-baselineflag: New flag forlintandanalyzecommands that temporarily ignores the baseline file, useful for reviewing and fixing baselined issues (#1076)
⚡ Performance
- Reduced AST size: Optimized AST node representation to reduce memory usage during parsing
- Leaner binary: Removed 7 third-party dependencies (
reqwest,openssl,num_cpus,strum_macros,derivative,strsim,bitflags,async-walkdir), replacing them with standard library equivalents or manual implementations.reqwest/opensslwere replaced withureq/rustlsfor a significantly smaller and faster-compiling binary
🐛 Bug Fixes
Analyzer
- Unused method false positives: Methods referenced in literal arrays (
[$this, 'method']) and string callbacks ('ClassName::method') are now correctly tracked as used (#1069, #1044) - Property/constant access type expansion: Property access and constant access expressions now have their types properly expanded, fixing incorrect type inference (#1071)
- Non-optional list items in array merge: Fixed an issue where non-optional list items were incorrectly skipped during array merging
Codex
@psalm-require-extendssupport in traits: Methods, properties, and class constants inherited from required parent classes via@psalm-require-extendsor@phpstan-require-extendsare now properly resolved in traits, eliminating falsenon-existent-property,non-existent-class-constant, andunknown-referrors (#1064, #1068, #1070)- Enum types in generic comparator: Fixed incorrect type comparison when enums implement generic interfaces, resolving false
invalid-return-typeerrors (#1061) - Platform-aware constant types: Predefined constants like
PHP_INT_SIZE,PHP_INT_MAX, andPHP_FLOAT_DIGnow use platform-aware range/union types instead of host-specific literal values.PHP_INT_SIZE > 4is no longer flagged as a redundant comparison (#1084)
Formatter
- Assignment alignment leaking into nested arrays: When
align-assignment-likeis enabled, the alignment context from consecutive variable assignments no longer leaks into nested array key-value pairs (#1082)
Linter
prefer-first-class-callablewith reference captures: Skip suggesting first-class callable syntax when the callee variable is captured by reference in a closure'suseclause, as the two forms have different semantics (#1067, #1063) by @kzmshx
Prelude (Type Stubs)
array_walkgenerics: Fixed generic templates forarray_walkto properly infer callback parameter types (#1066, #1045) by @ddanielouarray_splicetype precision: Improved type definitions forarray_spliceto preservelist<T>types and correctly handle non-array replacement arguments (#1072, #1080)- Sorting functions type precision: Enhanced type definitions for sorting functions (
usort,uasort,uksort, etc.) to preserve non-empty array types (#1083)
🏗️ Internal
- Replaced
reqwest+opensslwithureq+rustlsin self-update module - Replaced
num_cpuswithstd::thread::available_parallelism() - Replaced
bitflagswith manual bit flag implementations - Removed
derivative,strum_macros,strsim, andasync-walkdirdependencies - Improved array inference logic in codex
🙏 Thank You
Contributors
A huge thank you to everyone who contributed code to this release:
- @ddanielou — #1066
- @kzmshx — #1067
Issue Reporters
Thank you to everyone who reported issues and requested features that shaped this release:
- @aszenz — #1031
- @dotdash — #769
- @joshrai — #1070
- @karoun — #1064
- @klunejko — #1082
- @kzmshx — #1063
- @llaville — #1044
- @mathroc — #1061
- @Nadyita — #1074, #1080, #1081, #1083, #1084
- @Neila142 — #1076
- @rauanmayemir — #1068, #1069
- @tm1000 — #1057
- @WalterWoshid — #1071
Full Changelog: 1.6.0...1.7.0