Skip to content

Fix: unused import, duplicate issue shortcode, Windows CI opcache/bypass-finals conflict#11901

Closed
alies-dev wants to merge 5 commits into
vimeo:masterfrom
alies-dev:fix/11899-followup-cleanup
Closed

Fix: unused import, duplicate issue shortcode, Windows CI opcache/bypass-finals conflict#11901
alies-dev wants to merge 5 commits into
vimeo:masterfrom
alies-dev:fix/11899-followup-cleanup

Conversation

@alies-dev

@alies-dev alies-dev commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

Context

Stacked on #11900 (branched from fix/11899-statementsanalyzer-depth; this diff will shrink to just this branch's own commits once #11900 merges). While investigating why CI was still red on #11900 after fixing the StatementsAnalyzer regression, I found several unrelated pre-existing issues that #11900's fix let the test suite and self-analysis reach for the first time (previously everything crashed before getting this far):

  • Code Style Analysis: an unused TClosure import in FilterUtils.php.
  • DocumentationTest::testShortcodesAreUnique: IncompatibleTypeParameters (added in Support better template inference with type variables #11875) reused shortcode 362, already owned by ImpureGlobalVariable.
  • Windows unit tests (2 of 8 chunks, intermittently): Class Psalm\Tests\TestConfig cannot extend final class Psalm\Config. dg/bypass-finals strips final from source at require-time via a stream wrapper, a known incompatibility with OPcache (cached bytecode bypasses the wrapper). windows-ci.yml is the only workflow that sets opcache.enable_cli=1; Linux's ci.yml doesn't. Confirmed via the Windows job log: Zend OPcache v8.5.7 is active there. Could not reproduce locally (different OS), so this fix is based on the config asymmetry and the well-documented bypass-finals/OPcache incompatibility rather than a local repro.
  • Run Shepherd (self-analysis): 12 pre-existing MissingPureAnnotation/MissingImmutableAnnotation findings, all in the type-variable-support feature (Support better template inference with type variables #11875), which never got these annotations added.

Solution

Independent, minimal fixes, one per commit:

  • Remove the unused import.
  • Reassign IncompatibleTypeParameters to shortcode 368 (next free one).
  • Drop opcache.enable_cli=1 from the Windows CI ini-values, matching Linux.
  • Add the missing purity annotations via psalm --alter, reviewed individually. One of the twelve (TypeVariableBounds) is genuinely mutable by design (TypeVariableTracker appends to its bounds arrays in place so TTypeVariable instances already holding a reference see later constraints), so that one is @psalm-suppressed with a reason rather than incorrectly marked @psalm-immutable.

Full suite locally: 72 failing tests → 71 (the shortcode test now passes; the remaining 71 are the pre-existing PHP-8.5-host InternalCallMapHandlerTest baseline (70) plus one unrelated ReportOutputTest SARIF-metadata drift, both out of scope here). Self-analysis: 12 issues → 0.

Known remaining CI failure on this PR: Check backward compatibility will still flag the shortcode reassignment as a breaking constant-value change. roave-backward-compatibility-check compares straight against origin/master and has no baseline/ignore mechanism, so it can't distinguish "this class was merged three commits ago and never released" from "long-standing public API" — renumbering either colliding class trips it the same way. Since IncompatibleTypeParameters has never shipped in a tagged release, I don't think this is a real-world break, but flagging it explicitly rather than silently reverting the correct fix (which would just re-break testShortcodesAreUnique instead). Happy to revert the shortcode commit if maintainers would rather see BCC green here.

Run Psalm (mac OS) is unrelated to any of this: setup-php fails to install PHP 8.5 on the macOS runner itself (php: command not found), reproducing identically on master HEAD regardless of PR content.

alies-dev added 4 commits July 2, 2026 12:39
Merge commit 290eaec (6.x into master) resolved a conflict in
StatementsAnalyzer's property/constructor block by taking 6.x's
version wholesale, while the separate analyze() method kept
master's version wholesale. The two halves no longer matched:

- private int $depth = 0 was dropped, but $this->depth++/-- in
  analyze() remained, causing an uncaught RuntimeException on
  PHP 8.2+ (Psalm's ErrorHandler converts the dynamic-property
  deprecation into a crash).
- The $root_scope constructor-promoted property was dropped too,
  so $this->root_scope always read as an undefined property.
- The constructor logic that populates $this->taint_flow_graph
  and $this->variable_use_graph from the shared codebase graph
  was replaced by 6.x's simpler version, which never assigns
  either property. This silently disabled unused-variable
  detection and taint tracking wherever the crash above didn't
  already stop execution (e.g. under PHPUnit, which doesn't
  install that ErrorHandler).

Restores all three to match the pre-merge master constructor
(commit 5c1c31c) exactly, alongside the type_variable_tracker
logic 6.x legitimately added. Full test suite goes from 374
failing/erroring tests to 72 (all pre-existing/unrelated), and
self-analysis from 6139 issues to 12 (all pre-existing/unrelated).

Fixes vimeo#11899
Not referenced anywhere in the file; caught by phpcs.
IncompatibleTypeParameters (added in vimeo#11875) reused shortcode 362,
already owned by ImpureGlobalVariable. DocumentationTest::
testShortcodesAreUnique caught the collision; reassigns the newer
issue to 368, the next free shortcode.
dg/bypass-finals strips `final` from source via a require-time
stream wrapper, which is well known to be incompatible with
OPcache: cached bytecode bypasses the wrapper, so classes already
in the opcache serve their un-patched (still-final) source. This
uniquely broke Windows CI (only workflow enabling opcache.enable_cli;
Linux CI leaves it off) with intermittent "TestConfig cannot extend
final class Config" fatals in 2 of 8 chunks, since which classes
hit a cache populated before BypassFinals wraps them is a race.

Linux CI already runs without opcache.enable_cli; this aligns
Windows with it.
@alies-dev alies-dev marked this pull request as draft July 2, 2026 12:06
The type-variable-support feature (vimeo#11875) landed without
@psalm-mutation-free/@psalm-pure/@psalm-external-mutation-free
annotations on several pure methods, and psalm's own self-analysis
(Shepherd CI) has been failing on these 12 findings since. Added
via `psalm --alter --issues=MissingPureAnnotation,MissingImmutableAnnotation`,
reviewed individually.

TypeVariableBounds is deliberately mutable (TypeVariableTracker
appends to its bounds arrays in place so that TTypeVariable
instances already holding a reference see later constraints), so
it can't actually be marked @psalm-immutable as psalm suggested;
suppressed that one specific finding with a reason instead.
@alies-dev alies-dev closed this Jul 2, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant