Skip to content

[DowngradePhp82] Add DowngradeArrowFunctionNeverReturnTypeRector - #399

Open
roxblnfk wants to merge 1 commit into
rectorphp:mainfrom
roxblnfk:feature/downgrade-arrow-function-never-return-type
Open

[DowngradePhp82] Add DowngradeArrowFunctionNeverReturnTypeRector#399
roxblnfk wants to merge 1 commit into
rectorphp:mainfrom
roxblnfk:feature/downgrade-arrow-function-never-return-type

Conversation

@roxblnfk

@roxblnfk roxblnfk commented Sep 14, 2026

Copy link
Copy Markdown
Contributor

🔍 What was changed

  • New DowngradeArrowFunctionNeverReturnTypeRector in the PHP 8.2 set: strips the never return type from arrow functions only, e.g. fn (): never => throw ... becomes fn () => throw ....
  • Closures, functions and methods keep never, which PHP 8.1 accepts; the 8.1 set still removes it from all of them when downgrading further.

Why?

PHP 8.1 rejects never on arrow functions at compile time (A never-returning function must not return, php/php-src#7900, fixed in 8.2). DowngradeNeverTypeDeclarationRector (#397) covers arrow functions, but it lives in the 8.1 set, and a downgrade to 8.1 applies DOWN_TO_PHP_82 + PHP_82 only, so the construct survived and failed on the very runtime it was downgraded for.

Checklist

  • How was this tested:
    • Fixture tests added (arrow function, static arrow function with parameters as an argument, skip closure/function, skip other return type)
    • phpunit rules-tests/DowngradePhp82, phpstan, ecs, rule-doc-generator validate run locally

PHP 8.1 accepts the "never" return type on functions, methods and closures, but rejects it on arrow functions: the implicit return of the body expression trips "A never-returning function must not return" at compile time (php/php-src#7900, fixed in 8.2). rectorphp#397 taught DowngradeNeverTypeDeclarationRector to strip it from arrow functions, but that rule sits in the 8.1 set, which removes 8.1 features when downgrading *from* 8.1 to 8.0. Code downgraded *to* 8.1 never reaches it, so `fn (): never => throw ...` survived and still failed to compile on 8.1. The arrow-function case is an 8.2 feature and belongs in the 8.2 set; this rule puts it there and leaves every other function-like to the 8.1 set.

Assisted-By: Claude Fable 5.1 <noreply@anthropic.com>
roxblnfk added a commit to php-testo/testo that referenced this pull request Sep 14, 2026
ci(tests): exercise the suite on PHP 8.1 via an ephemeral Rector downgrade
fix(bench): guard memory_reset_peak_usage() for PHP 8.1
test(output): skip the memory-comparison diff test on PHP 8.1
refactor(console): give the init config template a `.stub` extension
ci: exclude benchmarks from the coverage report

The container shared readonly services across scopes by reflecting `readonly class`, which the 8.1 downgrade strips away; the sixteen services that actually land in the container cache now declare the sharing explicitly and `internal/container` is bumped to ^1.1 for the attribute.

The 8.1 leg runs `php-internal/actions/downgrade@v1`: dependencies resolve as if on 8.1, packages without an 8.1 version (the testo/* splits, the container, unpoly) are relieved, and core/plugin/bridge/tests are Rector-downgraded before the run. The console stub is renamed so the downgrade does not parse a template. `fn(): never` arrow functions in tests are temporarily plain closures until rectorphp/rector-downgrade-php#399 lands.

Assisted-By: Claude Fable 5.1 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

1 participant