This release features a major refactoring of Psalm's mutability inference system.
This release will likely be followed by a stable release.
The new automated mutability (pure, mutation free, externally mutation free, impure) attribute fixes that will be proposed by Psalm, when applied, will improve Psalm's type inference and especially security analysis, as pure functions are automatically specialized by Psalm, killing false positives during security analysis.
Now, Psalm will always analyze and emit MissingPureAnnotation and MissingImmutableAnnotation issues for all functions, methods and classes that can be marked with one of the following attributes (which can be automatically added by running Psalm with --alter --issues=MissingPureAnnotation,MissingImmutableAnnotation).
For functions and methods, MissingPureAnnotation will be emitted, automatically adding the following annotations:
@psalm-pure» - Indicates that the function or method is pure, one whose output is just a function of its input (no mutations or even read property accesses allowed).@psalm-mutation-free» - Used to annotate a class method that does not mutate state, either internally or externally of the class's scope (only internal property reads on$thisare allowed for methods)@psalm-external-mutation-free» - Used to annotate a class method that does not mutate state externally of the class's scope (internal property reads and writes on$thisandselfare allowed for methods)@psalm-impure» - A new annotation, equivalent to the default mutability level of functions and methods (all mutations allowed): Psalm will require the explicit annotation of only abstract methods with this or any of the above annotations through a separate, non-autofixableMissingAbstractPureAnnotationissue, to improve mutability inference for implementors of an interface (though it can be used on all functions and methods as well).
For classes, MissingImmutableAnnotation will be emitted, automatically adding the following annotations:
@psalm-immutable» - Used to annotate a class where every property is treated by consumers as@psalm-readonlyand every instance method is treated as@psalm-mutation-free.@psalm-external-mutation-free» - Used to annotate a class where every instance method is treated as@psalm-external-mutation-free.@psalm-mutable» - A new annotation, used to annotate a class where at least one property is mutable: this is the default behavior, but it can be explicitly marked for clarity: Psalm will require the explicit annotation of only interfaces with this or any of the above annotations through a separate, non-autofixableMissingInterfaceImmutableAnnotationissue, to improve mutability inference for implementors of an interface (though it can be used on all classes and interfaces as well).
New types
For situations where the callable or Closure needs to be pure, mutation-free or externally mutation-free, the following subtypes are available:
- Pure (no mutations or even read property accesses allowed), equivalent to marking functions or methods with
@psalm-purepure-callablepure-Closure
- Mutation-free (only internal property reads on
$thisare allowed for methods), equivalent to marking functions or methods with@psalm-mutation-freeself-accessing-callableself-accessing-Closure
- Externally mutation-free (internal property reads and writes on
$thisandselfare allowed for methods), equivalent to marking functions or methods with@psalm-external-mutation-freeself-mutating-callableself-mutating-Closure
- Impure (the default behavior, all mutations allowed); functions or methods can also be explicitly marked as impure with
@psalm-impureimpure-callable(an alias tocallable)impure-Closure(an alias toClosure)
This can be useful when the callable is used in a function marked with @psalm-pure or @psalm-mutation-free or @psalm-external-mutation-free.
What's Changed
Features
- Mutation refactoring, always emit MissingPureAnnotation and MissingImmutableAnnotation issues by @danog in #11630
- Global variables are impure like static variables by @kkmuffme in #11659
Fixes
Full Changelog: 6.15.1...7.0.0-beta15